116 lines
4.1 KiB
C#
116 lines
4.1 KiB
C#
using FastEndpoints;
|
|
using Socialize.Api.Data;
|
|
using Socialize.Api.Infrastructure.Security;
|
|
using Socialize.Api.Modules.Identity.Contracts;
|
|
using Socialize.Api.Modules.ReleaseCommunications.Contracts;
|
|
using Socialize.Api.Modules.ReleaseCommunications.Data;
|
|
using Socialize.Api.Modules.ReleaseCommunications.Services;
|
|
|
|
namespace Socialize.Api.Modules.ReleaseCommunications.Handlers;
|
|
|
|
internal record CreateDeveloperReleaseUpdateRequest(
|
|
string Title,
|
|
string Summary,
|
|
string? Body,
|
|
string Category,
|
|
string Importance,
|
|
string Audience,
|
|
string? DeploymentLabel,
|
|
string? BuildVersion,
|
|
string? CommitRange);
|
|
|
|
internal class CreateDeveloperReleaseUpdateRequestValidator
|
|
: Validator<CreateDeveloperReleaseUpdateRequest>
|
|
{
|
|
public CreateDeveloperReleaseUpdateRequestValidator()
|
|
{
|
|
RuleFor(x => x.Title).NotEmpty().MaximumLength(160);
|
|
RuleFor(x => x.Summary).NotEmpty().MaximumLength(512);
|
|
RuleFor(x => x.Body).MaximumLength(8000);
|
|
RuleFor(x => x.Category).NotEmpty().MaximumLength(32);
|
|
RuleFor(x => x.Importance).NotEmpty().MaximumLength(32);
|
|
RuleFor(x => x.Audience).NotEmpty().MaximumLength(32);
|
|
RuleFor(x => x.DeploymentLabel).MaximumLength(128);
|
|
RuleFor(x => x.BuildVersion).MaximumLength(128);
|
|
RuleFor(x => x.CommitRange).MaximumLength(256);
|
|
}
|
|
}
|
|
|
|
internal class CreateDeveloperReleaseUpdateHandler(AppDbContext dbContext)
|
|
: Endpoint<CreateDeveloperReleaseUpdateRequest, ReleaseUpdateDto>
|
|
{
|
|
public override void Configure()
|
|
{
|
|
Post("/api/developer/release-updates");
|
|
Roles(KnownRoles.Developer);
|
|
Options(o => o.WithTags("Release Communications"));
|
|
}
|
|
|
|
public override async Task HandleAsync(CreateDeveloperReleaseUpdateRequest request, CancellationToken ct)
|
|
{
|
|
if (!TryParseRequest(request, out ReleaseUpdateCategory category, out ReleaseUpdateImportance importance, out ReleaseUpdateAudience audience))
|
|
{
|
|
await SendErrorsAsync(StatusCodes.Status400BadRequest, ct);
|
|
return;
|
|
}
|
|
|
|
DateTimeOffset now = DateTimeOffset.UtcNow;
|
|
ReleaseUpdate update = new()
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Title = request.Title.Trim(),
|
|
Summary = request.Summary.Trim(),
|
|
Body = NormalizeOptional(request.Body),
|
|
Category = category,
|
|
Importance = importance,
|
|
Audience = audience,
|
|
Status = ReleaseUpdateStatus.Draft,
|
|
DeploymentLabel = NormalizeOptional(request.DeploymentLabel),
|
|
BuildVersion = NormalizeOptional(request.BuildVersion),
|
|
CommitRange = NormalizeOptional(request.CommitRange),
|
|
CreatedByUserId = User.GetUserId(),
|
|
CreatedAt = now,
|
|
UpdatedAt = now,
|
|
};
|
|
|
|
dbContext.ReleaseUpdates.Add(update);
|
|
await dbContext.SaveChangesAsync(ct);
|
|
|
|
await SendAsync(update.ToDto(false), StatusCodes.Status201Created, ct);
|
|
}
|
|
|
|
private bool TryParseRequest(
|
|
CreateDeveloperReleaseUpdateRequest request,
|
|
out ReleaseUpdateCategory category,
|
|
out ReleaseUpdateImportance importance,
|
|
out ReleaseUpdateAudience audience)
|
|
{
|
|
bool isValid = true;
|
|
if (!ReleaseUpdateRules.TryParseCategory(request.Category, out category))
|
|
{
|
|
AddError(x => x.Category, "The selected release update category is not valid.");
|
|
isValid = false;
|
|
}
|
|
|
|
if (!ReleaseUpdateRules.TryParseImportance(request.Importance, out importance))
|
|
{
|
|
AddError(x => x.Importance, "The selected release update importance is not valid.");
|
|
isValid = false;
|
|
}
|
|
|
|
if (!ReleaseUpdateRules.TryParseAudience(request.Audience, out audience))
|
|
{
|
|
AddError(x => x.Audience, "The selected release update audience is not valid.");
|
|
isValid = false;
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
private static string? NormalizeOptional(string? value)
|
|
{
|
|
string? normalized = value?.Trim();
|
|
return string.IsNullOrWhiteSpace(normalized) ? null : normalized;
|
|
}
|
|
}
|