Add /api/devices CRUD (list, get, rename, revoke) with owner scoping
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
using System.Security.Claims;
|
||||
using backend.Data;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace backend.Devices;
|
||||
|
||||
public record RenameRequest(string Name);
|
||||
|
||||
public static class DevicesEndpoints
|
||||
{
|
||||
public static IEndpointRouteBuilder MapDevicesEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var grp = app.MapGroup("/api/devices").RequireAuthorization();
|
||||
|
||||
grp.MapGet("/", async (AppDbContext db, HttpContext http, CancellationToken ct) =>
|
||||
{
|
||||
var uid = GetUserId(http);
|
||||
var devs = await db.Devices
|
||||
.Where(d => d.OwnerUserId == uid)
|
||||
.Select(d => new
|
||||
{
|
||||
id = d.Id,
|
||||
name = d.Name,
|
||||
pairedAt = d.PairedAt,
|
||||
lastSeenAt = d.LastSeenAt,
|
||||
isRevoked = d.IsRevoked,
|
||||
})
|
||||
.ToListAsync(ct);
|
||||
return Results.Ok(devs);
|
||||
});
|
||||
|
||||
grp.MapGet("/{id:guid}", async (Guid id, AppDbContext db, HttpContext http, CancellationToken ct) =>
|
||||
{
|
||||
var uid = GetUserId(http);
|
||||
var d = await db.Devices.Include(x => x.Config)
|
||||
.FirstOrDefaultAsync(x => x.Id == id && x.OwnerUserId == uid, ct);
|
||||
return d is null
|
||||
? Results.NotFound()
|
||||
: Results.Ok(new
|
||||
{
|
||||
id = d.Id,
|
||||
name = d.Name,
|
||||
pairedAt = d.PairedAt,
|
||||
lastSeenAt = d.LastSeenAt,
|
||||
isRevoked = d.IsRevoked,
|
||||
config = d.Config,
|
||||
});
|
||||
});
|
||||
|
||||
grp.MapPatch("/{id:guid}", async (
|
||||
Guid id, [FromBody] RenameRequest req,
|
||||
AppDbContext db, HttpContext http, CancellationToken ct) =>
|
||||
{
|
||||
var uid = GetUserId(http);
|
||||
var d = await db.Devices.FirstOrDefaultAsync(x => x.Id == id && x.OwnerUserId == uid, ct);
|
||||
if (d is null) return Results.NotFound();
|
||||
if (string.IsNullOrWhiteSpace(req.Name))
|
||||
return Results.BadRequest(new { error = "name is required" });
|
||||
d.Name = req.Name.Trim();
|
||||
await db.SaveChangesAsync(ct);
|
||||
return Results.Ok();
|
||||
});
|
||||
|
||||
grp.MapDelete("/{id:guid}", async (Guid id, AppDbContext db, HttpContext http, CancellationToken ct) =>
|
||||
{
|
||||
var uid = GetUserId(http);
|
||||
var d = await db.Devices.FirstOrDefaultAsync(x => x.Id == id && x.OwnerUserId == uid, ct);
|
||||
if (d is null) return Results.NotFound();
|
||||
d.IsRevoked = true;
|
||||
await db.SaveChangesAsync(ct);
|
||||
return Results.Ok();
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
private static Guid GetUserId(HttpContext http)
|
||||
{
|
||||
var s = http.User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
return Guid.TryParse(s, out var g) ? g : Guid.Empty;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user