using API.Schema.MangaContext; using API.Schema.MangaContext.MetadataFetchers; using Asp.Versioning; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; using static Microsoft.AspNetCore.Http.StatusCodes; // ReSharper disable InconsistentNaming namespace API.Controllers; [ApiVersion(2)] [ApiController] [Route("v{v:apiVersion}/[controller]")] public class MetadataFetcherController(MangaContext context) : Controller { /// /// Get all (Metadata-Sites) /// /// Names of (Metadata-Sites) [HttpGet] [ProducesResponseType(Status200OK, "application/json")] public IActionResult GetConnectors() { return Ok(Tranga.MetadataFetchers.Select(m => m.Name).ToArray()); } /// /// Returns all /// /// [HttpGet("Links")] [ProducesResponseType(Status200OK, "application/json")] public IActionResult GetLinkedEntries() { return Ok(context.MetadataEntries.ToArray()); } /// /// Searches (Metadata-Sites) for Manga-Metadata /// /// .Key /// .Name /// Instead of using the for search on Website, use a specific term /// /// (Metadata-Sites) with does not exist /// with not found [HttpPost("{MetadataFetcherName}/SearchManga/{MangaId}")] [ProducesResponseType(Status200OK, "application/json")] [ProducesResponseType(Status400BadRequest)] [ProducesResponseType(Status404NotFound)] public IActionResult SearchMangaMetadata(string MangaId, string MetadataFetcherName, [FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)]string? searchTerm = null) { if(context.Mangas.Find(MangaId) is not { } manga) return NotFound(); if(Tranga.MetadataFetchers.FirstOrDefault(f => f.Name == MetadataFetcherName) is not { } fetcher) return BadRequest(); MetadataSearchResult[] searchResults = searchTerm is null ? fetcher.SearchMetadataEntry(manga) : fetcher.SearchMetadataEntry(searchTerm); return Ok(searchResults); } /// /// Links (Metadata-Sites) using Provider-Specific Identifier to /// /// .Key /// .Name /// -Specific ID /// /// (Metadata-Sites) with does not exist /// with not found /// Error during Database Operation [HttpPost("{MetadataFetcherName}/Link/{MangaId}")] [ProducesResponseType(Status200OK, "application/json")] [ProducesResponseType(Status400BadRequest)] [ProducesResponseType(Status404NotFound)] [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult LinkMangaMetadata(string MangaId, string MetadataFetcherName, [FromBody]string Identifier) { if(context.Mangas.Find(MangaId) is not { } manga) return NotFound(); if(Tranga.MetadataFetchers.FirstOrDefault(f => f.Name == MetadataFetcherName) is not { } fetcher) return BadRequest(); MetadataEntry entry = fetcher.CreateMetadataEntry(manga, Identifier); context.MetadataEntries.Add(entry); if(context.Sync() is { } errorMessage) return StatusCode(Status500InternalServerError, errorMessage); return Ok(entry); } /// /// Un-Links (Metadata-Sites) from /// /// /// (Metadata-Sites) with does not exist /// with not found /// No linking and found /// Error during Database Operation [HttpPost("{MetadataFetcherName}/Unlink/{MangaId}")] [ProducesResponseType(Status200OK)] [ProducesResponseType(Status400BadRequest)] [ProducesResponseType(Status404NotFound)] [ProducesResponseType(Status412PreconditionFailed, "text/plain")] [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult UnlinkMangaMetadata(string MangaId, string MetadataFetcherName) { if(context.Mangas.Find(MangaId) is null) return NotFound(); if(Tranga.MetadataFetchers.FirstOrDefault(f => f.Name == MetadataFetcherName) is null) return BadRequest(); if(context.MetadataEntries.FirstOrDefault(e => e.MangaId == MangaId && e.MetadataFetcherName == MetadataFetcherName) is not { } entry) return StatusCode(Status412PreconditionFailed, "No entry found"); context.Remove(entry); if(context.Sync() is { success: false } result) return StatusCode(Status500InternalServerError, result.exceptionMessage); return Ok(); } }