Files
mission-control/src/MissionControl.Server/Endpoints/Missions/MissionLaunches/CreateMissionLaunch.cs
T

61 lines
2.0 KiB
C#

using FastEndpoints;
using FluentValidation;
using Microsoft.EntityFrameworkCore;
using MissionControl.Data;
using MissionControl.Domain.Entities;
namespace MissionControl.Server.Endpoints.Missions.MissionLaunches;
public class CreateMissionLaunch(MissionControlContext dbContext)
: Endpoint<CreateMissionLaunchRequest, MissionLaunchResponse>
{
public override void Configure()
{
Post("/missions/{MissionId}/launch");
}
public override async Task HandleAsync(CreateMissionLaunchRequest req, CancellationToken ct)
{
var missionExists = await dbContext.Missions.AnyAsync(mission => mission.Id == req.MissionId, ct);
if (!missionExists)
{
await Send.NotFoundAsync(ct);
return;
}
var missionLaunch = new MissionLaunch
{
ScheduledFor = req.ScheduledFor,
// Validated in `CreateMissionLaunchRequestValidator`
Status = Enum.Parse<MissionLaunchStatus>(req.Status, true),
MissionId = req.MissionId,
};
dbContext.MissionLaunches.Add(missionLaunch);
await dbContext.SaveChangesAsync(ct);
await Send.OkAsync(MissionLaunchResponse.FromDomain(missionLaunch), ct);
}
}
public record CreateMissionLaunchRequest
{
public Guid MissionId { get; init; }
public required DateTimeOffset ScheduledFor { get; init; }
// Define as a string here so it can be safely deserialized into its enum type, with a validation message when unable to do so
// Otherwise, we return a serialization error that is not assigned to a specific field
public required string Status { get; init; }
}
public class CreateMissionLaunchRequestValidator : Validator<CreateMissionLaunchRequest>
{
public CreateMissionLaunchRequestValidator()
{
RuleFor(req => req.MissionId)
.NotEqual(Guid.Empty)
.WithMessage("Please provide a non-zero GUID.");
RuleFor(req => req.Status).IsEnumName(typeof(MissionLaunchStatus), false);
}
}