using API.Schema; using API.Schema.Contexts; using API.Schema.MetadataFetchers; using Asp.Versioning; using log4net; using Microsoft.AspNetCore.Mvc; using static Microsoft.AspNetCore.Http.StatusCodes; // ReSharper disable InconsistentNaming namespace API.Controllers; [ApiVersion(2)] [ApiController] [Route("v{v:apiVersion}/[controller]")] public class MetadataFetcherController(PgsqlContext context, ILog Log) : Controller { /// /// Get all available Connectors (Metadata-Sites) /// /// Names of Metadata-Fetchers [HttpGet] [ProducesResponseType(Status200OK, "application/json")] public IActionResult GetConnectors() { string[] connectors = Tranga.MetadataFetchers.Select(f => f.MetadataFetcherName).ToArray(); return Ok(connectors); } /// /// Returns all Mangas which have a linked Metadata-Provider /// /// [HttpGet("Links")] [ProducesResponseType(Status200OK, "application/json")] public IActionResult GetLinkedEntries() { return Ok(context.MetadataEntries.ToArray()); } /// /// Tries linking a Manga to a Metadata-Provider-Site /// /// /// Metadata-fetcher with Name does not exist /// Manga with ID not found /// Could not find Entry on Metadata-Provider for Manga /// Error during Database Operation [HttpPost("{MetadataFetcherName}/{MangaId}/TryLink")] [ProducesResponseType(Status200OK, "application/json")] [ProducesResponseType(Status400BadRequest)] [ProducesResponseType(Status404NotFound)] [ProducesResponseType(Status417ExpectationFailed)] [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult LinkMangaToMetadataFetcher(string MangaId, string MetadataFetcherName) { if(context.Mangas.Find(MangaId) is not { } manga) return NotFound(); if(Tranga.MetadataFetchers.FirstOrDefault(f => f.MetadataFetcherName == MetadataFetcherName) is not { } fetcher) return BadRequest(); if (!fetcher.TryGetMetadataEntry(manga, out MetadataEntry? entry)) { return StatusCode(Status417ExpectationFailed, "Metadata entry not found"); } try { //Unlink previous metadata-entries IQueryable metadataEntries = context.MetadataEntries.Where(e => e.MangaId == MangaId); context.MetadataEntries.RemoveRange(metadataEntries); //Add new metadata-entry context.MetadataEntries.Add(entry); context.SaveChanges(); return Ok(entry); } catch (Exception e) { Log.Error(e); return StatusCode(500, e.Message); } } /// /// Tries linking a Manga to a Metadata-Provider-Site /// /// /// Manga has no linked entry with MetadataFetcher /// Error during Database Operation [HttpPost("{MetadataFetcherName}/{MangaId}/UpdateMetadata")] [ProducesResponseType(Status200OK)] [ProducesResponseType(Status400BadRequest)] [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult UpdateMetadata(string MangaId, string MetadataFetcherName) { if(context.MetadataEntries.Find(MangaId, MetadataFetcherName) is not { } entry) return BadRequest(); MetadataFetcher fetcher = Tranga.MetadataFetchers.FirstOrDefault(f => f.MetadataFetcherName == MetadataFetcherName)!; try { fetcher.UpdateMetadata(entry, context); } catch (Exception e) { Log.Error(e); return StatusCode(500, e.Message); } return Ok(); } }