using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Application.Helpers; using Domain.Entities.Developers; using SharedKernel.Results; namespace Application.Features.Api.Developers.Apps.CreateApp; internal sealed class Handler(IAppDbContext db) : ICommandHandler> { public async Task> Handle(Command request, CancellationToken ct) { if (string.IsNullOrWhiteSpace(request.Name) || request.Name.Length > 100) { return Result.Failure(Error.Problem("App.NameInvalid", "Name is required (1-100 chars).")); } var app = ApiApplication.Create(request.OwnerMemberID, request.Name, request.Description, request.HomepageUrl); app.Approve(); var clientID = ApiTokenGenerator.GenerateClientID(); var secret = ApiTokenGenerator.GenerateClientSecret(); await db.ApiApplication.AddAsync(app, ct); await db.SaveChangesAsync(ct); var credential = ApiCredential.Create(app.ID, clientID, ApiTokenGenerator.Hash(secret), ApiTokenGenerator.Hint(secret)); await db.ApiCredential.AddAsync(credential, ct); foreach (var scope in request.Scopes ?? []) { if (string.IsNullOrWhiteSpace(scope)) { continue; } await db.ApiApplicationScope.AddAsync(ApiApplicationScope.Create(app.ID, scope.Trim()), ct); } await db.SaveChangesAsync(ct); return Result.Success(new Response(app.ID, clientID, secret)); } }