diff --git a/Foxnouns.Backend/Controllers/FlagsController.cs b/Foxnouns.Backend/Controllers/FlagsController.cs index 5021d8e..7bf20e5 100644 --- a/Foxnouns.Backend/Controllers/FlagsController.cs +++ b/Foxnouns.Backend/Controllers/FlagsController.cs @@ -1,11 +1,9 @@ using Coravel.Queuing.Interfaces; using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; -using Foxnouns.Backend.Extensions; using Foxnouns.Backend.Jobs; using Foxnouns.Backend.Middleware; using Foxnouns.Backend.Services; -using Foxnouns.Backend.Utils; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -13,15 +11,11 @@ namespace Foxnouns.Backend.Controllers; [Route("/api/v2/users/@me/flags")] public class FlagsController( - ILogger logger, DatabaseContext db, UserRendererService userRenderer, - ObjectStorageService objectStorageService, ISnowflakeGenerator snowflakeGenerator, IQueue queue) : ApiControllerBase { - private readonly ILogger _logger = logger.ForContext(); - [HttpGet] [Authorize("identify")] [ProducesResponseType>(statusCode: StatusCodes.Status200OK)] @@ -37,8 +31,6 @@ public class FlagsController( [ProducesResponseType(statusCode: StatusCodes.Status202Accepted)] public IActionResult CreateFlag([FromBody] CreateFlagRequest req) { - ValidationUtils.Validate(ValidateFlag(req.Name, req.Description, req.Image)); - var id = snowflakeGenerator.GenerateSnowflake(); queue.QueueInvocableWithPayload( @@ -49,67 +41,7 @@ public class FlagsController( public record CreateFlagRequest(string Name, string Image, string? Description); - private record CreateFlagResponse(Snowflake Id, string Name, string? Description); - - [HttpPatch("{id}")] - [Authorize("user.update")] - public async Task UpdateFlagAsync(Snowflake id, [FromBody] UpdateFlagRequest req) - { - ValidationUtils.Validate(ValidateFlag(req.Name, req.Description, null)); - - var flag = await db.PrideFlags.FirstOrDefaultAsync(f => f.Id == id && f.UserId == CurrentUser!.Id); - if (flag == null) throw new ApiError.NotFound("Unknown flag ID, or it's not your flag."); - - if (req.Name != null) flag.Name = req.Name; - - if (req.HasProperty(nameof(req.Description))) - flag.Description = req.Description; - - db.Update(flag); - await db.SaveChangesAsync(); - - return Ok(ToResponse(flag)); - } - - public class UpdateFlagRequest : PatchRequest - { - public string? Name { get; init; } - public string? Description { get; init; } - } - - [HttpDelete("{id}")] - [Authorize("user.update")] - public async Task DeleteFlagAsync(Snowflake id) - { - await using var tx = await db.Database.BeginTransactionAsync(); - - var flag = await db.PrideFlags.FirstOrDefaultAsync(f => f.Id == id && f.UserId == CurrentUser!.Id); - if (flag == null) throw new ApiError.NotFound("Unknown flag ID, or it's not your flag."); - - var hash = flag.Hash; - - db.PrideFlags.Remove(flag); - await db.SaveChangesAsync(); - - var flagCount = await db.PrideFlags.CountAsync(f => f.Hash == flag.Hash); - if (flagCount == 0) - { - try - { - _logger.Information("Deleting flag file {Hash} as it is no longer used by any flags", hash); - await objectStorageService.DeleteFlagAsync(hash); - } - catch (Exception e) - { - _logger.Error(e, "Error deleting flag file {Hash}", hash); - } - } - else _logger.Debug("Flag file {Hash} is used by other flags, not deleting", hash); - - await tx.CommitAsync(); - - return NoContent(); - } + public record CreateFlagResponse(Snowflake Id, string Name, string? Description); private PrideFlagResponse ToResponse(PrideFlag flag) => new(flag.Id, userRenderer.ImageUrlFor(flag), flag.Name, flag.Description); @@ -119,52 +51,4 @@ public class FlagsController( string ImageUrl, string Name, string? Description); - - private static List<(string, ValidationError?)> ValidateFlag(string? name, string? description, string? imageData) - { - var errors = new List<(string, ValidationError?)>(); - - if (name != null) - { - switch (name.Length) - { - case < 1: - errors.Add(("name", ValidationError.LengthError("Name is too short", 1, 100, name.Length))); - break; - case > 100: - errors.Add(("name", ValidationError.LengthError("Name is too long", 1, 100, name.Length))); - break; - } - } - - if (description != null) - { - switch (description.Length) - { - case < 1: - errors.Add(("description", - ValidationError.LengthError("Description is too short", 1, 100, description.Length))); - break; - case > 500: - errors.Add(("description", - ValidationError.LengthError("Description is too long", 1, 100, description.Length))); - break; - } - } - - if (imageData != null) - { - switch (imageData.Length) - { - case 0: - errors.Add(("image", ValidationError.GenericValidationError("Image cannot be empty", null))); - break; - case > 1_500_000: - errors.Add(("image", ValidationError.GenericValidationError("Image is too large", null))); - break; - } - } - - return errors; - } } \ No newline at end of file diff --git a/Foxnouns.Backend/Extensions/AvatarObjectExtensions.cs b/Foxnouns.Backend/Extensions/AvatarObjectExtensions.cs index 6aa1626..063f835 100644 --- a/Foxnouns.Backend/Extensions/AvatarObjectExtensions.cs +++ b/Foxnouns.Backend/Extensions/AvatarObjectExtensions.cs @@ -24,10 +24,6 @@ public static class AvatarObjectExtensions CancellationToken ct = default) => await objectStorageService.RemoveObjectAsync(UserAvatarUpdateInvocable.Path(id, hash), ct); - public static async Task DeleteFlagAsync(this ObjectStorageService objectStorageService, string hash, - CancellationToken ct = default) => - await objectStorageService.RemoveObjectAsync(CreateFlagInvocable.Path(hash), ct); - public static async Task<(string Hash, Stream Image)> ConvertBase64UriToImage(this string uri, int size, bool crop) { if (!uri.StartsWith("data:image/")) diff --git a/Foxnouns.Backend/Jobs/CreateFlagInvocable.cs b/Foxnouns.Backend/Jobs/CreateFlagInvocable.cs index 0d99244..1acf054 100644 --- a/Foxnouns.Backend/Jobs/CreateFlagInvocable.cs +++ b/Foxnouns.Backend/Jobs/CreateFlagInvocable.cs @@ -1,3 +1,4 @@ +using System.Security.Cryptography; using Coravel.Invocable; using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; @@ -44,5 +45,5 @@ public class CreateFlagInvocable(DatabaseContext db, ObjectStorageService object throw new NotImplementedException(); } - public static string Path(string hash) => $"flags/{hash}.webp"; + private static string Path(string hash) => $"flags/{hash}.webp"; } \ No newline at end of file