using System; using System.Collections.Generic; using System.Linq; 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.MessagingSystem; using ASC.Notify.Cron; using ASC.Web.Core.PublicResources; using ASC.Web.Studio.Core; using ASC.Web.Studio.Utility; namespace ASC.Data.Backup { public class BackupAjaxHandler { private TenantManager TenantManager { get; } private MessageService MessageService { get; } private CoreBaseSettings CoreBaseSettings { get; } private CoreConfiguration CoreConfiguration { get; } private PermissionContext PermissionContext { get; } private SecurityContext SecurityContext { get; } private UserManager UserManager { get; } private TenantExtra TenantExtra { get; } private BackupHelper BackupHelper { get; } private ConsumerFactory ConsumerFactory { 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, BackupHelper backupHelper, ConsumerFactory consumerFactory) { TenantManager = tenantManager; MessageService = messageService; CoreBaseSettings = coreBaseSettings; CoreConfiguration = coreConfiguration; PermissionContext = permissionContext; SecurityContext = securityContext; UserManager = userManager; TenantExtra = tenantExtra; BackupHelper = backupHelper; ConsumerFactory = consumerFactory; BackupService = backupService; } public void StartBackup(BackupStorageType storageType, Dictionary storageParams, bool backupMail) { DemandPermissionsBackup(); DemandSize(); var backupRequest = new StartBackupRequest { TenantId = GetCurrentTenantId(), UserId = SecurityContext.CurrentAccount.ID, BackupMail = backupMail, StorageType = storageType, StorageParams = storageParams }; switch (storageType) { case BackupStorageType.ThridpartyDocuments: case BackupStorageType.Documents: backupRequest.StorageBasePath = storageParams["folderId"]; break; case BackupStorageType.Local: if (!CoreBaseSettings.Standalone) throw new Exception("Access denied"); backupRequest.StorageBasePath = storageParams["filePath"]; break; } MessageService.Send(MessageAction.StartBackupSetting); BackupService.StartBackup(backupRequest); } public BackupProgress GetBackupProgress() { DemandPermissionsBackup(); return BackupService.GetBackupProgress(GetCurrentTenantId()); } public void DeleteBackup(Guid id) { DemandPermissionsBackup(); BackupService.DeleteBackup(id); } public void DeleteAllBackups() { DemandPermissionsBackup(); BackupService.DeleteAllBackups(GetCurrentTenantId()); } public List GetBackupHistory() { DemandPermissionsBackup(); return BackupService.GetBackupHistory(GetCurrentTenantId()); } public void CreateSchedule(BackupStorageType storageType, Dictionary storageParams, int backupsStored, CronParams cronParams, bool backupMail) { DemandPermissionsBackup(); DemandSize(); if (!SetupInfo.IsVisibleSettings("AutoBackup")) throw new InvalidOperationException(Resource.ErrorNotAllowedOption); ValidateCronSettings(cronParams); var scheduleRequest = new CreateScheduleRequest { TenantId = TenantManager.GetCurrentTenant().TenantId, BackupMail = backupMail, Cron = cronParams.ToString(), NumberOfBackupsStored = backupsStored, StorageType = storageType, StorageParams = storageParams }; switch (storageType) { case BackupStorageType.ThridpartyDocuments: case BackupStorageType.Documents: scheduleRequest.StorageBasePath = storageParams["folderId"]; break; case BackupStorageType.Local: if (!CoreBaseSettings.Standalone) throw new Exception("Access denied"); scheduleRequest.StorageBasePath = storageParams["filePath"]; break; } BackupService.CreateSchedule(scheduleRequest); } public Schedule GetSchedule() { DemandPermissionsBackup(); ScheduleResponse response; response = BackupService.GetSchedule(GetCurrentTenantId()); if (response == null) { return null; } var schedule = new Schedule { StorageType = response.StorageType, StorageParams = response.StorageParams.ToDictionary(r => r.Key, r => r.Value) ?? new Dictionary(), CronParams = new CronParams(response.Cron), BackupMail = response.BackupMail ? (bool?)true : null, BackupsStored = response.NumberOfBackupsStored == 0 ? null : (int?)response.NumberOfBackupsStored, LastBackupTime = response.LastBackupTime }; if ((BackupStorageType)response.StorageType == BackupStorageType.CustomCloud) { var amazonSettings = CoreConfiguration.GetSection(); var consumer = ConsumerFactory.GetByKey("S3"); if (!consumer.IsSet) { consumer["acesskey"] = amazonSettings.AccessKeyId; consumer["secretaccesskey"] = amazonSettings.SecretAccessKey; consumer["bucket"] = amazonSettings.Bucket; consumer["region"] = amazonSettings.Region; } schedule.StorageType = BackupStorageType.ThirdPartyConsumer; schedule.StorageParams = consumer.AdditionalKeys.ToDictionary(r => r, r => consumer[r]); schedule.StorageParams.Add("module", "S3"); var Schedule = new CreateScheduleRequest { TenantId = TenantManager.GetCurrentTenant().TenantId, BackupMail = schedule.BackupMail == null ? false : (bool)schedule.BackupMail, Cron = schedule.CronParams.ToString(), NumberOfBackupsStored = schedule.BackupsStored == null ? 0 : (int)schedule.BackupsStored, StorageType = schedule.StorageType, StorageParams = schedule.StorageParams }; BackupService.CreateSchedule(Schedule); } else if ((BackupStorageType)response.StorageType != BackupStorageType.ThirdPartyConsumer) { schedule.StorageParams["folderId"] = response.StorageBasePath; } return schedule; } public void DeleteSchedule() { DemandPermissionsBackup(); BackupService.DeleteSchedule(GetCurrentTenantId()); } private void DemandPermissionsBackup() { PermissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings); if (!SetupInfo.IsVisibleSettings(ManagementType.Backup.ToString())) throw new BillingException(Resource.ErrorNotAllowedOption, "Backup"); } #endregion #region restore public void StartRestore(string backupId, BackupStorageType storageType, Dictionary storageParams, bool notify) { DemandPermissionsRestore(); var restoreRequest = new StartRestoreRequest { TenantId = GetCurrentTenantId(), NotifyAfterCompletion = notify, StorageParams = storageParams }; if (Guid.TryParse(backupId, out var guidBackupId)) { restoreRequest.BackupId = guidBackupId; } else { restoreRequest.StorageType = storageType; restoreRequest.FilePathOrId = storageParams["filePath"]; } BackupService.StartRestore(restoreRequest); } public BackupProgress GetRestoreProgress() { BackupProgress result; var tenant = TenantManager.GetCurrentTenant(); result = BackupService.GetRestoreProgress(tenant.TenantId); return result; } private void DemandPermissionsRestore() { PermissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings); if (!SetupInfo.IsVisibleSettings("Restore")) throw new BillingException(Resource.ErrorNotAllowedOption, "Restore"); } #endregion #region transfer public void StartTransfer(string targetRegion, bool notifyUsers, bool transferMail) { DemandPermissionsTransfer(); DemandSize(); MessageService.Send(MessageAction.StartTransferSetting); BackupService.StartTransfer( new StartTransferRequest { TenantId = GetCurrentTenantId(), TargetRegion = targetRegion, BackupMail = transferMail, NotifyUsers = notifyUsers }); } public BackupProgress GetTransferProgress() { return BackupService.GetTransferProgress(GetCurrentTenantId()); } private void DemandPermissionsTransfer() { PermissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings); var currentUser = UserManager.GetUsers(SecurityContext.CurrentAccount.ID); if (!SetupInfo.IsVisibleSettings(ManagementType.Migration.ToString()) || !currentUser.IsOwner(TenantManager.GetCurrentTenant()) || !SetupInfo.IsSecretEmail(currentUser.Email) && !TenantExtra.GetTenantQuota().HasMigration) throw new InvalidOperationException(Resource.ErrorNotAllowedOption); } #endregion public string GetTmpFolder() { return BackupService.GetTmpFolder(); } private void DemandSize() { if (BackupHelper.ExceedsMaxAvailableSize(TenantManager.GetCurrentTenant().TenantId)) throw new InvalidOperationException(string.Format(UserControlsCommonResource.BackupSpaceExceed, FileSizeComment.FilesSizeToString(BackupHelper.AvailableZipSize), "", "")); } private static void ValidateCronSettings(CronParams cronParams) { new CronExpression(cronParams.ToString()); } private int GetCurrentTenantId() { return TenantManager.GetCurrentTenant().TenantId; } public class Schedule { public BackupStorageType StorageType { get; set; } public Dictionary StorageParams { get; set; } public CronParams CronParams { get; set; } public bool? BackupMail { get; set; } public int? BackupsStored { get; set; } public DateTime LastBackupTime { get; set; } } public class CronParams { public BackupPeriod Period { get; set; } public int Hour { get; set; } public int Day { get; set; } public CronParams() { } public CronParams(string cronString) { var tokens = cronString.Split(' '); Hour = Convert.ToInt32(tokens[2]); if (tokens[3] != "?") { Period = BackupPeriod.EveryMonth; Day = Convert.ToInt32(tokens[3]); } else if (tokens[5] != "*") { Period = BackupPeriod.EveryWeek; Day = Convert.ToInt32(tokens[5]); } else { Period = BackupPeriod.EveryDay; } } public override string 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(), }; } } public enum BackupPeriod { EveryDay = 0, EveryWeek = 1, EveryMonth = 2 } } public static class BackupAjaxHandlerExtension { public static DIHelper AddBackupAjaxHandler(this DIHelper services) { services.TryAddScoped(); return services .AddTenantManagerService() .AddCoreBaseSettingsService() .AddMessageServiceService() .AddCoreSettingsService() .AddPermissionContextService() .AddSecurityContextService() .AddUserManagerService() .AddTenantExtraService() .AddConsumerFactoryService() .AddBackupHelperService(); } } }