feat(backend): add create flag endpoint and job
This commit is contained in:
parent
ff2ba1fb1b
commit
14e6e35cb7
4 changed files with 87 additions and 5 deletions
|
@ -1,4 +1,7 @@
|
||||||
|
using Coravel.Queuing.Interfaces;
|
||||||
using Foxnouns.Backend.Database;
|
using Foxnouns.Backend.Database;
|
||||||
|
using Foxnouns.Backend.Database.Models;
|
||||||
|
using Foxnouns.Backend.Jobs;
|
||||||
using Foxnouns.Backend.Middleware;
|
using Foxnouns.Backend.Middleware;
|
||||||
using Foxnouns.Backend.Services;
|
using Foxnouns.Backend.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -7,7 +10,11 @@ using Microsoft.EntityFrameworkCore;
|
||||||
namespace Foxnouns.Backend.Controllers;
|
namespace Foxnouns.Backend.Controllers;
|
||||||
|
|
||||||
[Route("/api/v2/users/@me/flags")]
|
[Route("/api/v2/users/@me/flags")]
|
||||||
public class FlagsController(DatabaseContext db, UserRendererService userRenderer) : ApiControllerBase
|
public class FlagsController(
|
||||||
|
DatabaseContext db,
|
||||||
|
UserRendererService userRenderer,
|
||||||
|
ISnowflakeGenerator snowflakeGenerator,
|
||||||
|
IQueue queue) : ApiControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Authorize("identify")]
|
[Authorize("identify")]
|
||||||
|
@ -16,10 +23,29 @@ public class FlagsController(DatabaseContext db, UserRendererService userRendere
|
||||||
{
|
{
|
||||||
var flags = await db.PrideFlags.Where(f => f.UserId == CurrentUser!.Id).ToListAsync(ct);
|
var flags = await db.PrideFlags.Where(f => f.UserId == CurrentUser!.Id).ToListAsync(ct);
|
||||||
|
|
||||||
return Ok(flags.Select(f => new PrideFlagResponse(
|
return Ok(flags.Select(ToResponse));
|
||||||
f.Id, userRenderer.ImageUrlFor(f), f.Name, f.Description)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize("user.update")]
|
||||||
|
[ProducesResponseType<PrideFlagResponse>(statusCode: StatusCodes.Status202Accepted)]
|
||||||
|
public IActionResult CreateFlag([FromBody] CreateFlagRequest req)
|
||||||
|
{
|
||||||
|
var id = snowflakeGenerator.GenerateSnowflake();
|
||||||
|
|
||||||
|
queue.QueueInvocableWithPayload<CreateFlagInvocable, CreateFlagPayload>(
|
||||||
|
new CreateFlagPayload(id, CurrentUser!.Id, req.Name, req.Image, req.Description));
|
||||||
|
|
||||||
|
return Accepted(new CreateFlagResponse(id, req.Name, req.Description));
|
||||||
|
}
|
||||||
|
|
||||||
|
public record CreateFlagRequest(string Name, string Image, string? Description);
|
||||||
|
|
||||||
|
public record CreateFlagResponse(Snowflake Id, string Name, string? Description);
|
||||||
|
|
||||||
|
private PrideFlagResponse ToResponse(PrideFlag flag) =>
|
||||||
|
new(flag.Id, userRenderer.ImageUrlFor(flag), flag.Name, flag.Description);
|
||||||
|
|
||||||
private record PrideFlagResponse(
|
private record PrideFlagResponse(
|
||||||
Snowflake Id,
|
Snowflake Id,
|
||||||
string ImageUrl,
|
string ImageUrl,
|
||||||
|
|
|
@ -99,7 +99,8 @@ public static class WebApplicationExtensions
|
||||||
.AddHostedService<PeriodicTasksService>()
|
.AddHostedService<PeriodicTasksService>()
|
||||||
// Transient jobs
|
// Transient jobs
|
||||||
.AddTransient<MemberAvatarUpdateInvocable>()
|
.AddTransient<MemberAvatarUpdateInvocable>()
|
||||||
.AddTransient<UserAvatarUpdateInvocable>();
|
.AddTransient<UserAvatarUpdateInvocable>()
|
||||||
|
.AddTransient<CreateFlagInvocable>();
|
||||||
|
|
||||||
if (!config.Logging.EnableMetrics)
|
if (!config.Logging.EnableMetrics)
|
||||||
services.AddHostedService<BackgroundMetricsCollectionService>();
|
services.AddHostedService<BackgroundMetricsCollectionService>();
|
||||||
|
|
53
Foxnouns.Backend/Jobs/CreateFlagInvocable.cs
Normal file
53
Foxnouns.Backend/Jobs/CreateFlagInvocable.cs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using Coravel.Invocable;
|
||||||
|
using Foxnouns.Backend.Database;
|
||||||
|
using Foxnouns.Backend.Database.Models;
|
||||||
|
using Foxnouns.Backend.Extensions;
|
||||||
|
using Foxnouns.Backend.Services;
|
||||||
|
|
||||||
|
namespace Foxnouns.Backend.Jobs;
|
||||||
|
|
||||||
|
public class CreateFlagInvocable(DatabaseContext db, ObjectStorageService objectStorageService, ILogger logger)
|
||||||
|
: IInvocable, IInvocableWithPayload<CreateFlagPayload>
|
||||||
|
{
|
||||||
|
private readonly ILogger _logger = logger.ForContext<CreateFlagInvocable>();
|
||||||
|
public required CreateFlagPayload Payload { get; set; }
|
||||||
|
|
||||||
|
public async Task Invoke()
|
||||||
|
{
|
||||||
|
_logger.Information("Creating flag {FlagId} for user {UserId} with image data length {DataLength}", Payload.Id,
|
||||||
|
Payload.UserId, Payload.ImageData.Length);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var image = await Payload.ImageData.ConvertBase64UriToImage(size: 256, crop: false);
|
||||||
|
image.Seek(0, SeekOrigin.Begin);
|
||||||
|
var hash = Convert.ToHexString(await SHA256.HashDataAsync(image)).ToLower();
|
||||||
|
image.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
await objectStorageService.PutObjectAsync(Path(hash), image, "image/webp");
|
||||||
|
|
||||||
|
var flag = new PrideFlag
|
||||||
|
{
|
||||||
|
Id = Payload.Id,
|
||||||
|
UserId = Payload.UserId,
|
||||||
|
Hash = hash,
|
||||||
|
Name = Payload.Name,
|
||||||
|
Description = Payload.Description
|
||||||
|
};
|
||||||
|
db.Add(flag);
|
||||||
|
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
_logger.Information("Uploaded flag {FlagId} with hash {Hash}", flag.Id, flag.Hash);
|
||||||
|
}
|
||||||
|
catch (ArgumentException ae)
|
||||||
|
{
|
||||||
|
_logger.Warning("Invalid data URI for flag {FlagId}: {Reason}", Payload.Id, ae.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Path(string hash) => $"flags/{hash}.webp";
|
||||||
|
}
|
|
@ -3,3 +3,5 @@ using Foxnouns.Backend.Database;
|
||||||
namespace Foxnouns.Backend.Jobs;
|
namespace Foxnouns.Backend.Jobs;
|
||||||
|
|
||||||
public record AvatarUpdatePayload(Snowflake Id, string? NewAvatar);
|
public record AvatarUpdatePayload(Snowflake Id, string? NewAvatar);
|
||||||
|
|
||||||
|
public record CreateFlagPayload(Snowflake Id, Snowflake UserId, string Name, string ImageData, string? Description);
|
Loading…
Reference in a new issue