Merge pull request #1132 from ONLYOFFICE/feature/asc.apicache

Feature/asc.apicache
This commit is contained in:
Pavel Bannov 2023-02-08 11:49:27 +03:00 committed by GitHub
commit 109b44c529
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 1366 additions and 341 deletions

View File

@ -91,6 +91,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Data.Storage.Encryption
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.ApiSystem", "common\services\ASC.ApiSystem\ASC.ApiSystem.csproj", "{EB0FC2DF-D8AC-460B-8FBE-307A7B163C6C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.ApiCache", "common\services\ASC.ApiCache\ASC.ApiCache.csproj", "{AD4F5F31-625C-472D-BE2C-AD1FB693E065}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -257,6 +259,10 @@ Global
{EB0FC2DF-D8AC-460B-8FBE-307A7B163C6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB0FC2DF-D8AC-460B-8FBE-307A7B163C6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB0FC2DF-D8AC-460B-8FBE-307A7B163C6C}.Release|Any CPU.Build.0 = Release|Any CPU
{AD4F5F31-625C-472D-BE2C-AD1FB693E065}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD4F5F31-625C-472D-BE2C-AD1FB693E065}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD4F5F31-625C-472D-BE2C-AD1FB693E065}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD4F5F31-625C-472D-BE2C-AD1FB693E065}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -20,6 +20,7 @@
"common\\ASC.MessagingSystem\\ASC.MessagingSystem.csproj",
"common\\ASC.Notify.Textile\\ASC.Notify.Textile.csproj",
"common\\ASC.Textile\\ASC.Textile.csproj",
"common\\services\\ASC.ApiCache\\ASC.ApiCache.csproj",
"common\\services\\ASC.ApiSystem\\ASC.ApiSystem.csproj",
"common\\services\\ASC.AuditTrail\\ASC.AuditTrail.csproj",
"common\\services\\ASC.ClearEvents\\ASC.ClearEvents.csproj",

View File

