From a45ad8d3f8da273f80029ba6d34beb7e4ff7d7b5 Mon Sep 17 00:00:00 2001 From: Jake Mannens Date: Fri, 8 May 2026 01:30:38 +1000 Subject: v0.14a --- Controllers/ApiMediaController.cs | 2 + Controllers/ApiTagController.cs | 4 +- Controllers/ApiUserController.cs | 109 ++++++++++++++++++++++++++++++++++++++ Controllers/MediaController.cs | 2 + Program.cs | 5 +- Server.csproj | 4 +- User.cs | 6 +++ 7 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 Controllers/ApiUserController.cs diff --git a/Controllers/ApiMediaController.cs b/Controllers/ApiMediaController.cs index 0539b77..a324f35 100644 --- a/Controllers/ApiMediaController.cs +++ b/Controllers/ApiMediaController.cs @@ -1,5 +1,6 @@ using HyperBooru.ApiModels; using HyperBooru.Services; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Text.Json; @@ -7,6 +8,7 @@ using System.Text.Json; namespace HyperBooru.Controllers; [ApiController] +[Authorize] [Route("/api/media")] public class ApiMediaController : Controller { private IDbContextFactory dbFactory; diff --git a/Controllers/ApiTagController.cs b/Controllers/ApiTagController.cs index afd5b05..26e3dc4 100644 --- a/Controllers/ApiTagController.cs +++ b/Controllers/ApiTagController.cs @@ -1,9 +1,11 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace HyperBooru.Controllers; [ApiController] +[Authorize] [Route("/api/tag")] public class ApiTagController : Controller { private IDbContextFactory dbFactory; diff --git a/Controllers/ApiUserController.cs b/Controllers/ApiUserController.cs new file mode 100644 index 0000000..d678287 --- /dev/null +++ b/Controllers/ApiUserController.cs @@ -0,0 +1,109 @@ +using HyperBooru.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace HyperBooru.Controllers; + +[ApiController] +[Authorize] +[Route("/api/user")] +public class ApiUserController : Controller { + private IDbContextFactory dbFactory; + + public ApiUserController(IDbContextFactory dbFactory) => + this.dbFactory = dbFactory; + + [HttpGet] + public async Task GetAllUsersAsync() { + using var db = dbFactory.CreateDbContext(); + + return Ok(await db.Users + .Select(u => (ApiModels.User) u) + .ToArrayAsync()); + } + + [HttpGet("{userId}")] + public async Task GetUserAsync([FromRoute] Guid userId) { + using var db = dbFactory.CreateDbContext(); + + var user = await db.Users + .FirstOrDefaultAsync(u => u.Guid == userId); + + return user is null ? NotFound() : Ok((ApiModels.User) user); + } + + [HttpPost] + public async Task CreateUserAsync([FromBody] ApiModels.UserCreateRequest request) { + using var db = dbFactory.CreateDbContext(); + + using var transaction = await db.Database.BeginTransactionAsync(); + + if(await db.Users.AnyAsync(u => u.Username == request.Username)) + return BadRequest("Username already exists"); + + var user = new User() { + Username = request.Username, + PasswordHash = UserService.HashPassword(request.Password) + }; + + db.Users.Add(user); + + await db.SaveChangesAsync(); + await transaction.CommitAsync(); + + return Ok((ApiModels.User) user); + } + + [HttpPatch("{userId}")] + public async Task UpdateUserAsync( + [FromRoute] Guid userId, + [FromBody] ApiModels.UserUpdateRequest request) { + + using var db = dbFactory.CreateDbContext(); + + using var transaction = await db.Database.BeginTransactionAsync(); + + var user = await db.Users.FirstOrDefaultAsync(u => u.Guid == userId); + if(user is null) + return NotFound(); + + if(request.Username is not null) { + if(string.IsNullOrWhiteSpace(request.Username)) + return BadRequest("Username cannot be empty"); + user.Username = request.Username; + } + + if(request.Password is not null) { + if(string.IsNullOrWhiteSpace(request.Password)) + return BadRequest("Password cannot be empty"); + user.PasswordHash = UserService.HashPassword(request.Password); + } + + await db.SaveChangesAsync(); + await transaction.CommitAsync(); + + return Ok((ApiModels.User) user); + } + + [HttpDelete("{userId}")] + public async Task DeleteUserAsync([FromRoute] Guid userId) { + if(userId == HBContext.AdminUser) + return BadRequest("Cannot delete the admin user"); + + using var db = dbFactory.CreateDbContext(); + + using var transaction = await db.Database.BeginTransactionAsync(); + + var user = await db.Users.FirstOrDefaultAsync(u => u.Guid == userId); + if(user is null) + return NotFound(); + + db.Users.Remove(user); + + await db.SaveChangesAsync(); + await transaction.CommitAsync(); + + return Ok((ApiModels.User) user); + } +} diff --git a/Controllers/MediaController.cs b/Controllers/MediaController.cs index 96ecb44..6a9e1fc 100644 --- a/Controllers/MediaController.cs +++ b/Controllers/MediaController.cs @@ -1,12 +1,14 @@ using HyperBooru.ApiModels; using HyperBooru.Services; using HyperBooru.Util; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace HyperBooru.Controllers; [ApiController] +[Authorize] [Route("/media")] public class MediaController : Controller { private IHttpContextAccessor httpContextAccessor; diff --git a/Program.cs b/Program.cs index 34db56f..5863368 100644 --- a/Program.cs +++ b/Program.cs @@ -14,6 +14,7 @@ public class Program { builder.Services.AddHttpContextAccessor(); builder.Services.AddAuthentication( CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(); + builder.Services.AddAuthorization(); builder.Services.AddControllers().AddJsonOptions(o => { var converter = new JsonStringEnumConverter(); o.JsonSerializerOptions.Converters.Add(converter); @@ -49,12 +50,14 @@ public class Program { using var db = scope.ServiceProvider.GetRequiredService(); db.Database.Migrate(); + app.UseRouting(); app.UseSession(); + app.UseAuthentication(); + app.UseAuthorization(); app.UseHsts(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseMiddleware(); - app.UseRouting(); app.MapBlazorHub(); app.MapControllers(); app.MapFallbackToPage("/_Host"); diff --git a/Server.csproj b/Server.csproj index c9afced..14893c7 100644 --- a/Server.csproj +++ b/Server.csproj @@ -6,9 +6,9 @@ enable HyperBooru HyperBooru - 0.13.0.0 + 0.14.0.0 $(AssemblyVersion) - 0.13-alpha + 0.14-alpha 2907567f-4640-4581-8f4d-0977952d26bd diff --git a/User.cs b/User.cs index 61ef03f..87384d2 100644 --- a/User.cs +++ b/User.cs @@ -6,4 +6,10 @@ namespace HyperBooru; public class User : HBObject { public string Username { get; set; } public string PasswordHash { get; set; } + + public static explicit operator ApiModels.User(User user) => + new() { + UserId = user.Guid, + Username = user.Username + }; } -- cgit v1.3