diff --git a/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/AbpBunnyBlobStoringModule .cs b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/AbpBunnyBlobStoringModule .cs index 49e97e861b..3fe814f2f0 100644 --- a/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/AbpBunnyBlobStoringModule .cs +++ b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/AbpBunnyBlobStoringModule .cs @@ -1,12 +1,11 @@ -using System; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Caching; using Volo.Abp.Modularity; namespace Volo.Abp.BlobStoring.Bunny; [DependsOn( - typeof(AbpBlobStoringModule), + typeof(AbpBlobStoringModule), typeof(AbpCachingModule))] public class AbpBlobStoringBunnyModule : AbpModule { @@ -14,4 +13,4 @@ public class AbpBlobStoringBunnyModule : AbpModule { context.Services.AddHttpClient(); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyApiException.cs b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyApiException.cs new file mode 100644 index 0000000000..1e10d4caa2 --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyApiException.cs @@ -0,0 +1,18 @@ +using System; + +namespace Volo.Abp.BlobStoring.Bunny; + +public class BunnyApiException : Exception +{ + public BunnyApiException(string message) + : base(message) + { + + } + + public BunnyApiException(string message, Exception innerException) + : base(message, innerException) + { + + } +} diff --git a/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyBlobNamingNormalizer.cs b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyBlobNamingNormalizer.cs index b478bac23e..74c436e2e9 100644 --- a/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyBlobNamingNormalizer.cs +++ b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyBlobNamingNormalizer.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.BlobStoring.Bunny; public class BunnyBlobNamingNormalizer : IBlobNamingNormalizer, ITransientDependency { - private static readonly Regex ValidCharactersRegex = + private readonly static Regex ValidCharactersRegex = new Regex(@"^[a-z0-9-]*$", RegexOptions.Compiled); private const int MinLength = 4; diff --git a/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyBlobProvider.cs b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyBlobProvider.cs index b154ab2160..6c06bc3f95 100644 --- a/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyBlobProvider.cs +++ b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyBlobProvider.cs @@ -24,7 +24,7 @@ public class BunnyBlobProvider : BlobProviderBase, ITransientDependency BunnyClientFactory = bunnyClientFactory; } - public override async Task SaveAsync(BlobProviderSaveArgs args) + public async override Task SaveAsync(BlobProviderSaveArgs args) { var configuration = args.Configuration.GetBunnyConfiguration(); var containerName = GetContainerName(args); @@ -48,7 +48,7 @@ public class BunnyBlobProvider : BlobProviderBase, ITransientDependency await bunnyStorage.UploadAsync(memoryStream, $"{containerName}/{blobName}"); } - public override async Task DeleteAsync(BlobProviderDeleteArgs args) + public async override Task DeleteAsync(BlobProviderDeleteArgs args) { var blobName = BunnyBlobNameCalculator.Calculate(args); var containerName = GetContainerName(args); @@ -69,7 +69,7 @@ public class BunnyBlobProvider : BlobProviderBase, ITransientDependency } } - public override async Task ExistsAsync(BlobProviderExistsArgs args) + public async override Task ExistsAsync(BlobProviderExistsArgs args) { var blobName = BunnyBlobNameCalculator.Calculate(args); var containerName = GetContainerName(args); @@ -78,7 +78,7 @@ public class BunnyBlobProvider : BlobProviderBase, ITransientDependency return await BlobExistsAsync(bunnyStorage, containerName, blobName); } - public override async Task GetOrNullAsync(BlobProviderGetArgs args) + public async override Task GetOrNullAsync(BlobProviderGetArgs args) { var blobName = BunnyBlobNameCalculator.Calculate(args); var containerName = GetContainerName(args); diff --git a/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyStorageZoneModel.cs b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyStorageZoneModel.cs new file mode 100644 index 0000000000..e718531927 --- /dev/null +++ b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/BunnyStorageZoneModel.cs @@ -0,0 +1,17 @@ +using System; + +namespace Volo.Abp.BlobStoring.Bunny; + +[Serializable] +public class BunnyStorageZoneModel +{ + public int Id { get; set; } + + public string Password { get; set; } = null!; + + public string Name { get; set; } = null!; + + public string? Region { get; set; } + + public bool Deleted { get; set; } +} diff --git a/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/DefaultBunnyClientFactory.cs b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/DefaultBunnyClientFactory.cs index ae60a25e01..d22cff0e0a 100644 --- a/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/DefaultBunnyClientFactory.cs +++ b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/DefaultBunnyClientFactory.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Text; using System.Text.Json; @@ -14,16 +15,16 @@ namespace Volo.Abp.BlobStoring.Bunny; public class DefaultBunnyClientFactory : IBunnyClientFactory, ITransientDependency { - private readonly IDistributedCache _cache; + private readonly IDistributedCache _cache; private readonly IHttpClientFactory _httpClientFactory; private readonly IStringEncryptionService _stringEncryptionService; private const string CacheKeyPrefix = "BunnyStorageZone:"; - private static TimeSpan CacheDuration = TimeSpan.FromHours(12); + private readonly static TimeSpan CacheDuration = TimeSpan.FromHours(12); public DefaultBunnyClientFactory( IHttpClientFactory httpClient, - IDistributedCache cache, + IDistributedCache cache, IStringEncryptionService stringEncryptionService) { _cache = cache; @@ -89,76 +90,63 @@ public class DefaultBunnyClientFactory : IBunnyClientFactory, ITransientDependen } } - protected virtual async Task CreateStorageZoneAsync( + protected virtual async Task CreateStorageZoneAsync( string accessKey, string containerName, string region) { - using var _client = _httpClientFactory.CreateClient("BunnyApiClient"); - _client.DefaultRequestHeaders.Add("AccessKey", accessKey); - - var payload = new Dictionary + using (var client = _httpClientFactory.CreateClient("BunnyApiClient")) { - { "Name", containerName }, - { "Region", region }, - { "ZoneTier", 0 } - }; + client.DefaultRequestHeaders.Add("AccessKey", accessKey); - var content = new StringContent( - JsonSerializer.Serialize(payload), - Encoding.UTF8, - "application/json"); + var payload = new Dictionary + { + { "Name", containerName }, + { "Region", region }, + { "ZoneTier", 0 } + }; - var response = await _client.PostAsync( - "https://api.bunny.net/storagezone", - content); + var content = new StringContent( + JsonSerializer.Serialize(payload), + Encoding.UTF8, + "application/json"); - if (!response.IsSuccessStatusCode) - { - var errorContent = await response.Content.ReadAsStringAsync(); - throw new AbpException( - $"Failed to create storage zone '{containerName}'. " + - $"Status: {response.StatusCode}, Error: {errorContent}"); - } + var response = await client.PostAsync( + "https://api.bunny.net/storagezone", + content); + + if (!response.IsSuccessStatusCode) + { + var errorContent = await response.Content.ReadAsStringAsync(); + throw new AbpException( + $"Failed to create storage zone '{containerName}'. " + + $"Status: {response.StatusCode}, Error: {errorContent}"); + } - var responseContent = await response.Content.ReadAsStringAsync(); - var createdZone = JsonSerializer.Deserialize(responseContent); + var responseContent = await response.Content.ReadAsStringAsync(); + var createdZone = JsonSerializer.Deserialize(responseContent); - if (createdZone == null) - { - throw new AbpException( - $"Failed to deserialize the created storage zone response for '{containerName}'"); - } + if (createdZone == null) + { + throw new AbpException($"Failed to deserialize the created storage zone response for '{containerName}'"); + } - return createdZone; + return createdZone; + } } - protected virtual async Task GetStorageZoneAsync(string accessKey, string containerName) + protected virtual async Task GetStorageZoneAsync(string accessKey, string containerName) { - using var _client = _httpClientFactory.CreateClient("BunnyApiClient"); - _client.DefaultRequestHeaders.Add("AccessKey", accessKey); - var response = await _client.GetAsync("https://api.bunny.net/storagezone"); - response.EnsureSuccessStatusCode(); - - var content = await response.Content.ReadAsStringAsync(); - var zones = JsonSerializer.Deserialize(content); + using (var client = _httpClientFactory.CreateClient("BunnyApiClient")) + { + client.DefaultRequestHeaders.Add("AccessKey", accessKey); + var response = await client.GetAsync("https://api.bunny.net/storagezone"); + response.EnsureSuccessStatusCode(); - return Array.Find(zones!, z => - z.Name.Equals(containerName, StringComparison.OrdinalIgnoreCase) && !z.Deleted); - } + var content = await response.Content.ReadAsStringAsync(); + var zones = JsonSerializer.Deserialize(content); - [Serializable] - public class StorageZone - { - public int Id { get; set; } - public string Password { get; set; } = null!; - public string Name { get; set; } = null!; - public string? Region { get; set; } - public bool Deleted { get; set; } + return zones?.FirstOrDefault(x => x.Name.Equals(containerName, StringComparison.OrdinalIgnoreCase) && !x.Deleted); + } } } -public class BunnyApiException : Exception -{ - public BunnyApiException(string message) : base(message) { } - public BunnyApiException(string message, Exception innerException) : base(message, innerException) { } -} diff --git a/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/IBunnyClientFactory.cs b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/IBunnyClientFactory.cs index dce2c5b6f0..7e5db5ed41 100644 --- a/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/IBunnyClientFactory.cs +++ b/framework/src/Volo.Abp.BlobStoring.Bunny/Volo/Abp/BlobStoring/Bunny/IBunnyClientFactory.cs @@ -6,5 +6,6 @@ namespace Volo.Abp.BlobStoring.Bunny; public interface IBunnyClientFactory { Task CreateAsync(string accessKey, string containerName, string region = "de"); + Task EnsureStorageZoneExistsAsync(string accessKey, string containerName, string region = "de", bool createIfNotExists = false); } diff --git a/framework/test/Volo.Abp.BlobStoring.Bunny.Tests/Volo/Abp/BlobStoring/Bunny/BunnyBlobContainer_Tests.cs b/framework/test/Volo.Abp.BlobStoring.Bunny.Tests/Volo/Abp/BlobStoring/Bunny/BunnyBlobContainer_Tests.cs index 3d4592cc97..84b255e4c5 100644 --- a/framework/test/Volo.Abp.BlobStoring.Bunny.Tests/Volo/Abp/BlobStoring/Bunny/BunnyBlobContainer_Tests.cs +++ b/framework/test/Volo.Abp.BlobStoring.Bunny.Tests/Volo/Abp/BlobStoring/Bunny/BunnyBlobContainer_Tests.cs @@ -1 +1,12 @@ namespace Volo.Abp.BlobStoring.Bunny; + +/* +//Please set the correct connection string in secrets.json and continue the test. +public class BunnyBlobContainer_Tests : BlobContainer_Tests +{ + public BunnyBlobContainer_Tests() + { + + } +} +*/ diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index 4233ce7b59..e60f374566 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -155,6 +155,7 @@ $projects = ( "framework/src/Volo.Abp.BlobStoring.Minio", "framework/src/Volo.Abp.BlobStoring.Aws", "framework/src/Volo.Abp.BlobStoring.Google", + "framework/src/Volo.Abp.BlobStoring.Bunny", "framework/src/Volo.Abp.Caching", "framework/src/Volo.Abp.Caching.StackExchangeRedis", "framework/src/Volo.Abp.Castle.Core",