diff --git a/ASC.Web.sln b/ASC.Web.sln index 0d92015d0dd..cfbf50017bd 100644 --- a/ASC.Web.sln +++ b/ASC.Web.sln @@ -1,4 +1,5 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.28803.202 MinimumVisualStudioVersion = 10.0.40219.1 @@ -57,8 +58,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Feed.Aggregator", "comm EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Thumbnails.Svc", "common\services\ASC.Thumbnails.Svc\ASC.Thumbnails.Svc.csproj", "{1D2F61B2-B1F4-45F0-83CA-03370FD6E62C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Data.Backup", "common\services\ASC.Data.Backup\ASC.Data.Backup.csproj", "{DE3DAF51-FB29-41FC-AF41-A4BA8D91BFB6}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Files.Core", "products\ASC.Files\Core\ASC.Files.Core.csproj", "{F0A39728-940D-4DBE-A37A-05D4EB57F342}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Socket.IO.Svc", "common\services\ASC.Socket.IO.Svc\ASC.Socket.IO.Svc.csproj", "{2DADEAD3-0FE9-4199-9817-41A32E6BF450}" @@ -88,12 +87,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Radicale", "common\serv EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.SsoAuth.Svc", "common\services\ASC.SsoAuth.Svc\ASC.SsoAuth.Svc.csproj", "{6AD828EA-FBA2-4D30-B969-756B3BE78E4E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASC.Web.HealthChecks.UI", "web\ASC.Web.HealthChecks.UI\ASC.Web.HealthChecks.UI.csproj", "{0C1A387E-0CD0-4BE8-82FC-9FCAD05BF289}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Web.HealthChecks.UI", "web\ASC.Web.HealthChecks.UI\ASC.Web.HealthChecks.UI.csproj", "{0C1A387E-0CD0-4BE8-82FC-9FCAD05BF289}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.ClearEvents", "common\services\ASC.ClearEvents\ASC.ClearEvents.csproj", "{448221A8-EABA-4200-9192-E08BF241A487}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.CRM.BackgroundTasks", "products\ASC.CRM\BackgroundTasks\ASC.CRM.BackgroundTasks.csproj", "{E52C0E35-A05C-437F-8FF2-3E0AC9F81433}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Data.Backup.Core", "common\ASC.Data.Backup.Core\ASC.Data.Backup.Core.csproj", "{F5D9DE01-06CD-4881-9F41-46882E9ED45C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Data.Backup", "common\services\ASC.Data.Backup\ASC.Data.Backup.csproj", "{027EEE53-7491-48F4-B467-6404D68798A7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -204,10 +207,6 @@ Global {1D2F61B2-B1F4-45F0-83CA-03370FD6E62C}.Debug|Any CPU.Build.0 = Debug|Any CPU {1D2F61B2-B1F4-45F0-83CA-03370FD6E62C}.Release|Any CPU.ActiveCfg = Release|Any CPU {1D2F61B2-B1F4-45F0-83CA-03370FD6E62C}.Release|Any CPU.Build.0 = Release|Any CPU - {DE3DAF51-FB29-41FC-AF41-A4BA8D91BFB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DE3DAF51-FB29-41FC-AF41-A4BA8D91BFB6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DE3DAF51-FB29-41FC-AF41-A4BA8D91BFB6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DE3DAF51-FB29-41FC-AF41-A4BA8D91BFB6}.Release|Any CPU.Build.0 = Release|Any CPU {F0A39728-940D-4DBE-A37A-05D4EB57F342}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F0A39728-940D-4DBE-A37A-05D4EB57F342}.Debug|Any CPU.Build.0 = Debug|Any CPU {F0A39728-940D-4DBE-A37A-05D4EB57F342}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -244,14 +243,14 @@ Global {277F4A2C-07CC-4BC5-B4F3-9695BB2DFFB9}.Debug|Any CPU.Build.0 = Debug|Any CPU {277F4A2C-07CC-4BC5-B4F3-9695BB2DFFB9}.Release|Any CPU.ActiveCfg = Release|Any CPU {277F4A2C-07CC-4BC5-B4F3-9695BB2DFFB9}.Release|Any CPU.Build.0 = Release|Any CPU + {137CA67B-D0F5-4746-B8BC-1888D2859B90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {137CA67B-D0F5-4746-B8BC-1888D2859B90}.Debug|Any CPU.Build.0 = Debug|Any CPU + {137CA67B-D0F5-4746-B8BC-1888D2859B90}.Release|Any CPU.ActiveCfg = Release|Any CPU + {137CA67B-D0F5-4746-B8BC-1888D2859B90}.Release|Any CPU.Build.0 = Release|Any CPU {74998718-3C9A-4A89-B834-14453762C60F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {74998718-3C9A-4A89-B834-14453762C60F}.Debug|Any CPU.Build.0 = Debug|Any CPU {74998718-3C9A-4A89-B834-14453762C60F}.Release|Any CPU.ActiveCfg = Release|Any CPU {74998718-3C9A-4A89-B834-14453762C60F}.Release|Any CPU.Build.0 = Release|Any CPU - {137CA67B-D0F5-4746-B8BC-1888D2859B90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {137CA67B-D0F5-4746-B8BC-1888D2859B90}.Debug|Any CPU.Build.0 = Debug|Any CPU - {137CA67B-D0F5-4746-B8BC-1888D2859B90}.Release|Any CPU.ActiveCfg = Release|Any CPU - {137CA67B-D0F5-4746-B8BC-1888D2859B90}.Release|Any CPU.Build.0 = Release|Any CPU {6AD828EA-FBA2-4D30-B969-756B3BE78E4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6AD828EA-FBA2-4D30-B969-756B3BE78E4E}.Debug|Any CPU.Build.0 = Debug|Any CPU {6AD828EA-FBA2-4D30-B969-756B3BE78E4E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -268,6 +267,14 @@ Global {E52C0E35-A05C-437F-8FF2-3E0AC9F81433}.Debug|Any CPU.Build.0 = Debug|Any CPU {E52C0E35-A05C-437F-8FF2-3E0AC9F81433}.Release|Any CPU.ActiveCfg = Release|Any CPU {E52C0E35-A05C-437F-8FF2-3E0AC9F81433}.Release|Any CPU.Build.0 = Release|Any CPU + {F5D9DE01-06CD-4881-9F41-46882E9ED45C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F5D9DE01-06CD-4881-9F41-46882E9ED45C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F5D9DE01-06CD-4881-9F41-46882E9ED45C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F5D9DE01-06CD-4881-9F41-46882E9ED45C}.Release|Any CPU.Build.0 = Release|Any CPU + {027EEE53-7491-48F4-B467-6404D68798A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {027EEE53-7491-48F4-B467-6404D68798A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {027EEE53-7491-48F4-B467-6404D68798A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {027EEE53-7491-48F4-B467-6404D68798A7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/common/ASC.Data.Backup.Core/ASC.Data.Backup.Core.csproj b/common/ASC.Data.Backup.Core/ASC.Data.Backup.Core.csproj new file mode 100644 index 00000000000..10431c607f5 --- /dev/null +++ b/common/ASC.Data.Backup.Core/ASC.Data.Backup.Core.csproj @@ -0,0 +1,55 @@ + + + + Exe + net5.0 + Library + NU1701 + + + + + + + + + + + + true + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + BackupResource.resx + True + True + + + + + + BackupResource.Designer.cs + ResXFileCodeGenerator + + + diff --git a/common/services/ASC.Data.Backup/ActionInvoker.cs b/common/ASC.Data.Backup.Core/ActionInvoker.cs similarity index 99% rename from common/services/ASC.Data.Backup/ActionInvoker.cs rename to common/ASC.Data.Backup.Core/ActionInvoker.cs index 95668a22f9b..e4ce1689632 100644 --- a/common/services/ASC.Data.Backup/ActionInvoker.cs +++ b/common/ASC.Data.Backup.Core/ActionInvoker.cs @@ -32,7 +32,7 @@ namespace ASC.Data.Backup public static class ActionInvoker { public static void Try( - Action action, + Action action, int maxAttempts, Action onFailure = null, Action onAttemptFailure = null, @@ -65,13 +65,13 @@ public static void Try( catch (Exception error) { if (countAttempts < maxAttempts) - { + { onAttemptFailure?.Invoke(error); - if (sleepMs > 0) + if (sleepMs > 0) Thread.Sleep(isSleepExponential ? sleepMs * countAttempts : sleepMs); } - else + else { onFailure?.Invoke(error); } diff --git a/common/services/ASC.Data.Backup/BackupAjaxHandler.cs b/common/ASC.Data.Backup.Core/BackupAjaxHandler.cs similarity index 99% rename from common/services/ASC.Data.Backup/BackupAjaxHandler.cs rename to common/ASC.Data.Backup.Core/BackupAjaxHandler.cs index 03b91d59a62..5dd3db0376d 100644 --- a/common/services/ASC.Data.Backup/BackupAjaxHandler.cs +++ b/common/ASC.Data.Backup.Core/BackupAjaxHandler.cs @@ -1,24 +1,24 @@ using System; using System.Collections.Generic; -using System.Linq; - -using ASC.Api.Utils; +using System.Linq; + +using ASC.Api.Utils; using ASC.Common; using ASC.Core; using ASC.Core.Billing; using ASC.Core.Common.Configuration; using ASC.Core.Users; -using ASC.Data.Backup.Contracts; -using ASC.Data.Backup.Service; +using ASC.Data.Backup.Contracts; +using ASC.Data.Backup.Service; using ASC.MessagingSystem; using ASC.Notify.Cron; using ASC.Web.Core.PublicResources; using ASC.Web.Studio.Core; -using ASC.Web.Studio.Core.Backup; -using ASC.Web.Studio.Utility; +using ASC.Web.Studio.Core.Backup; +using ASC.Web.Studio.Utility; namespace ASC.Data.Backup -{ +{ [Scope] public class BackupAjaxHandler { @@ -30,23 +30,23 @@ public class BackupAjaxHandler private SecurityContext SecurityContext { get; } private UserManager UserManager { get; } private TenantExtra TenantExtra { get; } - private ConsumerFactory ConsumerFactory { get; } - private BackupFileUploadHandler BackupFileUploadHandler { get; } - private BackupService BackupService { get; } + private ConsumerFactory ConsumerFactory { get; } + private BackupFileUploadHandler BackupFileUploadHandler { get; } + private BackupService BackupService { get; } #region backup - public BackupAjaxHandler( - BackupService backupService, - TenantManager tenantManager, - MessageService messageService, - CoreBaseSettings coreBaseSettings, - CoreConfiguration coreConfiguration, - PermissionContext permissionContext, - SecurityContext securityContext, - UserManager userManager, - TenantExtra tenantExtra, - ConsumerFactory consumerFactory, + public BackupAjaxHandler( + BackupService backupService, + TenantManager tenantManager, + MessageService messageService, + CoreBaseSettings coreBaseSettings, + CoreConfiguration coreConfiguration, + PermissionContext permissionContext, + SecurityContext securityContext, + UserManager userManager, + TenantExtra tenantExtra, + ConsumerFactory consumerFactory, BackupFileUploadHandler backupFileUploadHandler) { TenantManager = tenantManager; @@ -57,8 +57,8 @@ public BackupAjaxHandler( SecurityContext = securityContext; UserManager = userManager; TenantExtra = tenantExtra; - ConsumerFactory = consumerFactory; - BackupFileUploadHandler = backupFileUploadHandler; + ConsumerFactory = consumerFactory; + BackupFileUploadHandler = backupFileUploadHandler; BackupService = backupService; } @@ -71,7 +71,7 @@ public void StartBackup(BackupStorageType storageType, Dictionary string.Format("0 0 {0} ? * *", Hour), - BackupPeriod.EveryMonth => string.Format("0 0 {0} {1} * ?", Hour, Day), - BackupPeriod.EveryWeek => string.Format("0 0 {0} ? * {1}", Hour, Day), - _ => base.ToString(), - }; + return Period switch + { + BackupPeriod.EveryDay => string.Format("0 0 {0} ? * *", Hour), + BackupPeriod.EveryMonth => string.Format("0 0 {0} {1} * ?", Hour, Day), + BackupPeriod.EveryWeek => string.Format("0 0 {0} ? * {1}", Hour, Day), + _ => base.ToString(), + }; } } diff --git a/common/services/ASC.Data.Backup/BackupFileUploadHandler.cs b/common/ASC.Data.Backup.Core/BackupFileUploadHandler.cs similarity index 96% rename from common/services/ASC.Data.Backup/BackupFileUploadHandler.cs rename to common/ASC.Data.Backup.Core/BackupFileUploadHandler.cs index a5a2d791169..c2dc6b9b04d 100644 --- a/common/services/ASC.Data.Backup/BackupFileUploadHandler.cs +++ b/common/ASC.Data.Backup.Core/BackupFileUploadHandler.cs @@ -1,100 +1,100 @@ -/* - * - * (c) Copyright Ascensio System Limited 2010-2021 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * -*/ - - -using System; -using System.IO; - -using ASC.Common; -using ASC.Core; - -using Microsoft.AspNetCore.Http; - -namespace ASC.Web.Studio.Core.Backup -{ - [Scope] - public class BackupFileUploadHandler - { - private const long MaxBackupFileSize = 1024L * 1024L * 1024L; - private const string BackupTempFolder = "backup"; - private const string BackupFileName = "backup.tmp"; - - private PermissionContext PermissionContext { get; } - private TempPath TempPath { get; } - private TenantManager TenantManager { get; } - - public BackupFileUploadHandler( - PermissionContext permissionContext, - TempPath tempPath, - TenantManager tenantManager) - { - PermissionContext = permissionContext; - TempPath = tempPath; - TenantManager = tenantManager; - } - - public string ProcessUpload(IFormFile file) - { - if (file == null) - { - return "No files."; - } - - if (!PermissionContext.CheckPermissions(SecutiryConstants.EditPortalSettings)) - { - return "Access denied."; - } - - if (file.Length <= 0 || file.Length > MaxBackupFileSize) - { - return $"File size must be greater than 0 and less than {MaxBackupFileSize} bytes"; - } - - try - { - var filePath = GetFilePath(); - - if (File.Exists(filePath)) - { - File.Delete(filePath); - } - - using (var fileStream = File.Create(filePath)) - { - file.CopyTo(fileStream); - } - - return string.Empty; - } - catch (Exception error) - { - return error.Message; - } - } - - internal string GetFilePath() - { - var folder = Path.Combine(TempPath.GetTempPath(), BackupTempFolder, TenantManager.GetCurrentTenant().TenantId.ToString()); - - if (!Directory.Exists(folder)) - { - Directory.CreateDirectory(folder); - } - - return Path.Combine(folder, BackupFileName); - } - } +/* + * + * (c) Copyright Ascensio System Limited 2010-2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + + +using System; +using System.IO; + +using ASC.Common; +using ASC.Core; + +using Microsoft.AspNetCore.Http; + +namespace ASC.Web.Studio.Core.Backup +{ + [Scope] + public class BackupFileUploadHandler + { + private const long MaxBackupFileSize = 1024L * 1024L * 1024L; + private const string BackupTempFolder = "backup"; + private const string BackupFileName = "backup.tmp"; + + private PermissionContext PermissionContext { get; } + private TempPath TempPath { get; } + private TenantManager TenantManager { get; } + + public BackupFileUploadHandler( + PermissionContext permissionContext, + TempPath tempPath, + TenantManager tenantManager) + { + PermissionContext = permissionContext; + TempPath = tempPath; + TenantManager = tenantManager; + } + + public string ProcessUpload(IFormFile file) + { + if (file == null) + { + return "No files."; + } + + if (!PermissionContext.CheckPermissions(SecutiryConstants.EditPortalSettings)) + { + return "Access denied."; + } + + if (file.Length <= 0 || file.Length > MaxBackupFileSize) + { + return $"File size must be greater than 0 and less than {MaxBackupFileSize} bytes"; + } + + try + { + var filePath = GetFilePath(); + + if (File.Exists(filePath)) + { + File.Delete(filePath); + } + + using (var fileStream = File.Create(filePath)) + { + file.CopyTo(fileStream); + } + + return string.Empty; + } + catch (Exception error) + { + return error.Message; + } + } + + internal string GetFilePath() + { + var folder = Path.Combine(TempPath.GetTempPath(), BackupTempFolder, TenantManager.GetCurrentTenant().TenantId.ToString()); + + if (!Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + + return Path.Combine(folder, BackupFileName); + } + } } \ No newline at end of file diff --git a/common/services/ASC.Data.Backup/BackupResource.Designer.cs b/common/ASC.Data.Backup.Core/BackupResource.Designer.cs similarity index 95% rename from common/services/ASC.Data.Backup/BackupResource.Designer.cs rename to common/ASC.Data.Backup.Core/BackupResource.Designer.cs index e24a8985314..8bb976a9c1f 100644 --- a/common/services/ASC.Data.Backup/BackupResource.Designer.cs +++ b/common/ASC.Data.Backup.Core/BackupResource.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace ASC.Data.Backup { +namespace ASC.Data.Backup.Core { using System; @@ -39,7 +39,7 @@ internal BackupResource() { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Data.Backup.BackupResource", typeof(BackupResource).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Data.Backup.Core.BackupResource", typeof(BackupResource).Assembly); resourceMan = temp; } return resourceMan; diff --git a/common/services/ASC.Data.Backup/BackupResource.resx b/common/ASC.Data.Backup.Core/BackupResource.resx similarity index 97% rename from common/services/ASC.Data.Backup/BackupResource.resx rename to common/ASC.Data.Backup.Core/BackupResource.resx index af666c13189..69c7f0c17ed 100644 --- a/common/services/ASC.Data.Backup/BackupResource.resx +++ b/common/ASC.Data.Backup.Core/BackupResource.resx @@ -1,67 +1,67 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.6.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.6.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - The backup file is invalid. Please, use a file created in ONLYOFFICE v11.5 or later. - - - Set Password - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.6.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.6.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The backup file is invalid. Please, use a file created in ONLYOFFICE v11.5 or later. + + + Set Password + \ No newline at end of file diff --git a/common/services/ASC.Data.Backup/Contracts/BackupServiceModel.cs b/common/ASC.Data.Backup.Core/Contracts/BackupServiceModel.cs similarity index 97% rename from common/services/ASC.Data.Backup/Contracts/BackupServiceModel.cs rename to common/ASC.Data.Backup.Core/Contracts/BackupServiceModel.cs index 38cb1423379..03066dcf335 100644 --- a/common/services/ASC.Data.Backup/Contracts/BackupServiceModel.cs +++ b/common/ASC.Data.Backup.Core/Contracts/BackupServiceModel.cs @@ -23,9 +23,9 @@ * */ -using System; -using System.Collections.Generic; - +using System; +using System.Collections.Generic; + namespace ASC.Data.Backup.Contracts { public enum BackupStorageType @@ -41,130 +41,130 @@ public enum BackupStorageType DataStore = 4, ThirdPartyConsumer = 5 - } + } public class StartBackupRequest { - public int TenantId { get; set; } - - - public Guid UserId { get; set; } - - - public bool BackupMail { get; set; } - - - public BackupStorageType StorageType { get; set; } - - - public string StorageBasePath { get; set; } - - + public int TenantId { get; set; } + + + public Guid UserId { get; set; } + + + public bool BackupMail { get; set; } + + + public BackupStorageType StorageType { get; set; } + + + public string StorageBasePath { get; set; } + + public Dictionary StorageParams { get; set; } - } - - + } + + public class BackupHistoryRecord - { - - public Guid Id { get; set; } - - - public string FileName { get; set; } - - - public BackupStorageType StorageType { get; set; } - - - public DateTime CreatedOn { get; set; } - - + { + + public Guid Id { get; set; } + + + public string FileName { get; set; } + + + public BackupStorageType StorageType { get; set; } + + + public DateTime CreatedOn { get; set; } + + public DateTime ExpiresOn { get; set; } - } - - + } + + public class StartTransferRequest - { - - public int TenantId { get; set; } - - - public string TargetRegion { get; set; } - - - public bool NotifyUsers { get; set; } - - + { + + public int TenantId { get; set; } + + + public string TargetRegion { get; set; } + + + public bool NotifyUsers { get; set; } + + public bool BackupMail { get; set; } - } - - + } + + public class TransferRegion - { - - public string Name { get; set; } - - - public string BaseDomain { get; set; } - - + { + + public string Name { get; set; } + + + public string BaseDomain { get; set; } + + public bool IsCurrentRegion { get; set; } - } - - + } + + public class StartRestoreRequest - { - - public int TenantId { get; set; } - - - public Guid BackupId { get; set; } - - - public BackupStorageType StorageType { get; set; } - - - public string FilePathOrId { get; set; } - - - public bool NotifyAfterCompletion { get; set; } - - + { + + public int TenantId { get; set; } + + + public Guid BackupId { get; set; } + + + public BackupStorageType StorageType { get; set; } + + + public string FilePathOrId { get; set; } + + + public bool NotifyAfterCompletion { get; set; } + + public Dictionary StorageParams { get; set; } - } - - + } + + public class CreateScheduleRequest : StartBackupRequest - { - - public string Cron { get; set; } - - + { + + public string Cron { get; set; } + + public int NumberOfBackupsStored { get; set; } - } - - + } + + public class ScheduleResponse - { - - public BackupStorageType StorageType { get; set; } - - - public string StorageBasePath { get; set; } - - - public bool BackupMail { get; set; } - - - public int NumberOfBackupsStored { get; set; } - - - public string Cron { get; set; } - - - public DateTime LastBackupTime { get; set; } - - + { + + public BackupStorageType StorageType { get; set; } + + + public string StorageBasePath { get; set; } + + + public bool BackupMail { get; set; } + + + public int NumberOfBackupsStored { get; set; } + + + public string Cron { get; set; } + + + public DateTime LastBackupTime { get; set; } + + public Dictionary StorageParams { get; set; } } } \ No newline at end of file diff --git a/common/services/ASC.Data.Backup/Contracts/IBackupService.cs b/common/ASC.Data.Backup.Core/Contracts/IBackupService.cs similarity index 100% rename from common/services/ASC.Data.Backup/Contracts/IBackupService.cs rename to common/ASC.Data.Backup.Core/Contracts/IBackupService.cs diff --git a/common/services/ASC.Data.Backup/Core/DbBackupProvider.cs b/common/ASC.Data.Backup.Core/Core/DbBackupProvider.cs similarity index 99% rename from common/services/ASC.Data.Backup/Core/DbBackupProvider.cs rename to common/ASC.Data.Backup.Core/Core/DbBackupProvider.cs index 24603332efe..8b157647a2f 100644 --- a/common/services/ASC.Data.Backup/Core/DbBackupProvider.cs +++ b/common/ASC.Data.Backup.Core/Core/DbBackupProvider.cs @@ -31,20 +31,20 @@ using System.IO; using System.Linq; using System.Threading; -using System.Xml.Linq; - +using System.Xml.Linq; + using ASC.Common; -using ASC.Common.Utils; - +using ASC.Common.Utils; + namespace ASC.Data.Backup -{ +{ [Scope] public class DbBackupProvider : IBackupProvider { private readonly List processedTables = new List(); - private readonly DbHelper dbHelper; - private readonly TempStream tempStream; - + private readonly DbHelper dbHelper; + private readonly TempStream tempStream; + public string Name { get { return "databases"; } @@ -52,8 +52,8 @@ public string Name public DbBackupProvider(DbHelper dbHelper, TempStream tempStream) { - this.dbHelper = dbHelper; - this.tempStream = tempStream; + this.dbHelper = dbHelper; + this.tempStream = tempStream; } public IEnumerable GetElements(int tenant, string[] configs, IDataWriteOperator writer) { @@ -104,13 +104,13 @@ private Configuration GetConfiguration(string config) { if (config.Contains(Path.DirectorySeparatorChar) && !Uri.IsWellFormedUriString(config, UriKind.Relative)) { - var map = new ExeConfigurationFileMap - { - ExeConfigFilename = string.Compare(Path.GetExtension(config), ".config", true) == 0 ? config : CrossPlatform.PathCombine(config, "Web.config") + var map = new ExeConfigurationFileMap + { + ExeConfigFilename = string.Compare(Path.GetExtension(config), ".config", true) == 0 ? config : CrossPlatform.PathCombine(config, "Web.config") }; return ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None); } - return ConfigurationManager.OpenExeConfiguration(config); + return ConfigurationManager.OpenExeConfiguration(config); } public IEnumerable GetConnectionStrings(string[] configs) @@ -178,12 +178,12 @@ private List BackupDatabase(int tenant, ConnectionStringSettings conne foreach (DataColumn c in dataTable.Columns) { if (c.DataType == typeof(DateTime)) c.DateTimeMode = DataSetDateTime.Unspecified; - } - - using (var file = tempStream.Create()) - { - dataTable.WriteXml(file, XmlWriteMode.WriteSchema); - writer.WriteEntry(string.Format("{0}\\{1}\\{2}", Name, connectionString.Name, table).ToLower(), file); + } + + using (var file = tempStream.Create()) + { + dataTable.WriteXml(file, XmlWriteMode.WriteSchema); + writer.WriteEntry(string.Format("{0}\\{1}\\{2}", Name, connectionString.Name, table).ToLower(), file); } processedTables.Add(table); @@ -224,6 +224,6 @@ private void RestoreDatabase(ConnectionStringSettings connectionString, IEnumera processedTables.Add(table); } } - } + } } } diff --git a/common/services/ASC.Data.Backup/Core/DbHelper.cs b/common/ASC.Data.Backup.Core/Core/DbHelper.cs similarity index 99% rename from common/services/ASC.Data.Backup/Core/DbHelper.cs rename to common/ASC.Data.Backup.Core/Core/DbHelper.cs index 21a44745128..3df6f196eba 100644 --- a/common/services/ASC.Data.Backup/Core/DbHelper.cs +++ b/common/ASC.Data.Backup.Core/Core/DbHelper.cs @@ -11,14 +11,14 @@ using ASC.Common; using ASC.Common.Logging; -using ASC.Common.Utils; +using ASC.Common.Utils; using ASC.Data.Backup.EF.Context; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; namespace ASC.Data.Backup -{ +{ [Scope] public class DbHelper : IDisposable { diff --git a/common/services/ASC.Data.Backup/Core/FileBackupProvider.cs b/common/ASC.Data.Backup.Core/Core/FileBackupProvider.cs similarity index 99% rename from common/services/ASC.Data.Backup/Core/FileBackupProvider.cs rename to common/ASC.Data.Backup.Core/Core/FileBackupProvider.cs index 54607383cdc..5494183ad23 100644 --- a/common/services/ASC.Data.Backup/Core/FileBackupProvider.cs +++ b/common/ASC.Data.Backup.Core/Core/FileBackupProvider.cs @@ -28,25 +28,25 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Xml.Linq; - +using System.Xml.Linq; + using ASC.Common; using ASC.Common.Logging; -using ASC.Common.Utils; -using ASC.Data.Storage; - +using ASC.Common.Utils; +using ASC.Data.Storage; + using Microsoft.Extensions.Options; namespace ASC.Data.Backup -{ +{ [Scope] public class FileBackupProvider : IBackupProvider { private readonly IEnumerable allowedModules; private readonly ILog log; private StorageFactory StorageFactory { get; set; } - private StorageFactoryConfig StorageFactoryConfig { get; set; } - + private StorageFactoryConfig StorageFactoryConfig { get; set; } + public FileBackupProvider(IOptionsMonitor options, StorageFactory storageFactory, StorageFactoryConfig storageFactoryConfig) { StorageFactory = storageFactory; @@ -90,7 +90,7 @@ public IEnumerable GetElements(int tenant, string[] configs, IDataWrit { try { - using var stream = storage.GetReadStream(file.Domain, file.Path); + using var stream = storage.GetReadStream(file.Domain, file.Path); writer.WriteEntry(backupPath, stream); break; } @@ -240,10 +240,10 @@ public bool Equals(FileBackupInfo other) return Equals(other.Module, Module) && Equals(other.Domain, Domain) && Equals(other.Path, Path); } - public override int GetHashCode() - { - return HashCode.Combine(Module, Domain, Path); - } + public override int GetHashCode() + { + return HashCode.Combine(Module, Domain, Path); + } } } } \ No newline at end of file diff --git a/common/services/ASC.Data.Backup/Core/IBackupProvider.cs b/common/ASC.Data.Backup.Core/Core/IBackupProvider.cs similarity index 100% rename from common/services/ASC.Data.Backup/Core/IBackupProvider.cs rename to common/ASC.Data.Backup.Core/Core/IBackupProvider.cs diff --git a/common/services/ASC.Data.Backup/Core/IDataOperator.cs b/common/ASC.Data.Backup.Core/Core/IDataOperator.cs similarity index 99% rename from common/services/ASC.Data.Backup/Core/IDataOperator.cs rename to common/ASC.Data.Backup.Core/Core/IDataOperator.cs index 323a323d9d3..a2d6f46bb37 100644 --- a/common/services/ASC.Data.Backup/Core/IDataOperator.cs +++ b/common/ASC.Data.Backup.Core/Core/IDataOperator.cs @@ -37,7 +37,7 @@ public interface IDataWriteOperator : IDisposable public interface IDataReadOperator : IDisposable { - Stream GetEntry(string key); + Stream GetEntry(string key); IEnumerable GetEntries(string key); } } \ No newline at end of file diff --git a/common/services/ASC.Data.Backup/Core/NotifyHelper.cs b/common/ASC.Data.Backup.Core/Core/NotifyHelper.cs similarity index 98% rename from common/services/ASC.Data.Backup/Core/NotifyHelper.cs rename to common/ASC.Data.Backup.Core/Core/NotifyHelper.cs index 818b8cb274b..db8968d5c6e 100644 --- a/common/services/ASC.Data.Backup/Core/NotifyHelper.cs +++ b/common/ASC.Data.Backup.Core/Core/NotifyHelper.cs @@ -25,222 +25,223 @@ using System; -using System.Collections.Generic; -using System.Linq; - +using System.Collections.Generic; +using System.Linq; + using ASC.Common; -using ASC.Core; -using ASC.Core.Tenants; -using ASC.Core.Users; -using ASC.Notify.Model; -using ASC.Notify.Patterns; -using ASC.Notify.Recipients; -using ASC.Web.Core.Users; -using ASC.Web.Core.WhiteLabel; -using ASC.Web.Studio.Core.Notify; -using ASC.Web.Studio.Utility; - -using Microsoft.Extensions.DependencyInjection; - +using ASC.Core; +using ASC.Core.Tenants; +using ASC.Core.Users; +using ASC.Data.Backup.Core; +using ASC.Notify.Model; +using ASC.Notify.Patterns; +using ASC.Notify.Recipients; +using ASC.Web.Core.Users; +using ASC.Web.Core.WhiteLabel; +using ASC.Web.Studio.Core.Notify; +using ASC.Web.Studio.Utility; + +using Microsoft.Extensions.DependencyInjection; + namespace ASC.Data.Backup -{ +{ [Singletone(Additional = typeof(NotifyHelperExtension))] public class NotifyHelper - { - private IServiceProvider ServiceProvider { get; } - + { + private IServiceProvider ServiceProvider { get; } + public NotifyHelper(IServiceProvider serviceProvider) - { - ServiceProvider = serviceProvider; - } + { + ServiceProvider = serviceProvider; + } public void SendAboutTransferStart(Tenant tenant, string targetRegion, bool notifyUsers) - { + { MigrationNotify(tenant, Actions.MigrationPortalStart, targetRegion, string.Empty, notifyUsers); } public void SendAboutTransferComplete(Tenant tenant, string targetRegion, string targetAddress, bool notifyOnlyOwner, int toTenantId) - { + { MigrationNotify(tenant, Actions.MigrationPortalSuccessV115, targetRegion, targetAddress, !notifyOnlyOwner, toTenantId); } public void SendAboutTransferError(Tenant tenant, string targetRegion, string resultAddress, bool notifyOnlyOwner) - { + { MigrationNotify(tenant, !string.IsNullOrEmpty(targetRegion) ? Actions.MigrationPortalError : Actions.MigrationPortalServerFailure, targetRegion, resultAddress, !notifyOnlyOwner); } public void SendAboutBackupCompleted(Guid userId) - { - using var scope = ServiceProvider.CreateScope(); - var scopeClass = scope.ServiceProvider.GetService(); - var (userManager, studioNotifyHelper, studioNotifySource, displayUserSettingsHelper, _) = scopeClass; - var client = WorkContext.NotifyContext.NotifyService.RegisterClient(studioNotifySource, scope); - - client.SendNoticeToAsync( - Actions.BackupCreated, - new[] { studioNotifyHelper.ToRecipient(userId) }, - new[] { StudioNotifyService.EMailSenderName }, + { + using var scope = ServiceProvider.CreateScope(); + var scopeClass = scope.ServiceProvider.GetService(); + var (userManager, studioNotifyHelper, studioNotifySource, displayUserSettingsHelper, _) = scopeClass; + var client = WorkContext.NotifyContext.NotifyService.RegisterClient(studioNotifySource, scope); + + client.SendNoticeToAsync( + Actions.BackupCreated, + new[] { studioNotifyHelper.ToRecipient(userId) }, + new[] { StudioNotifyService.EMailSenderName }, new TagValue(Tags.OwnerName, userManager.GetUsers(userId).DisplayUserName(displayUserSettingsHelper))); } public void SendAboutRestoreStarted(Tenant tenant, bool notifyAllUsers) - { - using var scope = ServiceProvider.CreateScope(); - var scopeClass = scope.ServiceProvider.GetService(); - var (userManager, studioNotifyHelper, studioNotifySource, displayUserSettingsHelper, _) = scopeClass; - var client = WorkContext.NotifyContext.NotifyService.RegisterClient(studioNotifySource, scope); - - var owner = userManager.GetUsers(tenant.OwnerId); - var users = - notifyAllUsers - ? studioNotifyHelper.RecipientFromEmail(userManager.GetUsers(EmployeeStatus.Active).Where(r => r.ActivationStatus == EmployeeActivationStatus.Activated).Select(u => u.Email).ToList(), false) - : owner.ActivationStatus == EmployeeActivationStatus.Activated ? studioNotifyHelper.RecipientFromEmail(owner.Email, false) : new IDirectRecipient[0]; - - client.SendNoticeToAsync( - Actions.RestoreStarted, - users, + { + using var scope = ServiceProvider.CreateScope(); + var scopeClass = scope.ServiceProvider.GetService(); + var (userManager, studioNotifyHelper, studioNotifySource, displayUserSettingsHelper, _) = scopeClass; + var client = WorkContext.NotifyContext.NotifyService.RegisterClient(studioNotifySource, scope); + + var owner = userManager.GetUsers(tenant.OwnerId); + var users = + notifyAllUsers + ? studioNotifyHelper.RecipientFromEmail(userManager.GetUsers(EmployeeStatus.Active).Where(r => r.ActivationStatus == EmployeeActivationStatus.Activated).Select(u => u.Email).ToList(), false) + : owner.ActivationStatus == EmployeeActivationStatus.Activated ? studioNotifyHelper.RecipientFromEmail(owner.Email, false) : new IDirectRecipient[0]; + + client.SendNoticeToAsync( + Actions.RestoreStarted, + users, new[] { StudioNotifyService.EMailSenderName }); } public void SendAboutRestoreCompleted(Tenant tenant, bool notifyAllUsers) - { - using var scope = ServiceProvider.CreateScope(); - var scopeClass = scope.ServiceProvider.GetService(); - var tenantManager = scope.ServiceProvider.GetService(); - var commonLinkUtility = scope.ServiceProvider.GetService(); - var (userManager, studioNotifyHelper, studioNotifySource, displayUserSettingsHelper, authManager) = scopeClass; - var client = WorkContext.NotifyContext.NotifyService.RegisterClient(studioNotifySource, scope); - - var owner = userManager.GetUsers(tenant.OwnerId); - var users = notifyAllUsers - ? userManager.GetUsers(EmployeeStatus.Active) - : new[] { userManager.GetUsers(tenantManager.GetCurrentTenant().OwnerId) }; - - foreach (var user in users) - { - var hash = authManager.GetUserPasswordStamp(user.ID).ToString("s"); - var confirmationUrl = commonLinkUtility.GetConfirmationUrl(user.Email, ConfirmType.PasswordChange, hash); - - Func greenButtonText = () => BackupResource.ButtonSetPassword; - - client.SendNoticeToAsync( - Actions.RestoreCompletedV115, - new IRecipient[] { user }, - new[] { StudioNotifyService.EMailSenderName }, - null, - TagValues.GreenButton(greenButtonText, confirmationUrl)); - } - } - - private void MigrationNotify(Tenant tenant, INotifyAction action, string region, string url, bool notify, int? toTenantId = null) - { - using var scope = ServiceProvider.CreateScope(); - var scopeClass = scope.ServiceProvider.GetService(); - var (userManager, studioNotifyHelper, studioNotifySource, _, authManager) = scopeClass; - var client = WorkContext.NotifyContext.NotifyService.RegisterClient(studioNotifySource, scope); - var commonLinkUtility = scope.ServiceProvider.GetService(); - - var users = userManager.GetUsers() - .Where(u => notify ? u.ActivationStatus.HasFlag(EmployeeActivationStatus.Activated) : u.IsOwner(tenant)) - .ToArray(); - - if (users.Any()) - { - var args = CreateArgs(scope, region, url); - if (action == Actions.MigrationPortalSuccessV115) - { - foreach (var user in users) - { - var currentArgs = new List(args); - - var newTenantId = toTenantId.HasValue ? toTenantId.Value : tenant.TenantId; - var hash = authManager.GetUserPasswordStamp(user.ID).ToString("s"); - var confirmationUrl = url + "/" + commonLinkUtility.GetConfirmationUrlRelative(newTenantId, user.Email, ConfirmType.PasswordChange, hash); - - Func greenButtonText = () => BackupResource.ButtonSetPassword; - currentArgs.Add(TagValues.GreenButton(greenButtonText, confirmationUrl)); - - client.SendNoticeToAsync( - action, - null, - new IRecipient[] { user }, - new[] { StudioNotifyService.EMailSenderName }, - currentArgs.ToArray()); - } - } - else - { - client.SendNoticeToAsync( - action, - null, - users.Select(u => studioNotifyHelper.ToRecipient(u.ID)).ToArray(), - new[] { StudioNotifyService.EMailSenderName }, - args.ToArray()); - } - } - } - - private List CreateArgs(IServiceScope scope,string region, string url) - { - var args = new List() - { - new TagValue(Tags.RegionName, TransferResourceHelper.GetRegionDescription(region)), - new TagValue(Tags.PortalUrl, url) - }; - - if (!string.IsNullOrEmpty(url)) - { - args.Add(new TagValue(CommonTags.VirtualRootPath, url)); - args.Add(new TagValue(CommonTags.ProfileUrl, url + scope.ServiceProvider.GetService().GetMyStaff())); - args.Add(new TagValue(CommonTags.LetterLogo, scope.ServiceProvider.GetService().GetLogoDark(true))); - } - return args; + { + using var scope = ServiceProvider.CreateScope(); + var scopeClass = scope.ServiceProvider.GetService(); + var tenantManager = scope.ServiceProvider.GetService(); + var commonLinkUtility = scope.ServiceProvider.GetService(); + var (userManager, studioNotifyHelper, studioNotifySource, displayUserSettingsHelper, authManager) = scopeClass; + var client = WorkContext.NotifyContext.NotifyService.RegisterClient(studioNotifySource, scope); + + var owner = userManager.GetUsers(tenant.OwnerId); + var users = notifyAllUsers + ? userManager.GetUsers(EmployeeStatus.Active) + : new[] { userManager.GetUsers(tenantManager.GetCurrentTenant().OwnerId) }; + + foreach (var user in users) + { + var hash = authManager.GetUserPasswordStamp(user.ID).ToString("s"); + var confirmationUrl = commonLinkUtility.GetConfirmationUrl(user.Email, ConfirmType.PasswordChange, hash); + + Func greenButtonText = () => BackupResource.ButtonSetPassword; + + client.SendNoticeToAsync( + Actions.RestoreCompletedV115, + new IRecipient[] { user }, + new[] { StudioNotifyService.EMailSenderName }, + null, + TagValues.GreenButton(greenButtonText, confirmationUrl)); + } + } + + private void MigrationNotify(Tenant tenant, INotifyAction action, string region, string url, bool notify, int? toTenantId = null) + { + using var scope = ServiceProvider.CreateScope(); + var scopeClass = scope.ServiceProvider.GetService(); + var (userManager, studioNotifyHelper, studioNotifySource, _, authManager) = scopeClass; + var client = WorkContext.NotifyContext.NotifyService.RegisterClient(studioNotifySource, scope); + var commonLinkUtility = scope.ServiceProvider.GetService(); + + var users = userManager.GetUsers() + .Where(u => notify ? u.ActivationStatus.HasFlag(EmployeeActivationStatus.Activated) : u.IsOwner(tenant)) + .ToArray(); + + if (users.Any()) + { + var args = CreateArgs(scope, region, url); + if (action == Actions.MigrationPortalSuccessV115) + { + foreach (var user in users) + { + var currentArgs = new List(args); + + var newTenantId = toTenantId.HasValue ? toTenantId.Value : tenant.TenantId; + var hash = authManager.GetUserPasswordStamp(user.ID).ToString("s"); + var confirmationUrl = url + "/" + commonLinkUtility.GetConfirmationUrlRelative(newTenantId, user.Email, ConfirmType.PasswordChange, hash); + + Func greenButtonText = () => BackupResource.ButtonSetPassword; + currentArgs.Add(TagValues.GreenButton(greenButtonText, confirmationUrl)); + + client.SendNoticeToAsync( + action, + null, + new IRecipient[] { user }, + new[] { StudioNotifyService.EMailSenderName }, + currentArgs.ToArray()); + } + } + else + { + client.SendNoticeToAsync( + action, + null, + users.Select(u => studioNotifyHelper.ToRecipient(u.ID)).ToArray(), + new[] { StudioNotifyService.EMailSenderName }, + args.ToArray()); + } + } + } + + private List CreateArgs(IServiceScope scope,string region, string url) + { + var args = new List() + { + new TagValue(Tags.RegionName, TransferResourceHelper.GetRegionDescription(region)), + new TagValue(Tags.PortalUrl, url) + }; + + if (!string.IsNullOrEmpty(url)) + { + args.Add(new TagValue(CommonTags.VirtualRootPath, url)); + args.Add(new TagValue(CommonTags.ProfileUrl, url + scope.ServiceProvider.GetService().GetMyStaff())); + args.Add(new TagValue(CommonTags.LetterLogo, scope.ServiceProvider.GetService().GetLogoDark(true))); + } + return args; } } - + [Scope] - public class NotifyHelperScope - { - private AuthManager AuthManager { get; } - private UserManager UserManager { get; } - private StudioNotifyHelper StudioNotifyHelper { get; } - private StudioNotifySource StudioNotifySource { get; } - private DisplayUserSettingsHelper DisplayUserSettingsHelper { get; } - - public NotifyHelperScope( - UserManager userManager, - StudioNotifyHelper studioNotifyHelper, - StudioNotifySource studioNotifySource, - DisplayUserSettingsHelper displayUserSettingsHelper, - AuthManager authManager) - { - UserManager = userManager; - StudioNotifyHelper = studioNotifyHelper; - StudioNotifySource = studioNotifySource; - DisplayUserSettingsHelper = displayUserSettingsHelper; - AuthManager = authManager; - } - - public void Deconstruct( - out UserManager userManager, - out StudioNotifyHelper studioNotifyHelper, - out StudioNotifySource studioNotifySource, - out DisplayUserSettingsHelper displayUserSettingsHelper, - out AuthManager authManager - ) - { - userManager = UserManager; - studioNotifyHelper = StudioNotifyHelper; - studioNotifySource = StudioNotifySource; - displayUserSettingsHelper = DisplayUserSettingsHelper; - authManager = AuthManager; - } + public class NotifyHelperScope + { + private AuthManager AuthManager { get; } + private UserManager UserManager { get; } + private StudioNotifyHelper StudioNotifyHelper { get; } + private StudioNotifySource StudioNotifySource { get; } + private DisplayUserSettingsHelper DisplayUserSettingsHelper { get; } + + public NotifyHelperScope( + UserManager userManager, + StudioNotifyHelper studioNotifyHelper, + StudioNotifySource studioNotifySource, + DisplayUserSettingsHelper displayUserSettingsHelper, + AuthManager authManager) + { + UserManager = userManager; + StudioNotifyHelper = studioNotifyHelper; + StudioNotifySource = studioNotifySource; + DisplayUserSettingsHelper = displayUserSettingsHelper; + AuthManager = authManager; + } + + public void Deconstruct( + out UserManager userManager, + out StudioNotifyHelper studioNotifyHelper, + out StudioNotifySource studioNotifySource, + out DisplayUserSettingsHelper displayUserSettingsHelper, + out AuthManager authManager + ) + { + userManager = UserManager; + studioNotifyHelper = StudioNotifyHelper; + studioNotifySource = StudioNotifySource; + displayUserSettingsHelper = DisplayUserSettingsHelper; + authManager = AuthManager; + } } public class NotifyHelperExtension { public static void Register(DIHelper services) - { + { services.TryAdd(); } } diff --git a/common/services/ASC.Data.Backup/Core/Schedule.cs b/common/ASC.Data.Backup.Core/Core/Schedule.cs similarity index 99% rename from common/services/ASC.Data.Backup/Core/Schedule.cs rename to common/ASC.Data.Backup.Core/Core/Schedule.cs index 6d034f5b40a..228be978c35 100644 --- a/common/services/ASC.Data.Backup/Core/Schedule.cs +++ b/common/ASC.Data.Backup.Core/Core/Schedule.cs @@ -11,7 +11,7 @@ using Microsoft.Extensions.Options; namespace ASC.Data.Backup -{ +{ [Scope] public class Schedule { diff --git a/common/services/ASC.Data.Backup/Core/ZipOperator.cs b/common/ASC.Data.Backup.Core/Core/ZipOperator.cs similarity index 99% rename from common/services/ASC.Data.Backup/Core/ZipOperator.cs rename to common/ASC.Data.Backup.Core/Core/ZipOperator.cs index f578570b560..764080ab7ca 100644 --- a/common/services/ASC.Data.Backup/Core/ZipOperator.cs +++ b/common/ASC.Data.Backup.Core/Core/ZipOperator.cs @@ -26,29 +26,29 @@ using System.Collections.Generic; using System.IO; -using System.Text; - -using ASC.Common; - -using ICSharpCode.SharpZipLib.GZip; -using ICSharpCode.SharpZipLib.Tar; +using System.Text; + +using ASC.Common; + +using ICSharpCode.SharpZipLib.GZip; +using ICSharpCode.SharpZipLib.Tar; namespace ASC.Data.Backup -{ +{ public class ZipWriteOperator : IDataWriteOperator { private readonly GZipOutputStream gZipOutputStream; private readonly TarOutputStream tarOutputStream; - private readonly Stream file; - + private readonly Stream file; + private TempStream TempStream { get; } public ZipWriteOperator(TempStream tempStream, string targetFile) { file = new FileStream(targetFile, FileMode.Create); gZipOutputStream = new GZipOutputStream(file); - tarOutputStream = new TarOutputStream(gZipOutputStream, Encoding.UTF8); - TempStream = tempStream; + tarOutputStream = new TarOutputStream(gZipOutputStream, Encoding.UTF8); + TempStream = tempStream; } public void WriteEntry(string key, Stream stream) diff --git a/common/services/ASC.Data.Backup/EF/BackupRecord.cs b/common/ASC.Data.Backup.Core/EF/BackupRecord.cs similarity index 99% rename from common/services/ASC.Data.Backup/EF/BackupRecord.cs rename to common/ASC.Data.Backup.Core/EF/BackupRecord.cs index e10ada610da..062e447a044 100644 --- a/common/services/ASC.Data.Backup/EF/BackupRecord.cs +++ b/common/ASC.Data.Backup.Core/EF/BackupRecord.cs @@ -17,8 +17,8 @@ public class BackupRecord : BaseEntity [Column("is_scheduled")] public bool IsScheduled { get; set; } - public string Name { get; set; } - + public string Name { get; set; } + public string Hash { get; set; } [Column("storage_type")] diff --git a/common/services/ASC.Data.Backup/EF/BackupSchedule.cs b/common/ASC.Data.Backup.Core/EF/BackupSchedule.cs similarity index 100% rename from common/services/ASC.Data.Backup/EF/BackupSchedule.cs rename to common/ASC.Data.Backup.Core/EF/BackupSchedule.cs diff --git a/common/services/ASC.Data.Backup/EF/BackupsContext.cs b/common/ASC.Data.Backup.Core/EF/BackupsContext.cs similarity index 99% rename from common/services/ASC.Data.Backup/EF/BackupsContext.cs rename to common/ASC.Data.Backup.Core/EF/BackupsContext.cs index d674c0e7d50..9723eed9686 100644 --- a/common/services/ASC.Data.Backup/EF/BackupsContext.cs +++ b/common/ASC.Data.Backup.Core/EF/BackupsContext.cs @@ -19,13 +19,13 @@ public BackupsContext() { } public BackupsContext(DbContextOptions options) : base(options) { - } - + } + protected override void OnModelCreating(ModelBuilder modelBuilder) { ModelBuilderWrapper .From(modelBuilder, Provider) - .AddDbTenant() + .AddDbTenant() .AddDbTariff(); } } diff --git a/common/services/ASC.Data.Backup/Exceptions/DbBackupException.cs b/common/ASC.Data.Backup.Core/Exceptions/DbBackupException.cs similarity index 100% rename from common/services/ASC.Data.Backup/Exceptions/DbBackupException.cs rename to common/ASC.Data.Backup.Core/Exceptions/DbBackupException.cs diff --git a/common/services/ASC.Data.Backup/Exceptions/ThrowHelper.cs b/common/ASC.Data.Backup.Core/Exceptions/ThrowHelper.cs similarity index 100% rename from common/services/ASC.Data.Backup/Exceptions/ThrowHelper.cs rename to common/ASC.Data.Backup.Core/Exceptions/ThrowHelper.cs diff --git a/common/services/ASC.Data.Backup/Extensions/DataExtensions.cs b/common/ASC.Data.Backup.Core/Extensions/DataExtensions.cs similarity index 100% rename from common/services/ASC.Data.Backup/Extensions/DataExtensions.cs rename to common/ASC.Data.Backup.Core/Extensions/DataExtensions.cs diff --git a/common/services/ASC.Data.Backup/Extensions/EnumerableExtensions.cs b/common/ASC.Data.Backup.Core/Extensions/EnumerableExtensions.cs similarity index 100% rename from common/services/ASC.Data.Backup/Extensions/EnumerableExtensions.cs rename to common/ASC.Data.Backup.Core/Extensions/EnumerableExtensions.cs diff --git a/common/services/ASC.Data.Backup/Extensions/XmlExtensions.cs b/common/ASC.Data.Backup.Core/Extensions/XmlExtensions.cs similarity index 100% rename from common/services/ASC.Data.Backup/Extensions/XmlExtensions.cs rename to common/ASC.Data.Backup.Core/Extensions/XmlExtensions.cs diff --git a/common/services/ASC.Data.Backup/Listerners/BackupListener.cs b/common/ASC.Data.Backup.Core/Listerners/BackupListener.cs similarity index 99% rename from common/services/ASC.Data.Backup/Listerners/BackupListener.cs rename to common/ASC.Data.Backup.Core/Listerners/BackupListener.cs index 2c174c584be..6828fd591c4 100644 --- a/common/services/ASC.Data.Backup/Listerners/BackupListener.cs +++ b/common/ASC.Data.Backup.Core/Listerners/BackupListener.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Data.Backup.Listerners -{ +{ [Singletone] public class BackupListener { diff --git a/common/services/ASC.Data.Backup/Service/BackupService.cs b/common/ASC.Data.Backup.Core/Service/BackupService.cs similarity index 99% rename from common/services/ASC.Data.Backup/Service/BackupService.cs rename to common/ASC.Data.Backup.Core/Service/BackupService.cs index 0ba6c0cd9c5..6e2a4f43d72 100644 --- a/common/services/ASC.Data.Backup/Service/BackupService.cs +++ b/common/ASC.Data.Backup.Core/Service/BackupService.cs @@ -28,20 +28,20 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.ServiceModel; - +using System.ServiceModel; + using ASC.Common; using ASC.Common.Logging; using ASC.Common.Utils; using ASC.Data.Backup.Contracts; using ASC.Data.Backup.EF.Model; using ASC.Data.Backup.Storage; -using ASC.Data.Backup.Utils; - -using Microsoft.Extensions.Options; - -using Newtonsoft.Json; - +using ASC.Data.Backup.Utils; + +using Microsoft.Extensions.Options; + +using Newtonsoft.Json; + namespace ASC.Data.Backup.Service { [Scope] @@ -190,34 +190,34 @@ public string GetTmpFolder() } public List GetTransferRegions() - { - var settings = Configuration.GetSetting("backup"); - return settings.WebConfigs.Elements.Select(configElement => - { - var config = Utils.ConfigurationProvider.Open(PathHelper.ToRootedConfigPath(configElement.Path)); - var baseDomain = config.AppSettings.Settings["core:base-domain"].Value; - return new TransferRegion - { - Name = configElement.Region, - BaseDomain = baseDomain, - IsCurrentRegion = configElement.Region.Equals(settings.WebConfigs.CurrentRegion, StringComparison.InvariantCultureIgnoreCase) - }; - }) - .ToList(); + { + var settings = Configuration.GetSetting("backup"); + return settings.WebConfigs.Elements.Select(configElement => + { + var config = Utils.ConfigurationProvider.Open(PathHelper.ToRootedConfigPath(configElement.Path)); + var baseDomain = config.AppSettings.Settings["core:base-domain"].Value; + return new TransferRegion + { + Name = configElement.Region, + BaseDomain = baseDomain, + IsCurrentRegion = configElement.Region.Equals(settings.WebConfigs.CurrentRegion, StringComparison.InvariantCultureIgnoreCase) + }; + }) + .ToList(); } public void CreateSchedule(CreateScheduleRequest request) { BackupRepository.SaveBackupSchedule( - new BackupSchedule() - { - TenantId = request.TenantId, - Cron = request.Cron, - BackupMail = request.BackupMail, - BackupsStored = request.NumberOfBackupsStored, - StorageType = request.StorageType, - StorageBasePath = request.StorageBasePath, - StorageParams = JsonConvert.SerializeObject(request.StorageParams) + new BackupSchedule() + { + TenantId = request.TenantId, + Cron = request.Cron, + BackupMail = request.BackupMail, + BackupsStored = request.NumberOfBackupsStored, + StorageType = request.StorageType, + StorageBasePath = request.StorageBasePath, + StorageParams = JsonConvert.SerializeObject(request.StorageParams) }); } @@ -229,23 +229,23 @@ public void DeleteSchedule(int tenantId) public ScheduleResponse GetSchedule(int tenantId) { var schedule = BackupRepository.GetBackupSchedule(tenantId); - if (schedule != null) - { - var tmp = new ScheduleResponse - { - StorageType = schedule.StorageType, - StorageBasePath = schedule.StorageBasePath, - BackupMail = schedule.BackupMail, - NumberOfBackupsStored = schedule.BackupsStored, - Cron = schedule.Cron, - LastBackupTime = schedule.LastBackupTime, - StorageParams = JsonConvert.DeserializeObject>(schedule.StorageParams) - }; - return tmp; - } - else - { - return null; + if (schedule != null) + { + var tmp = new ScheduleResponse + { + StorageType = schedule.StorageType, + StorageBasePath = schedule.StorageBasePath, + BackupMail = schedule.BackupMail, + NumberOfBackupsStored = schedule.BackupsStored, + Cron = schedule.Cron, + LastBackupTime = schedule.LastBackupTime, + StorageParams = JsonConvert.DeserializeObject>(schedule.StorageParams) + }; + return tmp; + } + else + { + return null; } } } diff --git a/common/services/ASC.Data.Backup/Service/BackupSettings.cs b/common/ASC.Data.Backup.Core/Service/BackupSettings.cs similarity index 100% rename from common/services/ASC.Data.Backup/Service/BackupSettings.cs rename to common/ASC.Data.Backup.Core/Service/BackupSettings.cs diff --git a/common/services/ASC.Data.Backup/Service/BackupWorker.cs b/common/ASC.Data.Backup.Core/Service/BackupWorker.cs similarity index 97% rename from common/services/ASC.Data.Backup/Service/BackupWorker.cs rename to common/ASC.Data.Backup.Core/Service/BackupWorker.cs index 290f5494f0e..634a54d7d38 100644 --- a/common/services/ASC.Data.Backup/Service/BackupWorker.cs +++ b/common/ASC.Data.Backup.Core/Service/BackupWorker.cs @@ -1,901 +1,902 @@ -/* - * - * (c) Copyright Ascensio System Limited 2010-2020 - * - * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). - * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html - * - * You can contact Ascensio System SIA by email at sales@onlyoffice.com - * - * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display - * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. - * - * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains - * relevant author attributions when distributing the software. If the display of the logo in its graphic - * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" - * in every copy of the program you distribute. - * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. - * -*/ - - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Threading; - -using ASC.Common; -using ASC.Common.Caching; -using ASC.Common.Logging; -using ASC.Common.Threading; -using ASC.Common.Utils; -using ASC.Core; -using ASC.Core.Tenants; -using ASC.Data.Backup.Contracts; -using ASC.Data.Backup.EF.Model; -using ASC.Data.Backup.Storage; -using ASC.Data.Backup.Tasks; -using ASC.Data.Backup.Tasks.Modules; -using ASC.Data.Backup.Utils; - -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; - -using Newtonsoft.Json; - -namespace ASC.Data.Backup.Service -{ - [Singletone(Additional = typeof(BackupWorkerExtension))] - public class BackupWorker - { - private ILog Log { get; set; } - private DistributedTaskQueue ProgressQueue { get; set; } - internal string TempFolder { get; set; } - private string CurrentRegion { get; set; } - private Dictionary ConfigPaths { get; set; } - private int Limit { get; set; } - private string UpgradesPath { get; set; } - private ICacheNotify CacheBackupProgress { get; } - private FactoryProgressItem FactoryProgressItem { get; set; } - private TempPath TempPath { get; } - - private readonly object SynchRoot = new object(); - - public BackupWorker( - IOptionsMonitor options, - ICacheNotify cacheBackupProgress, - DistributedTaskQueueOptionsManager progressQueue, - FactoryProgressItem factoryProgressItem, - TempPath tempPath) - { - Log = options.CurrentValue; - ProgressQueue = progressQueue.Get(); - CacheBackupProgress = cacheBackupProgress; - FactoryProgressItem = factoryProgressItem; - TempPath = tempPath; - } - - public void Start(BackupSettings settings) - { - TempFolder = TempPath.GetTempPath(); - if (!Directory.Exists(TempFolder)) - { - Directory.CreateDirectory(TempFolder); - } - - Limit = settings.Limit; - UpgradesPath = settings.UpgradesPath; - CurrentRegion = settings.WebConfigs.CurrentRegion; - ConfigPaths = settings.WebConfigs.Elements.ToDictionary(el => el.Region, el => PathHelper.ToRootedConfigPath(el.Path)); - ConfigPaths[CurrentRegion] = PathHelper.ToRootedConfigPath(settings.WebConfigs.CurrentPath); - - var invalidConfigPath = ConfigPaths.Values.FirstOrDefault(path => !File.Exists(path)); - if (invalidConfigPath != null) - { - Log.WarnFormat("Configuration file {0} not found", invalidConfigPath); - } - } - - public void Stop() - { - if (ProgressQueue != null) - { - var tasks = ProgressQueue.GetTasks(); - foreach (var t in tasks) - { - ProgressQueue.CancelTask(t.Id); - } - - ProgressQueue = null; - } - } - - public BackupProgress StartBackup(StartBackupRequest request) - { - lock (SynchRoot) - { - var item = ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == request.TenantId); - if (item != null && item.IsCompleted) - { - ProgressQueue.RemoveTask(item.Id); - item = null; - } - if (item == null) - { - item = FactoryProgressItem.CreateBackupProgressItem(request, false, TempFolder, Limit, CurrentRegion, ConfigPaths); - ProgressQueue.QueueTask(item); - } - - item.PublishChanges(); - - return ToBackupProgress(item); - } - } - - public void StartScheduledBackup(BackupSchedule schedule) - { - lock (SynchRoot) - { - var item = ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == schedule.TenantId); - if (item != null && item.IsCompleted) - { - ProgressQueue.RemoveTask(item.Id); - item = null; - } - if (item == null) - { - item = FactoryProgressItem.CreateBackupProgressItem(schedule, false, TempFolder, Limit, CurrentRegion, ConfigPaths); - ProgressQueue.QueueTask(item); - } - } - } - - public BackupProgress GetBackupProgress(int tenantId) - { - lock (SynchRoot) - { - return ToBackupProgress(ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == tenantId)); - } - } - - public BackupProgress GetTransferProgress(int tenantId) - { - lock (SynchRoot) - { - return ToBackupProgress(ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == tenantId)); - } - } - - public BackupProgress GetRestoreProgress(int tenantId) - { - lock (SynchRoot) - { - return ToBackupProgress(ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == tenantId)); - } - } - - public void ResetBackupError(int tenantId) - { - lock (SynchRoot) - { - var progress = ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == tenantId); - if (progress != null) - { - progress.Exception = null; - } - } - } - - public void ResetRestoreError(int tenantId) - { - lock (SynchRoot) - { - var progress = ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == tenantId); - if (progress != null) - { - progress.Exception = null; - } - } - } - - public BackupProgress StartRestore(StartRestoreRequest request) - { - lock (SynchRoot) - { - var item = ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == request.TenantId); - if (item != null && item.IsCompleted) - { - ProgressQueue.RemoveTask(item.Id); - item = null; - } - if (item == null) - { - item = FactoryProgressItem.CreateRestoreProgressItem(request, TempFolder, UpgradesPath, CurrentRegion, ConfigPaths); - ProgressQueue.QueueTask(item); - } - return ToBackupProgress(item); - } - } - - public BackupProgress StartTransfer(int tenantId, string targetRegion, bool transferMail, bool notify) - { - lock (SynchRoot) - { - var item = ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == tenantId); - if (item != null && item.IsCompleted) - { - ProgressQueue.RemoveTask(item.Id); - item = null; - } - - if (item == null) - { - item = FactoryProgressItem.CreateTransferProgressItem(targetRegion, transferMail, tenantId, TempFolder, Limit, notify, CurrentRegion, ConfigPaths); - ProgressQueue.QueueTask(item); - } - - return ToBackupProgress(item); - } - } - - - private BackupProgress ToBackupProgress(BaseBackupProgressItem progressItem) - { - if (progressItem == null) - { - return null; - } - var progress = new BackupProgress - { - IsCompleted = progressItem.IsCompleted, - Progress = (int)progressItem.Percentage, - Error = progressItem.Exception != null ? progressItem.Exception.Message : "", - TenantId = progressItem.TenantId, - BackupProgressEnum = progressItem.BackupProgressItemEnum.Convert() - }; - - if (progressItem is BackupProgressItem backupProgressItem && backupProgressItem.Link != null) - { - progress.Link = backupProgressItem.Link; - } - else - { - if (progressItem is TransferProgressItem transferProgressItem && transferProgressItem.Link != null) - { - progress.Link = transferProgressItem.Link; - } - } - - return progress; - } - - internal static string GetBackupHash(string path) - { - using (var sha256 = SHA256.Create()) - using (var fileStream = File.OpenRead(path)) - { - fileStream.Position = 0; - var hash = sha256.ComputeHash(fileStream); - return BitConverter.ToString(hash).Replace("-", string.Empty); - } - } - } - - public enum BackupProgressItemEnum - { - Backup, - Restore, - Transfer - } - - public static class BackupProgressItemEnumConverter - { - public static BackupProgressEnum Convert(this BackupProgressItemEnum backupProgressItemEnum) - { - return backupProgressItemEnum switch - { - BackupProgressItemEnum.Backup => BackupProgressEnum.Backup, - BackupProgressItemEnum.Restore => BackupProgressEnum.Restore, - BackupProgressItemEnum.Transfer => BackupProgressEnum.Transfer, - _ => BackupProgressEnum.Backup - }; - } - } - - public abstract class BaseBackupProgressItem : DistributedTaskProgress - { - private int? tenantId; - public int TenantId - { - get - { - return tenantId ?? GetProperty(nameof(tenantId)); - } - set - { - tenantId = value; - SetProperty(nameof(tenantId), value); - } - } - - public abstract BackupProgressItemEnum BackupProgressItemEnum { get; } - - public abstract object Clone(); - - protected ILog Log { get; set; } - - protected IServiceProvider ServiceProvider { get; set; } - - public BaseBackupProgressItem(IOptionsMonitor options, IServiceProvider serviceProvider) - { - Log = options.CurrentValue; - ServiceProvider = serviceProvider; - } - } - - [Transient] - public class BackupProgressItem : BaseBackupProgressItem - { - private const string ArchiveFormat = "tar.gz"; - - public BackupProgressItem(IOptionsMonitor options, IServiceProvider serviceProvider) : base(options, serviceProvider) - { - } - - public override BackupProgressItemEnum BackupProgressItemEnum { get => BackupProgressItemEnum.Backup; } - - private bool IsScheduled { get; set; } - private Guid UserId { get; set; } - private BackupStorageType StorageType { get; set; } - private string StorageBasePath { get; set; } - public bool BackupMail { get; set; } - public Dictionary StorageParams { get; set; } - public string Link { get; private set; } - public string TempFolder { get; set; } - private string CurrentRegion { get; set; } - private Dictionary ConfigPaths { get; set; } - private int Limit { get; set; } - - public void Init(BackupSchedule schedule, bool isScheduled, string tempFolder, int limit, string currentRegion, Dictionary configPaths) - { - UserId = Guid.Empty; - TenantId = schedule.TenantId; - StorageType = schedule.StorageType; - StorageBasePath = schedule.StorageBasePath; - BackupMail = schedule.BackupMail; - StorageParams = JsonConvert.DeserializeObject>(schedule.StorageParams); - IsScheduled = isScheduled; - TempFolder = tempFolder; - Limit = limit; - CurrentRegion = currentRegion; - ConfigPaths = configPaths; - } - - public void Init(StartBackupRequest request, bool isScheduled, string tempFolder, int limit, string currentRegion, Dictionary configPaths) - { - UserId = request.UserId; - TenantId = request.TenantId; - StorageType = request.StorageType; - StorageBasePath = request.StorageBasePath; - BackupMail = request.BackupMail; - StorageParams = request.StorageParams.ToDictionary(r => r.Key, r => r.Value); - IsScheduled = isScheduled; - TempFolder = tempFolder; - Limit = limit; - CurrentRegion = currentRegion; - ConfigPaths = configPaths; - } - - protected override void DoJob() - { - if (ThreadPriority.BelowNormal < Thread.CurrentThread.Priority) - { - Thread.CurrentThread.Priority = ThreadPriority.BelowNormal; - } - - using var scope = ServiceProvider.CreateScope(); - var scopeClass = scope.ServiceProvider.GetService(); - var (tenantManager, backupStorageFactory, notifyHelper, backupRepository, backupWorker, backupPortalTask, _, _, coreBaseSettings) = scopeClass; - - var tenant = tenantManager.GetTenant(TenantId); - var dateTime = coreBaseSettings.Standalone ? DateTime.Now : DateTime.UtcNow; - var backupName = string.Format("{0}_{1:yyyy-MM-dd_HH-mm-ss}.{2}", tenantManager.GetTenant(TenantId).TenantAlias, dateTime, ArchiveFormat); - - var tempFile = CrossPlatform.PathCombine(TempFolder, backupName); - var storagePath = tempFile; - try - { - var backupTask = backupPortalTask; - - backupTask.Init(TenantId, ConfigPaths[CurrentRegion], tempFile, Limit); - if (!BackupMail) - { - backupTask.IgnoreModule(ModuleName.Mail); - } - - backupTask.ProgressChanged += (sender, args) => - { - Percentage = 0.9 * args.Progress; - PublishChanges(); - }; - - backupTask.RunJob(); - - var backupStorage = backupStorageFactory.GetBackupStorage(StorageType, TenantId, StorageParams); - if (backupStorage != null) - { - storagePath = backupStorage.Upload(StorageBasePath, tempFile, UserId); - Link = backupStorage.GetPublicLink(storagePath); - } - - var repo = backupRepository; - repo.SaveBackupRecord( - new BackupRecord - { - Id = Guid.Parse(Id), - TenantId = TenantId, - IsScheduled = IsScheduled, - Name = Path.GetFileName(tempFile), - StorageType = StorageType, - StorageBasePath = StorageBasePath, - StoragePath = storagePath, - CreatedOn = DateTime.UtcNow, - ExpiresOn = StorageType == BackupStorageType.DataStore ? DateTime.UtcNow.AddDays(1) : DateTime.MinValue, - StorageParams = JsonConvert.SerializeObject(StorageParams), - Hash = BackupWorker.GetBackupHash(tempFile) - }); - - Percentage = 100; - - if (UserId != Guid.Empty && !IsScheduled) - { - notifyHelper.SendAboutBackupCompleted(UserId); - } - - IsCompleted = true; - PublishChanges(); - } - catch (Exception error) - { - Log.ErrorFormat("RunJob - Params: {0}, Error = {1}", new { Id, Tenant = TenantId, File = tempFile, BasePath = StorageBasePath, }, error); - Exception = error; - IsCompleted = true; - } - finally - { - try - { - PublishChanges(); - } - catch (Exception error) - { - Log.Error("publish", error); - } - - try - { - if (!(storagePath == tempFile && StorageType == BackupStorageType.Local)) - { - File.Delete(tempFile); - } - } - catch (Exception error) - { - Log.Error("can't delete file: {0}", error); - } - } - } - - public override object Clone() - { - return MemberwiseClone(); - } - } - - [Transient] - public class RestoreProgressItem : BaseBackupProgressItem - { - public RestoreProgressItem(IOptionsMonitor options, IServiceProvider serviceProvider) : base(options, serviceProvider) - { - } - - public override BackupProgressItemEnum BackupProgressItemEnum { get => BackupProgressItemEnum.Restore; } - public BackupStorageType StorageType { get; set; } - public string StoragePath { get; set; } - public bool Notify { get; set; } - public Dictionary StorageParams { get; set; } - public string TempFolder { get; set; } - private string CurrentRegion { get; set; } - private string UpgradesPath { get; set; } - private Dictionary ConfigPaths { get; set; } - - public void Init(StartRestoreRequest request, string tempFolder, string upgradesPath, string currentRegion, Dictionary configPaths) - { - TenantId = request.TenantId; - Notify = request.NotifyAfterCompletion; - StoragePath = request.FilePathOrId; - StorageType = request.StorageType; - TempFolder = tempFolder; - UpgradesPath = upgradesPath; - CurrentRegion = currentRegion; - ConfigPaths = configPaths; - } - - protected override void DoJob() - { - using var scope = ServiceProvider.CreateScope(); - var scopeClass = scope.ServiceProvider.GetService(); - var (tenantManager, backupStorageFactory, notifyHelper, backupRepository, backupWorker, _, restorePortalTask, _, coreBaseSettings) = scopeClass; - Tenant tenant = null; - var tempFile = PathHelper.GetTempFileName(TempFolder); - try - { - tenant = tenantManager.GetTenant(TenantId); - tenantManager.SetCurrentTenant(tenant); - notifyHelper.SendAboutRestoreStarted(tenant, Notify); - var storage = backupStorageFactory.GetBackupStorage(StorageType, TenantId, StorageParams); - storage.Download(StoragePath, tempFile); - - if (!coreBaseSettings.Standalone) - { - var backupHash = BackupWorker.GetBackupHash(tempFile); - var record = backupRepository.GetBackupRecord(backupHash, TenantId); - if (record == null) - { - throw new Exception(BackupResource.BackupNotFound); - } - } - - Percentage = 10; - - tenant.SetStatus(TenantStatus.Restoring); - tenantManager.SaveTenant(tenant); - - var columnMapper = new ColumnMapper(); - columnMapper.SetMapping("tenants_tenants", "alias", tenant.TenantAlias, (Guid.Parse(Id)).ToString("N")); - columnMapper.Commit(); - - var restoreTask = restorePortalTask; - restoreTask.Init(ConfigPaths[CurrentRegion], tempFile, TenantId, columnMapper, UpgradesPath); - restoreTask.ProgressChanged += (sender, args) => - { - Percentage = Percentage = (10d + 0.65 * args.Progress); - PublishChanges(); - }; - restoreTask.RunJob(); - - Tenant restoredTenant = null; - - if (restoreTask.Dump) - { - AscCacheNotify.OnClearCache(); - - if (Notify) - { - var tenants = tenantManager.GetTenants(); - foreach (var t in tenants) - { - notifyHelper.SendAboutRestoreCompleted(t, Notify); - } - } - } - else - { - tenantManager.RemoveTenant(tenant.TenantId); - - restoredTenant = tenantManager.GetTenant(columnMapper.GetTenantMapping()); - restoredTenant.SetStatus(TenantStatus.Active); - restoredTenant.TenantAlias = tenant.TenantAlias; - restoredTenant.PaymentId = string.Empty; - if (string.IsNullOrEmpty(restoredTenant.MappedDomain) && !string.IsNullOrEmpty(tenant.MappedDomain)) - { - restoredTenant.MappedDomain = tenant.MappedDomain; - } - tenantManager.SaveTenant(restoredTenant); - tenantManager.SetCurrentTenant(restoredTenant); - // sleep until tenants cache expires - Thread.Sleep(TimeSpan.FromMinutes(2)); - - notifyHelper.SendAboutRestoreCompleted(restoredTenant, Notify); - } - - Percentage = 75; - - PublishChanges(); - - File.Delete(tempFile); - - Percentage = 100; - PublishChanges(); - } - catch (Exception error) - { - Log.Error(error); - Exception = error; - - if (tenant != null) - { - tenant.SetStatus(TenantStatus.Active); - tenantManager.SaveTenant(tenant); - } - } - finally - { - try - { - PublishChanges(); - } - catch (Exception error) - { - Log.Error("publish", error); - } - - if (File.Exists(tempFile)) - { - File.Delete(tempFile); - } - } - } - - public override object Clone() - { - return MemberwiseClone(); - } - - - } - - [Transient] - public class TransferProgressItem : BaseBackupProgressItem - { - public TransferProgressItem(IOptionsMonitor options, IServiceProvider serviceProvider) : base(options, serviceProvider) - { - } - - public override BackupProgressItemEnum BackupProgressItemEnum { get => BackupProgressItemEnum.Transfer; } - public string TargetRegion { get; set; } - public bool TransferMail { get; set; } - public bool Notify { get; set; } - - public string Link { get; set; } - public string TempFolder { get; set; } - public Dictionary ConfigPaths { get; set; } - public string CurrentRegion { get; set; } - public int Limit { get; set; } - - public void Init( - string targetRegion, - bool transferMail, - int tenantId, - string tempFolder, - int limit, - bool notify, - string currentRegion, - Dictionary configPaths) - { - TenantId = tenantId; - TargetRegion = targetRegion; - TransferMail = transferMail; - Notify = notify; - TempFolder = tempFolder; - ConfigPaths = configPaths; - CurrentRegion = currentRegion; - Limit = limit; - - } - - protected override void DoJob() - { - using var scope = ServiceProvider.CreateScope(); - var scopeClass = scope.ServiceProvider.GetService(); - var (tenantManager, _, notifyHelper, _, backupWorker, _, _, transferPortalTask, _) = scopeClass; - var tempFile = PathHelper.GetTempFileName(TempFolder); - var tenant = tenantManager.GetTenant(TenantId); - var alias = tenant.TenantAlias; - - try - { - notifyHelper.SendAboutTransferStart(tenant, TargetRegion, Notify); - var transferProgressItem = transferPortalTask; - transferProgressItem.Init(TenantId, ConfigPaths[CurrentRegion], ConfigPaths[TargetRegion], Limit, TempFolder); - transferProgressItem.ProgressChanged += (sender, args) => - { - Percentage = args.Progress; - PublishChanges(); - }; - if (!TransferMail) - { - transferProgressItem.IgnoreModule(ModuleName.Mail); - } - transferProgressItem.RunJob(); - - Link = GetLink(alias, false); - notifyHelper.SendAboutTransferComplete(tenant, TargetRegion, Link, !Notify, transferProgressItem.ToTenantId); - PublishChanges(); - } - catch (Exception error) - { - Log.Error(error); - Exception = error; - - Link = GetLink(alias, true); - notifyHelper.SendAboutTransferError(tenant, TargetRegion, Link, !Notify); - } - finally - { - try - { - PublishChanges(); - } - catch (Exception error) - { - Log.Error("publish", error); - } - - if (File.Exists(tempFile)) - { - File.Delete(tempFile); - } - } - } - - private string GetLink(string alias, bool isErrorLink) - { - return "https://" + alias + "." + ConfigurationProvider.Open(ConfigPaths[isErrorLink ? CurrentRegion : TargetRegion]).AppSettings.Settings["core:base-domain"].Value; - } - - public override object Clone() - { - return MemberwiseClone(); - } - } - - [Singletone(Additional = typeof(FactoryProgressItemExtension))] - public class FactoryProgressItem - { - public IServiceProvider ServiceProvider { get; } - - public FactoryProgressItem(IServiceProvider serviceProvider) - { - ServiceProvider = serviceProvider; - } - - public BackupProgressItem CreateBackupProgressItem( - StartBackupRequest request, - bool isScheduled, - string tempFolder, - int limit, - string currentRegion, - Dictionary configPaths) - { - var item = ServiceProvider.GetService(); - item.Init(request, isScheduled, tempFolder, limit, currentRegion, configPaths); - return item; - } - - public BackupProgressItem CreateBackupProgressItem( - BackupSchedule schedule, - bool isScheduled, - string tempFolder, - int limit, - string currentRegion, - Dictionary configPaths - ) - { - var item = ServiceProvider.GetService(); - item.Init(schedule, isScheduled, tempFolder, limit, currentRegion, configPaths); - return item; - } - - public RestoreProgressItem CreateRestoreProgressItem( - StartRestoreRequest request, - string tempFolder, - string upgradesPath, - string currentRegion, - Dictionary configPaths - ) - { - var item = ServiceProvider.GetService(); - item.Init(request, tempFolder, upgradesPath, currentRegion, configPaths); - return item; - } - - public TransferProgressItem CreateTransferProgressItem( - string targetRegion, - bool transferMail, - int tenantId, - string tempFolder, - int limit, - bool notify, - string currentRegion, - Dictionary configPaths - ) - { - var item = ServiceProvider.GetService(); - item.Init(targetRegion, transferMail, tenantId, tempFolder, limit, notify, currentRegion, configPaths); - return item; - } - } - - [Scope] - internal class BackupWorkerScope - { - private TenantManager TenantManager { get; } - private BackupStorageFactory BackupStorageFactory { get; } - private NotifyHelper NotifyHelper { get; } - private BackupRepository BackupRepository { get; } - private BackupWorker BackupWorker { get; } - private BackupPortalTask BackupPortalTask { get; } - private RestorePortalTask RestorePortalTask { get; } - private TransferPortalTask TransferPortalTask { get; } - private CoreBaseSettings CoreBaseSettings { get; } - - public BackupWorkerScope(TenantManager tenantManager, - BackupStorageFactory backupStorageFactory, - NotifyHelper notifyHelper, - BackupRepository backupRepository, - BackupWorker backupWorker, - BackupPortalTask backupPortalTask, - RestorePortalTask restorePortalTask, - TransferPortalTask transferPortalTask, - CoreBaseSettings coreBaseSettings) - { - TenantManager = tenantManager; - BackupStorageFactory = backupStorageFactory; - NotifyHelper = notifyHelper; - BackupRepository = backupRepository; - BackupWorker = backupWorker; - BackupPortalTask = backupPortalTask; - RestorePortalTask = restorePortalTask; - TransferPortalTask = transferPortalTask; - CoreBaseSettings = coreBaseSettings; - } - - public void Deconstruct(out TenantManager tenantManager, - out BackupStorageFactory backupStorageFactory, - out NotifyHelper notifyHelper, - out BackupRepository backupRepository, - out BackupWorker backupWorker, - out BackupPortalTask backupPortalTask, - out RestorePortalTask restorePortalTask, - out TransferPortalTask transferPortalTask, - out CoreBaseSettings coreBaseSettings) - { - tenantManager = TenantManager; - backupStorageFactory = BackupStorageFactory; - notifyHelper = NotifyHelper; - backupRepository = BackupRepository; - backupWorker = BackupWorker; - backupPortalTask = BackupPortalTask; - restorePortalTask = RestorePortalTask; - transferPortalTask = TransferPortalTask; - coreBaseSettings = CoreBaseSettings; - } - } - - public class BackupWorkerExtension - { - public static void Register(DIHelper services) - { - services.TryAdd(); - services.AddDistributedTaskQueueService(5); - } - } - - public class FactoryProgressItemExtension - { - public static void Register(DIHelper services) - { - services.TryAdd(); - services.TryAdd(); - services.TryAdd(); - } - } -} +/* + * + * (c) Copyright Ascensio System Limited 2010-2020 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Threading; + +using ASC.Common; +using ASC.Common.Caching; +using ASC.Common.Logging; +using ASC.Common.Threading; +using ASC.Common.Utils; +using ASC.Core; +using ASC.Core.Tenants; +using ASC.Data.Backup.Contracts; +using ASC.Data.Backup.Core; +using ASC.Data.Backup.EF.Model; +using ASC.Data.Backup.Storage; +using ASC.Data.Backup.Tasks; +using ASC.Data.Backup.Tasks.Modules; +using ASC.Data.Backup.Utils; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +using Newtonsoft.Json; + +namespace ASC.Data.Backup.Service +{ + [Singletone(Additional = typeof(BackupWorkerExtension))] + public class BackupWorker + { + private ILog Log { get; set; } + private DistributedTaskQueue ProgressQueue { get; set; } + internal string TempFolder { get; set; } + private string CurrentRegion { get; set; } + private Dictionary ConfigPaths { get; set; } + private int Limit { get; set; } + private string UpgradesPath { get; set; } + private ICacheNotify CacheBackupProgress { get; } + private FactoryProgressItem FactoryProgressItem { get; set; } + private TempPath TempPath { get; } + + private readonly object SynchRoot = new object(); + + public BackupWorker( + IOptionsMonitor options, + ICacheNotify cacheBackupProgress, + DistributedTaskQueueOptionsManager progressQueue, + FactoryProgressItem factoryProgressItem, + TempPath tempPath) + { + Log = options.CurrentValue; + ProgressQueue = progressQueue.Get(); + CacheBackupProgress = cacheBackupProgress; + FactoryProgressItem = factoryProgressItem; + TempPath = tempPath; + } + + public void Start(BackupSettings settings) + { + TempFolder = TempPath.GetTempPath(); + if (!Directory.Exists(TempFolder)) + { + Directory.CreateDirectory(TempFolder); + } + + Limit = settings.Limit; + UpgradesPath = settings.UpgradesPath; + CurrentRegion = settings.WebConfigs.CurrentRegion; + ConfigPaths = settings.WebConfigs.Elements.ToDictionary(el => el.Region, el => PathHelper.ToRootedConfigPath(el.Path)); + ConfigPaths[CurrentRegion] = PathHelper.ToRootedConfigPath(settings.WebConfigs.CurrentPath); + + var invalidConfigPath = ConfigPaths.Values.FirstOrDefault(path => !File.Exists(path)); + if (invalidConfigPath != null) + { + Log.WarnFormat("Configuration file {0} not found", invalidConfigPath); + } + } + + public void Stop() + { + if (ProgressQueue != null) + { + var tasks = ProgressQueue.GetTasks(); + foreach (var t in tasks) + { + ProgressQueue.CancelTask(t.Id); + } + + ProgressQueue = null; + } + } + + public BackupProgress StartBackup(StartBackupRequest request) + { + lock (SynchRoot) + { + var item = ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == request.TenantId); + if (item != null && item.IsCompleted) + { + ProgressQueue.RemoveTask(item.Id); + item = null; + } + if (item == null) + { + item = FactoryProgressItem.CreateBackupProgressItem(request, false, TempFolder, Limit, CurrentRegion, ConfigPaths); + ProgressQueue.QueueTask(item); + } + + item.PublishChanges(); + + return ToBackupProgress(item); + } + } + + public void StartScheduledBackup(BackupSchedule schedule) + { + lock (SynchRoot) + { + var item = ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == schedule.TenantId); + if (item != null && item.IsCompleted) + { + ProgressQueue.RemoveTask(item.Id); + item = null; + } + if (item == null) + { + item = FactoryProgressItem.CreateBackupProgressItem(schedule, false, TempFolder, Limit, CurrentRegion, ConfigPaths); + ProgressQueue.QueueTask(item); + } + } + } + + public BackupProgress GetBackupProgress(int tenantId) + { + lock (SynchRoot) + { + return ToBackupProgress(ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == tenantId)); + } + } + + public BackupProgress GetTransferProgress(int tenantId) + { + lock (SynchRoot) + { + return ToBackupProgress(ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == tenantId)); + } + } + + public BackupProgress GetRestoreProgress(int tenantId) + { + lock (SynchRoot) + { + return ToBackupProgress(ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == tenantId)); + } + } + + public void ResetBackupError(int tenantId) + { + lock (SynchRoot) + { + var progress = ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == tenantId); + if (progress != null) + { + progress.Exception = null; + } + } + } + + public void ResetRestoreError(int tenantId) + { + lock (SynchRoot) + { + var progress = ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == tenantId); + if (progress != null) + { + progress.Exception = null; + } + } + } + + public BackupProgress StartRestore(StartRestoreRequest request) + { + lock (SynchRoot) + { + var item = ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == request.TenantId); + if (item != null && item.IsCompleted) + { + ProgressQueue.RemoveTask(item.Id); + item = null; + } + if (item == null) + { + item = FactoryProgressItem.CreateRestoreProgressItem(request, TempFolder, UpgradesPath, CurrentRegion, ConfigPaths); + ProgressQueue.QueueTask(item); + } + return ToBackupProgress(item); + } + } + + public BackupProgress StartTransfer(int tenantId, string targetRegion, bool transferMail, bool notify) + { + lock (SynchRoot) + { + var item = ProgressQueue.GetTasks().FirstOrDefault(t => t.TenantId == tenantId); + if (item != null && item.IsCompleted) + { + ProgressQueue.RemoveTask(item.Id); + item = null; + } + + if (item == null) + { + item = FactoryProgressItem.CreateTransferProgressItem(targetRegion, transferMail, tenantId, TempFolder, Limit, notify, CurrentRegion, ConfigPaths); + ProgressQueue.QueueTask(item); + } + + return ToBackupProgress(item); + } + } + + + private BackupProgress ToBackupProgress(BaseBackupProgressItem progressItem) + { + if (progressItem == null) + { + return null; + } + var progress = new BackupProgress + { + IsCompleted = progressItem.IsCompleted, + Progress = (int)progressItem.Percentage, + Error = progressItem.Exception != null ? progressItem.Exception.Message : "", + TenantId = progressItem.TenantId, + BackupProgressEnum = progressItem.BackupProgressItemEnum.Convert() + }; + + if (progressItem is BackupProgressItem backupProgressItem && backupProgressItem.Link != null) + { + progress.Link = backupProgressItem.Link; + } + else + { + if (progressItem is TransferProgressItem transferProgressItem && transferProgressItem.Link != null) + { + progress.Link = transferProgressItem.Link; + } + } + + return progress; + } + + internal static string GetBackupHash(string path) + { + using (var sha256 = SHA256.Create()) + using (var fileStream = File.OpenRead(path)) + { + fileStream.Position = 0; + var hash = sha256.ComputeHash(fileStream); + return BitConverter.ToString(hash).Replace("-", string.Empty); + } + } + } + + public enum BackupProgressItemEnum + { + Backup, + Restore, + Transfer + } + + public static class BackupProgressItemEnumConverter + { + public static BackupProgressEnum Convert(this BackupProgressItemEnum backupProgressItemEnum) + { + return backupProgressItemEnum switch + { + BackupProgressItemEnum.Backup => BackupProgressEnum.Backup, + BackupProgressItemEnum.Restore => BackupProgressEnum.Restore, + BackupProgressItemEnum.Transfer => BackupProgressEnum.Transfer, + _ => BackupProgressEnum.Backup + }; + } + } + + public abstract class BaseBackupProgressItem : DistributedTaskProgress + { + private int? tenantId; + public int TenantId + { + get + { + return tenantId ?? GetProperty(nameof(tenantId)); + } + set + { + tenantId = value; + SetProperty(nameof(tenantId), value); + } + } + + public abstract BackupProgressItemEnum BackupProgressItemEnum { get; } + + public abstract object Clone(); + + protected ILog Log { get; set; } + + protected IServiceProvider ServiceProvider { get; set; } + + public BaseBackupProgressItem(IOptionsMonitor options, IServiceProvider serviceProvider) + { + Log = options.CurrentValue; + ServiceProvider = serviceProvider; + } + } + + [Transient] + public class BackupProgressItem : BaseBackupProgressItem + { + private const string ArchiveFormat = "tar.gz"; + + public BackupProgressItem(IOptionsMonitor options, IServiceProvider serviceProvider) : base(options, serviceProvider) + { + } + + public override BackupProgressItemEnum BackupProgressItemEnum { get => BackupProgressItemEnum.Backup; } + + private bool IsScheduled { get; set; } + private Guid UserId { get; set; } + private BackupStorageType StorageType { get; set; } + private string StorageBasePath { get; set; } + public bool BackupMail { get; set; } + public Dictionary StorageParams { get; set; } + public string Link { get; private set; } + public string TempFolder { get; set; } + private string CurrentRegion { get; set; } + private Dictionary ConfigPaths { get; set; } + private int Limit { get; set; } + + public void Init(BackupSchedule schedule, bool isScheduled, string tempFolder, int limit, string currentRegion, Dictionary configPaths) + { + UserId = Guid.Empty; + TenantId = schedule.TenantId; + StorageType = schedule.StorageType; + StorageBasePath = schedule.StorageBasePath; + BackupMail = schedule.BackupMail; + StorageParams = JsonConvert.DeserializeObject>(schedule.StorageParams); + IsScheduled = isScheduled; + TempFolder = tempFolder; + Limit = limit; + CurrentRegion = currentRegion; + ConfigPaths = configPaths; + } + + public void Init(StartBackupRequest request, bool isScheduled, string tempFolder, int limit, string currentRegion, Dictionary configPaths) + { + UserId = request.UserId; + TenantId = request.TenantId; + StorageType = request.StorageType; + StorageBasePath = request.StorageBasePath; + BackupMail = request.BackupMail; + StorageParams = request.StorageParams.ToDictionary(r => r.Key, r => r.Value); + IsScheduled = isScheduled; + TempFolder = tempFolder; + Limit = limit; + CurrentRegion = currentRegion; + ConfigPaths = configPaths; + } + + protected override void DoJob() + { + if (ThreadPriority.BelowNormal < Thread.CurrentThread.Priority) + { + Thread.CurrentThread.Priority = ThreadPriority.BelowNormal; + } + + using var scope = ServiceProvider.CreateScope(); + var scopeClass = scope.ServiceProvider.GetService(); + var (tenantManager, backupStorageFactory, notifyHelper, backupRepository, backupWorker, backupPortalTask, _, _, coreBaseSettings) = scopeClass; + + var tenant = tenantManager.GetTenant(TenantId); + var dateTime = coreBaseSettings.Standalone ? DateTime.Now : DateTime.UtcNow; + var backupName = string.Format("{0}_{1:yyyy-MM-dd_HH-mm-ss}.{2}", tenantManager.GetTenant(TenantId).TenantAlias, dateTime, ArchiveFormat); + + var tempFile = CrossPlatform.PathCombine(TempFolder, backupName); + var storagePath = tempFile; + try + { + var backupTask = backupPortalTask; + + backupTask.Init(TenantId, ConfigPaths[CurrentRegion], tempFile, Limit); + if (!BackupMail) + { + backupTask.IgnoreModule(ModuleName.Mail); + } + + backupTask.ProgressChanged += (sender, args) => + { + Percentage = 0.9 * args.Progress; + PublishChanges(); + }; + + backupTask.RunJob(); + + var backupStorage = backupStorageFactory.GetBackupStorage(StorageType, TenantId, StorageParams); + if (backupStorage != null) + { + storagePath = backupStorage.Upload(StorageBasePath, tempFile, UserId); + Link = backupStorage.GetPublicLink(storagePath); + } + + var repo = backupRepository; + repo.SaveBackupRecord( + new BackupRecord + { + Id = Guid.Parse(Id), + TenantId = TenantId, + IsScheduled = IsScheduled, + Name = Path.GetFileName(tempFile), + StorageType = StorageType, + StorageBasePath = StorageBasePath, + StoragePath = storagePath, + CreatedOn = DateTime.UtcNow, + ExpiresOn = StorageType == BackupStorageType.DataStore ? DateTime.UtcNow.AddDays(1) : DateTime.MinValue, + StorageParams = JsonConvert.SerializeObject(StorageParams), + Hash = BackupWorker.GetBackupHash(tempFile) + }); + + Percentage = 100; + + if (UserId != Guid.Empty && !IsScheduled) + { + notifyHelper.SendAboutBackupCompleted(UserId); + } + + IsCompleted = true; + PublishChanges(); + } + catch (Exception error) + { + Log.ErrorFormat("RunJob - Params: {0}, Error = {1}", new { Id, Tenant = TenantId, File = tempFile, BasePath = StorageBasePath, }, error); + Exception = error; + IsCompleted = true; + } + finally + { + try + { + PublishChanges(); + } + catch (Exception error) + { + Log.Error("publish", error); + } + + try + { + if (!(storagePath == tempFile && StorageType == BackupStorageType.Local)) + { + File.Delete(tempFile); + } + } + catch (Exception error) + { + Log.Error("can't delete file: {0}", error); + } + } + } + + public override object Clone() + { + return MemberwiseClone(); + } + } + + [Transient] + public class RestoreProgressItem : BaseBackupProgressItem + { + public RestoreProgressItem(IOptionsMonitor options, IServiceProvider serviceProvider) : base(options, serviceProvider) + { + } + + public override BackupProgressItemEnum BackupProgressItemEnum { get => BackupProgressItemEnum.Restore; } + public BackupStorageType StorageType { get; set; } + public string StoragePath { get; set; } + public bool Notify { get; set; } + public Dictionary StorageParams { get; set; } + public string TempFolder { get; set; } + private string CurrentRegion { get; set; } + private string UpgradesPath { get; set; } + private Dictionary ConfigPaths { get; set; } + + public void Init(StartRestoreRequest request, string tempFolder, string upgradesPath, string currentRegion, Dictionary configPaths) + { + TenantId = request.TenantId; + Notify = request.NotifyAfterCompletion; + StoragePath = request.FilePathOrId; + StorageType = request.StorageType; + TempFolder = tempFolder; + UpgradesPath = upgradesPath; + CurrentRegion = currentRegion; + ConfigPaths = configPaths; + } + + protected override void DoJob() + { + using var scope = ServiceProvider.CreateScope(); + var scopeClass = scope.ServiceProvider.GetService(); + var (tenantManager, backupStorageFactory, notifyHelper, backupRepository, backupWorker, _, restorePortalTask, _, coreBaseSettings) = scopeClass; + Tenant tenant = null; + var tempFile = PathHelper.GetTempFileName(TempFolder); + try + { + tenant = tenantManager.GetTenant(TenantId); + tenantManager.SetCurrentTenant(tenant); + notifyHelper.SendAboutRestoreStarted(tenant, Notify); + var storage = backupStorageFactory.GetBackupStorage(StorageType, TenantId, StorageParams); + storage.Download(StoragePath, tempFile); + + if (!coreBaseSettings.Standalone) + { + var backupHash = BackupWorker.GetBackupHash(tempFile); + var record = backupRepository.GetBackupRecord(backupHash, TenantId); + if (record == null) + { + throw new Exception(BackupResource.BackupNotFound); + } + } + + Percentage = 10; + + tenant.SetStatus(TenantStatus.Restoring); + tenantManager.SaveTenant(tenant); + + var columnMapper = new ColumnMapper(); + columnMapper.SetMapping("tenants_tenants", "alias", tenant.TenantAlias, (Guid.Parse(Id)).ToString("N")); + columnMapper.Commit(); + + var restoreTask = restorePortalTask; + restoreTask.Init(ConfigPaths[CurrentRegion], tempFile, TenantId, columnMapper, UpgradesPath); + restoreTask.ProgressChanged += (sender, args) => + { + Percentage = Percentage = (10d + 0.65 * args.Progress); + PublishChanges(); + }; + restoreTask.RunJob(); + + Tenant restoredTenant = null; + + if (restoreTask.Dump) + { + AscCacheNotify.OnClearCache(); + + if (Notify) + { + var tenants = tenantManager.GetTenants(); + foreach (var t in tenants) + { + notifyHelper.SendAboutRestoreCompleted(t, Notify); + } + } + } + else + { + tenantManager.RemoveTenant(tenant.TenantId); + + restoredTenant = tenantManager.GetTenant(columnMapper.GetTenantMapping()); + restoredTenant.SetStatus(TenantStatus.Active); + restoredTenant.TenantAlias = tenant.TenantAlias; + restoredTenant.PaymentId = string.Empty; + if (string.IsNullOrEmpty(restoredTenant.MappedDomain) && !string.IsNullOrEmpty(tenant.MappedDomain)) + { + restoredTenant.MappedDomain = tenant.MappedDomain; + } + tenantManager.SaveTenant(restoredTenant); + tenantManager.SetCurrentTenant(restoredTenant); + // sleep until tenants cache expires + Thread.Sleep(TimeSpan.FromMinutes(2)); + + notifyHelper.SendAboutRestoreCompleted(restoredTenant, Notify); + } + + Percentage = 75; + + PublishChanges(); + + File.Delete(tempFile); + + Percentage = 100; + PublishChanges(); + } + catch (Exception error) + { + Log.Error(error); + Exception = error; + + if (tenant != null) + { + tenant.SetStatus(TenantStatus.Active); + tenantManager.SaveTenant(tenant); + } + } + finally + { + try + { + PublishChanges(); + } + catch (Exception error) + { + Log.Error("publish", error); + } + + if (File.Exists(tempFile)) + { + File.Delete(tempFile); + } + } + } + + public override object Clone() + { + return MemberwiseClone(); + } + + + } + + [Transient] + public class TransferProgressItem : BaseBackupProgressItem + { + public TransferProgressItem(IOptionsMonitor options, IServiceProvider serviceProvider) : base(options, serviceProvider) + { + } + + public override BackupProgressItemEnum BackupProgressItemEnum { get => BackupProgressItemEnum.Transfer; } + public string TargetRegion { get; set; } + public bool TransferMail { get; set; } + public bool Notify { get; set; } + + public string Link { get; set; } + public string TempFolder { get; set; } + public Dictionary ConfigPaths { get; set; } + public string CurrentRegion { get; set; } + public int Limit { get; set; } + + public void Init( + string targetRegion, + bool transferMail, + int tenantId, + string tempFolder, + int limit, + bool notify, + string currentRegion, + Dictionary configPaths) + { + TenantId = tenantId; + TargetRegion = targetRegion; + TransferMail = transferMail; + Notify = notify; + TempFolder = tempFolder; + ConfigPaths = configPaths; + CurrentRegion = currentRegion; + Limit = limit; + + } + + protected override void DoJob() + { + using var scope = ServiceProvider.CreateScope(); + var scopeClass = scope.ServiceProvider.GetService(); + var (tenantManager, _, notifyHelper, _, backupWorker, _, _, transferPortalTask, _) = scopeClass; + var tempFile = PathHelper.GetTempFileName(TempFolder); + var tenant = tenantManager.GetTenant(TenantId); + var alias = tenant.TenantAlias; + + try + { + notifyHelper.SendAboutTransferStart(tenant, TargetRegion, Notify); + var transferProgressItem = transferPortalTask; + transferProgressItem.Init(TenantId, ConfigPaths[CurrentRegion], ConfigPaths[TargetRegion], Limit, TempFolder); + transferProgressItem.ProgressChanged += (sender, args) => + { + Percentage = args.Progress; + PublishChanges(); + }; + if (!TransferMail) + { + transferProgressItem.IgnoreModule(ModuleName.Mail); + } + transferProgressItem.RunJob(); + + Link = GetLink(alias, false); + notifyHelper.SendAboutTransferComplete(tenant, TargetRegion, Link, !Notify, transferProgressItem.ToTenantId); + PublishChanges(); + } + catch (Exception error) + { + Log.Error(error); + Exception = error; + + Link = GetLink(alias, true); + notifyHelper.SendAboutTransferError(tenant, TargetRegion, Link, !Notify); + } + finally + { + try + { + PublishChanges(); + } + catch (Exception error) + { + Log.Error("publish", error); + } + + if (File.Exists(tempFile)) + { + File.Delete(tempFile); + } + } + } + + private string GetLink(string alias, bool isErrorLink) + { + return "https://" + alias + "." + ConfigurationProvider.Open(ConfigPaths[isErrorLink ? CurrentRegion : TargetRegion]).AppSettings.Settings["core:base-domain"].Value; + } + + public override object Clone() + { + return MemberwiseClone(); + } + } + + [Singletone(Additional = typeof(FactoryProgressItemExtension))] + public class FactoryProgressItem + { + public IServiceProvider ServiceProvider { get; } + + public FactoryProgressItem(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public BackupProgressItem CreateBackupProgressItem( + StartBackupRequest request, + bool isScheduled, + string tempFolder, + int limit, + string currentRegion, + Dictionary configPaths) + { + var item = ServiceProvider.GetService(); + item.Init(request, isScheduled, tempFolder, limit, currentRegion, configPaths); + return item; + } + + public BackupProgressItem CreateBackupProgressItem( + BackupSchedule schedule, + bool isScheduled, + string tempFolder, + int limit, + string currentRegion, + Dictionary configPaths + ) + { + var item = ServiceProvider.GetService(); + item.Init(schedule, isScheduled, tempFolder, limit, currentRegion, configPaths); + return item; + } + + public RestoreProgressItem CreateRestoreProgressItem( + StartRestoreRequest request, + string tempFolder, + string upgradesPath, + string currentRegion, + Dictionary configPaths + ) + { + var item = ServiceProvider.GetService(); + item.Init(request, tempFolder, upgradesPath, currentRegion, configPaths); + return item; + } + + public TransferProgressItem CreateTransferProgressItem( + string targetRegion, + bool transferMail, + int tenantId, + string tempFolder, + int limit, + bool notify, + string currentRegion, + Dictionary configPaths + ) + { + var item = ServiceProvider.GetService(); + item.Init(targetRegion, transferMail, tenantId, tempFolder, limit, notify, currentRegion, configPaths); + return item; + } + } + + [Scope] + internal class BackupWorkerScope + { + private TenantManager TenantManager { get; } + private BackupStorageFactory BackupStorageFactory { get; } + private NotifyHelper NotifyHelper { get; } + private BackupRepository BackupRepository { get; } + private BackupWorker BackupWorker { get; } + private BackupPortalTask BackupPortalTask { get; } + private RestorePortalTask RestorePortalTask { get; } + private TransferPortalTask TransferPortalTask { get; } + private CoreBaseSettings CoreBaseSettings { get; } + + public BackupWorkerScope(TenantManager tenantManager, + BackupStorageFactory backupStorageFactory, + NotifyHelper notifyHelper, + BackupRepository backupRepository, + BackupWorker backupWorker, + BackupPortalTask backupPortalTask, + RestorePortalTask restorePortalTask, + TransferPortalTask transferPortalTask, + CoreBaseSettings coreBaseSettings) + { + TenantManager = tenantManager; + BackupStorageFactory = backupStorageFactory; + NotifyHelper = notifyHelper; + BackupRepository = backupRepository; + BackupWorker = backupWorker; + BackupPortalTask = backupPortalTask; + RestorePortalTask = restorePortalTask; + TransferPortalTask = transferPortalTask; + CoreBaseSettings = coreBaseSettings; + } + + public void Deconstruct(out TenantManager tenantManager, + out BackupStorageFactory backupStorageFactory, + out NotifyHelper notifyHelper, + out BackupRepository backupRepository, + out BackupWorker backupWorker, + out BackupPortalTask backupPortalTask, + out RestorePortalTask restorePortalTask, + out TransferPortalTask transferPortalTask, + out CoreBaseSettings coreBaseSettings) + { + tenantManager = TenantManager; + backupStorageFactory = BackupStorageFactory; + notifyHelper = NotifyHelper; + backupRepository = BackupRepository; + backupWorker = BackupWorker; + backupPortalTask = BackupPortalTask; + restorePortalTask = RestorePortalTask; + transferPortalTask = TransferPortalTask; + coreBaseSettings = CoreBaseSettings; + } + } + + public class BackupWorkerExtension + { + public static void Register(DIHelper services) + { + services.TryAdd(); + services.AddDistributedTaskQueueService(5); + } + } + + public class FactoryProgressItemExtension + { + public static void Register(DIHelper services) + { + services.TryAdd(); + services.TryAdd(); + services.TryAdd(); + } + } +} diff --git a/common/services/ASC.Data.Backup/Storage/BackupRepository.cs b/common/ASC.Data.Backup.Core/Storage/BackupRepository.cs similarity index 99% rename from common/services/ASC.Data.Backup/Storage/BackupRepository.cs rename to common/ASC.Data.Backup.Core/Storage/BackupRepository.cs index 89dad1e9693..c442e973c1d 100644 --- a/common/services/ASC.Data.Backup/Storage/BackupRepository.cs +++ b/common/ASC.Data.Backup.Core/Storage/BackupRepository.cs @@ -26,18 +26,18 @@ using System; using System.Collections.Generic; -using System.Linq; - -using ASC.Common; -using ASC.Core.Common.EF; +using System.Linq; + +using ASC.Common; +using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Data.Backup.EF.Context; -using ASC.Data.Backup.EF.Model; +using ASC.Data.Backup.EF.Model; namespace ASC.Data.Backup.Storage -{ +{ [Scope] public class BackupRepository : IBackupRepository - { + { private Lazy LazyBackupsContext { get; } private BackupsContext BackupContext { get => LazyBackupsContext.Value; } @@ -49,21 +49,21 @@ public BackupRepository(DbContextManager backupContext) public void SaveBackupRecord(BackupRecord backup) { BackupContext.AddOrUpdate(r => r.Backups, backup); - BackupContext.SaveChanges(); + BackupContext.SaveChanges(); } public BackupRecord GetBackupRecord(Guid id) - { - return BackupContext.Backups.SingleOrDefault(b => b.Id == id); - } - - public BackupRecord GetBackupRecord(string hash, int tenant) - { - return BackupContext.Backups.SingleOrDefault(b => b.Hash == hash && b.TenantId == tenant); - } + { + return BackupContext.Backups.SingleOrDefault(b => b.Id == id); + } + + public BackupRecord GetBackupRecord(string hash, int tenant) + { + return BackupContext.Backups.SingleOrDefault(b => b.Hash == hash && b.TenantId == tenant); + } public List GetExpiredBackupRecords() - { + { return BackupContext.Backups.Where(b => b.ExpiresOn != DateTime.MinValue && b.ExpiresOn <= DateTime.UtcNow).ToList(); } @@ -104,18 +104,18 @@ public void DeleteBackupSchedule(int tenantId) public List GetBackupSchedules() { var query = BackupContext.Schedules.Join(BackupContext.Tenants, - s => s.TenantId, + s => s.TenantId, t => t.Id, - (s, t) => new { schedule = s, tenant = t }) - .Where(q => q.tenant.Status == TenantStatus.Active) - .Select(q => q.schedule); + (s, t) => new { schedule = s, tenant = t }) + .Where(q => q.tenant.Status == TenantStatus.Active) + .Select(q => q.schedule); return query.ToList(); } public BackupSchedule GetBackupSchedule(int tenantId) - { - return BackupContext.Schedules.SingleOrDefault(s => s.TenantId == tenantId); - } + { + return BackupContext.Schedules.SingleOrDefault(s => s.TenantId == tenantId); + } } } diff --git a/common/services/ASC.Data.Backup/Storage/BackupStorageFactory.cs b/common/ASC.Data.Backup.Core/Storage/BackupStorageFactory.cs similarity index 99% rename from common/services/ASC.Data.Backup/Storage/BackupStorageFactory.cs rename to common/ASC.Data.Backup.Core/Storage/BackupStorageFactory.cs index 1baf5def6a7..1047310e08d 100644 --- a/common/services/ASC.Data.Backup/Storage/BackupStorageFactory.cs +++ b/common/ASC.Data.Backup.Core/Storage/BackupStorageFactory.cs @@ -25,92 +25,92 @@ using System; -using System.Collections.Generic; - +using System.Collections.Generic; + using ASC.Common; -using ASC.Common.Logging; +using ASC.Common.Logging; using ASC.Common.Utils; using ASC.Core; -using ASC.Data.Backup.Contracts; +using ASC.Data.Backup.Contracts; using ASC.Data.Backup.EF.Model; using ASC.Data.Backup.Service; -using ASC.Data.Backup.Utils; - -using Microsoft.Extensions.Options; - -using Newtonsoft.Json; - +using ASC.Data.Backup.Utils; + +using Microsoft.Extensions.Options; + +using Newtonsoft.Json; + namespace ASC.Data.Backup.Storage -{ +{ [Scope] public class BackupStorageFactory { private ConfigurationExtension Configuration { get; } private DocumentsBackupStorage DocumentsBackupStorage { get; } - private DataStoreBackupStorage DataStoreBackupStorage { get; } - private ILog Log { get; } + private DataStoreBackupStorage DataStoreBackupStorage { get; } + private ILog Log { get; } private LocalBackupStorage LocalBackupStorage { get; } private ConsumerBackupStorage ConsumerBackupStorage { get; } private TenantManager TenantManager { get; } - public BackupStorageFactory( - ConsumerBackupStorage consumerBackupStorage, - LocalBackupStorage localBackupStorage, - ConfigurationExtension configuration, - DocumentsBackupStorage documentsBackupStorage, - TenantManager tenantManager, - DataStoreBackupStorage dataStoreBackupStorage, + public BackupStorageFactory( + ConsumerBackupStorage consumerBackupStorage, + LocalBackupStorage localBackupStorage, + ConfigurationExtension configuration, + DocumentsBackupStorage documentsBackupStorage, + TenantManager tenantManager, + DataStoreBackupStorage dataStoreBackupStorage, IOptionsMonitor options) { Configuration = configuration; DocumentsBackupStorage = documentsBackupStorage; - DataStoreBackupStorage = dataStoreBackupStorage; - Log = options.CurrentValue; + DataStoreBackupStorage = dataStoreBackupStorage; + Log = options.CurrentValue; LocalBackupStorage = localBackupStorage; ConsumerBackupStorage = consumerBackupStorage; TenantManager = tenantManager; - } - + } + public IBackupStorage GetBackupStorage(BackupRecord record) - { - try - { - return GetBackupStorage(record.StorageType, record.TenantId, JsonConvert.DeserializeObject>(record.StorageParams)); - } - catch (Exception error) - { - Log.Error("can't get backup storage for record " + record.Id, error); - return null; + { + try + { + return GetBackupStorage(record.StorageType, record.TenantId, JsonConvert.DeserializeObject>(record.StorageParams)); + } + catch (Exception error) + { + Log.Error("can't get backup storage for record " + record.Id, error); + return null; } - } + } public IBackupStorage GetBackupStorage(BackupStorageType type, int tenantId, Dictionary storageParams) { var settings = Configuration.GetSetting("backup"); - var webConfigPath = PathHelper.ToRootedConfigPath(settings.WebConfigs.CurrentPath); - + var webConfigPath = PathHelper.ToRootedConfigPath(settings.WebConfigs.CurrentPath); + switch (type) { case BackupStorageType.Documents: - case BackupStorageType.ThridpartyDocuments: - { - DocumentsBackupStorage.Init(tenantId, webConfigPath); - return DocumentsBackupStorage; + case BackupStorageType.ThridpartyDocuments: + { + DocumentsBackupStorage.Init(tenantId, webConfigPath); + return DocumentsBackupStorage; } - case BackupStorageType.DataStore: - { - DataStoreBackupStorage.Init(tenantId, webConfigPath); - return DataStoreBackupStorage; + case BackupStorageType.DataStore: + { + DataStoreBackupStorage.Init(tenantId, webConfigPath); + return DataStoreBackupStorage; } case BackupStorageType.Local: return LocalBackupStorage; - case BackupStorageType.ThirdPartyConsumer: - { - if (storageParams == null) return null; - TenantManager.SetCurrentTenant(tenantId); - ConsumerBackupStorage.Init(storageParams); - return ConsumerBackupStorage; + case BackupStorageType.ThirdPartyConsumer: + { + if (storageParams == null) return null; + TenantManager.SetCurrentTenant(tenantId); + ConsumerBackupStorage.Init(storageParams); + return ConsumerBackupStorage; } default: throw new InvalidOperationException("Unknown storage type."); diff --git a/common/services/ASC.Data.Backup/Storage/ConsumerBackupStorage.cs b/common/ASC.Data.Backup.Core/Storage/ConsumerBackupStorage.cs similarity index 99% rename from common/services/ASC.Data.Backup/Storage/ConsumerBackupStorage.cs rename to common/ASC.Data.Backup.Core/Storage/ConsumerBackupStorage.cs index 61c6fccd320..251c26539f6 100644 --- a/common/services/ASC.Data.Backup/Storage/ConsumerBackupStorage.cs +++ b/common/ASC.Data.Backup.Core/Storage/ConsumerBackupStorage.cs @@ -34,7 +34,7 @@ using ASC.Data.Storage.Configuration; namespace ASC.Data.Backup.Storage -{ +{ [Scope] public class ConsumerBackupStorage : IBackupStorage { @@ -52,16 +52,16 @@ public void Init(IReadOnlyDictionary storageParams) } public string Upload(string storageBasePath, string localPath, Guid userId) { - using var stream = File.OpenRead(localPath); - var storagePath = Path.GetFileName(localPath); - Store.Save(Domain, storagePath, stream, ACL.Private); + using var stream = File.OpenRead(localPath); + var storagePath = Path.GetFileName(localPath); + Store.Save(Domain, storagePath, stream, ACL.Private); return storagePath; } public void Download(string storagePath, string targetLocalPath) { - using var source = Store.GetReadStream(Domain, storagePath); - using var destination = File.OpenWrite(targetLocalPath); + using var source = Store.GetReadStream(Domain, storagePath); + using var destination = File.OpenWrite(targetLocalPath); source.CopyTo(destination); } diff --git a/common/services/ASC.Data.Backup/Storage/DataStoreBackupStorage.cs b/common/ASC.Data.Backup.Core/Storage/DataStoreBackupStorage.cs similarity index 99% rename from common/services/ASC.Data.Backup/Storage/DataStoreBackupStorage.cs rename to common/ASC.Data.Backup.Core/Storage/DataStoreBackupStorage.cs index 928f4ed684a..8ac44080bb0 100644 --- a/common/services/ASC.Data.Backup/Storage/DataStoreBackupStorage.cs +++ b/common/ASC.Data.Backup.Core/Storage/DataStoreBackupStorage.cs @@ -31,7 +31,7 @@ using ASC.Data.Storage; namespace ASC.Data.Backup.Storage -{ +{ [Scope] public class DataStoreBackupStorage : IBackupStorage { @@ -50,16 +50,16 @@ public void Init(int tenant, string webConfigPath) } public string Upload(string storageBasePath, string localPath, Guid userId) { - using var stream = File.OpenRead(localPath); - var storagePath = Path.GetFileName(localPath); - GetDataStore().Save("", storagePath, stream); + using var stream = File.OpenRead(localPath); + var storagePath = Path.GetFileName(localPath); + GetDataStore().Save("", storagePath, stream); return storagePath; } public void Download(string storagePath, string targetLocalPath) { - using var source = GetDataStore().GetReadStream("", storagePath); - using var destination = File.OpenWrite(targetLocalPath); + using var source = GetDataStore().GetReadStream("", storagePath); + using var destination = File.OpenWrite(targetLocalPath); source.CopyTo(destination); } @@ -68,7 +68,7 @@ public void Delete(string storagePath) var dataStore = GetDataStore(); if (dataStore.IsFile("", storagePath)) { - dataStore.Delete("", storagePath); + dataStore.Delete("", storagePath); } } diff --git a/common/services/ASC.Data.Backup/Storage/DocumentsBackupStorage.cs b/common/ASC.Data.Backup.Core/Storage/DocumentsBackupStorage.cs similarity index 98% rename from common/services/ASC.Data.Backup/Storage/DocumentsBackupStorage.cs rename to common/ASC.Data.Backup.Core/Storage/DocumentsBackupStorage.cs index e9403c6b95f..2ff9ef461cf 100644 --- a/common/services/ASC.Data.Backup/Storage/DocumentsBackupStorage.cs +++ b/common/ASC.Data.Backup.Core/Storage/DocumentsBackupStorage.cs @@ -25,198 +25,198 @@ using System; -using System.IO; - -using ASC.Common; +using System.IO; + +using ASC.Common; using ASC.Core; using ASC.Data.Storage; -using ASC.Files.Core; -using ASC.Web.Studio.Core; -//using File = ASC.Files.Core.File; - -using Microsoft.Extensions.DependencyInjection; +using ASC.Files.Core; +using ASC.Web.Studio.Core; +//using File = ASC.Files.Core.File; + +using Microsoft.Extensions.DependencyInjection; namespace ASC.Data.Backup.Storage -{ +{ [Scope] public class DocumentsBackupStorage : IBackupStorage { private int TenantId { get; set; } - private string WebConfigPath { get; set; } - private SetupInfo SetupInfo { get; } + private string WebConfigPath { get; set; } + private SetupInfo SetupInfo { get; } private TenantManager TenantManager { get; set; } private SecurityContext SecurityContext { get; set; } private IDaoFactory DaoFactory { get; set; } - private StorageFactory StorageFactory { get; set; } - private IServiceProvider ServiceProvider { get; } - - public DocumentsBackupStorage( - SetupInfo setupInfo, - TenantManager tenantManager, - SecurityContext securityContext, - IDaoFactory daoFactory, - StorageFactory storageFactory, + private StorageFactory StorageFactory { get; set; } + private IServiceProvider ServiceProvider { get; } + + public DocumentsBackupStorage( + SetupInfo setupInfo, + TenantManager tenantManager, + SecurityContext securityContext, + IDaoFactory daoFactory, + StorageFactory storageFactory, IServiceProvider serviceProvider) - { - SetupInfo = setupInfo; + { + SetupInfo = setupInfo; TenantManager = tenantManager; SecurityContext = securityContext; DaoFactory = daoFactory; - StorageFactory = storageFactory; - ServiceProvider = serviceProvider; + StorageFactory = storageFactory; + ServiceProvider = serviceProvider; } - public void Init(int tenantId, string webConfigPath) - { + public void Init(int tenantId, string webConfigPath) + { TenantId = tenantId; - WebConfigPath = webConfigPath; + WebConfigPath = webConfigPath; } public string Upload(string folderId, string localPath, Guid userId) - { - TenantManager.SetCurrentTenant(TenantId); - if (!userId.Equals(Guid.Empty)) - { - SecurityContext.AuthenticateMeWithoutCookie(userId); - } - else - { - var tenant = TenantManager.GetTenant(TenantId); - SecurityContext.AuthenticateMeWithoutCookie(tenant.OwnerId); - } - - if (int.TryParse(folderId, out var fId)) - { - return Upload(fId, localPath).ToString(); - } - + { + TenantManager.SetCurrentTenant(TenantId); + if (!userId.Equals(Guid.Empty)) + { + SecurityContext.AuthenticateMeWithoutCookie(userId); + } + else + { + var tenant = TenantManager.GetTenant(TenantId); + SecurityContext.AuthenticateMeWithoutCookie(tenant.OwnerId); + } + + if (int.TryParse(folderId, out var fId)) + { + return Upload(fId, localPath).ToString(); + } + return Upload(folderId, localPath); } public void Download(string fileId, string targetLocalPath) - { - TenantManager.SetCurrentTenant(TenantId); - - if (int.TryParse(fileId, out var fId)) - { - DownloadDao(fId, targetLocalPath); - return; - } - - DownloadDao(fileId, targetLocalPath); + { + TenantManager.SetCurrentTenant(TenantId); + + if (int.TryParse(fileId, out var fId)) + { + DownloadDao(fId, targetLocalPath); + return; + } + + DownloadDao(fileId, targetLocalPath); } public void Delete(string fileId) - { - TenantManager.SetCurrentTenant(TenantId); - - if (int.TryParse(fileId, out var fId)) - { - DeleteDao(fId); - return; - } - - DeleteDao(fileId); + { + TenantManager.SetCurrentTenant(TenantId); + + if (int.TryParse(fileId, out var fId)) + { + DeleteDao(fId); + return; + } + + DeleteDao(fileId); } public bool IsExists(string fileId) - { - TenantManager.SetCurrentTenant(TenantId); - if (int.TryParse(fileId, out var fId)) - { - return IsExistsDao(fId); - } - + { + TenantManager.SetCurrentTenant(TenantId); + if (int.TryParse(fileId, out var fId)) + { + return IsExistsDao(fId); + } + return IsExistsDao(fileId); } public string GetPublicLink(string fileId) { return string.Empty; - } - + } + private T Upload(T folderId, string localPath) - { - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); - - var folder = folderDao.GetFolder(folderId); - if (folder == null) - { - throw new FileNotFoundException("Folder not found."); - } - - using var source = File.OpenRead(localPath); - var newFile = ServiceProvider.GetService>(); - newFile.Title = Path.GetFileName(localPath); - newFile.FolderID = folder.ID; - newFile.ContentLength = source.Length; - - File file = null; - var buffer = new byte[SetupInfo.ChunkUploadSize]; - var chunkedUploadSession = fileDao.CreateUploadSession(newFile, source.Length); - chunkedUploadSession.CheckQuota = false; - - var bytesRead = 0; - - while ((bytesRead = source.Read(buffer, 0, (int)SetupInfo.ChunkUploadSize)) > 0) - { - using (var theMemStream = new MemoryStream()) - { - theMemStream.Write(buffer, 0, bytesRead); - theMemStream.Position = 0; - file = fileDao.UploadChunk(chunkedUploadSession, theMemStream, bytesRead); - } - } - - return file.ID; - } - + { + var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); + + var folder = folderDao.GetFolder(folderId); + if (folder == null) + { + throw new FileNotFoundException("Folder not found."); + } + + using var source = File.OpenRead(localPath); + var newFile = ServiceProvider.GetService>(); + newFile.Title = Path.GetFileName(localPath); + newFile.FolderID = folder.ID; + newFile.ContentLength = source.Length; + + File file = null; + var buffer = new byte[SetupInfo.ChunkUploadSize]; + var chunkedUploadSession = fileDao.CreateUploadSession(newFile, source.Length); + chunkedUploadSession.CheckQuota = false; + + var bytesRead = 0; + + while ((bytesRead = source.Read(buffer, 0, (int)SetupInfo.ChunkUploadSize)) > 0) + { + using (var theMemStream = new MemoryStream()) + { + theMemStream.Write(buffer, 0, bytesRead); + theMemStream.Position = 0; + file = fileDao.UploadChunk(chunkedUploadSession, theMemStream, bytesRead); + } + } + + return file.ID; + } + private void DownloadDao(T fileId, string targetLocalPath) - { - TenantManager.SetCurrentTenant(TenantId); - var fileDao = GetFileDao(); - var file = fileDao.GetFile(fileId); - if (file == null) - { - throw new FileNotFoundException("File not found."); - } - - using var source = fileDao.GetFileStream(file); - using var destination = File.OpenWrite(targetLocalPath); - source.CopyTo(destination); - } - + { + TenantManager.SetCurrentTenant(TenantId); + var fileDao = GetFileDao(); + var file = fileDao.GetFile(fileId); + if (file == null) + { + throw new FileNotFoundException("File not found."); + } + + using var source = fileDao.GetFileStream(file); + using var destination = File.OpenWrite(targetLocalPath); + source.CopyTo(destination); + } + private void DeleteDao(T fileId) - { - var fileDao = GetFileDao(); - fileDao.DeleteFile(fileId); - } - + { + var fileDao = GetFileDao(); + fileDao.DeleteFile(fileId); + } + private bool IsExistsDao(T fileId) - { - var fileDao = GetFileDao(); - try - { - - var file = fileDao.GetFile(fileId); - return file != null && file.RootFolderType != FolderType.TRASH; - } - catch (Exception) - { - return false; - } - } - - private IFolderDao GetFolderDao() - { - return DaoFactory.GetFolderDao(); - } - - private IFileDao GetFileDao() - { - // hack: create storage using webConfigPath and put it into DataStoreCache - // FileDao will use this storage and will not try to create the new one from service config - StorageFactory.GetStorage(WebConfigPath, TenantId.ToString(), "files"); - return DaoFactory.GetFileDao(); - } + { + var fileDao = GetFileDao(); + try + { + + var file = fileDao.GetFile(fileId); + return file != null && file.RootFolderType != FolderType.TRASH; + } + catch (Exception) + { + return false; + } + } + + private IFolderDao GetFolderDao() + { + return DaoFactory.GetFolderDao(); + } + + private IFileDao GetFileDao() + { + // hack: create storage using webConfigPath and put it into DataStoreCache + // FileDao will use this storage and will not try to create the new one from service config + StorageFactory.GetStorage(WebConfigPath, TenantId.ToString(), "files"); + return DaoFactory.GetFileDao(); + } } } diff --git a/common/services/ASC.Data.Backup/Storage/IBackupRepository.cs b/common/ASC.Data.Backup.Core/Storage/IBackupRepository.cs similarity index 99% rename from common/services/ASC.Data.Backup/Storage/IBackupRepository.cs rename to common/ASC.Data.Backup.Core/Storage/IBackupRepository.cs index ed05643616d..1a6fdbd8e53 100644 --- a/common/services/ASC.Data.Backup/Storage/IBackupRepository.cs +++ b/common/ASC.Data.Backup.Core/Storage/IBackupRepository.cs @@ -34,7 +34,7 @@ namespace ASC.Data.Backup.Storage public interface IBackupRepository { void SaveBackupRecord(BackupRecord backupRecord); - BackupRecord GetBackupRecord(Guid id); + BackupRecord GetBackupRecord(Guid id); BackupRecord GetBackupRecord(string hash, int tenant); List GetExpiredBackupRecords(); List GetScheduledBackupRecords(); diff --git a/common/services/ASC.Data.Backup/Storage/IBackupStorage.cs b/common/ASC.Data.Backup.Core/Storage/IBackupStorage.cs similarity index 100% rename from common/services/ASC.Data.Backup/Storage/IBackupStorage.cs rename to common/ASC.Data.Backup.Core/Storage/IBackupStorage.cs diff --git a/common/services/ASC.Data.Backup/Storage/LocalBackupStorage.cs b/common/ASC.Data.Backup.Core/Storage/LocalBackupStorage.cs similarity index 99% rename from common/services/ASC.Data.Backup/Storage/LocalBackupStorage.cs rename to common/ASC.Data.Backup.Core/Storage/LocalBackupStorage.cs index 37009952c50..1864eecb054 100644 --- a/common/services/ASC.Data.Backup/Storage/LocalBackupStorage.cs +++ b/common/ASC.Data.Backup.Core/Storage/LocalBackupStorage.cs @@ -28,10 +28,10 @@ using System.IO; using ASC.Common; -using ASC.Common.Utils; - +using ASC.Common.Utils; + namespace ASC.Data.Backup.Storage -{ +{ [Scope] public class LocalBackupStorage : IBackupStorage { diff --git a/common/services/ASC.Data.Backup/Storage/S3BackupStorage.cs b/common/ASC.Data.Backup.Core/Storage/S3BackupStorage.cs similarity index 99% rename from common/services/ASC.Data.Backup/Storage/S3BackupStorage.cs rename to common/ASC.Data.Backup.Core/Storage/S3BackupStorage.cs index 6344e31c758..d4740de90c7 100644 --- a/common/services/ASC.Data.Backup/Storage/S3BackupStorage.cs +++ b/common/ASC.Data.Backup.Core/Storage/S3BackupStorage.cs @@ -58,7 +58,7 @@ public S3BackupStorage(IOptionsMonitor options, string accessKeyId, string public string Upload(string storageBasePath, string localPath, Guid userId) { - string key; + string key; if (string.IsNullOrEmpty(storageBasePath)) key = "backup/" + Path.GetFileName(localPath); diff --git a/common/services/ASC.Data.Backup/Tasks/BackupFileInfo.cs b/common/ASC.Data.Backup.Core/Tasks/BackupFileInfo.cs similarity index 100% rename from common/services/ASC.Data.Backup/Tasks/BackupFileInfo.cs rename to common/ASC.Data.Backup.Core/Tasks/BackupFileInfo.cs diff --git a/common/services/ASC.Data.Backup/Tasks/BackupPortalTask.cs b/common/ASC.Data.Backup.Core/Tasks/BackupPortalTask.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/BackupPortalTask.cs rename to common/ASC.Data.Backup.Core/Tasks/BackupPortalTask.cs index b3758e9e1df..2d89d272a1d 100644 --- a/common/services/ASC.Data.Backup/Tasks/BackupPortalTask.cs +++ b/common/ASC.Data.Backup.Core/Tasks/BackupPortalTask.cs @@ -33,10 +33,10 @@ using System.Text; using System.Threading.Tasks; using System.Xml.Linq; - + using ASC.Common; using ASC.Common.Logging; -using ASC.Common.Utils; +using ASC.Common.Utils; using ASC.Core; using ASC.Core.Common.EF; using ASC.Data.Backup.EF.Context; @@ -45,24 +45,24 @@ using ASC.Data.Backup.Tasks.Data; using ASC.Data.Backup.Tasks.Modules; using ASC.Data.Storage; - + using Microsoft.Extensions.Options; - + using Newtonsoft.Json; namespace ASC.Data.Backup.Tasks -{ +{ [Scope] public class BackupPortalTask : PortalTaskBase - { - private const int MaxLength = 250; + { + private const int MaxLength = 250; private const int BatchLimit = 5000; public string BackupFilePath { get; private set; } public int Limit { get; private set; } private bool Dump { get; set; } - private TenantManager TenantManager { get; set; } - private TempStream TempStream { get; } + private TenantManager TenantManager { get; set; } + private TempStream TempStream { get; } private Lazy LazyBackupsContext { get; } private BackupsContext BackupRecordContext { get => LazyBackupsContext.Value; } @@ -70,10 +70,10 @@ public BackupPortalTask(DbFactory dbFactory, DbContextManager db : base(dbFactory, options, storageFactory, storageFactoryConfig, moduleProvider) { Dump = coreBaseSettings.Standalone; - TenantManager = tenantManager; - TempStream = tempStream; + TenantManager = tenantManager; + TempStream = tempStream; LazyBackupsContext = new Lazy(() => dbContextManager.Get(DbFactory.ConnectionStringSettings.ConnectionString)); - } + } public void Init(int tenantId, string fromConfigPath, string toFilePath, int limit) { @@ -91,14 +91,14 @@ public override void RunJob() using (var writer = new ZipWriteOperator(TempStream, BackupFilePath)) - { + { if (Dump) { DoDump(writer); } else - { - + { + var modulesToProcess = GetModulesToProcess().ToList(); var fileGroups = GetFilesGroup(); @@ -119,10 +119,10 @@ public override void RunJob() } private void DoDump(IDataWriteOperator writer) - { - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(true.ToString()))) - { - writer.WriteEntry(KeyHelper.GetDumpKey(), stream); + { + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(true.ToString()))) + { + writer.WriteEntry(KeyHelper.GetDumpKey(), stream); } List tables; @@ -132,12 +132,12 @@ private void DoDump(IDataWriteOperator writer) var command = connection.CreateCommand(); command.CommandText = "show tables"; tables = ExecuteList(command).Select(r => Convert.ToString(r[0])).ToList(); - } - /* using (var dbManager = new DbManager("default", 100000)) - { - tables = dbManager.ExecuteList("show tables;").Select(r => Convert.ToString(r[0])).ToList(); - }*/ - + } + /* using (var dbManager = new DbManager("default", 100000)) + { + tables = dbManager.ExecuteList("show tables;").Select(r => Convert.ToString(r[0])).ToList(); + }*/ + var stepscount = tables.Count * 4; // (schema + data) * (dump + zip) if (ProcessStorage) { @@ -208,8 +208,8 @@ private void DoDump(IDataWriteOperator writer) private IEnumerable GetFiles(int tenantId) { var files = GetFilesToProcess(tenantId).ToList(); - var exclude = BackupRecordContext.Backups.Where(b => b.TenantId == tenantId && b.StorageType == 0 && b.StoragePath != null).ToList(); - files = files.Where(f => !exclude.Any(e => f.Path.Replace('\\', '/').Contains(string.Format("/file_{0}/", e.StoragePath)))).ToList(); + var exclude = BackupRecordContext.Backups.Where(b => b.TenantId == tenantId && b.StorageType == 0 && b.StoragePath != null).ToList(); + files = files.Where(f => !exclude.Any(e => f.Path.Replace('\\', '/').Contains(string.Format("/file_{0}/", e.StoragePath)))).ToList(); return files; } @@ -240,8 +240,8 @@ private void DumpTableScheme(string t, string dir) } SetStepCompleted(); - } - + } + Logger.DebugFormat("dump table scheme stop {0}", t); } catch (Exception e) @@ -256,13 +256,13 @@ private int SelectCount(string t) { try { - using var connection = DbFactory.OpenConnection(); - using var analyzeCommand = connection.CreateCommand(); - analyzeCommand.CommandText = $"analyze table {t}"; - analyzeCommand.ExecuteNonQuery(); - using var command = connection.CreateCommand(); - command.CommandText = $"select TABLE_ROWS from INFORMATION_SCHEMA.TABLES where TABLE_NAME = '{t}' and TABLE_SCHEMA = '{connection.Database}'"; - return int.Parse(command.ExecuteScalar().ToString()); + using var connection = DbFactory.OpenConnection(); + using var analyzeCommand = connection.CreateCommand(); + analyzeCommand.CommandText = $"analyze table {t}"; + analyzeCommand.ExecuteNonQuery(); + using var command = connection.CreateCommand(); + command.CommandText = $"select TABLE_ROWS from INFORMATION_SCHEMA.TABLES where TABLE_NAME = '{t}' and TABLE_SCHEMA = '{connection.Database}'"; + return int.Parse(command.ExecuteScalar().ToString()); } catch (Exception e) { @@ -318,47 +318,47 @@ private void DumpTableData(string t, string dir, int count) if (searchWithPrimary) { - using var connection = DbFactory.OpenConnection(); - var command = connection.CreateCommand(); - command.CommandText = string.Format("select max({1}), min({1}) from {0}", t, primaryIndex); - var minMax = ExecuteList(command).ConvertAll(r => new Tuple(Convert.ToInt32(r[0]), Convert.ToInt32(r[1]))).FirstOrDefault(); - primaryIndexStart = minMax.Item2; - primaryIndexStep = (minMax.Item1 - minMax.Item2) / count; - - if (primaryIndexStep < Limit) - { - primaryIndexStep = Limit; + using var connection = DbFactory.OpenConnection(); + var command = connection.CreateCommand(); + command.CommandText = string.Format("select max({1}), min({1}) from {0}", t, primaryIndex); + var minMax = ExecuteList(command).ConvertAll(r => new Tuple(Convert.ToInt32(r[0]), Convert.ToInt32(r[1]))).FirstOrDefault(); + primaryIndexStart = minMax.Item2; + primaryIndexStep = (minMax.Item1 - minMax.Item2) / count; + + if (primaryIndexStep < Limit) + { + primaryIndexStep = Limit; } } - - var path = CrossPlatform.PathCombine(dir, t); - - var offset = 0; - - do - { - List result; - - if (searchWithPrimary) - { - result = GetDataWithPrimary(t, columns, primaryIndex, primaryIndexStart, primaryIndexStep); - primaryIndexStart += primaryIndexStep; - } - else - { - result = GetData(t, columns, offset); - } - - offset += Limit; - - var resultCount = result.Count; - - if (resultCount == 0) break; - - SaveToFile(path, t, columns, result); - - if (resultCount < Limit) break; - + + var path = CrossPlatform.PathCombine(dir, t); + + var offset = 0; + + do + { + List result; + + if (searchWithPrimary) + { + result = GetDataWithPrimary(t, columns, primaryIndex, primaryIndexStart, primaryIndexStep); + primaryIndexStart += primaryIndexStep; + } + else + { + result = GetData(t, columns, offset); + } + + offset += Limit; + + var resultCount = result.Count; + + if (resultCount == 0) break; + + SaveToFile(path, t, columns, result); + + if (resultCount < Limit) break; + } while (true); @@ -374,27 +374,27 @@ private void DumpTableData(string t, string dir, int count) private List GetData(string t, List columns, int offset) { - using var connection = DbFactory.OpenConnection(); - var command = connection.CreateCommand(); - var selects = string.Join(',', columns); - command.CommandText = $"select {selects} from {t} LIMIT {offset}, {Limit}"; + using var connection = DbFactory.OpenConnection(); + var command = connection.CreateCommand(); + var selects = string.Join(',', columns); + command.CommandText = $"select {selects} from {t} LIMIT {offset}, {Limit}"; return ExecuteList(command); } private List GetDataWithPrimary(string t, List columns, string primary, int start, int step) { - using var connection = DbFactory.OpenConnection(); - var command = connection.CreateCommand(); - var selects = string.Join(',', columns); - command.CommandText = $"select {selects} from {t} where {primary} BETWEEN {start} and {start + step} "; - return ExecuteList(command); - } - + using var connection = DbFactory.OpenConnection(); + var command = connection.CreateCommand(); + var selects = string.Join(',', columns); + command.CommandText = $"select {selects} from {t} where {primary} BETWEEN {start} and {start + step} "; + return ExecuteList(command); + } + private void SaveToFile(string path, string t, IReadOnlyCollection columns, List data) { Logger.DebugFormat("save to file {0}", t); List portion; while ((portion = data.Take(BatchLimit).ToList()).Any()) - { + { using (var sw = new StreamWriter(path, true)) using (var writer = new JsonTextWriter(sw)) { @@ -478,11 +478,11 @@ private void DoDumpStorage(IDataWriteOperator writer, IReadOnlyList MaxLength) - { - filePath = @"\\?\" + filePath; - } + } + + if (!WorkContext.IsMono && filePath.Length > MaxLength) + { + filePath = @"\\?\" + filePath; + } using (var fileStream = storage.GetReadStream(file.Domain, file.Path)) using (var tmpFile = File.OpenWrite(filePath)) @@ -523,14 +523,14 @@ private void ArchiveDir(IDataWriteOperator writer, string subDir) Logger.DebugFormat("archive dir start {0}", subDir); foreach (var enumerateFile in Directory.EnumerateFiles(subDir, "*", SearchOption.AllDirectories)) { - var f = enumerateFile; - if (!WorkContext.IsMono && enumerateFile.Length > MaxLength) - { - f = @"\\?\" + f; - } - using (var tmpFile = new FileStream(f, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose)) - { - writer.WriteEntry(enumerateFile.Substring(subDir.Length), tmpFile); + var f = enumerateFile; + if (!WorkContext.IsMono && enumerateFile.Length > MaxLength) + { + f = @"\\?\" + f; + } + using (var tmpFile = new FileStream(f, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose)) + { + writer.WriteEntry(enumerateFile.Substring(subDir.Length), tmpFile); } SetStepCompleted(); } @@ -593,12 +593,12 @@ private void DoBackupModule(IDataWriteOperator writer, IModuleSpecifics module) Logger.DebugFormat("begin saving table {0}", table.Name); - 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); } Logger.DebugFormat("end saving table {0}", table.Name); @@ -626,7 +626,7 @@ private void DoBackupStorage(IDataWriteOperator writer, List { var f = (BackupFileInfo)state; - using var fileStream = storage.GetReadStream(f.Domain, f.Path); + using var fileStream = storage.GetReadStream(f.Domain, f.Path); writer.WriteEntry(file1.GetZipKey(), fileStream); }, file, 5, error => Logger.WarnFormat("can't backup file ({0}:{1}): {2}", file1.Module, file1.Path, error)); @@ -640,10 +640,10 @@ private void DoBackupStorage(IDataWriteOperator writer, List group.Select(file => (object)file.ToXElement())) .ToArray()); - using (var tmpFile = TempStream.Create()) - { - restoreInfoXml.WriteTo(tmpFile); - writer.WriteEntry(KeyHelper.GetStorageRestoreInfoZipKey(), tmpFile); + using (var tmpFile = TempStream.Create()) + { + restoreInfoXml.WriteTo(tmpFile); + writer.WriteEntry(KeyHelper.GetStorageRestoreInfoZipKey(), tmpFile); } Logger.Debug("end backup storage"); diff --git a/common/services/ASC.Data.Backup/Tasks/ColumnMapper.cs b/common/ASC.Data.Backup.Core/Tasks/ColumnMapper.cs similarity index 100% rename from common/services/ASC.Data.Backup/Tasks/ColumnMapper.cs rename to common/ASC.Data.Backup.Core/Tasks/ColumnMapper.cs diff --git a/common/services/ASC.Data.Backup/Tasks/Data/DataRowInfo.cs b/common/ASC.Data.Backup.Core/Tasks/Data/DataRowInfo.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/Data/DataRowInfo.cs rename to common/ASC.Data.Backup.Core/Tasks/Data/DataRowInfo.cs index c66df9a8188..445e94625ff 100644 --- a/common/services/ASC.Data.Backup/Tasks/Data/DataRowInfo.cs +++ b/common/ASC.Data.Backup.Core/Tasks/Data/DataRowInfo.cs @@ -1,4 +1,4 @@ -/* +/* * * (c) Copyright Ascensio System Limited 2010-2020 * @@ -103,4 +103,4 @@ public override string ToString() return sb.ToString(); } } -} +} \ No newline at end of file diff --git a/common/services/ASC.Data.Backup/Tasks/Data/DataRowInfoReader.cs b/common/ASC.Data.Backup.Core/Tasks/Data/DataRowInfoReader.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/Data/DataRowInfoReader.cs rename to common/ASC.Data.Backup.Core/Tasks/Data/DataRowInfoReader.cs index 47778847204..e1b89556c39 100644 --- a/common/services/ASC.Data.Backup/Tasks/Data/DataRowInfoReader.cs +++ b/common/ASC.Data.Backup.Core/Tasks/Data/DataRowInfoReader.cs @@ -1,4 +1,4 @@ -/* +/* * * (c) Copyright Ascensio System Limited 2010-2020 * @@ -97,4 +97,4 @@ private static object ConvertToType(string str, string schemaType) return str; } } -} +} \ No newline at end of file diff --git a/common/services/ASC.Data.Backup/Tasks/Data/RelationInfo.cs b/common/ASC.Data.Backup.Core/Tasks/Data/RelationInfo.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/Data/RelationInfo.cs rename to common/ASC.Data.Backup.Core/Tasks/Data/RelationInfo.cs index d4ecdaca157..3fd793804bf 100644 --- a/common/services/ASC.Data.Backup/Tasks/Data/RelationInfo.cs +++ b/common/ASC.Data.Backup.Core/Tasks/Data/RelationInfo.cs @@ -1,4 +1,4 @@ -/* +/* * * (c) Copyright Ascensio System Limited 2010-2020 * diff --git a/common/services/ASC.Data.Backup/Tasks/Data/TableInfo.cs b/common/ASC.Data.Backup.Core/Tasks/Data/TableInfo.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/Data/TableInfo.cs rename to common/ASC.Data.Backup.Core/Tasks/Data/TableInfo.cs index a88f2c0b665..3eacb6f69f1 100644 --- a/common/services/ASC.Data.Backup/Tasks/Data/TableInfo.cs +++ b/common/ASC.Data.Backup.Core/Tasks/Data/TableInfo.cs @@ -1,4 +1,4 @@ -/* +/* * * (c) Copyright Ascensio System Limited 2010-2020 * @@ -88,4 +88,4 @@ public override string ToString() return string.Format("{0} {1} [{2} ({3}), {4}]", InsertMethod, Name, IdColumn, IdType, TenantColumn); } } -} +} \ No newline at end of file diff --git a/common/services/ASC.Data.Backup/Tasks/DbFactory.cs b/common/ASC.Data.Backup.Core/Tasks/DbFactory.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/DbFactory.cs rename to common/ASC.Data.Backup.Core/Tasks/DbFactory.cs index cd8631a8f7f..378e207f16d 100644 --- a/common/services/ASC.Data.Backup/Tasks/DbFactory.cs +++ b/common/ASC.Data.Backup.Core/Tasks/DbFactory.cs @@ -37,7 +37,7 @@ using MySql.Data.MySqlClient; namespace ASC.Data.Backup.Tasks -{ +{ [Scope] public class DbFactory { @@ -45,7 +45,7 @@ public class DbFactory private DbProviderFactory dbProviderFactory; - private IConfiguration Configuration { get; set; } + private IConfiguration Configuration { get; set; } private ConfigurationExtension ConfigurationExtension { get; set; } private string ConnectionString { get; set; } private string Path { get; set; } @@ -82,8 +82,8 @@ private DbProviderFactory DbProviderFactory public DbFactory(IConfiguration configuration, ConfigurationExtension configurationExtension) { - Configuration = configuration; - ConfigurationExtension = configurationExtension; + Configuration = configuration; + ConfigurationExtension = configurationExtension; } public DbConnection OpenConnection(string path = "default", string connectionString = DefaultConnectionStringName)//TODO diff --git a/common/services/ASC.Data.Backup/Tasks/DeletePortalTask.cs b/common/ASC.Data.Backup.Core/Tasks/DeletePortalTask.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/DeletePortalTask.cs rename to common/ASC.Data.Backup.Core/Tasks/DeletePortalTask.cs index 31d66e42a98..5cc08414418 100644 --- a/common/services/ASC.Data.Backup/Tasks/DeletePortalTask.cs +++ b/common/ASC.Data.Backup.Core/Tasks/DeletePortalTask.cs @@ -31,8 +31,8 @@ using ASC.Data.Backup.Extensions; using ASC.Data.Backup.Tasks.Data; using ASC.Data.Backup.Tasks.Modules; -using ASC.Data.Storage; - +using ASC.Data.Storage; + using Microsoft.Extensions.Options; namespace ASC.Data.Backup.Tasks diff --git a/common/services/ASC.Data.Backup/Tasks/KeyHelper.cs b/common/ASC.Data.Backup.Core/Tasks/KeyHelper.cs similarity index 100% rename from common/services/ASC.Data.Backup/Tasks/KeyHelper.cs rename to common/ASC.Data.Backup.Core/Tasks/KeyHelper.cs diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/AuditModuleSpecifics.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/AuditModuleSpecifics.cs similarity index 100% rename from common/services/ASC.Data.Backup/Tasks/Modules/AuditModuleSpecifics.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/AuditModuleSpecifics.cs diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/CalendarModuleSpecifics.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/CalendarModuleSpecifics.cs similarity index 100% rename from common/services/ASC.Data.Backup/Tasks/Modules/CalendarModuleSpecifics.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/CalendarModuleSpecifics.cs diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/CommunityModuleSpecifics.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/CommunityModuleSpecifics.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/Modules/CommunityModuleSpecifics.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/CommunityModuleSpecifics.cs index ccd44291a02..68d48d69238 100644 --- a/common/services/ASC.Data.Backup/Tasks/Modules/CommunityModuleSpecifics.cs +++ b/common/ASC.Data.Backup.Core/Tasks/Modules/CommunityModuleSpecifics.cs @@ -28,9 +28,9 @@ using System.Collections.Generic; using System.Data.Common; using System.Linq; - + using ASC.Data.Backup.Tasks.Data; -using ASC.Data.Backup.Utils; +using ASC.Data.Backup.Utils; namespace ASC.Data.Backup.Tasks.Modules { @@ -70,7 +70,7 @@ public CommunityModuleSpecifics(Helpers helpers) DateColumns = new Dictionary {{"created_when", false}, {"LastModified", false}} }, new TableInfo("blogs_reviewposts", "Tenant") - { + { UserIDColumns = new[] {"reviewed_by"}, DateColumns = new Dictionary {{"timestamp", false}} }, @@ -160,7 +160,7 @@ public CommunityModuleSpecifics(Helpers helpers) new RelationInfo("bookmarking_bookmark", "ID", "bookmarking_bookmarktag", "BookmarkID"), new RelationInfo("bookmarking_tag", "TagID", "bookmarking_bookmarktag", "TagID"), new RelationInfo("bookmarking_bookmark", "ID", "bookmarking_comment", "BookmarkID"), - new RelationInfo("bookmarking_comment", "ID", "bookmarking_comment", "Parent"), + new RelationInfo("bookmarking_comment", "ID", "bookmarking_comment", "Parent"), new RelationInfo("bookmarking_bookmark", "ID", "bookmarking_userbookmark", "BookmarkID"), new RelationInfo("bookmarking_tag", "TagID", "bookmarking_userbookmarktag", "TagID"), new RelationInfo("bookmarking_userbookmark", "UserBookmarkID", "bookmarking_userbookmarktag", "UserBookmarkID"), @@ -171,7 +171,7 @@ public CommunityModuleSpecifics(Helpers helpers) new RelationInfo("blogs_posts", "id", "blogs_tags", "post_id"), new RelationInfo("events_feed", "Id", "events_comment", "Feed"), new RelationInfo("events_comment", "Id", "events_comment", "Parent"), - new RelationInfo("events_feed", "Id", "events_poll", "Id"), + new RelationInfo("events_feed", "Id", "events_poll", "Id"), new RelationInfo("events_pollvariant", "Id", "events_pollanswer", "Variant"), new RelationInfo("events_feed", "Id", "events_pollvariant", "Poll"), new RelationInfo("events_feed", "Id", "events_reader", "Feed"), @@ -180,7 +180,7 @@ public CommunityModuleSpecifics(Helpers helpers) new RelationInfo("forum_variant", "id", "forum_answer_variant", "variant_id"), new RelationInfo("forum_post", "id", "forum_attachment", "post_id"), new RelationInfo("forum_category", "id", "forum_attachment", "path"), - new RelationInfo("forum_thread", "id", "forum_attachment", "path"), + new RelationInfo("forum_thread", "id", "forum_attachment", "path"), new RelationInfo("forum_thread", "id", "forum_lastvisit", "thread_id"), new RelationInfo("forum_topic", "id", "forum_post", "topic_id"), new RelationInfo("forum_post", "id", "forum_post", "parent_post_id"), @@ -195,7 +195,7 @@ public CommunityModuleSpecifics(Helpers helpers) new RelationInfo("forum_topic", "id", "forum_topic_tag", "topic_id"), new RelationInfo("forum_tag", "id", "forum_topic_tag", "tag_id"), new RelationInfo("forum_question", "id", "forum_variant", "question_id"), - new RelationInfo("wiki_comments", "Id", "wiki_comments", "ParentId") + new RelationInfo("wiki_comments", "Id", "wiki_comments", "ParentId") }; public override ModuleName ModuleName diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/CoreModuleSpecifics.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/CoreModuleSpecifics.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/Modules/CoreModuleSpecifics.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/CoreModuleSpecifics.cs index fb592316b76..6a693b165c7 100644 --- a/common/services/ASC.Data.Backup/Tasks/Modules/CoreModuleSpecifics.cs +++ b/common/ASC.Data.Backup.Core/Tasks/Modules/CoreModuleSpecifics.cs @@ -27,8 +27,8 @@ using System; using System.Collections.Generic; using System.Data.Common; -using System.Linq; - +using System.Linq; + using ASC.Core.Billing; using ASC.Data.Backup.Tasks.Data; @@ -53,9 +53,9 @@ public class CoreModuleSpecifics : ModuleSpecificsBase private const string CrmCasesAclObjectStart = "ASC.CRM.Core.Entities.Cases|"; private const string CrmRelationshipEventAclObjectStart = "ASC.CRM.Core.Entities.RelationshipEvent|"; private const string CalendarCalendarAclObjectStart = "ASC.Api.Calendar.BusinessObjects.Calendar|"; - private const string CalendarEventAclObjectStart = "ASC.Api.Calendar.BusinessObjects.Event|"; - - + private const string CalendarEventAclObjectStart = "ASC.Api.Calendar.BusinessObjects.Event|"; + + private readonly TableInfo[] _tables = new[] { new TableInfo("core_acl", "tenant") {InsertMethod = InsertMethod.Ignore}, @@ -77,7 +77,7 @@ public class CoreModuleSpecifics : ModuleSpecificsBase new TableInfo("feed_users") {InsertMethod = InsertMethod.None}, new TableInfo("backup_backup", "tenant_id", "id", IdType.Guid), new TableInfo("backup_schedule", "tenant_id"), - new TableInfo("core_settings", "tenant") + new TableInfo("core_settings", "tenant") }; private readonly RelationInfo[] _tableRelations; @@ -175,8 +175,8 @@ public override IEnumerable TableRelations } protected override string GetSelectCommandConditionText(int tenantId, TableInfo table) - { - + { + if (table.Name == "feed_users") return "inner join core_user t1 on t1.id = t.user_id where t1.tenant = " + tenantId; diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/CrmModuleSpecifics.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/CrmModuleSpecifics.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/Modules/CrmModuleSpecifics.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/CrmModuleSpecifics.cs index a9302f3f3fd..2cf6251a13f 100644 --- a/common/services/ASC.Data.Backup/Tasks/Modules/CrmModuleSpecifics.cs +++ b/common/ASC.Data.Backup.Core/Tasks/Modules/CrmModuleSpecifics.cs @@ -28,10 +28,10 @@ using System.Collections.Generic; using System.Data.Common; using System.Linq; -using System.Text.RegularExpressions; - -using ASC.Data.Backup.Tasks.Data; - +using System.Text.RegularExpressions; + +using ASC.Data.Backup.Tasks.Data; + using Newtonsoft.Json.Linq; namespace ASC.Data.Backup.Tasks.Modules @@ -97,10 +97,10 @@ public CrmModuleSpecifics(Helpers helpers) { new RelationInfo("crm_contact", "id", "crm_contact", "company_id"), new RelationInfo("crm_list_item", "id", "crm_contact", "status_id"), - new RelationInfo("crm_list_item", "id", "crm_contact", "contact_type_id"), + new RelationInfo("crm_list_item", "id", "crm_contact", "contact_type_id"), new RelationInfo("crm_contact", "id", "crm_contact_info", "contact_id"), new RelationInfo("crm_deal_milestone", "id", "crm_deal", "deal_milestone_id"), - new RelationInfo("crm_contact", "id", "crm_deal", "contact_id"), + new RelationInfo("crm_contact", "id", "crm_deal", "contact_id"), new RelationInfo("projects_projects", "id", "crm_projects", "project_id", typeof(ProjectsModuleSpecifics)), new RelationInfo("crm_contact", "id", "crm_projects", "contact_id"), new RelationInfo("crm_contact", "id", "crm_task", "entity_id", x => ResolveRelation(x, 0, 4, 5)), @@ -200,7 +200,7 @@ public CrmModuleSpecifics2(Helpers helpers) new RelationInfo("crm_relationship_event", "id", "crm_field_value", "entity_id", typeof(CrmModuleSpecifics), x => ResolveRelation(x, 2)), new RelationInfo("crm_relationship_event", "id", "crm_entity_tag", "entity_id", typeof(CrmModuleSpecifics), x => ResolveRelation(x, 2)), new RelationInfo("crm_relationship_event", "id", "crm_entity_contact", "entity_id", typeof(CrmModuleSpecifics), x => ResolveRelation(x, 2)), - new RelationInfo("mail_mail", "id", "crm_relationship_event", "content", typeof(MailModuleSpecifics), x => Convert.ToInt32(x["category_id"]) == -3), + new RelationInfo("mail_mail", "id", "crm_relationship_event", "content", typeof(MailModuleSpecifics), x => Convert.ToInt32(x["category_id"]) == -3), }; public override string ConnectionStringName @@ -358,24 +358,24 @@ protected override bool TryPrepareValue(DbConnection connection, ColumnMapper co if (table.Name == "crm_invoice" && columnName == "json_data") { - var data = JObject.Parse((string)value); - + var data = JObject.Parse((string)value); + var oldValue = Convert.ToInt32(data["LogoBase64Id"]); if (oldValue != 0) { - data["LogoBase64Id"] = Convert.ToInt32(columnMapper.GetMapping("crm_organisation_logo", "id", oldValue)); + data["LogoBase64Id"] = Convert.ToInt32(columnMapper.GetMapping("crm_organisation_logo", "id", oldValue)); } oldValue = Convert.ToInt32(data["DeliveryAddressID"]); if (oldValue != 0) { - data["DeliveryAddressID"] = Convert.ToInt32(columnMapper.GetMapping("crm_contact_info", "id", oldValue)); + data["DeliveryAddressID"] = Convert.ToInt32(columnMapper.GetMapping("crm_contact_info", "id", oldValue)); } oldValue = Convert.ToInt32(data["BillingAddressID"]); if (oldValue != 0) { - data["BillingAddressID"] = Convert.ToInt32(columnMapper.GetMapping("crm_contact_info", "id", oldValue)); + data["BillingAddressID"] = Convert.ToInt32(columnMapper.GetMapping("crm_contact_info", "id", oldValue)); } value = data.ToString(); diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/FilesModuleSpecifics.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/FilesModuleSpecifics.cs similarity index 100% rename from common/services/ASC.Data.Backup/Tasks/Modules/FilesModuleSpecifics.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/FilesModuleSpecifics.cs diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/Helpers.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/Helpers.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/Modules/Helpers.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/Helpers.cs index 637e334b48d..a8cc1b64830 100644 --- a/common/services/ASC.Data.Backup/Tasks/Modules/Helpers.cs +++ b/common/ASC.Data.Backup.Core/Tasks/Modules/Helpers.cs @@ -25,17 +25,17 @@ using System; -using System.Linq; - +using System.Linq; + using ASC.Common; using ASC.Core; -using ASC.Security.Cryptography; - +using ASC.Security.Cryptography; + using ConfigurationConstants = ASC.Core.Configuration.Constants; using UserConstants = ASC.Core.Users.Constants; namespace ASC.Data.Backup.Tasks.Modules -{ +{ [Scope] public class Helpers { @@ -46,9 +46,9 @@ public class Helpers ConfigurationConstants.CoreSystem.ID, ConfigurationConstants.Guest.ID, UserConstants.LostUser.ID - }; - - + }; + + private readonly Guid[] SystemGroups = new[] { Guid.Empty, diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/IModuleSpecifics.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/IModuleSpecifics.cs similarity index 100% rename from common/services/ASC.Data.Backup/Tasks/Modules/IModuleSpecifics.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/IModuleSpecifics.cs diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/MailModuleSpecifics.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/MailModuleSpecifics.cs similarity index 100% rename from common/services/ASC.Data.Backup/Tasks/Modules/MailModuleSpecifics.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/MailModuleSpecifics.cs diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/ModuleProvider.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/ModuleProvider.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/Modules/ModuleProvider.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/ModuleProvider.cs index 51bebd615d6..1bf2817cb77 100644 --- a/common/services/ASC.Data.Backup/Tasks/Modules/ModuleProvider.cs +++ b/common/ASC.Data.Backup.Core/Tasks/Modules/ModuleProvider.cs @@ -26,15 +26,15 @@ using System.Collections.Generic; using System.Linq; - + using ASC.Common; using ASC.Common.Logging; -using ASC.Core; - -using Microsoft.Extensions.Options; +using ASC.Core; + +using Microsoft.Extensions.Options; namespace ASC.Data.Backup.Tasks.Modules -{ +{ [Scope] public class ModuleProvider { @@ -62,15 +62,15 @@ public ModuleProvider(IOptionsMonitor options, Helpers helpers, CoreSettin } public IModuleSpecifics GetByStorageModule(string storageModuleName, string storageDomainName = null) { - return storageModuleName switch - { - "files" => AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Files), - "projects" => AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Projects), - "crm" => AllModules.FirstOrDefault(m => m.ModuleName == (storageDomainName == "mail_messages" ? ModuleName.Crm2 : ModuleName.Crm)), - "forum" => AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Community), - "mailaggregator" => AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Mail), - _ => null, - }; + return storageModuleName switch + { + "files" => AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Files), + "projects" => AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Projects), + "crm" => AllModules.FirstOrDefault(m => m.ModuleName == (storageDomainName == "mail_messages" ? ModuleName.Crm2 : ModuleName.Crm)), + "forum" => AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Community), + "mailaggregator" => AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Mail), + _ => null, + }; } } } diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/ModuleSpecificsBase.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/ModuleSpecificsBase.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/Modules/ModuleSpecificsBase.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/ModuleSpecificsBase.cs index ed470855a92..b4e91652315 100644 --- a/common/services/ASC.Data.Backup/Tasks/Modules/ModuleSpecificsBase.cs +++ b/common/ASC.Data.Backup.Core/Tasks/Modules/ModuleSpecificsBase.cs @@ -254,8 +254,8 @@ protected virtual bool TryPrepareValue(DbConnection connection, ColumnMapper col { value = mappedValue; return true; - } - + } + return value == null || Guid.TryParse(Convert.ToString(value), out _) || int.TryParse(Convert.ToString(value), out _); diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/ProjectsModuleSpecifics.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/ProjectsModuleSpecifics.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/Modules/ProjectsModuleSpecifics.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/ProjectsModuleSpecifics.cs index 13c9a2612c5..d3b4749aa5c 100644 --- a/common/services/ASC.Data.Backup/Tasks/Modules/ProjectsModuleSpecifics.cs +++ b/common/ASC.Data.Backup.Core/Tasks/Modules/ProjectsModuleSpecifics.cs @@ -28,9 +28,9 @@ using System.Collections.Generic; using System.Data.Common; using System.Text.RegularExpressions; - + using ASC.Data.Backup.Tasks.Data; -using ASC.Data.Backup.Utils; +using ASC.Data.Backup.Utils; namespace ASC.Data.Backup.Tasks.Modules { @@ -87,7 +87,7 @@ public ProjectsModuleSpecifics(Helpers helpers) private readonly RelationInfo[] _tableRelations = new[] { - new RelationInfo("projects_comments", "id", "projects_comments", "parent_id"), + new RelationInfo("projects_comments", "id", "projects_comments", "parent_id"), new RelationInfo("projects_messages", "id", "projects_comments", "target_uniq_id", x => Convert.ToString(x["target_uniq_id"]).StartsWith("Message_", StringComparison.InvariantCultureIgnoreCase)), new RelationInfo("projects_tasks", "id", "projects_comments", "target_uniq_id", x => Convert.ToString(x["target_uniq_id"]).StartsWith("Task_", StringComparison.InvariantCultureIgnoreCase)), new RelationInfo("projects_milestones", "id", "projects_comments", "target_uniq_id", x => Convert.ToString(x["target_uniq_id"]).StartsWith("Milestone_", StringComparison.InvariantCultureIgnoreCase)), @@ -107,7 +107,7 @@ public ProjectsModuleSpecifics(Helpers helpers) new RelationInfo("projects_tasks", "id", "projects_tasks_links", "parent_id"), new RelationInfo("projects_projects", "id", "projects_tasks_order", "project_id"), new RelationInfo("projects_tasks", "id", "projects_tasks_order", "task_order"), - new RelationInfo("projects_milestones", "id", "projects_tasks_order", "task_order") + new RelationInfo("projects_milestones", "id", "projects_tasks_order", "task_order") }; public override ModuleName ModuleName diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/TenantsModuleSpecifics.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/TenantsModuleSpecifics.cs similarity index 100% rename from common/services/ASC.Data.Backup/Tasks/Modules/TenantsModuleSpecifics.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/TenantsModuleSpecifics.cs diff --git a/common/services/ASC.Data.Backup/Tasks/Modules/WebStudioModuleSpecifics.cs b/common/ASC.Data.Backup.Core/Tasks/Modules/WebStudioModuleSpecifics.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/Modules/WebStudioModuleSpecifics.cs rename to common/ASC.Data.Backup.Core/Tasks/Modules/WebStudioModuleSpecifics.cs index b1bf66b7ce5..120efbeb15e 100644 --- a/common/services/ASC.Data.Backup/Tasks/Modules/WebStudioModuleSpecifics.cs +++ b/common/ASC.Data.Backup.Core/Tasks/Modules/WebStudioModuleSpecifics.cs @@ -27,15 +27,15 @@ using System; using System.Collections.Generic; using System.Data.Common; -using System.Text.RegularExpressions; - +using System.Text.RegularExpressions; + using ASC.Data.Backup.Tasks.Data; namespace ASC.Data.Backup.Tasks.Modules { public class WebStudioModuleSpecifics : ModuleSpecificsBase { - public WebStudioModuleSpecifics(Helpers helpers) + public WebStudioModuleSpecifics(Helpers helpers) : base(helpers) { } private static readonly Guid CrmSettingsId = new Guid("fdf39b9a-ec96-4eb7-aeab-63f2c608eada"); diff --git a/common/services/ASC.Data.Backup/Tasks/PortalTaskBase.cs b/common/ASC.Data.Backup.Core/Tasks/PortalTaskBase.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/PortalTaskBase.cs rename to common/ASC.Data.Backup.Core/Tasks/PortalTaskBase.cs index dec1f902521..079bcdba695 100644 --- a/common/services/ASC.Data.Backup/Tasks/PortalTaskBase.cs +++ b/common/ASC.Data.Backup.Core/Tasks/PortalTaskBase.cs @@ -30,25 +30,25 @@ using System.IO; using System.Linq; using System.Text; -using System.Threading.Tasks; - +using System.Threading.Tasks; + using ASC.Common.Logging; using ASC.Data.Backup.Tasks.Modules; -using ASC.Data.Storage; - +using ASC.Data.Storage; + using Microsoft.Extensions.Options; namespace ASC.Data.Backup.Tasks { public class ProgressChangedEventArgs : EventArgs { - public int Progress { get; private set; } - - + public int Progress { get; private set; } + + public ProgressChangedEventArgs(int progress) { - Progress = progress; - + Progress = progress; + } } @@ -144,8 +144,8 @@ protected bool IsStorageModuleAllowed(string storageModuleName) "fckuploaders", "talk", "mailaggregator", - "whitelabel", - "customnavigation", + "whitelabel", + "customnavigation", "userPhotos" }; @@ -281,39 +281,39 @@ protected void RunMysqlFile(string file, bool db = false) } protected async Task RunMysqlFile(Stream stream, string delimiter = ";") - { - - if (stream == null) return; - - using var reader = new StreamReader(stream, Encoding.UTF8); - string commandText; - - while ((commandText = await reader.ReadLineAsync()) != null) - { - while (!commandText.EndsWith(delimiter)) - { - var newline = await reader.ReadLineAsync(); - if (newline == null) - { - break; - } - commandText += newline; - } - - try - { - - using var connection = DbFactory.OpenConnection(); - var command = connection.CreateCommand(); - command.CommandText = commandText; - await command.ExecuteNonQueryAsync(); - // await dbManager.ExecuteNonQueryAsync(commandText, null); - } - catch (Exception e) - { - Logger.Error("Restore", e); - } - } + { + + if (stream == null) return; + + using var reader = new StreamReader(stream, Encoding.UTF8); + string commandText; + + while ((commandText = await reader.ReadLineAsync()) != null) + { + while (!commandText.EndsWith(delimiter)) + { + var newline = await reader.ReadLineAsync(); + if (newline == null) + { + break; + } + commandText += newline; + } + + try + { + + using var connection = DbFactory.OpenConnection(); + var command = connection.CreateCommand(); + command.CommandText = commandText; + await command.ExecuteNonQueryAsync(); + // await dbManager.ExecuteNonQueryAsync(commandText, null); + } + catch (Exception e) + { + Logger.Error("Restore", e); + } + } } } } diff --git a/common/services/ASC.Data.Backup/Tasks/RestoreDbModuleTask.cs b/common/ASC.Data.Backup.Core/Tasks/RestoreDbModuleTask.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/RestoreDbModuleTask.cs rename to common/ASC.Data.Backup.Core/Tasks/RestoreDbModuleTask.cs index e4367b1ed34..419689d3cf4 100644 --- a/common/services/ASC.Data.Backup/Tasks/RestoreDbModuleTask.cs +++ b/common/ASC.Data.Backup.Core/Tasks/RestoreDbModuleTask.cs @@ -35,8 +35,8 @@ using ASC.Data.Backup.Extensions; using ASC.Data.Backup.Tasks.Data; using ASC.Data.Backup.Tasks.Modules; -using ASC.Data.Storage; - +using ASC.Data.Storage; + using Microsoft.Extensions.Options; namespace ASC.Data.Backup.Tasks @@ -56,7 +56,7 @@ public RestoreDbModuleTask(IOptionsMonitor options, IModuleSpecifics modul { Reader = reader ?? throw new ArgumentNullException("reader"); ColumnMapper = columnMapper ?? throw new ArgumentNullException("columnMapper"); - DbFactory = factory ?? throw new ArgumentNullException("factory"); + DbFactory = factory ?? throw new ArgumentNullException("factory"); Module = module; ReplaceDate = replaceDate; Dump = dump; @@ -95,111 +95,111 @@ private void RestoreTable(DbConnection connection, TableInfo tableInfo, ref int { SetColumns(connection, tableInfo); - using var stream = Reader.GetEntry(KeyHelper.GetTableZipKey(Module, tableInfo.Name)); - var lowImportanceRelations = Module - .TableRelations - .Where( - r => - string.Equals(r.ParentTable, tableInfo.Name, StringComparison.InvariantCultureIgnoreCase)) - .Where(r => r.Importance == RelationImportance.Low && !r.IsSelfRelation()) - .Select(r => Tuple.Create(r, Module.Tables.Single(t => t.Name == r.ChildTable))) - .ToList(); - - foreach ( - var rows in - GetRows(tableInfo, stream) - .Skip(transactionsCommited * TransactionLength) - .MakeParts(TransactionLength)) - { - using var transaction = connection.BeginTransaction(); - var rowsSuccess = 0; - foreach (var row in rows) - { - if (ReplaceDate) - { - foreach (var column in tableInfo.DateColumns) - { - ColumnMapper.SetDateMapping(tableInfo.Name, column, row[column.Key]); - } - } - - object oldIdValue = null; - object newIdValue = null; - - if (tableInfo.HasIdColumn()) - { - oldIdValue = row[tableInfo.IdColumn]; - newIdValue = ColumnMapper.GetMapping(tableInfo.Name, tableInfo.IdColumn, oldIdValue); - if (newIdValue == null) - { - if (tableInfo.IdType == IdType.Guid) - { - newIdValue = Guid.NewGuid().ToString("D"); - } - else if (tableInfo.IdType == IdType.Integer) - { - var command = connection.CreateCommand(); - command.CommandText = string.Format("select max({0}) from {1};", tableInfo.IdColumn, tableInfo.Name); - newIdValue = (int)command.WithTimeout(120).ExecuteScalar() + 1; - } - } - if (newIdValue != null) - { - ColumnMapper.SetMapping(tableInfo.Name, tableInfo.IdColumn, oldIdValue, - newIdValue); - } - } - - var insertCommand = Module.CreateInsertCommand(Dump, connection, ColumnMapper, tableInfo, - row); - if (insertCommand == null) - { - Logger.WarnFormat("Can't create command to insert row to {0} with values [{1}]", tableInfo, - row); - ColumnMapper.Rollback(); - continue; - } - insertCommand.WithTimeout(120).ExecuteNonQuery(); - rowsSuccess++; - - if (tableInfo.HasIdColumn() && tableInfo.IdType == IdType.Autoincrement) - { - var lastIdCommand = DbFactory.CreateLastInsertIdCommand(); - lastIdCommand.Connection = connection; - newIdValue = Convert.ToInt32(lastIdCommand.ExecuteScalar()); - ColumnMapper.SetMapping(tableInfo.Name, tableInfo.IdColumn, oldIdValue, newIdValue); - } - - ColumnMapper.Commit(); - - foreach (var relation in lowImportanceRelations) - { - if (!relation.Item2.HasTenantColumn()) - { - Logger.WarnFormat( - "Table {0} does not contain tenant id column. Can't apply low importance relations on such tables.", - relation.Item2.Name); - continue; - } - - var oldValue = row[relation.Item1.ParentColumn]; - var newValue = ColumnMapper.GetMapping(relation.Item1.ParentTable, - relation.Item1.ParentColumn, oldValue); - var command = connection.CreateCommand(); - command.CommandText = string.Format("update {0} set {1} = {2} where {1} = {3} and {4} = {5}", - relation.Item1.ChildTable, - relation.Item1.ChildColumn, - newValue is string ? "'" + newValue + "'" : newValue, - oldValue is string ? "'" + oldValue + "'" : oldValue, - relation.Item2.TenantColumn, - ColumnMapper.GetTenantMapping()); - command.WithTimeout(120).ExecuteNonQuery(); - } - } - - transaction.Commit(); - transactionsCommited++; - rowsInserted += rowsSuccess; + using var stream = Reader.GetEntry(KeyHelper.GetTableZipKey(Module, tableInfo.Name)); + var lowImportanceRelations = Module + .TableRelations + .Where( + r => + string.Equals(r.ParentTable, tableInfo.Name, StringComparison.InvariantCultureIgnoreCase)) + .Where(r => r.Importance == RelationImportance.Low && !r.IsSelfRelation()) + .Select(r => Tuple.Create(r, Module.Tables.Single(t => t.Name == r.ChildTable))) + .ToList(); + + foreach ( + var rows in + GetRows(tableInfo, stream) + .Skip(transactionsCommited * TransactionLength) + .MakeParts(TransactionLength)) + { + using var transaction = connection.BeginTransaction(); + var rowsSuccess = 0; + foreach (var row in rows) + { + if (ReplaceDate) + { + foreach (var column in tableInfo.DateColumns) + { + ColumnMapper.SetDateMapping(tableInfo.Name, column, row[column.Key]); + } + } + + object oldIdValue = null; + object newIdValue = null; + + if (tableInfo.HasIdColumn()) + { + oldIdValue = row[tableInfo.IdColumn]; + newIdValue = ColumnMapper.GetMapping(tableInfo.Name, tableInfo.IdColumn, oldIdValue); + if (newIdValue == null) + { + if (tableInfo.IdType == IdType.Guid) + { + newIdValue = Guid.NewGuid().ToString("D"); + } + else if (tableInfo.IdType == IdType.Integer) + { + var command = connection.CreateCommand(); + command.CommandText = string.Format("select max({0}) from {1};", tableInfo.IdColumn, tableInfo.Name); + newIdValue = (int)command.WithTimeout(120).ExecuteScalar() + 1; + } + } + if (newIdValue != null) + { + ColumnMapper.SetMapping(tableInfo.Name, tableInfo.IdColumn, oldIdValue, + newIdValue); + } + } + + var insertCommand = Module.CreateInsertCommand(Dump, connection, ColumnMapper, tableInfo, + row); + if (insertCommand == null) + { + Logger.WarnFormat("Can't create command to insert row to {0} with values [{1}]", tableInfo, + row); + ColumnMapper.Rollback(); + continue; + } + insertCommand.WithTimeout(120).ExecuteNonQuery(); + rowsSuccess++; + + if (tableInfo.HasIdColumn() && tableInfo.IdType == IdType.Autoincrement) + { + var lastIdCommand = DbFactory.CreateLastInsertIdCommand(); + lastIdCommand.Connection = connection; + newIdValue = Convert.ToInt32(lastIdCommand.ExecuteScalar()); + ColumnMapper.SetMapping(tableInfo.Name, tableInfo.IdColumn, oldIdValue, newIdValue); + } + + ColumnMapper.Commit(); + + foreach (var relation in lowImportanceRelations) + { + if (!relation.Item2.HasTenantColumn()) + { + Logger.WarnFormat( + "Table {0} does not contain tenant id column. Can't apply low importance relations on such tables.", + relation.Item2.Name); + continue; + } + + var oldValue = row[relation.Item1.ParentColumn]; + var newValue = ColumnMapper.GetMapping(relation.Item1.ParentTable, + relation.Item1.ParentColumn, oldValue); + var command = connection.CreateCommand(); + command.CommandText = string.Format("update {0} set {1} = {2} where {1} = {3} and {4} = {5}", + relation.Item1.ChildTable, + relation.Item1.ChildColumn, + newValue is string ? "'" + newValue + "'" : newValue, + oldValue is string ? "'" + oldValue + "'" : oldValue, + relation.Item2.TenantColumn, + ColumnMapper.GetTenantMapping()); + command.WithTimeout(120).ExecuteNonQuery(); + } + } + + transaction.Commit(); + transactionsCommited++; + rowsInserted += rowsSuccess; } } diff --git a/common/services/ASC.Data.Backup/Tasks/RestorePortalTask.cs b/common/ASC.Data.Backup.Core/Tasks/RestorePortalTask.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/RestorePortalTask.cs rename to common/ASC.Data.Backup.Core/Tasks/RestorePortalTask.cs index 147393e0cba..95ad6c19c36 100644 --- a/common/services/ASC.Data.Backup/Tasks/RestorePortalTask.cs +++ b/common/ASC.Data.Backup.Core/Tasks/RestorePortalTask.cs @@ -34,18 +34,18 @@ using ASC.Common; using ASC.Common.Caching; using ASC.Common.Logging; -using ASC.Common.Utils; +using ASC.Common.Utils; using ASC.Core; using ASC.Core.Billing; using ASC.Core.Tenants; using ASC.Data.Backup.Extensions; using ASC.Data.Backup.Tasks.Modules; -using ASC.Data.Storage; - +using ASC.Data.Storage; + using Microsoft.Extensions.Options; namespace ASC.Data.Backup.Tasks -{ +{ [Scope] public class RestorePortalTask : PortalTaskBase { @@ -57,29 +57,29 @@ public class RestorePortalTask : PortalTaskBase public bool ReplaceDate { get; set; } public bool Dump { get; set; } private CoreBaseSettings CoreBaseSettings { get; set; } - private LicenseReader LicenseReader { get; set; } - public TenantManager TenantManager { get; } + private LicenseReader LicenseReader { get; set; } + public TenantManager TenantManager { get; } private AscCacheNotify AscCacheNotify { get; set; } private IOptionsMonitor Options { get; set; } - public RestorePortalTask( - DbFactory dbFactory, - IOptionsMonitor options, - StorageFactory storageFactory, - StorageFactoryConfig storageFactoryConfig, - CoreBaseSettings coreBaseSettings, - LicenseReader licenseReader, - TenantManager tenantManager, - AscCacheNotify ascCacheNotify, + public RestorePortalTask( + DbFactory dbFactory, + IOptionsMonitor options, + StorageFactory storageFactory, + StorageFactoryConfig storageFactoryConfig, + CoreBaseSettings coreBaseSettings, + LicenseReader licenseReader, + TenantManager tenantManager, + AscCacheNotify ascCacheNotify, ModuleProvider moduleProvider) : base(dbFactory, options, storageFactory, storageFactoryConfig, moduleProvider) { CoreBaseSettings = coreBaseSettings; - LicenseReader = licenseReader; - TenantManager = tenantManager; + LicenseReader = licenseReader; + TenantManager = tenantManager; AscCacheNotify = ascCacheNotify; Options = options; - } + } public void Init(string toConfigPath, string fromFilePath, int tenantId = -1, ColumnMapper columnMapper = null, string upgradesPath = null) { @@ -93,7 +93,7 @@ public void Init(string toConfigPath, string fromFilePath, int tenantId = -1, Co UpgradesPath = upgradesPath; ColumnMapper = columnMapper ?? new ColumnMapper(); Init(tenantId, toConfigPath); - } + } public override void RunJob() { @@ -132,12 +132,12 @@ public override void RunJob() Logger.Debug("end restore data"); if (ProcessStorage) - { - if (CoreBaseSettings.Standalone) - { - Logger.Debug("clear cache"); - AscCacheNotify.ClearCache(); - } + { + if (CoreBaseSettings.Standalone) + { + Logger.Debug("clear cache"); + AscCacheNotify.ClearCache(); + } DoRestoreStorage(dataReader); } @@ -179,23 +179,23 @@ private void RestoreFromDump(IDataReadOperator dataReader) var stepscount = keys.Count * 2 + upgrades.Count; - SetStepsCount(ProcessStorage ? stepscount + 1 : stepscount); - - if (ProcessStorage) - { - var storageModules = StorageFactoryConfig.GetModuleList(ConfigPath).Where(IsStorageModuleAllowed); - var tenants = TenantManager.GetTenants(false); - - stepscount += storageModules.Count() * tenants.Count; - - SetStepsCount(stepscount + 1); - - DoDeleteStorage(storageModules, tenants); - } - else - { - SetStepsCount(stepscount); - } + SetStepsCount(ProcessStorage ? stepscount + 1 : stepscount); + + if (ProcessStorage) + { + var storageModules = StorageFactoryConfig.GetModuleList(ConfigPath).Where(IsStorageModuleAllowed); + var tenants = TenantManager.GetTenants(false); + + stepscount += storageModules.Count() * tenants.Count; + + SetStepsCount(stepscount + 1); + + DoDeleteStorage(storageModules, tenants); + } + else + { + SetStepsCount(stepscount); + } for (var i = 0; i < keys.Count; i += TasksLimit) { @@ -289,14 +289,14 @@ private void DoRestoreStorage(IDataReadOperator dataReader) { key = CrossPlatform.PathCombine(KeyHelper.GetStorage(), key); } - using var stream = dataReader.GetEntry(key); - try - { - storage.Save(file.Domain, adjustedPath, module != null ? module.PrepareData(key, stream, ColumnMapper) : stream); - } - catch (Exception error) - { - Logger.WarnFormat("can't restore file ({0}:{1}): {2}", file.Module, file.Path, error); + using var stream = dataReader.GetEntry(key); + try + { + storage.Save(file.Domain, adjustedPath, module != null ? module.PrepareData(key, stream, ColumnMapper) : stream); + } + catch (Exception error) + { + Logger.WarnFormat("can't restore file ({0}:{1}): {2}", file.Module, file.Path, error); } } } @@ -317,69 +317,69 @@ private void DoRestoreStorage(IDataReadOperator dataReader) SetStepCompleted(); } Logger.Debug("end restore storage"); - } - - private void DoDeleteStorage(IEnumerable storageModules, IEnumerable tenants) - { - Logger.Debug("begin delete storage"); - - foreach (var tenant in tenants) - { - foreach (var module in storageModules) - { - var storage = StorageFactory.GetStorage(ConfigPath, tenant.TenantId.ToString(), module); - var domains = StorageFactoryConfig.GetDomainList(ConfigPath, module).ToList(); - - domains.Add(string.Empty); //instead storage.DeleteFiles("\\", "*.*", true); - - foreach (var domain in domains) - { - ActionInvoker.Try( - state => - { - if (storage.IsDirectory((string)state)) - { - storage.DeleteFiles((string)state, "\\", "*.*", true); - } - }, - domain, - 5, - onFailure: error => Logger.WarnFormat("Can't delete files for domain {0}: \r\n{1}", domain, error) - ); - } - - SetStepCompleted(); - } - } - - Logger.Debug("end delete storage"); + } + + private void DoDeleteStorage(IEnumerable storageModules, IEnumerable tenants) + { + Logger.Debug("begin delete storage"); + + foreach (var tenant in tenants) + { + foreach (var module in storageModules) + { + var storage = StorageFactory.GetStorage(ConfigPath, tenant.TenantId.ToString(), module); + var domains = StorageFactoryConfig.GetDomainList(ConfigPath, module).ToList(); + + domains.Add(string.Empty); //instead storage.DeleteFiles("\\", "*.*", true); + + foreach (var domain in domains) + { + ActionInvoker.Try( + state => + { + if (storage.IsDirectory((string)state)) + { + storage.DeleteFiles((string)state, "\\", "*.*", true); + } + }, + domain, + 5, + onFailure: error => Logger.WarnFormat("Can't delete files for domain {0}: \r\n{1}", domain, error) + ); + } + + SetStepCompleted(); + } + } + + Logger.Debug("end delete storage"); } private IEnumerable GetFilesToProcess(IDataReadOperator dataReader) { - using var stream = dataReader.GetEntry(KeyHelper.GetStorageRestoreInfoZipKey()); - if (stream == null) - { - return Enumerable.Empty(); - } - var restoreInfo = XElement.Load(new StreamReader(stream)); + using var stream = dataReader.GetEntry(KeyHelper.GetStorageRestoreInfoZipKey()); + if (stream == null) + { + return Enumerable.Empty(); + } + var restoreInfo = XElement.Load(new StreamReader(stream)); return restoreInfo.Elements("file").Select(BackupFileInfo.FromXElement).ToList(); } private void SetTenantActive(int tenantId) { - using var connection = DbFactory.OpenConnection(); - var commandText = string.Format( - "update tenants_tenants " + - "set " + - " status={0}, " + - " last_modified='{1}', " + - " statuschanged='{1}' " + - "where id = '{2}'", - (int)TenantStatus.Active, - DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"), - tenantId); - + using var connection = DbFactory.OpenConnection(); + var commandText = string.Format( + "update tenants_tenants " + + "set " + + " status={0}, " + + " last_modified='{1}', " + + " statuschanged='{1}' " + + "where id = '{2}'", + (int)TenantStatus.Active, + DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"), + tenantId); + connection.CreateCommand().WithTimeout(120).ExecuteNonQuery(); } } diff --git a/common/services/ASC.Data.Backup/Tasks/TransferPortalTask.cs b/common/ASC.Data.Backup.Core/Tasks/TransferPortalTask.cs similarity index 99% rename from common/services/ASC.Data.Backup/Tasks/TransferPortalTask.cs rename to common/ASC.Data.Backup.Core/Tasks/TransferPortalTask.cs index 480aaa5b7c8..bb1b900760c 100644 --- a/common/services/ASC.Data.Backup/Tasks/TransferPortalTask.cs +++ b/common/ASC.Data.Backup.Core/Tasks/TransferPortalTask.cs @@ -31,7 +31,7 @@ using ASC.Common; using ASC.Common.Logging; -using ASC.Common.Utils; +using ASC.Common.Utils; using ASC.Core.Tenants; using ASC.Data.Backup.Extensions; using ASC.Data.Backup.Tasks.Modules; @@ -41,7 +41,7 @@ using Microsoft.Extensions.Options; namespace ASC.Data.Backup.Tasks -{ +{ [Scope] public class TransferPortalTask : PortalTaskBase { @@ -53,30 +53,30 @@ public class TransferPortalTask : PortalTaskBase public bool DeleteBackupFileAfterCompletion { get; set; } public bool BlockOldPortalAfterStart { get; set; } public bool DeleteOldPortalAfterCompletion { get; set; } - private IOptionsMonitor Options { get; set; } - private TempStream TempStream { get; } - private TempPath TempPath { get; } + private IOptionsMonitor Options { get; set; } + private TempStream TempStream { get; } + private TempPath TempPath { get; } private IServiceProvider ServiceProvider { get; set; } public int ToTenantId { get; private set; } public int Limit { get; private set; } - public TransferPortalTask( - DbFactory dbFactory, - IServiceProvider serviceProvider, - IOptionsMonitor options, - StorageFactory storageFactory, - StorageFactoryConfig storageFactoryConfig, - ModuleProvider moduleProvider, - TempStream tempStream, + public TransferPortalTask( + DbFactory dbFactory, + IServiceProvider serviceProvider, + IOptionsMonitor options, + StorageFactory storageFactory, + StorageFactoryConfig storageFactoryConfig, + ModuleProvider moduleProvider, + TempStream tempStream, TempPath tempPath) : base(dbFactory, options, storageFactory, storageFactoryConfig, moduleProvider) { DeleteBackupFileAfterCompletion = true; BlockOldPortalAfterStart = true; DeleteOldPortalAfterCompletion = true; - Options = options; - TempStream = tempStream; - TempPath = tempPath; + Options = options; + TempStream = tempStream; + TempPath = tempPath; ServiceProvider = serviceProvider; } @@ -145,8 +145,8 @@ public override void RunJob() else if (BlockOldPortalAfterStart) { SaveTenant(fromDbFactory, tenantAlias, TenantStatus.Active); - } - + } + ToTenantId = columnMapper.GetTenantMapping(); } catch diff --git a/common/services/ASC.Data.Backup/Utils/ConfigurationProvider.cs b/common/ASC.Data.Backup.Core/Utils/ConfigurationProvider.cs similarity index 100% rename from common/services/ASC.Data.Backup/Utils/ConfigurationProvider.cs rename to common/ASC.Data.Backup.Core/Utils/ConfigurationProvider.cs diff --git a/common/services/ASC.Data.Backup/Utils/FCKEditorPathUtility.cs b/common/ASC.Data.Backup.Core/Utils/FCKEditorPathUtility.cs similarity index 100% rename from common/services/ASC.Data.Backup/Utils/FCKEditorPathUtility.cs rename to common/ASC.Data.Backup.Core/Utils/FCKEditorPathUtility.cs diff --git a/common/services/ASC.Data.Backup/Utils/PathHelper.cs b/common/ASC.Data.Backup.Core/Utils/PathHelper.cs similarity index 100% rename from common/services/ASC.Data.Backup/Utils/PathHelper.cs rename to common/ASC.Data.Backup.Core/Utils/PathHelper.cs diff --git a/common/services/ASC.Data.Backup/protos/BackupProgress.proto b/common/ASC.Data.Backup.Core/protos/BackupProgress.proto similarity index 100% rename from common/services/ASC.Data.Backup/protos/BackupProgress.proto rename to common/ASC.Data.Backup.Core/protos/BackupProgress.proto diff --git a/common/services/ASC.Data.Backup/protos/DeleteSchedule.proto b/common/ASC.Data.Backup.Core/protos/DeleteSchedule.proto similarity index 100% rename from common/services/ASC.Data.Backup/protos/DeleteSchedule.proto rename to common/ASC.Data.Backup.Core/protos/DeleteSchedule.proto diff --git a/common/services/ASC.Data.Backup/ASC.Data.Backup.csproj b/common/services/ASC.Data.Backup/ASC.Data.Backup.csproj index bd37b4b5031..68e28a90b05 100644 --- a/common/services/ASC.Data.Backup/ASC.Data.Backup.csproj +++ b/common/services/ASC.Data.Backup/ASC.Data.Backup.csproj @@ -12,47 +12,6 @@ none false - - - - - - - - True - True - BackupResource.resx - - - - - ResXFileCodeGenerator - BackupResource.Designer.cs - - - - - - - true - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - @@ -61,5 +20,8 @@ + + + diff --git a/common/services/ASC.Data.Backup/Service/BackupCleanerService.cs b/common/services/ASC.Data.Backup/BackupCleanerService.cs similarity index 99% rename from common/services/ASC.Data.Backup/Service/BackupCleanerService.cs rename to common/services/ASC.Data.Backup/BackupCleanerService.cs index 2bed6d75666..eccf93f26dd 100644 --- a/common/services/ASC.Data.Backup/Service/BackupCleanerService.cs +++ b/common/services/ASC.Data.Backup/BackupCleanerService.cs @@ -26,41 +26,41 @@ using System; using System.Linq; -using System.Threading; - +using System.Threading; + using ASC.Common; using ASC.Common.Logging; -using ASC.Data.Backup.Storage; -using ASC.Files.Core; - -using Microsoft.Extensions.DependencyInjection; +using ASC.Data.Backup.Storage; +using ASC.Files.Core; + +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace ASC.Data.Backup.Service -{ +{ [Scope] internal class BackupCleanerHelperService { - private readonly ILog log; - - private BackupRepository BackupRepository { get; } - private BackupStorageFactory BackupStorageFactory { get; } - - public BackupCleanerHelperService( - IOptionsMonitor options, - BackupRepository backupRepository, + private readonly ILog log; + + private BackupRepository BackupRepository { get; } + private BackupStorageFactory BackupStorageFactory { get; } + + public BackupCleanerHelperService( + IOptionsMonitor options, + BackupRepository backupRepository, BackupStorageFactory backupStorageFactory) { - log = options.CurrentValue; - BackupRepository = backupRepository; - BackupStorageFactory = backupStorageFactory; + log = options.CurrentValue; + BackupRepository = backupRepository; + BackupStorageFactory = backupStorageFactory; } internal void DeleteExpiredBackups(BackupCleanerService backupCleanerService) { - log.Debug("started to clean expired backups"); - + log.Debug("started to clean expired backups"); + var backupsToRemove = BackupRepository.GetExpiredBackupRecords(); log.DebugFormat("found {0} backups which are expired", backupsToRemove.Count); @@ -95,14 +95,14 @@ internal void DeleteExpiredBackups(BackupCleanerService backupCleanerService) backupStorage.Delete(backupRecord.StoragePath); BackupRepository.DeleteBackupRecord(backupRecord.Id); - } - catch (ProviderInfoArgumentException error) - { - log.Warn("can't remove backup record " + backupRecord.Id, error); - if (DateTime.UtcNow > backupRecord.CreatedOn.AddMonths(6)) - { - BackupRepository.DeleteBackupRecord(backupRecord.Id); - } + } + catch (ProviderInfoArgumentException error) + { + log.Warn("can't remove backup record " + backupRecord.Id, error); + if (DateTime.UtcNow > backupRecord.CreatedOn.AddMonths(6)) + { + BackupRepository.DeleteBackupRecord(backupRecord.Id); + } } catch (Exception error) { @@ -110,8 +110,8 @@ internal void DeleteExpiredBackups(BackupCleanerService backupCleanerService) } } } - } - + } + [Singletone(Additional = typeof(BackupCleanerServiceExtension))] public class BackupCleanerService { @@ -119,14 +119,14 @@ public class BackupCleanerService private Timer CleanTimer { get; set; } internal bool IsStarted { get; set; } private ILog Log { get; set; } - public TimeSpan Period { get; set; } - private IServiceProvider ServiceProvider { get; set; } - - public BackupCleanerService( - IOptionsMonitor options, + public TimeSpan Period { get; set; } + private IServiceProvider ServiceProvider { get; set; } + + public BackupCleanerService( + IOptionsMonitor options, IServiceProvider serviceProvider) - { - ServiceProvider = serviceProvider; + { + ServiceProvider = serviceProvider; Log = options.CurrentValue; Period = TimeSpan.FromMinutes(15); } @@ -164,10 +164,10 @@ private void DeleteExpiredBackups() if (Monitor.TryEnter(cleanerLock)) { try - { - - using var scope = ServiceProvider.CreateScope(); - var backupCleanerHelperService = scope.ServiceProvider.GetService(); + { + + using var scope = ServiceProvider.CreateScope(); + var backupCleanerHelperService = scope.ServiceProvider.GetService(); backupCleanerHelperService.DeleteExpiredBackups(this); } catch (Exception error) @@ -180,13 +180,13 @@ private void DeleteExpiredBackups() } } } - } - - public class BackupCleanerServiceExtension - { - public static void Register(DIHelper services) - { - services.TryAdd(); - } + } + + public class BackupCleanerServiceExtension + { + public static void Register(DIHelper services) + { + services.TryAdd(); + } } } diff --git a/common/services/ASC.Data.Backup/Service/BackupSchedulerService.cs b/common/services/ASC.Data.Backup/BackupSchedulerService.cs similarity index 99% rename from common/services/ASC.Data.Backup/Service/BackupSchedulerService.cs rename to common/services/ASC.Data.Backup/BackupSchedulerService.cs index c261d3808b3..b26a3033f51 100644 --- a/common/services/ASC.Data.Backup/Service/BackupSchedulerService.cs +++ b/common/services/ASC.Data.Backup/BackupSchedulerService.cs @@ -27,44 +27,44 @@ using System; using System.Linq; using System.Threading; - + using ASC.Common; using ASC.Common.Logging; using ASC.Core; using ASC.Core.Billing; using ASC.Data.Backup.Storage; - -using Microsoft.Extensions.DependencyInjection; + +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace ASC.Data.Backup.Service -{ +{ [Scope] internal class BackupSchedulerServiceHelper { private ILog Log { get; } private PaymentManager PaymentManager { get; } - private BackupWorker BackupWorker { get; } - private BackupRepository BackupRepository { get; } - private Schedule Schedule { get; } - private TenantManager TenantManager { get; } - private CoreBaseSettings CoreBaseSettings { get; } - - public BackupSchedulerServiceHelper( - IOptionsMonitor options, - PaymentManager paymentManager, - BackupWorker backupWorker, - BackupRepository backupRepository, - Schedule schedule, - TenantManager tenantManager, + private BackupWorker BackupWorker { get; } + private BackupRepository BackupRepository { get; } + private Schedule Schedule { get; } + private TenantManager TenantManager { get; } + private CoreBaseSettings CoreBaseSettings { get; } + + public BackupSchedulerServiceHelper( + IOptionsMonitor options, + PaymentManager paymentManager, + BackupWorker backupWorker, + BackupRepository backupRepository, + Schedule schedule, + TenantManager tenantManager, CoreBaseSettings coreBaseSettings) { PaymentManager = paymentManager; - BackupWorker = backupWorker; - BackupRepository = backupRepository; - Schedule = schedule; - TenantManager = tenantManager; - CoreBaseSettings = coreBaseSettings; + BackupWorker = backupWorker; + BackupRepository = backupRepository; + Schedule = schedule; + TenantManager = tenantManager; + CoreBaseSettings = coreBaseSettings; Log = options.CurrentValue; } @@ -80,25 +80,25 @@ public void ScheduleBackupTasks(BackupSchedulerService backupSchedulerService) return; } try - { - if (CoreBaseSettings.Standalone || TenantManager.GetTenantQuota(schedule.TenantId).AutoBackup) - { - var tariff = PaymentManager.GetTariff(schedule.TenantId); - if (tariff.State < TariffState.Delay) - { - schedule.LastBackupTime = DateTime.UtcNow; - BackupRepository.SaveBackupSchedule(schedule); - Log.DebugFormat("Start scheduled backup: {0}, {1}, {2}, {3}", schedule.TenantId, schedule.BackupMail, schedule.StorageType, schedule.StorageBasePath); - BackupWorker.StartScheduledBackup(schedule); - } - else - { - Log.DebugFormat("Skip portal {0} not paid", schedule.TenantId); - } - } - else - { - Log.DebugFormat("Skip portal {0} haven't access", schedule.TenantId); + { + if (CoreBaseSettings.Standalone || TenantManager.GetTenantQuota(schedule.TenantId).AutoBackup) + { + var tariff = PaymentManager.GetTariff(schedule.TenantId); + if (tariff.State < TariffState.Delay) + { + schedule.LastBackupTime = DateTime.UtcNow; + BackupRepository.SaveBackupSchedule(schedule); + Log.DebugFormat("Start scheduled backup: {0}, {1}, {2}, {3}", schedule.TenantId, schedule.BackupMail, schedule.StorageType, schedule.StorageBasePath); + BackupWorker.StartScheduledBackup(schedule); + } + else + { + Log.DebugFormat("Skip portal {0} not paid", schedule.TenantId); + } + } + else + { + Log.DebugFormat("Skip portal {0} haven't access", schedule.TenantId); } } catch (Exception error) @@ -107,27 +107,27 @@ public void ScheduleBackupTasks(BackupSchedulerService backupSchedulerService) } } } - } - + } + [Singletone(Additional = typeof(BackupSchedulerServiceExtension))] public class BackupSchedulerService { private readonly object schedulerLock = new object(); private Timer SchedulerTimer { get; set; } - internal bool IsStarted { get; set; } + internal bool IsStarted { get; set; } public TimeSpan Period { get; set; } - private ILog Log { get; } - private IServiceProvider ServiceProvider { get; } - - public BackupSchedulerService( - IOptionsMonitor options, + private ILog Log { get; } + private IServiceProvider ServiceProvider { get; } + + public BackupSchedulerService( + IOptionsMonitor options, IServiceProvider serviceProvider) - { + { Log = options.CurrentValue; - Period = TimeSpan.FromMinutes(15); - ServiceProvider = serviceProvider; - } - + Period = TimeSpan.FromMinutes(15); + ServiceProvider = serviceProvider; + } + public void Start() { if (!IsStarted && Period > TimeSpan.Zero) @@ -160,9 +160,9 @@ private void ScheduleBackupTasks() if (Monitor.TryEnter(schedulerLock)) { try - { - using var scope = ServiceProvider.CreateScope(); - var backupSchedulerServiceHelper = scope.ServiceProvider.GetService(); + { + using var scope = ServiceProvider.CreateScope(); + var backupSchedulerServiceHelper = scope.ServiceProvider.GetService(); backupSchedulerServiceHelper.ScheduleBackupTasks(this); } catch (Exception error) @@ -175,13 +175,13 @@ private void ScheduleBackupTasks() } } } - } - - public class BackupSchedulerServiceExtension - { - public static void Register(DIHelper services) - { - services.TryAdd(); - } + } + + public class BackupSchedulerServiceExtension + { + public static void Register(DIHelper services) + { + services.TryAdd(); + } } } diff --git a/common/services/ASC.Data.Backup/BackupServiceLauncher.cs b/common/services/ASC.Data.Backup/BackupServiceLauncher.cs index 57d0b94e9ca..991dccefa6d 100644 --- a/common/services/ASC.Data.Backup/BackupServiceLauncher.cs +++ b/common/services/ASC.Data.Backup/BackupServiceLauncher.cs @@ -29,42 +29,42 @@ using ASC.Common; using ASC.Common.Utils; -using ASC.Data.Backup.Listerners; -using ASC.Web.Studio.Core.Notify; - +using ASC.Data.Backup.Listerners; +using ASC.Web.Studio.Core.Notify; + using Microsoft.Extensions.Hosting; namespace ASC.Data.Backup.Service { [Singletone] internal class BackupServiceLauncher : IHostedService - { + { private BackupCleanerService CleanerService { get; set; } private BackupSchedulerService SchedulerService { get; set; } private BackupWorker BackupWorker { get; set; } - private ConfigurationExtension Configuration { get; set; } + private ConfigurationExtension Configuration { get; set; } private BackupListener BackupListener { get; set; } - public NotifyConfiguration NotifyConfiguration { get; } - - public BackupServiceLauncher( + public NotifyConfiguration NotifyConfiguration { get; } + + public BackupServiceLauncher( BackupCleanerService cleanerService, BackupSchedulerService schedulerService, BackupWorker backupWorker, ConfigurationExtension configuration, - BackupListener backupListener, + BackupListener backupListener, NotifyConfiguration notifyConfiguration) - { + { CleanerService = cleanerService; SchedulerService = schedulerService; BackupWorker = backupWorker; - Configuration = configuration; + Configuration = configuration; BackupListener = backupListener; - NotifyConfiguration = notifyConfiguration; + NotifyConfiguration = notifyConfiguration; } public Task StartAsync(CancellationToken cancellationToken) - { - NotifyConfiguration.Configure(); + { + NotifyConfiguration.Configure(); var settings = Configuration.GetSetting("backup"); diff --git a/common/services/ASC.Data.Backup/Controllers/BackupController.cs b/common/services/ASC.Data.Backup/Controllers/BackupController.cs index ed2ec55b6bc..67b805a5d32 100644 --- a/common/services/ASC.Data.Backup/Controllers/BackupController.cs +++ b/common/services/ASC.Data.Backup/Controllers/BackupController.cs @@ -1,271 +1,271 @@ - -using System; -using System.Collections.Generic; -using System.Linq; - -using ASC.Common; -using ASC.Core; -using ASC.Data.Backup.Contracts; -using ASC.Data.Backup.ModelApi; -using ASC.Data.Backup.Models; -using ASC.Web.Api.Routing; -using ASC.Web.Studio.Utility; - -using Microsoft.AspNetCore.Mvc; - -using static ASC.Data.Backup.BackupAjaxHandler; - -namespace ASC.Data.Backup.Controllers -{ - [Scope] - [DefaultRoute] - [ApiController] - public class BackupController - { - private BackupAjaxHandler BackupHandler { get; } - private CoreBaseSettings CoreBaseSettings { get; } - private TenantExtra TenantExtra { get; } - - public BackupController( - BackupAjaxHandler backupAjaxHandler, - CoreBaseSettings coreBaseSettings, - TenantExtra tenantExtra) - { - BackupHandler = backupAjaxHandler; - CoreBaseSettings = coreBaseSettings; - TenantExtra = tenantExtra; - } - /// - /// Returns the backup schedule of the current portal - /// - /// Backup - /// Backup Schedule - [Read("getbackupschedule")] - public BackupAjaxHandler.Schedule GetBackupSchedule() - { - if (CoreBaseSettings.Standalone) - { - TenantExtra.DemandControlPanelPermission(); - } - - return BackupHandler.GetSchedule(); - } - - /// - /// Create the backup schedule of the current portal - /// - /// Storage type - /// Storage parameters - /// Max of the backup's stored copies - /// Cron parameters - /// Include mail in the backup - /// Backup - [Create("createbackupschedule")] - public bool CreateBackupScheduleFromBody([FromBody]BackupSchedule backupSchedule) - { - return CreateBackupSchedule(backupSchedule); - } - - [Create("createbackupschedule")] - [Consumes("application/x-www-form-urlencoded")] - public bool CreateBackupScheduleFromForm([FromForm]BackupSchedule backupSchedule) - { - return CreateBackupSchedule(backupSchedule); - } - - private bool CreateBackupSchedule(BackupSchedule backupSchedule) - { - if (CoreBaseSettings.Standalone) - { - TenantExtra.DemandControlPanelPermission(); - } - var storageType = backupSchedule.StorageType == null ? BackupStorageType.Documents : (BackupStorageType)Int32.Parse(backupSchedule.StorageType); - var storageParams = backupSchedule.StorageParams == null ? new Dictionary() : backupSchedule.StorageParams.ToDictionary(r => r.Key.ToString(), r => r.Value.ToString()); - var backupStored = backupSchedule.BackupsStored == null ? 0 : Int32.Parse(backupSchedule.BackupsStored); - var cron = new CronParams() - { - Period = backupSchedule.CronParams.Period == null ? BackupPeriod.EveryDay : (BackupPeriod)Int32.Parse(backupSchedule.CronParams.Period), - Hour = backupSchedule.CronParams.Hour == null ? 0 : Int32.Parse(backupSchedule.CronParams.Hour), - Day = backupSchedule.CronParams.Day == null ? 0 : Int32.Parse(backupSchedule.CronParams.Day), - }; - BackupHandler.CreateSchedule(storageType, storageParams, backupStored, cron, backupSchedule.BackupMail); - return true; - } - - /// - /// Delete the backup schedule of the current portal - /// - /// Backup - [Delete("deletebackupschedule")] - public bool DeleteBackupSchedule() - { - if (CoreBaseSettings.Standalone) - { - TenantExtra.DemandControlPanelPermission(); - } - - BackupHandler.DeleteSchedule(); - - return true; - } - - /// - /// Start a backup of the current portal - /// - /// Storage Type - /// Storage Params - /// Include mail in the backup - /// Backup - /// Backup Progress - [Create("startbackup")] - public BackupProgress StartBackupFromBody([FromBody]Models.Backup backup) - { - return StartBackup(backup); - } - - [Create("startbackup")] - [Consumes("application/x-www-form-urlencoded")] - public BackupProgress StartBackupFromForm([FromForm]Models.Backup backup) - { - return StartBackup(backup); - } - - private BackupProgress StartBackup(Models.Backup backup) - { - if (CoreBaseSettings.Standalone) - { - TenantExtra.DemandControlPanelPermission(); - } - var storageType = backup.StorageType == null ? BackupStorageType.Documents : (BackupStorageType)Int32.Parse(backup.StorageType); - var storageParams = backup.StorageParams == null ? new Dictionary() : backup.StorageParams.ToDictionary(r => r.Key.ToString(), r => r.Value.ToString()); - BackupHandler.StartBackup(storageType, storageParams, backup.BackupMail); - return BackupHandler.GetBackupProgress(); - } - - /// - /// Returns the progress of the started backup - /// - /// Backup - /// Backup Progress - [Read("getbackupprogress")] - public BackupProgress GetBackupProgress() - { - if (CoreBaseSettings.Standalone) - { - TenantExtra.DemandControlPanelPermission(); - } - - return BackupHandler.GetBackupProgress(); - } - - /// - /// Returns the backup history of the started backup - /// - /// Backup - /// Backup History - [Read("getbackuphistory")] - public List GetBackupHistory() - { - if (CoreBaseSettings.Standalone) - { - TenantExtra.DemandControlPanelPermission(); - } - - return BackupHandler.GetBackupHistory(); - } - - /// - /// Delete the backup with the specified id - /// - /// Backup - [Delete("deletebackup/{id}")] - public bool DeleteBackup(Guid id) - { - if (CoreBaseSettings.Standalone) - { - TenantExtra.DemandControlPanelPermission(); - } - - BackupHandler.DeleteBackup(id); - return true; - } - - /// - /// Delete all backups of the current portal - /// - /// Backup - /// Backup History - [Delete("deletebackuphistory")] - public bool DeleteBackupHistory() - { - if (CoreBaseSettings.Standalone) - { - TenantExtra.DemandControlPanelPermission(); - } - - BackupHandler.DeleteAllBackups(); - return true; - } - - /// - /// Start a data restore of the current portal - /// - /// Backup Id - /// Storage Type - /// Storage Params - /// Notify about backup to users - /// Backup - /// Restore Progress - [Create("startrestore")] - public BackupProgress StartBackupRestoreFromBody([FromBody]BackupRestore backupRestore) - { - return StartBackupRestore(backupRestore); - } - - [Create("startrestore")] - [Consumes("application/x-www-form-urlencoded")] - public BackupProgress StartBackupRestoreFromForm([FromForm]BackupRestore backupRestore) - { - return StartBackupRestore(backupRestore); - } - - private BackupProgress StartBackupRestore(BackupRestore backupRestore) - { - if (CoreBaseSettings.Standalone) - { - TenantExtra.DemandControlPanelPermission(); - } - var storageParams = backupRestore.StorageParams == null ? new Dictionary() : backupRestore.StorageParams.ToDictionary(r => r.Key.ToString(), r => r.Value.ToString()); - BackupHandler.StartRestore(backupRestore.BackupId, (BackupStorageType)Int32.Parse(backupRestore.StorageType.ToString()), storageParams, backupRestore.Notify); - return BackupHandler.GetBackupProgress(); - } - - /// - /// Returns the progress of the started restore - /// - /// Backup - /// Restore Progress - [Read("getrestoreprogress", true)] //NOTE: this method doesn't check payment!!! - public BackupProgress GetRestoreProgress() - { - if (CoreBaseSettings.Standalone) - { - TenantExtra.DemandControlPanelPermission(); - } - - return BackupHandler.GetRestoreProgress(); - } - - ///false - [Read("backuptmp")] - public object GetTempPath() - { - if (CoreBaseSettings.Standalone) - { - TenantExtra.DemandControlPanelPermission(); - } - - return BackupHandler.GetTmpFolder(); - } - } -} + +using System; +using System.Collections.Generic; +using System.Linq; + +using ASC.Common; +using ASC.Core; +using ASC.Data.Backup.Contracts; +using ASC.Data.Backup.ModelApi; +using ASC.Data.Backup.Models; +using ASC.Web.Api.Routing; +using ASC.Web.Studio.Utility; + +using Microsoft.AspNetCore.Mvc; + +using static ASC.Data.Backup.BackupAjaxHandler; + +namespace ASC.Data.Backup.Controllers +{ + [Scope] + [DefaultRoute] + [ApiController] + public class BackupController + { + private BackupAjaxHandler BackupHandler { get; } + private CoreBaseSettings CoreBaseSettings { get; } + private TenantExtra TenantExtra { get; } + + public BackupController( + BackupAjaxHandler backupAjaxHandler, + CoreBaseSettings coreBaseSettings, + TenantExtra tenantExtra) + { + BackupHandler = backupAjaxHandler; + CoreBaseSettings = coreBaseSettings; + TenantExtra = tenantExtra; + } + /// + /// Returns the backup schedule of the current portal + /// + /// Backup + /// Backup Schedule + [Read("getbackupschedule")] + public BackupAjaxHandler.Schedule GetBackupSchedule() + { + if (CoreBaseSettings.Standalone) + { + TenantExtra.DemandControlPanelPermission(); + } + + return BackupHandler.GetSchedule(); + } + + /// + /// Create the backup schedule of the current portal + /// + /// Storage type + /// Storage parameters + /// Max of the backup's stored copies + /// Cron parameters + /// Include mail in the backup + /// Backup + [Create("createbackupschedule")] + public bool CreateBackupScheduleFromBody([FromBody]BackupSchedule backupSchedule) + { + return CreateBackupSchedule(backupSchedule); + } + + [Create("createbackupschedule")] + [Consumes("application/x-www-form-urlencoded")] + public bool CreateBackupScheduleFromForm([FromForm]BackupSchedule backupSchedule) + { + return CreateBackupSchedule(backupSchedule); + } + + private bool CreateBackupSchedule(BackupSchedule backupSchedule) + { + if (CoreBaseSettings.Standalone) + { + TenantExtra.DemandControlPanelPermission(); + } + var storageType = backupSchedule.StorageType == null ? BackupStorageType.Documents : (BackupStorageType)Int32.Parse(backupSchedule.StorageType); + var storageParams = backupSchedule.StorageParams == null ? new Dictionary() : backupSchedule.StorageParams.ToDictionary(r => r.Key.ToString(), r => r.Value.ToString()); + var backupStored = backupSchedule.BackupsStored == null ? 0 : Int32.Parse(backupSchedule.BackupsStored); + var cron = new CronParams() + { + Period = backupSchedule.CronParams.Period == null ? BackupPeriod.EveryDay : (BackupPeriod)Int32.Parse(backupSchedule.CronParams.Period), + Hour = backupSchedule.CronParams.Hour == null ? 0 : Int32.Parse(backupSchedule.CronParams.Hour), + Day = backupSchedule.CronParams.Day == null ? 0 : Int32.Parse(backupSchedule.CronParams.Day), + }; + BackupHandler.CreateSchedule(storageType, storageParams, backupStored, cron, backupSchedule.BackupMail); + return true; + } + + /// + /// Delete the backup schedule of the current portal + /// + /// Backup + [Delete("deletebackupschedule")] + public bool DeleteBackupSchedule() + { + if (CoreBaseSettings.Standalone) + { + TenantExtra.DemandControlPanelPermission(); + } + + BackupHandler.DeleteSchedule(); + + return true; + } + + /// + /// Start a backup of the current portal + /// + /// Storage Type + /// Storage Params + /// Include mail in the backup + /// Backup + /// Backup Progress + [Create("startbackup")] + public BackupProgress StartBackupFromBody([FromBody]Models.Backup backup) + { + return StartBackup(backup); + } + + [Create("startbackup")] + [Consumes("application/x-www-form-urlencoded")] + public BackupProgress StartBackupFromForm([FromForm]Models.Backup backup) + { + return StartBackup(backup); + } + + private BackupProgress StartBackup(Models.Backup backup) + { + if (CoreBaseSettings.Standalone) + { + TenantExtra.DemandControlPanelPermission(); + } + var storageType = backup.StorageType == null ? BackupStorageType.Documents : (BackupStorageType)Int32.Parse(backup.StorageType); + var storageParams = backup.StorageParams == null ? new Dictionary() : backup.StorageParams.ToDictionary(r => r.Key.ToString(), r => r.Value.ToString()); + BackupHandler.StartBackup(storageType, storageParams, backup.BackupMail); + return BackupHandler.GetBackupProgress(); + } + + /// + /// Returns the progress of the started backup + /// + /// Backup + /// Backup Progress + [Read("getbackupprogress")] + public BackupProgress GetBackupProgress() + { + if (CoreBaseSettings.Standalone) + { + TenantExtra.DemandControlPanelPermission(); + } + + return BackupHandler.GetBackupProgress(); + } + + /// + /// Returns the backup history of the started backup + /// + /// Backup + /// Backup History + [Read("getbackuphistory")] + public List GetBackupHistory() + { + if (CoreBaseSettings.Standalone) + { + TenantExtra.DemandControlPanelPermission(); + } + + return BackupHandler.GetBackupHistory(); + } + + /// + /// Delete the backup with the specified id + /// + /// Backup + [Delete("deletebackup/{id}")] + public bool DeleteBackup(Guid id) + { + if (CoreBaseSettings.Standalone) + { + TenantExtra.DemandControlPanelPermission(); + } + + BackupHandler.DeleteBackup(id); + return true; + } + + /// + /// Delete all backups of the current portal + /// + /// Backup + /// Backup History + [Delete("deletebackuphistory")] + public bool DeleteBackupHistory() + { + if (CoreBaseSettings.Standalone) + { + TenantExtra.DemandControlPanelPermission(); + } + + BackupHandler.DeleteAllBackups(); + return true; + } + + /// + /// Start a data restore of the current portal + /// + /// Backup Id + /// Storage Type + /// Storage Params + /// Notify about backup to users + /// Backup + /// Restore Progress + [Create("startrestore")] + public BackupProgress StartBackupRestoreFromBody([FromBody]BackupRestore backupRestore) + { + return StartBackupRestore(backupRestore); + } + + [Create("startrestore")] + [Consumes("application/x-www-form-urlencoded")] + public BackupProgress StartBackupRestoreFromForm([FromForm]BackupRestore backupRestore) + { + return StartBackupRestore(backupRestore); + } + + private BackupProgress StartBackupRestore(BackupRestore backupRestore) + { + if (CoreBaseSettings.Standalone) + { + TenantExtra.DemandControlPanelPermission(); + } + var storageParams = backupRestore.StorageParams == null ? new Dictionary() : backupRestore.StorageParams.ToDictionary(r => r.Key.ToString(), r => r.Value.ToString()); + BackupHandler.StartRestore(backupRestore.BackupId, (BackupStorageType)Int32.Parse(backupRestore.StorageType.ToString()), storageParams, backupRestore.Notify); + return BackupHandler.GetBackupProgress(); + } + + /// + /// Returns the progress of the started restore + /// + /// Backup + /// Restore Progress + [Read("getrestoreprogress", true)] //NOTE: this method doesn't check payment!!! + public BackupProgress GetRestoreProgress() + { + if (CoreBaseSettings.Standalone) + { + TenantExtra.DemandControlPanelPermission(); + } + + return BackupHandler.GetRestoreProgress(); + } + + ///false + [Read("backuptmp")] + public object GetTempPath() + { + if (CoreBaseSettings.Standalone) + { + TenantExtra.DemandControlPanelPermission(); + } + + return BackupHandler.GetTmpFolder(); + } + } +} diff --git a/common/services/ASC.Data.Backup/Program.cs b/common/services/ASC.Data.Backup/Program.cs index f4279122114..e87a83c5009 100644 --- a/common/services/ASC.Data.Backup/Program.cs +++ b/common/services/ASC.Data.Backup/Program.cs @@ -1,56 +1,56 @@ -using System; +using System; using System.Collections.Generic; using System.IO; -using System.Runtime.InteropServices; -using System.Threading.Tasks; - -using ASC.Api.Core; -using ASC.Common.Utils; - -using Autofac.Extensions.DependencyInjection; - -using Microsoft.AspNetCore.Hosting; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +using ASC.Api.Core; +using ASC.Common.Utils; + +using Autofac.Extensions.DependencyInjection; + +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; namespace ASC.Data.Backup { public class Program - { + { public async static Task Main(string[] args) - { - var host = CreateHostBuilder(args).Build(); - + { + var host = CreateHostBuilder(args).Build(); + await host.RunAsync(); } public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .UseSystemd() - .UseWindowsService() + Host.CreateDefaultBuilder(args) + .UseSystemd() + .UseWindowsService() .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureWebHostDefaults(webBuilder => { - var builder = webBuilder.UseStartup(); - - builder.ConfigureKestrel((hostingContext, serverOptions) => - { - var kestrelConfig = hostingContext.Configuration.GetSection("Kestrel"); - - if (!kestrelConfig.Exists()) return; - - var unixSocket = kestrelConfig.GetValue("ListenUnixSocket"); - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - if (!String.IsNullOrWhiteSpace(unixSocket)) - { - unixSocket = String.Format(unixSocket, hostingContext.HostingEnvironment.ApplicationName.Replace("ASC.", "").Replace(".", "")); - - serverOptions.ListenUnixSocket(unixSocket); - } - } - }); + var builder = webBuilder.UseStartup(); + + builder.ConfigureKestrel((hostingContext, serverOptions) => + { + var kestrelConfig = hostingContext.Configuration.GetSection("Kestrel"); + + if (!kestrelConfig.Exists()) return; + + var unixSocket = kestrelConfig.GetValue("ListenUnixSocket"); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + if (!String.IsNullOrWhiteSpace(unixSocket)) + { + unixSocket = String.Format(unixSocket, hostingContext.HostingEnvironment.ApplicationName.Replace("ASC.", "").Replace(".", "")); + + serverOptions.ListenUnixSocket(unixSocket); + } + } + }); }) .ConfigureAppConfiguration((hostContext, config) => { @@ -66,19 +66,19 @@ public static IHostBuilder CreateHostBuilder(string[] args) => .AddJsonFile("appsettings.json") .AddJsonFile($"appsettings.{env}.json", true) .AddJsonFile("storage.json") - .AddJsonFile("notify.json") + .AddJsonFile("notify.json") .AddJsonFile($"notify.{env}.json", true) .AddJsonFile("backup.json") .AddJsonFile("kafka.json") .AddJsonFile($"kafka.{env}.json", true) - .AddEnvironmentVariables() + .AddEnvironmentVariables() .AddInMemoryCollection(new Dictionary { {"pathToConf", path } } ); - }) - .ConfigureNLogLogging(); + }) + .ConfigureNLogLogging(); } } diff --git a/common/services/ASC.Data.Backup/Startup.cs b/common/services/ASC.Data.Backup/Startup.cs index 794da2ed9a9..a4a59493d70 100644 --- a/common/services/ASC.Data.Backup/Startup.cs +++ b/common/services/ASC.Data.Backup/Startup.cs @@ -21,15 +21,15 @@ * in every copy of the program you distribute. * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. * -*/ - +*/ + using ASC.Api.Core; -using ASC.Common; -using ASC.Common.Threading; +using ASC.Common; +using ASC.Common.Threading; using ASC.Data.Backup.Controllers; -using ASC.Data.Backup.Service; -using ASC.Web.Studio.Core.Notify; - +using ASC.Data.Backup.Service; +using ASC.Web.Studio.Core.Notify; + using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -41,22 +41,22 @@ public class Startup : BaseStartup public Startup(IConfiguration configuration, IHostEnvironment hostEnvironment) : base(configuration, hostEnvironment) { - } + } - public override void ConfigureServices(IServiceCollection services) + public override void ConfigureServices(IServiceCollection services) { - base.ConfigureServices(services); + base.ConfigureServices(services); DIHelper.AddDistributedTaskQueueService(1); - - DIHelper.TryAdd(); - DIHelper.TryAdd(); - DIHelper.TryAdd(); - - DIHelper.TryAdd(); - DIHelper.TryAdd(); - NotifyConfigurationExtension.Register(DIHelper); - + + DIHelper.TryAdd(); + DIHelper.TryAdd(); + DIHelper.TryAdd(); + + DIHelper.TryAdd(); + DIHelper.TryAdd(); + NotifyConfigurationExtension.Register(DIHelper); + services.AddHostedService(); } } diff --git a/web/ASC.Web.Api/ASC.Web.Api.csproj b/web/ASC.Web.Api/ASC.Web.Api.csproj index b61ee817518..27667fc3034 100644 --- a/web/ASC.Web.Api/ASC.Web.Api.csproj +++ b/web/ASC.Web.Api/ASC.Web.Api.csproj @@ -27,8 +27,8 @@ + -