Skip to content

Commit

Permalink
feat: Add FeatureManagement and blob storage mime types
Browse files Browse the repository at this point in the history
  • Loading branch information
nikolaia committed May 27, 2024
1 parent 65c5e42 commit cd9b3ba
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 11 deletions.
6 changes: 6 additions & 0 deletions infrastructure/sql-webapp-access.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,10 @@ ALTER ROLE db_datareader
GO
ALTER ROLE db_datawriter
ADD MEMBER [chewie-webapp-ld2ijhpvmb34c];
GO

-- Additional permissions needed for migrations
GRANT ALTER TO [chewie-webapp-ld2ijhpvmb34c];
GRANT CREATE TABLE TO [chewie-webapp-ld2ijhpvmb34c];
GRANT REFERENCES TO [chewie-webapp-ld2ijhpvmb34c];
GO
1 change: 1 addition & 0 deletions src/Infrastructure/Infrastructure.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<PackageReference Include="Npgsql" Version="8.0.3" />
<PackageReference Include="Refit" Version="7.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
<PackageReference Include="Microsoft.FeatureManagement" Version="3.3.1" />
</ItemGroup>

<ItemGroup>
Expand Down
29 changes: 21 additions & 8 deletions src/Infrastructure/Repositories/BlobStorageRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@

using Azure.Identity;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.FeatureManagement;

using Shared;

namespace Infrastructure.Repositories;

public class BlobStorageRepository : IBlobStorageRepository
{
private readonly IFeatureManager _featureManager;
private readonly IOptionsSnapshot<AppSettings> _appSettings;
private ILogger<BlobStorageRepository> _logger;

Expand All @@ -25,8 +28,9 @@ public class BlobStorageRepository : IBlobStorageRepository
* <param name="appSettings"> Options for connection string and which container to add to </param>
* <param name="logger">ILogger interface for logging</param>
*/
public BlobStorageRepository(IOptionsSnapshot<AppSettings> appSettings, ILogger<BlobStorageRepository> logger)
public BlobStorageRepository(IFeatureManager featureManager, IOptionsSnapshot<AppSettings> appSettings, ILogger<BlobStorageRepository> logger)
{
_featureManager = featureManager;
_appSettings = appSettings;
_logger = logger;
}
Expand All @@ -44,7 +48,6 @@ public BlobStorageRepository(IOptionsSnapshot<AppSettings> appSettings, ILogger<

var blockBlobClient = container.GetBlobClient($"{cvPartnerUserId}.png");


using var client = new HttpClient();
var message = new HttpRequestMessage(HttpMethod.Get, uri);

Expand All @@ -60,11 +63,20 @@ public BlobStorageRepository(IOptionsSnapshot<AppSettings> appSettings, ILogger<
var response = await client.SendAsync(message);
if (response.StatusCode == HttpStatusCode.NotModified)
{
// No need to update the blob
_logger.LogInformation(
"No need to update the blob for {CvPartnerUserId} as the image has not changed",
cvPartnerUserId);
return blockBlobClient.Uri.AbsoluteUri;
if (await _featureManager.IsEnabledAsync("ForceImageUploadToBlobStorage"))
{
_logger.LogWarning(
"No need to update the blob for {CvPartnerUserId} as the image has not changed, but the feature flag is enabled to force the upload anyway",
cvPartnerUserId);
}
else
{
// No need to update the blob
_logger.LogInformation(
"No need to update the blob for {CvPartnerUserId} as the image has not changed",
cvPartnerUserId);
return blockBlobClient.Uri.AbsoluteUri;
}
}

if (!response.IsSuccessStatusCode)
Expand All @@ -82,7 +94,8 @@ public BlobStorageRepository(IOptionsSnapshot<AppSettings> appSettings, ILogger<
await stream.FlushAsync();
await stream.DisposeAsync();

await blockBlobClient.SetMetadataAsync(new Dictionary<string, string>()
await blockBlobClient.SetHttpHeadersAsync(new BlobHttpHeaders { ContentType = "image/png" });
await blockBlobClient.SetMetadataAsync(new Dictionary<string, string>
{
{ "name", cvPartnerUserId }, { BlobMetadataLastModifiedKey, lastModified }
});
Expand Down
1 change: 1 addition & 0 deletions src/Shared/HealthcheckResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ public record HealthcheckResponse
public bool Database { get; init; }
public bool KeyVault { get; init; }
public bool AppConfig { get; init; }
public bool FeatureManagement { get; set; }
}
10 changes: 7 additions & 3 deletions src/Web/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.FeatureManagement;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;

Expand Down Expand Up @@ -86,6 +87,8 @@
.AddJsonFile("appsettings.Local.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();

builder.Services.AddFeatureManagement();

builder.Services.AddScoped<BlobStorageService>();
builder.Services.AddScoped<IBlobStorageRepository, BlobStorageRepository>();

Expand Down Expand Up @@ -228,16 +231,17 @@

// Example of Minimal API instead of using Controllers
app.MapGet("/healthcheck",
async ([FromServices] EmployeeContext db, [FromServices] IOptionsSnapshot<AppSettings> appSettings) =>
async ([FromServices] EmployeeContext db, [FromServices] IFeatureManager featureManager, [FromServices] IOptionsSnapshot<AppSettings> appSettings) =>
{
app.Logger.LogInformation("Getting employees from database");

var dbCanConnect = await db.Database.CanConnectAsync();
var healthcheck = appSettings.Value.Healthcheck;


var featuresFromAppCfg = await featureManager.IsEnabledAsync("ReadsFeatureManagementFromAppConfig");
var response = new HealthcheckResponse
{
Database = dbCanConnect, KeyVault = healthcheck.KeyVault, AppConfig = healthcheck.AppConfig
Database = dbCanConnect, KeyVault = healthcheck.KeyVault, AppConfig = healthcheck.AppConfig, FeatureManagement = featuresFromAppCfg
};

return response;
Expand Down
1 change: 1 addition & 0 deletions src/Web/Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="8.0.5" />
<PackageReference Include="Microsoft.FeatureManagement.AspNetCore" Version="3.3.1" />
<PackageReference Include="Refit" Version="7.0.0" />
<PackageReference Include="Refit.HttpClientFactory" Version="7.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.2" />
Expand Down
4 changes: 4 additions & 0 deletions src/Web/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"FeatureManagement": {
"ReadsFeatureManagementFromAppConfig": false,
"ForceImageUploadToBlobStorage": false
},
"AppSettings": {
"AzureAppConfigUri": "https://chewie-appcfg-ld2ijhpvmb34c.azconfig.io",
"UseAzureAppConfig": true,
Expand Down
1 change: 1 addition & 0 deletions tests/ComponentTests/Tests/HealthcheckTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@ public async void HealthcheckEndpoint_Should_Return()
content?.Database.Should().Be(true);
content?.AppConfig.Should().Be(false);
content?.KeyVault.Should().Be(false);
content?.FeatureManagement.Should().Be(false);
}
}

0 comments on commit cd9b3ba

Please sign in to comment.