using API.Schema; using API.Schema.Contexts; using API.Schema.Jobs; using API.Schema.MangaConnectors; using Asp.Versioning; using log4net; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using static Microsoft.AspNetCore.Http.StatusCodes; // ReSharper disable InconsistentNaming namespace API.Controllers; [ApiVersion(2)] [ApiController] [Route("v{v:apiVersion}/[controller]")] public class SearchController(PgsqlContext context, ILog Log) : Controller { /// /// Initiate a search for a Manga on a specific Connector /// /// /// /// /// MangaConnector with ID not found /// MangaConnector with ID is disabled /// Error during Database Operation [HttpGet("{MangaConnectorName}/{Query}")] [ProducesResponseType(Status200OK, "application/json")] [ProducesResponseType(Status404NotFound)] [ProducesResponseType(Status406NotAcceptable)] [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult SearchManga(string MangaConnectorName, string Query) { if(context.MangaConnectors.Find(MangaConnectorName) is not { } connector) return NotFound(); else if (connector.Enabled is false) return StatusCode(Status406NotAcceptable); Manga[] mangas = connector.SearchManga(Query); List retMangas = new(); foreach (Manga manga in mangas) { try { if(AddMangaToContext(manga) is { } add) retMangas.Add(add); } catch (DbUpdateException e) { Log.Error(e); return StatusCode(Status500InternalServerError, e.Message); } } return Ok(retMangas.ToArray()); } /// /// Returns Manga from MangaConnector associated with URL /// /// Manga-Page URL /// /// Multiple connectors found for URL /// No Manga at URL /// No connector found for URL /// Error during Database Operation [HttpPost("Url")] [ProducesResponseType(Status200OK, "application/json")] [ProducesResponseType(Status400BadRequest)] [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult GetMangaFromUrl([FromBody]string url) { if (context.MangaConnectors.Find("Global") is not { } connector) return StatusCode(Status500InternalServerError, "Could not find Global Connector."); if(connector.GetMangaFromUrl(url) is not { } manga) return BadRequest(); try { if(AddMangaToContext(manga) is { } add) return Ok(add); return StatusCode(Status500InternalServerError); } catch (DbUpdateException e) { Log.Error(e); return StatusCode(Status500InternalServerError, e.Message); } } private Manga? AddMangaToContext(Manga manga) { context.Mangas.Load(); context.Authors.Load(); context.Tags.Load(); context.MangaConnectors.Load(); IEnumerable mergedTags = manga.MangaTags.Select(mt => { MangaTag? inDb = context.Tags.Find(mt.Tag); return inDb ?? mt; }); manga.MangaTags = mergedTags.ToList(); IEnumerable mergedAuthors = manga.Authors.Select(ma => { Author? inDb = context.Authors.Find(ma.AuthorId); return inDb ?? ma; }); manga.Authors = mergedAuthors.ToList(); try { if (context.Mangas.Find(manga.MangaId) is { } r) { context.Mangas.Remove(r); context.SaveChanges(); } context.Mangas.Add(manga); context.Jobs.Add(new DownloadMangaCoverJob(manga)); context.SaveChanges(); } catch (DbUpdateException e) { Log.Error(e); return null; } return manga; } }