Files
astrain/src/ASTRAIN.Api/Endpoints/RoutineEndpoints.cs

189 lines
7.7 KiB
C#

using ASTRAIN.Api.Data;
using ASTRAIN.Api.Services;
using ASTRAIN.Shared.Dtos;
using ASTRAIN.Shared.Models;
using ASTRAIN.Shared.Requests;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
namespace ASTRAIN.Api.Endpoints;
/// <summary>
/// Provides routine-related endpoints.
/// </summary>
internal static class RoutineEndpoints
{
/// <summary>
/// Registers routine routes under the provided route group.
/// </summary>
/// <param name="group">The API route group.</param>
/// <returns>The same route group for chaining.</returns>
public static RouteGroupBuilder MapRoutineEndpoints(this RouteGroupBuilder group)
{
group.MapGet("/users/{userId}/routines", async (string userId, AppDbContext db, IConfiguration config) =>
{
var populateSampleData = config.GetValue("SampleData:Enabled", false);
var user = await UserProvisioning.EnsureUserAsync(db, userId, populateSampleData);
var routines = await db.Routines
.Include(r => r.Exercises)
.ThenInclude(re => re.Exercise)
.Where(r => r.UserId == user.Id)
.OrderBy(r => r.Name)
.ToListAsync();
var payload = routines.Select(r => new RoutineDto(
r.Id,
r.Name,
r.Exercises
.OrderBy(re => re.Order)
.Select(re => new RoutineExerciseDto(re.ExerciseId, re.Exercise?.Name ?? string.Empty, re.Order))
.ToList()
));
return Results.Ok(payload);
})
.WithSummary("List routines")
.WithDescription("Returns all routines for the specified user.");
group.MapGet("/users/{userId}/routines/{routineId:int}", async (string userId, int routineId, AppDbContext db, IConfiguration config) =>
{
var populateSampleData = config.GetValue("SampleData:Enabled", false);
var user = await UserProvisioning.EnsureUserAsync(db, userId, populateSampleData);
var routine = await db.Routines
.Include(r => r.Exercises)
.ThenInclude(re => re.Exercise)
.FirstOrDefaultAsync(r => r.Id == routineId && r.UserId == user.Id);
if (routine is null)
{
return Results.NotFound();
}
var payload = new RoutineDto(
routine.Id,
routine.Name,
routine.Exercises
.OrderBy(re => re.Order)
.Select(re => new RoutineExerciseDto(re.ExerciseId, re.Exercise?.Name ?? string.Empty, re.Order))
.ToList());
return Results.Ok(payload);
})
.WithSummary("Get routine")
.WithDescription("Returns a specific routine and its exercises.");
group.MapPost("/users/{userId}/routines", async (string userId, RoutineUpsertRequest request, AppDbContext db, IConfiguration config) =>
{
var populateSampleData = config.GetValue("SampleData:Enabled", false);
var user = await UserProvisioning.EnsureUserAsync(db, userId, populateSampleData);
if (string.IsNullOrWhiteSpace(request.Name))
{
return Results.BadRequest("Name is required.");
}
var routine = new Routine
{
Name = request.Name.Trim(),
UserId = user.Id
};
var exercises = await db.Exercises
.Where(e => e.UserId == user.Id && request.ExerciseIds.Contains(e.Id))
.ToListAsync();
routine.Exercises = request.ExerciseIds
.Select((exerciseId, index) => new RoutineExercise
{
ExerciseId = exerciseId,
Order = index
})
.ToList();
db.Routines.Add(routine);
await db.SaveChangesAsync();
var dto = new RoutineDto(
routine.Id,
routine.Name,
routine.Exercises
.Select((re, index) => new RoutineExerciseDto(re.ExerciseId, exercises.FirstOrDefault(e => e.Id == re.ExerciseId)?.Name ?? string.Empty, index))
.ToList());
return Results.Ok(dto);
})
.WithSummary("Create routine")
.WithDescription("Creates a routine and associates exercises with it.");
group.MapPut("/users/{userId}/routines/{routineId:int}", async (string userId, int routineId, RoutineUpsertRequest request, AppDbContext db, IConfiguration config) =>
{
var populateSampleData = config.GetValue("SampleData:Enabled", false);
var user = await UserProvisioning.EnsureUserAsync(db, userId, populateSampleData);
var routine = await db.Routines
.Include(r => r.Exercises)
.FirstOrDefaultAsync(r => r.Id == routineId && r.UserId == user.Id);
if (routine is null)
{
return Results.NotFound();
}
if (string.IsNullOrWhiteSpace(request.Name))
{
return Results.BadRequest("Name is required.");
}
routine.Name = request.Name.Trim();
routine.Exercises.Clear();
foreach (var exerciseId in request.ExerciseIds)
{
routine.Exercises.Add(new RoutineExercise
{
ExerciseId = exerciseId,
Order = routine.Exercises.Count
});
}
await db.SaveChangesAsync();
var exercises = await db.Exercises
.Where(e => e.UserId == user.Id && request.ExerciseIds.Contains(e.Id))
.ToListAsync();
var dto = new RoutineDto(
routine.Id,
routine.Name,
routine.Exercises
.OrderBy(re => re.Order)
.Select(re => new RoutineExerciseDto(re.ExerciseId, exercises.FirstOrDefault(e => e.Id == re.ExerciseId)?.Name ?? string.Empty, re.Order))
.ToList());
return Results.Ok(dto);
})
.WithSummary("Update routine")
.WithDescription("Updates routine metadata and exercise ordering.");
group.MapDelete("/users/{userId}/routines/{routineId:int}", async (string userId, int routineId, AppDbContext db, IConfiguration config) =>
{
var populateSampleData = config.GetValue("SampleData:Enabled", false);
var user = await UserProvisioning.EnsureUserAsync(db, userId, populateSampleData);
var routine = await db.Routines.FirstOrDefaultAsync(r => r.Id == routineId && r.UserId == user.Id);
if (routine is null)
{
return Results.NotFound();
}
db.Routines.Remove(routine);
await db.SaveChangesAsync();
return Results.NoContent();
})
.WithSummary("Delete routine")
.WithDescription("Deletes a routine and its associated data for the specified user.");
return group;
}
}