Merge branch 'release/rc-v1.2.0' of github.com:ONLYOFFICE/DocSpace into release/rc-v1.2.0

This commit is contained in:
Akmal Isomadinov 2022-12-09 18:50:46 +05:00
commit 2684249dfa
54 changed files with 527 additions and 650 deletions

View File

@ -44,6 +44,7 @@ CORE=" --core:products:folder=${BASE_DIR}/products --core:products:subfolder=ser
SERVICE_NAME=(
api
api-system
socket
studio-notify
notify
@ -67,6 +68,11 @@ reassign_values (){
WORK_DIR="${BASE_DIR}/studio/ASC.Web.Api/"
EXEC_FILE="ASC.Web.Api.dll"
;;
api-system )
SERVICE_PORT="5010"
WORK_DIR="${BASE_DIR}/services/ASC.ApiSystem/"
EXEC_FILE="ASC.ApiSystem.dll"
;;
socket )
SERVICE_PORT="5028"
WORK_DIR="${BASE_DIR}/services/ASC.Socket.IO/"

View File

@ -105,6 +105,14 @@ Depends: {{product}}-common (= {{package_header_tag_version}}),
${shlibs:Depends}
Description: Description
Package: {{product}}-api-system
Architecture: any
Depends: {{product}}-common (= {{package_header_tag_version}}),
dotnet-sdk-6.0,
${misc:Depends},
${shlibs:Depends}
Description: Description
Package: {{product}}-studio
Architecture: any
Depends: {{product}}-common (= {{package_header_tag_version}}),

View File

