chore(backend): add explicit test data seed command
All checks were successful
deploy-socialize / image (push) Successful in 53s
deploy-socialize / deploy (push) Successful in 21s

This commit is contained in:
2026-05-07 13:43:53 -04:00
parent 918136aae2
commit 6e417312f9
9 changed files with 74 additions and 47 deletions

View File

@@ -1,8 +0,0 @@
namespace Socialize.Api.Infrastructure.Development;
public record DevelopmentSeedOptions
{
public const string SectionName = "DevelopmentSeed";
public bool Enabled { get; init; } = true;
}

View File

@@ -16,11 +16,10 @@ using Socialize.Api.Modules.Organizations.Data;
using Socialize.Api.Modules.Organizations.Services;
using Socialize.Api.Modules.Workspaces.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
namespace Socialize.Api.Infrastructure.Development;
namespace Socialize.Api.Infrastructure.TestData;
public static class DevelopmentSeedExtensions
public static class TestDataSeedExtensions
{
private static readonly Guid OrganizationId = Guid.Parse("99999999-9999-9999-9999-999999999999");
private static readonly Guid WorkspaceId = Guid.Parse("11111111-1111-1111-1111-111111111111");
@@ -39,23 +38,11 @@ public static class DevelopmentSeedExtensions
private static readonly Guid ClientCommentId = Guid.Parse("77777777-7777-7777-7777-777777777777");
private static readonly Guid NotificationId = Guid.Parse("88888888-8888-8888-8888-888888888888");
public static async Task<IApplicationBuilder> UseDevelopmentSeedAsync(
this IApplicationBuilder app,
public static async Task<IServiceProvider> SeedTestDataAsync(
this IServiceProvider services,
CancellationToken cancellationToken = default)
{
IHostEnvironment environment = app.ApplicationServices.GetRequiredService<IHostEnvironment>();
if (!environment.IsDevelopment())
{
return app;
}
using IServiceScope scope = app.ApplicationServices.CreateScope();
IOptions<DevelopmentSeedOptions> options = scope.ServiceProvider.GetRequiredService<IOptions<DevelopmentSeedOptions>>();
if (!options.Value.Enabled)
{
return app;
}
using IServiceScope scope = services.CreateScope();
UserManager userManager = scope.ServiceProvider.GetRequiredService<UserManager>();
AppDbContext dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
@@ -64,7 +51,7 @@ public static class DevelopmentSeedExtensions
id: Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"),
username: "manager",
email: "manager@socialize.local",
password: "manager",
password: "Manager1!",
alias: "Northstar Manager",
firstname: "Morgan",
lastname: "Reid",
@@ -80,7 +67,7 @@ public static class DevelopmentSeedExtensions
id: Guid.Parse("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"),
username: "client",
email: "client@socialize.local",
password: "client",
password: "Client1!",
alias: "Sofia Martin",
firstname: "Sofia",
lastname: "Martin",
@@ -97,7 +84,7 @@ public static class DevelopmentSeedExtensions
id: Guid.Parse("cccccccc-cccc-cccc-cccc-cccccccccccc"),
username: "provider",
email: "provider@socialize.local",
password: "provider",
password: "Provider1!",
alias: "Alex Studio",
firstname: "Alex",
lastname: "Studio",
@@ -115,7 +102,7 @@ public static class DevelopmentSeedExtensions
id: Guid.Parse("dddddddd-dddd-dddd-dddd-dddddddddddd"),
username: "dev",
email: "dev@socialize.local",
password: "dev",
password: "Developer1!",
alias: "Socialize Dev",
firstname: "Jo",
lastname: "Bumble",
@@ -138,7 +125,7 @@ public static class DevelopmentSeedExtensions
dbContext,
cancellationToken);
return app;
return services;
}
private static async Task<User> EnsureUserAsync(
@@ -175,7 +162,7 @@ public static class DevelopmentSeedExtensions
if (!createResult.Succeeded)
{
throw new InvalidOperationException(
$"Failed to seed development user '{username}': {string.Join(", ", createResult.Errors.Select(error => error.Description))}");
$"Failed to seed test user '{username}': {string.Join(", ", createResult.Errors.Select(error => error.Description))}");
}
}
@@ -195,7 +182,7 @@ public static class DevelopmentSeedExtensions
if (!passwordResetResult.Succeeded)
{
throw new InvalidOperationException(
$"Failed to set development password for '{username}': {string.Join(", ", passwordResetResult.Errors.Select(error => error.Description))}");
$"Failed to set test password for '{username}': {string.Join(", ", passwordResetResult.Errors.Select(error => error.Description))}");
}
}

View File

@@ -1,5 +1,4 @@
using Socialize.Api.Modules.Workspaces.Data;
using Socialize.Api.Infrastructure.Development;
namespace Socialize.Api.Modules.Workspaces;
@@ -8,9 +7,6 @@ public static class DependencyInjection
public static WebApplicationBuilder AddWorkspaceModule(
this WebApplicationBuilder builder)
{
builder.Services.Configure<DevelopmentSeedOptions>(
builder.Configuration.GetSection(DevelopmentSeedOptions.SectionName));
return builder;
}
}

View File

@@ -6,7 +6,7 @@ using Socialize;
using Socialize.Api.Infrastructure.BlobStorage.Configuration;
using Socialize.Api.Infrastructure.BlobStorage.Services;
using Socialize.Api.Infrastructure;
using Socialize.Api.Infrastructure.Development;
using Socialize.Api.Infrastructure.TestData;
using Socialize.Api.Modules.Approvals;
using Socialize.Api.Modules.Assets;
using Socialize.Api.Modules.Channels;
@@ -23,6 +23,7 @@ using Socialize.Api.Modules.Workspaces;
var builder = WebApplication.CreateBuilder(args);
bool seedTestData = args.Any(arg => string.Equals(arg, "seed-testdata", StringComparison.OrdinalIgnoreCase));
string? vaultUri = Environment.GetEnvironmentVariable("VaultUri");
if (!string.IsNullOrWhiteSpace(vaultUri))
@@ -78,6 +79,25 @@ builder.AddCalendarIntegrationsModule();
var app = builder.Build();
if (seedTestData)
{
if (app.Environment.IsProduction()
&& !string.Equals(
Environment.GetEnvironmentVariable("CONFIRM_PRODUCTION_SEED"),
"true",
StringComparison.Ordinal))
{
throw new InvalidOperationException(
"Refusing to seed test data in Production without CONFIRM_PRODUCTION_SEED=true.");
}
await app.UseAppDataAsync();
await app.UseIdentityModuleAsync();
await app.Services.SeedTestDataAsync();
Console.WriteLine("Seeded test data.");
return;
}
app.UseForwardedHeaders(
new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedProto }
);
@@ -90,7 +110,6 @@ app.UseAuthorization();
// Initialize and seed the db.
await app.UseAppDataAsync();
await app.UseIdentityModuleAsync();
await app.UseDevelopmentSeedAsync();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())

View File

@@ -22,8 +22,5 @@
"Lifetime": "00:05:00",
"RefreshTokenLifetime": "0.00:30:00"
}
},
"DevelopmentSeed": {
"Enabled": true
}
}

View File

@@ -5,8 +5,5 @@
"LocalBlobStorage": {
"RootPath": "App_Data/blob-storage",
"RequestPath": "/api/storage"
},
"DevelopmentSeed": {
"Enabled": false
}
}