From 707ea7c9fd42cc24efe43d97734ccbc70c44d1f3 Mon Sep 17 00:00:00 2001 From: "George Njeri (Swagfin)" Date: Sat, 2 Aug 2025 22:49:40 +0300 Subject: [PATCH] chore: in-depth delete of version object storage --- .../Bots/InDepthDeleteObjectStorageBot.cs | 43 ++++++++++++++++++- SemanticBackup/Pages/Index.cshtml.cs | 3 +- .../DatabaseBackups/Details.cshtml.cs | 4 +- SemanticBackup/SemanticBackup.csproj | 4 +- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/SemanticBackup.Infrastructure/BackgroundJobs/Bots/InDepthDeleteObjectStorageBot.cs b/SemanticBackup.Infrastructure/BackgroundJobs/Bots/InDepthDeleteObjectStorageBot.cs index 1e69abd..2a7fde1 100644 --- a/SemanticBackup.Infrastructure/BackgroundJobs/Bots/InDepthDeleteObjectStorageBot.cs +++ b/SemanticBackup.Infrastructure/BackgroundJobs/Bots/InDepthDeleteObjectStorageBot.cs @@ -3,6 +3,7 @@ using SemanticBackup.Core.Helpers; using SemanticBackup.Core.Models; using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Threading; @@ -46,8 +47,48 @@ await WithRetry.TaskAsync(async () => //Filename string fileName = Path.GetFileName(this._backupRecord.Path); //Proceed - using IMinioClient minioClient = new MinioClient().WithEndpoint(settings.Server, settings.Port).WithCredentials(settings.AccessKey, settings.SecretKey).WithSSL(settings.UseSsl).Build(); + using IMinioClient minioClient = new MinioClient() + .WithEndpoint(settings.Server, settings.Port) + .WithCredentials(settings.AccessKey, settings.SecretKey) + .WithSSL(settings.UseSsl) + .Build(); + //deleting recursive + List objectVersions = []; + // Attempt to list object versions + ListObjectsArgs listArgs = new ListObjectsArgs() + .WithBucket(validBucket) + .WithPrefix(fileName) + .WithRecursive(true) + .WithVersions(true); + + await foreach (Minio.DataModel.Item version in minioClient.ListObjectsEnumAsync(listArgs)) { + if (version.Key == fileName && !string.IsNullOrEmpty(version.VersionId)) + { + objectVersions.Add(version); + } + } + + if (objectVersions.Count > 0) + { + // Bucket is versioned: delete all versions + Console.WriteLine($"Found {objectVersions.Count} versions. Deleting all..."); + + foreach (Minio.DataModel.Item version in objectVersions) + { + await minioClient.RemoveObjectAsync(new RemoveObjectArgs() + .WithBucket(validBucket) + .WithObject(fileName) + .WithVersionId(version.VersionId), cancellationToken); + + Console.WriteLine($"Deleted version {version.VersionId}"); + } + } + else + { + // Bucket is non-versioned or no versions found: delete normally + Console.WriteLine("No versions found. Deleting object directly..."); + await minioClient.RemoveObjectAsync(new RemoveObjectArgs() .WithBucket(validBucket) .WithObject(fileName), cancellationToken); diff --git a/SemanticBackup/Pages/Index.cshtml.cs b/SemanticBackup/Pages/Index.cshtml.cs index 5ec5ccf..7839242 100644 --- a/SemanticBackup/Pages/Index.cshtml.cs +++ b/SemanticBackup/Pages/Index.cshtml.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Logging; using SemanticBackup.Core.Interfaces; -using System.Threading.Tasks; namespace SemanticBackup.Pages { @@ -18,7 +17,7 @@ public IndexModel(ILogger logger, IResourceGroupRepository resourceG this._resourceGroupPersistance = resourceGroupPersistance; } - public async Task OnGetAsync() + public IActionResult OnGetAsync() { return LocalRedirect($"/resource-groups/"); } diff --git a/SemanticBackup/Pages/ResourceGroups/DatabaseBackups/Details.cshtml.cs b/SemanticBackup/Pages/ResourceGroups/DatabaseBackups/Details.cshtml.cs index 8fd8ee8..1977111 100644 --- a/SemanticBackup/Pages/ResourceGroups/DatabaseBackups/Details.cshtml.cs +++ b/SemanticBackup/Pages/ResourceGroups/DatabaseBackups/Details.cshtml.cs @@ -148,12 +148,12 @@ private async Task DownloadableContentAsync(BackupRecordDelivery new FileExtensionContentTypeProvider().TryGetContentType(BackupRecordResponse.Path, out string contentType); contentType = contentType ?? "application/octet-stream"; string fileName = System.IO.Path.GetFileName(BackupRecordResponse.Path); - var cd = new System.Net.Mime.ContentDisposition + System.Net.Mime.ContentDisposition cd = new() { FileName = fileName, Inline = true, }; - Response.Headers.Add("Content-Disposition", cd.ToString()); + Response.Headers.TryAdd("Content-Disposition", cd.ToString()); byte[] filedata = await System.IO.File.ReadAllBytesAsync(BackupRecordResponse.Path); return File(filedata, contentType); } diff --git a/SemanticBackup/SemanticBackup.csproj b/SemanticBackup/SemanticBackup.csproj index 598fe65..c84d948 100644 --- a/SemanticBackup/SemanticBackup.csproj +++ b/SemanticBackup/SemanticBackup.csproj @@ -4,8 +4,8 @@ net8.0 98e83838-8ab0-44d3-a023-52d80ba01705 Linux - 5.2.1.3 - 5.2.1.3 + 5.2.1.4 + 5.2.1.4