diff options
| -rw-r--r-- | Controllers/ApiMediaController.cs | 121 | ||||
| -rw-r--r-- | Server.csproj | 4 | ||||
| -rw-r--r-- | Tag.cs | 4 |
3 files changed, 125 insertions, 4 deletions
diff --git a/Controllers/ApiMediaController.cs b/Controllers/ApiMediaController.cs index a324f35..a1b07b1 100644 --- a/Controllers/ApiMediaController.cs +++ b/Controllers/ApiMediaController.cs @@ -97,4 +97,125 @@ public class ApiMediaController : Controller { [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/Server.csproj b/Server.csproj index 14893c7..61c9b6b 100644 --- a/Server.csproj +++ b/Server.csproj @@ -6,9 +6,9 @@ <ImplicitUsings>enable</ImplicitUsings> <AssemblyName>HyperBooru</AssemblyName> <RootNamespace>HyperBooru</RootNamespace> - <AssemblyVersion>0.14.0.0</AssemblyVersion> + <AssemblyVersion>0.15.0.0</AssemblyVersion> <FileVersion>$(AssemblyVersion)</FileVersion> - <Version>0.14-alpha</Version> + <Version>0.15-alpha</Version> <UserSecretsId>2907567f-4640-4581-8f4d-0977952d26bd</UserSecretsId> </PropertyGroup> @@ -11,7 +11,7 @@ public class TagDefinition : HBObject { public TagSource Source { get; set; } = TagSource.Internal; public string? Namespace { get; set; } public string Name { get; set; } - public string? Alias { get; set;} + public string? Alias { get; set; } public virtual List<TagDefinition> ImplicitTags { get; set; } = new(); public static explicit operator ApiModels.TagDefinition(TagDefinition tagDefinition) => new() { @@ -34,4 +34,4 @@ public class Tag : HBObject { public Tag(TagDefinition tagDef) => this.TagDefinition = tagDef; -}
\ No newline at end of file +} |
