189 lines
7.7 KiB
C#
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;
|
|
}
|
|
}
|