using API.Schema.MangaContext;
using API.Schema.MangaContext.MetadataFetchers;
using Asp.Versioning;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
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 MetadataFetcherController(MangaContext context) : Controller
{
///
/// Get all (Metadata-Sites)
///
/// Names of (Metadata-Sites)
[HttpGet]
[ProducesResponseType>(Status200OK, "application/json")]
public Ok> GetConnectors ()
{
return TypedResults.Ok(Tranga.MetadataFetchers.Select(m => m.Name).ToList());
}
///
/// Returns all
///
///
/// Error during Database Operation
[HttpGet("Links")]
[ProducesResponseType>(Status200OK, "application/json")]
[ProducesResponseType(Status500InternalServerError)]
public async Task>, InternalServerError>> GetLinkedEntries ()
{
if (await context.MetadataEntries.ToListAsync() is not { } result)
return TypedResults.InternalServerError();
return TypedResults.Ok(result);
}
///
/// 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, "text/plain")]
public async Task>, BadRequest, NotFound>> SearchMangaMetadata(string MangaId, string MetadataFetcherName, [FromBody (EmptyBodyBehavior = EmptyBodyBehavior.Allow)]string? searchTerm = null)
{
if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return TypedResults.NotFound(nameof(MangaId));
if(Tranga.MetadataFetchers.FirstOrDefault(f => f.Name == MetadataFetcherName) is not { } fetcher)
return TypedResults.BadRequest();
MetadataSearchResult[] searchResults = searchTerm is null ? fetcher.SearchMetadataEntry(manga) : fetcher.SearchMetadataEntry(searchTerm);
return TypedResults.Ok(searchResults.ToList());
}
///
/// 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, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
public async Task, BadRequest, NotFound, InternalServerError>> LinkMangaMetadata (string MangaId, string MetadataFetcherName, [FromBody]string Identifier)
{
if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return TypedResults.NotFound(nameof(MangaId));
if(Tranga.MetadataFetchers.FirstOrDefault(f => f.Name == MetadataFetcherName) is not { } fetcher)
return TypedResults.BadRequest();
MetadataEntry entry = fetcher.CreateMetadataEntry(manga, Identifier);
context.MetadataEntries.Add(entry);
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return TypedResults.InternalServerError(result.exceptionMessage);
return TypedResults.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, "text/plain")]
[ProducesResponseType(Status412PreconditionFailed)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
public async Task, InternalServerError, StatusCodeHttpResult>> UnlinkMangaMetadata (string MangaId, string MetadataFetcherName)
{
if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } _)
return TypedResults.NotFound(nameof(MangaId));
if(Tranga.MetadataFetchers.FirstOrDefault(f => f.Name == MetadataFetcherName) is null)
return TypedResults.BadRequest();
if (context.MetadataEntries.FirstOrDefault(e =>
e.MangaId == MangaId && e.MetadataFetcherName == MetadataFetcherName) is not { } entry)
return TypedResults.StatusCode(Status412PreconditionFailed);
context.Remove(entry);
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return TypedResults.InternalServerError(result.exceptionMessage);
return TypedResults.Ok();
}
}