DocSpace-client/common/ASC.Data.Backup.Core/BackupAjaxHandler.cs
2022-06-14 11:11:41 +03:00

460 lines
15 KiB
C#

// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Data.Backup;
[Scope]
public class BackupAjaxHandler
{
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 TenantExtra _tenantExtra;
private readonly ConsumerFactory _consumerFactory;
private readonly BackupService _backupService;
private readonly TempPath _tempPath;
private const string BackupTempFolder = "backup";
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,
TenantExtra tenantExtra,
ConsumerFactory consumerFactory,
TempPath tempPath)
{
_tenantManager = tenantManager;
_messageService = messageService;
_coreBaseSettings = coreBaseSettings;
_coreConfiguration = coreConfiguration;
_permissionContext = permissionContext;
_securityContext = securityContext;
_userManager = userManager;
_tenantExtra = tenantExtra;
_consumerFactory = consumerFactory;
_backupService = backupService;
_tempPath = tempPath;
}
public void StartBackup(BackupStorageType storageType, Dictionary<string, string> storageParams, bool backupMail)
{
DemandPermissionsBackup();
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 BackupProgress GetBackupProgress(int tenantId)
{
DemandPermissionsBackup();
return _backupService.GetBackupProgress(tenantId);
}
public void DeleteBackup(Guid id)
{
DemandPermissionsBackup();
_backupService.DeleteBackup(id);
}
public void DeleteAllBackups()
{
DemandPermissionsBackup();
_backupService.DeleteAllBackups(GetCurrentTenantId());
}
public List<BackupHistoryRecord> GetBackupHistory()
{
DemandPermissionsBackup();
return _backupService.GetBackupHistory(GetCurrentTenantId());
}
public void CreateSchedule(BackupStorageType storageType, Dictionary<string, string> storageParams, int backupsStored, CronParams cronParams, bool backupMail)
{
DemandPermissionsBackup();
if (!SetupInfo.IsVisibleSettings("AutoBackup"))
{
throw new InvalidOperationException(Resource.ErrorNotAllowedOption);
}
ValidateCronSettings(cronParams);
var scheduleRequest = new CreateScheduleRequest
{
TenantId = _tenantManager.GetCurrentTenant().Id,
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<string, string>(),
CronParams = new CronParams(response.Cron),
BackupMail = response.BackupMail.NullIfDefault(),
BackupsStored = response.NumberOfBackupsStored.NullIfDefault(),
LastBackupTime = response.LastBackupTime
};
if (response.StorageType == BackupStorageType.CustomCloud)
{
var amazonSettings = _coreConfiguration.GetSection<AmazonS3Settings>();
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
{
TenantId = _tenantManager.GetCurrentTenant().Id,
BackupMail = schedule.BackupMail != null && (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 (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 (!_coreBaseSettings.Standalone && !SetupInfo.IsVisibleSettings(nameof(ManagementType.Backup)))
{
throw new BillingException(Resource.ErrorNotAllowedOption, "Backup");
}
}
#endregion
#region restore
public void StartRestore(string backupId, BackupStorageType storageType, Dictionary<string, string> 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"];
if (restoreRequest.StorageType == BackupStorageType.Local && !_coreBaseSettings.Standalone)
{
restoreRequest.FilePathOrId = GetTmpFilePath();
}
}
_backupService.StartRestore(restoreRequest);
}
public BackupProgress GetRestoreProgress()
{
BackupProgress result;
var tenant = _tenantManager.GetCurrentTenant();
result = _backupService.GetRestoreProgress(tenant.Id);
return result;
}
public void DemandPermissionsRestore()
{
_permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
if (!SetupInfo.IsVisibleSettings("Restore") ||
(!_coreBaseSettings.Standalone && !_tenantManager.GetTenantQuota(_tenantManager.GetCurrentTenant().Id).Restore))
{
throw new BillingException(Resource.ErrorNotAllowedOption, "Restore");
}
if (!_coreBaseSettings.Standalone
&& (!SetupInfo.IsVisibleSettings("Restore")
|| !_tenantManager.GetTenantQuota(_tenantManager.GetCurrentTenant().Id).Restore))
{
throw new BillingException(Resource.ErrorNotAllowedOption, "Restore");
}
}
public void DemandPermissionsAutoBackup()
{
_permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
if (!SetupInfo.IsVisibleSettings("AutoBackup") ||
(!_coreBaseSettings.Standalone && !_tenantManager.GetTenantQuota(_tenantManager.GetCurrentTenant().Id).AutoBackup))
{
throw new BillingException(Resource.ErrorNotAllowedOption, "AutoBackup");
}
}
#endregion
#region transfer
public void StartTransfer(string targetRegion, bool notifyUsers, bool transferMail)
{
DemandPermissionsTransfer();
_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(nameof(ManagementType.Migration))
|| !currentUser.IsOwner(_tenantManager.GetCurrentTenant())
|| !SetupInfo.IsSecretEmail(currentUser.Email) && !_tenantExtra.GetTenantQuota().HasMigration)
{
throw new InvalidOperationException(Resource.ErrorNotAllowedOption);
}
}
#endregion
public string GetTmpFolder()
{
return _backupService.GetTmpFolder();
}
private static void ValidateCronSettings(CronParams cronParams)
{
new CronExpression(cronParams.ToString());
}
private int GetCurrentTenantId()
{
return _tenantManager.GetCurrentTenant().Id;
}
public string GetTmpFilePath()
{
var folder = Path.Combine(_tempPath.GetTempPath(), BackupTempFolder, _tenantManager.GetCurrentTenant().Id.ToString());
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 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
}
}