Merge pull request #1132 from ONLYOFFICE/feature/asc.apicache
Feature/asc.apicache
This commit is contained in:
commit
109b44c529
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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>
|
||||
{
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
54
common/ASC.Core.Common/EF/CreatorDbContext.cs
Normal file
54
common/ASC.Core.Common/EF/CreatorDbContext.cs
Normal 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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
30
common/ASC.Core.Common/EF/Teamlabsite/ITeamlabsiteDb.cs
Normal file
30
common/ASC.Core.Common/EF/Teamlabsite/ITeamlabsiteDb.cs
Normal 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
|
||||
{
|
||||
}
|
82
common/ASC.Core.Common/EF/Teamlabsite/Model/DbCache.cs
Normal file
82
common/ASC.Core.Common/EF/Teamlabsite/Model/DbCache.cs
Normal 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");
|
||||
});
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -65,7 +65,7 @@ public class BackupPortalTask : PortalTaskBase
|
||||
ArgumentNullOrEmptyException.ThrowIfNullOrEmpty(toFilePath);
|
||||
|
||||
BackupFilePath = toFilePath;
|
||||
Limit = limit;
|
||||
Limit = limit;
|
||||
WriteOperator = writeOperator;
|
||||
Init(tenantId);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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; }
|
||||
|
@ -30,4 +30,5 @@ public class Options
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public IEnumerable<ProviderInfo> Providers { get; set; }
|
||||
public IEnumerable<ProviderInfo> TeamlabsiteProviders { get; set; }
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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++;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
{
|
||||
|
24
common/services/ASC.ApiCache/ASC.ApiCache.csproj
Normal file
24
common/services/ASC.ApiCache/ASC.ApiCache.csproj
Normal 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>
|
@ -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;
|
||||
}
|
||||
}
|
131
common/services/ASC.ApiCache/Controllers/PortalController.cs
Normal file
131
common/services/ASC.ApiCache/Controllers/PortalController.cs
Normal 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
|
||||
});
|
||||
}
|
||||
}
|
62
common/services/ASC.ApiCache/GlobalUsings.cs
Normal file
62
common/services/ASC.ApiCache/GlobalUsings.cs
Normal 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;
|
@ -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;
|
||||
}
|
||||
}
|
32
common/services/ASC.ApiCache/Models/CacheDto.cs
Normal file
32
common/services/ASC.ApiCache/Models/CacheDto.cs
Normal 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; }
|
||||
}
|
83
common/services/ASC.ApiCache/Program.cs
Normal file
83
common/services/ASC.ApiCache/Program.cs
Normal 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);
|
||||
}
|
29
common/services/ASC.ApiCache/Properties/launchSettings.json
Normal file
29
common/services/ASC.ApiCache/Properties/launchSettings.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
141
common/services/ASC.ApiCache/Startup.cs
Normal file
141
common/services/ASC.ApiCache/Startup.cs
Normal 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")
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
3
common/services/ASC.ApiCache/appsettings.json
Normal file
3
common/services/ASC.ApiCache/appsettings.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"pathToConf": "..\\..\\..\\config"
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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
8
config/apicache.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"auth" : {
|
||||
"allowskip" : {
|
||||
"default" : false,
|
||||
"registerportal": true
|
||||
}
|
||||
}
|
||||
}
|
@ -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": {
|
||||
|
@ -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;
|
||||
|
43
migrations/mysql/TeamlabSiteContext/20221219145514_TeamlabSiteContextMigrate.Designer.cs
generated
Normal file
43
migrations/mysql/TeamlabSiteContext/20221219145514_TeamlabSiteContextMigrate.Designer.cs
generated
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -1,6 +1,10 @@
|
||||
{
|
||||
"HealthChecksUI": {
|
||||
"HealthChecks": [
|
||||
{
|
||||
"Name": "ASC.ApiCache",
|
||||
"Uri": "http://localhost:5100/health"
|
||||
},
|
||||
{
|
||||
"Name": "ASC.ApiSystem",
|
||||
"Uri": "http://localhost:5010/health"
|
||||
|
Loading…
Reference in New Issue
Block a user