diff --git a/SemanticBackup.Core/Models/RSSettings.cs b/SemanticBackup.Core/Models/RSSettings.cs deleted file mode 100644 index 27bec8a..0000000 --- a/SemanticBackup.Core/Models/RSSettings.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Collections.Generic; - -namespace SemanticBackup.Core.Models -{ - public class RSDownloadLinkSetting - { - public bool IsEnabled { get; set; } = true; - public string DownloadLinkType { get; set; } - } - public class RSFTPSetting - { - public bool IsEnabled { get; set; } = false; - public string Server { get; set; } - public string Username { get; set; } - public string Password { get; set; } - public string Directory { get; set; } = "/"; - } - public class RSEmailSMTPSetting - { - public bool IsEnabled { get; set; } = false; - public bool SMTPEnableSSL { get; set; } = true; - public string SMTPHost { get; set; } - public int SMTPPort { get; set; } = 587; - public string SMTPEmailAddress { get; set; } - public string SMTPEmailCredentials { get; set; } - public string SMTPDefaultSMTPFromName { get; set; } - public string SMTPDestinations { get; set; } - public List ValidSMTPDestinations - { - get - { - List allEmails = new List(); - if (SMTPDestinations == null) - return allEmails; - string[] emailSplits = SMTPDestinations?.Split(','); - if (emailSplits.Length < 1) - return allEmails; - foreach (string email in emailSplits) - if (!string.IsNullOrEmpty(email)) - allEmails.Add(email.Replace(" ", string.Empty).Trim()); - return allEmails; - } - } - } - public class RSDropBoxSetting - { - public bool IsEnabled { get; set; } = false; - public string AccessToken { get; set; } - public string Directory { get; set; } = "/"; - } - public class RSAzureBlobStorageSetting - { - public bool IsEnabled { get; set; } = false; - public string ConnectionString { get; set; } - public string BlobContainer { get; set; } - } -} diff --git a/SemanticBackup.Core/Models/Requests/RSSettings.cs b/SemanticBackup.Core/Models/Requests/RSSettings.cs deleted file mode 100644 index 4027615..0000000 --- a/SemanticBackup.Core/Models/Requests/RSSettings.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Collections.Generic; - -namespace SemanticBackup.Core.Models.Requests -{ - public class RSDownloadLinkSetting - { - public bool IsEnabled { get; set; } = true; - public string DownloadLinkType { get; set; } - } - public class RSFTPSetting - { - public bool IsEnabled { get; set; } = false; - public string Server { get; set; } - public string Username { get; set; } - public string Password { get; set; } - public string Directory { get; set; } = "/"; - } - public class RSEmailSMTPSetting - { - public bool IsEnabled { get; set; } = false; - public bool SMTPEnableSSL { get; set; } = true; - public string SMTPHost { get; set; } - public int SMTPPort { get; set; } = 587; - public string SMTPEmailAddress { get; set; } - public string SMTPEmailCredentials { get; set; } - public string SMTPDefaultSMTPFromName { get; set; } - public string SMTPDestinations { get; set; } - public List ValidSMTPDestinations - { - get - { - List allEmails = new List(); - if (SMTPDestinations == null) - return allEmails; - string[] emailSplits = SMTPDestinations?.Split(','); - if (emailSplits.Length < 1) - return allEmails; - foreach (string email in emailSplits) - if (!string.IsNullOrEmpty(email)) - allEmails.Add(email.Replace(" ", string.Empty).Trim()); - return allEmails; - } - } - } - public class RSDropBoxSetting - { - public bool IsEnabled { get; set; } = false; - public string AccessToken { get; set; } - public string Directory { get; set; } = "/"; - } - - public class RSAzureBlobStorageSetting - { - public bool IsEnabled { get; set; } = false; - public string ConnectionString { get; set; } - public string BlobContainer { get; set; } - } - - public class RSObjectStorageSetting - { - public bool IsEnabled { get; set; } = false; - public string Server { get; set; } = "localhost"; - public int Port { get; set; } = 9000; - public string Bucket { get; set; } = "backups"; - public string AccessKey { get; set; } = string.Empty; - public string SecretKey { get; set; } = string.Empty; - public bool UseSsl { get; set; } = false; - } -} diff --git a/SemanticBackup.Core/Models/Requests/ResourceGroupRequest.cs b/SemanticBackup.Core/Models/Requests/ResourceGroupRequest.cs deleted file mode 100644 index f62d923..0000000 --- a/SemanticBackup.Core/Models/Requests/ResourceGroupRequest.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace SemanticBackup.Core.Models.Requests -{ - public class ResourceGroupRequest - { - [Required] - public string Name { get; set; } - [Range(1, 50)] - public int MaximumRunningBots { get; set; } = 1; - - [Required] - public string DbServer { get; set; } = "127.0.0.1"; - [Required] - public string DbUsername { get; set; } - public string DbPassword { get; set; } - public int DbPort { get; set; } = 0; - [Required] - public string DbType { get; set; } = DbTypes.SQLSERVER2019.ToString(); - - public bool CompressBackupFiles { get; set; } = true; - [Range(1, 366)] - public int BackupExpiryAgeInDays { get; set; } = 7; - public RSDownloadLinkSetting RSDownloadLinkSetting { get; set; } = null; - public RSFTPSetting RSFTPSetting { get; set; } = null; - public RSEmailSMTPSetting RSEmailSMTPSetting { get; set; } = null; - public RSDropBoxSetting RSDropBoxSetting { get; set; } = null; - public RSAzureBlobStorageSetting RSAzureBlobStorageSetting { get; set; } = null; - public RSObjectStorageSetting RSObjectStorageSetting { get; set; } = null; - public bool NotifyOnErrorBackups { get; set; } = false; - public bool NotifyOnErrorBackupDelivery { get; set; } = false; - public string NotifyEmailDestinations { get; set; } = null; - } -} diff --git a/SemanticBackup.Core/Models/ResourceGroup.cs b/SemanticBackup.Core/Models/ResourceGroup.cs index 5b3df1f..ef5c279 100644 --- a/SemanticBackup.Core/Models/ResourceGroup.cs +++ b/SemanticBackup.Core/Models/ResourceGroup.cs @@ -1,14 +1,13 @@ -using System; -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; namespace SemanticBackup.Core.Models { public class ResourceGroup { [Key, Required] - public string Id { get; set; } = Guid.NewGuid().ToString().ToUpper(); + public string Id { get; set; } [Required] - public string Key { get { return Name.FormatToUrlStyle(); } } + public string Key { get { return Name?.FormatToUrlStyle(); } } [Required] public string Name { get; set; } //Shared Db Connection Configs @@ -21,7 +20,7 @@ public class ResourceGroup [Required] public string DbType { get; set; } = DbTypes.SQLSERVER2019.ToString(); //Other Configs - public int MaximumRunningBots { get; set; } = 1; + public int MaximumRunningBots { get; set; } = 2; public bool CompressBackupFiles { get; set; } = true; public int BackupExpiryAgeInDays { get; set; } = 7; //delivery Configs diff --git a/SemanticBackup.Infrastructure/BackgroundJobs/BackupBackgroundJob.cs b/SemanticBackup.Infrastructure/BackgroundJobs/BackupBackgroundJob.cs index 016ae3d..215a2d2 100644 --- a/SemanticBackup.Infrastructure/BackgroundJobs/BackupBackgroundJob.cs +++ b/SemanticBackup.Infrastructure/BackgroundJobs/BackupBackgroundJob.cs @@ -97,7 +97,7 @@ private void SetupBackgroundService(CancellationToken cancellationToken) _logger.LogWarning($"Queued for Backup but was unable to update backup record Key: #{backupRecord.Id} status"); } else - _logger.LogInformation($"Resource Group With Id: {resourceGroup.Id} has Exceeded its Maximum Allocated Running Threads Count: {resourceGroup.MaximumRunningBots}"); + _logger.LogInformation($"Resource Group With Id: {resourceGroup.Id} Bots are Busy, Running Bots Count: {resourceGroup.MaximumRunningBots}, waiting for available Bots...."); } } diff --git a/SemanticBackup.Infrastructure/BackgroundJobs/BackupRecordDeliveryDispatchBackgroundJob.cs b/SemanticBackup.Infrastructure/BackgroundJobs/BackupRecordDeliveryDispatchBackgroundJob.cs index af9e659..10604f4 100644 --- a/SemanticBackup.Infrastructure/BackgroundJobs/BackupRecordDeliveryDispatchBackgroundJob.cs +++ b/SemanticBackup.Infrastructure/BackgroundJobs/BackupRecordDeliveryDispatchBackgroundJob.cs @@ -83,7 +83,7 @@ private void SetupBackgroundService(CancellationToken cancellationToken) else { //Override Maximum Running Threads// This is because of currently being used exception - if (_botsManagerBackgroundJob.HasAvailableResourceGroupBotsCount(resourceGroup.Id, 1)) + if (_botsManagerBackgroundJob.HasAvailableResourceGroupBotsCount(resourceGroup.Id, resourceGroup.MaximumRunningBots)) { string status = BackupRecordDeliveryStatus.EXECUTING.ToString(); string statusMsg = "Dispatching Backup Record"; diff --git a/SemanticBackup.Infrastructure/BackgroundJobs/BackupSchedulerBackgroundJob.cs b/SemanticBackup.Infrastructure/BackgroundJobs/BackupSchedulerBackgroundJob.cs index 17e4032..5b8a2a3 100644 --- a/SemanticBackup.Infrastructure/BackgroundJobs/BackupSchedulerBackgroundJob.cs +++ b/SemanticBackup.Infrastructure/BackgroundJobs/BackupSchedulerBackgroundJob.cs @@ -63,7 +63,7 @@ private void SetupBackgroundService(CancellationToken cancellationToken) List dueSchedules = await backupSchedulePersistanceService.GetAllDueByDateAsync(); if (dueSchedules != null && dueSchedules.Count > 0) { - List scheduleToDelete = new List(); + List scheduleToDelete = []; foreach (BackupSchedule schedule in dueSchedules.OrderBy(x => x.NextRunUTC).ToList()) { _logger.LogInformation($"Queueing Scheduled Backup..."); diff --git a/SemanticBackup.Infrastructure/Implementations/ResourceGroupRepositoryLiteDb.cs b/SemanticBackup.Infrastructure/Implementations/ResourceGroupRepositoryLiteDb.cs index 40c5c70..dca3e1d 100644 --- a/SemanticBackup.Infrastructure/Implementations/ResourceGroupRepositoryLiteDb.cs +++ b/SemanticBackup.Infrastructure/Implementations/ResourceGroupRepositoryLiteDb.cs @@ -1,5 +1,6 @@ using LiteDB; using LiteDB.Async; +using SemanticBackup.Core; using SemanticBackup.Core.Interfaces; using SemanticBackup.Core.Models; using System; @@ -25,9 +26,10 @@ public ResourceGroupRepositoryLiteDb(IBackupRecordRepository backupRecordPersist this._backupSchedulePersistanceService = backupSchedulePersistanceService; this._databaseInfoPersistanceService = databaseInfoPersistanceService; } + public async Task AddAsync(ResourceGroup record) { - record.Id = Guid.NewGuid().ToString().ToUpper(); + record.Id = record.Name.FormatToUrlStyle(); record.Name = record.Name.Trim(); //attempt to check if exists ResourceGroup preExistingRecord = await GetByIdOrKeyAsync(record.Id); diff --git a/SemanticBackup/Pages/ResourceGroups/Create.cshtml b/SemanticBackup/Pages/ResourceGroups/Create.cshtml index 45e378a..54f9e29 100644 --- a/SemanticBackup/Pages/ResourceGroups/Create.cshtml +++ b/SemanticBackup/Pages/ResourceGroups/Create.cshtml @@ -19,31 +19,22 @@ } } -
+

Backup Resource Hosting

- +
- + + + +
@@ -56,7 +47,7 @@
- @{ foreach (var dbType in Enum.GetValues(typeof(DbTypes)).Cast()) { @@ -67,22 +58,22 @@
- +
- +
- +
- +
@@ -96,13 +87,13 @@
- - + +
- - + +
@@ -122,13 +113,13 @@
- +
Download Link will Expire if the Backup Record Expires.
- @@ -139,101 +130,101 @@
- +
- +
- +
- +
- +
- - + +

*Note, if Backup compression is turned on, Email servers will not deliver compressed files, to deliver successfull, turn off Compression*

- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
@@ -241,34 +232,34 @@
- +
- +
- +
- +
- +
- +
@@ -281,21 +272,21 @@
- +
- +
- - The above Emails will receive the notifications if any execution or delivery cContent Run Fails + + The above Emails will receive the notifications if any execution or delivery Content Run Fails
diff --git a/SemanticBackup/Pages/ResourceGroups/Create.cshtml.cs b/SemanticBackup/Pages/ResourceGroups/Create.cshtml.cs index 20abb6c..4048626 100644 --- a/SemanticBackup/Pages/ResourceGroups/Create.cshtml.cs +++ b/SemanticBackup/Pages/ResourceGroups/Create.cshtml.cs @@ -5,7 +5,6 @@ using SemanticBackup.Core; using SemanticBackup.Core.Interfaces; using SemanticBackup.Core.Models; -using SemanticBackup.Core.Models.Requests; using System; using System.Threading.Tasks; @@ -22,101 +21,31 @@ public class CreateModel : PageModel public string ErrorResponse { get; set; } = null; [BindProperty] - public ResourceGroupRequest request { get; set; } + public ResourceGroup ResourceGrp { get; set; } = new ResourceGroup(); public CreateModel(ILogger logger, SystemConfigOptions options, IResourceGroupRepository resourceGroupPersistance, IBackupProviderForMySQLServer backupProviderForMySQLServer, IBackupProviderForSQLServer backupProviderForSQLServer) { - this._logger = logger; - this._persistanceOptions = options; - this._resourceGroupPersistance = resourceGroupPersistance; - this._backupProviderForMySQLServer = backupProviderForMySQLServer; - this._backupProviderForSQLServer = backupProviderForSQLServer; - } - public void OnGet() - { + _logger = logger; + _persistanceOptions = options; + _resourceGroupPersistance = resourceGroupPersistance; + _backupProviderForMySQLServer = backupProviderForMySQLServer; + _backupProviderForSQLServer = backupProviderForSQLServer; } public async Task OnPostAsync() { try { - if (request == null) + if (ResourceGrp == null) return Page(); //Validate Fields if (!IsValidationPassed()) return Page(); //Check TimeZone Provided - request.MaximumRunningBots = (request.MaximumRunningBots < 1) ? 1 : request.MaximumRunningBots; - //Proceed - ResourceGroup saveObj = new() - { - Name = request.Name, - MaximumRunningBots = request.MaximumRunningBots, - DbType = request.DbType, - DbServer = request.DbServer, - DbPort = request.DbPort, - DbPassword = request.DbPassword, - DbUsername = request.DbUsername, - CompressBackupFiles = request.CompressBackupFiles, - BackupExpiryAgeInDays = request.BackupExpiryAgeInDays, - NotifyEmailDestinations = request.NotifyEmailDestinations, - NotifyOnErrorBackupDelivery = request.NotifyOnErrorBackupDelivery, - NotifyOnErrorBackups = request.NotifyOnErrorBackups, - BackupDeliveryConfig = new BackupDeliveryConfig - { - DownloadLink = new DownloadLinkDeliveryConfig - { - IsEnabled = request.RSDownloadLinkSetting.IsEnabled, - DownloadLinkType = request.RSDownloadLinkSetting.DownloadLinkType - }, - Ftp = new FtpDeliveryConfig - { - IsEnabled = request.RSFTPSetting.IsEnabled, - Server = request.RSFTPSetting.Server, - Username = request.RSFTPSetting.Username, - Password = request.RSFTPSetting.Password, - Directory = request.RSFTPSetting.Directory - }, - Smtp = new SmtpDeliveryConfig - { - IsEnabled = request.RSEmailSMTPSetting.IsEnabled, - SMTPEnableSSL = request.RSEmailSMTPSetting.SMTPEnableSSL, - SMTPHost = request.RSEmailSMTPSetting.SMTPHost, - SMTPPort = request.RSEmailSMTPSetting.SMTPPort, - SMTPEmailAddress = request.RSEmailSMTPSetting.SMTPEmailAddress, - SMTPEmailCredentials = request.RSEmailSMTPSetting.SMTPEmailCredentials, - SMTPDefaultSMTPFromName = request.RSEmailSMTPSetting.SMTPDefaultSMTPFromName, - SMTPDestinations = request.RSEmailSMTPSetting.SMTPDestinations - }, - Dropbox = new DropboxDeliveryConfig - { - IsEnabled = request.RSDropBoxSetting.IsEnabled, - AccessToken = request.RSDropBoxSetting.AccessToken, - Directory = request.RSDropBoxSetting.Directory - }, - AzureBlobStorage = new AzureBlobStorageDeliveryConfig - { - IsEnabled = request.RSAzureBlobStorageSetting.IsEnabled, - BlobContainer = request.RSAzureBlobStorageSetting.BlobContainer, - ConnectionString = request.RSAzureBlobStorageSetting.ConnectionString - }, - ObjectStorage = new ObjectStorageDeliveryConfig - { - IsEnabled = request.RSObjectStorageSetting.IsEnabled, - Server = request.RSObjectStorageSetting.Server, - Port = request.RSObjectStorageSetting.Port, - Bucket = request.RSObjectStorageSetting.Bucket, - AccessKey = request.RSObjectStorageSetting.AccessKey, - SecretKey = request.RSObjectStorageSetting.SecretKey, - UseSsl = request.RSObjectStorageSetting.UseSsl - } - } - }; - + ResourceGrp.MaximumRunningBots = (ResourceGrp.MaximumRunningBots < 1) ? 1 : ResourceGrp.MaximumRunningBots; //atttempt check connection string - await ValidateDbConnectionAsync(saveObj); - - bool savedSuccess = await _resourceGroupPersistance.AddAsync(saveObj); + await ValidateDbConnectionAsync(ResourceGrp); + bool savedSuccess = await _resourceGroupPersistance.AddAsync(ResourceGrp); if (!savedSuccess) throw new Exception("Data was not Saved"); return Redirect("/resource-groups"); @@ -133,64 +62,67 @@ private bool IsValidationPassed() { try { - if (string.IsNullOrWhiteSpace(request.DbServer)) + if (string.IsNullOrWhiteSpace(ResourceGrp.DbServer)) { ErrorResponse = "Database Server Name was not provided"; return false; } - if (string.IsNullOrWhiteSpace(request.DbUsername)) + if (string.IsNullOrWhiteSpace(ResourceGrp.DbUsername)) { ErrorResponse = "Database Username is required"; return false; } - if (request.RSFTPSetting != null && request.RSFTPSetting.IsEnabled) - if (string.IsNullOrEmpty(request.RSFTPSetting.Password) || string.IsNullOrEmpty(request.RSFTPSetting.Username) || string.IsNullOrEmpty(request.RSFTPSetting.Server)) + //check delivery config + ResourceGrp.BackupDeliveryConfig ??= new BackupDeliveryConfig(); + + if (ResourceGrp.BackupDeliveryConfig.Ftp != null && ResourceGrp.BackupDeliveryConfig.Ftp.IsEnabled) + if (string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Ftp.Password) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Ftp.Username) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Ftp.Server)) { ErrorResponse = "Server, Username and Password Fields are required for[ FTP Content Delivery] is been Enabled"; return false; } - if (request.RSEmailSMTPSetting != null && request.RSEmailSMTPSetting.IsEnabled) - if (string.IsNullOrEmpty(request.RSEmailSMTPSetting.SMTPHost) || string.IsNullOrEmpty(request.RSEmailSMTPSetting.SMTPEmailAddress) || string.IsNullOrEmpty(request.RSEmailSMTPSetting.SMTPEmailCredentials)) + if (ResourceGrp.BackupDeliveryConfig.Smtp != null && ResourceGrp.BackupDeliveryConfig.Smtp.IsEnabled) + if (string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Smtp.SMTPHost) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Smtp.SMTPEmailAddress) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Smtp.SMTPEmailCredentials)) { ErrorResponse = "SMTP Host, SMTP Email Address and SMTP Email Credentials Fields are required If [Email SMTP Content Delivery] has been Enabled"; return false; } - else if (string.IsNullOrWhiteSpace(request.RSEmailSMTPSetting.SMTPDestinations)) + else if (string.IsNullOrWhiteSpace(ResourceGrp.BackupDeliveryConfig.Smtp.SMTPDestinations)) { ErrorResponse = "SMTP Host Destination Address have not been added, at list one destination address required If [Email SMTP Content Delivery] has been Enabled"; return false; } - if (request.RSDropBoxSetting != null && request.RSDropBoxSetting.IsEnabled) - if (string.IsNullOrEmpty(request.RSDropBoxSetting.AccessToken) || string.IsNullOrEmpty(request.RSDropBoxSetting.Directory)) + if (ResourceGrp.BackupDeliveryConfig.Dropbox != null && ResourceGrp.BackupDeliveryConfig.Dropbox.IsEnabled) + if (string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Dropbox.AccessToken) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Dropbox.Directory)) { ErrorResponse = "Dropbox API Token and Directory field are required If [Dropbox Content Delivery] has been Enabled"; return false; } else - if (request.RSDropBoxSetting.AccessToken.Length < 16) + if (ResourceGrp.BackupDeliveryConfig.Dropbox.AccessToken.Length < 16) { ErrorResponse = "Dropbox API Token provided is Invalid"; return false; } - if (request.RSAzureBlobStorageSetting != null && request.RSAzureBlobStorageSetting.IsEnabled) - if (string.IsNullOrEmpty(request.RSAzureBlobStorageSetting.ConnectionString) || string.IsNullOrEmpty(request.RSAzureBlobStorageSetting.BlobContainer)) + if (ResourceGrp.BackupDeliveryConfig.AzureBlobStorage != null && ResourceGrp.BackupDeliveryConfig.AzureBlobStorage.IsEnabled) + if (string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.AzureBlobStorage.ConnectionString) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.AzureBlobStorage.BlobContainer)) { ErrorResponse = "Azure Blob Storage Connection String and Blob Container fields are required If [Azure Blob Storage Content Delivery] has been Enabled"; return false; } - if (request.RSObjectStorageSetting != null && request.RSObjectStorageSetting.IsEnabled) - if (string.IsNullOrEmpty(request.RSObjectStorageSetting.Server) || string.IsNullOrEmpty(request.RSObjectStorageSetting.Bucket)) + if (ResourceGrp.BackupDeliveryConfig.ObjectStorage != null && ResourceGrp.BackupDeliveryConfig.ObjectStorage.IsEnabled) + if (string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.ObjectStorage.Server) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.ObjectStorage.Bucket)) { ErrorResponse = "Object Storage Server and Bucket fields are required If [Object Storage Content Delivery] has been Enabled"; return false; } //Notifications - if (request.NotifyOnErrorBackups || request.NotifyOnErrorBackupDelivery) - if (string.IsNullOrWhiteSpace(request.NotifyEmailDestinations)) + if (ResourceGrp.NotifyOnErrorBackups || ResourceGrp.NotifyOnErrorBackupDelivery) + if (string.IsNullOrWhiteSpace(ResourceGrp.NotifyEmailDestinations)) { ErrorResponse = "Notification Address must be set if [Notification of Execution Run Failure] is Enabled"; return false; @@ -205,15 +137,15 @@ private async Task ValidateDbConnectionAsync(ResourceGroup saveObj) //Finnally Validate Database Connection if (saveObj.DbType.Contains("SQLSERVER")) { - var response = await _backupProviderForSQLServer.TryTestDbConnectivityAsync(saveObj); - if (!response.success) - throw new Exception(response.err); + (bool success, string err) = await _backupProviderForSQLServer.TryTestDbConnectivityAsync(saveObj); + if (!success) + throw new Exception(err); } - else if (request.DbType.Contains("MYSQL") || request.DbType.Contains("MARIADB")) + else if (ResourceGrp.DbType.Contains("MYSQL") || ResourceGrp.DbType.Contains("MARIADB")) { - var response = await _backupProviderForMySQLServer.TryTestDbConnectivityAsync(saveObj); - if (!response.success) - throw new Exception(response.err); + (bool success, string err) = await _backupProviderForMySQLServer.TryTestDbConnectivityAsync(saveObj); + if (!success) + throw new Exception(err); } } } diff --git a/SemanticBackup/Pages/ResourceGroups/Edit.cshtml b/SemanticBackup/Pages/ResourceGroups/Edit.cshtml new file mode 100644 index 0000000..9ec52af --- /dev/null +++ b/SemanticBackup/Pages/ResourceGroups/Edit.cshtml @@ -0,0 +1,323 @@ +@page "/resource-groups/edit/{resourceGroupId}" +@model SemanticBackup.Pages.ResourceGroups.EditModel +@{ + ViewData["Title"] = string.Format("Edit Resource Group | {0}", Model.ResourceGrp.Name); + Layout = "_LayoutNoDirectory"; +} + +
+ +
+ +
+

@string.Format("Edit Resource Group | {0}", Model.ResourceGrp.Name)

+
+ @{ + if (!string.IsNullOrWhiteSpace(Model.ErrorResponse)) + { +
@(Model.ErrorResponse)
+ } + } + + +

Backup Resource Hosting

+
+
+ + +
+ +
+ + +
+
+ +
+

Database Configuration

+ +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+ + +
+

Backup Preference

+ +
+
+ + + + + +
+
+ + +
+
+ +
+

Backup Content Delivery Settings

+
+ + + + +
+ + + + +
Download Link will Expire if the Backup Record Expires.
+
+ + +
+ +
+ + +
+ + + + + +
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+ + + + +

*Note, if Backup compression is turned on, Email servers will not deliver compressed files, to deliver successfull, turn off Compression*

+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + + + + +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ + + + + +
+ + +
+ + + + + +
+ + +
+
+ + +
+
+ + +
+ + + + + +
+ + +
+
+ + +
+
+ + +
+ +
+

Notification Alerts

+
+
+ + + + + +
+
+ + + + + +
+
+ + + The above Emails will receive the notifications if any execution or delivery content Run Fails +
+ +
+ +
+

+ +

+ + +
+
+
+@section Scripts { + +} \ No newline at end of file diff --git a/SemanticBackup/Pages/ResourceGroups/Edit.cshtml.cs b/SemanticBackup/Pages/ResourceGroups/Edit.cshtml.cs new file mode 100644 index 0000000..4b9e7e8 --- /dev/null +++ b/SemanticBackup/Pages/ResourceGroups/Edit.cshtml.cs @@ -0,0 +1,172 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; +using SemanticBackup.Core; +using SemanticBackup.Core.Interfaces; +using SemanticBackup.Core.Models; +using System; +using System.Threading.Tasks; + +namespace SemanticBackup.Pages.ResourceGroups +{ + [Authorize] + public class EditModel : PageModel + { + private readonly ILogger _logger; + private readonly SystemConfigOptions _persistanceOptions; + private readonly IResourceGroupRepository _resourceGroupPersistance; + private readonly IBackupProviderForMySQLServer _backupProviderForMySQLServer; + private readonly IBackupProviderForSQLServer _backupProviderForSQLServer; + + public string ErrorResponse { get; set; } = null; + [BindProperty] + public ResourceGroup ResourceGrp { get; set; } = new ResourceGroup(); + + public EditModel(ILogger logger, SystemConfigOptions options, IResourceGroupRepository resourceGroupPersistance, IBackupProviderForMySQLServer backupProviderForMySQLServer, IBackupProviderForSQLServer backupProviderForSQLServer) + { + _logger = logger; + _persistanceOptions = options; + _resourceGroupPersistance = resourceGroupPersistance; + _backupProviderForMySQLServer = backupProviderForMySQLServer; + _backupProviderForSQLServer = backupProviderForSQLServer; + } + + public async Task OnGetAsync(string resourceGroupId) + { + try + { + ResourceGrp = await _resourceGroupPersistance.VerifyByIdOrKeyThrowIfNotExistAsync(resourceGroupId); + return Page(); + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + return Redirect("/resource-groups"); + } + } + + public async Task OnPostAsync(string resourceGroupId) + { + try + { + ResourceGroup existingResourceGrp = await _resourceGroupPersistance.VerifyByIdOrKeyThrowIfNotExistAsync(resourceGroupId); + //proceed + if (ResourceGrp == null) + return Page(); + //Validate Fields + if (!IsValidationPassed()) + return Page(); + //proceed + //proceed + ResourceGrp.MaximumRunningBots = (ResourceGrp.MaximumRunningBots < 1) ? 1 : ResourceGrp.MaximumRunningBots; + //atttempt check connection string + await ValidateDbConnectionAsync(ResourceGrp); + //update details + ResourceGrp.Id = existingResourceGrp.Id; + ResourceGrp.Name = existingResourceGrp.Name; + bool savedSuccess = await _resourceGroupPersistance.UpdateAsync(ResourceGrp); + if (!savedSuccess) + throw new Exception("Data was not Saved"); + return Redirect("/resource-groups"); + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + ErrorResponse = ex.Message; + return Page(); + } + } + + private bool IsValidationPassed() + { + try + { + if (string.IsNullOrWhiteSpace(ResourceGrp.DbServer)) + { + ErrorResponse = "Database Server Name was not provided"; + return false; + } + if (string.IsNullOrWhiteSpace(ResourceGrp.DbUsername)) + { + ErrorResponse = "Database Username is required"; + return false; + } + //check delivery config + ResourceGrp.BackupDeliveryConfig ??= new BackupDeliveryConfig(); + + if (ResourceGrp.BackupDeliveryConfig.Ftp != null && ResourceGrp.BackupDeliveryConfig.Ftp.IsEnabled) + if (string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Ftp.Password) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Ftp.Username) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Ftp.Server)) + { + ErrorResponse = "Server, Username and Password Fields are required for[ FTP Content Delivery] is been Enabled"; + return false; + } + if (ResourceGrp.BackupDeliveryConfig.Smtp != null && ResourceGrp.BackupDeliveryConfig.Smtp.IsEnabled) + if (string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Smtp.SMTPHost) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Smtp.SMTPEmailAddress) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Smtp.SMTPEmailCredentials)) + { + ErrorResponse = "SMTP Host, SMTP Email Address and SMTP Email Credentials Fields are required If [Email SMTP Content Delivery] has been Enabled"; + return false; + } + else if (string.IsNullOrWhiteSpace(ResourceGrp.BackupDeliveryConfig.Smtp.SMTPDestinations)) + { + ErrorResponse = "SMTP Host Destination Address have not been added, at list one destination address required If [Email SMTP Content Delivery] has been Enabled"; + return false; + } + + if (ResourceGrp.BackupDeliveryConfig.Dropbox != null && ResourceGrp.BackupDeliveryConfig.Dropbox.IsEnabled) + if (string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Dropbox.AccessToken) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.Dropbox.Directory)) + { + ErrorResponse = "Dropbox API Token and Directory field are required If [Dropbox Content Delivery] has been Enabled"; + return false; + } + else + if (ResourceGrp.BackupDeliveryConfig.Dropbox.AccessToken.Length < 16) + { + ErrorResponse = "Dropbox API Token provided is Invalid"; + return false; + } + + if (ResourceGrp.BackupDeliveryConfig.AzureBlobStorage != null && ResourceGrp.BackupDeliveryConfig.AzureBlobStorage.IsEnabled) + if (string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.AzureBlobStorage.ConnectionString) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.AzureBlobStorage.BlobContainer)) + { + ErrorResponse = "Azure Blob Storage Connection String and Blob Container fields are required If [Azure Blob Storage Content Delivery] has been Enabled"; + return false; + } + + if (ResourceGrp.BackupDeliveryConfig.ObjectStorage != null && ResourceGrp.BackupDeliveryConfig.ObjectStorage.IsEnabled) + if (string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.ObjectStorage.Server) || string.IsNullOrEmpty(ResourceGrp.BackupDeliveryConfig.ObjectStorage.Bucket)) + { + ErrorResponse = "Object Storage Server and Bucket fields are required If [Object Storage Content Delivery] has been Enabled"; + return false; + } + + //Notifications + if (ResourceGrp.NotifyOnErrorBackups || ResourceGrp.NotifyOnErrorBackupDelivery) + if (string.IsNullOrWhiteSpace(ResourceGrp.NotifyEmailDestinations)) + { + ErrorResponse = "Notification Address must be set if [Notification of Execution Run Failure] is Enabled"; + return false; + } + return true; + } + catch (Exception ex) { _logger.LogWarning(ex.Message); ErrorResponse = ex.Message; return false; } + + } + private async Task ValidateDbConnectionAsync(ResourceGroup saveObj) + { + //Finnally Validate Database Connection + if (saveObj.DbType.Contains("SQLSERVER")) + { + (bool success, string err) = await _backupProviderForSQLServer.TryTestDbConnectivityAsync(saveObj); + if (!success) + throw new Exception(err); + } + else if (ResourceGrp.DbType.Contains("MYSQL") || ResourceGrp.DbType.Contains("MARIADB")) + { + (bool success, string err) = await _backupProviderForMySQLServer.TryTestDbConnectivityAsync(saveObj); + if (!success) + throw new Exception(err); + } + } + } +} diff --git a/SemanticBackup/Pages/ResourceGroups/Index.cshtml b/SemanticBackup/Pages/ResourceGroups/Index.cshtml index 0e381ef..c1aff2b 100644 --- a/SemanticBackup/Pages/ResourceGroups/Index.cshtml +++ b/SemanticBackup/Pages/ResourceGroups/Index.cshtml @@ -30,27 +30,27 @@
@foreach (var resourceGrp in Model.ResourceGroups) - { -
-
- -
- @(resourceGrp.Name) -
-
-
- Max Bots: @string.Format("{0:N0} concurrent", resourceGrp.MaximumRunningBots)
- Compression: @string.Format("{0}", resourceGrp.CompressBackupFiles ? "ZIP" : "(none)") -
+ { +
+
+ +
+ @(resourceGrp.Name)
-
-
- Manage - Delete -
+
+
+ Max Bots: @string.Format("{0:N0} concurrent", resourceGrp.MaximumRunningBots)
+ Compression: @string.Format("{0}", resourceGrp.CompressBackupFiles ? "ZIP" : "(none)")
- } +
+
+ Manage + Edit +
+
+
+ }
} diff --git a/SemanticBackup/SemanticBackup.csproj b/SemanticBackup/SemanticBackup.csproj index bf66518..74d062b 100644 --- a/SemanticBackup/SemanticBackup.csproj +++ b/SemanticBackup/SemanticBackup.csproj @@ -4,8 +4,8 @@ net8.0 98e83838-8ab0-44d3-a023-52d80ba01705 Linux - 5.1.5 - 5.1.5 + 5.1.6 + 5.1.6