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.Models; | ||||
| using Foxnouns.Backend.Jobs; | ||||
| using Foxnouns.Backend.Middleware; | ||||
| using Foxnouns.Backend.Services; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
|  | @ -7,7 +10,11 @@ using Microsoft.EntityFrameworkCore; | |||
| namespace Foxnouns.Backend.Controllers; | ||||
| 
 | ||||
| [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] | ||||
|     [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); | ||||
| 
 | ||||
|         return Ok(flags.Select(f => new PrideFlagResponse( | ||||
|             f.Id, userRenderer.ImageUrlFor(f), f.Name, f.Description))); | ||||
|         return Ok(flags.Select(ToResponse)); | ||||
|     } | ||||
| 
 | ||||
|     [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( | ||||
|         Snowflake Id, | ||||
|         string ImageUrl, | ||||
|  |  | |||
|  | @ -99,7 +99,8 @@ public static class WebApplicationExtensions | |||
|                 .AddHostedService<PeriodicTasksService>() | ||||
|                 // Transient jobs | ||||
|                 .AddTransient<MemberAvatarUpdateInvocable>() | ||||
|                 .AddTransient<UserAvatarUpdateInvocable>(); | ||||
|                 .AddTransient<UserAvatarUpdateInvocable>() | ||||
|                 .AddTransient<CreateFlagInvocable>(); | ||||
| 
 | ||||
|             if (!config.Logging.EnableMetrics) | ||||
|                 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"; | ||||
| } | ||||
|  | @ -2,4 +2,6 @@ using Foxnouns.Backend.Database; | |||
| 
 | ||||
| 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…
	
	Add table
		Add a link
		
	
		Reference in a new issue