diff --git a/API/Controllers/DTOs/AltTitle.cs b/API/Controllers/DTOs/AltTitle.cs
new file mode 100644
index 0000000..bb06267
--- /dev/null
+++ b/API/Controllers/DTOs/AltTitle.cs
@@ -0,0 +1,24 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+
+namespace API.Controllers.DTOs;
+
+///
+/// DTO
+///
+public sealed record AltTitle(string Language, string Title)
+{
+ ///
+ /// Language of the Title
+ ///
+ [Required]
+ [Description("Language of the Title")]
+ public string Language { get; init; } = Language;
+
+ ///
+ /// Title
+ ///
+ [Required]
+ [Description("Title")]
+ public string Title { get; init; } = Title;
+}
\ No newline at end of file
diff --git a/API/Controllers/DTOs/Author.cs b/API/Controllers/DTOs/Author.cs
new file mode 100644
index 0000000..0e2403b
--- /dev/null
+++ b/API/Controllers/DTOs/Author.cs
@@ -0,0 +1,17 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+
+namespace API.Controllers.DTOs;
+
+///
+/// The DTO
+///
+public record Author(string Key, string Name) : Identifiable(Key)
+{
+ ///
+ /// Name of the Author.
+ ///
+ [Required]
+ [Description("Name of the Author.")]
+ public string Name { get; init; } = Name;
+}
\ No newline at end of file
diff --git a/API/Controllers/DTOs/Chapter.cs b/API/Controllers/DTOs/Chapter.cs
new file mode 100644
index 0000000..aab2860
--- /dev/null
+++ b/API/Controllers/DTOs/Chapter.cs
@@ -0,0 +1,52 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+
+namespace API.Controllers.DTOs;
+
+///
+/// DTO
+///
+public record Chapter(string Key, string MangaId, int? Volume, string ChapterNumber, string? Title, IEnumerable MangaConnectorIds, bool Downloaded) : Identifiable(Key)
+{
+ ///
+ /// Identifier of the Manga this Chapter belongs to
+ ///
+ [Required]
+ [Description("Identifier of the Manga this Chapter belongs to")]
+ public string MangaId { get; init; } = MangaId;
+
+ ///
+ /// Volume number
+ ///
+ [Required]
+ [Description("Volume number")]
+ public int? Volume { get; init; } = Volume;
+
+ ///
+ /// Chapter number
+ ///
+ [Required]
+ [Description("Chapter number")]
+ public string ChapterNumber { get; init; } = ChapterNumber;
+
+ ///
+ /// Title of the Chapter
+ ///
+ [Required]
+ [Description("Title of the Chapter")]
+ public string? Title { get; init; } = Title;
+
+ ///
+ /// Whether Chapter is Downloaded (on disk)
+ ///
+ [Required]
+ [Description("Whether Chapter is Downloaded (on disk)")]
+ public bool Downloaded { get; init; } = Downloaded;
+
+ ///
+ /// Ids of the Manga on MangaConnectors
+ ///
+ [Required]
+ [Description("Ids of the Manga on MangaConnectors")]
+ public IEnumerable MangaConnectorIds { get; init; } = MangaConnectorIds;
+}
\ No newline at end of file
diff --git a/API/Controllers/DTOs/Identifiable.cs b/API/Controllers/DTOs/Identifiable.cs
new file mode 100644
index 0000000..4d20ab2
--- /dev/null
+++ b/API/Controllers/DTOs/Identifiable.cs
@@ -0,0 +1,18 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+
+namespace API.Controllers.DTOs;
+
+///
+///
+///
+public record Identifiable(string Key)
+{
+ ///
+ /// Unique Identifier of the DTO
+ ///
+ [Required]
+ [Description("Unique Identifier of the DTO")]
+ [StringLength(TokenGen.MaximumLength, MinimumLength = TokenGen.MinimumLength)]
+ public string Key { get; init; } = Key;
+}
\ No newline at end of file
diff --git a/API/Controllers/DTOs/Link.cs b/API/Controllers/DTOs/Link.cs
new file mode 100644
index 0000000..0ed1439
--- /dev/null
+++ b/API/Controllers/DTOs/Link.cs
@@ -0,0 +1,25 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+
+namespace API.Controllers.DTOs;
+
+
+///
+/// DTO
+///
+public sealed record Link(string Key, string Provider, string Url) : Identifiable(Key)
+{
+ ///
+ /// Name of the Provider
+ ///
+ [Required]
+ [Description("Name of the Provider")]
+ public string Provider { get; init; } = Provider;
+
+ ///
+ /// Url
+ ///
+ [Required]
+ [Description("Url")]
+ public string Url { get; init; } = Url;
+}
\ No newline at end of file
diff --git a/API/Controllers/DTOs/Manga.cs b/API/Controllers/DTOs/Manga.cs
new file mode 100644
index 0000000..587e1b2
--- /dev/null
+++ b/API/Controllers/DTOs/Manga.cs
@@ -0,0 +1,66 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using API.Schema.MangaContext;
+
+namespace API.Controllers.DTOs;
+
+///
+/// DTO
+///
+public record Manga(string Key, string Name, string Description, MangaReleaseStatus ReleaseStatus, IEnumerable MangaConnectorIds, float IgnoreChaptersBefore, uint? Year, string? OriginalLanguage, IEnumerable ChapterIds, IEnumerable Authors, IEnumerable Tags, IEnumerable Links, IEnumerable AltTitles)
+ : MinimalManga(Key, Name, Description, ReleaseStatus, MangaConnectorIds)
+{
+ ///
+ /// Chapter cutoff for Downloads (Chapters before this will not be downloaded)
+ ///
+ [Required]
+ [Description("Chapter cutoff for Downloads (Chapters before this will not be downloaded)")]
+ public float IgnoreChaptersBefore { get; init; } = IgnoreChaptersBefore;
+
+ ///
+ /// Release Year
+ ///
+ [Description("Release Year")]
+ public uint? Year { get; init; } = Year;
+
+ ///
+ /// Release Language
+ ///
+ [Description("Release Language")]
+ public string? OriginalLanguage { get; init; } = OriginalLanguage;
+
+ ///
+ /// Keys of ChapterDTOs
+ ///
+ [Required]
+ [Description("Keys of ChapterDTOs")]
+ public IEnumerable ChapterIds { get; init; } = ChapterIds;
+
+ ///
+ /// Author-names
+ ///
+ [Required]
+ [Description("Author-names")]
+ public IEnumerable Authors { get; init; } = Authors;
+
+ ///
+ /// Manga Tags
+ ///
+ [Required]
+ [Description("Manga Tags")]
+ public IEnumerable Tags { get; init; } = Tags;
+
+ ///
+ /// Links for more Metadata
+ ///
+ [Required]
+ [Description("Links for more Metadata")]
+ public IEnumerable Links { get; init; } = Links;
+
+ ///
+ /// Alt Titles of Manga
+ ///
+ [Required]
+ [Description("Alt Titles of Manga")]
+ public IEnumerable AltTitles { get; init; } = AltTitles;
+}
\ No newline at end of file
diff --git a/API/Controllers/DTOs/MangaConnectorId.cs b/API/Controllers/DTOs/MangaConnectorId.cs
new file mode 100644
index 0000000..b9c4892
--- /dev/null
+++ b/API/Controllers/DTOs/MangaConnectorId.cs
@@ -0,0 +1,38 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using API.Schema.MangaContext;
+
+namespace API.Controllers.DTOs;
+
+///
+/// DTO
+///
+public sealed record MangaConnectorId(string Key, string MangaConnectorName, string ForeignKey, string? WebsiteUrl, bool UseForDownload) : Identifiable(Key)
+{
+ ///
+ /// Name of the Connector
+ ///
+ [Required]
+ [Description("Name of the Connector")]
+ public string MangaConnectorName { get; init; } = MangaConnectorName;
+
+ ///
+ /// Key of the referenced DTO
+ ///
+ [Required]
+ [Description("Key of the referenced DTO")]
+ public string ForeignKey { get; init; } = ForeignKey;
+
+ ///
+ /// Website Link for reference, if any
+ ///
+ [Description("Website Link for reference, if any")]
+ public string? WebsiteUrl { get; init; } = WebsiteUrl;
+
+ ///
+ /// Whether this Link is used for downloads
+ ///
+ [Required]
+ [Description("Whether this Link is used for downloads")]
+ public bool UseForDownload { get; init; } = UseForDownload;
+}
\ No newline at end of file
diff --git a/API/Controllers/DTOs/MinimalManga.cs b/API/Controllers/DTOs/MinimalManga.cs
index 32e4ad8..72e778a 100644
--- a/API/Controllers/DTOs/MinimalManga.cs
+++ b/API/Controllers/DTOs/MinimalManga.cs
@@ -1,21 +1,39 @@
+using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using API.Schema.MangaContext;
-using Newtonsoft.Json;
namespace API.Controllers.DTOs;
-public sealed record MinimalManga(string Key, string Name, string Description, MangaReleaseStatus ReleaseStatus, IEnumerable>? MangaConnectorIds = null)
+///
+/// Shortened Version of
+///
+public record MinimalManga(string Key, string Name, string Description, MangaReleaseStatus ReleaseStatus, IEnumerable MangaConnectorIds) : Identifiable(Key)
{
- [Required] [StringLength(TokenGen.MaximumLength, MinimumLength = TokenGen.MinimumLength)]
- public string Key { get; init; } = Key;
+ ///
+ /// Name of the Manga
+ ///
[Required]
- [JsonRequired]
+ [Description("Name of the Manga")]
public string Name { get; init; } = Name;
+
+ ///
+ /// Description of the Manga
+ ///
[Required]
- [JsonRequired]
+ [Description("Description of the Manga")]
public string Description { get; init; } = Description;
+
+ ///
+ /// ReleaseStatus of the Manga
+ ///
[Required]
- [JsonRequired]
+ [Description("ReleaseStatus of the Manga")]
public MangaReleaseStatus ReleaseStatus { get; init; } = ReleaseStatus;
- public IEnumerable>? MangaConnectorIds { get; init; } = MangaConnectorIds;
+
+ ///
+ /// Ids of the Manga on MangaConnectors
+ ///
+ [Required]
+ [Description("Ids of the Manga on MangaConnectors")]
+ public IEnumerable MangaConnectorIds { get; init; } = MangaConnectorIds;
}
\ No newline at end of file
diff --git a/API/Controllers/DTOs/PeriodicWorker.cs b/API/Controllers/DTOs/PeriodicWorker.cs
new file mode 100644
index 0000000..4433618
--- /dev/null
+++ b/API/Controllers/DTOs/PeriodicWorker.cs
@@ -0,0 +1,33 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using API.Workers;
+
+namespace API.Controllers.DTOs;
+
+///
+/// DTO ( )
+///
+public sealed record PeriodicWorker(string Key, IEnumerable Dependencies, IEnumerable MissingDependencies, bool DependenciesFulfilled, WorkerExecutionState State, DateTime LastExecution, TimeSpan Interval, DateTime NextExecution)
+ : Worker(Key, Dependencies, MissingDependencies, DependenciesFulfilled, State)
+{
+ ///
+ /// Timestamp when Worker executed last.
+ ///
+ [Required]
+ [Description("Timestamp when Worker executed last.")]
+ public DateTime LastExecution { get; init; } = LastExecution;
+
+ ///
+ /// Interval at which Worker runs.
+ ///
+ [Required]
+ [Description("Interval at which Worker runs.")]
+ public TimeSpan Interval { get; init; } = Interval;
+
+ ///
+ /// Timestamp when Worker is scheduled to execute next.
+ ///
+ [Required]
+ [Description("Timestamp when Worker is scheduled to execute next.")]
+ public DateTime NextExecution { get; init; } = LastExecution;
+}
\ No newline at end of file
diff --git a/API/Controllers/DTOs/Worker.cs b/API/Controllers/DTOs/Worker.cs
new file mode 100644
index 0000000..8f9292c
--- /dev/null
+++ b/API/Controllers/DTOs/Worker.cs
@@ -0,0 +1,39 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using API.Workers;
+
+namespace API.Controllers.DTOs;
+
+///
+/// DTO
+///
+public record Worker(string Key, IEnumerable Dependencies, IEnumerable MissingDependencies, bool DependenciesFulfilled, WorkerExecutionState State) : Identifiable(Key)
+{
+ ///
+ /// Workers this worker depends on having ran.
+ ///
+ [Required]
+ [Description("Workers this worker depends on having ran.")]
+ public IEnumerable Dependencies { get; init; } = Dependencies;
+
+ ///
+ /// Workers that have not yet ran, that need to run for this Worker to run.
+ ///
+ [Required]
+ [Description("Workers that have not yet ran, that need to run for this Worker to run.")]
+ public IEnumerable MissingDependencies { get; init; } = MissingDependencies;
+
+ ///
+ /// Worker can run.
+ ///
+ [Required]
+ [Description("Worker can run.")]
+ public bool DependenciesFulfilled { get; init; } = DependenciesFulfilled;
+
+ ///
+ /// Execution state of the Worker.
+ ///
+ [Required]
+ [Description("Execution state of the Worker.")]
+ public WorkerExecutionState State { get; init; } = State;
+}
\ No newline at end of file
diff --git a/API/Controllers/FileLibraryController.cs b/API/Controllers/FileLibraryController.cs
index bd9df1d..fba8910 100644
--- a/API/Controllers/FileLibraryController.cs
+++ b/API/Controllers/FileLibraryController.cs
@@ -1,5 +1,6 @@
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;
@@ -19,11 +20,12 @@ public class FileLibraryController(MangaContext context) : Controller
/// Error during Database Operation
[HttpGet]
[ProducesResponseType(Status200OK, "application/json")]
- public async Task GetFileLibraries ()
+ [ProducesResponseType(Status500InternalServerError)]
+ public async Task>, InternalServerError>> GetFileLibraries ()
{
- if(await context.FileLibraries.ToArrayAsync(HttpContext.RequestAborted) is not { } result)
- return StatusCode(Status500InternalServerError);
- return Ok(result);
+ if (await context.FileLibraries.ToListAsync(HttpContext.RequestAborted) is not { } result)
+ return TypedResults.InternalServerError();
+ return TypedResults.Ok(result);
}
///
@@ -34,13 +36,13 @@ public class FileLibraryController(MangaContext context) : Controller
/// with not found.
[HttpGet("{FileLibraryId}")]
[ProducesResponseType(Status200OK, "application/json")]
- [ProducesResponseType(Status404NotFound)]
- public async Task GetFileLibrary (string FileLibraryId)
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ public async Task, NotFound>> GetFileLibrary (string FileLibraryId)
{
if(await context.FileLibraries.FirstOrDefaultAsync(l => l.Key == FileLibraryId, HttpContext.RequestAborted) is not { } library)
- return NotFound();
+ return TypedResults.NotFound(nameof(FileLibraryId));
- return Ok(library);
+ return TypedResults.Ok(library);
}
///
@@ -53,19 +55,19 @@ public class FileLibraryController(MangaContext context) : Controller
/// Error during Database Operation
[HttpPatch("{FileLibraryId}/ChangeBasePath")]
[ProducesResponseType(Status200OK)]
- [ProducesResponseType(Status404NotFound)]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task ChangeLibraryBasePath (string FileLibraryId, [FromBody]string newBasePath)
+ public async Task, InternalServerError>> ChangeLibraryBasePath (string FileLibraryId, [FromBody]string newBasePath)
{
if(await context.FileLibraries.FirstOrDefaultAsync(l => l.Key == FileLibraryId, HttpContext.RequestAborted) is not { } library)
- return NotFound();
+ return TypedResults.NotFound(nameof(FileLibraryId));
//TODO Path check
library.BasePath = newBasePath;
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
- return StatusCode(Status500InternalServerError, result.exceptionMessage);
- return Ok();
+ return TypedResults.InternalServerError(result.exceptionMessage);
+ return TypedResults.Ok();
}
///
@@ -78,39 +80,39 @@ public class FileLibraryController(MangaContext context) : Controller
/// Error during Database Operation
[HttpPatch("{FileLibraryId}/ChangeName")]
[ProducesResponseType(Status200OK)]
- [ProducesResponseType(Status404NotFound)]
- [ProducesResponseType(Status400BadRequest)]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task ChangeLibraryName (string FileLibraryId, [FromBody] string newName)
+ public async Task, InternalServerError>> ChangeLibraryName (string FileLibraryId, [FromBody] string newName)
{
if(await context.FileLibraries.FirstOrDefaultAsync(l => l.Key == FileLibraryId, HttpContext.RequestAborted) is not { } library)
- return NotFound();
+ return TypedResults.NotFound(nameof(FileLibraryId));
//TODO Name check
library.LibraryName = newName;
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
- return StatusCode(Status500InternalServerError, result.exceptionMessage);
- return Ok();
+ return TypedResults.InternalServerError(result.exceptionMessage);
+ return TypedResults.Ok();
}
///
/// Creates new
///
/// New to add
- ///
+ /// Key of new Library
/// Error during Database Operation
[HttpPut]
- [ProducesResponseType(Status201Created)]
+ [ProducesResponseType(Status201Created, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task CreateNewLibrary ([FromBody]FileLibrary library)
+ public async Task, InternalServerError>> CreateNewLibrary ([FromBody]FileLibrary library)
{
//TODO Parameter check
context.FileLibraries.Add(library);
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
- return StatusCode(Status500InternalServerError, result.exceptionMessage);
- return Created();
+ return TypedResults.InternalServerError(result.exceptionMessage);
+
+ return TypedResults.Created(string.Empty, library.Key);
}
///
@@ -118,20 +120,21 @@ public class FileLibraryController(MangaContext context) : Controller
///
/// .Key
///
+ /// with not found.
/// Error during Database Operation
[HttpDelete("{FileLibraryId}")]
[ProducesResponseType(Status200OK)]
- [ProducesResponseType(Status404NotFound)]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task DeleteLocalLibrary (string FileLibraryId)
+ public async Task, InternalServerError>> DeleteLocalLibrary (string FileLibraryId)
{
if(await context.FileLibraries.FirstOrDefaultAsync(l => l.Key == FileLibraryId, HttpContext.RequestAborted) is not { } library)
- return NotFound();
+ return TypedResults.NotFound(nameof(FileLibraryId));
context.FileLibraries.Remove(library);
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
- return StatusCode(Status500InternalServerError, result.exceptionMessage);
- return Ok();
+ return TypedResults.InternalServerError(result.exceptionMessage);
+ return TypedResults.Ok();
}
}
\ No newline at end of file
diff --git a/API/Controllers/LibraryConnectorController.cs b/API/Controllers/LibraryConnectorController.cs
index f2865fa..389771b 100644
--- a/API/Controllers/LibraryConnectorController.cs
+++ b/API/Controllers/LibraryConnectorController.cs
@@ -1,6 +1,7 @@
using API.Schema.LibraryContext;
using API.Schema.LibraryContext.LibraryConnectors;
using Asp.Versioning;
+using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using static Microsoft.AspNetCore.Http.StatusCodes;
@@ -19,13 +20,13 @@ public class LibraryConnectorController(LibraryContext context) : Controller
///
/// Error during Database Operation
[HttpGet]
- [ProducesResponseType(Status200OK, "application/json")]
- public async Task GetAllConnectors ()
+ [ProducesResponseType>(Status200OK, "application/json")]
+ public async Task>, InternalServerError>> GetAllConnectors ()
{
- if (await context.LibraryConnectors.ToArrayAsync(HttpContext.RequestAborted) is not { } connectors)
- return StatusCode(Status500InternalServerError);
+ if (await context.LibraryConnectors.ToListAsync(HttpContext.RequestAborted) is not { } connectors)
+ return TypedResults.InternalServerError();
- return Ok(connectors);
+ return TypedResults.Ok(connectors);
}
///
@@ -36,13 +37,13 @@ public class LibraryConnectorController(LibraryContext context) : Controller
/// with not found.
[HttpGet("{LibraryConnectorId}")]
[ProducesResponseType(Status200OK, "application/json")]
- [ProducesResponseType(Status404NotFound)]
- public async Task GetConnector (string LibraryConnectorId)
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ public async Task, NotFound>> GetConnector (string LibraryConnectorId)
{
if (await context.LibraryConnectors.FirstOrDefaultAsync(l => l.Key == LibraryConnectorId) is not { } connector)
- return NotFound();
+ return TypedResults.NotFound(nameof(LibraryConnectorId));
- return Ok(connector);
+ return TypedResults.Ok(connector);
}
///
@@ -52,16 +53,15 @@ public class LibraryConnectorController(LibraryContext context) : Controller
///
/// Error during Database Operation
[HttpPut]
- [ProducesResponseType(Status201Created)]
+ [ProducesResponseType(Status201Created, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task CreateConnector ([FromBody]LibraryConnector libraryConnector)
+ public async Task, InternalServerError>> CreateConnector ([FromBody]LibraryConnector libraryConnector)
{
-
context.LibraryConnectors.Add(libraryConnector);
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
- return StatusCode(Status500InternalServerError, result.exceptionMessage);
- return Created();
+ return TypedResults.InternalServerError(result.exceptionMessage);
+ return TypedResults.Created(string.Empty, libraryConnector.Key);
}
///
@@ -73,17 +73,17 @@ public class LibraryConnectorController(LibraryContext context) : Controller
/// Error during Database Operation
[HttpDelete("{LibraryConnectorId}")]
[ProducesResponseType(Status200OK)]
- [ProducesResponseType(Status404NotFound)]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task DeleteConnector (string LibraryConnectorId)
+ public async Task, InternalServerError>> DeleteConnector (string LibraryConnectorId)
{
if (await context.LibraryConnectors.FirstOrDefaultAsync(l => l.Key == LibraryConnectorId) is not { } connector)
- return NotFound();
+ return TypedResults.NotFound(nameof(LibraryConnectorId));
context.LibraryConnectors.Remove(connector);
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
- return StatusCode(Status500InternalServerError, result.exceptionMessage);
- return Ok();
+ return TypedResults.InternalServerError(result.exceptionMessage);
+ return TypedResults.Ok();
}
}
\ No newline at end of file
diff --git a/API/Controllers/MaintenanceController.cs b/API/Controllers/MaintenanceController.cs
index caab816..2611984 100644
--- a/API/Controllers/MaintenanceController.cs
+++ b/API/Controllers/MaintenanceController.cs
@@ -1,6 +1,7 @@
using API.MangaConnectors;
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;
@@ -21,18 +22,18 @@ public class MaintenanceController(MangaContext mangaContext) : Controller
[HttpPost("CleanupNoDownloadManga")]
[ProducesResponseType(Status200OK)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task CleanupNoDownloadManga()
+ public async Task>> CleanupNoDownloadManga()
{
if (await mangaContext.Mangas
.Include(m => m.MangaConnectorIds)
.Where(m => !m.MangaConnectorIds.Any(id => id.UseForDownload))
.ToArrayAsync(HttpContext.RequestAborted) is not { } noDownloads)
- return StatusCode(Status500InternalServerError);
+ return TypedResults.InternalServerError("Could not fetch Manga");
mangaContext.Mangas.RemoveRange(noDownloads);
if(await mangaContext.Sync(HttpContext.RequestAborted) is { success: false } result)
- return StatusCode(Status500InternalServerError, result.exceptionMessage);
- return Ok();
+ return TypedResults.InternalServerError(result.exceptionMessage);
+ return TypedResults.Ok();
}
}
\ No newline at end of file
diff --git a/API/Controllers/MangaConnectorController.cs b/API/Controllers/MangaConnectorController.cs
index b04a0f6..faf7fa9 100644
--- a/API/Controllers/MangaConnectorController.cs
+++ b/API/Controllers/MangaConnectorController.cs
@@ -1,6 +1,7 @@
using API.MangaConnectors;
using API.Schema.MangaContext;
using Asp.Versioning;
+using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using static Microsoft.AspNetCore.Http.StatusCodes;
// ReSharper disable InconsistentNaming
@@ -17,10 +18,10 @@ public class MangaConnectorController(MangaContext context) : Controller
///
/// Names of (Scanlation-Sites)
[HttpGet]
- [ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetConnectors()
+ [ProducesResponseType>(Status200OK, "application/json")]
+ public Ok> GetConnectors()
{
- return Ok(Tranga.MangaConnectors.ToArray());
+ return TypedResults.Ok(Tranga.MangaConnectors.ToList());
}
///
@@ -31,13 +32,13 @@ public class MangaConnectorController(MangaContext context) : Controller
/// (Scanlation-Sites) with Name not found.
[HttpGet("{MangaConnectorName}")]
[ProducesResponseType(Status200OK, "application/json")]
- [ProducesResponseType(Status404NotFound)]
- public IActionResult GetConnector(string MangaConnectorName)
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ public Results, NotFound> GetConnector(string MangaConnectorName)
{
if(Tranga.MangaConnectors.FirstOrDefault(c => c.Name.Equals(MangaConnectorName, StringComparison.InvariantCultureIgnoreCase)) is not { } connector)
- return NotFound();
+ return TypedResults.NotFound(nameof(MangaConnectorName));
- return Ok(connector);
+ return TypedResults.Ok(connector);
}
///
@@ -45,10 +46,10 @@ public class MangaConnectorController(MangaContext context) : Controller
///
///
[HttpGet("Enabled")]
- [ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetEnabledConnectors()
+ [ProducesResponseType>(Status200OK, "application/json")]
+ public Ok> GetEnabledConnectors()
{
- return Ok(Tranga.MangaConnectors.Where(c => c.Enabled).ToArray());
+ return TypedResults.Ok(Tranga.MangaConnectors.Where(c => c.Enabled).ToList());
}
///
@@ -56,11 +57,11 @@ public class MangaConnectorController(MangaContext context) : Controller
///
///
[HttpGet("Disabled")]
- [ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetDisabledConnectors()
+ [ProducesResponseType>(Status200OK, "application/json")]
+ public Ok> GetDisabledConnectors()
{
- return Ok(Tranga.MangaConnectors.Where(c => c.Enabled == false).ToArray());
+ return TypedResults.Ok(Tranga.MangaConnectors.Where(c => c.Enabled == false).ToList());
}
///
@@ -68,22 +69,22 @@ public class MangaConnectorController(MangaContext context) : Controller
///
/// .Name
/// Set true to enable, false to disable
- ///
+ ///
/// (Scanlation-Sites) with Name not found.
/// Error during Database Operation
[HttpPatch("{MangaConnectorName}/SetEnabled/{Enabled}")]
- [ProducesResponseType(Status202Accepted)]
- [ProducesResponseType(Status404NotFound)]
+ [ProducesResponseType(Status200OK)]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task SetEnabled(string MangaConnectorName, bool Enabled)
+ public async Task, InternalServerError>> SetEnabled(string MangaConnectorName, bool Enabled)
{
if(Tranga.MangaConnectors.FirstOrDefault(c => c.Name.Equals(MangaConnectorName, StringComparison.InvariantCultureIgnoreCase)) is not { } connector)
- return NotFound();
+ return TypedResults.NotFound(nameof(MangaConnectorName));
connector.Enabled = Enabled;
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
- return StatusCode(Status500InternalServerError, result.exceptionMessage);
- return Accepted();
+ return TypedResults.InternalServerError(result.exceptionMessage);
+ return TypedResults.Ok();
}
}
\ No newline at end of file
diff --git a/API/Controllers/MangaController.cs b/API/Controllers/MangaController.cs
index 006ff2d..f6b5180 100644
--- a/API/Controllers/MangaController.cs
+++ b/API/Controllers/MangaController.cs
@@ -3,6 +3,7 @@ using API.MangaConnectors;
using API.Schema.MangaContext;
using API.Workers;
using Asp.Versioning;
+using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
@@ -12,6 +13,12 @@ using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
using static Microsoft.AspNetCore.Http.StatusCodes;
+using AltTitle = API.Controllers.DTOs.AltTitle;
+using Author = API.Controllers.DTOs.Author;
+using Chapter = API.Controllers.DTOs.Chapter;
+using Link = API.Controllers.DTOs.Link;
+using Manga = API.Controllers.DTOs.Manga;
+
// ReSharper disable InconsistentNaming
namespace API.Controllers;
@@ -23,86 +30,114 @@ public class MangaController(MangaContext context) : Controller
{
///
- /// Returns all cached
+ /// Returns all cached
///
- /// exert of . Use for more information
+ /// exert of . Use for more information
/// Error during Database Operation
[HttpGet]
- [ProducesResponseType(Status200OK, "application/json")]
- public async Task GetAllManga ()
+ [ProducesResponseType>(Status200OK, "application/json")]
+ [ProducesResponseType(Status500InternalServerError)]
+ public async Task>, InternalServerError>> GetAllManga ()
{
- if(await context.Mangas.ToArrayAsync(HttpContext.RequestAborted) is not { } result)
- return StatusCode(Status500InternalServerError);
+ if (await context.Mangas.Include(m => m.MangaConnectorIds).ToArrayAsync(HttpContext.RequestAborted) is not
+ { } result)
+ return TypedResults.InternalServerError();
- return Ok(result.Select(m => new MinimalManga(m.Key, m.Name, m.Description, m.ReleaseStatus)));
+ return TypedResults.Ok(result.Select(m =>
+ {
+ IEnumerable ids = m.MangaConnectorIds.Select(id => new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
+ return new MinimalManga(m.Key, m.Name, m.Description, m.ReleaseStatus, ids);
+ }).ToList());
}
///
- /// Returns all cached .Keys
+ /// Returns all cached .Keys
///
- /// Keys/IDs
+ /// Keys/IDs
/// Error during Database Operation
[HttpGet("Keys")]
[ProducesResponseType(Status200OK, "application/json")]
- public async Task GetAllMangaKeys ()
+ [ProducesResponseType(Status500InternalServerError)]
+ public async Task, InternalServerError>> GetAllMangaKeys ()
{
- if(await context.Mangas.Select(m => m.Key).ToArrayAsync(HttpContext.RequestAborted) is not { } result)
- return StatusCode(Status500InternalServerError);
+ if (await context.Mangas.Select(m => m.Key).ToArrayAsync(HttpContext.RequestAborted) is not { } result)
+ return TypedResults.InternalServerError();
- return Ok(result);
+ return TypedResults.Ok(result);
}
///
- /// Returns all that are being downloaded from at least one
+ /// Returns all that are being downloaded from at least one
///
- /// exert of . Use for more information
+ /// exert of . Use for more information
/// Error during Database Operation
[HttpGet("Downloading")]
[ProducesResponseType(Status200OK, "application/json")]
- public async Task GetMangaDownloading ()
+ [ProducesResponseType(Status500InternalServerError)]
+ public async Task>, InternalServerError>> GetMangaDownloading()
{
- if(await context.Mangas
- .Include(m => m.MangaConnectorIds)
- .Where(m => m.MangaConnectorIds.Any(id => id.UseForDownload))
- .ToArrayAsync(HttpContext.RequestAborted) is not { } result)
- return StatusCode(Status500InternalServerError);
+ if (await context.Mangas
+ .Include(m => m.MangaConnectorIds)
+ .Where(m => m.MangaConnectorIds.Any(id => id.UseForDownload))
+ .ToArrayAsync(HttpContext.RequestAborted) is not { } result)
+ return TypedResults.InternalServerError();
- return Ok(result.Select(m => new MinimalManga(m.Key, m.Name, m.Description, m.ReleaseStatus, m.MangaConnectorIds)));
+ return TypedResults.Ok(result.Select(m =>
+ {
+ IEnumerable ids = m.MangaConnectorIds.Select(id => new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
+ return new MinimalManga(m.Key, m.Name, m.Description, m.ReleaseStatus, ids);
+ }).ToList());
}
///
- /// Returns all cached with
+ /// Returns all cached with
///
- /// Array of .Key
- ///
+ /// Array of .Key
+ ///
/// Error during Database Operation
[HttpPost("WithIDs")]
- [ProducesResponseType(Status200OK, "application/json")]
- public async Task GetMangaWithIds ([FromBody]string[] MangaIds)
+ [ProducesResponseType>(Status200OK, "application/json")]
+ [ProducesResponseType(Status500InternalServerError)]
+ public async Task>, InternalServerError>> GetMangaWithIds ([FromBody]string[] MangaIds)
{
- if(await context.MangaIncludeAll()
- .Where(m => MangaIds.Contains(m.Key))
- .ToArrayAsync(HttpContext.RequestAborted) is not { } result)
- return StatusCode(Status500InternalServerError);
+ if (await context.MangaIncludeAll()
+ .Where(m => MangaIds.Contains(m.Key))
+ .ToArrayAsync(HttpContext.RequestAborted) is not { } result)
+ return TypedResults.InternalServerError();
- return Ok(result);
+ return TypedResults.Ok(result.Select(m =>
+ {
+ IEnumerable ids = m.MangaConnectorIds.Select(id => new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
+ IEnumerable authors = m.Authors.Select(a => new Author(a.Key, a.AuthorName));
+ IEnumerable tags = m.MangaTags.Select(t => t.Tag);
+ IEnumerable links = m.Links.Select(l => new Link(l.Key, l.LinkProvider, l.LinkUrl));
+ IEnumerable altTitles = m.AltTitles.Select(a => new AltTitle(a.Language, a.Title));
+ return new Manga(m.Key, m.Name, m.Description, m.ReleaseStatus, ids, m.IgnoreChaptersBefore, m.Year, m.OriginalLanguage, m.ChapterIds, authors, tags, links, altTitles);
+ }).ToList());
}
///
- /// Return with
+ /// Return with
///
- /// .Key
+ /// .Key
///
/// with not found
[HttpGet("{MangaId}")]
[ProducesResponseType(Status200OK, "application/json")]
- [ProducesResponseType(Status404NotFound)]
- public async Task GetManga (string MangaId)
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ public async Task, NotFound>> GetManga (string MangaId)
{
if (await context.MangaIncludeAll().FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
- return NotFound(nameof(MangaId));
+ return TypedResults.NotFound(nameof(MangaId));
- return Ok(manga);
+ IEnumerable ids = manga.MangaConnectorIds.Select(id => new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
+ IEnumerable authors = manga.Authors.Select(a => new Author(a.Key, a.AuthorName));
+ IEnumerable tags = manga.MangaTags.Select(t => t.Tag);
+ IEnumerable links = manga.Links.Select(l => new Link(l.Key, l.LinkProvider, l.LinkUrl));
+ IEnumerable altTitles = manga.AltTitles.Select(a => new AltTitle(a.Language, a.Title));
+ Manga result = new (manga.Key, manga.Name, manga.Description, manga.ReleaseStatus, ids, manga.IgnoreChaptersBefore, manga.Year, manga.OriginalLanguage, manga.ChapterIds, authors, tags, links, altTitles);
+
+ return TypedResults.Ok(result);
}
///
@@ -114,18 +149,18 @@ public class MangaController(MangaContext context) : Controller
/// Error during Database Operation
[HttpDelete("{MangaId}")]
[ProducesResponseType(Status200OK)]
- [ProducesResponseType(Status404NotFound)]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task DeleteManga (string MangaId)
+ public async Task, InternalServerError>> DeleteManga (string MangaId)
{
if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
- return NotFound(nameof(MangaId));
+ return TypedResults.NotFound(nameof(MangaId));
context.Mangas.Remove(manga);
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
- return StatusCode(Status500InternalServerError, result.exceptionMessage);
- return Ok();
+ return TypedResults.InternalServerError(result.exceptionMessage);
+ return TypedResults.Ok();
}
@@ -137,27 +172,19 @@ public class MangaController(MangaContext context) : Controller
///
/// with or not found
[HttpPatch("{MangaIdFrom}/MergeInto/{MangaIdInto}")]
- [ProducesResponseType(Status200OK,"image/jpeg")]
- [ProducesResponseType(Status404NotFound)]
- public async Task MergeIntoManga (string MangaIdFrom, string MangaIdInto)
+ [ProducesResponseType(Status200OK)]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ public async Task>> MergeIntoManga (string MangaIdFrom, string MangaIdInto)
{
- if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaIdFrom, HttpContext.RequestAborted) is not { } from)
- return NotFound(nameof(MangaIdFrom));
- if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaIdInto, HttpContext.RequestAborted) is not { } into)
- return NotFound(nameof(MangaIdInto));
-
- foreach (CollectionEntry collectionEntry in context.Entry(from).Collections)
- await collectionEntry.LoadAsync(HttpContext.RequestAborted);
- await context.Entry(from).Navigation(nameof(Manga.Library)).LoadAsync(HttpContext.RequestAborted);
-
- foreach (CollectionEntry collectionEntry in context.Entry(into).Collections)
- await collectionEntry.LoadAsync(HttpContext.RequestAborted);
- await context.Entry(into).Navigation(nameof(Manga.Library)).LoadAsync(HttpContext.RequestAborted);
+ if (await context.MangaIncludeAll().FirstOrDefaultAsync(m => m.Key == MangaIdFrom, HttpContext.RequestAborted) is not { } from)
+ return TypedResults.NotFound(nameof(MangaIdFrom));
+ if (await context.MangaIncludeAll().FirstOrDefaultAsync(m => m.Key == MangaIdInto, HttpContext.RequestAborted) is not { } into)
+ return TypedResults.NotFound(nameof(MangaIdInto));
BaseWorker[] newJobs = into.MergeFrom(from, context);
Tranga.AddWorkers(newJobs);
- return Ok();
+ return TypedResults.Ok();
}
///
@@ -175,22 +202,22 @@ public class MangaController(MangaContext context) : Controller
[ProducesResponseType(Status200OK,"image/jpeg")]
[ProducesResponseType(Status204NoContent)]
[ProducesResponseType(Status400BadRequest)]
- [ProducesResponseType(Status404NotFound)]
- [ProducesResponseType(Status503ServiceUnavailable, "text/plain")]
- public async Task GetCover (string MangaId, [FromQuery]int? width, [FromQuery]int? height)
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ [ProducesResponseType(Status503ServiceUnavailable)]
+ public async Task, StatusCodeHttpResult>> GetCover (string MangaId, [FromQuery]int? width, [FromQuery]int? height)
{
if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
- return NotFound(nameof(MangaId));
+ return TypedResults.NotFound(nameof(MangaId));
if (!System.IO.File.Exists(manga.CoverFileNameInCache))
{
if (Tranga.GetRunningWorkers().Any(worker => worker is DownloadCoverFromMangaconnectorWorker w && context.MangaConnectorToManga.Find(w.MangaConnectorIdId)?.ObjId == MangaId))
{
Response.Headers.Append("Retry-After", $"{Tranga.Settings.WorkCycleTimeoutMs * 2 / 1000:D}");
- return StatusCode(Status503ServiceUnavailable, Tranga.Settings.WorkCycleTimeoutMs * 2 / 1000);
+ return TypedResults.StatusCode(Status503ServiceUnavailable);
}
else
- return NoContent();
+ return TypedResults.NoContent();
}
Image image = await Image.LoadAsync(manga.CoverFileNameInCache, HttpContext.RequestAborted);
@@ -198,7 +225,7 @@ public class MangaController(MangaContext context) : Controller
if (width is { } w && height is { } h)
{
if (width < 10 || height < 10 || width > 65535 || height > 65535)
- return BadRequest();
+ return TypedResults.BadRequest();
image.Mutate(i => i.ApplyProcessor(new ResizeProcessor(new ResizeOptions()
{
Mode = ResizeMode.Max,
@@ -210,7 +237,7 @@ public class MangaController(MangaContext context) : Controller
await image.SaveAsync(ms, new JpegEncoder(){Quality = 100}, HttpContext.RequestAborted);
DateTime lastModified = new FileInfo(manga.CoverFileNameInCache).LastWriteTime;
HttpContext.Response.Headers.CacheControl = "public";
- return File(ms.GetBuffer(), "image/jpeg", new DateTimeOffset(lastModified), EntityTagHeaderValue.Parse($"\"{lastModified.Ticks}\""));
+ return TypedResults.File(ms.GetBuffer(), "image/jpeg", lastModified: new DateTimeOffset(lastModified), entityTag: EntityTagHeaderValue.Parse($"\"{lastModified.Ticks}\""));
}
///
@@ -220,17 +247,20 @@ public class MangaController(MangaContext context) : Controller
///
/// with not found
[HttpGet("{MangaId}/Chapters")]
- [ProducesResponseType(Status200OK, "application/json")]
+ [ProducesResponseType>(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
- public async Task GetChapters (string MangaId)
+ public async Task>, NotFound>> GetChapters(string MangaId)
{
- if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
- return NotFound(nameof(MangaId));
+ if (await context.Mangas.Include(m => m.Chapters).ThenInclude(c => c.MangaConnectorIds).FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
+ return TypedResults.NotFound(nameof(MangaId));
- await context.Entry(manga).Collection(m => m.Chapters).LoadAsync();
-
- Chapter[] chapters = manga.Chapters.ToArray();
- return Ok(chapters);
+ List chapters = manga.Chapters.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);
+ }).ToList();
+ return TypedResults.Ok(chapters);
}
///
@@ -243,19 +273,22 @@ public class MangaController(MangaContext context) : Controller
[HttpGet("{MangaId}/Chapters/Downloaded")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status204NoContent)]
- [ProducesResponseType(Status404NotFound)]
- public async Task GetChaptersDownloaded (string MangaId)
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ public async Task>, NoContent, NotFound>> GetChaptersDownloaded(string MangaId)
{
- if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
- return NotFound(nameof(MangaId));
+ if (await context.Mangas.Include(m => m.Chapters).FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
+ return TypedResults.NotFound(nameof(MangaId));
- await context.Entry(manga).Collection(m => m.Chapters).LoadAsync();
-
- List chapters = manga.Chapters.Where(c => c.Downloaded).ToList();
+ List chapters = manga.Chapters.Where(c => c.Downloaded).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);
+ }).ToList();
if (chapters.Count == 0)
- return NoContent();
+ return TypedResults.NoContent();
- return Ok(chapters);
+ return TypedResults.Ok(chapters);
}
///
@@ -266,21 +299,24 @@ public class MangaController(MangaContext context) : Controller
/// No available chapters
/// with not found.
[HttpGet("{MangaId}/Chapters/NotDownloaded")]
- [ProducesResponseType(Status200OK, "application/json")]
+ [ProducesResponseType>(Status200OK, "application/json")]
[ProducesResponseType(Status204NoContent)]
- [ProducesResponseType(Status404NotFound)]
- public async Task GetChaptersNotDownloaded (string MangaId)
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ public async Task>, NoContent, NotFound>> GetChaptersNotDownloaded(string MangaId)
{
- if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
- return NotFound(nameof(MangaId));
+ if (await context.Mangas.Include(m => m.Chapters).FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
+ return TypedResults.NotFound(nameof(MangaId));
- await context.Entry(manga).Collection(m => m.Chapters).LoadAsync(HttpContext.RequestAborted);
-
- List chapters = manga.Chapters.Where(c => c.Downloaded == false).ToList();
+ List chapters = manga.Chapters.Where(c => c.Downloaded == false).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);
+ }).ToList();
if (chapters.Count == 0)
- return NoContent();
+ return TypedResults.NoContent();
- return Ok(chapters);
+ return TypedResults.Ok(chapters);
}
///
@@ -293,38 +329,41 @@ public class MangaController(MangaContext context) : Controller
/// Could not retrieve the maximum chapter-number
/// Retry after timeout, updating value
[HttpGet("{MangaId}/Chapter/LatestAvailable")]
- [ProducesResponseType(Status200OK, "application/json")]
+ [ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status204NoContent)]
[ProducesResponseType(Status404NotFound, "text/plain")]
- [ProducesResponseType(Status500InternalServerError, "text/plain")]
- [ProducesResponseType(Status503ServiceUnavailable, "text/plain")]
- public async Task GetLatestChapter (string MangaId)
+ [ProducesResponseType(Status500InternalServerError)]
+ [ProducesResponseType(Status503ServiceUnavailable)]
+ public async Task, NoContent, InternalServerError, NotFound, StatusCodeHttpResult>> GetLatestChapter(string MangaId)
{
- if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
- return NotFound(nameof(MangaId));
+ if (await context.Mangas.Include(m => m.Chapters).FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
+ return TypedResults.NotFound(nameof(MangaId));
- await context.Entry(manga).Collection(m => m.Chapters).LoadAsync(HttpContext.RequestAborted);
-
- List chapters = manga.Chapters.ToList();
+ List chapters = manga.Chapters.ToList();
if (chapters.Count == 0)
{
- if (Tranga.GetRunningWorkers().Any(worker => worker is RetrieveMangaChaptersFromMangaconnectorWorker w && context.MangaConnectorToManga.Find(w.MangaConnectorIdId)?.ObjId == MangaId && w.State < WorkerExecutionState.Completed))
+ if (Tranga.GetRunningWorkers().Any(worker =>
+ worker is RetrieveMangaChaptersFromMangaconnectorWorker w &&
+ context.MangaConnectorToManga.Find(w.MangaConnectorIdId)?.ObjId == MangaId &&
+ w.State < WorkerExecutionState.Completed))
{
Response.Headers.Append("Retry-After", $"{Tranga.Settings.WorkCycleTimeoutMs * 2 / 1000:D}");
- return StatusCode(Status503ServiceUnavailable, Tranga.Settings.WorkCycleTimeoutMs * 2/ 1000);
- }else
- return Ok(0);
+ return TypedResults.StatusCode(Status503ServiceUnavailable);
+ }
+ else
+ return TypedResults.NoContent();
}
- Chapter? max = chapters.Max();
+ API.Schema.MangaContext.Chapter? max = chapters.Max();
if (max is null)
- return StatusCode(Status500InternalServerError, "Max chapter could not be found");
+ return TypedResults.InternalServerError();
foreach (CollectionEntry collectionEntry in context.Entry(max).Collections)
await collectionEntry.LoadAsync(HttpContext.RequestAborted);
- await context.Entry(max).Navigation(nameof(Chapter.ParentManga)).LoadAsync(HttpContext.RequestAborted);
- return Ok(max);
+ IEnumerable ids = max.MangaConnectorIds.Select(id =>
+ new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
+ return TypedResults.Ok(new Chapter(max.Key, max.ParentMangaId, max.VolumeNumber, max.ChapterNumber, max.Title,ids, max.Downloaded));
}
///
@@ -339,36 +378,34 @@ public class MangaController(MangaContext context) : Controller
[HttpGet("{MangaId}/Chapter/LatestDownloaded")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status204NoContent)]
- [ProducesResponseType(Status404NotFound)]
- [ProducesResponseType(Status412PreconditionFailed, "text/plain")]
- [ProducesResponseType(Status503ServiceUnavailable, "text/plain")]
- public async Task GetLatestChapterDownloaded (string MangaId)
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ [ProducesResponseType(Status412PreconditionFailed)]
+ [ProducesResponseType(Status503ServiceUnavailable)]
+ public async Task, NoContent, NotFound, StatusCodeHttpResult>> GetLatestChapterDownloaded(string MangaId)
{
if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
- return NotFound(nameof(MangaId));
+ return TypedResults.NotFound(nameof(MangaId));
await context.Entry(manga).Collection(m => m.Chapters).LoadAsync(HttpContext.RequestAborted);
- List chapters = manga.Chapters.ToList();
+ List chapters = manga.Chapters.ToList();
if (chapters.Count == 0)
{
if (Tranga.GetRunningWorkers().Any(worker => worker is RetrieveMangaChaptersFromMangaconnectorWorker w && context.MangaConnectorToManga.Find(w.MangaConnectorIdId)?.ObjId == MangaId && w.State < WorkerExecutionState.Completed))
{
Response.Headers.Append("Retry-After", $"{Tranga.Settings.WorkCycleTimeoutMs * 2 / 1000:D}");
- return StatusCode(Status503ServiceUnavailable, Tranga.Settings.WorkCycleTimeoutMs * 2/ 1000);
+ return TypedResults.StatusCode(Status503ServiceUnavailable);
}else
- return NoContent();
+ return TypedResults.NoContent();
}
- Chapter? max = chapters.Max();
+ API.Schema.MangaContext.Chapter? max = chapters.Max();
if (max is null)
- return StatusCode(Status412PreconditionFailed, "Max chapter could not be found");
+ return TypedResults.StatusCode(Status412PreconditionFailed);
- foreach (CollectionEntry collectionEntry in context.Entry(max).Collections)
- await collectionEntry.LoadAsync(HttpContext.RequestAborted);
- await context.Entry(max).Navigation(nameof(Chapter.ParentManga)).LoadAsync(HttpContext.RequestAborted);
-
- return Ok(max);
+ IEnumerable ids = max.MangaConnectorIds.Select(id =>
+ new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
+ return TypedResults.Ok(new Chapter(max.Key, max.ParentMangaId, max.VolumeNumber, max.ChapterNumber, max.Title,ids, max.Downloaded));
}
///
@@ -380,19 +417,19 @@ public class MangaController(MangaContext context) : Controller
/// with not found.
/// Error during Database Operation
[HttpPatch("{MangaId}/IgnoreChaptersBefore")]
- [ProducesResponseType(Status202Accepted)]
- [ProducesResponseType(Status404NotFound)]
+ [ProducesResponseType(Status200OK)]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task IgnoreChaptersBefore (string MangaId, [FromBody]float chapterThreshold)
+ 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 NotFound(nameof(MangaId));
+ return TypedResults.NotFound(nameof(MangaId));
manga.IgnoreChaptersBefore = chapterThreshold;
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
- return StatusCode(Status500InternalServerError, result.exceptionMessage);
+ return TypedResults.InternalServerError(result.exceptionMessage);
- return Accepted();
+ return TypedResults.Ok();
}
///
@@ -403,24 +440,20 @@ public class MangaController(MangaContext context) : Controller
/// Folder is going to be moved
/// or not found
[HttpPost("{MangaId}/ChangeLibrary/{LibraryId}")]
- [ProducesResponseType(Status202Accepted)]
- [ProducesResponseType(Status404NotFound)]
- public async Task ChangeLibrary (string MangaId, string LibraryId)
+ [ProducesResponseType(Status200OK)]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ public async Task>> ChangeLibrary(string MangaId, string LibraryId)
{
- if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
- return NotFound(nameof(MangaId));
+ if (await context.MangaIncludeAll().FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
+ return TypedResults.NotFound(nameof(MangaId));
if (await context.FileLibraries.FirstOrDefaultAsync(l => l.Key == LibraryId, HttpContext.RequestAborted) is not { } library)
- return NotFound(nameof(LibraryId));
-
- foreach (CollectionEntry collectionEntry in context.Entry(manga).Collections)
- await collectionEntry.LoadAsync(HttpContext.RequestAborted);
- await context.Entry(manga).Navigation(nameof(Manga.Library)).LoadAsync(HttpContext.RequestAborted);
+ return TypedResults.NotFound(nameof(LibraryId));
MoveMangaLibraryWorker moveLibrary = new(manga, library);
Tranga.AddWorkers([moveLibrary]);
- return Accepted();
+ return TypedResults.Ok();
}
///
@@ -440,51 +473,50 @@ public class MangaController(MangaContext context) : Controller
[ProducesResponseType(Status412PreconditionFailed, "text/plain")]
[ProducesResponseType(Status428PreconditionRequired, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task MarkAsRequested (string MangaId, string MangaConnectorName, bool IsRequested)
+ public async Task, StatusCodeHttpResult, InternalServerError>> MarkAsRequested(string MangaId, string MangaConnectorName, bool IsRequested)
{
if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } _)
- return NotFound(nameof(MangaId));
+ return TypedResults.NotFound(nameof(MangaId));
if(!Tranga.TryGetMangaConnector(MangaConnectorName, out MangaConnector? _))
- return NotFound(nameof(MangaConnectorName));
+ return TypedResults.NotFound(nameof(MangaConnectorName));
if (context.MangaConnectorToManga
.FirstOrDefault(id => id.MangaConnectorName == MangaConnectorName && id.ObjId == MangaId)
is not { } mcId)
{
if(IsRequested)
- return StatusCode(Status428PreconditionRequired, "Don't know how to download this Manga from MangaConnector");
+ return TypedResults.StatusCode(Status428PreconditionRequired);
else
- return StatusCode(Status412PreconditionFailed, "Not linked anyways.");
+ return TypedResults.StatusCode(Status412PreconditionFailed);
}
mcId.UseForDownload = IsRequested;
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
- return StatusCode(Status500InternalServerError, result.exceptionMessage);
-
+ return TypedResults.InternalServerError(result.exceptionMessage);
DownloadCoverFromMangaconnectorWorker downloadCover = new(mcId);
RetrieveMangaChaptersFromMangaconnectorWorker retrieveChapters = new(mcId, Tranga.Settings.DownloadLanguage);
Tranga.AddWorkers([downloadCover, retrieveChapters]);
- return Ok();
+ return TypedResults.Ok();
}
///
- /// Initiate a search for on a different
+ /// Initiate a search for on a different
///
- /// with
+ /// with
/// .Name
- ///
+ /// exert of
/// with Name not found
/// with Name is disabled
[HttpPost("{MangaId}/SearchOn/{MangaConnectorName}")]
- [ProducesResponseType(Status200OK, "application/json")]
- [ProducesResponseType(Status404NotFound)]
+ [ProducesResponseType>(Status200OK, "application/json")]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
[ProducesResponseType(Status406NotAcceptable)]
- public async Task SearchOnDifferentConnector (string MangaId, string MangaConnectorName)
+ public async Task>, NotFound, StatusCodeHttpResult>> SearchOnDifferentConnector (string MangaId, string MangaConnectorName)
{
if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
- return NotFound(nameof(MangaId));
+ return TypedResults.NotFound(nameof(MangaId));
return new SearchController(context).SearchManga(MangaConnectorName, manga.Name);
}
@@ -495,14 +527,27 @@ public class MangaController(MangaContext context) : Controller
/// .Key
///
/// with
+ /// /// Error during Database Operation
[HttpGet("WithAuthorId/{AuthorId}")]
- [ProducesResponseType(Status200OK, "application/json")]
- public async Task GetMangaWithAuthorIds (string AuthorId)
+ [ProducesResponseType>(Status200OK, "application/json")]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ public async Task>, NotFound, InternalServerError>> GetMangaWithAuthorIds (string AuthorId)
{
- if (await context.Authors.FirstOrDefaultAsync(a => a.Key == AuthorId, HttpContext.RequestAborted) is not { } author)
- return NotFound(nameof(AuthorId));
-
- return Ok(context.Mangas.Where(m => m.Authors.Contains(author)));
+ if (await context.Authors.FirstOrDefaultAsync(a => a.Key == AuthorId, HttpContext.RequestAborted) is not { } _)
+ return TypedResults.NotFound(nameof(AuthorId));
+
+ if (await context.MangaIncludeAll().Where(m => m.Authors.Any(a => a.Key == AuthorId)).ToListAsync(HttpContext.RequestAborted) is not { } result)
+ return TypedResults.InternalServerError();
+
+ return TypedResults.Ok(result.Select(m =>
+ {
+ IEnumerable ids = m.MangaConnectorIds.Select(id => new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
+ IEnumerable authors = m.Authors.Select(a => new Author(a.Key, a.AuthorName));
+ IEnumerable tags = m.MangaTags.Select(t => t.Tag);
+ IEnumerable links = m.Links.Select(l => new Link(l.Key, l.LinkProvider, l.LinkUrl));
+ IEnumerable altTitles = m.AltTitles.Select(a => new AltTitle(a.Language, a.Title));
+ return new Manga(m.Key, m.Name, m.Description, m.ReleaseStatus, ids, m.IgnoreChaptersBefore, m.Year, m.OriginalLanguage, m.ChapterIds, authors, tags, links, altTitles);
+ }).ToList());
}
///
@@ -511,13 +556,28 @@ public class MangaController(MangaContext context) : Controller
/// .Tag
///
/// not found
+ /// Error during Database Operation
[HttpGet("WithTag/{Tag}")]
[ProducesResponseType(Status200OK, "application/json")]
- public async Task GetMangasWithTag (string Tag)
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ [ProducesResponseType(Status500InternalServerError)]
+ public async Task>, NotFound, InternalServerError>> GetMangasWithTag (string Tag)
{
if (await context.Tags.FirstOrDefaultAsync(t => t.Tag == Tag, HttpContext.RequestAborted) is not { } tag)
- return NotFound(nameof(Tag));
-
- return Ok(context.Mangas.Where(m => m.MangaTags.Contains(tag)));
+ return TypedResults.NotFound(nameof(Tag));
+
+
+ if (await context.MangaIncludeAll().Where(m => m.MangaTags.Any(t => t.Tag.Equals(tag))) .ToListAsync(HttpContext.RequestAborted) is not { } result)
+ return TypedResults.InternalServerError();
+
+ return TypedResults.Ok(result.Select(m =>
+ {
+ IEnumerable ids = m.MangaConnectorIds.Select(id => new MangaConnectorId(id.Key, id.MangaConnectorName, id.ObjId, id.WebsiteUrl, id.UseForDownload));
+ IEnumerable authors = m.Authors.Select(a => new Author(a.Key, a.AuthorName));
+ IEnumerable tags = m.MangaTags.Select(t => t.Tag);
+ IEnumerable links = m.Links.Select(l => new Link(l.Key, l.LinkProvider, l.LinkUrl));
+ IEnumerable altTitles = m.AltTitles.Select(a => new AltTitle(a.Language, a.Title));
+ return new Manga(m.Key, m.Name, m.Description, m.ReleaseStatus, ids, m.IgnoreChaptersBefore, m.Year, m.OriginalLanguage, m.ChapterIds, authors, tags, links, altTitles);
+ }).ToList());
}
}
\ No newline at end of file
diff --git a/API/Controllers/MetadataFetcherController.cs b/API/Controllers/MetadataFetcherController.cs
index c215b7a..90dc0e9 100644
--- a/API/Controllers/MetadataFetcherController.cs
+++ b/API/Controllers/MetadataFetcherController.cs
@@ -1,6 +1,7 @@
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;
@@ -19,10 +20,10 @@ public class MetadataFetcherController(MangaContext context) : Controller
///
/// Names of (Metadata-Sites)
[HttpGet]
- [ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetConnectors ()
+ [ProducesResponseType>(Status200OK, "application/json")]
+ public Ok> GetConnectors ()
{
- return Ok(Tranga.MetadataFetchers.Select(m => m.Name).ToArray());
+ return TypedResults.Ok(Tranga.MetadataFetchers.Select(m => m.Name).ToList());
}
///
@@ -31,13 +32,14 @@ public class MetadataFetcherController(MangaContext context) : Controller
///
/// Error during Database Operation
[HttpGet("Links")]
- [ProducesResponseType(Status200OK, "application/json")]
- public async Task GetLinkedEntries ()
+ [ProducesResponseType>(Status200OK, "application/json")]
+ [ProducesResponseType(Status500InternalServerError)]
+ public async Task>, InternalServerError>> GetLinkedEntries ()
{
- if (await context.MetadataEntries.ToArrayAsync() is not { } result)
- return StatusCode(Status500InternalServerError);
+ if (await context.MetadataEntries.ToListAsync() is not { } result)
+ return TypedResults.InternalServerError();
- return Ok(result);
+ return TypedResults.Ok(result);
}
///
@@ -52,16 +54,16 @@ public class MetadataFetcherController(MangaContext context) : Controller
[HttpPost("{MetadataFetcherName}/SearchManga/{MangaId}")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status400BadRequest)]
- [ProducesResponseType(Status404NotFound)]
- public async Task SearchMangaMetadata(string MangaId, string MetadataFetcherName, [FromBody (EmptyBodyBehavior = EmptyBodyBehavior.Allow)]string? searchTerm = null)
+ [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 NotFound(nameof(MangaId));
+ return TypedResults.NotFound(nameof(MangaId));
if(Tranga.MetadataFetchers.FirstOrDefault(f => f.Name == MetadataFetcherName) is not { } fetcher)
- return BadRequest();
+ return TypedResults.BadRequest();
MetadataSearchResult[] searchResults = searchTerm is null ? fetcher.SearchMetadataEntry(manga) : fetcher.SearchMetadataEntry(searchTerm);
- return Ok(searchResults);
+ return TypedResults.Ok(searchResults.ToList());
}
///
@@ -77,21 +79,21 @@ public class MetadataFetcherController(MangaContext context) : Controller
[HttpPost("{MetadataFetcherName}/Link/{MangaId}")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status400BadRequest)]
- [ProducesResponseType(Status404NotFound)]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task LinkMangaMetadata (string MangaId, string MetadataFetcherName, [FromBody]string Identifier)
+ 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 NotFound(nameof(MangaId));
+ return TypedResults.NotFound(nameof(MangaId));
if(Tranga.MetadataFetchers.FirstOrDefault(f => f.Name == MetadataFetcherName) is not { } fetcher)
- return BadRequest();
+ return TypedResults.BadRequest();
MetadataEntry entry = fetcher.CreateMetadataEntry(manga, Identifier);
context.MetadataEntries.Add(entry);
if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
- return StatusCode(Status500InternalServerError, result.exceptionMessage);
- return Ok(entry);
+ return TypedResults.InternalServerError(result.exceptionMessage);
+ return TypedResults.Ok(entry);
}
///
@@ -105,22 +107,23 @@ public class MetadataFetcherController(MangaContext context) : Controller
[HttpPost("{MetadataFetcherName}/Unlink/{MangaId}")]
[ProducesResponseType(Status200OK)]
[ProducesResponseType(Status400BadRequest)]
- [ProducesResponseType(Status404NotFound)]
- [ProducesResponseType(Status412PreconditionFailed, "text/plain")]
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ [ProducesResponseType(Status412PreconditionFailed)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public async Task UnlinkMangaMetadata (string MangaId, string MetadataFetcherName)
+ public async Task, InternalServerError, StatusCodeHttpResult>> UnlinkMangaMetadata (string MangaId, string MetadataFetcherName)
{
if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } _)
- return NotFound(nameof(MangaId));
+ return TypedResults.NotFound(nameof(MangaId));
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");
+ 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 StatusCode(Status500InternalServerError, result.exceptionMessage);
- return Ok();
+ return TypedResults.InternalServerError(result.exceptionMessage);
+ return TypedResults.Ok();
}
}
\ No newline at end of file
diff --git a/API/Controllers/NotificationConnectorController.cs b/API/Controllers/NotificationConnectorController.cs
index 95a98c6..4e3cdbd 100644
--- a/API/Controllers/NotificationConnectorController.cs
+++ b/API/Controllers/NotificationConnectorController.cs
@@ -3,6 +3,7 @@ using API.APIEndpointRecords;
using API.Schema.NotificationsContext;
using API.Schema.NotificationsContext.NotificationConnectors;
using Asp.Versioning;
+using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using static Microsoft.AspNetCore.Http.StatusCodes;
@@ -22,13 +23,14 @@ public class NotificationConnectorController(NotificationsContext context) : Con
///
/// Error during Database Operation
[HttpGet]
- [ProducesResponseType(Status200OK, "application/json")]
- public async Task GetAllConnectors ()
+ [ProducesResponseType>(Status200OK, "application/json")]
+ [ProducesResponseType(Status500InternalServerError)]
+ public async Task>, InternalServerError>> GetAllConnectors ()
{
- if(await context.NotificationConnectors.ToArrayAsync(HttpContext.RequestAborted) is not { } result)
- return StatusCode(Status500InternalServerError);
+ if(await context.NotificationConnectors.ToListAsync(HttpContext.RequestAborted) is not { } result)
+ return TypedResults.InternalServerError();
- return Ok(result);
+ return TypedResults.Ok(result);
}
///
@@ -39,13 +41,13 @@ public class NotificationConnectorController(NotificationsContext context) : Con
/// with not found
[HttpGet("{Name}")]
[ProducesResponseType(Status200OK, "application/json")]
- [ProducesResponseType(Status404NotFound)]
- public async Task GetConnector (string Name)
+ [ProducesResponseType(Status404NotFound, "text/plain")]
+ public async Task, NotFound>> GetConnector (string Name)
{
if (await context.NotificationConnectors.FirstOrDefaultAsync(c => c.Name == Name, HttpContext.RequestAborted) is not { } connector)
- return NotFound(nameof(Name));
+ return TypedResults.NotFound(nameof(Name));
- return Ok(connector);
+ return TypedResults.Ok(connector);
}
///