summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Controllers/ApiMediaController.cs121
-rw-r--r--Server.csproj4
-rw-r--r--Tag.cs4
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>
diff --git a/Tag.cs b/Tag.cs
index 172fe8d..c857c66 100644
--- a/Tag.cs
+++ b/Tag.cs
@@ -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
+}