diff options
| author | Jake Mannens <jake@asger.xyz> | 2026-05-22 12:46:00 +1000 |
|---|---|---|
| committer | Jake Mannens <jake@asger.xyz> | 2026-05-23 22:13:00 +1000 |
| commit | 4ea3ddb38d010c2f85c22b7f1c3f2d7e0c1355e3 (patch) | |
| tree | 90af9203059d645eb77216f1a091722ee9702438 /Controllers | |
| parent | 6de5d7f5364fe1d54703da6d6b7cb08ea26e939f (diff) | |
Initial commitwasm-oldserver
Diffstat (limited to 'Controllers')
| -rw-r--r-- | Controllers/ApiFeedController.cs | 25 | ||||
| -rw-r--r-- | Controllers/ApiMediaController.cs | 221 | ||||
| -rw-r--r-- | Controllers/ApiTagController.cs | 253 | ||||
| -rw-r--r-- | Controllers/ApiUserController.cs | 109 | ||||
| -rw-r--r-- | Controllers/LoginController.cs | 49 | ||||
| -rw-r--r-- | Controllers/MediaController.cs | 155 |
6 files changed, 0 insertions, 812 deletions
diff --git a/Controllers/ApiFeedController.cs b/Controllers/ApiFeedController.cs deleted file mode 100644 index 382169e..0000000 --- a/Controllers/ApiFeedController.cs +++ /dev/null @@ -1,25 +0,0 @@ -using HyperBooru.ApiModels; -using HyperBooru.Services; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; - -namespace HyperBooru.Controllers; - -[ApiController] -[Authorize] -[Route("/api/feed")] -public class ApiFeedController : Controller { - private IFeedService feedService; - - public ApiFeedController(IDbContextFactory<HBContext> dbFactory, IFeedService feedService) => - this.feedService = feedService; - - [HttpPost] - public IActionResult FetchChunkAsync([FromBody] FeedRequest feedRequest) { - if(feedRequest.Count > 1000) - return BadRequest("Total number of requested items exceeds maximum"); - - return Ok(feedService.LoadChunk(feedRequest).Select(m => m.Guid).ToArray()); - } -} diff --git a/Controllers/ApiMediaController.cs b/Controllers/ApiMediaController.cs deleted file mode 100644 index a1b07b1..0000000 --- a/Controllers/ApiMediaController.cs +++ /dev/null @@ -1,221 +0,0 @@ -using HyperBooru.ApiModels; -using HyperBooru.Services; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using System.Text.Json; - -namespace HyperBooru.Controllers; - -[ApiController] -[Authorize] -[Route("/api/media")] -public class ApiMediaController : Controller { - private IDbContextFactory<HBContext> dbFactory; - private IMediaService mediaService; - - public ApiMediaController(IDbContextFactory<HBContext> dbFactory, IMediaService mediaService) { - this.dbFactory = dbFactory; - this.mediaService = mediaService; - } - - [HttpGet("{mediaId}")] - public async Task<IActionResult> Get([FromRoute] Guid mediaId) { - using var db = dbFactory.CreateDbContext(); - - var media = await db.Media.FirstOrDefaultAsync(m => m.Guid == mediaId); - - if(media is null) - throw new ObjectNotFoundException(mediaId); - - return Ok((ApiModels.Media) media); - } - - [HttpGet("{mediaId}/files")] - public async Task<IActionResult> GetUploadedFiles([FromRoute] Guid mediaId) { - using var db = dbFactory.CreateDbContext(); - - var media = await db.Media - .Include(m => m.UploadedFiles) - .FirstOrDefaultAsync(m => m.Guid == mediaId); - - if(media is null) - throw new ObjectNotFoundException(mediaId); - - return Ok(media.UploadedFiles.Select(uf => (ApiModels.UploadedFile) uf).ToArray()); - } - - [HttpPatch] - public async Task<IActionResult> UpdateMedia([FromBody] ApiModels.Media updatedMedia) { - using var db = dbFactory.CreateDbContext(); - using var transaction = await db.Database.BeginTransactionAsync(); - - var media = await db.Media.FirstOrDefaultAsync(m => m.Guid == updatedMedia.MediaId); - if(media is null) - return NotFound(); - - media.ShortDescription = updatedMedia.ShortDescription; - media.LongDescription = updatedMedia.LongDescription; - - await db.SaveChangesAsync(); - await transaction.CommitAsync(); - - return Ok(); - } - - [HttpPost] - public IActionResult Upload() { - if(Request.Form.Files.Count == 0) - return BadRequest("No files"); - if(Request.Form.Files.Count > 1) - return BadRequest("More than one file supplied"); - - var metadataString = Request.Form.Files - .First() - .Headers["X-HyperBooru-Metadata"] - .ElementAtOrDefault(0); - - MediaUploadRequest? metadata = metadataString is null ? null : - JsonSerializer.Deserialize<MediaUploadRequest>(metadataString); - - var formFile = Request.Form.Files.First(); - - var media = mediaService.Create( - formFile.OpenReadStream(), - formFile.FileName, - metadata?.Checksum, - metadata?.LastAccessTime, - metadata?.LastWriteTime, - metadata?.CreateTime, - metadata?.Path, - metadata?.PathType, - metadata?.Tags); - - return Ok((ApiModels.Media) media); - } - - [HttpDelete("{mediaId}")] - public void Delete([FromRoute] Guid mediaId) => - mediaService.Delete(mediaId); - - [HttpGet("{mediaId}/tags")] - public async Task<IActionResult> GetMediaTagsAsync([FromRoute] Guid mediaId) { - using var db = dbFactory.CreateDbContext(); - - var media = await db.Media - .Include(m => m.Tags) - .ThenInclude(t => t.TagDefinition) - .ThenInclude(td => td.ImplicitTags) - .FirstOrDefaultAsync(m => m.Guid == mediaId); - if(media is null) - return NotFound(); - - return Ok(media.Tags.Select(t => (ApiModels.TagDefinition) t.TagDefinition).ToArray()); - } - - [HttpPatch("{mediaId}/tags")] - public async Task<IActionResult> AddTagsToMediaAsync( - [FromRoute] Guid mediaId, - [FromBody] Guid[] tagIds) { - - using var db = dbFactory.CreateDbContext(); - using var transaction = await db.Database.BeginTransactionAsync(); - - var media = await db.Media - .Include(m => m.Tags) - .ThenInclude(t => t.TagDefinition) - .ThenInclude(td => td.ImplicitTags) - .FirstOrDefaultAsync(m => m.Guid == mediaId); - if(media is null) - return NotFound(); - - tagIds = tagIds.Distinct().ToArray(); - - var tags = await db.TagDefinitions - .Where(td => tagIds.Contains(td.Guid)) - .ToArrayAsync(); - - if(tags.Count() < tagIds.Count()) - return NotFound("Invalid tag IDs specified"); - - media.Tags.AddRange(tags - .Where(td => !media.Tags.Select(t => t.TagDefinition.Guid).Contains(td.Guid)) - .Select(td => new Tag() { TagDefinition = td })); - - await db.SaveChangesAsync(); - await transaction.CommitAsync(); - - return Ok(media.Tags.Select(t => (ApiModels.TagDefinition) t.TagDefinition).ToArray()); - } - - [HttpPut("{mediaId}/tags")] - public async Task<IActionResult> ReplaceMediaTagsAsync( - [FromRoute] Guid mediaId, - [FromBody] Guid[] tagIds) { - - using var db = dbFactory.CreateDbContext(); - using var transaction = await db.Database.BeginTransactionAsync(); - - var media = await db.Media - .Include(m => m.Tags) - .ThenInclude(t => t.TagDefinition) - .ThenInclude(td => td.ImplicitTags) - .FirstOrDefaultAsync(m => m.Guid == mediaId); - if(media is null) - return NotFound(); - - tagIds = tagIds.Distinct().Order().ToArray(); - var tags = await db.TagDefinitions - .Where(td => tagIds.Contains(td.Guid)) - .ToArrayAsync(); - - var missingTags = tagIds.Except(tags.Select(td => td.Guid)); - var missingTagsString = string.Join(", ", missingTags.Select(t => t.ToString())); - if(missingTags.Any()) - return BadRequest($"Invalid tag IDs specified: {missingTagsString}"); - - media.Tags.AddRange(tags - .Where(td => !media.Tags.Select(t => t.TagDefinition.Guid).Contains(td.Guid)) - .Select(td => new Tag() { TagDefinition = td })); - - db.Tags.RemoveRange( - media.Tags.Where(t => !tagIds.Contains(t.TagDefinition.Guid))); - - await db.SaveChangesAsync(); - await transaction.CommitAsync(); - - return Ok(media.Tags.Select(t => (ApiModels.TagDefinition) t.TagDefinition).ToArray()); - } - - [HttpPatch("{mediaId}/tags/delete")] - public async Task<IActionResult> DeleteTagsFromMediaAsync( - [FromRoute] Guid mediaId, - [FromBody] Guid[] tagIds) { - - using var db = dbFactory.CreateDbContext(); - using var transaction = await db.Database.BeginTransactionAsync(); - - var media = await db.Media - .Include(m => m.Tags) - .ThenInclude(t => t.TagDefinition) - .ThenInclude(td => td.ImplicitTags) - .FirstOrDefaultAsync(m => m.Guid == mediaId); - if(media is null) - return NotFound(); - - tagIds = tagIds.Distinct().Order().ToArray(); - - var missingTags = tagIds.Except(media.Tags.Select(t => t.TagDefinition.Guid)); - var missingTagsString = string.Join(", ", missingTags.Select(t => t.ToString())); - if(missingTags.Any()) - return BadRequest($"Media does not contain the following tags: {missingTagsString}"); - - db.Tags.RemoveRange( - media.Tags.Where(t => tagIds.Contains(t.TagDefinition.Guid))); - - await db.SaveChangesAsync(); - await transaction.CommitAsync(); - - return Ok(media.Tags.Select(t => (ApiModels.TagDefinition) t.TagDefinition).ToArray()); - } -} diff --git a/Controllers/ApiTagController.cs b/Controllers/ApiTagController.cs deleted file mode 100644 index f48cc05..0000000 --- a/Controllers/ApiTagController.cs +++ /dev/null @@ -1,253 +0,0 @@ -using HyperBooru.ApiModels; -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<HBContext> dbFactory; - - public ApiTagController(IDbContextFactory<HBContext> dbFactory) => - this.dbFactory = dbFactory; - - [HttpGet("definition")] - public async Task<IActionResult> GetAllTagDefinitionsAsync() { - using var db = dbFactory.CreateDbContext(); - - var definitions = await db.TagDefinitions - .Include(td => td.ImplicitTags) - .Select(td => (ApiModels.TagDefinition)td) - .ToArrayAsync(); - - return Ok(definitions); - } - - [HttpGet("definition/{tagDefinitionId}")] - public async Task<IActionResult> GetTagDefinitionAsync([FromRoute] Guid tagDefinitionId) { - using var db = dbFactory.CreateDbContext(); - - var tagDefinition = await db.TagDefinitions - .Include(td => td.ImplicitTags) - .FirstOrDefaultAsync(td => td.Guid == tagDefinitionId); - - return tagDefinition is not null ? Ok(tagDefinition) : NotFound(); - } - - [HttpPost("definition")] - public async Task<IActionResult> CreateTagDefinitionAsync([FromBody] TagCreateRequest request) { - using var db = dbFactory.CreateDbContext(); - using var transaction = await db.Database.BeginTransactionAsync(); - - if(db.TagDefinitions.Any(td => td.Name == request.Name)) - return BadRequest("Name already exists"); - - if(request.Alias is not null) - if(db.TagDefinitions.Any(td => td.Alias == request.Alias)) - return BadRequest("Alias already exists"); - - List<TagDefinition> implicitTags = new(); - if(request.ImplicitTags is not null) { - implicitTags = await db.TagDefinitions - .Where(td => request.ImplicitTags.Distinct().Contains(td.Guid)) - .ToListAsync(); - } - - var tagDefinition = new TagDefinition { - Source = TagSource.UserTag, - Namespace = request.Namespace, - Name = request.Name, - Alias = request.Alias, - ImplicitTags = implicitTags - }; - - db.TagDefinitions.Add(tagDefinition); - - await db.SaveChangesAsync(); - await transaction.CommitAsync(); - - return Ok((ApiModels.TagDefinition) tagDefinition); - } - - [HttpDelete("definition/{tagDefinitionId}")] - public async Task<IActionResult> DeleteTagDefinitionAsync([FromRoute] Guid tagDefinitionId) { - using var db = dbFactory.CreateDbContext(); - using var transaction = await db.Database.BeginTransactionAsync(); - - var tagDefinition = await db.TagDefinitions - .FirstOrDefaultAsync(td => td.Guid == tagDefinitionId); - - if(tagDefinition is null) - return NotFound("Tag definition not found"); - - if(tagDefinition.ObjectId < 0) - return BadRequest("Cannot delete built-in tag definition"); - - db.TagDefinitions.Remove(tagDefinition); - - await db.SaveChangesAsync(); - await transaction.CommitAsync(); - - return Ok(); - } - - [HttpPatch("definition/{tagDefinitionId}")] - public async Task<IActionResult> UpdateTagDefinitionAsync( - [FromRoute] Guid tagDefinitionId, - [FromBody] TagUpdateRequest request) { - - using var db = dbFactory.CreateDbContext(); - using var transaction = await db.Database.BeginTransactionAsync(); - - var tagDefinition = await db.TagDefinitions - .FirstOrDefaultAsync(td => td.Guid == tagDefinitionId); - - if(tagDefinition is null) - return NotFound("Tag definition not found"); - - if(tagDefinition.ObjectId < 0) - return BadRequest("Cannot update built-in tag definition"); - - if(request.Name is not null) - if(db.TagDefinitions.Any(td => td.Name == request.Name)) - return BadRequest("Name already exists"); - - if(request.Alias is not null) - if(db.TagDefinitions.Any(td => td.Alias == request.Alias)) - return BadRequest("Alias already exists"); - - tagDefinition.Namespace = request.Namespace ?? tagDefinition.Namespace; - tagDefinition.Name = request.Name ?? tagDefinition.Name; - tagDefinition.Alias = request.Alias ?? tagDefinition.Alias; - - await db.SaveChangesAsync(); - await transaction.CommitAsync(); - - return Ok((ApiModels.TagDefinition) tagDefinition); - } - - [HttpPatch("definition/{tagDefinitionId}/implicit")] - public async Task<IActionResult> AddImplicitTagsAsync( - [FromRoute] Guid tagDefinitionId, - [FromBody] Guid[] implicitTagIds) { - - using var db = dbFactory.CreateDbContext(); - using var transaction = await db.Database.BeginTransactionAsync(); - - var tagDefinition = await db.TagDefinitions - .Include(td => td.ImplicitTags) - .FirstOrDefaultAsync(td => td.Guid == tagDefinitionId); - - if(tagDefinition is null) - return NotFound("Tag definition not found"); - - if(tagDefinition.ObjectId < 0) - return BadRequest("Cannot update built-in tag definition"); - - implicitTagIds = implicitTagIds.Distinct().ToArray(); - - var implicitTags = db.TagDefinitions - .Where(td => implicitTagIds.Contains(td.Guid)) - .ToArray(); - - var missingTags = implicitTagIds.Except(implicitTags.Select(td => td.Guid)); - var missingTagsString = string.Join(", ", missingTags.Select(td => td.ToString())); - if(missingTags.Any()) - return BadRequest($"Invalid tag IDs specified: {missingTagsString}"); - - tagDefinition.ImplicitTags.AddRange( - implicitTags.ExceptBy(tagDefinition.ImplicitTags.Select(td => td.Guid), td => td.Guid)); - - await db.SaveChangesAsync(); - await transaction.CommitAsync(); - - return Ok(); - } - - [HttpPut("definition/{tagDefinitionId}/implicit")] - public async Task<IActionResult> ReplaceImplicitTagsAsync( - [FromRoute] Guid tagDefinitionId, - [FromBody] Guid[] implicitTagIds) { - - using var db = dbFactory.CreateDbContext(); - using var transaction = await db.Database.BeginTransactionAsync(); - - var tagDefinition = await db.TagDefinitions - .Include(td => td.ImplicitTags) - .FirstOrDefaultAsync(td => td.Guid == tagDefinitionId); - - if(tagDefinition is null) - return NotFound("Tag definition not found"); - - if(tagDefinition.ObjectId < 0) - return BadRequest("Cannot update built-in tag definition"); - - implicitTagIds = implicitTagIds.Distinct().ToArray(); - - var implicitTags = db.TagDefinitions - .Where(td => implicitTagIds.Contains(td.Guid)) - .ToArray(); - - var missingTags = implicitTagIds.Except(implicitTags.Select(td => td.Guid)); - var missingTagsString = string.Join(", ", missingTags.Select(td => td.ToString())); - if(missingTags.Any()) - return BadRequest($"Invalid tag IDs specified: {missingTagsString}"); - - tagDefinition.ImplicitTags.AddRange( - implicitTags.ExceptBy(tagDefinition.ImplicitTags.Select(td => td.Guid), td => td.Guid)); - - var toRemove = tagDefinition.ImplicitTags - .Where(td => !implicitTags.Select(td => td.Guid).Contains(td.Guid)) - .ToArray(); - - foreach(var td in toRemove) - tagDefinition.ImplicitTags.Remove(td); - - await db.SaveChangesAsync(); - await transaction.CommitAsync(); - - return Ok(); - } - - [HttpPost("definition/{tagDefinitionId}/implicit/delete")] - public async Task<IActionResult> DeleteImplicitTagAsync( - [FromRoute] Guid tagDefinitionId, - [FromBody] Guid[] implicitTagIds) { - - using var db = dbFactory.CreateDbContext(); - using var transaction = await db.Database.BeginTransactionAsync(); - - var tagDefinition = await db.TagDefinitions - .Include(td => td.ImplicitTags) - .FirstOrDefaultAsync(td => td.Guid == tagDefinitionId); - - if(tagDefinition is null) - return NotFound("Tag definition not found"); - - if(tagDefinition.ObjectId < 0) - return BadRequest("Cannot update built-in tag definition"); - - implicitTagIds = implicitTagIds.Distinct().ToArray(); - - var missingTagIds = implicitTagIds - .Except(tagDefinition.ImplicitTags.Select(td => td.Guid)); - var missingTagsString = string.Join(", ", missingTagIds.Select(td => td.ToString())); - if(missingTagIds.Any()) - return BadRequest($"Invalid tag IDs specified: {missingTagsString}"); - - var toRemove = tagDefinition.ImplicitTags - .Where(td => !implicitTagIds.Contains(td.Guid)) - .ToArray(); - - foreach(var td in toRemove) - tagDefinition.ImplicitTags.Remove(td); - - await db.SaveChangesAsync(); - await transaction.CommitAsync(); - - return Ok(); - } -} diff --git a/Controllers/ApiUserController.cs b/Controllers/ApiUserController.cs deleted file mode 100644 index d678287..0000000 --- a/Controllers/ApiUserController.cs +++ /dev/null @@ -1,109 +0,0 @@ -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<HBContext> dbFactory; - - public ApiUserController(IDbContextFactory<HBContext> dbFactory) => - this.dbFactory = dbFactory; - - [HttpGet] - public async Task<IActionResult> GetAllUsersAsync() { - using var db = dbFactory.CreateDbContext(); - - return Ok(await db.Users - .Select(u => (ApiModels.User) u) - .ToArrayAsync()); - } - - [HttpGet("{userId}")] - public async Task<IActionResult> 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<IActionResult> 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<IActionResult> 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<IActionResult> 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/LoginController.cs b/Controllers/LoginController.cs deleted file mode 100644 index c93f0d5..0000000 --- a/Controllers/LoginController.cs +++ /dev/null @@ -1,49 +0,0 @@ -using HyperBooru.Services; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Mvc; -using System.Security.Claims; - -namespace HyperBooru.Controllers; - -[ApiController] -[Route("/")] -public class LoginController : Controller { - private IHttpContextAccessor httpContextAccessor; - - public LoginController(IHttpContextAccessor httpContextAccessor) => - this.httpContextAccessor = httpContextAccessor; - - [HttpPost("Login")] - public async Task<IActionResult> Login( - [FromForm] string username, - [FromForm] string password, - HBContext db) { - - var user = db.Users.FirstOrDefault(u => u.Username == username); - if(user is null) - return StatusCode(403); - - var hash = UserService.HashPassword(password); - if(hash != user.PasswordHash) - return StatusCode(403); - - var claims = new Claim[] { - new Claim(ClaimTypes.Name, user.Username), - new Claim("ObjectId", user.ObjectId.ToString()) - }; - - var claimsIdentity = new ClaimsIdentity( - claims, - CookieAuthenticationDefaults.AuthenticationScheme); - - var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); - - await httpContextAccessor.HttpContext!.SignInAsync(claimsPrincipal); - return Ok(); - } - - [HttpPost("Logout")] - public async Task Logout() => - await httpContextAccessor.HttpContext!.SignOutAsync(); -} diff --git a/Controllers/MediaController.cs b/Controllers/MediaController.cs deleted file mode 100644 index 6a9e1fc..0000000 --- a/Controllers/MediaController.cs +++ /dev/null @@ -1,155 +0,0 @@ -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; - private IMediaService mediaService; - private IConfigService config; - private HBContext db; - - private readonly string[] FormatPriority = [ - "image/webp", - "image/png" - ]; - - public MediaController( - IHttpContextAccessor httpContextAccessor, - IMediaService mediaService, - IConfigService config, - HBContext db) { - - this.httpContextAccessor = httpContextAccessor; - this.mediaService = mediaService; - this.config = config; - this.db = db; - } - - [HttpGet("{mediaId}")] - public IActionResult Fetch([FromRoute] Guid mediaId) { - var media = db.Media - .Include(m => m.CurrentUploadedFile) - .First(m => m.Guid == mediaId); - if(media is null) - return NotFound(); - - // Check if the requested media item is a HEIC image and if it is, convert it - // otherwise, return the original file content, unaltered - if(media.CurrentUploadedFile!.MimeType == "image/heic") { - // If the media needs to be converted, check the HTTP request for allowed - // media formats, and convert to the best available format or WebP otherwise - var allowedTypes = httpContextAccessor - .HttpContext? - .Request - .GetTypedHeaders().Accept.Select(h => h.MediaType.ToString()) ?? Array.Empty<string>(); - - var format = FormatPriority.FirstOrDefault(f => allowedTypes.Contains(f)) ?? "image/webp"; - - var fs = mediaService.GetConverted(media, format); - - return new FileStreamResult(fs, format); - } else { - var fs = System.IO.File.OpenRead(mediaService.GetPath(media)); - return new FileStreamResult(fs, media.CurrentUploadedFile!.MimeType); - } - } - - [HttpGet("thumb/{mediaId}")] - public IActionResult Thumbnail( - [FromRoute] Guid mediaId, - [FromQuery(Name = "w")] int? width, - [FromQuery(Name = "h")] int? height) { - - try { - var thumb = mediaService.GetThumbnail(mediaId, width, height); - return new FileStreamResult(thumb, "image/jpeg"); - } catch(ThumbnailException e) { - return BadRequest(e.Message); - } catch(ObjectNotFoundException e) { - return NotFound(e.Message); - } - } - - [HttpDelete("{mediaId}")] - public void Delete([FromRoute] Guid mediaId) { - mediaService.Delete(mediaId); - } - - [HttpPost] - public IActionResult Upload() { - if(Request.Form.Files.Count == 0) - return BadRequest("No files"); - - Media media = new(); - - foreach(var formFile in Request.Form.Files) { - try { - // Parse timestamps from headers - DateTime? lastAccessTime = - formFile.Headers["X-HyperBooru-LastAccessTime"] - .ElementAtOrDefault(0)? - .TryParseDateTimeUtc(); - DateTime? lastWriteTime = - formFile.Headers["X-HyperBooru-LastWriteTime"] - .ElementAtOrDefault(0)? - .TryParseDateTimeUtc(); - DateTime? createTime = - formFile.Headers["X-HyperBooru-CreateTime"] - .ElementAtOrDefault(0)? - .TryParseDateTimeUtc(); - - // Parse original path from headers - string? path = - formFile.Headers["X-HyperBooru-Path"] - .ElementAtOrDefault(0); - - object? pathType = null; - string? pathTypeString = - formFile.Headers["X-HyperBooru-PathType"] - .ElementAtOrDefault(0); - Enum.TryParse(typeof(PathType), pathTypeString, true, out pathType); - - // Parse tag IDs from headers - Guid[]? tagIds = formFile.Headers["X-HyperBooru-Tags"] - .ElementAtOrDefault(0)? - .Split(',') - .Select(t => Guid.Parse(t)) - .ToArray(); - - media = mediaService.Create( - formFile.OpenReadStream(), - formFile.FileName, - formFile.Headers["X-HyperBooru-Checksum"] - .ElementAtOrDefault(0), - lastAccessTime, - lastWriteTime, - createTime, - path, - (PathType?) pathType, - tagIds); - - // Return the GUID of the new media object if requested - bool returnMetadataParsed = bool.TryParse( - formFile.Headers["X-HyperBooru-ReturnMediaId"], out var returnMetadata); - - if(returnMetadataParsed && returnMetadata) - return Content(media.Guid.ToString()); - } catch(MediaCreateException e) { - return BadRequest(e.Message); - } - } - - if(Request.Form.Files.Count == 1) - return Redirect($"/ViewMedia?m={media.Guid}"); - else - return Redirect($"/Gallery"); - } -}
\ No newline at end of file |
