using API.Controllers.DTOs;
using API.Schema.MangaContext;
using Asp.Versioning;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using static Microsoft.AspNetCore.Http.StatusCodes;
using Chapter = API.Controllers.DTOs.Chapter;
// ReSharper disable InconsistentNaming
namespace API.Controllers;
[ApiVersion(2)]
[ApiController]
[Route("v{v:apiVersion}/[controller]")]
public class ChaptersController(MangaContext context) : Controller
{
///
/// Returns all of with
///
/// .Key
///
/// with not found
[HttpGet("{MangaId}")]
[ProducesResponseType>(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
public async Task>, NotFound>> GetChapters(string MangaId)
{
if(await context.Chapters.Include(ch => ch.MangaConnectorIds)
.Where(ch => ch.ParentMangaId == MangaId)
.ToListAsync(HttpContext.RequestAborted)
is not { } dbChapters)
return TypedResults.NotFound(nameof(MangaId));
List chapters = dbChapters.OrderDescending().Select(c =>
{
IEnumerable ids = c.MangaConnectorIds.Select(id =>
new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
return new Chapter(c.Key, c.ParentMangaId, c.VolumeNumber, c.ChapterNumber, c.Title, ids, c.Downloaded, c.FileName);
}).ToList();
return TypedResults.Ok(chapters);
}
///
/// Returns all downloaded for with
///
/// .Key
///
/// with not found.
[HttpGet("{MangaId}/Downloaded")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound, "text/plain")]
public async Task>, NotFound>> GetChaptersDownloaded(string MangaId)
{
if(await context.Chapters.Include(ch => ch.MangaConnectorIds)
.Where(ch => ch.ParentMangaId == MangaId && ch.Downloaded)
.ToListAsync(HttpContext.RequestAborted)
is not { } dbChapters)
return TypedResults.NotFound(nameof(MangaId));
List chapters = dbChapters.OrderDescending().Select(c =>
{
IEnumerable ids = c.MangaConnectorIds.Select(id =>
new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
return new Chapter(c.Key, c.ParentMangaId, c.VolumeNumber, c.ChapterNumber, c.Title, ids, c.Downloaded, c.FileName);
}).ToList();
return TypedResults.Ok(chapters);
}
///
/// Returns all not downloaded for with
///
/// .Key
///
/// with not found.
[HttpGet("{MangaId}/NotDownloaded")]
[ProducesResponseType>(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound, "text/plain")]
public async Task>, NoContent, NotFound>> GetChaptersNotDownloaded(string MangaId)
{
if(await context.Chapters.Include(ch => ch.MangaConnectorIds)
.Where(ch => ch.ParentMangaId == MangaId && ch.Downloaded == false)
.ToListAsync(HttpContext.RequestAborted)
is not { } dbChapters)
return TypedResults.NotFound(nameof(MangaId));
List chapters = dbChapters.OrderDescending().Select(c =>
{
IEnumerable ids = c.MangaConnectorIds.Select(id =>
new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
return new Chapter(c.Key, c.ParentMangaId, c.VolumeNumber, c.ChapterNumber, c.Title, ids, c.Downloaded, c.FileName);
}).ToList();
return TypedResults.Ok(chapters);
}
///
/// Returns the latest of requested
///
/// .Key
///
/// No available chapters
/// with not found.
[HttpGet("{MangaId}/LatestAvailable")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status204NoContent)]
[ProducesResponseType(Status404NotFound, "text/plain")]
public async Task, NoContent, NotFound>> GetLatestChapter(string MangaId)
{
if(await context.Chapters.Include(ch => ch.MangaConnectorIds)
.Where(ch => ch.ParentMangaId == MangaId)
.ToListAsync(HttpContext.RequestAborted)
is not { } dbChapters)
return TypedResults.NotFound(nameof(MangaId));
Schema.MangaContext.Chapter? c = dbChapters.Max();
if (c is null)
return TypedResults.NoContent();
IEnumerable ids = c.MangaConnectorIds.Select(id =>
new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
return TypedResults.Ok(new Chapter(c.Key, c.ParentMangaId, c.VolumeNumber, c.ChapterNumber, c.Title, ids, c.Downloaded, c.FileName));
}
///
/// Returns the latest of requested that is downloaded
///
/// .Key
///
/// No available chapters
/// with not found.
/// Could not retrieve the maximum chapter-number
/// Retry after timeout, updating value
[HttpGet("{MangaId}/LatestDownloaded")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status204NoContent)]
[ProducesResponseType(Status404NotFound, "text/plain")]
[ProducesResponseType(Status412PreconditionFailed)]
[ProducesResponseType(Status503ServiceUnavailable)]
public async Task, NoContent, NotFound, StatusCodeHttpResult>> GetLatestChapterDownloaded(string MangaId)
{
if(await context.Chapters.Include(ch => ch.MangaConnectorIds)
.Where(ch => ch.ParentMangaId == MangaId && ch.Downloaded)
.ToListAsync(HttpContext.RequestAborted)
is not { } dbChapters)
return TypedResults.NotFound(nameof(MangaId));
Schema.MangaContext.Chapter? c = dbChapters.Max();
if (c is null)
return TypedResults.NoContent();
IEnumerable ids = c.MangaConnectorIds.Select(id =>
new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
return TypedResults.Ok(new Chapter(c.Key, c.ParentMangaId, c.VolumeNumber, c.ChapterNumber, c.Title, ids, c.Downloaded, c.FileName));
}
///
/// Configure the cut-off for
///
/// .Key
/// Threshold ( ChapterNumber)
///
/// with not found.
/// Error during Database Operation
[HttpPatch("{MangaId}/IgnoreBefore")]
[ProducesResponseType(Status200OK)]
[ProducesResponseType(Status404NotFound, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
public async Task, InternalServerError>> IgnoreChaptersBefore(string MangaId, [FromBody]float chapterThreshold)
{
if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return TypedResults.NotFound(nameof(MangaId));
manga.IgnoreChaptersBefore = chapterThreshold;
if(await context.Sync(HttpContext.RequestAborted, GetType(), System.Reflection.MethodBase.GetCurrentMethod()?.Name) is { success: false } result)
return TypedResults.InternalServerError(result.exceptionMessage);
return TypedResults.Ok();
}
///
/// Returns with
///
/// .Key
///
/// with not found
[HttpGet("WithId/{ChapterId}")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound, "text/plain")]
public async Task, NotFound>> GetChapter (string ChapterId)
{
if (await context.Chapters.FirstOrDefaultAsync(c => c.Key == ChapterId, HttpContext.RequestAborted) is not { } chapter)
return TypedResults.NotFound(nameof(ChapterId));
IEnumerable ids = chapter.MangaConnectorIds.Select(id =>
new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
return TypedResults.Ok(new Chapter(chapter.Key, chapter.ParentMangaId, chapter.VolumeNumber, chapter.ChapterNumber, chapter.Title,ids, chapter.Downloaded, chapter.FileName));
}
///
/// Returns the with .Key
///
/// Key of
///
/// with not found
[HttpGet("ConnectorId/{MangaConnectorIdId}")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound, "text/plain")]
public async Task, NotFound>> GetChapterMangaConnectorId (string MangaConnectorIdId)
{
if (await context.MangaConnectorToChapter.FirstOrDefaultAsync(c => c.Key == MangaConnectorIdId, HttpContext.RequestAborted) is not { } mcIdManga)
return TypedResults.NotFound(nameof(MangaConnectorIdId));
MangaConnectorId result = new (mcIdManga.Key, mcIdManga.MangaConnectorName, mcIdManga.ObjId, mcIdManga.WebsiteUrl, mcIdManga.UseForDownload);
return TypedResults.Ok(result);
}
}