@ -150,7 +150,7 @@ RUN dos2unix /docker-entrypoint.d/prepare-nginx-proxy.sh && \
RUN chown nginx:nginx /etc/nginx/* -R && \
chown nginx:nginx /docker-entrypoint.d/* && \
# changes for upstream configure
# sed -i 's/127.0.0.1:5010/$service_api_system/' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i 's/127.0.0.1:5010/$service_api_system/' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i 's/127.0.0.1:5012/$service_backup/' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i 's/127.0.0.1:5007/$service_files/' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i 's/127.0.0.1:5004/$service_people_server/' /etc/nginx/conf.d/onlyoffice.conf && \
@ -175,13 +175,13 @@ COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.Data.B
CMD ["ASC.Data.Backup.BackgroundTasks.dll", "ASC.Data.Backup.BackgroundTasks"]
# ASC.ApiSystem ##
# FROM dotnetrun AS api_system
# WORKDIR ${BUILD_PATH}/services/ASC.ApiSystem/
FROM dotnetrun AS api_system
WORKDIR ${BUILD_PATH}/services/ASC.ApiSystem/
# COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
# COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.ApiSystem/service/ .
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.py ./docker-entrypoint.py
COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.ApiSystem/service/ .
# CMD ["ASC.ApiSystem.dll", "ASC.ApiSystem"]
CMD ["ASC.ApiSystem.dll", "ASC.ApiSystem"]
## ASC.ClearEvents ##
FROM dotnetrun AS clear-events

View File

@ -92,12 +92,12 @@ services:
target: api
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api:${DOCKER_TAG}"
# onlyoffice-api-system:
# build:
# context: ./
# dockerfile: "${DOCKERFILE}"
# target: api_system
# image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api-system:${DOCKER_TAG}"
onlyoffice-api-system:
build:
context: ./
dockerfile: "${DOCKERFILE}"
target: api_system
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api-system:${DOCKER_TAG}"
onlyoffice-studio:
build:

View File

@ -29,6 +29,7 @@ x-service: &x-service-base
- files_data:/var/www/products/ASC.Files/server/
- people_data:/var/www/products/ASC.People/server/
- ${ROOT_DIR}/config/appsettings.${ENV_EXTENSION}.json:/app/onlyoffice/config/appsettings.${ENV_EXTENSION}.json
- ${ROOT_DIR}/config/apisystem.${ENV_EXTENSION}.json:/app/onlyoffice/config/apisystem.${ENV_EXTENSION}.json
services:
onlyoffice-elasticsearch:
@ -116,10 +117,10 @@ services:
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api:${DOCKER_TAG}"
container_name: ${API_HOST}
# onlyoffice-api-system:
# <<: *x-service-base
# image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api-system:${DOCKER_TAG}"
# container_name: ${API_SYSTEM_HOST}
onlyoffice-api-system:
<<: *x-service-base
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api-system:${DOCKER_TAG}"
container_name: ${API_SYSTEM_HOST}
onlyoffice-studio:
<<: *x-service-base
@ -163,7 +164,7 @@ services:
# - onlyoffice-telegram-service
# - onlyoffice-urlshortener
- onlyoffice-api
# - onlyoffice-api-system
- onlyoffice-api-system
- onlyoffice-studio
- onlyoffice-ssoauth
environment:

View File

@ -84,6 +84,14 @@ Requires: dotnet-sdk-6.0
AutoReqProv: no
%description api
%package api-system
Summary: api-system
Group: Applications/Internet
Requires: %name-common = %version-%release
Requires: dotnet-sdk-6.0
AutoReqProv: no
%description api-system
%package ssoauth
Summary: ssoauth
Group: Applications/Internet

View File

@ -34,7 +34,7 @@ public abstract class BaseStartup
private const string BasicAuthScheme = "Basic";
private const string MultiAuthSchemes = "MultiAuthSchemes";
private readonly IConfiguration _configuration;
protected readonly IConfiguration _configuration;
private readonly IHostEnvironment _hostEnvironment;
private readonly string _corsOrigin;

View File

@ -248,6 +248,7 @@ public class DbTenantService : ITenantService
dbTenant.Industry = tenant.Industry;
dbTenant.Spam = tenant.Spam;
dbTenant.Calls = tenant.Calls;
dbTenant.OwnerId = tenant.OwnerId;
}
tenantDbContext.SaveChanges();

View File

@ -26,7 +26,7 @@
namespace ASC.Core.Notify.Socket;
[Singletone]
[Scope]
public class SocketServiceClient
{
private readonly TimeSpan _timeout = TimeSpan.FromSeconds(1);

View File

@ -15,6 +15,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\migrations\mysql\ASC.Migrations.MySql.csproj" />
<ProjectReference Include="..\..\..\web\ASC.Web.Api\ASC.Web.Api.csproj" />
</ItemGroup>

View File

@ -46,16 +46,15 @@ class ApiApplication : WebApplicationFactory<Program>
builder.UseSetting(s.Key, s.Value);
}
builder.ConfigureAppConfiguration((context, a) =>
{
(a.Sources[0] as ChainedConfigurationSource).Configuration["pathToConf"] = a.Build()["pathToConf"];
});
builder.ConfigureServices(services =>
{
services.AddBaseDbContext<UserDbContext>();
services.AddBaseDbContext<TenantDbContext>();
services.AddBaseDbContext<WebstudioDbContext>();
var DIHelper = new ASC.Common.DIHelper();
DIHelper.Configure(services);
foreach (var a in Assembly.Load("ASC.Files").GetTypes().Where(r => r.IsAssignableTo<ControllerBase>()))
foreach (var a in Assembly.Load("ASC.Web.Api").GetTypes().Where(r => r.IsAssignableTo<ControllerBase>()))
{
DIHelper.TryAdd(a);
}
@ -73,19 +72,18 @@ public class MySetUpClass
[OneTimeSetUp]
public void CreateDb()
{
var host = new ApiApplication(new Dictionary<string, string>
var args = new Dictionary<string, string>
{
{ "pathToConf", Path.Combine("..","..", "..", "config") },
{ "ConnectionStrings:default:connectionString", BaseApiTests.TestConnection },
{ "migration:enabled", "true" },
{ "core:products:folder", Path.Combine("..","..", "..", "products") },
{ "web:hub::internal", "" }
})
.WithWebHostBuilder(builder =>
{
});
Migrate(host.Services);
{ "web:hub::internal", "" },
{ "disableLdapNotifyService", "true" }
};
var host = new ApiApplication(args);
Migrate(host.Services, "ASC.Migrations.MySql");
host = new ApiApplication(args);
Migrate(host.Services, Assembly.GetExecutingAssembly().GetName().Name);
_scope = host.Services.CreateScope();
@ -99,18 +97,21 @@ public class MySetUpClass
}
private void Migrate(IServiceProvider serviceProvider, string testAssembly = null)
private void Migrate(IServiceProvider serviceProvider, string testAssembly )
{
using var scope = serviceProvider.CreateScope();
using var scope = serviceProvider.CreateScope();
var configuration = scope.ServiceProvider.GetService<IConfiguration>();
configuration["testAssembly"] = testAssembly;
if (!string.IsNullOrEmpty(testAssembly))
{
var configuration = scope.ServiceProvider.GetService<IConfiguration>();
configuration["testAssembly"] = testAssembly;
}
using var db = scope.ServiceProvider.GetService<IDbContextFactory<UserDbContext>>().CreateDbContext();
db.Database.Migrate();
using var userDbContext = scope.ServiceProvider.GetService<UserDbContext>();
userDbContext.Database.Migrate();
using var tenantDbContext = scope.ServiceProvider.GetService<TenantDbContext>();
tenantDbContext.Database.Migrate();
using var webstudioDbContext = scope.ServiceProvider.GetService<WebstudioDbContext>();
webstudioDbContext.Database.Migrate();
}
}
@ -131,10 +132,10 @@ class BaseApiTests
{
var host = new ApiApplication(new Dictionary<string, string>
{
{ "pathToConf", Path.Combine("..","..", "..", "config") },
{ "ConnectionStrings:default:connectionString", TestConnection },
{ "migration:enabled", "true" },
{ "web:hub:internal", "" }
{ "web:hub:internal", "" },
{ "disableLdapNotifyService", "true" }
})
.WithWebHostBuilder(a => { });

View File

@ -28,7 +28,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
namespace ASC.Core.Common.Migrations;
public partial class TestMigration : Microsoft.EntityFrameworkCore.Migrations.Migration
public partial class TestMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
@ -41,8 +41,8 @@ public partial class TestMigration : Microsoft.EntityFrameworkCore.Migrations.Mi
migrationBuilder.InsertData(
table: "core_user",
columns: new[] { "id", "activation_status", "bithdate", "contacts", "culture", "email", "firstname", "last_modified", "lastname", "location", "notes", "phone", "phone_activation", "removed", "sex", "sid", "sso_name_id", "sso_session_id", "status", "tenant", "terminateddate", "title", "username", "workfromdate" },
values: new object[] { "99223c7b-e3c9-11eb-9063-982cbc0ea1e5", 0, null, null, null, "test@gmail.com", "Test", new DateTime(2021, 8, 4, 11, 1, 4, 513, DateTimeKind.Utc).AddTicks(2928), "User", null, null, null, 0, false, null, null, null, null, 1, 1, null, null, "TestUser", new DateTime(2021, 8, 4, 11, 1, 4, 513, DateTimeKind.Utc).AddTicks(2940) });
columns: new[] { "id", "activation_status", "bithdate", "contacts", "culture", "email", "firstname", "last_modified", "lastname", "location", "notes", "phone", "phone_activation", "removed", "sex", "sid", "sso_name_id", "sso_session_id", "status", "tenant", "terminateddate", "title", "username", "workfromdate", "create_on" },
values: new object[] { "99223c7b-e3c9-11eb-9063-982cbc0ea1e5", 0, null, null, null, "test@gmail.com", "Test", new DateTime(2021, 8, 4, 11, 1, 4, 513, DateTimeKind.Utc).AddTicks(2928), "User", null, null, null, 0, false, null, null, null, null, 1, 1, null, null, "TestUser", new DateTime(2021, 8, 4, 11, 1, 4, 513, DateTimeKind.Utc).AddTicks(2940), DateTime.UtcNow });
migrationBuilder.InsertData(
table: "core_usersecurity",
@ -69,4 +69,4 @@ public partial class TestMigration : Microsoft.EntityFrameworkCore.Migrations.Mi
columns: new[] { "last_modified", "workfromdate" },
values: new object[] { new DateTime(2021, 8, 3, 21, 35, 0, 522, DateTimeKind.Utc).AddTicks(6893), new DateTime(2021, 8, 3, 21, 35, 0, 522, DateTimeKind.Utc).AddTicks(5587) });
}
}
}

View File

@ -82,7 +82,6 @@ class WizardTest : BaseApiTests
PasswordHash = passwordHash,
Lng = lng,
TimeZone = timeZone,
Promocode = promocode,
AmiId = amiid,
SubscribeFromSite = subscribeFromSite
};

View File

@ -16,6 +16,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\migrations\mysql\ASC.Migrations.MySql.csproj" />
<ProjectReference Include="..\..\ASC.Api.Core\ASC.Api.Core.csproj" />
<ProjectReference Include="..\..\services\ASC.Webhooks.Service\ASC.Webhooks.Service.csproj" />
</ItemGroup>

View File

@ -29,14 +29,18 @@ using System.IO;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using System.Threading.Tasks;
using ASC.Api.Core;
using ASC.Api.Core.Extensions;
using ASC.Common;
using ASC.Common.Caching;
using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.Core.Common.EF;
using ASC.Core.Common.EF.Context;
using ASC.Webhooks.Core;
using ASC.Webhooks.Core.EF.Context;
using ASC.Webhooks.Service;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@ -47,108 +51,119 @@ using Microsoft.Extensions.Hosting;
using NUnit.Framework;
namespace ASC.Webhooks.Tests
namespace ASC.Webhooks.Tests;
public class BaseSetUp
{
public class BaseSetUp
private IServiceProvider _serviceProvider;
protected IHost _host;
protected WebhookSender _webhookSender;
protected RequestHistory _requestHistory;
protected Settings _settings;
protected IHttpClientFactory _httpClientFactory;
protected string _testConnection = "Server=localhost;Database=onlyoffice_test;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True";
protected static int _port = 8867;
[OneTimeSetUp]
public async Task CreateDb()
{
private IServiceProvider serviceProvider;
protected IHost host;
protected WebhookSender webhookSender;
protected RequestHistory requestHistory;
protected Settings settings;
protected IHttpClientFactory httpClientFactory;
protected string TestConnection = "Server=localhost;Database=onlyoffice_test;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True";
protected static int port = 8867;
var args = new string[] {
"--pathToConf", Path.Combine( "..", "..", "..", "..", "..", "..", "config"),
"--ConnectionStrings:default:connectionString", _testConnection,
"--migration:enabled", "true"};
[OneTimeSetUp]
public async Task CreateDb()
{
var args = new string[] {
"--pathToConf", Path.Combine( "..", "..", "..", "..", "..", "..", "config"),
"--ConnectionStrings:default:connectionString", TestConnection,
"--migration:enabled", "true"};
await StartHost(args);
await StartHost(args);
Migrate(_serviceProvider, "ASC.Migrations.MySql");
Migrate(_serviceProvider, Assembly.GetExecutingAssembly().GetName().Name);
}
Migrate(serviceProvider);
Migrate(serviceProvider, Assembly.GetExecutingAssembly().GetName().Name);
}
[OneTimeTearDown]
public async Task DropDb()
{
var scope = _serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetService<IDbContextFactory<WebhooksDbContext>>().CreateDbContext();
context.Database.EnsureDeleted();
await _host.StopAsync();
}
[OneTimeTearDown]
public async Task DropDb()
{
var scope = serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetService<IDbContextFactory<WebhooksDbContext>>().CreateDbContext();
context.Database.EnsureDeleted();
await host.StopAsync();
}
private async Task StartHost(string[] args)
{
host = await Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
private async Task StartHost(string[] args)
{
IConfiguration configuration = null;
_host = await Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseKestrel(options =>
{
webBuilder
.UseKestrel(options =>
{
options.Listen(IPAddress.Loopback, port);
})
.ConfigureServices(services =>
{
services.AddControllers();
services.AddMemoryCache();
services.AddHttpClient();
var dIHelper = new DIHelper();
dIHelper.Configure(services);
dIHelper.TryAdd<DbWorker>();
dIHelper.TryAdd<TestController>();
dIHelper.TryAdd<WebhookSender>();
dIHelper.TryAdd(typeof(ICacheNotify<>), typeof(KafkaCacheNotify<>));
})
.Configure(app =>
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
});
})
options.Listen(IPAddress.Loopback, _port);
})
.ConfigureAppConfiguration((hostingContext, config) =>
{
var buided = config.Build();
var path = buided["pathToConf"];
configuration = config.Build();
var path = configuration["pathToConf"];
if (!Path.IsPathRooted(path))
{
path = Path.GetFullPath(CrossPlatform.PathCombine(hostingContext.HostingEnvironment.ContentRootPath, path));
}
config.SetBasePath(path);
config
.AddJsonFile("appsettings.json")
.AddCommandLine(args);
})
.StartAsync();
.ConfigureServices(services =>
{
services.AddControllers();
services.AddMemoryCache();
services.AddHttpClient();
services.AddScoped<EFLoggerFactory>();
services.AddBaseDbContextPool<WebhooksDbContext>();
services.AddBaseDbContextPool<TenantDbContext>();
services.AddBaseDbContextPool<UserDbContext>();
services.AddBaseDbContextPool<CoreDbContext>();
services.AddDistributedCache(configuration);
services.AddDistributedTaskQueue();
services.AddCacheNotify(configuration);
services.AddAutoMapper(BaseStartup.GetAutoMapperProfileAssemblies());
serviceProvider = host.Services;
webhookSender = serviceProvider.GetService<WebhookSender>();
requestHistory = serviceProvider.GetService<RequestHistory>();
settings = serviceProvider.GetService<Settings>();
httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();
}
private void Migrate(IServiceProvider serviceProvider, string testAssembly = null)
var dIHelper = new DIHelper();
dIHelper.Configure(services);
dIHelper.TryAdd<DbWorker>();
dIHelper.TryAdd<TestController>();
dIHelper.TryAdd<WebhookSender>();
dIHelper.TryAdd(typeof(ICacheNotify<>), typeof(KafkaCacheNotify<>));
})
.Configure(app =>
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
});
})
.StartAsync();
_serviceProvider = _host.Services;
_webhookSender = _serviceProvider.GetService<WebhookSender>();
_requestHistory = _serviceProvider.GetService<RequestHistory>();
_settings = _serviceProvider.GetService<Settings>();
_httpClientFactory = _serviceProvider.GetService<IHttpClientFactory>();
}
private void Migrate(IServiceProvider serviceProvider, string testAssembly = null)
{
if (!string.IsNullOrEmpty(testAssembly))
{
if (!string.IsNullOrEmpty(testAssembly))
{
var configuration = serviceProvider.GetService<IConfiguration>();
configuration["testAssembly"] = testAssembly;
}
using var db = serviceProvider.GetService<IDbContextFactory<WebhooksDbContext>>().CreateDbContext();
db.Database.Migrate();
var configuration = serviceProvider.GetService<IConfiguration>();
configuration["testAssembly"] = testAssembly;
}
using var db = serviceProvider.GetService<IDbContextFactory<WebhooksDbContext>>().CreateDbContext();
db.Database.Migrate();
}
}

View File

@ -27,6 +27,7 @@
using System;
using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
@ -59,120 +60,93 @@ namespace ASC.Webhooks.Tests
[TestFixture]
public class CommonWebhooksTests : BaseSetUp
{
private readonly string EventName = "testEvent";
private readonly string secretKey = "testSecretKey";
private readonly string content = JsonSerializer.Serialize("testContent");
private readonly string headers = JsonSerializer.Serialize(new { Host = new StringValues("localhost") });
private readonly string URI = $"http://localhost:{port}/api/2.0/Test/";
private readonly DateTime creationTime = DateTime.Now;
private readonly CacheNotifyAction testCacheNotifyAction = CacheNotifyAction.Update;
private readonly string _eventName = "testEvent";
private readonly string _secretKey = "testSecretKey";
private readonly string _content = "testContent";
private readonly string _contentSerialize = JsonSerializer.Serialize("testContent");
private readonly string _uri = $"http://localhost:{_port}/api/2.0/Test/";
private readonly DateTime _creationTime = DateTime.Now;
private readonly CacheNotifyAction _testCacheNotifyAction = CacheNotifyAction.Update;
[Order(1)]
[Test]
public void Publisher()
public async Task Publisher()
{
var scope = host.Services.CreateScope();
var scope = _host.Services.CreateScope();
var dbWorker = scope.ServiceProvider.GetService<DbWorker>();
var tenantManager = scope.ServiceProvider.GetService<TenantManager>();
var id = 1;
var testWebhookRequest = new WebhookRequest { Id = id };
var testTenant = new Tenant(1, "testWebhooksPublisher");
var testWebhookConfig = new WebhooksConfig()
{
SecretKey = secretKey,
TenantId = testTenant.Id,
Uri = URI
};
var testWebhooksEntry = new WebhookEntry()
{
Id = id,
Payload = content,
SecretKey = secretKey,
Uri = URI
};
try
{
tenantManager.SetCurrentTenant(testTenant);
dbWorker.AddWebhookConfig(testWebhookConfig);
await dbWorker.AddWebhookConfig(_eventName, _uri, _secretKey);
var mockedKafkaCaches = new Mock<ICacheNotify<WebhookRequest>>();
mockedKafkaCaches.Setup(a => a.Publish(testWebhookRequest, testCacheNotifyAction)).Verifiable();
mockedKafkaCaches.Setup(a => a.Publish(testWebhookRequest, _testCacheNotifyAction)).Verifiable();
var publisher = new WebhookPublisher(dbWorker, tenantManager, mockedKafkaCaches.Object);
publisher.Publish(EventName, content);
var publisher = new WebhookPublisher(dbWorker, mockedKafkaCaches.Object);
await publisher.PublishAsync(_eventName, "", _contentSerialize);
mockedKafkaCaches.Verify(a => a.Publish(testWebhookRequest, testCacheNotifyAction), Times.Once);
mockedKafkaCaches.Verify(a => a.Publish(testWebhookRequest, _testCacheNotifyAction), Times.Once);
}
catch (Exception ex)
{
Assert.Fail(ex.ToString());
}
Assert.AreEqual(dbWorker.ReadFromJournal(id), testWebhooksEntry);
Assert.AreEqual((await dbWorker.ReadJournal(id)).RequestPayload, _contentSerialize);
}
[Order(2)]
[Test]
public async Task Sender()
{
var scope = host.Services.CreateScope();
var scope = _host.Services.CreateScope();
var serviceProvider = scope.ServiceProvider;
var dbWorker = serviceProvider.GetService<DbWorker>();
var tenantManager = serviceProvider.GetService<TenantManager>();
var successedId = dbWorker.ConfigsNumber() + 1;
var failedId = successedId + 1;
var testTenant = new Tenant(2, "testWebhooksSender");
tenantManager.SetCurrentTenant(testTenant);
var successWebhookConfig = new WebhooksConfig { ConfigId = successedId, SecretKey = secretKey, Uri = $"{URI}SuccessRequest/" };
var failedWebhookConfig = new WebhooksConfig { ConfigId = failedId, SecretKey = secretKey, Uri = $"{URI}FailedRequest/" };
dbWorker.AddWebhookConfig(successWebhookConfig);
dbWorker.AddWebhookConfig(failedWebhookConfig);
var successedId = (await dbWorker.AddWebhookConfig(_eventName, $"{_uri}SuccessRequest/", _secretKey)).Id;
var failedId = (await dbWorker.AddWebhookConfig(_eventName, $"{_uri}FailedRequest/", _secretKey)).Id;
var successWebhookPayload = new WebhooksLog { ConfigId = successedId, Status = ProcessStatus.InProcess, CreationTime = creationTime, RequestPayload = content };
var failedWebhookPayload = new WebhooksLog { ConfigId = failedId, Status = ProcessStatus.InProcess, CreationTime = creationTime, RequestPayload = content };
var successWebhookPayloadId = dbWorker.WriteToJournal(successWebhookPayload);
var failedWebhookPayloadId = dbWorker.WriteToJournal(failedWebhookPayload);
var mockedLog = new Mock<ILoggerProvider>();
//mockedLog.Setup(a => a.Error(It.IsAny<string>())).Verifiable();
//var mockedLogOptions = new Mock<IOptionsMonitor<ILog>>();
//mockedLogOptions.Setup(a => a.Get("ASC.Webhooks.Core")).Returns(mockedLog.Object).Verifiable();
var successWebhookPayload = new WebhooksLog { ConfigId = successedId, Status = 200, CreationTime = _creationTime, RequestPayload = _contentSerialize };
var failedWebhookPayload = new WebhooksLog { ConfigId = failedId, Status = 400, CreationTime = _creationTime, RequestPayload = _contentSerialize };
var successWebhookPayloadId = (await dbWorker.WriteToJournal(successWebhookPayload)).Id;
var failedWebhookPayloadId = (await dbWorker.WriteToJournal(failedWebhookPayload)).Id;
var source = new CancellationTokenSource();
var token = source.Token;
var SuccessedWebhookRequest = new WebhookRequest { Id = successWebhookPayloadId };
var FailedWebhookRequest = new WebhookRequest { Id = failedWebhookPayloadId };
var FailedWebhookRequest = new WebhookRequest { Id = failedWebhookPayloadId };
var sender = new WebhookSender(mockedLog.Object, serviceProvider.GetRequiredService<IServiceScopeFactory>(), settings, httpClientFactory);
var sender = new WebhookSender(serviceProvider.GetService<ILoggerProvider>(), serviceProvider.GetRequiredService<IServiceScopeFactory>(), _httpClientFactory);
await sender.Send(SuccessedWebhookRequest, token);
await sender.Send(FailedWebhookRequest, token);
var asd = requestHistory.SuccessCounter;
Assert.IsTrue(requestHistory.SuccessCounter == 1, "Problem with successed request");
Assert.IsTrue(requestHistory.FailedCounter == webhookSender.RepeatCount, "Problem with failed request");
Assert.IsTrue(requestHistory.СorrectSignature, "Problem with signature");
Assert.IsTrue(_requestHistory.SuccessCounter == 1, "Problem with successed request");
Assert.IsTrue(_requestHistory.FailedCounter == 1, "Problem with failed request");
Assert.IsTrue(_requestHistory.СorrectSignature, "Problem with signature");
}
[Test]
public async Task GlobalFilter()
{
try
{
var controllerAddress = "api/2.0/Test/testMethod";
var getEventName = $"method: GET, route: {controllerAddress}";
var postEventName = $"method: POST, route: {controllerAddress}";
var mockedWebhookPubslisher = new Mock<IWebhookPublisher>();
mockedWebhookPubslisher.Setup(a => a.Publish(getEventName, content)).Verifiable();
mockedWebhookPubslisher.Setup(a => a.Publish(postEventName, content)).Verifiable();
mockedWebhookPubslisher.Setup(a => a.PublishAsync("GET", controllerAddress, _content)).Verifiable();
mockedWebhookPubslisher.Setup(a => a.PublishAsync("POST", controllerAddress, _content)).Verifiable();
using var host = await new HostBuilder()
@ -185,7 +159,7 @@ namespace ASC.Webhooks.Tests
services.AddSingleton(mockedWebhookPubslisher.Object);
services.AddControllers();
services.AddSingleton(new Action<JsonOptions>(opt => opt.JsonSerializerOptions.IgnoreNullValues = false));
services.AddSingleton(new Action<JsonOptions>(opt => opt.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.Never));
var dIHelper = new DIHelper();
dIHelper.Configure(services);
@ -211,12 +185,12 @@ namespace ASC.Webhooks.Tests
.StartAsync();
var getResponse = await host.GetTestClient().GetAsync(controllerAddress);
mockedWebhookPubslisher.Verify(a => a.Publish(getEventName, content), Times.Never);
mockedWebhookPubslisher.Verify(a => a.PublishAsync("GET", controllerAddress, _content), Times.Never);
StringContent stringContent = new StringContent(content);
var stringContent = new StringContent(_content);
var postResponse = await host.GetTestClient().PostAsync(controllerAddress, stringContent);
mockedWebhookPubslisher.Verify(a => a.Publish(postEventName, content), Times.Once);
mockedWebhookPubslisher.Verify(a => a.PublishAsync("POST", controllerAddress, _content), Times.Once);
}
catch (Exception ex)
{

View File

@ -31,16 +31,12 @@ public class FeedAggregatorService : FeedBaseService
{
protected override string LoggerName { get; set; } = "ASC.Feed.Aggregator";
private readonly SocketServiceClient _socketServiceClient;
public FeedAggregatorService(
FeedSettings feedSettings,
IServiceScopeFactory serviceScopeFactory,
ILoggerProvider optionsMonitor,
SocketServiceClient socketServiceClient)
ILoggerProvider optionsMonitor)
: base(feedSettings, serviceScopeFactory, optionsMonitor)
{
_socketServiceClient = socketServiceClient;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
@ -112,6 +108,7 @@ public class FeedAggregatorService : FeedBaseService
var userManager = scope.ServiceProvider.GetService<UserManager>();
var authManager = scope.ServiceProvider.GetService<AuthManager>();
var securityContext = scope.ServiceProvider.GetService<SecurityContext>();
var socketServiceClient = scope.ServiceProvider.GetRequiredService<SocketServiceClient>();
foreach (var module in modules)
{
@ -200,7 +197,7 @@ public class FeedAggregatorService : FeedBaseService
}
}
await _socketServiceClient.MakeRequest("sendUnreadUsers", unreadUsers);
await socketServiceClient.MakeRequest("sendUnreadUsers", unreadUsers);
_logger.DebugTimeCollectingNews(DateTime.UtcNow - start);
}

49
config/apisystem.dev.json Normal file
View File

@ -0,0 +1,49 @@
{
"core": {
"base-domain": "localhost",
"machinekey": "your_core_machinekey",
"notify": {
"postman": "log"
},
"payment-partners": "",
"username": {
"regex": "^[\\p{L}\\p{M}' \\-]+$"
}
},
"web": {
"alias": {
"min": 3
},
"api-cache": "",
"autotest": {
"secret-email": ""
},
"app": {
"keys": ""
}
},
"recaptcha": {
"required": false,
"private-key": {
"default": "",
"android": "",
"ios": ""
}
},
"auth": {
"allowskip": {
"default": false,
"registerportal": true
}
},
"ConnectionStrings": {
"default": {
"name": "default",
"connectionString": "Server=onlyoffice-mysql-server;Port=3306;Database=onlyoffice;User ID=onlyoffice_user;Password=onlyoffice_pass;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;ConnectionReset=false",
"providerName": "MySql.Data.MySqlClient"
}
},
"quota": {
"id": -3
}
}

View File

@ -249,15 +249,18 @@ server {
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
}
location /products {
location ~* /files {
location ~* (/httphandlers/filehandler.ashx|ChunkedUploader.ashx) {
proxy_pass http://127.0.0.1:5007;
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
}
}
location /filehandler.ashx {
proxy_pass http://127.0.0.1:5007;
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
}
location /ChunkedUploader.ashx {
proxy_pass http://127.0.0.1:5007;
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
}
location /Products {
location ~* /Files {
rewrite ^/Products/Files(.*)$ $1 redirect;

View File

@ -10,6 +10,7 @@
"InviteUsersToRoom": "Invite users to room",
"Invited": "Invited",
"LinkCopySuccess": "Link has been copied",
"SearchPlaceholder": "Invite people by name or email",
"InviteRoomSearchPlaceholder": "Invite people by name or email",
"InviteAccountSearchPlaceholder": "Invite people by email",
"SendInvitation": "Send invitation"
}

View File

@ -3,6 +3,7 @@ import { inject, observer } from "mobx-react";
import { useTranslation } from "react-i18next";
import { CreateRoomDialog } from "../dialogs";
import { toastr } from "@docspace/components";
import { isMobile } from "react-device-detect";
const CreateRoomEvent = ({
visible,
@ -38,7 +39,7 @@ const CreateRoomEvent = ({
setView("info_members");
fetchFiles(id)
.then(() => {
setInfoPanelIsVisible(true);
!isMobile && setInfoPanelIsVisible(true);
})
.finally(() => {
setIsLoading(false);

View File

@ -35,9 +35,9 @@ const DeleteDialogComponent = (props) => {
const item = props.selection[i];
if (!item?.isEditing) {
if (item?.access === 0 || item?.access === 1 || unsubscribe) {
selection.push(item);
}
// if (item?.access === 0 || item?.access === 1 || unsubscribe) {
selection.push(item);
// }
}
i++;
}

View File

@ -49,7 +49,7 @@ const StyledSubHeader = styled(Heading)`
font-size: 16px;
padding-left: 16px;
padding-right: 16px;
margin: 20px 0;
margin: 16px 0;
${(props) =>
props.inline &&

View File

@ -97,12 +97,15 @@ const InviteInput = ({
const value = e.target.value;
const clearValue = value.trim();
if ((!!usersList.length || clearValue.length > 1) && !searchPanelVisible) {
if ((!!usersList.length || clearValue.length > 2) && !searchPanelVisible) {
openInviteInputPanel();
}
setInputValue(value);
debouncedSearch(clearValue);
if (roomId !== -1) {
debouncedSearch(clearValue);
}
};
const removeExist = (items) => {
@ -238,33 +241,39 @@ const InviteInput = ({
<TextInput
scale
onChange={onChange}
placeholder={t("SearchPlaceholder")}
placeholder={
roomId === -1
? t("InviteAccountSearchPlaceholder")
: t("InviteRoomSearchPlaceholder")
}
value={inputValue}
onFocus={openInviteInputPanel}
/>
</StyledInviteInput>
<StyledDropDown
width={searchRef?.current?.offsetWidth}
isDefaultMode={false}
open={searchPanelVisible}
manualX="16px"
showDisabledItems
clickOutsideAction={closeInviteInputPanel}
{...dropDownMaxHeight}
>
{!!usersList.length
? foundUsers
: inputValue.length > 2 && (
<DropDownItem
style={{ width: "inherit" }}
textOverflow
onClick={addEmail}
height={48}
>
{t("Add")} «{inputValue}»
</DropDownItem>
)}
</StyledDropDown>
{inputValue.length > 2 && (
<StyledDropDown
width={searchRef?.current?.offsetWidth}
isDefaultMode={false}
open={searchPanelVisible}
manualX="16px"
showDisabledItems
clickOutsideAction={closeInviteInputPanel}
{...dropDownMaxHeight}
>
{!!usersList.length ? (
foundUsers
) : (
<DropDownItem
style={{ width: "inherit" }}
textOverflow
onClick={addEmail}
height={48}
>
{t("Add")} «{inputValue}»
</DropDownItem>
)}
</StyledDropDown>
)}
<AccessSelector
t={t}

View File

@ -21,7 +21,6 @@ class PeopleTableHeader extends React.Component {
enable: true,
default: true,
sortBy: "AZ",
active: true,
minWidth: 210,
onClick: this.onFilter,
onIconClick: this.onIconClick,
@ -30,8 +29,10 @@ class PeopleTableHeader extends React.Component {
key: "Type",
title: t("Common:Type"),
enable: true,
sortBy: "type",
resizable: true,
onChange: this.onColumnChange,
onClick: this.onFilter,
},
// {
// key: "Room",
@ -45,7 +46,9 @@ class PeopleTableHeader extends React.Component {
title: t("Common:Email"),
enable: true,
resizable: true,
sortBy: "email",
onChange: this.onColumnChange,
onClick: this.onFilter,
},
];
@ -88,32 +91,43 @@ class PeopleTableHeader extends React.Component {
localStorage.setItem(`${TABLE_COLUMNS}=${this.props.userId}`, tableColumns);
};
onFilter = () => {
onFilter = (sortBy) => {
const { filter, setIsLoading, fetchPeople } = this.props;
const newFilter = filter.clone();
if (newFilter.sortBy === "lastname") {
newFilter.sortBy = "firstname";
if (newFilter.sortBy === sortBy && sortBy !== "AZ") {
newFilter.sortOrder =
newFilter.sortOrder === "ascending" ? "descending" : "ascending";
} else {
newFilter.sortBy = "lastname";
newFilter.sortBy = sortBy;
if (sortBy === "AZ") {
if (
newFilter.sortBy !== "lastname" &&
newFilter.sortBy !== "firstname"
) {
newFilter.sortBy = "firstname";
} else if (newFilter.sortBy === "lastname") {
newFilter.sortBy = "firstname";
} else {
newFilter.sortBy = "lastname";
}
}
}
setIsLoading(true);
fetchPeople(newFilter).finally(() => setIsLoading(false));
fetchPeople(newFilter, true).finally(() => setIsLoading(false));
};
onIconClick = () => {
const { filter, setIsLoading, fetchPeople } = this.props;
const newFilter = filter.clone();
if (newFilter.sortOrder === "ascending") {
newFilter.sortOrder = "descending";
} else {
newFilter.sortOrder = "ascending";
}
newFilter.sortOrder =
newFilter.sortOrder === "ascending" ? "descending" : "ascending";
setIsLoading(true);
fetchPeople(newFilter).finally(() => setIsLoading(false));
fetchPeople(newFilter, true).finally(() => setIsLoading(false));
};
render() {
@ -129,10 +143,16 @@ class PeopleTableHeader extends React.Component {
} = this.props;
const { sortOrder } = filter;
const sortBy =
filter.sortBy === "firstname" || filter.sortBy === "lastname"
? "AZ"
: filter.sortBy;
return (
<TableHeader
checkboxSize="48px"
sorted={sortOrder === "descending"}
sortBy={sortBy}
containerRef={containerRef}
columns={columns}
columnStorageName={columnStorageName}

View File

@ -258,6 +258,12 @@ const SectionFilterContent = ({
label: t("Common:Type"),
default: true,
},
{
id: "sory-by_email",
key: "email",
label: t("Common:Email"),
default: true,
},
];
}, [t]);

View File

@ -2,15 +2,26 @@ import React, { useEffect } from "react";
import { withRouter } from "react-router";
import Loader from "@docspace/components/loader";
import Section from "@docspace/common/components/Section";
import { combineUrl } from "@docspace/common/utils";
import tryRedirectTo from "@docspace/common/utils/tryRedirectTo";
import { AppServerConfig } from "@docspace/common/constants";
import { loginWithConfirmKey } from "@docspace/common/api/user";
import toastr from "@docspace/components/toast/toastr";
const Auth = (props) => {
console.log("Auth render");
const { linkData } = props;
useEffect(() => {
tryRedirectTo(combineUrl(AppServerConfig.proxyURL, `/login`));
loginWithConfirmKey({
ConfirmData: {
Email: linkData.email,
Key: linkData.confirmHeader,
},
})
.then((res) => {
console.log("Login with confirm key success", res);
if (typeof res === "string") window.location.replace(res);
else window.location.replace("/");
})
.catch((error) => toastr.error(error));
});
return <Loader className="pageLoader" type="rombs" size="40px" />;

View File

@ -84,6 +84,23 @@ const StyledUser = styled.div`
props.theme.infoPanel.members.disabledRoleSelectorColor};
}
}
.role-view_remove-icon {
cursor: pointer;
svg {
path {
fill: ${(props) => props.theme.iconButton.color};
}
}
:hover {
svg {
path {
fill: ${(props) => props.theme.iconButton.hoverColor};
}
}
}
}
`;
StyledUserTypeHeader.defaultProps = { theme: Base };

View File

@ -4,6 +4,8 @@ import { StyledUser } from "../../styles/members";
import Avatar from "@docspace/components/avatar";
import { ComboBox } from "@docspace/components";
import { ReactSVG } from "react-svg";
import { FolderType } from "@docspace/common/constants";
const User = ({
t,
user,
@ -84,6 +86,29 @@ const User = ({
}
};
const isArchiveRoot = rootFolderType === FolderType.Archive;
const changingMemberInfo = isArchiveRoot ? (
<ReactSVG
className="role-view_remove-icon"
src="images/remove.session.svg"
onClick={() => onOptionClick({ key: "remove" })}
/>
) : (
<ComboBox
className="role-combobox"
selectedOption={userRole}
options={userRoleOptions}
onSelect={onOptionClick}
scaled={false}
withBackdrop={false}
size="content"
modernView
title={t("Common:Role")}
manualWidth={"fit-content"}
/>
);
return (
<StyledUser isExpect={isExpect} key={user.id}>
<Avatar
@ -104,18 +129,7 @@ const User = ({
{userRole && userRoleOptions && (
<div className="role-wrapper">
{canChangeUserRole || canDeleteUser ? (
<ComboBox
className="role-combobox"
selectedOption={userRole}
options={userRoleOptions}
onSelect={onOptionClick}
scaled={false}
withBackdrop={false}
size="content"
modernView
title={t("Common:Role")}
manualWidth={"fit-content"}
/>
changingMemberInfo
) : (
<div className="disabled-role-combobox" title={t("Common:Role")}>
{userRole.label}

View File

@ -85,6 +85,11 @@ const InterfaceTheme = (props) => {
};
const isSystemTheme = currentTheme === ThemeKeys.SystemStr;
const systemThemeValue =
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
? ThemeKeys.DarkStr
: ThemeKeys.BaseStr;
return (
<StyledWrapper>
@ -111,7 +116,10 @@ const InterfaceTheme = (props) => {
accentColor={currentColorScheme.main.accent}
themeId={selectedThemeId}
value={ThemeKeys.BaseStr}
isChecked={currentTheme === ThemeKeys.BaseStr}
isChecked={
currentTheme === ThemeKeys.BaseStr ||
(isSystemTheme && systemThemeValue === ThemeKeys.BaseStr)
}
onChangeTheme={onChangeTheme}
/>
<ThemePreview
@ -121,7 +129,10 @@ const InterfaceTheme = (props) => {
accentColor={currentColorScheme.main.accent}
themeId={selectedThemeId}
value={ThemeKeys.DarkStr}
isChecked={currentTheme === ThemeKeys.DarkStr}
isChecked={
currentTheme === ThemeKeys.DarkStr ||
(isSystemTheme && systemThemeValue === ThemeKeys.DarkStr)
}
onChangeTheme={onChangeTheme}
/>
</div>

View File

@ -89,13 +89,11 @@ const LanguagesCombo = (props) => {
/>
</Text>
<ComboBox
className="combo"
directionY="both"
options={cultureNames}
selectedOption={selectedLanguage}
onSelect={onLanguageSelect}
isDisabled={false}
noBorder={!isMobileOnly}
scaled={isMobileOnly}
scaledOptions={false}
size="content"
@ -105,6 +103,7 @@ const LanguagesCombo = (props) => {
isDefaultMode={!isMobileOnly}
withBlur={isMobileOnly}
fillIcon={false}
modernView={!isMobileOnly}
/>
</StyledRow>
);

View File

@ -206,12 +206,7 @@ export const StyledRow = styled.div`
@media ${desktop} {
height: 28px;
}
.combo {
& > div {
justify-content: flex-start !important;
}
align-items: center;
}
.label {

View File

@ -1260,7 +1260,6 @@ class FilesActionStore {
isAvailableOption = (option) => {
const {
isAccessedSelected,
canConvertSelected,
hasSelection,
allFilesIsEditing,
@ -1292,7 +1291,7 @@ class FilesActionStore {
rootFolderType,
editing: allFilesIsEditing,
});
return hasSelection && isAccessedSelected && canMove;
return hasSelection && canMove;
case "archive":
case "unarchive":
@ -1314,9 +1313,8 @@ class FilesActionStore {
rootFolderType,
editing: allFilesIsEditing,
});
const deleteCondition = hasSelection && isAccessedSelected;
return canDelete && deleteCondition;
return canDelete && hasSelection;
}
};

View File

@ -63,3 +63,12 @@ export function loginWithTfaCode(userName, passwordHash, code) {
data,
});
}
export function loginWithConfirmKey(data) {
return request({
method: "post",
url: `/authentication.json`,
skipLogout: true,
data,
});
}

View File

@ -1,4 +1,5 @@
import styled, { css } from "styled-components";
import { isMobileOnly } from "react-device-detect";
import Base from "../../themes/base";
import NoUserSelect from "../../utils/commonStyles";
@ -218,6 +219,11 @@ const StyledArrowIcon = styled.div`
`
transform: scale(1, -1);
`}
${isMobileOnly &&
css`
margin-left: auto;
`}
`;
StyledArrowIcon.defaultProps = { theme: Base };

View File

@ -129,6 +129,7 @@ const StyledDropdownItem = styled.div`
props.isActive &&
css`
transform: rotate(90deg);
height: auto;
`}
}

View File

@ -1,6 +1,7 @@
import React from "react";
import styled from "styled-components";
import PropTypes from "prop-types";
import { mobile } from "../../utils/device";
const StyledModalBackdrop = styled.div.attrs((props) => ({
style: {
@ -26,12 +27,16 @@ const StyledModalBackdrop = styled.div.attrs((props) => ({
min-height: fill-available;
max-height: 100vh;
width: 100vw;
overflow: hidden;
position: fixed;
left: 0;
top: 0;
z-index: ${(props) => props.zIndex};
@media ${mobile} {
position: absolute;
}
transition: 0.2s;
opacity: 0;
&.modal-backdrop-active {

View File

@ -488,10 +488,10 @@ const Dark = {
marginRight: "8px",
background: "#292929",
disableBackground: "#646464",
disableBackground: "#545454",
fillColor: grayMaxLight,
disableFillColor: "#646464",
disableFillColor: "#474747",
borderColor: "#646464",
disableBorderColor: "none",

View File

@ -29,7 +29,7 @@ namespace ASC.Web.Files.Configuration;
[Scope]
public class ProductEntryPoint : Product
{
internal const string ProductPath = "/products/files/";
internal const string ProductPath = "/";
private readonly FilesSpaceUsageStatManager _filesSpaceUsageStatManager;
private readonly CoreBaseSettings _coreBaseSettings;

View File

@ -29,7 +29,7 @@ namespace ASC.Files.Core.Helpers;
[Scope]
public class FilesLinkUtility
{
public const string FilesBaseVirtualPath = "~/products/files/";
public const string FilesBaseVirtualPath = "~/";
public const string EditorPage = "doceditor";
private readonly string _filesUploaderURL;
@ -77,7 +77,7 @@ public class FilesLinkUtility
public string FileHandlerPath
{
get { return FilesBaseAbsolutePath + "httphandlers/filehandler.ashx"; }
get { return FilesBaseAbsolutePath + "filehandler.ashx"; }
}
public string DocServiceUrl
@ -276,24 +276,11 @@ public class FilesLinkUtility
get { return $"{FileWebEditorUrlString}&{Action}=view"; }
}
public string GetFileWebViewerUrlForMobile(object fileId, int fileVersion)
{
var viewerUrl = _commonLinkUtility.ToAbsolute("~/../products/files/") + EditorPage + "?" + FileId + "={0}";
return string.Format(viewerUrl, HttpUtility.UrlEncode(fileId.ToString()))
+ (fileVersion > 0 ? "&" + Version + "=" + fileVersion : string.Empty);
}
public string FileWebViewerExternalUrlString
{
get { return FilesBaseAbsolutePath + EditorPage + "?" + FileUri + "={0}&" + FileTitle + "={1}&" + FolderUrl + "={2}"; }
}
public string GetFileWebViewerExternalUrl(string fileUri, string fileTitle, string refererUrl = "")
{
return string.Format(FileWebViewerExternalUrlString, HttpUtility.UrlEncode(fileUri), HttpUtility.UrlEncode(fileTitle), HttpUtility.UrlEncode(refererUrl));
}
public string FileWebEditorUrlString
{
get { return $"/{EditorPage}?{FileId}={{0}}"; }

View File

@ -30,9 +30,7 @@ namespace ASC.Web.Files.Classes;
public class PathProvider
{
public static readonly string ProjectVirtualPath = "~/Products/Projects/TMDocs.aspx";
public static readonly string TemplatePath = "/Products/Files/Templates/";
public static readonly string StartURL = FilesLinkUtility.FilesBaseVirtualPath;
public readonly string GetFileServicePath;
private readonly WebImageSupplier _webImageSupplier;
private readonly IDaoFactory _daoFactory;
@ -58,7 +56,6 @@ public class PathProvider
_emailValidationKeyProvider = emailValidationKeyProvider;
_globalStore = globalStore;
_baseCommonLinkUtility = baseCommonLinkUtility;
GetFileServicePath = _baseCommonLinkUtility.ToAbsolute("~/Products/Files/Services/WCFService/service.svc/");
}
public string GetImagePath(string imgFileName)
@ -66,26 +63,6 @@ public class PathProvider
return _webImageSupplier.GetAbsoluteWebPath(imgFileName, ProductEntryPoint.ID);
}
public string GetFileStaticRelativePath(string fileName)
{
var ext = FileUtility.GetFileExtension(fileName);
return ext switch
{
//Attention: Only for ResourceBundleControl
".js" => VirtualPathUtility.ToAbsolute("~/Products/Files/js/" + fileName),
".ascx" => _baseCommonLinkUtility.ToAbsolute("~/Products/Files/Controls/" + fileName),
//Attention: Only for ResourceBundleControl
".css" => VirtualPathUtility.ToAbsolute("~/Products/Files/App_Themes/default/" + fileName),
_ => fileName,
};
}
public string GetFileControlPath(string fileName)
{
return _baseCommonLinkUtility.ToAbsolute("~/Products/Files/Controls/" + fileName);
}
public async Task<string> GetFolderUrlAsync<T>(Folder<T> folder, int projectID = 0)
{
if (folder == null)

View File

@ -43,7 +43,7 @@ public class DocuSignHandlerService
{
public static string Path(FilesLinkUtility filesLinkUtility)
{
return filesLinkUtility.FilesBaseAbsolutePath + "httphandlers/docusignhandler.ashx";
return filesLinkUtility.FilesBaseAbsolutePath + "docusignhandler.ashx";
}
private readonly ILogger<DocuSignHandlerService> _log;

View File

@ -224,7 +224,6 @@ abstract class FileOperation<T, TId> : FileOperation where T : FileOperationData
var (tenantManager, daoFactory, fileSecurity, logger) = scopeClass;
tenantManager.SetCurrentTenant(CurrentTenant);
Thread.CurrentPrincipal = _principal;
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(_culture);
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(_culture);

View File

@ -75,7 +75,7 @@ public class Startup : BaseStartup
base.Configure(app, env);
app.MapWhen(
context => context.Request.Path.ToString().EndsWith("httphandlers/filehandler.ashx", StringComparison.OrdinalIgnoreCase),
context => context.Request.Path.ToString().EndsWith("filehandler.ashx", StringComparison.OrdinalIgnoreCase),
appBranch =>
{
appBranch.UseFileHandler();
@ -96,7 +96,7 @@ public class Startup : BaseStartup
});
app.MapWhen(
context => context.Request.Path.ToString().EndsWith("httphandlers/DocuSignHandler.ashx", StringComparison.OrdinalIgnoreCase),
context => context.Request.Path.ToString().EndsWith("DocuSignHandler.ashx", StringComparison.OrdinalIgnoreCase),
appBranch =>
{
appBranch.UseDocuSignHandler();

View File

@ -41,6 +41,7 @@ global using ASC.Core.Common;
global using ASC.Core.Common.EF;
global using ASC.Core.Common.Hosting;
global using ASC.Core.Common.Hosting.Interfaces;
global using ASC.Core.Notify.Socket;
global using ASC.Core.Tenants;
global using ASC.ElasticSearch;
global using ASC.ElasticSearch.Service;

View File

@ -91,6 +91,7 @@ public class Startup : BaseWorkerStartup
DIHelper.TryAdd<SecurityContext>();
DIHelper.TryAdd<TenantManager>();
DIHelper.TryAdd<UserManager>();
DIHelper.TryAdd<SocketServiceClient>();
services.AddBaseDbContextPool<FilesDbContext>();

View File

@ -31,7 +31,6 @@
<PackageReference Include="Moq" Version="4.14.7" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
<PackageReference Include="NEST" Version="7.15.2" />
<PackageReference Include="NLog" Version="5.0.1" />
<PackageReference Include="nunit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
@ -48,7 +47,6 @@
<ProjectReference Include="..\..\..\common\services\ASC.ElasticSearch\ASC.ElasticSearch.csproj" />
<ProjectReference Include="..\..\..\migrations\mysql\ASC.Migrations.MySql.csproj" />
<ProjectReference Include="..\..\..\web\ASC.Web.Core\ASC.Web.Core.csproj" />
<ProjectReference Include="..\..\ASC.People\Server\ASC.People.csproj" />
<ProjectReference Include="..\Core\ASC.Files.Core.csproj" />
<ProjectReference Include="..\Server\ASC.Files.csproj" />
</ItemGroup>

View File

@ -27,7 +27,9 @@
using ASC.Files.Core.EF;
using ASC.MessagingSystem.Core;
using ASC.MessagingSystem.EF.Context;
using ASC.Web.Core;
using ASC.Webhooks.Core.EF.Context;
using Microsoft.EntityFrameworkCore;
@ -50,11 +52,6 @@ class FilesApplication : WebApplicationFactory<Program>
builder.UseSetting(s.Key, s.Value);
}
builder.ConfigureAppConfiguration((context, a) =>
{
(a.Sources[0] as ChainedConfigurationSource).Configuration["pathToConf"] = a.Build()["pathToConf"];
});
builder.ConfigureServices(services =>
{
services.AddBaseDbContext<UserDbContext>();
@ -86,7 +83,6 @@ public class MySetUpClass
{
var args = new Dictionary<string, string>
{
{ "pathToConf", Path.Combine("..","..", "..", "config") },
{ "ConnectionStrings:default:connectionString", BaseFilesTests.TestConnection },
{ "migration:enabled", "true" },
{ "core:products:folder", Path.Combine("..", "..", "..", "products") },
@ -175,7 +171,6 @@ public partial class BaseFilesTests
{
var host = new FilesApplication(new Dictionary<string, string>
{
{ "pathToConf", Path.Combine("..","..", "..", "config") },
{ "ConnectionStrings:default:connectionString", TestConnection },
{ "migration:enabled", "true" },
{ "web:hub:internal", "" },
@ -197,8 +192,9 @@ public partial class BaseFilesTests
var tenant = tenantManager.GetTenant(1);
tenantManager.SetCurrentTenant(tenant);
var securityContext = scope.ServiceProvider.GetService<SecurityContext>();
_cookie = securityContext.AuthenticateMe(tenant.OwnerId);
var _cookiesManager = scope.ServiceProvider.GetService<CookiesManager>();
var action = MessageAction.LoginSuccessViaApi;
_cookie = _cookiesManager.AuthenticateMeAndSetCookies(tenant.Id, tenant.OwnerId, action);
_client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _cookie);
_client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

View File

@ -1,68 +0,0 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Files.Tests;
[TestFixture]
public partial class BaseFilesTests
{
[TestCase(DataTests.FileIdForRecent, DataTests.FileNameForRecent)]
[Category("File")]
[Order(1)]
[Description("post - file/{fileId}/recent - add file to recent")]
public async Task RecentFileReturnsFolderWrapper(int fileId, string fileName)
{
var file = await PostAsync<FileDto<int>>($"file/{fileId}/recent");
Assert.IsNotNull(file);
Assert.AreEqual(fileName, file.Title);
}
[TestCase(DataTests.FileIdForRecent, DataTests.FileNameForRecent)]
[Category("File")]
[Order(2)]
[Description("delete - file/{fileId}/recent - delete file which added to recent")]
public async Task DeleteRecentFileReturnsFolderWrapper(int fileId, string fileTitleExpected)
{
await PostAsync<FileDto<int>>($"file/{fileId}/recent");
await DeleteAsync($"file/{fileId}", new { DeleteAfter = false, Immediately = true });
await WaitLongOperation();
var recents = await GetAsync<FolderContentDto<int>>("@recent");
Assert.IsTrue(!recents.Files.Any(r => r.Title == fileTitleExpected + ".docx"));
}
[TestCase(DataTests.SharedForReadFileId, DataTests.FileName)]
[Category("File")]
[Order(3)]
public async Task ShareFileToAnotherUserAddToRecent(int fileId, string fileName)
{
var file = await PostAsync<FileDto<int>>($"file/{fileId}/recent");
Assert.IsNotNull(file);
Assert.AreEqual(fileName, file.Title);
}
}

View File

@ -157,33 +157,6 @@ public partial class BaseFilesTests
{
var folder = await PutAsync<FolderDto<int>>($"rooms/{id}/unpin");
Assert.IsFalse(folder.Pinned);
}
[TestCase(DataTests.RoomId, DataTests.Email)]
[Category("Room")]
[Order(13)]
[Description("put - rooms/{id}/links/send - send invitation links to email")]
public async Task SendLink(int id, string email)
{
var invites = await PutAsync<IEnumerable<InviteResultDto>>($"rooms/{id}/links/send", new { Emails = new List<string>() { email }, EmployeeType = EmployeeType.All, Access = Core.Security.FileShare.Read });
Assert.IsTrue(invites.First().Success);
}
[TestCase(DataTests.RoomId)]
[Category("Room")]
[Order(15)]
[Description("get - rooms/{id}/links - get invitation links /// put - rooms/{id}/share - share a room by link")]
public async Task GetLinkAndShareRoomByLink(int id)
{
var invite = await GetAsync<string>($"rooms/{id}/links?access=2");
Assert.IsNotNull(invite);
Assert.IsNotEmpty(invite);
var key = invite.Substring(invite.IndexOf("&key=") + 5);
key = key.Substring(0, key.IndexOf('&'));
var share = await PutAsync<IEnumerable<FileShareDto>>($"rooms/{id}/share", new { Access = Core.Security.FileShare.Read, Key = key });
Assert.IsNotNull(share);
}
//[TestCase(DataTests.RoomId, DataTests.Image)]

View File

@ -1,200 +0,0 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Files.Tests;
[TestFixture]
public partial class BaseFilesTests
{
private IEnumerable<FileShareParams> _testFolderParamRead;
private IEnumerable<FileShareParams> _testFolderParamReadAndWrite;
[OneTimeSetUp]
public void SetUp()
{
var newUser = _userManager.GetUsers(Guid.Parse("005bb3ff-7de3-47d2-9b3d-61b9ec8a76a5"));
_testFolderParamRead = new List<FileShareParams> { new FileShareParams { Access = Core.Security.FileShare.Read, ShareTo = newUser.Id } };
_testFolderParamReadAndWrite = new List<FileShareParams> { new FileShareParams { Access = Core.Security.FileShare.ReadWrite, ShareTo = newUser.Id } };
}
#region Shared Folder and File (Read)
[TestCase(DataTests.SubFolderId, DataTests.Notify, DataTests.Message)]
[Category("Folder Read")]
[Order(2)]
[Description("put - files/folder/{folderId}/share - share folder to another user for read")]
public async Task ShareFolderToAnotherUserRead(int folderId, bool notify, string message)
{
var share = await PutAsync<IEnumerable<FileShareDto>>($"folder/{folderId}/share", new { Share = _testFolderParamRead, Notify = notify, SharingMessage = message });
Assert.IsNotNull(share);
}
[TestCase(DataTests.SharedForReadFolderId)]
[Category("Folder Read")]
[Order(4)]
[Description("put - files/folder/{folderId} - try to update folder which can only read")]
public async Task RenameSharedFolderReturnsFolderWrapperReadAsync(int folderId)
{
var result = await SendAsync(HttpMethod.Put, "folder/" + folderId, new { Title = "newName" });
Assert.AreEqual(HttpStatusCode.Forbidden, result.StatusCode);
}
[TestCase(DataTests.FileId, DataTests.Notify, DataTests.Message)]
[Category("File Read")]
[Order(7)]
[Description("put - file/{fileId}/share - share file to another user for read")]
public async Task ShareFileToAnotherUserRead(int fileId, bool notify, string message)
{
var share = await PutAsync<IEnumerable<FileShareDto>>($"file/{fileId}/share", new { Share = _testFolderParamRead, Notify = notify, SharingMessage = message });
Assert.IsNotNull(share);
}
[TestCase(DataTests.SharedForReadFileId)]
[Category("File Read")]
[Order(9)]
[Description("put - files/file/{fileId} - try to update file which can only read")]
public async Task UpdateSharedFileReturnsFolderWrapperReadAsync(int fileId)
{
var result = await SendAsync(HttpMethod.Put, "file/" + fileId, new { Title = "newName", LastVersion = 0 });
Assert.That(HttpStatusCode.Forbidden == result.StatusCode);
}
#endregion
#region Shared Folder and File (Read and Write)
[TestCase(DataTests.SubFolderId, DataTests.Notify, DataTests.Message)]
[Category("Folder Read and Write")]
[Order(11)]
[Description("put - files/folder/{folderId}/share - share folder to another user for read and write")]
public async Task ShareFolderToAnotherUserReadAndWrite(int folderId, bool notify, string message)
{
var share = await PutAsync<IEnumerable<FileShareDto>>($"folder/{folderId}/share", new { Share = _testFolderParamReadAndWrite, Notify = notify, SharingMessage = message });
Assert.IsNotNull(share);
}
[TestCase(DataTests.SharedForReadAndWriteFolderId, DataTests.NewTitle)]
[Category("Folder Read and Write")]
[Order(13)]
[Description("put - files/folder/{folderId} - rename shared for read and write folder")]
public async Task RenameSharedFolderReturnsFolderWrapperReadAndWrite(int folderId, string newTitle)
{
var sharedFolder = await PutAsync<FolderDto<int>>($"folder/{folderId}", new { Title = newTitle });
Assert.IsNotNull(sharedFolder);
Assert.AreEqual(newTitle, sharedFolder.Title);
}
[TestCase(DataTests.FileId, DataTests.Notify, DataTests.Message)]
[Category("File Read and Write")]
[Order(15)]
[Description("put - files/file/{fileId}/share - share file to another user for read and write")]
public async Task ShareFileToAnotherUserReadAndWrite(int fileId, bool notify, string message)
{
var share = await PutAsync<IEnumerable<FileShareDto>>($"file/{fileId}/share", new { Share = _testFolderParamReadAndWrite, Notify = notify, SharingMessage = message });
Assert.IsNotNull(share);
}
[TestCase(DataTests.SharedForReadAndWriteFileId, DataTests.NewTitle, 0)]
[Category("File Read and Write")]
[Order(17)]
[Description("put - files/file/{fileId} - update shared for read and write file")]
public async Task UpdateSharedFileReturnsFolderWrapperReadAndWrite(int fileId, string fileTitle, int lastVersion)
{
var sharedFile = await PutAsync<FolderDto<int>>($"file/{fileId}", new { Title = fileTitle, LastVersion = lastVersion });
Assert.IsNotNull(sharedFile);
Assert.AreEqual(fileTitle + ".docx", sharedFile.Title);
}
#endregion
[TestCase(DataTests.SharedForReadFolderId, DataTests.SharedForReadFolderName, DataTests.ShareId)]
[TestCase(DataTests.SharedForReadAndWriteFolderId, DataTests.SharedForReadAndWriteFolderName, DataTests.ShareId)]
[Category("Folder")]
[Order(3)]
[Description("get - files/folder/{folderId} - get shared folder")]
public async Task GetSharedFolderInfoReturnsFolderWrapperRead(int folderId, string folderName, int parentId)
{
var sharedFolder = await GetAsync<FolderDto<int>>($"folder/{folderId}");
Assert.IsNotNull(sharedFolder);
Assert.AreEqual(folderName, sharedFolder.Title);
Assert.AreEqual(folderId, sharedFolder.Id);
Assert.AreEqual(parentId, sharedFolder.ParentId);
}
[TestCase(DataTests.SharedForReadFileId, DataTests.SharedForReadFileName)]
[TestCase(DataTests.SharedForReadAndWriteFileId, DataTests.SharedForReadAndWriteFileName)]
[Category("File")]
[Order(8)]
[Description("get - files/file/{fileId} - get shared file")]
public async Task GetSharedFileInfoReturnsFolderWrapperRead(int fileId, string fileName)
{
var sharedFile = await GetAsync<FolderDto<int>>($"file/{fileId}");
Assert.IsNotNull(sharedFile);
Assert.AreEqual(fileName, sharedFile.Title);
}
[TestCase(DataTests.SharedForReadFileId, DataTests.DeleteAfter, DataTests.Immediately)]
[TestCase(DataTests.SharedForReadAndWriteFileId, DataTests.DeleteAfter, DataTests.Immediately)]
[Category("File")]
[Order(10)]
[Description("delete - files/file/{fileId} - try delete shared file")]
public async Task DeleteSharedFileReturnsFolderWrapperRead(int fileId, bool deleteAfter, bool immediately)
{
var result = (await DeleteAsync<IEnumerable<FileOperationDto>>($"file/{fileId}", new { DeleteAfter = deleteAfter, Immediately = immediately })).FirstOrDefault();
await WaitLongOperation(result, FilesCommonResource.ErrorMassage_SecurityException_DeleteFile);
}
[TestCase(DataTests.SharedForReadFolderId, DataTests.DeleteAfter, DataTests.Immediately)]
[TestCase(DataTests.SharedForReadAndWriteFolderId, DataTests.DeleteAfter, DataTests.Immediately)]
[Category("Folder")]
[Order(50)]
[Description("delete - files/folder/{folderId} - try delete shared folder")]
public async Task DeleteSharedFolderReturnsFolderWrapperRead(int folderId, bool deleteAfter, bool immediately)
{
var result = (await DeleteAsync<IEnumerable<FileOperationDto>>($"folder/{folderId}", new { DeleteAfter = deleteAfter, Immediately = immediately })).FirstOrDefault();
await WaitLongOperation(result, FilesCommonResource.ErrorMassage_SecurityException_DeleteFolder);
}
private async Task WaitLongOperation(FileOperationDto result, string assertError)
{
if (result != null && result.Finished)
{
Assert.That(result.Error == assertError, result.Error);
return;
}
var statuses = await WaitLongOperation();
var error = string.Join(",", statuses.Select(r => r.Error));
Assert.That(error == assertError, error);
}
}

View File

@ -42,7 +42,8 @@ public class AuthenticationController : ControllerBase
private readonly CookiesManager _cookiesManager;
private readonly PasswordHasher _passwordHasher;
private readonly EmailValidationKeyModelHelper _emailValidationKeyModelHelper;
private readonly ICache _cache;
private readonly ICache _cache;
private readonly SetupInfo _setupInfo;
private readonly MessageService _messageService;
private readonly ProviderManager _providerManager;
private readonly AccountLinker _accountLinker;
@ -66,7 +67,8 @@ public class AuthenticationController : ControllerBase
private readonly CookieStorage _cookieStorage;
private readonly DbLoginEventsManager _dbLoginEventsManager;
private readonly UserManagerWrapper _userManagerWrapper;
private readonly TfaAppAuthSettingsHelper _tfaAppAuthSettingsHelper;
private readonly TfaAppAuthSettingsHelper _tfaAppAuthSettingsHelper;
private readonly EmailValidationKeyProvider _emailValidationKeyProvider;
private readonly BruteForceLoginManager _bruteForceLoginManager;
public AuthenticationController(
@ -103,7 +105,8 @@ public class AuthenticationController : ControllerBase
CookieStorage cookieStorage,
DbLoginEventsManager dbLoginEventsManager,
BruteForceLoginManager bruteForceLoginManager,
TfaAppAuthSettingsHelper tfaAppAuthSettingsHelper)
TfaAppAuthSettingsHelper tfaAppAuthSettingsHelper,
EmailValidationKeyProvider emailValidationKeyProvider)
{
_userManager = userManager;
_tenantManager = tenantManager;
@ -112,7 +115,8 @@ public class AuthenticationController : ControllerBase
_cookiesManager = cookiesManager;
_passwordHasher = passwordHasher;
_emailValidationKeyModelHelper = emailValidationKeyModelHelper;
_cache = cache;
_cache = cache;
_setupInfo = setupInfo;
_messageService = messageService;
_providerManager = providerManager;
_accountLinker = accountLinker;
@ -137,7 +141,8 @@ public class AuthenticationController : ControllerBase
_dbLoginEventsManager = dbLoginEventsManager;
_userManagerWrapper = userManagerWrapper;
_bruteForceLoginManager = bruteForceLoginManager;
_tfaAppAuthSettingsHelper = tfaAppAuthSettingsHelper;
_tfaAppAuthSettingsHelper = tfaAppAuthSettingsHelper;
_emailValidationKeyProvider = emailValidationKeyProvider;
}
[AllowNotPayment]
@ -215,7 +220,12 @@ public class AuthenticationController : ControllerBase
{
var wrapper = await GetUser(inDto);
var viaEmail = wrapper.ViaEmail;
var user = wrapper.UserInfo;
var user = wrapper.UserInfo;
if (user == null || Equals(user, Constants.LostUser))
{
throw new Exception(Resource.ErrorUserNotFound);
}
if (_studioSmsNotificationSettingsHelper.IsVisibleAndAvailableSettings() && _studioSmsNotificationSettingsHelper.TfaEnabledForUser(user.Id))
{
@ -347,12 +357,34 @@ public class AuthenticationController : ControllerBase
var wrapper = new UserInfoWrapper
{
ViaEmail = true
};
};
var action = MessageAction.LoginFailViaApi;
UserInfo user;
UserInfo user = null;
try
{
if ((string.IsNullOrEmpty(inDto.Provider) && string.IsNullOrEmpty(inDto.SerializedProfile)) || inDto.Provider == "email")
{
if (inDto.ConfirmData != null)
{
var email = inDto.ConfirmData.Email;
var checkKeyResult = _emailValidationKeyProvider.ValidateEmailKey(email + ConfirmType.Auth + inDto.ConfirmData.First + inDto.ConfirmData.Module + inDto.ConfirmData.Sms, inDto.ConfirmData.Key, _setupInfo.ValidAuthKeyInterval);
if (checkKeyResult == ValidationResult.Ok)
{
user = email.Contains("@")
? _userManager.GetUserByEmail(email)
: _userManager.GetUsers(new Guid(email));
if (_securityContext.IsAuthenticated && _securityContext.CurrentAccount.ID != user.Id)
{
_securityContext.Logout();
_cookiesManager.ClearCookies(CookiesType.AuthKey);
_cookiesManager.ClearCookies(CookiesType.SocketIO);
}
}
}
else if ((string.IsNullOrEmpty(inDto.Provider) && string.IsNullOrEmpty(inDto.SerializedProfile)) || inDto.Provider == "email")
{
inDto.UserName.ThrowIfNull(new ArgumentException(@"userName empty", "userName"));
if (!string.IsNullOrEmpty(inDto.Password))

View File

@ -36,10 +36,21 @@ public class AuthRequestsDto
public string SerializedProfile { get; set; }
public string Code { get; set; }
public string CodeOAuth { get; set; }
public bool Session { get; set; }
public bool Session { get; set; }
public ConfirmData ConfirmData { get; set; }
}
public class MobileRequestsDto
{
public string MobilePhone { get; set; }
}
public class ConfirmData
{
public string Email { get; set; }
public string Module { get; set; }
public bool? First { get; set; }
public bool? Sms { get; set; }
public string Key { get; set; }
}

View File

@ -39,8 +39,11 @@ public class Startup : BaseStartup
{
base.ConfigureServices(services);
services.AddHostedService<LdapNotifyService>();
DIHelper.TryAdd<LdapNotifyService>();
if (!_configuration.GetValue<bool>("disableLdapNotifyService"))
{
services.AddHostedService<LdapNotifyService>();
DIHelper.TryAdd<LdapNotifyService>();
}
services.AddBaseDbContextPool<FilesDbContext>();
services.AddBaseDbContextPool<BackupsContext>();