@ -24,7 +24,7 @@
// 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.ApiSystem.Classes;
namespace ASC.Api.Core.Auth;
[Scope]
public class AuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
@ -35,11 +35,6 @@ public class AuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
private readonly MachinePseudoKeys _machinePseudoKeys;
private readonly IHttpContextAccessor _httpContextAccessor;
public AuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) :
base(options, logger, encoder, clock)
{
}
public AuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
@ -53,9 +48,7 @@ public class AuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
base(options, logger, encoder, clock)
{
_configuration = configuration;
_log = log;
_apiSystemHelper = apiSystemHelper;
_machinePseudoKeys = machinePseudoKeys;
_httpContextAccessor = httpContextAccessor;
@ -152,7 +145,7 @@ public class AuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
private void Authenticate()
{
var account = Core.Configuration.Constants.SystemAccounts.FirstOrDefault(a => a.ID == Core.Configuration.Constants.CoreSystem.ID);
var account = ASC.Core.Configuration.Constants.SystemAccounts.FirstOrDefault(a => a.ID == ASC.Core.Configuration.Constants.CoreSystem.ID);
var claims = new List<Claim>
{

View File

@ -35,10 +35,11 @@ global using System.Runtime.Serialization;
global using System.Security;
global using System.Security.Authentication;
global using System.Security.Claims;
global using System.Security.Cryptography;
global using System.Text;
global using System.Text.Encodings.Web;
global using System.Text.Encodings.Web;
global using System.Text.Json;
global using System.Text.Json.Serialization;
global using System.Text.Json.Serialization;
global using System.Text.RegularExpressions;
global using System.Web;
global using System.Xml.Linq;
@ -60,6 +61,7 @@ global using ASC.Common.Caching.Settings;
global using ASC.Common.DependencyInjection;
global using ASC.Common.Log;
global using ASC.Common.Logging;
global using ASC.Common.Security.Authorizing;
global using ASC.Common.Threading;
global using ASC.Common.Utils;
global using ASC.Common.Web;
@ -71,6 +73,7 @@ global using ASC.Core.Common.Hosting;
global using ASC.Core.Common.Hosting.Interfaces;
global using ASC.Core.Common.Quota;
global using ASC.Core.Common.Quota.Features;
global using ASC.Core.Common.Security;
global using ASC.Core.Common.Settings;
global using ASC.Core.Tenants;
global using ASC.Core.Users;
@ -87,6 +90,7 @@ global using ASC.MessagingSystem.EF.Model;
global using ASC.Security.Cryptography;
global using ASC.Web.Api.Routing;
global using ASC.Web.Core;
global using ASC.Web.Core.Helpers;
global using ASC.Web.Core.PublicResources;
global using ASC.Web.Core.Quota;
global using ASC.Web.Core.Users;

View File

@ -32,18 +32,22 @@ public enum Provider
MySql
}
public static class BaseDbContextExtension
public class InstallerOptionsAction
{
public static void OptionsAction(IServiceProvider sp, DbContextOptionsBuilder optionsBuilder)
private readonly string _region;
private readonly string _nameConnectionString;
public InstallerOptionsAction(string region, string nameConnectionString)
{
OptionsAction(sp, optionsBuilder, "current");
_region = region;
_nameConnectionString = nameConnectionString;
}
public static void OptionsAction(IServiceProvider sp, DbContextOptionsBuilder optionsBuilder, string region)
public void OptionsAction(IServiceProvider sp, DbContextOptionsBuilder optionsBuilder)
{
var configuration = new ConfigurationExtension(sp.GetRequiredService<IConfiguration>());
var migrateAssembly = configuration["testAssembly"];
var connectionString = configuration.GetConnectionStrings("default", region);
var connectionString = configuration.GetConnectionStrings(_nameConnectionString, _region);
var loggerFactory = sp.GetRequiredService<EFLoggerFactory>();
optionsBuilder.UseLoggerFactory(loggerFactory);
@ -86,17 +90,22 @@ public static class BaseDbContextExtension
break;
}
}
}
public static IServiceCollection AddBaseDbContextPool<T>(this IServiceCollection services) where T : DbContext
public static class BaseDbContextExtension
{
public static IServiceCollection AddBaseDbContextPool<T>(this IServiceCollection services, string region = "current", string nameConnectionString = "default") where T : DbContext
{
services.AddPooledDbContextFactory<T>(OptionsAction);
var installerOptionsAction = new InstallerOptionsAction(region, nameConnectionString);
services.AddPooledDbContextFactory<T>(installerOptionsAction.OptionsAction);
return services;
}
public static IServiceCollection AddBaseDbContext<T>(this IServiceCollection services) where T : DbContext
public static IServiceCollection AddBaseDbContext<T>(this IServiceCollection services, string region = "current", string nameConnectionString = "default") where T : DbContext
{
services.AddDbContext<T>(OptionsAction);
var installerOptionsAction = new InstallerOptionsAction(region, nameConnectionString);
services.AddDbContext<T>(installerOptionsAction.OptionsAction);
return services;
}

View File

@ -0,0 +1,54 @@
// (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.Core.Common.EF;
[Singletone]
public class CreatorDbContext
{
private readonly IServiceProvider _serviceProvider;
private readonly ICache _cache;
public CreatorDbContext(IServiceProvider serviceProvider, ICache cache)
{
_serviceProvider = serviceProvider;
_cache = cache;
}
public T CreateDbContext<T>(string region = "current", string nameConnectionString = "default") where T : DbContext
{
var contextOptions = _cache.Get<DbContextOptionsBuilder<T>>($"context {typeof(T)} {region}");
if (contextOptions == null)
{
contextOptions = new DbContextOptionsBuilder<T>();
var installerOptionsAction = new InstallerOptionsAction(region, nameConnectionString);
installerOptionsAction.OptionsAction(_serviceProvider, contextOptions);
var key = $"context {region}:{nameConnectionString}";
_cache.Insert(key, contextOptions, TimeSpan.FromMinutes(15));
}
return (T)Activator.CreateInstance(typeof(T), contextOptions.Options);
}
}

View File

@ -0,0 +1,42 @@
// (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
using ASC.Core.Common.EF.Teamlabsite.Model;
namespace ASC.Core.Common.EF.Teamlabsite.Context;
public class TeamlabSiteContext: DbContext, ITeamlabsiteDb
{
public DbSet<DbCache> Cache { get; set; }
public TeamlabSiteContext(DbContextOptions<TeamlabSiteContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
ModelBuilderWrapper
.From(modelBuilder, Database)
.AddDbCache();
}
}

View File

@ -0,0 +1,30 @@
// (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.Core.Common.EF.Teamlabsite;
public interface ITeamlabsiteDb
{
}

View File

@ -0,0 +1,82 @@
// (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.Core.Common.EF.Teamlabsite.Model;
public class DbCache
{
public string TenantAlias { get; set; }
}
public static class DbCacheExtension
{
public static ModelBuilderWrapper AddDbCache(this ModelBuilderWrapper modelBuilder)
{
modelBuilder
.Add(MySqlAddDbCache, Provider.MySql)
.Add(PgSqlAddDbCache, Provider.PostgreSql);
return modelBuilder;
}
public static void MySqlAddDbCache(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<DbCache>(entity =>
{
entity.ToTable("tenants_cache")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.HasKey(e => e.TenantAlias)
.HasName("PRIMARY");
entity.Property(e => e.TenantAlias)
.HasColumnName("tenant_alias")
.HasColumnType("varchar(100)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
});
}
public static void PgSqlAddDbCache(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<DbCache>(entity =>
{
entity.ToTable("tenants_cache")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.HasKey(e => e.TenantAlias)
.HasName("PRIMARY");
entity.Property(e => e.TenantAlias)
.HasColumnName("tenant_alias")
.HasColumnType("varchar(100)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
});
}
}

View File

@ -23,7 +23,7 @@
// 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.Data.Backup.Services;
@ -105,29 +105,27 @@ public class BackupProgressItem : BaseBackupProgressItem
var backupName = string.Format("{0}_{1:yyyy-MM-dd_HH-mm-ss}.{2}", _tenantManager.GetTenant(TenantId).Alias, dateTime, ArchiveFormat);
var tempFile = CrossPlatform.PathCombine(TempFolder, backupName);
var storagePath = tempFile;
var storagePath = tempFile;
string hash;
try
{
var backupStorage = _backupStorageFactory.GetBackupStorage(_storageType, TenantId, StorageParams);
var writer = await ZipWriteOperatorFactory.GetWriteOperatorAsync(_tempStream, _storageBasePath, backupName, TempFolder, _userId, backupStorage as IGetterWriteOperator);
var backupTask = _backupPortalTask;
var writer = await ZipWriteOperatorFactory.GetWriteOperatorAsync(_tempStream, _storageBasePath, backupName, TempFolder, _userId, backupStorage as IGetterWriteOperator);
backupTask.Init(TenantId, tempFile, _limit, writer);
_backupPortalTask.Init(TenantId, tempFile, _limit, writer);
backupTask.ProgressChanged += (sender, args) =>
_backupPortalTask.ProgressChanged += (sender, args) =>
{
Percentage = 0.9 * args.Progress;
PublishChanges();
};
await backupTask.RunJob();
await _backupPortalTask.RunJob();
if (writer.NeedUpload)
{
storagePath = await backupStorage.Upload(_storageBasePath, tempFile, _userId);
{
storagePath = await backupStorage.Upload(_storageBasePath, tempFile, _userId);
hash = BackupWorker.GetBackupHash(tempFile);
}
else

View File

@ -30,12 +30,12 @@ namespace ASC.Data.Backup.Storage;
public class BackupRepository : IBackupRepository
{
private readonly IDbContextFactory<BackupsContext> _dbContextFactory;
private readonly DbFactory _dbFactory;
private readonly CreatorDbContext _creatorDbContext;
public BackupRepository(IDbContextFactory<BackupsContext> dbContextFactory, DbFactory dbFactory)
public BackupRepository(IDbContextFactory<BackupsContext> dbContextFactory, CreatorDbContext creatorDbContext)
{
_dbContextFactory = dbContextFactory;
_dbFactory = dbFactory;
_creatorDbContext = creatorDbContext;
}
public void SaveBackupRecord(BackupRecord backup)
@ -87,7 +87,7 @@ public class BackupRepository : IBackupRepository
backup.Id = Guid.NewGuid();
});
var backupContextByNewTenant = _dbFactory.CreateDbContext<BackupsContext>(region);
var backupContextByNewTenant = _creatorDbContext.CreateDbContext<BackupsContext>(region);
backupContextByNewTenant.Backups.AddRange(backups);
backupContextByNewTenant.SaveChanges();
}

View File

@ -64,7 +64,7 @@ public class ConsumerBackupStorage : IBackupStorage, IGetterWriteOperator
public void Init(int tenant)
{
_isTemporary = true;
_store = _storageFactory.GetStorage(tenant, "backup");
_store = _storageFactory.GetStorage(tenant, "backup");
_sessionHolder = new CommonChunkedUploadSessionHolder(_tempPath, _logger, _store, Domain, _setupInfo.ChunkUploadSize);
}

View File

@ -37,7 +37,7 @@ public class DocumentsBackupStorage : IBackupStorage, IGetterWriteOperator
private readonly SecurityContext _securityContext;
private readonly IDaoFactory _daoFactory;
private readonly StorageFactory _storageFactory;
private readonly IServiceProvider _serviceProvider;
private readonly IServiceProvider _serviceProvider;
private FilesChunkedUploadSessionHolder _sessionHolder;
private readonly TempPath _tempPath;
private readonly ILogger<DocumentsBackupStorage> _logger;
@ -57,7 +57,7 @@ public class DocumentsBackupStorage : IBackupStorage, IGetterWriteOperator
_securityContext = securityContext;
_daoFactory = daoFactory;
_storageFactory = storageFactory;
_serviceProvider = serviceProvider;
_serviceProvider = serviceProvider;
_tempPath = tempPath;
_logger = logger;
}
@ -67,8 +67,8 @@ public class DocumentsBackupStorage : IBackupStorage, IGetterWriteOperator
_tenantId = tenantId;
var store = _storageFactory.GetStorage(_tenantId, "files");
_sessionHolder = new FilesChunkedUploadSessionHolder(_daoFactory, _tempPath, _logger, store, "", _setupInfo.ChunkUploadSize);
}
}
public async Task<string> Upload(string folderId, string localPath, Guid userId)
{
_tenantManager.SetCurrentTenant(_tenantId);
@ -206,8 +206,8 @@ public class DocumentsBackupStorage : IBackupStorage, IGetterWriteOperator
{
return false;
}
}
}
public async Task<IDataWriteOperator> GetWriteOperatorAsync(string storageBasePath, string title, Guid userId)
{
_tenantManager.SetCurrentTenant(_tenantId);

View File

@ -65,7 +65,7 @@ public class BackupPortalTask : PortalTaskBase
ArgumentNullOrEmptyException.ThrowIfNullOrEmpty(toFilePath);
BackupFilePath = toFilePath;
Limit = limit;
Limit = limit;
WriteOperator = writeOperator;
Init(tenantId);

View File

@ -76,18 +76,6 @@ public class DbFactory
_cache = cache;
}
public T CreateDbContext<T>(string region = "current") where T : DbContext
{
var contextOptions = _cache.Get<DbContextOptionsBuilder<T>>($"context {typeof(T)} {region}");
if (contextOptions == null)
{
contextOptions = new DbContextOptionsBuilder<T>();
BaseDbContextExtension.OptionsAction(_serviceProvider, contextOptions, region);
_cache.Insert($"context {region}", contextOptions, TimeSpan.FromMinutes(15));
}
return (T)Activator.CreateInstance(typeof(T), contextOptions.Options);
}
public DbConnection OpenConnection(string path = "default", string connectionString = null, string region = "current")
{
var connection = DbProviderFactory.CreateConnection();

View File

@ -45,7 +45,7 @@ public abstract class PortalTaskBase
protected ILogger Logger { get; set; }
public int Progress { get; private set; }
public int TenantId { get; private set; }
public bool ProcessStorage { get; set; }
public bool ProcessStorage { get; set; }
protected IDataWriteOperator WriteOperator { get; set; }
protected ModuleProvider ModuleProvider { get; set; }
protected DbFactory DbFactory { get; set; }

View File

@ -30,4 +30,5 @@ public class Options
{
public string Path { get; set; }
public IEnumerable<ProviderInfo> Providers { get; set; }
public IEnumerable<ProviderInfo> TeamlabsiteProviders { get; set; }
}

View File

@ -24,10 +24,11 @@
// 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
global using ASC.ActiveDirectory.Base;
global using ASC.Common.Logging;
global using ASC.Core.Common.EF;
global using ASC.Core.Common.EF.Context;
global using ASC.Core.Common.EF.Teamlabsite;
global using ASC.Core.Common.EF.Teamlabsite.Context;
global using ASC.Core.Common.Hosting;
global using ASC.Data.Backup.EF.Context;
global using ASC.EventBus.Extensions.Logger;
@ -38,6 +39,7 @@ global using ASC.Webhooks.Core.EF.Context;
global using Microsoft.Extensions.Hosting.WindowsServices;
global using Migration.Core.Models;
global using Migration.Core.Utils;
global using Migration.Creator;

View File

@ -23,7 +23,7 @@
// 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 Migration.Creator;
public class MigrationCreator
@ -45,29 +45,44 @@ public class MigrationCreator
foreach (var contextType in ctxTypesFinder.GetDependetContextsTypes())
{
foreach (var providerInfo in options.Providers)
if (contextType.GetInterfaces().Contains(typeof(ITeamlabsiteDb)))
{
var providerInfoProjectPath = Solution.GetProviderProjectPath(options.Path, providerInfo);
var dbContextActivator = new DbContextActivator(_serviceProvider);
var context = dbContextActivator.CreateInstance(contextType, providerInfo);
var modelDiffChecker = new ModelDifferenceChecker(context);
if (!modelDiffChecker.IsDifferent())
foreach (var providerInfo in options.TeamlabsiteProviders)
{
continue;
CreateMigration(options, contextType, providerInfo);
counter++;
}
}
else
{
foreach (var providerInfo in options.Providers)
{
CreateMigration(options, contextType, providerInfo);
counter++;
}
context = dbContextActivator.CreateInstance(contextType, providerInfo); //Hack: refresh context
var migrationGenerator = new MigrationGenerator(context, providerInfo.Provider, providerInfoProjectPath);
migrationGenerator.Generate();
counter++;
}
}
}
Console.WriteLine($"Created {counter} migrations");
}
private void CreateMigration(Options options, Type contextType, ProviderInfo providerInfo)
{
var dbContextActivator = new DbContextActivator(_serviceProvider);
var context = dbContextActivator.CreateInstance(contextType, providerInfo);
var modelDiffChecker = new ModelDifferenceChecker(context);
if (!modelDiffChecker.IsDifferent())
{
return;
}
context = dbContextActivator.CreateInstance(contextType, providerInfo); //Hack: refresh context
var providerInfoProjectPath = Solution.GetProviderProjectPath(options.Path, providerInfo);
var migrationGenerator = new MigrationGenerator(context, providerInfo.Provider, providerInfoProjectPath);
migrationGenerator.Generate();
}
}

