DocSpace-client/common/ASC.Data.Backup.Core/BackupAjaxHandler.cs

452 lines
15 KiB
C#
Raw Normal View History

2022-03-15 18:00:53 +00:00
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
2022-10-11 12:29:23 +00:00
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
2022-03-15 18:00:53 +00:00
namespace ASC.Data.Backup;
[Scope]
public class BackupAjaxHandler
2021-08-31 09:40:28 +00:00
{
private readonly TenantManager _tenantManager;
private readonly MessageService _messageService;
private readonly CoreBaseSettings _coreBaseSettings;
private readonly CoreConfiguration _coreConfiguration;
private readonly PermissionContext _permissionContext;
private readonly SecurityContext _securityContext;
private readonly UserManager _userManager;
private readonly ConsumerFactory _consumerFactory;
private readonly BackupService _backupService;
2022-10-11 12:29:23 +00:00
private readonly StorageFactory _storageFactory;
2022-10-11 12:29:23 +00:00
private const string BackupTempModule = "backup_temp";
private const string BackupFileName = "backup.tmp";
#region backup
public BackupAjaxHandler(
BackupService backupService,
TenantManager tenantManager,
MessageService messageService,
CoreBaseSettings coreBaseSettings,
CoreConfiguration coreConfiguration,
PermissionContext permissionContext,
SecurityContext securityContext,
UserManager userManager,
ConsumerFactory consumerFactory,
2022-10-11 12:29:23 +00:00
StorageFactory storageFactory)
{
_tenantManager = tenantManager;
_messageService = messageService;
_coreBaseSettings = coreBaseSettings;
_coreConfiguration = coreConfiguration;
_permissionContext = permissionContext;
_securityContext = securityContext;
_userManager = userManager;
_consumerFactory = consumerFactory;
_backupService = backupService;
2022-10-11 12:29:23 +00:00
_storageFactory = storageFactory;
}
2023-03-16 15:23:59 +00:00
public async Task StartBackupAsync(BackupStorageType storageType, Dictionary<string, string> storageParams)
{
2023-03-20 16:16:00 +00:00
await DemandPermissionsBackupAsync();
var backupRequest = new StartBackupRequest
{
2023-03-20 16:16:00 +00:00
TenantId = await GetCurrentTenantIdAsync(),
UserId = _securityContext.CurrentAccount.ID,
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;
}
2023-03-16 15:23:59 +00:00
await _messageService.SendAsync(MessageAction.StartBackupSetting);
_backupService.StartBackup(backupRequest);
}
2023-03-20 16:16:00 +00:00
public async Task<BackupProgress> GetBackupProgressAsync()
{
2023-03-20 16:16:00 +00:00
await DemandPermissionsBackupAsync();
2023-03-20 16:16:00 +00:00
return _backupService.GetBackupProgress(await GetCurrentTenantIdAsync());
}
2021-08-31 09:40:28 +00:00
2023-03-20 16:16:00 +00:00
public async Task<BackupProgress> GetBackupProgressAsync(int tenantId)
{
2023-03-20 16:16:00 +00:00
await DemandPermissionsBackupAsync();
return _backupService.GetBackupProgress(tenantId);
}
2021-08-31 09:40:28 +00:00
2023-03-20 16:16:00 +00:00
public async Task DeleteBackupAsync(Guid id)
{
2023-03-20 16:16:00 +00:00
await DemandPermissionsBackupAsync();
2023-03-20 16:16:00 +00:00
await _backupService.DeleteBackupAsync(id);
}
2021-08-31 09:40:28 +00:00
2023-03-20 16:16:00 +00:00
public async Task DeleteAllBackupsAsync()
{
2023-03-20 16:16:00 +00:00
await DemandPermissionsBackupAsync();
2020-10-14 14:26:18 +00:00
2023-03-20 16:16:00 +00:00
await _backupService.DeleteAllBackupsAsync(await GetCurrentTenantIdAsync());
}
2022-10-27 10:49:42 +00:00
public async Task<List<BackupHistoryRecord>> GetBackupHistory()
{
2023-03-20 16:16:00 +00:00
await DemandPermissionsBackupAsync();
2023-03-20 16:16:00 +00:00
return await _backupService.GetBackupHistoryAsync(await GetCurrentTenantIdAsync());
}
2023-03-14 20:44:44 +00:00
public async Task CreateScheduleAsync(BackupStorageType storageType, Dictionary<string, string> storageParams, int backupsStored, CronParams cronParams)
{
2023-03-20 16:16:00 +00:00
await DemandPermissionsBackupAsync();
if (!SetupInfo.IsVisibleSettings("AutoBackup"))
{
throw new InvalidOperationException(Resource.ErrorNotAllowedOption);
}
ValidateCronSettings(cronParams);
var scheduleRequest = new CreateScheduleRequest
{
2023-03-20 16:16:00 +00:00
TenantId = (await _tenantManager.GetCurrentTenantAsync()).Id,
Cron = cronParams.ToString(),
NumberOfBackupsStored = backupsStored,
StorageType = storageType,
StorageParams = storageParams
};
2021-08-31 09:40:28 +00:00
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;
}
2023-03-14 20:44:44 +00:00
await _backupService.CreateScheduleAsync(scheduleRequest);
}
2023-03-13 16:29:42 +00:00
public async Task<Schedule> GetScheduleAsync()
{
2023-03-20 16:16:00 +00:00
await DemandPermissionsBackupAsync();
ScheduleResponse response;
2022-02-09 18:33:50 +00:00
2023-03-20 16:16:00 +00:00
response = await _backupService.GetScheduleAsync(await GetCurrentTenantIdAsync());
if (response == null)
{
return null;
}
var schedule = new Schedule
{
StorageType = response.StorageType,
StorageParams = response.StorageParams.ToDictionary(r => r.Key, r => r.Value) ?? new Dictionary<string, string>(),
CronParams = new CronParams(response.Cron),
BackupsStored = response.NumberOfBackupsStored.NullIfDefault(),
LastBackupTime = response.LastBackupTime
};
if (response.StorageType == BackupStorageType.CustomCloud)
{
2023-03-20 16:16:00 +00:00
var amazonSettings = await _coreConfiguration.GetSectionAsync<AmazonS3Settings>();
2020-06-04 10:47:22 +00:00
var consumer = _consumerFactory.GetByKey<DataStoreConsumer>("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
{
2023-03-20 16:16:00 +00:00
TenantId = (await _tenantManager.GetCurrentTenantAsync()).Id,
Cron = schedule.CronParams.ToString(),
NumberOfBackupsStored = schedule.BackupsStored == null ? 0 : (int)schedule.BackupsStored,
StorageType = schedule.StorageType,
StorageParams = schedule.StorageParams
};
2023-03-14 20:44:44 +00:00
await _backupService.CreateScheduleAsync(Schedule);
}
else if (response.StorageType != BackupStorageType.ThirdPartyConsumer)
{
schedule.StorageParams["folderId"] = response.StorageBasePath;
}
return schedule;
}
2023-03-20 16:16:00 +00:00
public async Task DeleteScheduleAsync()
{
2023-03-20 16:16:00 +00:00
await DemandPermissionsBackupAsync();
2023-03-20 16:16:00 +00:00
await _backupService.DeleteScheduleAsync(await GetCurrentTenantIdAsync());
}
2023-03-20 16:16:00 +00:00
private async Task DemandPermissionsBackupAsync()
{
2023-03-20 16:16:00 +00:00
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
2022-06-14 08:11:41 +00:00
if (!_coreBaseSettings.Standalone && !SetupInfo.IsVisibleSettings(nameof(ManagementType.Backup)))
{
throw new BillingException(Resource.ErrorNotAllowedOption, "Backup");
}
}
#endregion
#region restore
2020-06-04 10:47:22 +00:00
2023-03-14 20:44:44 +00:00
public async Task StartRestoreAsync(string backupId, BackupStorageType storageType, Dictionary<string, string> storageParams, bool notify)
{
2023-03-14 20:44:44 +00:00
await DemandPermissionsRestoreAsync();
var restoreRequest = new StartRestoreRequest
{
2023-03-20 16:16:00 +00:00
TenantId = await GetCurrentTenantIdAsync(),
NotifyAfterCompletion = notify,
StorageParams = storageParams
};
if (Guid.TryParse(backupId, out var guidBackupId))
{
restoreRequest.BackupId = guidBackupId;
}
else
{
restoreRequest.StorageType = storageType;
restoreRequest.FilePathOrId = storageParams["filePath"];
if (restoreRequest.StorageType == BackupStorageType.Local && !_coreBaseSettings.Standalone)
{
2023-03-20 16:16:00 +00:00
restoreRequest.FilePathOrId = await GetTmpFilePathAsync();
}
}
2021-08-31 09:40:28 +00:00
2023-03-14 20:44:44 +00:00
await _backupService.StartRestoreAsync(restoreRequest);
}
2021-05-24 17:41:31 +00:00
2023-03-20 16:16:00 +00:00
public async Task<BackupProgress> GetRestoreProgressAsync()
{
BackupProgress result;
2023-03-20 16:16:00 +00:00
var tenant = await _tenantManager.GetCurrentTenantAsync();
result = _backupService.GetRestoreProgress(tenant.Id);
return result;
}
2023-03-14 20:44:44 +00:00
public async Task DemandPermissionsRestoreAsync()
{
2023-03-20 16:16:00 +00:00
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
2023-03-14 20:44:44 +00:00
2023-03-28 07:43:46 +00:00
var quota = await _tenantManager.GetTenantQuotaAsync((await _tenantManager.GetCurrentTenantAsync()).Id);
if (!SetupInfo.IsVisibleSettings("Restore") ||
2023-03-14 20:44:44 +00:00
(!_coreBaseSettings.Standalone && !quota.AutoBackupRestore))
{
throw new BillingException(Resource.ErrorNotAllowedOption, "Restore");
2022-06-14 08:11:41 +00:00
}
if (!_coreBaseSettings.Standalone
&& (!SetupInfo.IsVisibleSettings("Restore")
2023-03-14 20:44:44 +00:00
|| !quota.AutoBackupRestore))
2022-06-14 08:11:41 +00:00
{
throw new BillingException(Resource.ErrorNotAllowedOption, "Restore");
}
}
2023-03-14 20:44:44 +00:00
public async Task DemandPermissionsAutoBackupAsync()
{
2023-03-20 16:16:00 +00:00
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
if (!SetupInfo.IsVisibleSettings("AutoBackup") ||
2023-03-20 16:16:00 +00:00
(!_coreBaseSettings.Standalone && !(await _tenantManager.GetTenantQuotaAsync((await _tenantManager.GetCurrentTenantAsync()).Id)).AutoBackupRestore))
{
throw new BillingException(Resource.ErrorNotAllowedOption, "AutoBackup");
}
}
#endregion
#region transfer
2023-03-14 20:44:44 +00:00
public async Task StartTransferAsync(string targetRegion, bool notifyUsers)
{
2023-03-14 20:44:44 +00:00
await DemandPermissionsTransferAsync();
2023-03-16 15:23:59 +00:00
await _messageService.SendAsync(MessageAction.StartTransferSetting);
_backupService.StartTransfer(
new StartTransferRequest
{
2023-03-20 16:16:00 +00:00
TenantId = await GetCurrentTenantIdAsync(),
TargetRegion = targetRegion,
NotifyUsers = notifyUsers
});
2020-06-04 10:47:22 +00:00
}
2023-03-20 16:16:00 +00:00
public async Task<BackupProgress> GetTransferProgressAsync()
{
2023-03-20 16:16:00 +00:00
return _backupService.GetTransferProgress(await GetCurrentTenantIdAsync());
}
2023-03-14 20:44:44 +00:00
private async Task DemandPermissionsTransferAsync()
{
2023-03-20 16:16:00 +00:00
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
2023-03-24 07:53:49 +00:00
var currentUser = await _userManager.GetUsersAsync(_securityContext.CurrentAccount.ID);
if (!SetupInfo.IsVisibleSettings(nameof(ManagementType.Migration))
2023-03-20 16:16:00 +00:00
|| !currentUser.IsOwner(await _tenantManager.GetCurrentTenantAsync())
2023-03-14 20:44:44 +00:00
|| !SetupInfo.IsSecretEmail(currentUser.Email) && !(await _tenantManager.GetCurrentTenantQuotaAsync()).AutoBackupRestore)
2021-08-31 09:40:28 +00:00
{
throw new InvalidOperationException(Resource.ErrorNotAllowedOption);
}
}
#endregion
public string GetTmpFolder()
{
return _backupService.GetTmpFolder();
}
private static void ValidateCronSettings(CronParams cronParams)
{
new CronExpression(cronParams.ToString());
}
2023-03-20 16:16:00 +00:00
private async Task<int> GetCurrentTenantIdAsync()
{
2023-03-20 16:16:00 +00:00
return (await _tenantManager.GetCurrentTenantAsync()).Id;
}
2023-03-20 16:16:00 +00:00
public async Task<string> GetTmpFilePathAsync()
{
2023-03-24 16:24:59 +00:00
var discStore = await _storageFactory.GetStorageAsync((await _tenantManager.GetCurrentTenantAsync()).Id, BackupTempModule, (IQuotaController)null) as DiscDataStore;
2022-10-11 12:29:23 +00:00
var folder = discStore.GetPhysicalPath("", "");
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
return Path.Combine(folder, BackupFileName);
}
public class Schedule
{
public BackupStorageType StorageType { get; set; }
public Dictionary<string, string> StorageParams { get; set; }
public CronParams CronParams { 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
}
}