View File

@ -22,8 +22,8 @@
//
// 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
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
var options = new WebApplicationOptions
{
Args = args,
@ -33,27 +33,30 @@ var options = new WebApplicationOptions
var builder = WebApplication.CreateBuilder(options);
builder.Configuration.AddJsonFile($"appsettings.creator.json", true)
.AddCommandLine(args);
.AddCommandLine(args);
builder.Services.AddScoped<EFLoggerFactory>()
.AddBaseDbContext<AccountLinkContext>()
.AddBaseDbContext<CoreDbContext>()
.AddBaseDbContext<TenantDbContext>()
.AddBaseDbContext<UserDbContext>()
.AddBaseDbContext<TelegramDbContext>()
.AddBaseDbContext<CustomDbContext>()
.AddBaseDbContext<WebstudioDbContext>()
.AddBaseDbContext<InstanceRegistrationContext>()
.AddBaseDbContext<IntegrationEventLogContext>()
.AddBaseDbContext<FeedDbContext>()
.AddBaseDbContext<MessagesContext>()
.AddBaseDbContext<WebhooksDbContext>()
.AddBaseDbContext<MessagesContext>()
.AddBaseDbContext<BackupsContext>()
.AddBaseDbContext<FilesDbContext>()
.AddBaseDbContext<NotifyDbContext>()
.AddBaseDbContext<UrlShortenerFakeDbContext>()
.AddBaseDbContext<FirebaseDbContext>();
builder.WebHost.ConfigureServices((hostContext, services) =>
{
services.AddScoped<EFLoggerFactory>();
services.AddBaseDbContext<AccountLinkContext>();
services.AddBaseDbContext<CoreDbContext>();
services.AddBaseDbContext<TenantDbContext>();
services.AddBaseDbContext<UserDbContext>();
services.AddBaseDbContext<TelegramDbContext>();
services.AddBaseDbContext<CustomDbContext>();
services.AddBaseDbContext<WebstudioDbContext>();
services.AddBaseDbContext<InstanceRegistrationContext>();
services.AddBaseDbContext<IntegrationEventLogContext>();
services.AddBaseDbContext<FeedDbContext>();
services.AddBaseDbContext<MessagesContext>();
services.AddBaseDbContext<WebhooksDbContext>();
services.AddBaseDbContext<BackupsContext>();
services.AddBaseDbContext<FilesDbContext>();
services.AddBaseDbContext<NotifyDbContext>();
services.AddBaseDbContext<UrlShortenerFakeDbContext>();
services.AddBaseDbContext<FirebaseDbContext>();
services.AddBaseDbContext<TeamlabSiteContext>();
});
var app = builder.Build();

View File

@ -12,6 +12,13 @@
"ProviderFullName": "Npgsql",
"ConnectionString": "Host=localhost;Port=5432;Database=onlyoffice;Username=postgres;Password=dev;"
}
],
"TeamlabsiteProviders": [
{
"Provider": "MySql",
"ProviderFullName": "MySql.Data.MySqlClient",
"ConnectionString": "Server=localhost;Database=teamlabsite;User ID=root;Password=root"
}
]
}
}

View File

@ -26,10 +26,11 @@
global using System.Reflection;
global using ASC.ActiveDirectory.Base;
global using ASC.Common.Logging;
global using ASC.Core.Common.EF;
global using ASC.Core.Common.EF.Context;
global using ASC.Core.Common.EF.Teamlabsite;
global using ASC.Core.Common.EF.Teamlabsite.Context;
global using ASC.Core.Common.Hosting;
global using ASC.Data.Backup.EF.Context;
global using ASC.EventBus.Extensions.Logger;

View File

@ -35,7 +35,7 @@ public class MigrationRunner
_dbContextActivator = new DbContextActivator(serviceProvider);
}
public void RunApplyMigrations(string path, ProviderInfo dbProvider)
public void RunApplyMigrations(string path, ProviderInfo dbProvider, ProviderInfo teamlabsiteProvider)
{
var counter = 0;
@ -45,10 +45,16 @@ public class MigrationRunner
foreach (var contextType in ctxTypesFinder.GetIndependentContextsTypes())
{
var context = _dbContextActivator.CreateInstance(contextType, dbProvider);
DbContext context = null;
if (contextType.GetInterfaces().Contains(typeof(ITeamlabsiteDb)))
{
context = _dbContextActivator.CreateInstance(contextType, teamlabsiteProvider);
}
else
{
context = _dbContextActivator.CreateInstance(contextType, dbProvider);
}
context.Database.Migrate();
counter++;
}
}

View File

@ -22,7 +22,7 @@
//
// 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
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
var options = new WebApplicationOptions
{
@ -33,27 +33,30 @@ var options = new WebApplicationOptions
var builder = WebApplication.CreateBuilder(options);
builder.Configuration.AddJsonFile($"appsettings.runner.json", true)
.AddCommandLine(args);
.AddCommandLine(args);
builder.Services.AddScoped<EFLoggerFactory>()
.AddBaseDbContext<AccountLinkContext>()
.AddBaseDbContext<CoreDbContext>()
.AddBaseDbContext<TenantDbContext>()
.AddBaseDbContext<UserDbContext>()
.AddBaseDbContext<TelegramDbContext>()
.AddBaseDbContext<FirebaseDbContext>()
.AddBaseDbContext<CustomDbContext>()
.AddBaseDbContext<WebstudioDbContext>()
.AddBaseDbContext<InstanceRegistrationContext>()
.AddBaseDbContext<IntegrationEventLogContext>()
.AddBaseDbContext<FeedDbContext>()
.AddBaseDbContext<MessagesContext>()
.AddBaseDbContext<WebhooksDbContext>()
.AddBaseDbContext<MessagesContext>()
.AddBaseDbContext<BackupsContext>()
.AddBaseDbContext<FilesDbContext>()
.AddBaseDbContext<NotifyDbContext>()
.AddBaseDbContext<UrlShortenerFakeDbContext>();
builder.WebHost.ConfigureServices((hostContext, services) =>
{
services.AddScoped<EFLoggerFactory>();
services.AddBaseDbContext<AccountLinkContext>();
services.AddBaseDbContext<CoreDbContext>();
services.AddBaseDbContext<TenantDbContext>();
services.AddBaseDbContext<UserDbContext>();
services.AddBaseDbContext<TelegramDbContext>();
services.AddBaseDbContext<FirebaseDbContext>();
services.AddBaseDbContext<CustomDbContext>();
services.AddBaseDbContext<WebstudioDbContext>();
services.AddBaseDbContext<InstanceRegistrationContext>();
services.AddBaseDbContext<IntegrationEventLogContext>();
services.AddBaseDbContext<FeedDbContext>();
services.AddBaseDbContext<WebhooksDbContext>();
services.AddBaseDbContext<MessagesContext>();
services.AddBaseDbContext<BackupsContext>();
services.AddBaseDbContext<FilesDbContext>();
services.AddBaseDbContext<NotifyDbContext>();
services.AddBaseDbContext<UrlShortenerFakeDbContext>();
services.AddBaseDbContext<TeamlabSiteContext>();
});
var app = builder.Build();
@ -62,5 +65,5 @@ var providersInfo = app.Configuration.GetSection("options").Get<Options>();
foreach (var providerInfo in providersInfo.Providers)
{
var migrationCreator = new MigrationRunner(app.Services);
migrationCreator.RunApplyMigrations(AppContext.BaseDirectory, providerInfo);
migrationCreator.RunApplyMigrations(AppContext.BaseDirectory, providerInfo, providersInfo.TeamlabsiteProviders.SingleOrDefault(q => q.Provider == providerInfo.Provider));
}

View File

@ -6,6 +6,13 @@
"ProviderFullName": "MySql.Data.MySqlClient",
"ConnectionString": "Server=localhost;Database=onlyoffice;User ID=root;Password=root"
}
],
"TeamlabsiteProviders": [
{
"Provider": "MySql",
"ProviderFullName": "MySql.Data.MySqlClient",
"ConnectionString": "Server=localhost;Database=teamlabsite;User ID=root;Password=root"
}
]
}
}

View File

@ -23,9 +23,9 @@
// 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.Migration.PersonalToDocspace.Creator;
[Scope]
public class MigrationCreator
{
@ -33,15 +33,16 @@ public class MigrationCreator
private readonly TempStream _tempStream;
private readonly DbFactory _dbFactory;
private readonly StorageFactory _storageFactory;
private readonly StorageFactoryConfig _storageFactoryConfig;
private readonly ModuleProvider _moduleProvider;
private readonly StorageFactoryConfig _storageFactoryConfig;
private readonly ModuleProvider _moduleProvider;
private readonly IMapper _mapper;
private readonly CreatorDbContext _creatorDbContext;
private List<IModuleSpecifics> _modules;
private string _pathToSave;
private string _userName;
private string _userName;
private string _mail;
private string _toRegion;
private string _toRegion;
private string _toAlias;
private string _fromAlias;
private int _fromTenantId;
@ -54,8 +55,8 @@ public class MigrationCreator
ModuleName.Files2,
ModuleName.Tenants,
ModuleName.WebStudio
};
};
private readonly List<ModuleName> _namesModulesForAlreadyExistPortal = new List<ModuleName>()
{
ModuleName.Core,
@ -63,31 +64,33 @@ public class MigrationCreator
ModuleName.Files2,
};
public string NewAlias { get; private set; }
public MigrationCreator(
TenantDomainValidator tenantDomainValidator,
TempStream tempStream,
DbFactory dbFactory,
StorageFactory storageFactory,
StorageFactoryConfig storageFactoryConfig,
public string NewAlias { get; private set; }
public MigrationCreator(
TenantDomainValidator tenantDomainValidator,
TempStream tempStream,
DbFactory dbFactory,
StorageFactory storageFactory,
StorageFactoryConfig storageFactoryConfig,
ModuleProvider moduleProvider,
IMapper mapper)
{
_tenantDomainValidator = tenantDomainValidator;
_tempStream = tempStream;
_dbFactory = dbFactory;
_storageFactory = storageFactory;
_storageFactoryConfig = storageFactoryConfig;
_moduleProvider = moduleProvider;
IMapper mapper,
CreatorDbContext сreatorDbContext)
{
_tenantDomainValidator = tenantDomainValidator;
_tempStream = tempStream;
_dbFactory = dbFactory;
_storageFactory = storageFactory;
_storageFactoryConfig = storageFactoryConfig;
_moduleProvider = moduleProvider;
_mapper = mapper;
}
_creatorDbContext = сreatorDbContext;
}
public string Create(string fromAlias, string userName, string mail, string toRegion, string toAlias)
{
{
Init(fromAlias, userName, mail, toRegion, toAlias);
var id = GetUserId();
var id = GetUserId();
CheckCountManager();
var fileName = _userName + ".tar.gz";
var path = Path.Combine(_pathToSave, fileName);
@ -95,15 +98,15 @@ public class MigrationCreator
{
DoMigrationDb(id, writer);
DoMigrationStorage(id, writer);
}
}
return fileName;
}
}
private void Init(string fromAlias, string userName, string mail, string toRegion, string toAlias)
{
_pathToSave = "";
_toRegion = toRegion;
_userName = userName;
_userName = userName;
_mail = mail;
_fromAlias = fromAlias;
_toAlias = toAlias;
@ -114,9 +117,9 @@ public class MigrationCreator
if (tenant == null)
{
throw new ArgumentException("tenant was not found");
}
}
_fromTenantId = tenant.Id;
_modules = string.IsNullOrEmpty(_toAlias)
? _moduleProvider.AllModules.Where(m => _namesModules.Contains(m.ModuleName)).ToList()
: _moduleProvider.AllModules.Where(m => _namesModulesForAlreadyExistPortal.Contains(m.ModuleName)).ToList();
@ -125,25 +128,25 @@ public class MigrationCreator
private Guid GetUserId()
{
try
{
{
using var userDbContext = _dbFactory.CreateDbContext<UserDbContext>();
User user = null;
if (string.IsNullOrEmpty(_userName) || string.IsNullOrEmpty(_mail))
{
if (string.IsNullOrEmpty(_userName))
{
User user = null;
if (string.IsNullOrEmpty(_userName) || string.IsNullOrEmpty(_mail))
{
if (string.IsNullOrEmpty(_userName))
{
user = userDbContext.Users.FirstOrDefault(q => q.Tenant == _fromTenantId && q.Status == EmployeeStatus.Active && q.Email == _mail);
_userName = user.UserName;
}
else
{
_userName = user.UserName;
}
else
{
user = userDbContext.Users.FirstOrDefault(q => q.Tenant == _fromTenantId && q.Status == EmployeeStatus.Active && q.UserName == _userName);
}
}
else
{
}
}
else
{
user = userDbContext.Users.FirstOrDefault(q => q.Tenant == _fromTenantId && q.Status == EmployeeStatus.Active && q.UserName == _userName && q.Email == _mail);
}
}
if (!string.IsNullOrEmpty(_toAlias))
{
using var dbContextTenant = _dbFactory.CreateDbContext<TenantDbContext>(_toRegion);
@ -162,7 +165,7 @@ public class MigrationCreator
}
}
return user.Id;
}
}
catch (ArgumentException e)
{
throw e;
@ -171,8 +174,8 @@ public class MigrationCreator
{
throw new ArgumentException("username was not found");
}
}
}
private void CheckCountManager()
{
if (!string.IsNullOrEmpty(_toAlias)) {
@ -198,7 +201,7 @@ public class MigrationCreator
private void DoMigrationDb(Guid id, IDataWriteOperator writer)
{
{
if (!string.IsNullOrEmpty(_toAlias))
{
using (var connection = _dbFactory.OpenConnection())
@ -216,55 +219,55 @@ public class MigrationCreator
using (var connection = _dbFactory.OpenConnection())
{
foreach (var table in tablesToProcess)
{
if (table.Name == "files_thirdparty_account" || table.Name == "files_thirdparty_id_mapping" || table.Name == "core_subscription" || table.Name == "files_security")
{
continue;
}
{
if (table.Name == "files_thirdparty_account" || table.Name == "files_thirdparty_id_mapping" || table.Name == "core_subscription" || table.Name == "files_security")
{
continue;
}
ArhiveTable(table, writer, module, connection, id);
}
}
}
}
private void ArhiveTable(TableInfo table, IDataWriteOperator writer, IModuleSpecifics module, DbConnection connection, Guid id)
{
Console.WriteLine($"backup table {table.Name}");
using (var data = new DataTable(table.Name))
{
ActionInvoker.Try(
state =>
{
data.Clear();
int counts;
var offset = 0;
do
{
var t = (TableInfo)state;
var dataAdapter = _dbFactory.CreateDataAdapter();
Console.WriteLine($"backup table {table.Name}");
using (var data = new DataTable(table.Name))
{
ActionInvoker.Try(
state =>
{
data.Clear();
int counts;
var offset = 0;
do
{
var t = (TableInfo)state;
var dataAdapter = _dbFactory.CreateDataAdapter();
dataAdapter.SelectCommand = module.CreateSelectCommand(connection.Fix(), _fromTenantId, t, _limit, offset, id).WithTimeout(600);
counts = ((DbDataAdapter)dataAdapter).Fill(data);
offset += _limit;
} while (counts == _limit);
},
table,
maxAttempts: 5,
onFailure: error => { throw ThrowHelper.CantBackupTable(table.Name, error); });
foreach (var col in data.Columns.Cast<DataColumn>().Where(col => col.DataType == typeof(DateTime)))
{
col.DateTimeMode = DataSetDateTime.Unspecified;
}
module.PrepareData(data);
if (data.TableName == "tenants_tenants")
{
ChangeAlias(data);
ChangeName(data);
}
counts = ((DbDataAdapter)dataAdapter).Fill(data);
offset += _limit;
} while (counts == _limit);
},
table,
maxAttempts: 5,
onFailure: error => { throw ThrowHelper.CantBackupTable(table.Name, error); });
foreach (var col in data.Columns.Cast<DataColumn>().Where(col => col.DataType == typeof(DateTime)))
{
col.DateTimeMode = DataSetDateTime.Unspecified;
}
module.PrepareData(data);
if (data.TableName == "tenants_tenants")
{
ChangeAlias(data);
ChangeName(data);
}
if (data.TableName == "files_bunch_objects")
{
ClearCommonBunch(data);
@ -276,14 +279,14 @@ public class MigrationCreator
private void WriteEnrty(DataTable data, IDataWriteOperator writer, IModuleSpecifics module)
{
using (var file = _tempStream.Create())
{
data.WriteXml(file, XmlWriteMode.WriteSchema);
data.Clear();
writer.WriteEntry(KeyHelper.GetTableZipKey(module, data.TableName), file);
}
}
using (var file = _tempStream.Create())
{
data.WriteXml(file, XmlWriteMode.WriteSchema);
data.Clear();
writer.WriteEntry(KeyHelper.GetTableZipKey(module, data.TableName), file);
}
}
private void ChangeAlias(DataTable data)
{
@ -292,7 +295,7 @@ public class MigrationCreator
while (true)
{
try
{
{
NewAlias = RemoveInvalidCharacters(NewAlias);
_tenantDomainValidator.ValidateDomainLength(NewAlias);
_tenantDomainValidator.ValidateDomainCharacters(NewAlias);
@ -304,53 +307,53 @@ public class MigrationCreator
}
catch (TenantTooShortException ex)
{
if (NewAlias.Length > 100)
{
NewAlias = NewAlias.Substring(0, 50);
}
else
{
NewAlias = $"DocSpace{NewAlias}";
}
if (NewAlias.Length > 100)
{
NewAlias = NewAlias.Substring(0, 50);
}
else
{
NewAlias = $"DocSpace{NewAlias}";
}
Console.WriteLine(ex.Message);
}
}
catch (Exception ex)
{
var last = NewAlias.Substring(NewAlias.Length-1);
if (int.TryParse(last, out var lastNumber))
{
NewAlias = NewAlias.Substring(0, NewAlias.Length - 1) + (lastNumber + 1);
}
else
{
NewAlias = NewAlias + 1;
}
{
var last = NewAlias.Substring(NewAlias.Length-1);
if (int.TryParse(last, out var lastNumber))
{
NewAlias = NewAlias.Substring(0, NewAlias.Length - 1) + (lastNumber + 1);
}
else
{
NewAlias = NewAlias + 1;
}
Console.WriteLine(ex.Message);
}
}
}
Console.WriteLine($"Alias is - {NewAlias}");
data.Rows[0]["alias"] = NewAlias;
}
private string RemoveInvalidCharacters(string alias)
{
return Regex.Replace(alias, "[^a-z0-9]", "", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
}
private string RemoveInvalidCharacters(string alias)
{
return Regex.Replace(alias, "[^a-z0-9]", "", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
}
private List<string> GetAliases()
{
using var dbContext = _dbFactory.CreateDbContext<TenantDbContext>(_toRegion);
var tenants = dbContext.Tenants.Select(t => t.Alias).ToList();
{
using var dbContext = _creatorDbContext.CreateDbContext<TenantDbContext>(_toRegion);
var tenants = dbContext.Tenants.Select(t => t.Alias).ToList();
var forbidens = dbContext.TenantForbiden.Select(tf => tf.Address).ToList();
return tenants.Union(forbidens).ToList();
}
}
private void ChangeName(DataTable data)
{
data.Rows[0]["name"] = "";
}
}
private void ClearCommonBunch(DataTable data)
{
for(var i = 0; i < data.Rows.Count; i++)
@ -364,11 +367,11 @@ public class MigrationCreator
}
private void DoMigrationStorage(Guid id, IDataWriteOperator writer)
{
{
Console.WriteLine($"start backup storage");
var fileGroups = GetFilesGroup(id);
foreach (var group in fileGroups)
{
{
Console.WriteLine($"start backup fileGroup: {group.Key}");
foreach (var file in group)
{
@ -380,7 +383,7 @@ public class MigrationCreator
using var fileStream = storage.GetReadStreamAsync(f.Domain, f.Path).Result;
writer.WriteEntry(file1.GetZipKey(), fileStream);
}, file, 5);
}
}
Console.WriteLine($"end backup fileGroup: {group.Key}");
}
@ -394,7 +397,7 @@ public class MigrationCreator
{
restoreInfoXml.WriteTo(tmpFile);
writer.WriteEntry(KeyHelper.GetStorageRestoreInfoZipKey(), tmpFile);
}
}
Console.WriteLine($"end backup storage");
}
@ -404,64 +407,64 @@ public class MigrationCreator
return files.GroupBy(file => file.Module).ToList();
}
private IEnumerable<BackupFileInfo> GetFilesToProcess(Guid id)
{
var files = new List<BackupFileInfo>();
var filesDbContext = _dbFactory.CreateDbContext<FilesDbContext>();
var files = new List<BackupFileInfo>();
var filesDbContext = _dbFactory.CreateDbContext<FilesDbContext>();
var module = _storageFactoryConfig.GetModuleList().Where(m => m == "files").Single();
var module = _storageFactoryConfig.GetModuleList().Where(m => m == "files").Single();
var store = _storageFactory.GetStorage(_fromTenantId, module);
var dbFiles = filesDbContext.Files.Where(q => q.CreateBy == id && q.TenantId == _fromTenantId).ToList();
var tasks = new List<Task>(20);
foreach (var dbFile in dbFiles)
{
if (tasks.Count != 20)
{
tasks.Add(FindFiles(files, store, dbFile, module));
}
else
{
Task.WaitAll(tasks.ToArray());
tasks.Clear();
}
}
Task.WaitAll(tasks.ToArray());
var tasks = new List<Task>(20);
foreach (var dbFile in dbFiles)
{
if (tasks.Count != 20)
{
tasks.Add(FindFiles(files, store, dbFile, module));
}
else
{
Task.WaitAll(tasks.ToArray());
tasks.Clear();
}
}
Task.WaitAll(tasks.ToArray());
return files.Distinct();
}
private async Task FindFiles(List<BackupFileInfo> list, IDataStore store, DbFile dbFile, string module)
{
var files = await store.ListFilesRelativeAsync(string.Empty, $"\\{GetUniqFileDirectory(dbFile.Id)}", "*.*", true)
private async Task FindFiles(List<BackupFileInfo> list, IDataStore store, DbFile dbFile, string module)
{
var files = await store.ListFilesRelativeAsync(string.Empty, $"\\{GetUniqFileDirectory(dbFile.Id)}", "*.*", true)
.Select(path => new BackupFileInfo(string.Empty, module, $"{GetUniqFileDirectory(dbFile.Id)}\\{path}", _fromTenantId))
.ToListAsync();
lock (_locker)
{
list.AddRange(files);
}
if (files.Any())
{
Console.WriteLine($"file {dbFile.Id} found");
}
else
{
Console.WriteLine($"file {dbFile.Id} not found");
}
}
private string GetUniqFileDirectory(int fileId)
{
if (fileId == 0)
{
throw new ArgumentNullException("fileIdObject");
}
return string.Format("folder_{0}/file_{1}", (fileId / 1000 + 1) * 1000, fileId);
.ToListAsync();
lock (_locker)
{
list.AddRange(files);
}
if (files.Any())
{
Console.WriteLine($"file {dbFile.Id} found");
}
else
{
Console.WriteLine($"file {dbFile.Id} not found");
}
}
private string GetUniqFileDirectory(int fileId)
{
if (fileId == 0)
{
throw new ArgumentNullException("fileIdObject");
}
return string.Format("folder_{0}/file_{1}", (fileId / 1000 + 1) * 1000, fileId);
}
}

View File

@ -33,7 +33,8 @@ public class MigrationRunner
private readonly StorageFactory _storageFactory;
private readonly StorageFactoryConfig _storageFactoryConfig;
private readonly ModuleProvider _moduleProvider;
private readonly ILogger<RestoreDbModuleTask> _logger;
private readonly ILogger<RestoreDbModuleTask> _logger;
private readonly CreatorDbContext _creatorDbContext;
private string _backupFile;
private string _region;
@ -52,13 +53,15 @@ public class MigrationRunner
StorageFactory storageFactory,
StorageFactoryConfig storageFactoryConfig,
ModuleProvider moduleProvider,
ILogger<RestoreDbModuleTask> logger)
ILogger<RestoreDbModuleTask> logger,
CreatorDbContext creatorDbContext)
{
_dbFactory = dbFactory;
_storageFactory = storageFactory;
_storageFactoryConfig = storageFactoryConfig;
_moduleProvider = moduleProvider;
_logger = logger;
_creatorDbContext = creatorDbContext;
}
public async Task Run(string backupFile, string region, string fromAlias, string toAlias)
@ -71,7 +74,7 @@ public class MigrationRunner
{
using var dbContextTenant = _dbFactory.CreateDbContext<TenantDbContext>();
var fromTenant = dbContextTenant.Tenants.SingleOrDefault(q => q.Alias == fromAlias);
using var dbContextToTenant = _dbFactory.CreateDbContext<TenantDbContext>(region);
var toTenant = dbContextToTenant.Tenants.SingleOrDefault(q => q.Alias == toAlias);
@ -96,9 +99,9 @@ public class MigrationRunner
}
await DoRestoreStorage(dataReader, columnMapper);
SetTenantActiveaAndTenantOwner(columnMapper.GetTenantMapping());
SetAdmin(columnMapper.GetTenantMapping());
SetAdmin(columnMapper.GetTenantMapping());
}
}
@ -154,8 +157,8 @@ public class MigrationRunner
private void SetTenantActiveaAndTenantOwner(int tenantId)
{
using var dbContextTenant = _dbFactory.CreateDbContext<TenantDbContext>(_region);
using var dbContextUser = _dbFactory.CreateDbContext<UserDbContext>(_region);
using var dbContextTenant = _creatorDbContext.CreateDbContext<TenantDbContext>(_region);
using var dbContextUser = _creatorDbContext.CreateDbContext<UserDbContext>(_region);
var tenant = dbContextTenant.Tenants.Single(t=> t.Id == tenantId);
tenant.Status = TenantStatus.Active;
@ -168,16 +171,16 @@ public class MigrationRunner
var user = dbContextUser.Users.Single(u => u.Tenant == tenantId);
tenant.OwnerId = user.Id;
Console.WriteLine($"set ownerId {user.Id}");
}
}
dbContextTenant.Tenants.Update(tenant);
dbContextTenant.SaveChanges();
}
private void SetAdmin(int tenantId)
{
using var dbContextTenant = _dbFactory.CreateDbContext<TenantDbContext>(_region);
using var dbContextTenant = _creatorDbContext.CreateDbContext<TenantDbContext>(_region);
var tenant = dbContextTenant.Tenants.Single(t => t.Id == tenantId);
using var dbContextUser = _dbFactory.CreateDbContext<UserDbContext>(_region);
using var dbContextUser = _creatorDbContext.CreateDbContext<UserDbContext>(_region);
if (!dbContextUser.UserGroups.Any(q => q.Tenant == tenantId))
{

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<AssemblyTitle>ASC.ApiCache</AssemblyTitle>
<Company>Ascensio System SIA</Company>
<Product>ASC.ApiSystem</Product>
<Copyright>(c) Ascensio System SIA. All rights reserved</Copyright>
<RazorCompileOnBuild>false</RazorCompileOnBuild>
<GenerateMvcApplicationPartsAssemblyAttributes>false</GenerateMvcApplicationPartsAssemblyAttributes>
<DisableImplicitComponentsAnalyzers>true</DisableImplicitComponentsAnalyzers>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<NoWarn>NU1701</NoWarn>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\web\ASC.Web.Core\ASC.Web.Core.csproj" />
<ProjectReference Include="..\..\ASC.Api.Core\ASC.Api.Core.csproj" />
<ProjectReference Include="..\..\ASC.Common\ASC.Common.csproj" />
<ProjectReference Include="..\..\ASC.Core.Common\ASC.Core.Common.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,38 @@
// (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.ApiCache;
public static class ConfigurationManagerExtension
{
public static ConfigurationManager AddApiCacheConfiguration(this ConfigurationManager config)
{
config
.AddJsonFile($"apicache.json");
return config;
}
}

View File

@ -0,0 +1,131 @@
// (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.ApiCache.Controllers;
[Scope]
[ApiController]
[Route("[controller]")]
public class PortalController : ControllerBase
{
private readonly PortalControllerHelper _portalControllerHelper;
private readonly ILogger<PortalController> _log;
public PortalController(PortalControllerHelper portalControllerHelper,
ILogger<PortalController> log)
{
_portalControllerHelper = portalControllerHelper;
_log = log;
}
[HttpGet("test")]
public IActionResult Check()
{
return Ok(new
{
value = "Portal cache api works"
});
}
[HttpGet("find")]
public async Task<IActionResult> FindPortalNameInCache([FromQuery] CacheDto inDto)
{
if (string.IsNullOrEmpty(inDto.PortalName))
{
return BadRequest(new
{
error = "portalNameEmpty",
message = "PortalName is required"
});
}
_log.LogDebug("FindPortalNameInCache method. portalname = {0}", inDto.PortalName);
var sameAliasTenants = await _portalControllerHelper.FindTenantsInCacheAsync(inDto.PortalName);
return Ok(new
{
variants = sameAliasTenants
});
}
[HttpPost("add")]
[Authorize(AuthenticationSchemes = "auth:allowskip:default")]
public async Task<IActionResult> AddPortalNameToCacheAsync(CacheDto inDto)
{
if (String.IsNullOrEmpty(inDto.PortalName))
{
return BadRequest(new
{
error = "portalNameEmpty",
message = "PortalName is required"
});
}
try
{
await _portalControllerHelper.AddTenantToCacheAsync(inDto.PortalName);
}
catch (Exception e)
{
_log.LogError(e, "registerNewTenantError");
return BadRequest(new { errors = "registerNewTenantError", message = e.Message, stacktrace = e.StackTrace });
}
return Ok(new
{
portalName = inDto.PortalName
});
}
[HttpDelete("remove")]
[Authorize(AuthenticationSchemes = "auth:allowskip:default")]
public async Task<IActionResult> RemoveFromCacheAsync([FromQuery] CacheDto inDto)
{
if (String.IsNullOrEmpty(inDto.PortalName))
{
return BadRequest(new
{
error = "portalNameEmpty",
message = "PortalName is required"
});
}
try
{
await _portalControllerHelper.RemoveTenantFromCacheAsync(inDto.PortalName);
}
catch (Exception e)
{
_log.LogError(e, "removeTenantFromCacheError");
return BadRequest(new { errors = "removeTenantFromCacheError", message = e.Message, stacktrace = e.StackTrace });
}
return Ok(new
{
portalName = inDto.PortalName
});
}
}

View File

@ -0,0 +1,62 @@
// (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
global using System.Text.Json.Serialization;
global using ASC.Api.Core;
global using ASC.Api.Core.Auth;
global using ASC.Api.Core.Core;
global using ASC.Api.Core.Extensions;
global using ASC.ApiCache;
global using ASC.ApiCache.Helpers;
global using ASC.ApiCache.Models;
global using ASC.Common;
global using ASC.Common.Logging;
global using ASC.Core.Common.EF;
global using ASC.Core.Common.EF.Context;
global using ASC.Core.Common.EF.Teamlabsite.Context;
global using ASC.Core.Common.EF.Teamlabsite.Model;
global using ASC.Core.Common.Hosting;
global using ASC.Core.Tenants;
global using ASC.EventBus.Extensions.Logger;
global using ASC.Feed.Context;
global using ASC.MessagingSystem.EF.Context;
global using ASC.Web.Core.Helpers;
global using ASC.Webhooks.Core;
global using ASC.Webhooks.Core.EF.Context;
global using Autofac;
global using HealthChecks.UI.Client;
global using Microsoft.AspNetCore.Authentication;
global using Microsoft.AspNetCore.Authorization;
global using Microsoft.AspNetCore.Diagnostics.HealthChecks;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.Extensions.DependencyInjection.Extensions;
global using Microsoft.Extensions.Hosting.WindowsServices;
global using NLog;

View File

@ -0,0 +1,96 @@
// (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
using Microsoft.EntityFrameworkCore;
namespace ASC.ApiCache.Helpers;
[Scope]
public class PortalControllerHelper
{
private readonly ILogger<PortalControllerHelper> _log;
private readonly TenantDomainValidator _tenantDomainValidator;
private readonly IDbContextFactory<TeamlabSiteContext> _teamlabSiteContext;
public PortalControllerHelper(ILogger<PortalControllerHelper> log, TenantDomainValidator tenantDomainValidator, IDbContextFactory<TeamlabSiteContext> teamlabSiteContext)
{
_log = log;
_tenantDomainValidator = tenantDomainValidator;
_teamlabSiteContext = teamlabSiteContext;
}
public async Task AddTenantToCacheAsync(string tenant)
{
var cache = new DbCache()
{
TenantAlias = tenant.ToLowerInvariant()
};
var context = await _teamlabSiteContext.CreateDbContextAsync();
await context.Cache.AddAsync(cache);
await context.SaveChangesAsync();
}
public async Task RemoveTenantFromCacheAsync(string domain)
{
domain = domain.ToLowerInvariant();
var context = await _teamlabSiteContext.CreateDbContextAsync();
var cache = await context.Cache.SingleOrDefaultAsync(q => q.TenantAlias == domain);
context.Cache.Remove(cache);
await context.SaveChangesAsync();
}
public async Task<List<string>> FindTenantsInCacheAsync(string portalName)
{
//return tenants starts like current
_log.LogDebug("FindTenantsInCache method");
portalName = (portalName ?? "").Trim().ToLowerInvariant();
// forbidden or exists
var context = await _teamlabSiteContext.CreateDbContextAsync();
var exists = await context.Cache.Where(q => q.TenantAlias.Equals(portalName)).AnyAsync();
if (exists)
{
// cut number suffix
while (true)
{
if (_tenantDomainValidator.MinLength < portalName.Length && char.IsNumber(portalName, portalName.Length - 1))
{
portalName = portalName[0..^1];
}
else
{
break;
}
}
return await context.Cache.Select(q => q.TenantAlias).Where(q => q.StartsWith(portalName)).ToListAsync();
}
return null;
}
}

View File

@ -0,0 +1,32 @@
// (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.ApiCache.Models;
public class CacheDto
{
public string PortalName { get; set; }
}

View File

@ -0,0 +1,83 @@
// (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
var options = new WebApplicationOptions
{
Args = args,
ContentRootPath = WindowsServiceHelpers.IsWindowsService() ? AppContext.BaseDirectory : default
};
var builder = WebApplication.CreateBuilder(options);
builder.Configuration.AddDefaultConfiguration(builder.Environment)
.AddApiCacheConfiguration()
.AddEnvironmentVariables()
.AddCommandLine(args);
var logger = LogManager.Setup()
.SetupExtensions(s =>
{
s.RegisterLayoutRenderer("application-context", (logevent) => AppName);
})
.LoadConfiguration(builder.Configuration, builder.Environment)
.GetLogger(typeof(Startup).Namespace);
try
{
logger.Info("Configuring web host ({applicationContext})...", AppName);
builder.Host.ConfigureDefault();
var startup = new Startup(builder.Configuration, builder.Environment);
startup.ConfigureServices(builder.Services);
var app = builder.Build();
startup.Configure(app, app.Environment);
logger.Info("Starting web host ({applicationContext})...", AppName);
await app.RunWithTasksAsync();
}
catch (Exception ex)
{
if (logger != null)
{
logger.Error(ex, "Program terminated unexpectedly ({applicationContext})!", AppName);
}
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
LogManager.Shutdown();
}
public partial class Program
{
public static string Namespace = typeof(Startup).Namespace;
public static string AppName = Namespace.Substring(Namespace.LastIndexOf('.') + 1);
}

View File

@ -0,0 +1,29 @@
{
"profiles": {
"Kestrel WebServer": {
"commandName": "Project",
"launchBrowser": false,
"launchUrl": "http://localhost:5100/portal/test",
"environmentVariables": {
"$STORAGE_ROOT": "../../../Data",
"log__name": "apicache",
"log__dir": "../../../Logs",
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_URLS": "http://localhost:5100"
}
},
"WSL 2 : Ubuntu 20.04": {
"commandName": "WSL2",
"launchBrowser": false,
"launchUrl": "http://localhost:5100/portal/test",
"environmentVariables": {
"$STORAGE_ROOT": "../../../Data",
"log__name": "apicache",
"log__dir": "../../../Logs",
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_URLS": "http://localhost:5100"
},
"distributionName": "Ubuntu-20.04"
}
}
}

View File

@ -0,0 +1,141 @@
// (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.ApiCache;
public class Startup
{
private const string CustomCorsPolicyName = "Basic";
private readonly IConfiguration _configuration;
private readonly IHostEnvironment _hostEnvironment;
private readonly DIHelper _diHelper;
private readonly string _corsOrigin;
public Startup(IConfiguration configuration, IHostEnvironment hostEnvironment)
{
_configuration = configuration;
_hostEnvironment = hostEnvironment;
_diHelper = new DIHelper();
_corsOrigin = _configuration["core:cors"];
}
public void ConfigureServices(IServiceCollection services)
{
services.AddCustomHealthCheck(_configuration);
services.AddHttpContextAccessor();
services.AddMemoryCache();
services.AddHttpClient();
services.AddScoped<EFLoggerFactory>();
services.AddBaseDbContextPool<TeamlabSiteContext>(nameConnectionString: "teamlabsite");
services.AddSession();
_diHelper.Configure(services);
Action<JsonOptions> jsonOptions = options =>
{
options.JsonSerializerOptions.WriteIndented = false;
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
options.JsonSerializerOptions.Converters.Add(new ApiDateTimeConverter());
};
services.AddControllers()
.AddXmlSerializerFormatters()
.AddJsonOptions(jsonOptions);
services.AddSingleton(jsonOptions);
_diHelper.AddControllers();
_diHelper.TryAdd<ApiSystemHelper>();
services.RegisterFeature();
services.AddBaseDbContextPool<TenantDbContext>();
services.AddBaseDbContextPool<UserDbContext>();
services.AddBaseDbContextPool<CoreDbContext>();
services.AddBaseDbContextPool<WebstudioDbContext>();
services.AddAutoMapper(BaseStartup.GetAutoMapperProfileAssemblies());
if (!string.IsNullOrEmpty(_corsOrigin))
{
services.AddCors(options =>
{
options.AddPolicy(name: CustomCorsPolicyName,
policy =>
{
policy.WithOrigins(_corsOrigin)
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
}
services.AddDistributedCache(_configuration);
services.AddEventBus(_configuration);
services.AddDistributedTaskQueue();
services.AddCacheNotify(_configuration);
if (!_hostEnvironment.IsDevelopment())
{
services.AddStartupTask<WarmupServicesStartupTask>()
.TryAddSingleton(services);
}
services.AddAuthentication()
.AddScheme<AuthenticationSchemeOptions, AuthHandler>("auth:allowskip:default", _ => { });
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
if (!string.IsNullOrEmpty(_corsOrigin))
{
app.UseCors(CustomCorsPolicyName);
}
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapCustom();
endpoints.MapHealthChecks("/health", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
{
Predicate = r => r.Name.Contains("self")
});
});
}
}

View File

@ -0,0 +1,3 @@
{
"pathToConf": "..\\..\\..\\config"
}

View File

@ -29,17 +29,13 @@ global using System.Diagnostics;
global using System.Globalization;
global using System.Net;
global using System.Net.Http.Headers;
global using System.Security.Authentication;
global using System.Security.Claims;
global using System.Security.Cryptography;
global using System.Text;
global using System.Text.Encodings.Web;
global using System.Text.Json.Serialization;
global using System.Text.RegularExpressions;
global using System.Web;
global using System.Web.Http.Filters;
global using ASC.Api.Core;
global using ASC.Api.Core;
global using ASC.Api.Core.Auth;
global using ASC.Api.Core.Core;
global using ASC.Api.Core.Extensions;
@ -51,14 +47,12 @@ global using ASC.ApiSystem.Models;
global using ASC.Common;
global using ASC.Common.Caching;
global using ASC.Common.Logging;
global using ASC.Common.Security.Authorizing;
global using ASC.Common.Utils;
global using ASC.Core;
global using ASC.Core.Billing;
global using ASC.Core.Common.EF;
global using ASC.Core.Common.EF.Context;
global using ASC.Core.Common.Hosting;
global using ASC.Core.Common.Security;
global using ASC.Core.Common.Settings;
global using ASC.Core.Tenants;
global using ASC.Core.Users;
@ -83,11 +77,9 @@ global using Microsoft.AspNetCore.Authentication;
global using Microsoft.AspNetCore.Authorization;
global using Microsoft.AspNetCore.Diagnostics.HealthChecks;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.AspNetCore.WebUtilities;
global using Microsoft.Extensions.Caching.Memory;
global using Microsoft.Extensions.DependencyInjection.Extensions;
global using Microsoft.Extensions.Hosting.WindowsServices;
global using Microsoft.Extensions.Options;
global using Newtonsoft.Json.Linq;

View File

@ -24,9 +24,6 @@
// 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
using StackExchange.Redis.Extensions.Core.Configuration;
var options = new WebApplicationOptions
{
Args = args,
@ -46,10 +43,7 @@ var logger = LogManager.Setup()
s.RegisterLayoutRenderer("application-context", (logevent) => AppName);
})
.LoadConfiguration(builder.Configuration, builder.Environment)
.GetLogger(typeof(Startup).Namespace);
var path = builder.Configuration["pathToConf"];
logger.Debug("path: " + path);
logger.Debug("EnvironmentName: " + builder.Environment.EnvironmentName);
.GetLogger(typeof(Startup).Namespace);
try
{

8
config/apicache.json Normal file
View File

@ -0,0 +1,8 @@
{
"auth" : {
"allowskip" : {
"default" : false,
"registerportal": true
}
}
}

View File

@ -140,6 +140,11 @@
"name": "mysql",
"connectionString": "Server=localhost;Database=onlyoffice;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True;Connection Timeout=30;Maximum Pool Size=300;ConnectionReset=false",
"providerName": "MySql.Data.MySqlClient"
},
"teamlabsite": {
"name": "teamlabsite",
"connectionString": "Server=localhost;Database=teamlabsite;User ID=dev;Password=dev;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none;AllowPublicKeyRetrieval=True;Connection Timeout=30;Maximum Pool Size=300;ConnectionReset=false",
"providerName": "MySql.Data.MySqlClient"
}
},
"migration": {

View File

@ -280,6 +280,12 @@ server {
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
}
location /apicache {
rewrite apicache/(.*) /$1 break;
proxy_pass http://127.0.0.1:5100;
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
}
location /sh {
rewrite sh/(.*) /$1 break;
proxy_pass http://127.0.0.1:9999;

View File

@ -0,0 +1,43 @@
// <auto-generated />
using ASC.Core.Common.EF.Teamlabsite.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace ASC.Migrations.MySql.Migrations.TeamlabSite
{
[DbContext(typeof(TeamlabSiteContext))]
[Migration("20221219145514_TeamlabSiteContextMigrate")]
partial class TeamlabSiteContextMigrate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "6.0.7")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("ASC.Core.Common.EF.Teamlabsite.Model.DbCache", b =>
{
b.Property<string>("TenantAlias")
.HasColumnType("varchar(100)")
.HasColumnName("tenant_alias")
.UseCollation("utf8_general_ci")
.HasAnnotation("MySql:CharSet", "utf8");
b.HasKey("TenantAlias")
.HasName("PRIMARY");
b.ToTable("tenants_cache", (string)null);
b
.HasAnnotation("MySql:CharSet", "utf8")
.HasAnnotation("Relational:Collation", "utf8_general_ci");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ASC.Migrations.MySql.Migrations.TeamlabSite
{
public partial class TeamlabSiteContextMigrate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "tenants_cache",
columns: table => new
{
tenant_alias = table.Column<string>(type: "varchar(100)", nullable: false, collation: "utf8_general_ci")
.Annotation("MySql:CharSet", "utf8")
},
constraints: table =>
{
table.PrimaryKey("PRIMARY", x => x.tenant_alias);
})
.Annotation("MySql:CharSet", "utf8")
.Annotation("Relational:Collation", "utf8_general_ci");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "tenants_cache");
}
}
}

View File

@ -0,0 +1,41 @@
// <auto-generated />
using ASC.Core.Common.EF.Teamlabsite.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace ASC.Migrations.MySql.Migrations.TeamlabSite
{
[DbContext(typeof(TeamlabSiteContext))]
partial class TeamlabSiteContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "6.0.7")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("ASC.Core.Common.EF.Teamlabsite.Model.DbCache", b =>
{
b.Property<string>("TenantAlias")
.HasColumnType("varchar(100)")
.HasColumnName("tenant_alias")
.UseCollation("utf8_general_ci")
.HasAnnotation("MySql:CharSet", "utf8");
b.HasKey("TenantAlias")
.HasName("PRIMARY");
b.ToTable("tenants_cache", (string)null);
b
.HasAnnotation("MySql:CharSet", "utf8")
.HasAnnotation("Relational:Collation", "utf8_general_ci");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -62,7 +62,7 @@ public class ApiSystemHelper
{
try
{
var data = $"portalName={HttpUtility.UrlEncode(domain)}";
var data = "{\"portalName\":\"" + HttpUtility.UrlEncode(domain) + "\"}";
await SendToApiAsync(ApiSystemUrl, "portal/validateportalname", WebRequestMethods.Http.Post, userId, data);
}
catch (WebException exception)
@ -107,7 +107,7 @@ public class ApiSystemHelper
public async Task AddTenantToCacheAsync(string domain, Guid userId)
{
var data = $"portalName={HttpUtility.UrlEncode(domain)}";
var data = "{\"portalName\":\"" + HttpUtility.UrlEncode(domain) + "\"}";
await SendToApiAsync(ApiCacheUrl, "portal/add", WebRequestMethods.Http.Post, userId, data);
}
@ -147,7 +147,7 @@ public class ApiSystemHelper
if (data != null)
{
request.Content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded");
request.Content = new StringContent(data, Encoding.UTF8, "application/json");
}
var httpClient = _clientFactory.CreateClient();

View File

@ -1,6 +1,10 @@
{
"HealthChecksUI": {
"HealthChecks": [
{
"Name": "ASC.ApiCache",
"Uri": "http://localhost:5100/health"
},
{
"Name": "ASC.ApiSystem",
"Uri": "http://localhost:5010/health"