diff --git a/API/Controllers/JobController.cs b/API/Controllers/JobController.cs deleted file mode 100644 index f47317a..0000000 --- a/API/Controllers/JobController.cs +++ /dev/null @@ -1,389 +0,0 @@ -using API.APIEndpointRecords; -using API.Schema; -using API.Schema.Contexts; -using API.Schema.Jobs; -using Asp.Versioning; -using log4net; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ModelBinding; -using static Microsoft.AspNetCore.Http.StatusCodes; -// ReSharper disable InconsistentNaming - -namespace API.Controllers; - -[ApiVersion(2)] -[ApiController] -[Route("v{version:apiVersion}/[controller]")] -public class JobController(PgsqlContext context, ILog Log) : Controller -{ - /// - /// Returns all Jobs - /// - /// - [HttpGet] - [ProducesResponseType(Status200OK, "application/json")] - public IActionResult GetAllJobs() - { - Job[] ret = context.Jobs.ToArray(); - return Ok(ret); - } - - /// - /// Returns Jobs with requested Job-IDs - /// - /// Array of Job-IDs - /// - [HttpPost("WithIDs")] - [ProducesResponseType(Status200OK, "application/json")] - public IActionResult GetJobs([FromBody]string[] ids) - { - Job[] ret = context.Jobs.Where(job => ids.Contains(job.Key)).ToArray(); - return Ok(ret); - } - - /// - /// Get all Jobs in requested State - /// - /// Requested Job-State - /// - [HttpGet("State/{JobState}")] - [ProducesResponseType(Status200OK, "application/json")] - public IActionResult GetJobsInState(JobState JobState) - { - Job[] jobsInState = context.Jobs.Where(job => job.state == JobState).ToArray(); - return Ok(jobsInState); - } - - /// - /// Returns all Jobs of requested Type - /// - /// Requested Job-Type - /// - [HttpGet("Type/{JobType}")] - [ProducesResponseType(Status200OK, "application/json")] - public IActionResult GetJobsOfType(JobType JobType) - { - Job[] jobsOfType = context.Jobs.Where(job => job.JobType == JobType).ToArray(); - return Ok(jobsOfType); - } - - /// - /// Returns all Jobs of requested Type and State - /// - /// Requested Job-Type - /// Requested Job-State - /// - [HttpGet("TypeAndState/{JobType}/{JobState}")] - [ProducesResponseType(Status200OK, "application/json")] - public IActionResult GetJobsOfType(JobType JobType, JobState JobState) - { - Job[] jobsOfType = context.Jobs.Where(job => job.JobType == JobType && job.state == JobState).ToArray(); - return Ok(jobsOfType); - } - - /// - /// Return Job with ID - /// - /// Job-ID - /// - /// Job with ID could not be found - [HttpGet("{JobId}")] - [ProducesResponseType(Status200OK, "application/json")] - [ProducesResponseType(Status404NotFound)] - public IActionResult GetJob(string JobId) - { - Job? ret = context.Jobs.Find(JobId); - return (ret is not null) switch - { - true => Ok(ret), - false => NotFound() - }; - } - - /// - /// Create a new DownloadAvailableChaptersJob - /// - /// ID of Obj - /// Job-Configuration - /// Job-IDs - /// Could not find ToFileLibrary with ID - /// Could not find Obj with ID - /// Error during Database Operation - [HttpPut("DownloadAvailableChaptersJob/{MangaId}")] - [ProducesResponseType(Status201Created, "application/json")] - [ProducesResponseType(Status400BadRequest)] - [ProducesResponseType(Status404NotFound)] - [ProducesResponseType(Status500InternalServerError, "text/plain")] - public IActionResult CreateDownloadAvailableChaptersJob(string MangaId, [FromBody]DownloadAvailableChaptersJobRecord record) - { - if (context.Mangas.Find(MangaId) is not { } m) - return NotFound(); - else - { - try - { - FileLibrary? l = context.LocalLibraries.Find(record.localLibraryId); - if (l is null) - return BadRequest(); - m.Library = l; - context.SaveChanges(); - } - catch (Exception e) - { - Log.Error(e); - return StatusCode(500, e.Message); - } - } - Job retrieveChapters = new RetrieveChaptersJob(m, record.language, record.recurrenceTimeMs); - Job updateFilesDownloaded = - new UpdateChaptersDownloadedJob(m, record.recurrenceTimeMs, dependsOnJobs: [retrieveChapters]); - Job downloadChapters = new DownloadAvailableChaptersJob(m, record.recurrenceTimeMs, dependsOnJobs: [retrieveChapters, updateFilesDownloaded]); - Job UpdateCover = new UpdateCoverJob(m, record.recurrenceTimeMs, downloadChapters); - retrieveChapters.ParentJob = downloadChapters; - updateFilesDownloaded.ParentJob = retrieveChapters; - return AddJobs([retrieveChapters, downloadChapters, updateFilesDownloaded, UpdateCover]); - } - - /// - /// Create a new DownloadSingleChapterJob - /// - /// ID of the Chapter - /// Job-IDs - /// Could not find Chapter with ID - /// Error during Database Operation - [HttpPut("DownloadSingleChapterJob/{ChapterId}")] - [ProducesResponseType(Status201Created, "application/json")] - [ProducesResponseType(Status404NotFound)] - [ProducesResponseType(Status500InternalServerError, "text/plain")] - public IActionResult CreateNewDownloadChapterJob(string ChapterId) - { - if(context.Chapters.Find(ChapterId) is not { } c) - return NotFound(); - Job job = new DownloadSingleChapterJob(c); - return AddJobs([job]); - } - - /// - /// Create a new UpdateChaptersDownloadedJob - /// - /// ID of the Obj - /// Job-IDs - /// Could not find Obj with ID - /// Error during Database Operation - [HttpPut("UpdateFilesJob/{MangaId}")] - [ProducesResponseType(Status201Created, "application/json")] - [ProducesResponseType(Status404NotFound)] - [ProducesResponseType(Status500InternalServerError, "text/plain")] - public IActionResult CreateUpdateFilesDownloadedJob(string MangaId) - { - if(context.Mangas.Find(MangaId) is not { } m) - return NotFound(); - Job job = new UpdateChaptersDownloadedJob(m, 0); - return AddJobs([job]); - } - - /// - /// Create a new UpdateMetadataJob for all Obj - /// - /// Job-IDs - /// Error during Database Operation - [HttpPut("UpdateAllFilesJob")] - [ProducesResponseType(Status201Created, "application/json")] - [ProducesResponseType(Status500InternalServerError, "text/plain")] - public IActionResult CreateUpdateAllFilesDownloadedJob() - { - List jobs = context.Mangas.Select(m => new UpdateChaptersDownloadedJob(m, 0, null, null)).ToList(); - try - { - context.Jobs.AddRange(jobs); - context.SaveChanges(); - return Created(); - } - catch (Exception e) - { - Log.Error(e); - return StatusCode(500, e.Message); - } - } - - /// - /// Not Implemented: Create a new UpdateMetadataJob - /// - /// ID of the Obj - /// Job-IDs - /// Could not find Obj with ID - /// Error during Database Operation - [HttpPut("UpdateMetadataJob/{MangaId}")] - [ProducesResponseType(Status201Created, "application/json")] - [ProducesResponseType(Status404NotFound)] - [ProducesResponseType(Status500InternalServerError, "text/plain")] - public IActionResult CreateUpdateMetadataJob(string MangaId) - { - return StatusCode(Status501NotImplemented); - } - - /// - /// Not Implemented: Create a new UpdateMetadataJob for all Obj - /// - /// Job-IDs - /// Error during Database Operation - [HttpPut("UpdateAllMetadataJob")] - [ProducesResponseType(Status201Created, "application/json")] - [ProducesResponseType(Status500InternalServerError, "text/plain")] - public IActionResult CreateUpdateAllMetadataJob() - { - return StatusCode(Status501NotImplemented); - } - - private IActionResult AddJobs(Job[] jobs) - { - try - { - context.Jobs.AddRange(jobs); - context.SaveChanges(); - return new CreatedResult((string?)null, jobs.Select(j => j.Key).ToArray()); - } - catch (Exception e) - { - Log.Error(e); - return StatusCode(500, e.Message); - } - } - - /// - /// Delete Job with ID and all children - /// - /// Job-ID - /// - /// Job could not be found - /// Error during Database Operation - [HttpDelete("{JobId}")] - [ProducesResponseType(Status200OK)] - [ProducesResponseType(Status404NotFound)] - [ProducesResponseType(Status500InternalServerError, "text/plain")] - public IActionResult DeleteJob(string JobId) - { - try - { - if(context.Jobs.Find(JobId) is not { } ret) - return NotFound(); - - context.Remove(ret); - context.SaveChanges(); - return Ok(); - } - catch (Exception e) - { - Log.Error(e); - return StatusCode(500, e.Message); - } - } - - /// - /// Modify Job with ID - /// - /// Job-ID - /// Fields to modify, set to null to keep previous value - /// Job modified - /// Malformed request - /// Job with ID not found - /// Error during Database Operation - [HttpPatch("{JobId}")] - [ProducesResponseType(Status202Accepted, "application/json")] - [ProducesResponseType(Status400BadRequest)] - [ProducesResponseType(Status404NotFound)] - [ProducesResponseType(Status500InternalServerError, "text/plain")] - public IActionResult ModifyJob(string JobId, [FromBody]ModifyJobRecord modifyJobRecord) - { - try - { - Job? ret = context.Jobs.Find(JobId); - if(ret is null) - return NotFound(); - - ret.RecurrenceMs = modifyJobRecord.RecurrenceMs ?? ret.RecurrenceMs; - ret.Enabled = modifyJobRecord.Enabled ?? ret.Enabled; - - context.SaveChanges(); - return new AcceptedResult(ret.Key, ret); - } - catch (Exception e) - { - Log.Error(e); - return StatusCode(500, e.Message); - } - } - - /// - /// Starts the Job with the requested ID - /// - /// Job-ID - /// Start Jobs necessary for execution - /// Job started - /// Job with ID not found - /// Job was already running - /// Error during Database Operation - [HttpPost("{JobId}/Start")] - [ProducesResponseType(Status202Accepted)] - [ProducesResponseType(Status404NotFound)] - [ProducesResponseType(Status409Conflict)] - [ProducesResponseType(Status500InternalServerError, "text/plain")] - public IActionResult StartJob(string JobId, [FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)]bool startDependencies = false) - { - Job? ret = context.Jobs.Find(JobId); - if (ret is null) - return NotFound(); - List dependencies = startDependencies ? ret.GetDependenciesAndSelf() : [ret]; - - try - { - if(dependencies.Any(d => d.state >= JobState.Running && d.state < JobState.Completed)) - return new ConflictResult(); - dependencies.ForEach(d => - { - d.LastExecution = DateTime.UnixEpoch; - d.state = JobState.CompletedWaiting; - }); - context.SaveChanges(); - return Accepted(); - } - catch (Exception e) - { - Log.Error(e); - return StatusCode(500, e.Message); - } - } - - /// - /// Stops the Job with the requested ID - /// - /// Job-ID - ///

NOT IMPLEMENTED

- [HttpPost("{JobId}/Stop")] - [ProducesResponseType(Status501NotImplemented)] - public IActionResult StopJob(string JobId) - { - return StatusCode(Status501NotImplemented); - } - - /// - /// Removes failed and completed Jobs (that are not recurring) - /// - /// Job started - /// Error during Database Operation - [HttpPost("Cleanup")] - public IActionResult CleanupJobs() - { - try - { - context.Jobs.RemoveRange(context.Jobs.Where(j => j.state == JobState.Failed || j.state == JobState.Completed)); - context.SaveChanges(); - return Ok(); - } - catch (Exception e) - { - Log.Error(e); - return StatusCode(500, e.Message); - } - } -} \ No newline at end of file diff --git a/API/Controllers/LibraryConnectorController.cs b/API/Controllers/LibraryConnectorController.cs index ccf4419..f69fdf8 100644 --- a/API/Controllers/LibraryConnectorController.cs +++ b/API/Controllers/LibraryConnectorController.cs @@ -1,5 +1,5 @@ -using API.Schema.Contexts; -using API.Schema.LibraryConnectors; +using API.Schema.LibraryContext; +using API.Schema.LibraryContext.LibraryConnectors; using Asp.Versioning; using log4net; using Microsoft.AspNetCore.Mvc; diff --git a/API/Controllers/LocalLibrariesController.cs b/API/Controllers/LocalLibrariesController.cs index 8ca8e6d..8302662 100644 --- a/API/Controllers/LocalLibrariesController.cs +++ b/API/Controllers/LocalLibrariesController.cs @@ -1,6 +1,5 @@ using API.APIEndpointRecords; -using API.Schema; -using API.Schema.Contexts; +using API.Schema.MangaContext; using Asp.Versioning; using log4net; using Microsoft.AspNetCore.Mvc; @@ -11,7 +10,7 @@ namespace API.Controllers; [ApiVersion(2)] [ApiController] [Route("v{v:apiVersion}/[controller]")] -public class LocalLibrariesController(PgsqlContext context, ILog Log) : Controller +public class LocalLibrariesController(MangaContext context, ILog Log) : Controller { [HttpGet] [ProducesResponseType(Status200OK, "application/json")] diff --git a/API/Controllers/MangaConnectorController.cs b/API/Controllers/MangaConnectorController.cs index ac317ab..60d8077 100644 --- a/API/Controllers/MangaConnectorController.cs +++ b/API/Controllers/MangaConnectorController.cs @@ -1,5 +1,5 @@ -using API.Schema.Contexts; -using API.Schema.MangaConnectors; +using API.Schema.MangaContext; +using API.Schema.MangaContext.MangaConnectors; using Asp.Versioning; using log4net; using Microsoft.AspNetCore.Mvc; @@ -10,7 +10,7 @@ namespace API.Controllers; [ApiVersion(2)] [ApiController] [Route("v{v:apiVersion}/[controller]")] -public class MangaConnectorController(PgsqlContext context, ILog Log) : Controller +public class MangaConnectorController(MangaContext context, ILog Log) : Controller { /// /// Get all available Connectors (Scanlation-Sites) diff --git a/API/Controllers/MangaController.cs b/API/Controllers/MangaController.cs index 5079583..554c339 100644 --- a/API/Controllers/MangaController.cs +++ b/API/Controllers/MangaController.cs @@ -1,6 +1,6 @@ -using API.Schema; -using API.Schema.Contexts; -using API.Schema.Jobs; +using API.Schema.MangaContext; +using API.Schema.MangaContext.MangaConnectors; +using API.Workers; using Asp.Versioning; using log4net; using Microsoft.AspNetCore.Mvc; @@ -18,56 +18,58 @@ namespace API.Controllers; [ApiVersion(2)] [ApiController] [Route("v{v:apiVersion}/[controller]")] -public class MangaController(PgsqlContext context, ILog Log) : Controller +public class MangaController(IServiceScope scope) : Controller { /// - /// Returns all cached Obj + /// Returns all cached /// /// [HttpGet] [ProducesResponseType(Status200OK, "application/json")] public IActionResult GetAllManga() { + MangaContext context = scope.ServiceProvider.GetRequiredService(); Manga[] ret = context.Mangas.ToArray(); return Ok(ret); } /// - /// Returns all cached Obj with IDs + /// Returns all cached with /// - /// Array of Obj-IDs + /// Array of <.Key /// [HttpPost("WithIDs")] [ProducesResponseType(Status200OK, "application/json")] - public IActionResult GetManga([FromBody]string[] ids) + public IActionResult GetManga([FromBody]string[] MangaIds) { - Manga[] ret = context.Mangas.Where(m => ids.Contains(m.Key)).ToArray(); + MangaContext context = scope.ServiceProvider.GetRequiredService(); + Manga[] ret = context.Mangas.Where(m => MangaIds.Contains(m.Key)).ToArray(); return Ok(ret); } /// - /// Return Obj with ID + /// Return with /// - /// Obj-ID + /// .Key /// - /// Obj with ID not found + /// with not found [HttpGet("{MangaId}")] [ProducesResponseType(Status200OK, "application/json")] [ProducesResponseType(Status404NotFound)] public IActionResult GetManga(string MangaId) { - Manga? ret = context.Mangas.Find(MangaId); - if (ret is null) - return NotFound(); - return Ok(ret); + MangaContext context = scope.ServiceProvider.GetRequiredService(); + if (context.Mangas.Find(MangaId) is not { } manga) + return NotFound(nameof(MangaId)); + return Ok(manga); } /// - /// Delete Obj with ID + /// Delete with /// - /// Obj-ID + /// .Key /// - /// Obj with ID not found + /// < with not found /// Error during Database Operation [HttpDelete("{MangaId}")] [ProducesResponseType(Status200OK)] @@ -75,62 +77,52 @@ public class MangaController(PgsqlContext context, ILog Log) : Controller [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult DeleteManga(string MangaId) { - try - { - Manga? ret = context.Mangas.Find(MangaId); - if (ret is null) - return NotFound(); - - context.Remove(ret); - context.SaveChanges(); - return Ok(); - } - catch (Exception e) - { - Log.Error(e); - return StatusCode(500, e.Message); - } + MangaContext context = scope.ServiceProvider.GetRequiredService(); + if (context.Mangas.Find(MangaId) is not { } manga) + return NotFound(nameof(MangaId)); + + context.Mangas.Remove(manga); + + if(context.Sync().Result is { } errorMessage) + return StatusCode(Status500InternalServerError, errorMessage); + return Ok(); } - + /// - /// Merge two Manga into one. THIS IS NOT REVERSIBLE! + /// Merge two into one. THIS IS NOT REVERSIBLE! /// + /// .Key of merging data from (getting deleted) + /// .Key of merging data into /// - /// MangaId not found - /// Error during Database Operation - [HttpPatch("{MangaIdFrom}/MergeInto/{MangaIdTo}")] + /// with or not found + [HttpPatch("{MangaIdFrom}/MergeInto/{MangaIdInto}")] [ProducesResponseType(Status200OK,"image/jpeg")] [ProducesResponseType(Status404NotFound)] - [ProducesResponseType(Status500InternalServerError, "text/plain")] - public IActionResult MergeIntoManga(string MangaIdFrom, string MangaIdTo) + public IActionResult MergeIntoManga(string MangaIdFrom, string MangaIdInto) { - if(context.Mangas.Find(MangaIdFrom) is not { } from) - return NotFound(MangaIdFrom); - if(context.Mangas.Find(MangaIdTo) is not { } to) - return NotFound(MangaIdTo); - try - { - to.MergeFrom(from, context); - return Ok(); - } - catch (DbUpdateException e) - { - Log.Error(e); - return StatusCode(500, e.Message); - } + MangaContext context = scope.ServiceProvider.GetRequiredService(); + if (context.Mangas.Find(MangaIdFrom) is not { } from) + return NotFound(nameof(MangaIdFrom)); + if (context.Mangas.Find(MangaIdInto) is not { } into) + return NotFound(nameof(MangaIdInto)); + + BaseWorker[] newJobs = into.MergeFrom(from, context); + Tranga.AddWorkers(newJobs); + + return Ok(); } /// - /// Returns Cover of Obj + /// Returns Cover of with /// - /// Obj-ID - /// If width is provided, height needs to also be provided - /// If height is provided, width needs to also be provided + /// .Key + /// If is provided, needs to also be provided + /// If is provided, needs to also be provided /// JPEG Image /// Cover not loaded /// The formatting-request was invalid - /// Obj with ID not found + /// with not found /// Retry later, downloading cover [HttpGet("{MangaId}/Cover")] [ProducesResponseType(Status200OK,"image/jpeg")] @@ -140,22 +132,22 @@ public class MangaController(PgsqlContext context, ILog Log) : Controller [ProducesResponseType(Status503ServiceUnavailable, "text/plain")] public IActionResult GetCover(string MangaId, [FromQuery]int? width, [FromQuery]int? height) { - if(context.Mangas.Find(MangaId) is not { } m) - return NotFound(); + MangaContext context = scope.ServiceProvider.GetRequiredService(); + if (context.Mangas.Find(MangaId) is not { } manga) + return NotFound(nameof(MangaId)); - if (!System.IO.File.Exists(m.CoverFileNameInCache)) + if (!System.IO.File.Exists(manga.CoverFileNameInCache)) { - List coverDownloadJobs = context.Jobs.Where(j => j.JobType == JobType.DownloadMangaCoverJob).Include(j => ((DownloadMangaCoverJob)j).Manga).ToList(); - if (coverDownloadJobs.Any(j => j is DownloadMangaCoverJob dmc && dmc.MangaId == MangaId && dmc.state < JobState.Completed)) + if (Tranga.GetRunningWorkers().Any(worker => worker is DownloadCoverFromMangaconnectorWorker w && w.MangaConnectorId.ObjId == MangaId)) { - Response.Headers.Append("Retry-After", $"{TrangaSettings.startNewJobTimeoutMs * coverDownloadJobs.Count() * 2 / 1000:D}"); - return StatusCode(Status503ServiceUnavailable, TrangaSettings.startNewJobTimeoutMs * coverDownloadJobs.Count() * 2 / 1000); + Response.Headers.Append("Retry-After", $"{TrangaSettings.workCycleTimeout * 2 / 1000:D}"); + return StatusCode(Status503ServiceUnavailable, TrangaSettings.workCycleTimeout * 2 / 1000); } else return NoContent(); } - Image image = Image.Load(m.CoverFileNameInCache); + Image image = Image.Load(manga.CoverFileNameInCache); if (width is { } w && height is { } h) { @@ -170,46 +162,48 @@ public class MangaController(PgsqlContext context, ILog Log) : Controller using MemoryStream ms = new(); image.Save(ms, new JpegEncoder(){Quality = 100}); - DateTime lastModified = new FileInfo(m.CoverFileNameInCache).LastWriteTime; + 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}\"")); } /// - /// Returns all Chapters of Obj + /// Returns all of with /// - /// Obj-ID + /// .Key /// - /// Obj with ID not found + /// with not found [HttpGet("{MangaId}/Chapters")] [ProducesResponseType(Status200OK, "application/json")] [ProducesResponseType(Status404NotFound)] public IActionResult GetChapters(string MangaId) { - if(context.Mangas.Find(MangaId) is not { } m) - return NotFound(); + MangaContext context = scope.ServiceProvider.GetRequiredService(); + if (context.Mangas.Find(MangaId) is not { } manga) + return NotFound(nameof(MangaId)); - Chapter[] chapters = m.Chapters.ToArray(); + Chapter[] chapters = manga.Chapters.ToArray(); return Ok(chapters); } /// - /// Returns all downloaded Chapters for Obj with ID + /// Returns all downloaded for with /// - /// Obj-ID + /// .Key /// /// No available chapters - /// Obj with ID not found. + /// with not found. [HttpGet("{MangaId}/Chapters/Downloaded")] [ProducesResponseType(Status200OK, "application/json")] [ProducesResponseType(Status204NoContent)] [ProducesResponseType(Status404NotFound)] public IActionResult GetChaptersDownloaded(string MangaId) { - if(context.Mangas.Find(MangaId) is not { } m) - return NotFound(); - - List chapters = m.Chapters.ToList(); + MangaContext context = scope.ServiceProvider.GetRequiredService(); + if (context.Mangas.Find(MangaId) is not { } manga) + return NotFound(nameof(MangaId)); + + List chapters = manga.Chapters.Where(c => c.Downloaded).ToList(); if (chapters.Count == 0) return NoContent(); @@ -217,22 +211,23 @@ public class MangaController(PgsqlContext context, ILog Log) : Controller } /// - /// Returns all Chapters not downloaded for Obj with ID + /// Returns all not downloaded for with /// - /// Obj-ID + /// .Key /// /// No available chapters - /// Obj with ID not found. + /// with not found. [HttpGet("{MangaId}/Chapters/NotDownloaded")] [ProducesResponseType(Status200OK, "application/json")] [ProducesResponseType(Status204NoContent)] [ProducesResponseType(Status404NotFound)] public IActionResult GetChaptersNotDownloaded(string MangaId) { - if(context.Mangas.Find(MangaId) is not { } m) - return NotFound(); + MangaContext context = scope.ServiceProvider.GetRequiredService(); + if (context.Mangas.Find(MangaId) is not { } manga) + return NotFound(nameof(MangaId)); - List chapters = m.Chapters.ToList(); + List chapters = manga.Chapters.Where(c => c.Downloaded == false).ToList(); if (chapters.Count == 0) return NoContent(); @@ -240,13 +235,13 @@ public class MangaController(PgsqlContext context, ILog Log) : Controller } /// - /// Returns the latest Chapter of requested Obj available on Website + /// Returns the latest of requested available on /// - /// Obj-ID + /// .Key /// /// No available chapters - /// Obj with ID not found. - /// Could not retrieve the maximum chapter-number + /// with not found. + /// Could not retrieve the maximum chapter-number /// Retry after timeout, updating value [HttpGet("{MangaId}/Chapter/LatestAvailable")] [ProducesResponseType(Status200OK, "application/json")] @@ -256,130 +251,115 @@ public class MangaController(PgsqlContext context, ILog Log) : Controller [ProducesResponseType(Status503ServiceUnavailable, "text/plain")] public IActionResult GetLatestChapter(string MangaId) { - if(context.Mangas.Find(MangaId) is not { } m) - return NotFound(); + MangaContext context = scope.ServiceProvider.GetRequiredService(); + if (context.Mangas.Find(MangaId) is not { } manga) + return NotFound(nameof(MangaId)); - List chapters = m.Chapters.ToList(); + List chapters = manga.Chapters.ToList(); if (chapters.Count == 0) { - List retrieveChapterJobs = context.Jobs.Where(j => j.JobType == JobType.RetrieveChaptersJob).Include(j => ((RetrieveChaptersJob)j).Manga).ToList(); - if (retrieveChapterJobs.Any(j => j is RetrieveChaptersJob rcj && rcj.MangaId == MangaId && rcj.state < JobState.Completed)) + if (Tranga.GetRunningWorkers().Any(worker => worker is RetrieveMangaChaptersFromMangaconnectorWorker w && w.MangaConnectorId.ObjId == MangaId && w.State < WorkerExecutionState.Completed)) { - Response.Headers.Append("Retry-After", $"{TrangaSettings.startNewJobTimeoutMs * retrieveChapterJobs.Count() * 2 / 1000:D}"); - return StatusCode(Status503ServiceUnavailable, TrangaSettings.startNewJobTimeoutMs * retrieveChapterJobs.Count() * 2/ 1000); + Response.Headers.Append("Retry-After", $"{TrangaSettings.workCycleTimeout * 2 / 1000:D}"); + return StatusCode(Status503ServiceUnavailable, TrangaSettings.workCycleTimeout * 2/ 1000); }else return Ok(0); } Chapter? max = chapters.Max(); if (max is null) - return StatusCode(500, "Max chapter could not be found"); + return StatusCode(Status500InternalServerError, "Max chapter could not be found"); return Ok(max); } /// - /// Returns the latest Chapter of requested Obj that is downloaded + /// Returns the latest of requested that is downloaded /// - /// Obj-ID + /// .Key /// /// No available chapters - /// Obj with ID not found. - /// Could not retrieve the maximum chapter-number + /// with not found. + /// Could not retrieve the maximum chapter-number /// Retry after timeout, updating value [HttpGet("{MangaId}/Chapter/LatestDownloaded")] [ProducesResponseType(Status200OK, "application/json")] [ProducesResponseType(Status204NoContent)] [ProducesResponseType(Status404NotFound)] - [ProducesResponseType(Status500InternalServerError, "text/plain")] + [ProducesResponseType(Status412PreconditionFailed, "text/plain")] [ProducesResponseType(Status503ServiceUnavailable, "text/plain")] public IActionResult GetLatestChapterDownloaded(string MangaId) { - if(context.Mangas.Find(MangaId) is not { } m) - return NotFound(); + MangaContext context = scope.ServiceProvider.GetRequiredService(); + if (context.Mangas.Find(MangaId) is not { } manga) + return NotFound(nameof(MangaId)); - List chapters = m.Chapters.ToList(); + List chapters = manga.Chapters.ToList(); if (chapters.Count == 0) { - List retrieveChapterJobs = context.Jobs.Where(j => j.JobType == JobType.RetrieveChaptersJob).Include(j => ((RetrieveChaptersJob)j).Manga).ToList(); - if (retrieveChapterJobs.Any(j => j is RetrieveChaptersJob rcj && rcj.MangaId == MangaId && rcj.state < JobState.Completed)) + if (Tranga.GetRunningWorkers().Any(worker => worker is RetrieveMangaChaptersFromMangaconnectorWorker w && w.MangaConnectorId.ObjId == MangaId && w.State < WorkerExecutionState.Completed)) { - Response.Headers.Append("Retry-After", $"{TrangaSettings.startNewJobTimeoutMs * retrieveChapterJobs.Count() * 2 / 1000:D}"); - return StatusCode(Status503ServiceUnavailable, TrangaSettings.startNewJobTimeoutMs * retrieveChapterJobs.Count() * 2 / 1000); + Response.Headers.Append("Retry-After", $"{TrangaSettings.workCycleTimeout * 2 / 1000:D}"); + return StatusCode(Status503ServiceUnavailable, TrangaSettings.workCycleTimeout * 2/ 1000); }else return NoContent(); } Chapter? max = chapters.Max(); if (max is null) - return StatusCode(500, "Max chapter could not be found"); + return StatusCode(Status412PreconditionFailed, "Max chapter could not be found"); return Ok(max); } /// - /// Configure the cut-off for Obj + /// Configure the cut-off for /// - /// Obj-ID - /// Threshold (Chapter Number) - /// - /// Obj with ID not found. + /// .Key + /// Threshold ( ChapterNumber) + /// + /// with not found. /// Error during Database Operation [HttpPatch("{MangaId}/IgnoreChaptersBefore")] - [ProducesResponseType(Status200OK)] + [ProducesResponseType(Status202Accepted)] [ProducesResponseType(Status404NotFound)] [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult IgnoreChaptersBefore(string MangaId, [FromBody]float chapterThreshold) { - Manga? m = context.Mangas.Find(MangaId); - if (m is null) + MangaContext context = scope.ServiceProvider.GetRequiredService(); + if (context.Mangas.Find(MangaId) is not { } manga) return NotFound(); - try - { - m.IgnoreChaptersBefore = chapterThreshold; - context.SaveChanges(); - return Ok(); - } - catch (Exception e) - { - Log.Error(e); - return StatusCode(500, e.Message); - } + manga.IgnoreChaptersBefore = chapterThreshold; + if(context.Sync().Result is { } errorMessage) + return StatusCode(Status500InternalServerError, errorMessage); + + return Accepted(); } /// - /// Move Obj to different ToFileLibrary + /// Move to different /// - /// Obj-ID - /// ToFileLibrary-Id + /// .Key + /// .Key /// Folder is going to be moved - /// MangaId or LibraryId not found - /// Error during Database Operation + /// or not found [HttpPost("{MangaId}/ChangeLibrary/{LibraryId}")] [ProducesResponseType(Status202Accepted)] [ProducesResponseType(Status404NotFound)] - [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult MoveFolder(string MangaId, string LibraryId) { + MangaContext context = scope.ServiceProvider.GetRequiredService(); if (context.Mangas.Find(MangaId) is not { } manga) - return NotFound(); + return NotFound(nameof(MangaId)); if(context.LocalLibraries.Find(LibraryId) is not { } library) - return NotFound(); + return NotFound(nameof(LibraryId)); - MoveMangaLibraryJob moveLibrary = new(manga, library); - UpdateChaptersDownloadedJob updateDownloadedFiles = new(manga, 0, dependsOnJobs: [moveLibrary]); + MoveMangaLibraryWorker moveLibrary = new(manga, library, scope); + UpdateChaptersDownloadedWorker updateDownloadedFiles = new(manga, scope, [moveLibrary]); - try - { - context.Jobs.AddRange(moveLibrary, updateDownloadedFiles); - context.SaveChanges(); - return Accepted(); - } - catch (Exception e) - { - Log.Error(e); - return StatusCode(500, e.Message); - } + Tranga.AddWorkers([moveLibrary, updateDownloadedFiles]); + + return Accepted(); } } \ No newline at end of file diff --git a/API/Controllers/MetadataFetcherController.cs b/API/Controllers/MetadataFetcherController.cs index 33f67b0..4653a2b 100644 --- a/API/Controllers/MetadataFetcherController.cs +++ b/API/Controllers/MetadataFetcherController.cs @@ -1,6 +1,5 @@ -using API.Schema; -using API.Schema.Contexts; -using API.Schema.MetadataFetchers; +using API.Schema.MangaContext; +using API.Schema.MangaContext.MetadataFetchers; using Asp.Versioning; using log4net; using Microsoft.AspNetCore.Mvc; @@ -13,7 +12,7 @@ namespace API.Controllers; [ApiVersion(2)] [ApiController] [Route("v{v:apiVersion}/[controller]")] -public class MetadataFetcherController(PgsqlContext context, ILog Log) : Controller +public class MetadataFetcherController(MangaContext context, ILog Log) : Controller { /// /// Get all available Connectors (Metadata-Sites) diff --git a/API/Controllers/NotificationConnectorController.cs b/API/Controllers/NotificationConnectorController.cs index 4ef4655..e521ad5 100644 --- a/API/Controllers/NotificationConnectorController.cs +++ b/API/Controllers/NotificationConnectorController.cs @@ -1,7 +1,7 @@ using System.Text; using API.APIEndpointRecords; -using API.Schema.Contexts; -using API.Schema.NotificationConnectors; +using API.Schema.NotificationsContext; +using API.Schema.NotificationsContext.NotificationConnectors; using Asp.Versioning; using log4net; using Microsoft.AspNetCore.Mvc; diff --git a/API/Controllers/QueryController.cs b/API/Controllers/QueryController.cs index bfa2160..d258260 100644 --- a/API/Controllers/QueryController.cs +++ b/API/Controllers/QueryController.cs @@ -1,5 +1,4 @@ -using API.Schema; -using API.Schema.Contexts; +using API.Schema.MangaContext; using Asp.Versioning; using log4net; using Microsoft.AspNetCore.Mvc; @@ -11,7 +10,7 @@ namespace API.Controllers; [ApiVersion(2)] [ApiController] [Route("v{v:apiVersion}/[controller]")] -public class QueryController(PgsqlContext context, ILog Log) : Controller +public class QueryController(MangaContext context, ILog Log) : Controller { /// /// Returns the Author-Information for Author-ID diff --git a/API/Controllers/SearchController.cs b/API/Controllers/SearchController.cs index 7b10ec3..9edd200 100644 --- a/API/Controllers/SearchController.cs +++ b/API/Controllers/SearchController.cs @@ -1,5 +1,4 @@ -using API.Schema; -using API.Schema.Contexts; +using API.Schema.MangaContext; using Asp.Versioning; using log4net; using Microsoft.AspNetCore.Mvc; @@ -13,7 +12,7 @@ namespace API.Controllers; [ApiVersion(2)] [ApiController] [Route("v{v:apiVersion}/[controller]")] -public class SearchController(PgsqlContext context, ILog Log) : Controller +public class SearchController(MangaContext context, ILog Log) : Controller { /// /// Initiate a search for a Obj on a specific Connector @@ -104,7 +103,7 @@ public class SearchController(PgsqlContext context, ILog Log) : Controller private Manga? AddMangaToContext((Manga, MangaConnectorId) manga) => AddMangaToContext(manga.Item1, manga.Item2, context); - internal static Manga? AddMangaToContext(Manga addManga, MangaConnectorId addMcId, PgsqlContext context) + internal static Manga? AddMangaToContext(Manga addManga, MangaConnectorId addMcId, MangaContext context) { Manga manga = context.Mangas.Find(addManga.Key) ?? addManga; MangaConnectorId mcId = context.MangaConnectorToManga.Find(addMcId.Key) ?? addMcId; diff --git a/API/Controllers/SettingsController.cs b/API/Controllers/SettingsController.cs index 3fdc2e3..09a2a48 100644 --- a/API/Controllers/SettingsController.cs +++ b/API/Controllers/SettingsController.cs @@ -1,7 +1,6 @@ using API.MangaDownloadClients; -using API.Schema; -using API.Schema.Contexts; -using API.Schema.Jobs; +using API.Schema.JobsContext.Jobs; +using API.Schema.MangaContext; using Asp.Versioning; using log4net; using Microsoft.AspNetCore.Mvc; @@ -13,7 +12,7 @@ namespace API.Controllers; [ApiVersion(2)] [ApiController] [Route("v{v:apiVersion}/[controller]")] -public class SettingsController(PgsqlContext context, ILog Log) : Controller +public class SettingsController(MangaContext context, ILog Log) : Controller { /// /// Get all Settings diff --git a/API/Controllers/WorkerController.cs b/API/Controllers/WorkerController.cs new file mode 100644 index 0000000..4349433 --- /dev/null +++ b/API/Controllers/WorkerController.cs @@ -0,0 +1,193 @@ +using API.APIEndpointRecords; +using API.Schema.MangaContext; +using API.Workers; +using Asp.Versioning; +using log4net; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using static Microsoft.AspNetCore.Http.StatusCodes; +// ReSharper disable InconsistentNaming + +namespace API.Controllers; + +[ApiVersion(2)] +[ApiController] +[Route("v{version:apiVersion}/[controller]")] +public class WorkerController(ILog Log) : Controller +{ + /// + /// Returns all + /// + /// + [HttpGet] + [ProducesResponseType(Status200OK, "application/json")] + public IActionResult GetAllWorkers() + { + return Ok(Tranga.Workers.ToArray()); + } + + /// + /// Returns with requested + /// + /// Array of .Key + /// + [HttpPost("WithIDs")] + [ProducesResponseType(Status200OK, "application/json")] + public IActionResult GetJobs([FromBody]string[] WorkerIds) + { + return Ok(Tranga.Workers.Where(worker => WorkerIds.Contains(worker.Key)).ToArray()); + } + + /// + /// Get all in requested + /// + /// Requested + /// + [HttpGet("State/{State}")] + [ProducesResponseType(Status200OK, "application/json")] + public IActionResult GetJobsInState(WorkerExecutionState State) + { + return Ok(Tranga.Workers.Where(worker => worker.State == State).ToArray()); + } + + /// + /// Return with + /// + /// .Key + /// + /// with could not be found + [HttpGet("{WorkerId}")] + [ProducesResponseType(Status200OK, "application/json")] + [ProducesResponseType(Status404NotFound)] + public IActionResult GetJob(string WorkerId) + { + if(Tranga.Workers.FirstOrDefault(w => w.Key == WorkerId) is not { } worker) + return NotFound(nameof(WorkerId)); + return Ok(worker); + } + + /// + /// Delete with and all child-s + /// + /// .Key + /// + /// with could not be found + [HttpDelete("{WorkerId}")] + [ProducesResponseType(Status200OK)] + [ProducesResponseType(Status404NotFound)] + public IActionResult DeleteJob(string WorkerId) + { + if(Tranga.Workers.FirstOrDefault(w => w.Key == WorkerId) is not { } worker) + return NotFound(nameof(WorkerId)); + Tranga.RemoveWorker(worker); + return Ok(); + } + + /// + /// Modify Job with ID + /// + /// Job-ID + /// Fields to modify, set to null to keep previous value + /// Job modified + /// Malformed request + /// Job with ID not found + /// Error during Database Operation + [HttpPatch("{JobId}")] + [ProducesResponseType(Status202Accepted, "application/json")] + [ProducesResponseType(Status400BadRequest)] + [ProducesResponseType(Status404NotFound)] + [ProducesResponseType(Status500InternalServerError, "text/plain")] + public IActionResult ModifyJob(string JobId, [FromBody]ModifyJobRecord modifyJobRecord) + { + try + { + Job? ret = context.Jobs.Find(JobId); + if(ret is null) + return NotFound(); + + ret.RecurrenceMs = modifyJobRecord.RecurrenceMs ?? ret.RecurrenceMs; + ret.Enabled = modifyJobRecord.Enabled ?? ret.Enabled; + + context.SaveChanges(); + return new AcceptedResult(ret.Key, ret); + } + catch (Exception e) + { + Log.Error(e); + return StatusCode(500, e.Message); + } + } + + /// + /// Starts the Job with the requested ID + /// + /// Job-ID + /// Start Jobs necessary for execution + /// Job started + /// Job with ID not found + /// Job was already running + /// Error during Database Operation + [HttpPost("{JobId}/Start")] + [ProducesResponseType(Status202Accepted)] + [ProducesResponseType(Status404NotFound)] + [ProducesResponseType(Status409Conflict)] + [ProducesResponseType(Status500InternalServerError, "text/plain")] + public IActionResult StartJob(string JobId, [FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)]bool startDependencies = false) + { + Job? ret = context.Jobs.Find(JobId); + if (ret is null) + return NotFound(); + List dependencies = startDependencies ? ret.GetDependenciesAndSelf() : [ret]; + + try + { + if(dependencies.Any(d => d.state >= JobState.Running && d.state < JobState.Completed)) + return new ConflictResult(); + dependencies.ForEach(d => + { + d.LastExecution = DateTime.UnixEpoch; + d.state = JobState.CompletedWaiting; + }); + context.SaveChanges(); + return Accepted(); + } + catch (Exception e) + { + Log.Error(e); + return StatusCode(500, e.Message); + } + } + + /// + /// Stops the Job with the requested ID + /// + /// Job-ID + ///

NOT IMPLEMENTED

+ [HttpPost("{JobId}/Stop")] + [ProducesResponseType(Status501NotImplemented)] + public IActionResult StopJob(string JobId) + { + return StatusCode(Status501NotImplemented); + } + + /// + /// Removes failed and completed Jobs (that are not recurring) + /// + /// Job started + /// Error during Database Operation + [HttpPost("Cleanup")] + public IActionResult CleanupJobs() + { + try + { + context.Jobs.RemoveRange(context.Jobs.Where(j => j.state == JobState.Failed || j.state == JobState.Completed)); + context.SaveChanges(); + return Ok(); + } + catch (Exception e) + { + Log.Error(e); + return StatusCode(500, e.Message); + } + } +} \ No newline at end of file diff --git a/API/Migrations/library/20250515120732_Initial.Designer.cs b/API/Migrations/library/20250515120732_Initial.Designer.cs deleted file mode 100644 index c086b4e..0000000 --- a/API/Migrations/library/20250515120732_Initial.Designer.cs +++ /dev/null @@ -1,71 +0,0 @@ -// -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.library -{ - [DbContext(typeof(LibraryContext))] - [Migration("20250515120732_Initial")] - partial class Initial - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.LibraryConnectors.LibraryConnector", b => - { - b.Property("LibraryConnectorId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Auth") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("BaseUrl") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryType") - .HasColumnType("smallint"); - - b.HasKey("LibraryConnectorId"); - - b.ToTable("LibraryConnectors"); - - b.HasDiscriminator("LibraryType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.LibraryConnectors.Kavita", b => - { - b.HasBaseType("API.Schema.LibraryConnectors.LibraryConnector"); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.LibraryConnectors.Komga", b => - { - b.HasBaseType("API.Schema.LibraryConnectors.LibraryConnector"); - - b.HasDiscriminator().HasValue((byte)0); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/library/20250515120732_Initial.cs b/API/Migrations/library/20250515120732_Initial.cs deleted file mode 100644 index 3ad2851..0000000 --- a/API/Migrations/library/20250515120732_Initial.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace API.Migrations.library -{ - /// - public partial class Initial : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "LibraryConnectors", - columns: table => new - { - LibraryConnectorId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - LibraryType = table.Column(type: "smallint", nullable: false), - BaseUrl = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - Auth = table.Column(type: "character varying(256)", maxLength: 256, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_LibraryConnectors", x => x.LibraryConnectorId); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "LibraryConnectors"); - } - } -} diff --git a/API/Migrations/library/LibraryContextModelSnapshot.cs b/API/Migrations/library/LibraryContextModelSnapshot.cs deleted file mode 100644 index d79d7f0..0000000 --- a/API/Migrations/library/LibraryContextModelSnapshot.cs +++ /dev/null @@ -1,68 +0,0 @@ -// -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.library -{ - [DbContext(typeof(LibraryContext))] - partial class LibraryContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.LibraryConnectors.LibraryConnector", b => - { - b.Property("LibraryConnectorId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Auth") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("BaseUrl") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryType") - .HasColumnType("smallint"); - - b.HasKey("LibraryConnectorId"); - - b.ToTable("LibraryConnectors"); - - b.HasDiscriminator("LibraryType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.LibraryConnectors.Kavita", b => - { - b.HasBaseType("API.Schema.LibraryConnectors.LibraryConnector"); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.LibraryConnectors.Komga", b => - { - b.HasBaseType("API.Schema.LibraryConnectors.LibraryConnector"); - - b.HasDiscriminator().HasValue((byte)0); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/notifications/20250515120746_Initial.Designer.cs b/API/Migrations/notifications/20250515120746_Initial.Designer.cs deleted file mode 100644 index 396d022..0000000 --- a/API/Migrations/notifications/20250515120746_Initial.Designer.cs +++ /dev/null @@ -1,89 +0,0 @@ -// -using System; -using System.Collections.Generic; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.notifications -{ - [DbContext(typeof(NotificationsContext))] - [Migration("20250515120746_Initial")] - partial class Initial - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore"); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Notification", b => - { - b.Property("NotificationId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Date") - .HasColumnType("timestamp with time zone"); - - b.Property("Message") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("Urgency") - .HasColumnType("smallint"); - - b.HasKey("NotificationId"); - - b.ToTable("Notifications"); - }); - - modelBuilder.Entity("API.Schema.NotificationConnectors.NotificationConnector", b => - { - b.Property("Name") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Body") - .IsRequired() - .HasMaxLength(4096) - .HasColumnType("character varying(4096)"); - - b.Property>("Headers") - .IsRequired() - .HasColumnType("hstore"); - - b.Property("HttpMethod") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.HasKey("Name"); - - b.ToTable("NotificationConnectors"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/notifications/20250515120746_Initial.cs b/API/Migrations/notifications/20250515120746_Initial.cs deleted file mode 100644 index 8ab8590..0000000 --- a/API/Migrations/notifications/20250515120746_Initial.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace API.Migrations.notifications -{ - /// - public partial class Initial : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterDatabase() - .Annotation("Npgsql:PostgresExtension:hstore", ",,"); - - migrationBuilder.CreateTable( - name: "NotificationConnectors", - columns: table => new - { - Name = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - Url = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: false), - Headers = table.Column>(type: "hstore", nullable: false), - HttpMethod = table.Column(type: "character varying(8)", maxLength: 8, nullable: false), - Body = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_NotificationConnectors", x => x.Name); - }); - - migrationBuilder.CreateTable( - name: "Notifications", - columns: table => new - { - NotificationId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - Urgency = table.Column(type: "smallint", nullable: false), - Title = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), - Message = table.Column(type: "character varying(512)", maxLength: 512, nullable: false), - Date = table.Column(type: "timestamp with time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Notifications", x => x.NotificationId); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "NotificationConnectors"); - - migrationBuilder.DropTable( - name: "Notifications"); - } - } -} diff --git a/API/Migrations/notifications/20250701203510_Notification-Identifiable.Designer.cs b/API/Migrations/notifications/20250701203510_Notification-Identifiable.Designer.cs deleted file mode 100644 index 09dddbd..0000000 --- a/API/Migrations/notifications/20250701203510_Notification-Identifiable.Designer.cs +++ /dev/null @@ -1,88 +0,0 @@ -// -using System; -using System.Collections.Generic; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.notifications -{ - [DbContext(typeof(NotificationsContext))] - [Migration("20250701203510_Notification-Identifiable")] - partial class NotificationIdentifiable - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore"); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Notification", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("Date") - .HasColumnType("timestamp with time zone"); - - b.Property("Message") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("Urgency") - .HasColumnType("smallint"); - - b.HasKey("Key"); - - b.ToTable("Notifications"); - }); - - modelBuilder.Entity("API.Schema.NotificationConnectors.NotificationConnector", b => - { - b.Property("Name") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Body") - .IsRequired() - .HasMaxLength(4096) - .HasColumnType("character varying(4096)"); - - b.Property>("Headers") - .IsRequired() - .HasColumnType("hstore"); - - b.Property("HttpMethod") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.HasKey("Name"); - - b.ToTable("NotificationConnectors"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/notifications/20250701203510_Notification-Identifiable.cs b/API/Migrations/notifications/20250701203510_Notification-Identifiable.cs deleted file mode 100644 index 3cc52ad..0000000 --- a/API/Migrations/notifications/20250701203510_Notification-Identifiable.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace API.Migrations.notifications -{ - /// - public partial class NotificationIdentifiable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropPrimaryKey( - name: "PK_Notifications", - table: "Notifications"); - - migrationBuilder.DropColumn( - name: "NotificationId", - table: "Notifications"); - - migrationBuilder.AddColumn( - name: "Key", - table: "Notifications", - type: "text", - nullable: false, - defaultValue: ""); - - migrationBuilder.AddPrimaryKey( - name: "PK_Notifications", - table: "Notifications", - column: "Key"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropPrimaryKey( - name: "PK_Notifications", - table: "Notifications"); - - migrationBuilder.DropColumn( - name: "Key", - table: "Notifications"); - - migrationBuilder.AddColumn( - name: "NotificationId", - table: "Notifications", - type: "character varying(64)", - maxLength: 64, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddPrimaryKey( - name: "PK_Notifications", - table: "Notifications", - column: "NotificationId"); - } - } -} diff --git a/API/Migrations/notifications/NotificationsContextModelSnapshot.cs b/API/Migrations/notifications/NotificationsContextModelSnapshot.cs deleted file mode 100644 index 94a333e..0000000 --- a/API/Migrations/notifications/NotificationsContextModelSnapshot.cs +++ /dev/null @@ -1,85 +0,0 @@ -// -using System; -using System.Collections.Generic; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.notifications -{ - [DbContext(typeof(NotificationsContext))] - partial class NotificationsContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore"); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Notification", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("Date") - .HasColumnType("timestamp with time zone"); - - b.Property("Message") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("Urgency") - .HasColumnType("smallint"); - - b.HasKey("Key"); - - b.ToTable("Notifications"); - }); - - modelBuilder.Entity("API.Schema.NotificationConnectors.NotificationConnector", b => - { - b.Property("Name") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Body") - .IsRequired() - .HasMaxLength(4096) - .HasColumnType("character varying(4096)"); - - b.Property>("Headers") - .IsRequired() - .HasColumnType("hstore"); - - b.Property("HttpMethod") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.HasKey("Name"); - - b.ToTable("NotificationConnectors"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/pgsql/20250515120724_Initial-1.Designer.cs b/API/Migrations/pgsql/20250515120724_Initial-1.Designer.cs deleted file mode 100644 index 4b1b2cb..0000000 --- a/API/Migrations/pgsql/20250515120724_Initial-1.Designer.cs +++ /dev/null @@ -1,682 +0,0 @@ -// -using System; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - [DbContext(typeof(PgsqlContext))] - [Migration("20250515120724_Initial-1")] - partial class Initial1 - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Author", b => - { - b.Property("AuthorId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("AuthorName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("AuthorId"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Property("ChapterId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ChapterNumber") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Downloaded") - .HasColumnType("boolean"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ParentMangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b.Property("Title") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.Property("VolumeNumber") - .HasColumnType("integer"); - - b.HasKey("ChapterId"); - - b.HasIndex("ParentMangaId"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.Property("JobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("JobType") - .HasColumnType("smallint"); - - b.Property("LastExecution") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentJobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("RecurrenceMs") - .HasColumnType("numeric(20,0)"); - - b.Property("state") - .HasColumnType("smallint"); - - b.HasKey("JobId"); - - b.HasIndex("ParentJobId"); - - b.ToTable("Jobs"); - - b.HasDiscriminator("JobType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.LocalLibrary", b => - { - b.Property("LocalLibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("BasePath") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryName") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("LocalLibraryId"); - - b.ToTable("LocalLibraries"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Property("MangaId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("CoverFileNameInCache") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("CoverUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("DirectoryName") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IgnoreChaptersBefore") - .HasColumnType("real"); - - b.Property("LibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("OriginalLanguage") - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("ReleaseStatus") - .HasColumnType("smallint"); - - b.Property("WebsiteUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Year") - .HasColumnType("bigint"); - - b.HasKey("MangaId"); - - b.HasIndex("LibraryId"); - - b.HasIndex("MangaConnectorName"); - - b.ToTable("Mangas"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.MangaTag", b => - { - b.Property("Tag") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Tag"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.Property("AuthorIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("AuthorIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("AuthorToManga"); - }); - - modelBuilder.Entity("JobJob", b => - { - b.Property("DependsOnJobsJobId") - .HasColumnType("character varying(64)"); - - b.Property("JobId") - .HasColumnType("character varying(64)"); - - b.HasKey("DependsOnJobsJobId", "JobId"); - - b.HasIndex("JobId"); - - b.ToTable("JobJob"); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.Property("MangaTagIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("MangaTagIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("MangaTagToManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("DownloadAvailableChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasDiscriminator().HasValue((byte)4); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.HasDiscriminator().HasValue((byte)0); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveFileOrFolderJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("FromLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ToLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasDiscriminator().HasValue((byte)3); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ToLibraryId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasIndex("ToLibraryId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("MoveMangaLibraryJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)7); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("RetrieveChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)5); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateFilesDownloadedJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)6); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.Global", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("Global"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("MangaDex"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.HasOne("API.Schema.Manga", "ParentManga") - .WithMany("Chapters") - .HasForeignKey("ParentMangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ParentManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.HasOne("API.Schema.Jobs.Job", "ParentJob") - .WithMany() - .HasForeignKey("ParentJobId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentJob"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.HasOne("API.Schema.LocalLibrary", "Library") - .WithMany() - .HasForeignKey("LibraryId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.OwnsMany("API.Schema.Link", "Links", b1 => - { - b1.Property("LinkId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkProvider") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.HasKey("LinkId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("Link"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.OwnsMany("API.Schema.MangaAltTitle", "AltTitles", b1 => - { - b1.Property("AltTitleId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b1.HasKey("AltTitleId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("MangaAltTitle"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.Navigation("AltTitles"); - - b.Navigation("Library"); - - b.Navigation("Links"); - - b.Navigation("MangaConnector"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.HasOne("API.Schema.Author", null) - .WithMany() - .HasForeignKey("AuthorIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("JobJob", b => - { - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("DependsOnJobsJobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("JobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MangaTag", null) - .WithMany() - .HasForeignKey("MangaTagIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.LocalLibrary", "ToLibrary") - .WithMany() - .HasForeignKey("ToLibraryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("ToLibrary"); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Navigation("Chapters"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/pgsql/20250515120724_Initial-1.cs b/API/Migrations/pgsql/20250515120724_Initial-1.cs deleted file mode 100644 index 97295f0..0000000 --- a/API/Migrations/pgsql/20250515120724_Initial-1.cs +++ /dev/null @@ -1,433 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace API.Migrations.pgsql -{ - /// - public partial class Initial1 : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Authors", - columns: table => new - { - AuthorId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - AuthorName = table.Column(type: "character varying(128)", maxLength: 128, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Authors", x => x.AuthorId); - }); - - migrationBuilder.CreateTable( - name: "LocalLibraries", - columns: table => new - { - LocalLibraryId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - BasePath = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - LibraryName = table.Column(type: "character varying(512)", maxLength: 512, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_LocalLibraries", x => x.LocalLibraryId); - }); - - migrationBuilder.CreateTable( - name: "MangaConnectors", - columns: table => new - { - Name = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), - SupportedLanguages = table.Column(type: "text[]", maxLength: 8, nullable: false), - IconUrl = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: false), - BaseUris = table.Column(type: "text[]", maxLength: 256, nullable: false), - Enabled = table.Column(type: "boolean", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_MangaConnectors", x => x.Name); - }); - - migrationBuilder.CreateTable( - name: "Tags", - columns: table => new - { - Tag = table.Column(type: "character varying(64)", maxLength: 64, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Tags", x => x.Tag); - }); - - migrationBuilder.CreateTable( - name: "Mangas", - columns: table => new - { - MangaId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - IdOnConnectorSite = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - Name = table.Column(type: "character varying(512)", maxLength: 512, nullable: false), - Description = table.Column(type: "text", nullable: false), - WebsiteUrl = table.Column(type: "character varying(512)", maxLength: 512, nullable: false), - CoverUrl = table.Column(type: "character varying(512)", maxLength: 512, nullable: false), - ReleaseStatus = table.Column(type: "smallint", nullable: false), - LibraryId = table.Column(type: "character varying(64)", maxLength: 64, nullable: true), - MangaConnectorName = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), - IgnoreChaptersBefore = table.Column(type: "real", nullable: false), - DirectoryName = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), - CoverFileNameInCache = table.Column(type: "character varying(512)", maxLength: 512, nullable: true), - Year = table.Column(type: "bigint", nullable: false), - OriginalLanguage = table.Column(type: "character varying(8)", maxLength: 8, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Mangas", x => x.MangaId); - table.ForeignKey( - name: "FK_Mangas_LocalLibraries_LibraryId", - column: x => x.LibraryId, - principalTable: "LocalLibraries", - principalColumn: "LocalLibraryId", - onDelete: ReferentialAction.SetNull); - table.ForeignKey( - name: "FK_Mangas_MangaConnectors_MangaConnectorName", - column: x => x.MangaConnectorName, - principalTable: "MangaConnectors", - principalColumn: "Name", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AuthorToManga", - columns: table => new - { - AuthorIds = table.Column(type: "character varying(64)", nullable: false), - MangaIds = table.Column(type: "character varying(64)", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AuthorToManga", x => new { x.AuthorIds, x.MangaIds }); - table.ForeignKey( - name: "FK_AuthorToManga_Authors_AuthorIds", - column: x => x.AuthorIds, - principalTable: "Authors", - principalColumn: "AuthorId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_AuthorToManga_Mangas_MangaIds", - column: x => x.MangaIds, - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Chapters", - columns: table => new - { - ChapterId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - ParentMangaId = table.Column(type: "character varying(64)", nullable: false), - VolumeNumber = table.Column(type: "integer", nullable: true), - ChapterNumber = table.Column(type: "character varying(10)", maxLength: 10, nullable: false), - Url = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: false), - Title = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - FileName = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - Downloaded = table.Column(type: "boolean", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Chapters", x => x.ChapterId); - table.ForeignKey( - name: "FK_Chapters_Mangas_ParentMangaId", - column: x => x.ParentMangaId, - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Link", - columns: table => new - { - LinkId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - LinkProvider = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - LinkUrl = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: false), - MangaId = table.Column(type: "character varying(64)", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Link", x => x.LinkId); - table.ForeignKey( - name: "FK_Link_Mangas_MangaId", - column: x => x.MangaId, - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "MangaAltTitle", - columns: table => new - { - AltTitleId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - Language = table.Column(type: "character varying(8)", maxLength: 8, nullable: false), - Title = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - MangaId = table.Column(type: "character varying(64)", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_MangaAltTitle", x => x.AltTitleId); - table.ForeignKey( - name: "FK_MangaAltTitle_Mangas_MangaId", - column: x => x.MangaId, - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "MangaTagToManga", - columns: table => new - { - MangaTagIds = table.Column(type: "character varying(64)", nullable: false), - MangaIds = table.Column(type: "character varying(64)", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_MangaTagToManga", x => new { x.MangaTagIds, x.MangaIds }); - table.ForeignKey( - name: "FK_MangaTagToManga_Mangas_MangaIds", - column: x => x.MangaIds, - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_MangaTagToManga_Tags_MangaTagIds", - column: x => x.MangaTagIds, - principalTable: "Tags", - principalColumn: "Tag", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Jobs", - columns: table => new - { - JobId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - ParentJobId = table.Column(type: "character varying(64)", maxLength: 64, nullable: true), - JobType = table.Column(type: "smallint", nullable: false), - RecurrenceMs = table.Column(type: "numeric(20,0)", nullable: false), - LastExecution = table.Column(type: "timestamp with time zone", nullable: false), - state = table.Column(type: "smallint", nullable: false), - Enabled = table.Column(type: "boolean", nullable: false), - DownloadAvailableChaptersJob_MangaId = table.Column(type: "character varying(64)", maxLength: 64, nullable: true), - MangaId = table.Column(type: "character varying(64)", maxLength: 64, nullable: true), - ChapterId = table.Column(type: "character varying(64)", maxLength: 64, nullable: true), - FromLocation = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - ToLocation = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - MoveMangaLibraryJob_MangaId = table.Column(type: "character varying(64)", maxLength: 64, nullable: true), - ToLibraryId = table.Column(type: "character varying(64)", maxLength: 64, nullable: true), - RetrieveChaptersJob_MangaId = table.Column(type: "character varying(64)", maxLength: 64, nullable: true), - Language = table.Column(type: "character varying(8)", maxLength: 8, nullable: true), - UpdateFilesDownloadedJob_MangaId = table.Column(type: "character varying(64)", maxLength: 64, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Jobs", x => x.JobId); - table.ForeignKey( - name: "FK_Jobs_Chapters_ChapterId", - column: x => x.ChapterId, - principalTable: "Chapters", - principalColumn: "ChapterId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Jobs_Jobs_ParentJobId", - column: x => x.ParentJobId, - principalTable: "Jobs", - principalColumn: "JobId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Jobs_LocalLibraries_ToLibraryId", - column: x => x.ToLibraryId, - principalTable: "LocalLibraries", - principalColumn: "LocalLibraryId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Jobs_Mangas_DownloadAvailableChaptersJob_MangaId", - column: x => x.DownloadAvailableChaptersJob_MangaId, - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Jobs_Mangas_MangaId", - column: x => x.MangaId, - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Jobs_Mangas_MoveMangaLibraryJob_MangaId", - column: x => x.MoveMangaLibraryJob_MangaId, - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Jobs_Mangas_RetrieveChaptersJob_MangaId", - column: x => x.RetrieveChaptersJob_MangaId, - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Jobs_Mangas_UpdateFilesDownloadedJob_MangaId", - column: x => x.UpdateFilesDownloadedJob_MangaId, - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "JobJob", - columns: table => new - { - DependsOnJobsJobId = table.Column(type: "character varying(64)", nullable: false), - JobId = table.Column(type: "character varying(64)", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_JobJob", x => new { x.DependsOnJobsJobId, x.JobId }); - table.ForeignKey( - name: "FK_JobJob_Jobs_DependsOnJobsJobId", - column: x => x.DependsOnJobsJobId, - principalTable: "Jobs", - principalColumn: "JobId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_JobJob_Jobs_JobId", - column: x => x.JobId, - principalTable: "Jobs", - principalColumn: "JobId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_AuthorToManga_MangaIds", - table: "AuthorToManga", - column: "MangaIds"); - - migrationBuilder.CreateIndex( - name: "IX_Chapters_ParentMangaId", - table: "Chapters", - column: "ParentMangaId"); - - migrationBuilder.CreateIndex( - name: "IX_JobJob_JobId", - table: "JobJob", - column: "JobId"); - - migrationBuilder.CreateIndex( - name: "IX_Jobs_ChapterId", - table: "Jobs", - column: "ChapterId"); - - migrationBuilder.CreateIndex( - name: "IX_Jobs_DownloadAvailableChaptersJob_MangaId", - table: "Jobs", - column: "DownloadAvailableChaptersJob_MangaId"); - - migrationBuilder.CreateIndex( - name: "IX_Jobs_MangaId", - table: "Jobs", - column: "MangaId"); - - migrationBuilder.CreateIndex( - name: "IX_Jobs_MoveMangaLibraryJob_MangaId", - table: "Jobs", - column: "MoveMangaLibraryJob_MangaId"); - - migrationBuilder.CreateIndex( - name: "IX_Jobs_ParentJobId", - table: "Jobs", - column: "ParentJobId"); - - migrationBuilder.CreateIndex( - name: "IX_Jobs_RetrieveChaptersJob_MangaId", - table: "Jobs", - column: "RetrieveChaptersJob_MangaId"); - - migrationBuilder.CreateIndex( - name: "IX_Jobs_ToLibraryId", - table: "Jobs", - column: "ToLibraryId"); - - migrationBuilder.CreateIndex( - name: "IX_Jobs_UpdateFilesDownloadedJob_MangaId", - table: "Jobs", - column: "UpdateFilesDownloadedJob_MangaId"); - - migrationBuilder.CreateIndex( - name: "IX_Link_MangaId", - table: "Link", - column: "MangaId"); - - migrationBuilder.CreateIndex( - name: "IX_MangaAltTitle_MangaId", - table: "MangaAltTitle", - column: "MangaId"); - - migrationBuilder.CreateIndex( - name: "IX_Mangas_LibraryId", - table: "Mangas", - column: "LibraryId"); - - migrationBuilder.CreateIndex( - name: "IX_Mangas_MangaConnectorName", - table: "Mangas", - column: "MangaConnectorName"); - - migrationBuilder.CreateIndex( - name: "IX_MangaTagToManga_MangaIds", - table: "MangaTagToManga", - column: "MangaIds"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "AuthorToManga"); - - migrationBuilder.DropTable( - name: "JobJob"); - - migrationBuilder.DropTable( - name: "Link"); - - migrationBuilder.DropTable( - name: "MangaAltTitle"); - - migrationBuilder.DropTable( - name: "MangaTagToManga"); - - migrationBuilder.DropTable( - name: "Authors"); - - migrationBuilder.DropTable( - name: "Jobs"); - - migrationBuilder.DropTable( - name: "Tags"); - - migrationBuilder.DropTable( - name: "Chapters"); - - migrationBuilder.DropTable( - name: "Mangas"); - - migrationBuilder.DropTable( - name: "LocalLibraries"); - - migrationBuilder.DropTable( - name: "MangaConnectors"); - } - } -} diff --git a/API/Migrations/pgsql/20250516121442_AltTitle-Owned.Designer.cs b/API/Migrations/pgsql/20250516121442_AltTitle-Owned.Designer.cs deleted file mode 100644 index c97d81d..0000000 --- a/API/Migrations/pgsql/20250516121442_AltTitle-Owned.Designer.cs +++ /dev/null @@ -1,688 +0,0 @@ -// -using System; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - [DbContext(typeof(PgsqlContext))] - [Migration("20250516121442_AltTitle-Owned")] - partial class AltTitleOwned - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Author", b => - { - b.Property("AuthorId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("AuthorName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("AuthorId"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Property("ChapterId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ChapterNumber") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Downloaded") - .HasColumnType("boolean"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ParentMangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b.Property("Title") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.Property("VolumeNumber") - .HasColumnType("integer"); - - b.HasKey("ChapterId"); - - b.HasIndex("ParentMangaId"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.Property("JobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("JobType") - .HasColumnType("smallint"); - - b.Property("LastExecution") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentJobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("RecurrenceMs") - .HasColumnType("numeric(20,0)"); - - b.Property("state") - .HasColumnType("smallint"); - - b.HasKey("JobId"); - - b.HasIndex("ParentJobId"); - - b.ToTable("Jobs"); - - b.HasDiscriminator("JobType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.LocalLibrary", b => - { - b.Property("LocalLibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("BasePath") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryName") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("LocalLibraryId"); - - b.ToTable("LocalLibraries"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Property("MangaId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("CoverFileNameInCache") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("CoverUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("DirectoryName") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IgnoreChaptersBefore") - .HasColumnType("real"); - - b.Property("LibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("OriginalLanguage") - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("ReleaseStatus") - .HasColumnType("smallint"); - - b.Property("WebsiteUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Year") - .HasColumnType("bigint"); - - b.HasKey("MangaId"); - - b.HasIndex("LibraryId"); - - b.HasIndex("MangaConnectorName"); - - b.ToTable("Mangas"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.MangaTag", b => - { - b.Property("Tag") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Tag"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.Property("AuthorIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("AuthorIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("AuthorToManga"); - }); - - modelBuilder.Entity("JobJob", b => - { - b.Property("DependsOnJobsJobId") - .HasColumnType("character varying(64)"); - - b.Property("JobId") - .HasColumnType("character varying(64)"); - - b.HasKey("DependsOnJobsJobId", "JobId"); - - b.HasIndex("JobId"); - - b.ToTable("JobJob"); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.Property("MangaTagIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("MangaTagIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("MangaTagToManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("DownloadAvailableChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasDiscriminator().HasValue((byte)4); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.HasDiscriminator().HasValue((byte)0); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveFileOrFolderJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("FromLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ToLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasDiscriminator().HasValue((byte)3); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ToLibraryId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasIndex("ToLibraryId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("MoveMangaLibraryJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)7); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("RetrieveChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)5); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateFilesDownloadedJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)6); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.ComickIo", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("ComickIo"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.Global", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("Global"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("MangaDex"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.HasOne("API.Schema.Manga", "ParentManga") - .WithMany("Chapters") - .HasForeignKey("ParentMangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ParentManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.HasOne("API.Schema.Jobs.Job", "ParentJob") - .WithMany() - .HasForeignKey("ParentJobId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentJob"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.HasOne("API.Schema.LocalLibrary", "Library") - .WithMany() - .HasForeignKey("LibraryId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.OwnsMany("API.Schema.Link", "Links", b1 => - { - b1.Property("LinkId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkProvider") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.HasKey("LinkId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("Link"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.OwnsMany("API.Schema.MangaAltTitle", "AltTitles", b1 => - { - b1.Property("MangaId") - .HasColumnType("character varying(64)"); - - b1.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); - - b1.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b1.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b1.HasKey("MangaId", "Id"); - - b1.ToTable("MangaAltTitle"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.Navigation("AltTitles"); - - b.Navigation("Library"); - - b.Navigation("Links"); - - b.Navigation("MangaConnector"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.HasOne("API.Schema.Author", null) - .WithMany() - .HasForeignKey("AuthorIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("JobJob", b => - { - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("DependsOnJobsJobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("JobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MangaTag", null) - .WithMany() - .HasForeignKey("MangaTagIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.LocalLibrary", "ToLibrary") - .WithMany() - .HasForeignKey("ToLibraryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("ToLibrary"); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Navigation("Chapters"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/pgsql/20250516121442_AltTitle-Owned.cs b/API/Migrations/pgsql/20250516121442_AltTitle-Owned.cs deleted file mode 100644 index bde9cb6..0000000 --- a/API/Migrations/pgsql/20250516121442_AltTitle-Owned.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - /// - public partial class AltTitleOwned : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropPrimaryKey( - name: "PK_MangaAltTitle", - table: "MangaAltTitle"); - - migrationBuilder.DropIndex( - name: "IX_MangaAltTitle_MangaId", - table: "MangaAltTitle"); - - migrationBuilder.DropColumn( - name: "AltTitleId", - table: "MangaAltTitle"); - - migrationBuilder.AddColumn( - name: "Id", - table: "MangaAltTitle", - type: "integer", - nullable: false, - defaultValue: 0) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - migrationBuilder.AddPrimaryKey( - name: "PK_MangaAltTitle", - table: "MangaAltTitle", - columns: new[] { "MangaId", "Id" }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropPrimaryKey( - name: "PK_MangaAltTitle", - table: "MangaAltTitle"); - - migrationBuilder.DropColumn( - name: "Id", - table: "MangaAltTitle"); - - migrationBuilder.AddColumn( - name: "AltTitleId", - table: "MangaAltTitle", - type: "character varying(64)", - maxLength: 64, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddPrimaryKey( - name: "PK_MangaAltTitle", - table: "MangaAltTitle", - column: "AltTitleId"); - - migrationBuilder.CreateIndex( - name: "IX_MangaAltTitle_MangaId", - table: "MangaAltTitle", - column: "MangaId"); - } - } -} diff --git a/API/Migrations/pgsql/20250516121725_Manga-Year-Nullable.Designer.cs b/API/Migrations/pgsql/20250516121725_Manga-Year-Nullable.Designer.cs deleted file mode 100644 index 2ebe310..0000000 --- a/API/Migrations/pgsql/20250516121725_Manga-Year-Nullable.Designer.cs +++ /dev/null @@ -1,688 +0,0 @@ -// -using System; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - [DbContext(typeof(PgsqlContext))] - [Migration("20250516121725_Manga-Year-Nullable")] - partial class MangaYearNullable - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Author", b => - { - b.Property("AuthorId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("AuthorName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("AuthorId"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Property("ChapterId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ChapterNumber") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Downloaded") - .HasColumnType("boolean"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ParentMangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b.Property("Title") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.Property("VolumeNumber") - .HasColumnType("integer"); - - b.HasKey("ChapterId"); - - b.HasIndex("ParentMangaId"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.Property("JobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("JobType") - .HasColumnType("smallint"); - - b.Property("LastExecution") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentJobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("RecurrenceMs") - .HasColumnType("numeric(20,0)"); - - b.Property("state") - .HasColumnType("smallint"); - - b.HasKey("JobId"); - - b.HasIndex("ParentJobId"); - - b.ToTable("Jobs"); - - b.HasDiscriminator("JobType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.LocalLibrary", b => - { - b.Property("LocalLibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("BasePath") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryName") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("LocalLibraryId"); - - b.ToTable("LocalLibraries"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Property("MangaId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("CoverFileNameInCache") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("CoverUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("DirectoryName") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IgnoreChaptersBefore") - .HasColumnType("real"); - - b.Property("LibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("OriginalLanguage") - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("ReleaseStatus") - .HasColumnType("smallint"); - - b.Property("WebsiteUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Year") - .HasColumnType("bigint"); - - b.HasKey("MangaId"); - - b.HasIndex("LibraryId"); - - b.HasIndex("MangaConnectorName"); - - b.ToTable("Mangas"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.MangaTag", b => - { - b.Property("Tag") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Tag"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.Property("AuthorIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("AuthorIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("AuthorToManga"); - }); - - modelBuilder.Entity("JobJob", b => - { - b.Property("DependsOnJobsJobId") - .HasColumnType("character varying(64)"); - - b.Property("JobId") - .HasColumnType("character varying(64)"); - - b.HasKey("DependsOnJobsJobId", "JobId"); - - b.HasIndex("JobId"); - - b.ToTable("JobJob"); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.Property("MangaTagIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("MangaTagIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("MangaTagToManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("DownloadAvailableChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasDiscriminator().HasValue((byte)4); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.HasDiscriminator().HasValue((byte)0); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveFileOrFolderJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("FromLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ToLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasDiscriminator().HasValue((byte)3); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ToLibraryId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasIndex("ToLibraryId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("MoveMangaLibraryJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)7); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("RetrieveChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)5); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateFilesDownloadedJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)6); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.ComickIo", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("ComickIo"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.Global", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("Global"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("MangaDex"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.HasOne("API.Schema.Manga", "ParentManga") - .WithMany("Chapters") - .HasForeignKey("ParentMangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ParentManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.HasOne("API.Schema.Jobs.Job", "ParentJob") - .WithMany() - .HasForeignKey("ParentJobId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentJob"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.HasOne("API.Schema.LocalLibrary", "Library") - .WithMany() - .HasForeignKey("LibraryId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.OwnsMany("API.Schema.Link", "Links", b1 => - { - b1.Property("LinkId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkProvider") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.HasKey("LinkId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("Link"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.OwnsMany("API.Schema.MangaAltTitle", "AltTitles", b1 => - { - b1.Property("MangaId") - .HasColumnType("character varying(64)"); - - b1.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); - - b1.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b1.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b1.HasKey("MangaId", "Id"); - - b1.ToTable("MangaAltTitle"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.Navigation("AltTitles"); - - b.Navigation("Library"); - - b.Navigation("Links"); - - b.Navigation("MangaConnector"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.HasOne("API.Schema.Author", null) - .WithMany() - .HasForeignKey("AuthorIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("JobJob", b => - { - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("DependsOnJobsJobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("JobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MangaTag", null) - .WithMany() - .HasForeignKey("MangaTagIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.LocalLibrary", "ToLibrary") - .WithMany() - .HasForeignKey("ToLibraryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("ToLibrary"); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Navigation("Chapters"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/pgsql/20250516121725_Manga-Year-Nullable.cs b/API/Migrations/pgsql/20250516121725_Manga-Year-Nullable.cs deleted file mode 100644 index 9c0b7a8..0000000 --- a/API/Migrations/pgsql/20250516121725_Manga-Year-Nullable.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace API.Migrations.pgsql -{ - /// - public partial class MangaYearNullable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "Year", - table: "Mangas", - type: "bigint", - nullable: true, - oldClrType: typeof(long), - oldType: "bigint"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "Year", - table: "Mangas", - type: "bigint", - nullable: false, - defaultValue: 0L, - oldClrType: typeof(long), - oldType: "bigint", - oldNullable: true); - } - } -} diff --git a/API/Migrations/pgsql/20250516122242_AltTitle-Owned-WithId.Designer.cs b/API/Migrations/pgsql/20250516122242_AltTitle-Owned-WithId.Designer.cs deleted file mode 100644 index 7b86671..0000000 --- a/API/Migrations/pgsql/20250516122242_AltTitle-Owned-WithId.Designer.cs +++ /dev/null @@ -1,689 +0,0 @@ -// -using System; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - [DbContext(typeof(PgsqlContext))] - [Migration("20250516122242_AltTitle-Owned-WithId")] - partial class AltTitleOwnedWithId - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Author", b => - { - b.Property("AuthorId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("AuthorName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("AuthorId"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Property("ChapterId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ChapterNumber") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Downloaded") - .HasColumnType("boolean"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ParentMangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b.Property("Title") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.Property("VolumeNumber") - .HasColumnType("integer"); - - b.HasKey("ChapterId"); - - b.HasIndex("ParentMangaId"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.Property("JobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("JobType") - .HasColumnType("smallint"); - - b.Property("LastExecution") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentJobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("RecurrenceMs") - .HasColumnType("numeric(20,0)"); - - b.Property("state") - .HasColumnType("smallint"); - - b.HasKey("JobId"); - - b.HasIndex("ParentJobId"); - - b.ToTable("Jobs"); - - b.HasDiscriminator("JobType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.LocalLibrary", b => - { - b.Property("LocalLibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("BasePath") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryName") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("LocalLibraryId"); - - b.ToTable("LocalLibraries"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Property("MangaId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("CoverFileNameInCache") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("CoverUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("DirectoryName") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IgnoreChaptersBefore") - .HasColumnType("real"); - - b.Property("LibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("OriginalLanguage") - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("ReleaseStatus") - .HasColumnType("smallint"); - - b.Property("WebsiteUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Year") - .HasColumnType("bigint"); - - b.HasKey("MangaId"); - - b.HasIndex("LibraryId"); - - b.HasIndex("MangaConnectorName"); - - b.ToTable("Mangas"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.MangaTag", b => - { - b.Property("Tag") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Tag"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.Property("AuthorIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("AuthorIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("AuthorToManga"); - }); - - modelBuilder.Entity("JobJob", b => - { - b.Property("DependsOnJobsJobId") - .HasColumnType("character varying(64)"); - - b.Property("JobId") - .HasColumnType("character varying(64)"); - - b.HasKey("DependsOnJobsJobId", "JobId"); - - b.HasIndex("JobId"); - - b.ToTable("JobJob"); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.Property("MangaTagIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("MangaTagIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("MangaTagToManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("DownloadAvailableChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasDiscriminator().HasValue((byte)4); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.HasDiscriminator().HasValue((byte)0); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveFileOrFolderJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("FromLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ToLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasDiscriminator().HasValue((byte)3); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ToLibraryId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasIndex("ToLibraryId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("MoveMangaLibraryJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)7); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("RetrieveChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)5); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateFilesDownloadedJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)6); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.ComickIo", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("ComickIo"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.Global", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("Global"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("MangaDex"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.HasOne("API.Schema.Manga", "ParentManga") - .WithMany("Chapters") - .HasForeignKey("ParentMangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ParentManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.HasOne("API.Schema.Jobs.Job", "ParentJob") - .WithMany() - .HasForeignKey("ParentJobId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentJob"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.HasOne("API.Schema.LocalLibrary", "Library") - .WithMany() - .HasForeignKey("LibraryId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.OwnsMany("API.Schema.Link", "Links", b1 => - { - b1.Property("LinkId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkProvider") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.HasKey("LinkId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("Link"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.OwnsMany("API.Schema.MangaAltTitle", "AltTitles", b1 => - { - b1.Property("AltTitleId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b1.HasKey("AltTitleId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("MangaAltTitle"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.Navigation("AltTitles"); - - b.Navigation("Library"); - - b.Navigation("Links"); - - b.Navigation("MangaConnector"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.HasOne("API.Schema.Author", null) - .WithMany() - .HasForeignKey("AuthorIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("JobJob", b => - { - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("DependsOnJobsJobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("JobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MangaTag", null) - .WithMany() - .HasForeignKey("MangaTagIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.LocalLibrary", "ToLibrary") - .WithMany() - .HasForeignKey("ToLibraryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("ToLibrary"); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Navigation("Chapters"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/pgsql/20250516122242_AltTitle-Owned-WithId.cs b/API/Migrations/pgsql/20250516122242_AltTitle-Owned-WithId.cs deleted file mode 100644 index 3814d95..0000000 --- a/API/Migrations/pgsql/20250516122242_AltTitle-Owned-WithId.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - /// - public partial class AltTitleOwnedWithId : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropPrimaryKey( - name: "PK_MangaAltTitle", - table: "MangaAltTitle"); - - migrationBuilder.DropColumn( - name: "Id", - table: "MangaAltTitle"); - - migrationBuilder.AddColumn( - name: "AltTitleId", - table: "MangaAltTitle", - type: "character varying(64)", - maxLength: 64, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddPrimaryKey( - name: "PK_MangaAltTitle", - table: "MangaAltTitle", - column: "AltTitleId"); - - migrationBuilder.CreateIndex( - name: "IX_MangaAltTitle_MangaId", - table: "MangaAltTitle", - column: "MangaId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropPrimaryKey( - name: "PK_MangaAltTitle", - table: "MangaAltTitle"); - - migrationBuilder.DropIndex( - name: "IX_MangaAltTitle_MangaId", - table: "MangaAltTitle"); - - migrationBuilder.DropColumn( - name: "AltTitleId", - table: "MangaAltTitle"); - - migrationBuilder.AddColumn( - name: "Id", - table: "MangaAltTitle", - type: "integer", - nullable: false, - defaultValue: 0) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - migrationBuilder.AddPrimaryKey( - name: "PK_MangaAltTitle", - table: "MangaAltTitle", - columns: new[] { "MangaId", "Id" }); - } - } -} diff --git a/API/Migrations/pgsql/20250516180953_Split-UpdateChaptersDownloadedJob-Into-UpdateSingleChapterDownloadedJob.Designer.cs b/API/Migrations/pgsql/20250516180953_Split-UpdateChaptersDownloadedJob-Into-UpdateSingleChapterDownloadedJob.Designer.cs deleted file mode 100644 index effec49..0000000 --- a/API/Migrations/pgsql/20250516180953_Split-UpdateChaptersDownloadedJob-Into-UpdateSingleChapterDownloadedJob.Designer.cs +++ /dev/null @@ -1,720 +0,0 @@ -// -using System; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - [DbContext(typeof(PgsqlContext))] - [Migration("20250516180953_Split-UpdateChaptersDownloadedJob-Into-UpdateSingleChapterDownloadedJob")] - partial class SplitUpdateChaptersDownloadedJobIntoUpdateSingleChapterDownloadedJob - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Author", b => - { - b.Property("AuthorId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("AuthorName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("AuthorId"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Property("ChapterId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ChapterNumber") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Downloaded") - .HasColumnType("boolean"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ParentMangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b.Property("Title") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.Property("VolumeNumber") - .HasColumnType("integer"); - - b.HasKey("ChapterId"); - - b.HasIndex("ParentMangaId"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.Property("JobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("JobType") - .HasColumnType("smallint"); - - b.Property("LastExecution") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentJobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("RecurrenceMs") - .HasColumnType("numeric(20,0)"); - - b.Property("state") - .HasColumnType("smallint"); - - b.HasKey("JobId"); - - b.HasIndex("ParentJobId"); - - b.ToTable("Jobs"); - - b.HasDiscriminator("JobType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.LocalLibrary", b => - { - b.Property("LocalLibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("BasePath") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryName") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("LocalLibraryId"); - - b.ToTable("LocalLibraries"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Property("MangaId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("CoverFileNameInCache") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("CoverUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("DirectoryName") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IgnoreChaptersBefore") - .HasColumnType("real"); - - b.Property("LibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("OriginalLanguage") - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("ReleaseStatus") - .HasColumnType("smallint"); - - b.Property("WebsiteUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Year") - .HasColumnType("bigint"); - - b.HasKey("MangaId"); - - b.HasIndex("LibraryId"); - - b.HasIndex("MangaConnectorName"); - - b.ToTable("Mangas"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.MangaTag", b => - { - b.Property("Tag") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Tag"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.Property("AuthorIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("AuthorIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("AuthorToManga"); - }); - - modelBuilder.Entity("JobJob", b => - { - b.Property("DependsOnJobsJobId") - .HasColumnType("character varying(64)"); - - b.Property("JobId") - .HasColumnType("character varying(64)"); - - b.HasKey("DependsOnJobsJobId", "JobId"); - - b.HasIndex("JobId"); - - b.ToTable("JobJob"); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.Property("MangaTagIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("MangaTagIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("MangaTagToManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("DownloadAvailableChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasDiscriminator().HasValue((byte)4); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.HasDiscriminator().HasValue((byte)0); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveFileOrFolderJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("FromLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ToLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasDiscriminator().HasValue((byte)3); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ToLibraryId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasIndex("ToLibraryId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("MoveMangaLibraryJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)7); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("RetrieveChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)5); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateChaptersDownloadedJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)6); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateSingleChapterDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.ToTable("Jobs", t => - { - t.Property("ChapterId") - .HasColumnName("UpdateSingleChapterDownloadedJob_ChapterId"); - }); - - b.HasDiscriminator().HasValue((byte)8); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.ComickIo", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("ComickIo"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.Global", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("Global"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("MangaDex"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.HasOne("API.Schema.Manga", "ParentManga") - .WithMany("Chapters") - .HasForeignKey("ParentMangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ParentManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.HasOne("API.Schema.Jobs.Job", "ParentJob") - .WithMany() - .HasForeignKey("ParentJobId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentJob"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.HasOne("API.Schema.LocalLibrary", "Library") - .WithMany() - .HasForeignKey("LibraryId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.OwnsMany("API.Schema.Link", "Links", b1 => - { - b1.Property("LinkId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkProvider") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.HasKey("LinkId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("Link"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.OwnsMany("API.Schema.MangaAltTitle", "AltTitles", b1 => - { - b1.Property("AltTitleId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b1.HasKey("AltTitleId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("MangaAltTitle"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.Navigation("AltTitles"); - - b.Navigation("Library"); - - b.Navigation("Links"); - - b.Navigation("MangaConnector"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.HasOne("API.Schema.Author", null) - .WithMany() - .HasForeignKey("AuthorIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("JobJob", b => - { - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("DependsOnJobsJobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("JobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MangaTag", null) - .WithMany() - .HasForeignKey("MangaTagIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.LocalLibrary", "ToLibrary") - .WithMany() - .HasForeignKey("ToLibraryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("ToLibrary"); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateSingleChapterDownloadedJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Navigation("Chapters"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/pgsql/20250516180953_Split-UpdateChaptersDownloadedJob-Into-UpdateSingleChapterDownloadedJob.cs b/API/Migrations/pgsql/20250516180953_Split-UpdateChaptersDownloadedJob-Into-UpdateSingleChapterDownloadedJob.cs deleted file mode 100644 index eff3b29..0000000 --- a/API/Migrations/pgsql/20250516180953_Split-UpdateChaptersDownloadedJob-Into-UpdateSingleChapterDownloadedJob.cs +++ /dev/null @@ -1,94 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace API.Migrations.pgsql -{ - /// - public partial class SplitUpdateChaptersDownloadedJobIntoUpdateSingleChapterDownloadedJob : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_UpdateFilesDownloadedJob_MangaId", - table: "Jobs"); - - migrationBuilder.RenameColumn( - name: "UpdateFilesDownloadedJob_MangaId", - table: "Jobs", - newName: "UpdateChaptersDownloadedJob_MangaId"); - - migrationBuilder.RenameIndex( - name: "IX_Jobs_UpdateFilesDownloadedJob_MangaId", - table: "Jobs", - newName: "IX_Jobs_UpdateChaptersDownloadedJob_MangaId"); - - migrationBuilder.AddColumn( - name: "UpdateSingleChapterDownloadedJob_ChapterId", - table: "Jobs", - type: "character varying(64)", - maxLength: 64, - nullable: true); - - migrationBuilder.CreateIndex( - name: "IX_Jobs_UpdateSingleChapterDownloadedJob_ChapterId", - table: "Jobs", - column: "UpdateSingleChapterDownloadedJob_ChapterId"); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Chapters_UpdateSingleChapterDownloadedJob_ChapterId", - table: "Jobs", - column: "UpdateSingleChapterDownloadedJob_ChapterId", - principalTable: "Chapters", - principalColumn: "ChapterId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_UpdateChaptersDownloadedJob_MangaId", - table: "Jobs", - column: "UpdateChaptersDownloadedJob_MangaId", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Chapters_UpdateSingleChapterDownloadedJob_ChapterId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_UpdateChaptersDownloadedJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropIndex( - name: "IX_Jobs_UpdateSingleChapterDownloadedJob_ChapterId", - table: "Jobs"); - - migrationBuilder.DropColumn( - name: "UpdateSingleChapterDownloadedJob_ChapterId", - table: "Jobs"); - - migrationBuilder.RenameColumn( - name: "UpdateChaptersDownloadedJob_MangaId", - table: "Jobs", - newName: "UpdateFilesDownloadedJob_MangaId"); - - migrationBuilder.RenameIndex( - name: "IX_Jobs_UpdateChaptersDownloadedJob_MangaId", - table: "Jobs", - newName: "IX_Jobs_UpdateFilesDownloadedJob_MangaId"); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_UpdateFilesDownloadedJob_MangaId", - table: "Jobs", - column: "UpdateFilesDownloadedJob_MangaId", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - } - } -} diff --git a/API/Migrations/pgsql/20250518142903_Chapter-IdOnConnectorSite.Designer.cs b/API/Migrations/pgsql/20250518142903_Chapter-IdOnConnectorSite.Designer.cs deleted file mode 100644 index ab6324c..0000000 --- a/API/Migrations/pgsql/20250518142903_Chapter-IdOnConnectorSite.Designer.cs +++ /dev/null @@ -1,724 +0,0 @@ -// -using System; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - [DbContext(typeof(PgsqlContext))] - [Migration("20250518142903_Chapter-IdOnConnectorSite")] - partial class ChapterIdOnConnectorSite - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Author", b => - { - b.Property("AuthorId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("AuthorName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("AuthorId"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Property("ChapterId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ChapterNumber") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Downloaded") - .HasColumnType("boolean"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IdOnConnectorSite") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ParentMangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b.Property("Title") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.Property("VolumeNumber") - .HasColumnType("integer"); - - b.HasKey("ChapterId"); - - b.HasIndex("ParentMangaId"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.Property("JobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("JobType") - .HasColumnType("smallint"); - - b.Property("LastExecution") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentJobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("RecurrenceMs") - .HasColumnType("numeric(20,0)"); - - b.Property("state") - .HasColumnType("smallint"); - - b.HasKey("JobId"); - - b.HasIndex("ParentJobId"); - - b.ToTable("Jobs"); - - b.HasDiscriminator("JobType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.LocalLibrary", b => - { - b.Property("LocalLibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("BasePath") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryName") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("LocalLibraryId"); - - b.ToTable("LocalLibraries"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Property("MangaId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("CoverFileNameInCache") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("CoverUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("DirectoryName") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IgnoreChaptersBefore") - .HasColumnType("real"); - - b.Property("LibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("OriginalLanguage") - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("ReleaseStatus") - .HasColumnType("smallint"); - - b.Property("WebsiteUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Year") - .HasColumnType("bigint"); - - b.HasKey("MangaId"); - - b.HasIndex("LibraryId"); - - b.HasIndex("MangaConnectorName"); - - b.ToTable("Mangas"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.MangaTag", b => - { - b.Property("Tag") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Tag"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.Property("AuthorIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("AuthorIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("AuthorToManga"); - }); - - modelBuilder.Entity("JobJob", b => - { - b.Property("DependsOnJobsJobId") - .HasColumnType("character varying(64)"); - - b.Property("JobId") - .HasColumnType("character varying(64)"); - - b.HasKey("DependsOnJobsJobId", "JobId"); - - b.HasIndex("JobId"); - - b.ToTable("JobJob"); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.Property("MangaTagIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("MangaTagIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("MangaTagToManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("DownloadAvailableChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasDiscriminator().HasValue((byte)4); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.HasDiscriminator().HasValue((byte)0); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveFileOrFolderJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("FromLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ToLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasDiscriminator().HasValue((byte)3); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ToLibraryId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasIndex("ToLibraryId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("MoveMangaLibraryJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)7); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("RetrieveChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)5); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateChaptersDownloadedJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)6); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateSingleChapterDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.ToTable("Jobs", t => - { - t.Property("ChapterId") - .HasColumnName("UpdateSingleChapterDownloadedJob_ChapterId"); - }); - - b.HasDiscriminator().HasValue((byte)8); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.ComickIo", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("ComickIo"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.Global", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("Global"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("MangaDex"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.HasOne("API.Schema.Manga", "ParentManga") - .WithMany("Chapters") - .HasForeignKey("ParentMangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ParentManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.HasOne("API.Schema.Jobs.Job", "ParentJob") - .WithMany() - .HasForeignKey("ParentJobId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentJob"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.HasOne("API.Schema.LocalLibrary", "Library") - .WithMany() - .HasForeignKey("LibraryId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.OwnsMany("API.Schema.Link", "Links", b1 => - { - b1.Property("LinkId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkProvider") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.HasKey("LinkId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("Link"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.OwnsMany("API.Schema.MangaAltTitle", "AltTitles", b1 => - { - b1.Property("AltTitleId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b1.HasKey("AltTitleId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("MangaAltTitle"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.Navigation("AltTitles"); - - b.Navigation("Library"); - - b.Navigation("Links"); - - b.Navigation("MangaConnector"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.HasOne("API.Schema.Author", null) - .WithMany() - .HasForeignKey("AuthorIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("JobJob", b => - { - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("DependsOnJobsJobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("JobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MangaTag", null) - .WithMany() - .HasForeignKey("MangaTagIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.LocalLibrary", "ToLibrary") - .WithMany() - .HasForeignKey("ToLibraryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("ToLibrary"); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateSingleChapterDownloadedJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Navigation("Chapters"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/pgsql/20250518142903_Chapter-IdOnConnectorSite.cs b/API/Migrations/pgsql/20250518142903_Chapter-IdOnConnectorSite.cs deleted file mode 100644 index c15b30e..0000000 --- a/API/Migrations/pgsql/20250518142903_Chapter-IdOnConnectorSite.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace API.Migrations.pgsql -{ - /// - public partial class ChapterIdOnConnectorSite : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "IdOnConnectorSite", - table: "Chapters", - type: "character varying(256)", - maxLength: 256, - nullable: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "IdOnConnectorSite", - table: "Chapters"); - } - } -} diff --git a/API/Migrations/pgsql/20250518161710_UpdateCoverJob.Designer.cs b/API/Migrations/pgsql/20250518161710_UpdateCoverJob.Designer.cs deleted file mode 100644 index a62ed0d..0000000 --- a/API/Migrations/pgsql/20250518161710_UpdateCoverJob.Designer.cs +++ /dev/null @@ -1,755 +0,0 @@ -// -using System; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - [DbContext(typeof(PgsqlContext))] - [Migration("20250518161710_UpdateCoverJob")] - partial class UpdateCoverJob - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Author", b => - { - b.Property("AuthorId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("AuthorName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("AuthorId"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Property("ChapterId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ChapterNumber") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Downloaded") - .HasColumnType("boolean"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IdOnConnectorSite") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ParentMangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b.Property("Title") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.Property("VolumeNumber") - .HasColumnType("integer"); - - b.HasKey("ChapterId"); - - b.HasIndex("ParentMangaId"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.Property("JobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("JobType") - .HasColumnType("smallint"); - - b.Property("LastExecution") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentJobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("RecurrenceMs") - .HasColumnType("numeric(20,0)"); - - b.Property("state") - .HasColumnType("smallint"); - - b.HasKey("JobId"); - - b.HasIndex("ParentJobId"); - - b.ToTable("Jobs"); - - b.HasDiscriminator("JobType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.LocalLibrary", b => - { - b.Property("LocalLibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("BasePath") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryName") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("LocalLibraryId"); - - b.ToTable("LocalLibraries"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Property("MangaId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("CoverFileNameInCache") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("CoverUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("DirectoryName") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IgnoreChaptersBefore") - .HasColumnType("real"); - - b.Property("LibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("OriginalLanguage") - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("ReleaseStatus") - .HasColumnType("smallint"); - - b.Property("WebsiteUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Year") - .HasColumnType("bigint"); - - b.HasKey("MangaId"); - - b.HasIndex("LibraryId"); - - b.HasIndex("MangaConnectorName"); - - b.ToTable("Mangas"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.MangaTag", b => - { - b.Property("Tag") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Tag"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.Property("AuthorIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("AuthorIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("AuthorToManga"); - }); - - modelBuilder.Entity("JobJob", b => - { - b.Property("DependsOnJobsJobId") - .HasColumnType("character varying(64)"); - - b.Property("JobId") - .HasColumnType("character varying(64)"); - - b.HasKey("DependsOnJobsJobId", "JobId"); - - b.HasIndex("JobId"); - - b.ToTable("JobJob"); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.Property("MangaTagIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("MangaTagIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("MangaTagToManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("DownloadAvailableChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasDiscriminator().HasValue((byte)4); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.HasDiscriminator().HasValue((byte)0); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveFileOrFolderJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("FromLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ToLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasDiscriminator().HasValue((byte)3); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ToLibraryId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasIndex("ToLibraryId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("MoveMangaLibraryJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)7); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("RetrieveChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)5); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateChaptersDownloadedJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)6); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateCoverJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)9); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateSingleChapterDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.ToTable("Jobs", t => - { - t.Property("ChapterId") - .HasColumnName("UpdateSingleChapterDownloadedJob_ChapterId"); - }); - - b.HasDiscriminator().HasValue((byte)8); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.ComickIo", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("ComickIo"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.Global", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("Global"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("MangaDex"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.HasOne("API.Schema.Manga", "ParentManga") - .WithMany("Chapters") - .HasForeignKey("ParentMangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ParentManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.HasOne("API.Schema.Jobs.Job", "ParentJob") - .WithMany() - .HasForeignKey("ParentJobId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentJob"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.HasOne("API.Schema.LocalLibrary", "Library") - .WithMany() - .HasForeignKey("LibraryId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.OwnsMany("API.Schema.Link", "Links", b1 => - { - b1.Property("LinkId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkProvider") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.HasKey("LinkId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("Link"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.OwnsMany("API.Schema.MangaAltTitle", "AltTitles", b1 => - { - b1.Property("AltTitleId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b1.HasKey("AltTitleId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("MangaAltTitle"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.Navigation("AltTitles"); - - b.Navigation("Library"); - - b.Navigation("Links"); - - b.Navigation("MangaConnector"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.HasOne("API.Schema.Author", null) - .WithMany() - .HasForeignKey("AuthorIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("JobJob", b => - { - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("DependsOnJobsJobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("JobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MangaTag", null) - .WithMany() - .HasForeignKey("MangaTagIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.LocalLibrary", "ToLibrary") - .WithMany() - .HasForeignKey("ToLibraryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("ToLibrary"); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateSingleChapterDownloadedJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Navigation("Chapters"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/pgsql/20250518161710_UpdateCoverJob.cs b/API/Migrations/pgsql/20250518161710_UpdateCoverJob.cs deleted file mode 100644 index ef4a40c..0000000 --- a/API/Migrations/pgsql/20250518161710_UpdateCoverJob.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace API.Migrations.pgsql -{ - /// - public partial class UpdateCoverJob : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "UpdateCoverJob_MangaId", - table: "Jobs", - type: "character varying(64)", - maxLength: 64, - nullable: true); - - migrationBuilder.CreateIndex( - name: "IX_Jobs_UpdateCoverJob_MangaId", - table: "Jobs", - column: "UpdateCoverJob_MangaId"); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_UpdateCoverJob_MangaId", - table: "Jobs", - column: "UpdateCoverJob_MangaId", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_UpdateCoverJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropIndex( - name: "IX_Jobs_UpdateCoverJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropColumn( - name: "UpdateCoverJob_MangaId", - table: "Jobs"); - } - } -} diff --git a/API/Migrations/pgsql/20250518183729_Remove-UpdateSingleChapterDownloaded-Job.Designer.cs b/API/Migrations/pgsql/20250518183729_Remove-UpdateSingleChapterDownloaded-Job.Designer.cs deleted file mode 100644 index 18fbaee..0000000 --- a/API/Migrations/pgsql/20250518183729_Remove-UpdateSingleChapterDownloaded-Job.Designer.cs +++ /dev/null @@ -1,724 +0,0 @@ -// -using System; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - [DbContext(typeof(PgsqlContext))] - [Migration("20250518183729_Remove-UpdateSingleChapterDownloaded-Job")] - partial class RemoveUpdateSingleChapterDownloadedJob - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Author", b => - { - b.Property("AuthorId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("AuthorName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("AuthorId"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Property("ChapterId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ChapterNumber") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Downloaded") - .HasColumnType("boolean"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IdOnConnectorSite") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ParentMangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b.Property("Title") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.Property("VolumeNumber") - .HasColumnType("integer"); - - b.HasKey("ChapterId"); - - b.HasIndex("ParentMangaId"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.Property("JobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("JobType") - .HasColumnType("smallint"); - - b.Property("LastExecution") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentJobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("RecurrenceMs") - .HasColumnType("numeric(20,0)"); - - b.Property("state") - .HasColumnType("smallint"); - - b.HasKey("JobId"); - - b.HasIndex("ParentJobId"); - - b.ToTable("Jobs"); - - b.HasDiscriminator("JobType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.LocalLibrary", b => - { - b.Property("LocalLibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("BasePath") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryName") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("LocalLibraryId"); - - b.ToTable("LocalLibraries"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Property("MangaId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("CoverFileNameInCache") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("CoverUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("DirectoryName") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IgnoreChaptersBefore") - .HasColumnType("real"); - - b.Property("LibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("OriginalLanguage") - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("ReleaseStatus") - .HasColumnType("smallint"); - - b.Property("WebsiteUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Year") - .HasColumnType("bigint"); - - b.HasKey("MangaId"); - - b.HasIndex("LibraryId"); - - b.HasIndex("MangaConnectorName"); - - b.ToTable("Mangas"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.MangaTag", b => - { - b.Property("Tag") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Tag"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.Property("AuthorIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("AuthorIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("AuthorToManga"); - }); - - modelBuilder.Entity("JobJob", b => - { - b.Property("DependsOnJobsJobId") - .HasColumnType("character varying(64)"); - - b.Property("JobId") - .HasColumnType("character varying(64)"); - - b.HasKey("DependsOnJobsJobId", "JobId"); - - b.HasIndex("JobId"); - - b.ToTable("JobJob"); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.Property("MangaTagIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("MangaTagIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("MangaTagToManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("DownloadAvailableChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasDiscriminator().HasValue((byte)4); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.HasDiscriminator().HasValue((byte)0); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveFileOrFolderJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("FromLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ToLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasDiscriminator().HasValue((byte)3); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ToLibraryId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasIndex("ToLibraryId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("MoveMangaLibraryJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)7); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("RetrieveChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)5); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateChaptersDownloadedJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)6); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateCoverJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)9); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.ComickIo", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("ComickIo"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.Global", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("Global"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("MangaDex"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.HasOne("API.Schema.Manga", "ParentManga") - .WithMany("Chapters") - .HasForeignKey("ParentMangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ParentManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.HasOne("API.Schema.Jobs.Job", "ParentJob") - .WithMany() - .HasForeignKey("ParentJobId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentJob"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.HasOne("API.Schema.LocalLibrary", "Library") - .WithMany() - .HasForeignKey("LibraryId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.OwnsMany("API.Schema.Link", "Links", b1 => - { - b1.Property("LinkId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkProvider") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.HasKey("LinkId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("Link"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.OwnsMany("API.Schema.MangaAltTitle", "AltTitles", b1 => - { - b1.Property("AltTitleId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b1.HasKey("AltTitleId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("MangaAltTitle"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.Navigation("AltTitles"); - - b.Navigation("Library"); - - b.Navigation("Links"); - - b.Navigation("MangaConnector"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.HasOne("API.Schema.Author", null) - .WithMany() - .HasForeignKey("AuthorIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("JobJob", b => - { - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("DependsOnJobsJobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("JobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MangaTag", null) - .WithMany() - .HasForeignKey("MangaTagIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.LocalLibrary", "ToLibrary") - .WithMany() - .HasForeignKey("ToLibraryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("ToLibrary"); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Navigation("Chapters"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/pgsql/20250518183729_Remove-UpdateSingleChapterDownloaded-Job.cs b/API/Migrations/pgsql/20250518183729_Remove-UpdateSingleChapterDownloaded-Job.cs deleted file mode 100644 index cc683c1..0000000 --- a/API/Migrations/pgsql/20250518183729_Remove-UpdateSingleChapterDownloaded-Job.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace API.Migrations.pgsql -{ - /// - public partial class RemoveUpdateSingleChapterDownloadedJob : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Chapters_UpdateSingleChapterDownloadedJob_ChapterId", - table: "Jobs"); - - migrationBuilder.DropIndex( - name: "IX_Jobs_UpdateSingleChapterDownloadedJob_ChapterId", - table: "Jobs"); - - migrationBuilder.DropColumn( - name: "UpdateSingleChapterDownloadedJob_ChapterId", - table: "Jobs"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "UpdateSingleChapterDownloadedJob_ChapterId", - table: "Jobs", - type: "character varying(64)", - maxLength: 64, - nullable: true); - - migrationBuilder.CreateIndex( - name: "IX_Jobs_UpdateSingleChapterDownloadedJob_ChapterId", - table: "Jobs", - column: "UpdateSingleChapterDownloadedJob_ChapterId"); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Chapters_UpdateSingleChapterDownloadedJob_ChapterId", - table: "Jobs", - column: "UpdateSingleChapterDownloadedJob_ChapterId", - principalTable: "Chapters", - principalColumn: "ChapterId", - onDelete: ReferentialAction.Cascade); - } - } -} diff --git a/API/Migrations/pgsql/20250628204956_AddMAL.Designer.cs b/API/Migrations/pgsql/20250628204956_AddMAL.Designer.cs deleted file mode 100644 index e5ada84..0000000 --- a/API/Migrations/pgsql/20250628204956_AddMAL.Designer.cs +++ /dev/null @@ -1,788 +0,0 @@ -// -using System; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - [DbContext(typeof(PgsqlContext))] - [Migration("20250628204956_AddMAL")] - partial class AddMAL - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Author", b => - { - b.Property("AuthorId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("AuthorName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("AuthorId"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Property("ChapterId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ChapterNumber") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Downloaded") - .HasColumnType("boolean"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IdOnConnectorSite") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ParentMangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b.Property("Title") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.Property("VolumeNumber") - .HasColumnType("integer"); - - b.HasKey("ChapterId"); - - b.HasIndex("ParentMangaId"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.Property("JobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("JobType") - .HasColumnType("smallint"); - - b.Property("LastExecution") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentJobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("RecurrenceMs") - .HasColumnType("numeric(20,0)"); - - b.Property("state") - .HasColumnType("smallint"); - - b.HasKey("JobId"); - - b.HasIndex("ParentJobId"); - - b.ToTable("Jobs"); - - b.HasDiscriminator("JobType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.LocalLibrary", b => - { - b.Property("LocalLibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("BasePath") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryName") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("LocalLibraryId"); - - b.ToTable("LocalLibraries"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Property("MangaId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("CoverFileNameInCache") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("CoverUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("DirectoryName") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IgnoreChaptersBefore") - .HasColumnType("real"); - - b.Property("LibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("OriginalLanguage") - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("ReleaseStatus") - .HasColumnType("smallint"); - - b.Property("WebsiteUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Year") - .HasColumnType("bigint"); - - b.HasKey("MangaId"); - - b.HasIndex("LibraryId"); - - b.HasIndex("MangaConnectorName"); - - b.ToTable("Mangas"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.MangaTag", b => - { - b.Property("Tag") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Tag"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("API.Schema.MetadataFetchers.MetadataEntry", b => - { - b.Property("MangaId") - .HasColumnType("character varying(64)"); - - b.Property("MetadataFetcherName") - .HasColumnType("text"); - - b.Property("Identifier") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("MangaId", "MetadataFetcherName"); - - b.HasIndex("MetadataFetcherName"); - - b.ToTable("MetadataEntries"); - }); - - modelBuilder.Entity("API.Schema.MetadataFetchers.MetadataFetcher", b => - { - b.Property("MetadataFetcherName") - .HasColumnType("text"); - - b.Property("MetadataEntry") - .IsRequired() - .HasMaxLength(21) - .HasColumnType("character varying(21)"); - - b.HasKey("MetadataFetcherName"); - - b.ToTable("MetadataFetcher"); - - b.HasDiscriminator("MetadataEntry").HasValue("MetadataFetcher"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.Property("AuthorIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("AuthorIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("AuthorToManga"); - }); - - modelBuilder.Entity("JobJob", b => - { - b.Property("DependsOnJobsJobId") - .HasColumnType("character varying(64)"); - - b.Property("JobId") - .HasColumnType("character varying(64)"); - - b.HasKey("DependsOnJobsJobId", "JobId"); - - b.HasIndex("JobId"); - - b.ToTable("JobJob"); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.Property("MangaTagIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("MangaTagIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("MangaTagToManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("DownloadAvailableChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasDiscriminator().HasValue((byte)4); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.HasDiscriminator().HasValue((byte)0); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveFileOrFolderJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("FromLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ToLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasDiscriminator().HasValue((byte)3); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ToLibraryId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasIndex("ToLibraryId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("MoveMangaLibraryJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)7); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("RetrieveChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)5); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateChaptersDownloadedJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)6); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateCoverJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)9); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.ComickIo", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("ComickIo"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.Global", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("Global"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("MangaDex"); - }); - - modelBuilder.Entity("API.Schema.MetadataFetchers.MyAnimeList", b => - { - b.HasBaseType("API.Schema.MetadataFetchers.MetadataFetcher"); - - b.HasDiscriminator().HasValue("MyAnimeList"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.HasOne("API.Schema.Manga", "ParentManga") - .WithMany("Chapters") - .HasForeignKey("ParentMangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ParentManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.HasOne("API.Schema.Jobs.Job", "ParentJob") - .WithMany() - .HasForeignKey("ParentJobId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentJob"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.HasOne("API.Schema.LocalLibrary", "Library") - .WithMany() - .HasForeignKey("LibraryId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.OwnsMany("API.Schema.Link", "Links", b1 => - { - b1.Property("LinkId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkProvider") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.HasKey("LinkId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("Link"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.OwnsMany("API.Schema.MangaAltTitle", "AltTitles", b1 => - { - b1.Property("AltTitleId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b1.HasKey("AltTitleId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("MangaAltTitle"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.Navigation("AltTitles"); - - b.Navigation("Library"); - - b.Navigation("Links"); - - b.Navigation("MangaConnector"); - }); - - modelBuilder.Entity("API.Schema.MetadataFetchers.MetadataEntry", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MetadataFetchers.MetadataFetcher", "MetadataFetcher") - .WithMany() - .HasForeignKey("MetadataFetcherName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("MetadataFetcher"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.HasOne("API.Schema.Author", null) - .WithMany() - .HasForeignKey("AuthorIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("JobJob", b => - { - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("DependsOnJobsJobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("JobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MangaTag", null) - .WithMany() - .HasForeignKey("MangaTagIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.LocalLibrary", "ToLibrary") - .WithMany() - .HasForeignKey("ToLibraryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("ToLibrary"); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Navigation("Chapters"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/pgsql/20250628204956_AddMAL.cs b/API/Migrations/pgsql/20250628204956_AddMAL.cs deleted file mode 100644 index 1ddb427..0000000 --- a/API/Migrations/pgsql/20250628204956_AddMAL.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace API.Migrations.pgsql -{ - /// - public partial class AddMAL : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "MetadataFetcher", - columns: table => new - { - MetadataFetcherName = table.Column(type: "text", nullable: false), - MetadataEntry = table.Column(type: "character varying(21)", maxLength: 21, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_MetadataFetcher", x => x.MetadataFetcherName); - }); - - migrationBuilder.CreateTable( - name: "MetadataEntries", - columns: table => new - { - MangaId = table.Column(type: "character varying(64)", nullable: false), - MetadataFetcherName = table.Column(type: "text", nullable: false), - Identifier = table.Column(type: "text", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_MetadataEntries", x => new { x.MangaId, x.MetadataFetcherName }); - table.ForeignKey( - name: "FK_MetadataEntries_Mangas_MangaId", - column: x => x.MangaId, - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_MetadataEntries_MetadataFetcher_MetadataFetcherName", - column: x => x.MetadataFetcherName, - principalTable: "MetadataFetcher", - principalColumn: "MetadataFetcherName", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_MetadataEntries_MetadataFetcherName", - table: "MetadataEntries", - column: "MetadataFetcherName"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "MetadataEntries"); - - migrationBuilder.DropTable( - name: "MetadataFetcher"); - } - } -} diff --git a/API/Migrations/pgsql/20250629184056_MetadataEntry-PrimaryKeyChange.Designer.cs b/API/Migrations/pgsql/20250629184056_MetadataEntry-PrimaryKeyChange.Designer.cs deleted file mode 100644 index a7f35e7..0000000 --- a/API/Migrations/pgsql/20250629184056_MetadataEntry-PrimaryKeyChange.Designer.cs +++ /dev/null @@ -1,788 +0,0 @@ -// -using System; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - [DbContext(typeof(PgsqlContext))] - [Migration("20250629184056_MetadataEntry-PrimaryKeyChange")] - partial class MetadataEntryPrimaryKeyChange - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Author", b => - { - b.Property("AuthorId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("AuthorName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("AuthorId"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Property("ChapterId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ChapterNumber") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Downloaded") - .HasColumnType("boolean"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IdOnConnectorSite") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ParentMangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b.Property("Title") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("Url") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.Property("VolumeNumber") - .HasColumnType("integer"); - - b.HasKey("ChapterId"); - - b.HasIndex("ParentMangaId"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.Property("JobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("JobType") - .HasColumnType("smallint"); - - b.Property("LastExecution") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentJobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("RecurrenceMs") - .HasColumnType("numeric(20,0)"); - - b.Property("state") - .HasColumnType("smallint"); - - b.HasKey("JobId"); - - b.HasIndex("ParentJobId"); - - b.ToTable("Jobs"); - - b.HasDiscriminator("JobType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.LocalLibrary", b => - { - b.Property("LocalLibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("BasePath") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryName") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("LocalLibraryId"); - - b.ToTable("LocalLibraries"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Property("MangaId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("CoverFileNameInCache") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("CoverUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("DirectoryName") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("IgnoreChaptersBefore") - .HasColumnType("real"); - - b.Property("LibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("OriginalLanguage") - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("ReleaseStatus") - .HasColumnType("smallint"); - - b.Property("WebsiteUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Year") - .HasColumnType("bigint"); - - b.HasKey("MangaId"); - - b.HasIndex("LibraryId"); - - b.HasIndex("MangaConnectorName"); - - b.ToTable("Mangas"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.MangaTag", b => - { - b.Property("Tag") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Tag"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("API.Schema.MetadataFetchers.MetadataEntry", b => - { - b.Property("MetadataFetcherName") - .HasColumnType("text"); - - b.Property("Identifier") - .HasColumnType("text"); - - b.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b.HasKey("MetadataFetcherName", "Identifier"); - - b.HasIndex("MangaId"); - - b.ToTable("MetadataEntries"); - }); - - modelBuilder.Entity("API.Schema.MetadataFetchers.MetadataFetcher", b => - { - b.Property("MetadataFetcherName") - .HasColumnType("text"); - - b.Property("MetadataEntry") - .IsRequired() - .HasMaxLength(21) - .HasColumnType("character varying(21)"); - - b.HasKey("MetadataFetcherName"); - - b.ToTable("MetadataFetcher"); - - b.HasDiscriminator("MetadataEntry").HasValue("MetadataFetcher"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.Property("AuthorIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("AuthorIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("AuthorToManga"); - }); - - modelBuilder.Entity("JobJob", b => - { - b.Property("DependsOnJobsJobId") - .HasColumnType("character varying(64)"); - - b.Property("JobId") - .HasColumnType("character varying(64)"); - - b.HasKey("DependsOnJobsJobId", "JobId"); - - b.HasIndex("JobId"); - - b.ToTable("JobJob"); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.Property("MangaTagIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("character varying(64)"); - - b.HasKey("MangaTagIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("MangaTagToManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("DownloadAvailableChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasDiscriminator().HasValue((byte)4); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.HasDiscriminator().HasValue((byte)0); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveFileOrFolderJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("FromLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ToLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasDiscriminator().HasValue((byte)3); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ToLibraryId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasIndex("ToLibraryId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("MoveMangaLibraryJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)7); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("RetrieveChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)5); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateChaptersDownloadedJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)6); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateCoverJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)9); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.ComickIo", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("ComickIo"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.Global", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("Global"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("MangaDex"); - }); - - modelBuilder.Entity("API.Schema.MetadataFetchers.MyAnimeList", b => - { - b.HasBaseType("API.Schema.MetadataFetchers.MetadataFetcher"); - - b.HasDiscriminator().HasValue("MyAnimeList"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.HasOne("API.Schema.Manga", "ParentManga") - .WithMany("Chapters") - .HasForeignKey("ParentMangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ParentManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.HasOne("API.Schema.Jobs.Job", "ParentJob") - .WithMany() - .HasForeignKey("ParentJobId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentJob"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.HasOne("API.Schema.LocalLibrary", "Library") - .WithMany() - .HasForeignKey("LibraryId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.OwnsMany("API.Schema.Link", "Links", b1 => - { - b1.Property("LinkId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkProvider") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.HasKey("LinkId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("Link"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.OwnsMany("API.Schema.MangaAltTitle", "AltTitles", b1 => - { - b1.Property("AltTitleId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b1.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b1.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b1.HasKey("AltTitleId"); - - b1.HasIndex("MangaId"); - - b1.ToTable("MangaAltTitle"); - - b1.WithOwner() - .HasForeignKey("MangaId"); - }); - - b.Navigation("AltTitles"); - - b.Navigation("Library"); - - b.Navigation("Links"); - - b.Navigation("MangaConnector"); - }); - - modelBuilder.Entity("API.Schema.MetadataFetchers.MetadataEntry", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MetadataFetchers.MetadataFetcher", "MetadataFetcher") - .WithMany() - .HasForeignKey("MetadataFetcherName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("MetadataFetcher"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.HasOne("API.Schema.Author", null) - .WithMany() - .HasForeignKey("AuthorIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("JobJob", b => - { - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("DependsOnJobsJobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("JobId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MangaTag", null) - .WithMany() - .HasForeignKey("MangaTagIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.LocalLibrary", "ToLibrary") - .WithMany() - .HasForeignKey("ToLibraryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("ToLibrary"); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Navigation("Chapters"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/pgsql/20250629184056_MetadataEntry-PrimaryKeyChange.cs b/API/Migrations/pgsql/20250629184056_MetadataEntry-PrimaryKeyChange.cs deleted file mode 100644 index 5fb57ee..0000000 --- a/API/Migrations/pgsql/20250629184056_MetadataEntry-PrimaryKeyChange.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace API.Migrations.pgsql -{ - /// - public partial class MetadataEntryPrimaryKeyChange : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropPrimaryKey( - name: "PK_MetadataEntries", - table: "MetadataEntries"); - - migrationBuilder.DropIndex( - name: "IX_MetadataEntries_MetadataFetcherName", - table: "MetadataEntries"); - - migrationBuilder.AddPrimaryKey( - name: "PK_MetadataEntries", - table: "MetadataEntries", - columns: new[] { "MetadataFetcherName", "Identifier" }); - - migrationBuilder.CreateIndex( - name: "IX_MetadataEntries_MangaId", - table: "MetadataEntries", - column: "MangaId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropPrimaryKey( - name: "PK_MetadataEntries", - table: "MetadataEntries"); - - migrationBuilder.DropIndex( - name: "IX_MetadataEntries_MangaId", - table: "MetadataEntries"); - - migrationBuilder.AddPrimaryKey( - name: "PK_MetadataEntries", - table: "MetadataEntries", - columns: new[] { "MangaId", "MetadataFetcherName" }); - - migrationBuilder.CreateIndex( - name: "IX_MetadataEntries_MetadataFetcherName", - table: "MetadataEntries", - column: "MetadataFetcherName"); - } - } -} diff --git a/API/Migrations/pgsql/20250630182650_OofV2.1.Designer.cs b/API/Migrations/pgsql/20250630182650_OofV2.1.Designer.cs deleted file mode 100644 index 372412f..0000000 --- a/API/Migrations/pgsql/20250630182650_OofV2.1.Designer.cs +++ /dev/null @@ -1,795 +0,0 @@ -// -using System; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - [DbContext(typeof(PgsqlContext))] - [Migration("20250630182650_OofV2.1")] - partial class OofV21 - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Author", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("AuthorName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("Key"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("ChapterNumber") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Downloaded") - .HasColumnType("boolean"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ParentMangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Title") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("VolumeNumber") - .HasColumnType("integer"); - - b.HasKey("Key"); - - b.HasIndex("ParentMangaId"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("API.Schema.FileLibrary", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("BasePath") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryName") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("Key"); - - b.ToTable("LocalLibraries"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("JobType") - .HasColumnType("smallint"); - - b.Property("LastExecution") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentJobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("RecurrenceMs") - .HasColumnType("numeric(20,0)"); - - b.Property("state") - .HasColumnType("smallint"); - - b.HasKey("Key"); - - b.HasIndex("ParentJobId"); - - b.ToTable("Jobs"); - - b.HasDiscriminator("JobType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("CoverFileNameInCache") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("CoverUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("DirectoryName") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("IgnoreChaptersBefore") - .HasColumnType("real"); - - b.Property("LibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("OriginalLanguage") - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("ReleaseStatus") - .HasColumnType("smallint"); - - b.Property("Year") - .HasColumnType("bigint"); - - b.HasKey("Key"); - - b.HasIndex("LibraryId"); - - b.ToTable("Mangas"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectorId", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("ObjId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("WebsiteUrl") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("Key"); - - b.HasIndex("MangaConnectorName"); - - b.HasIndex("ObjId"); - - b.ToTable("MangaConnectorToChapter"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectorId", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("ObjId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("WebsiteUrl") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("Key"); - - b.HasIndex("MangaConnectorName"); - - b.HasIndex("ObjId"); - - b.ToTable("MangaConnectorToManga"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.MangaTag", b => - { - b.Property("Tag") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Tag"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.Property("AuthorIds") - .HasColumnType("text"); - - b.Property("MangaIds") - .HasColumnType("text"); - - b.HasKey("AuthorIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("AuthorToManga"); - }); - - modelBuilder.Entity("JobJob", b => - { - b.Property("DependsOnJobsKey") - .HasColumnType("text"); - - b.Property("JobKey") - .HasColumnType("text"); - - b.HasKey("DependsOnJobsKey", "JobKey"); - - b.HasIndex("JobKey"); - - b.ToTable("JobJob"); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.Property("MangaTagIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("text"); - - b.HasKey("MangaTagIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("MangaTagToManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("DownloadAvailableChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasDiscriminator().HasValue((byte)4); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.HasDiscriminator().HasValue((byte)0); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveFileOrFolderJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("FromLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ToLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasDiscriminator().HasValue((byte)3); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ToLibraryId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasIndex("ToLibraryId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("MoveMangaLibraryJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)7); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("RetrieveChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)5); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateChaptersDownloadedJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)6); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateCoverJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)9); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.ComickIo", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("ComickIo"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.Global", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("Global"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("MangaDex"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.HasOne("API.Schema.Manga", "ParentManga") - .WithMany("Chapters") - .HasForeignKey("ParentMangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ParentManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.HasOne("API.Schema.Jobs.Job", "ParentJob") - .WithMany() - .HasForeignKey("ParentJobId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentJob"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.HasOne("API.Schema.FileLibrary", "Library") - .WithMany() - .HasForeignKey("LibraryId") - .OnDelete(DeleteBehavior.SetNull); - - b.OwnsMany("API.Schema.AltTitle", "AltTitles", b1 => - { - b1.Property("Key") - .HasColumnType("text"); - - b1.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b1.Property("MangaKey") - .IsRequired() - .HasColumnType("text"); - - b1.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b1.HasKey("Key"); - - b1.HasIndex("MangaKey"); - - b1.ToTable("AltTitle"); - - b1.WithOwner() - .HasForeignKey("MangaKey"); - }); - - b.OwnsMany("API.Schema.Link", "Links", b1 => - { - b1.Property("Key") - .HasColumnType("text"); - - b1.Property("LinkProvider") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b1.Property("MangaKey") - .IsRequired() - .HasColumnType("text"); - - b1.HasKey("Key"); - - b1.HasIndex("MangaKey"); - - b1.ToTable("Link"); - - b1.WithOwner() - .HasForeignKey("MangaKey"); - }); - - b.Navigation("AltTitles"); - - b.Navigation("Library"); - - b.Navigation("Links"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectorId", b => - { - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Chapter", "Obj") - .WithMany("MangaConnectorIds") - .HasForeignKey("ObjId") - .OnDelete(DeleteBehavior.NoAction) - .IsRequired(); - - b.Navigation("MangaConnector"); - - b.Navigation("Obj"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectorId", b => - { - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", "Obj") - .WithMany("MangaConnectorIds") - .HasForeignKey("ObjId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("MangaConnector"); - - b.Navigation("Obj"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.HasOne("API.Schema.Author", null) - .WithMany() - .HasForeignKey("AuthorIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("JobJob", b => - { - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("DependsOnJobsKey") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("JobKey") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MangaTag", null) - .WithMany() - .HasForeignKey("MangaTagIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.FileLibrary", "ToFileLibrary") - .WithMany() - .HasForeignKey("ToLibraryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("ToFileLibrary"); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Navigation("MangaConnectorIds"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Navigation("Chapters"); - - b.Navigation("MangaConnectorIds"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Migrations/pgsql/20250630182650_OofV2.1.cs b/API/Migrations/pgsql/20250630182650_OofV2.1.cs deleted file mode 100644 index a59670f..0000000 --- a/API/Migrations/pgsql/20250630182650_OofV2.1.cs +++ /dev/null @@ -1,1055 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace API.Migrations.pgsql -{ - /// - public partial class OofV21 : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_AuthorToManga_Authors_AuthorIds", - table: "AuthorToManga"); - - migrationBuilder.DropForeignKey( - name: "FK_AuthorToManga_Mangas_MangaIds", - table: "AuthorToManga"); - - migrationBuilder.DropForeignKey( - name: "FK_Chapters_Mangas_ParentMangaId", - table: "Chapters"); - - migrationBuilder.DropForeignKey( - name: "FK_JobJob_Jobs_DependsOnJobsJobId", - table: "JobJob"); - - migrationBuilder.DropForeignKey( - name: "FK_JobJob_Jobs_JobId", - table: "JobJob"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Chapters_ChapterId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Jobs_ParentJobId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_LocalLibraries_ToLibraryId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_DownloadAvailableChaptersJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_MangaId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_MoveMangaLibraryJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_RetrieveChaptersJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_UpdateChaptersDownloadedJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_UpdateCoverJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Link_Mangas_MangaId", - table: "Link"); - - migrationBuilder.DropForeignKey( - name: "FK_Mangas_LocalLibraries_LibraryId", - table: "Mangas"); - - migrationBuilder.DropForeignKey( - name: "FK_Mangas_MangaConnectors_MangaConnectorName", - table: "Mangas"); - - migrationBuilder.DropForeignKey( - name: "FK_MangaTagToManga_Mangas_MangaIds", - table: "MangaTagToManga"); - - migrationBuilder.DropTable( - name: "MangaAltTitle"); - - migrationBuilder.DropPrimaryKey( - name: "PK_Mangas", - table: "Mangas"); - - migrationBuilder.DropIndex( - name: "IX_Mangas_MangaConnectorName", - table: "Mangas"); - - migrationBuilder.DropPrimaryKey( - name: "PK_LocalLibraries", - table: "LocalLibraries"); - - migrationBuilder.DropPrimaryKey( - name: "PK_Link", - table: "Link"); - - migrationBuilder.DropIndex( - name: "IX_Link_MangaId", - table: "Link"); - - migrationBuilder.DropPrimaryKey( - name: "PK_Jobs", - table: "Jobs"); - - migrationBuilder.DropPrimaryKey( - name: "PK_JobJob", - table: "JobJob"); - - migrationBuilder.DropIndex( - name: "IX_JobJob_JobId", - table: "JobJob"); - - migrationBuilder.DropPrimaryKey( - name: "PK_Chapters", - table: "Chapters"); - - migrationBuilder.DropPrimaryKey( - name: "PK_Authors", - table: "Authors"); - - migrationBuilder.DropColumn( - name: "MangaId", - table: "Mangas"); - - migrationBuilder.DropColumn( - name: "IdOnConnectorSite", - table: "Mangas"); - - migrationBuilder.DropColumn( - name: "MangaConnectorName", - table: "Mangas"); - - migrationBuilder.DropColumn( - name: "WebsiteUrl", - table: "Mangas"); - - migrationBuilder.DropColumn( - name: "LocalLibraryId", - table: "LocalLibraries"); - - migrationBuilder.DropColumn( - name: "LinkId", - table: "Link"); - - migrationBuilder.DropColumn( - name: "MangaId", - table: "Link"); - - migrationBuilder.DropColumn( - name: "JobId", - table: "Jobs"); - - migrationBuilder.DropColumn( - name: "DependsOnJobsJobId", - table: "JobJob"); - - migrationBuilder.DropColumn( - name: "JobId", - table: "JobJob"); - - migrationBuilder.DropColumn( - name: "ChapterId", - table: "Chapters"); - - migrationBuilder.DropColumn( - name: "IdOnConnectorSite", - table: "Chapters"); - - migrationBuilder.DropColumn( - name: "Url", - table: "Chapters"); - - migrationBuilder.DropColumn( - name: "AuthorId", - table: "Authors"); - - migrationBuilder.AlterColumn( - name: "MangaIds", - table: "MangaTagToManga", - type: "text", - nullable: false, - oldClrType: typeof(string), - oldType: "character varying(64)"); - - migrationBuilder.AddColumn( - name: "Key", - table: "Mangas", - type: "text", - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "Key", - table: "LocalLibraries", - type: "text", - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "Key", - table: "Link", - type: "text", - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "MangaKey", - table: "Link", - type: "text", - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "Key", - table: "Jobs", - type: "text", - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "DependsOnJobsKey", - table: "JobJob", - type: "text", - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "JobKey", - table: "JobJob", - type: "text", - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "Key", - table: "Chapters", - type: "text", - nullable: false, - defaultValue: ""); - - migrationBuilder.AlterColumn( - name: "MangaIds", - table: "AuthorToManga", - type: "text", - nullable: false, - oldClrType: typeof(string), - oldType: "character varying(64)"); - - migrationBuilder.AlterColumn( - name: "AuthorIds", - table: "AuthorToManga", - type: "text", - nullable: false, - oldClrType: typeof(string), - oldType: "character varying(64)"); - - migrationBuilder.AddColumn( - name: "Key", - table: "Authors", - type: "text", - nullable: false, - defaultValue: ""); - - migrationBuilder.AddPrimaryKey( - name: "PK_Mangas", - table: "Mangas", - column: "Key"); - - migrationBuilder.AddPrimaryKey( - name: "PK_LocalLibraries", - table: "LocalLibraries", - column: "Key"); - - migrationBuilder.AddPrimaryKey( - name: "PK_Link", - table: "Link", - column: "Key"); - - migrationBuilder.AddPrimaryKey( - name: "PK_Jobs", - table: "Jobs", - column: "Key"); - - migrationBuilder.AddPrimaryKey( - name: "PK_JobJob", - table: "JobJob", - columns: new[] { "DependsOnJobsKey", "JobKey" }); - - migrationBuilder.AddPrimaryKey( - name: "PK_Chapters", - table: "Chapters", - column: "Key"); - - migrationBuilder.AddPrimaryKey( - name: "PK_Authors", - table: "Authors", - column: "Key"); - - migrationBuilder.CreateTable( - name: "AltTitle", - columns: table => new - { - Key = table.Column(type: "text", nullable: false), - Language = table.Column(type: "character varying(8)", maxLength: 8, nullable: false), - Title = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - MangaKey = table.Column(type: "text", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AltTitle", x => x.Key); - table.ForeignKey( - name: "FK_AltTitle_Mangas_MangaKey", - column: x => x.MangaKey, - principalTable: "Mangas", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "MangaConnectorToChapter", - columns: table => new - { - Key = table.Column(type: "text", nullable: false), - ObjId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - MangaConnectorName = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), - IdOnConnectorSite = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - WebsiteUrl = table.Column(type: "character varying(512)", maxLength: 512, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_MangaConnectorToChapter", x => x.Key); - table.ForeignKey( - name: "FK_MangaConnectorToChapter_Chapters_ObjId", - column: x => x.ObjId, - principalTable: "Chapters", - principalColumn: "Key"); - table.ForeignKey( - name: "FK_MangaConnectorToChapter_MangaConnectors_MangaConnectorName", - column: x => x.MangaConnectorName, - principalTable: "MangaConnectors", - principalColumn: "Name", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "MangaConnectorToManga", - columns: table => new - { - Key = table.Column(type: "text", nullable: false), - ObjId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - MangaConnectorName = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), - IdOnConnectorSite = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - WebsiteUrl = table.Column(type: "character varying(512)", maxLength: 512, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_MangaConnectorToManga", x => x.Key); - table.ForeignKey( - name: "FK_MangaConnectorToManga_MangaConnectors_MangaConnectorName", - column: x => x.MangaConnectorName, - principalTable: "MangaConnectors", - principalColumn: "Name", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_MangaConnectorToManga_Mangas_ObjId", - column: x => x.ObjId, - principalTable: "Mangas", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_Link_MangaKey", - table: "Link", - column: "MangaKey"); - - migrationBuilder.CreateIndex( - name: "IX_JobJob_JobKey", - table: "JobJob", - column: "JobKey"); - - migrationBuilder.CreateIndex( - name: "IX_AltTitle_MangaKey", - table: "AltTitle", - column: "MangaKey"); - - migrationBuilder.CreateIndex( - name: "IX_MangaConnectorToChapter_MangaConnectorName", - table: "MangaConnectorToChapter", - column: "MangaConnectorName"); - - migrationBuilder.CreateIndex( - name: "IX_MangaConnectorToChapter_ObjId", - table: "MangaConnectorToChapter", - column: "ObjId"); - - migrationBuilder.CreateIndex( - name: "IX_MangaConnectorToManga_MangaConnectorName", - table: "MangaConnectorToManga", - column: "MangaConnectorName"); - - migrationBuilder.CreateIndex( - name: "IX_MangaConnectorToManga_ObjId", - table: "MangaConnectorToManga", - column: "ObjId"); - - migrationBuilder.AddForeignKey( - name: "FK_AuthorToManga_Authors_AuthorIds", - table: "AuthorToManga", - column: "AuthorIds", - principalTable: "Authors", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_AuthorToManga_Mangas_MangaIds", - table: "AuthorToManga", - column: "MangaIds", - principalTable: "Mangas", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Chapters_Mangas_ParentMangaId", - table: "Chapters", - column: "ParentMangaId", - principalTable: "Mangas", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_JobJob_Jobs_DependsOnJobsKey", - table: "JobJob", - column: "DependsOnJobsKey", - principalTable: "Jobs", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_JobJob_Jobs_JobKey", - table: "JobJob", - column: "JobKey", - principalTable: "Jobs", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Chapters_ChapterId", - table: "Jobs", - column: "ChapterId", - principalTable: "Chapters", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Jobs_ParentJobId", - table: "Jobs", - column: "ParentJobId", - principalTable: "Jobs", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_LocalLibraries_ToLibraryId", - table: "Jobs", - column: "ToLibraryId", - principalTable: "LocalLibraries", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_DownloadAvailableChaptersJob_MangaId", - table: "Jobs", - column: "DownloadAvailableChaptersJob_MangaId", - principalTable: "Mangas", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_MangaId", - table: "Jobs", - column: "MangaId", - principalTable: "Mangas", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_MoveMangaLibraryJob_MangaId", - table: "Jobs", - column: "MoveMangaLibraryJob_MangaId", - principalTable: "Mangas", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_RetrieveChaptersJob_MangaId", - table: "Jobs", - column: "RetrieveChaptersJob_MangaId", - principalTable: "Mangas", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_UpdateChaptersDownloadedJob_MangaId", - table: "Jobs", - column: "UpdateChaptersDownloadedJob_MangaId", - principalTable: "Mangas", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_UpdateCoverJob_MangaId", - table: "Jobs", - column: "UpdateCoverJob_MangaId", - principalTable: "Mangas", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Link_Mangas_MangaKey", - table: "Link", - column: "MangaKey", - principalTable: "Mangas", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Mangas_LocalLibraries_LibraryId", - table: "Mangas", - column: "LibraryId", - principalTable: "LocalLibraries", - principalColumn: "Key", - onDelete: ReferentialAction.SetNull); - - migrationBuilder.AddForeignKey( - name: "FK_MangaTagToManga_Mangas_MangaIds", - table: "MangaTagToManga", - column: "MangaIds", - principalTable: "Mangas", - principalColumn: "Key", - onDelete: ReferentialAction.Cascade); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_AuthorToManga_Authors_AuthorIds", - table: "AuthorToManga"); - - migrationBuilder.DropForeignKey( - name: "FK_AuthorToManga_Mangas_MangaIds", - table: "AuthorToManga"); - - migrationBuilder.DropForeignKey( - name: "FK_Chapters_Mangas_ParentMangaId", - table: "Chapters"); - - migrationBuilder.DropForeignKey( - name: "FK_JobJob_Jobs_DependsOnJobsKey", - table: "JobJob"); - - migrationBuilder.DropForeignKey( - name: "FK_JobJob_Jobs_JobKey", - table: "JobJob"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Chapters_ChapterId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Jobs_ParentJobId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_LocalLibraries_ToLibraryId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_DownloadAvailableChaptersJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_MangaId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_MoveMangaLibraryJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_RetrieveChaptersJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_UpdateChaptersDownloadedJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Jobs_Mangas_UpdateCoverJob_MangaId", - table: "Jobs"); - - migrationBuilder.DropForeignKey( - name: "FK_Link_Mangas_MangaKey", - table: "Link"); - - migrationBuilder.DropForeignKey( - name: "FK_Mangas_LocalLibraries_LibraryId", - table: "Mangas"); - - migrationBuilder.DropForeignKey( - name: "FK_MangaTagToManga_Mangas_MangaIds", - table: "MangaTagToManga"); - - migrationBuilder.DropTable( - name: "AltTitle"); - - migrationBuilder.DropTable( - name: "MangaConnectorToChapter"); - - migrationBuilder.DropTable( - name: "MangaConnectorToManga"); - - migrationBuilder.DropPrimaryKey( - name: "PK_Mangas", - table: "Mangas"); - - migrationBuilder.DropPrimaryKey( - name: "PK_LocalLibraries", - table: "LocalLibraries"); - - migrationBuilder.DropPrimaryKey( - name: "PK_Link", - table: "Link"); - - migrationBuilder.DropIndex( - name: "IX_Link_MangaKey", - table: "Link"); - - migrationBuilder.DropPrimaryKey( - name: "PK_Jobs", - table: "Jobs"); - - migrationBuilder.DropPrimaryKey( - name: "PK_JobJob", - table: "JobJob"); - - migrationBuilder.DropIndex( - name: "IX_JobJob_JobKey", - table: "JobJob"); - - migrationBuilder.DropPrimaryKey( - name: "PK_Chapters", - table: "Chapters"); - - migrationBuilder.DropPrimaryKey( - name: "PK_Authors", - table: "Authors"); - - migrationBuilder.DropColumn( - name: "Key", - table: "Mangas"); - - migrationBuilder.DropColumn( - name: "Key", - table: "LocalLibraries"); - - migrationBuilder.DropColumn( - name: "Key", - table: "Link"); - - migrationBuilder.DropColumn( - name: "MangaKey", - table: "Link"); - - migrationBuilder.DropColumn( - name: "Key", - table: "Jobs"); - - migrationBuilder.DropColumn( - name: "DependsOnJobsKey", - table: "JobJob"); - - migrationBuilder.DropColumn( - name: "JobKey", - table: "JobJob"); - - migrationBuilder.DropColumn( - name: "Key", - table: "Chapters"); - - migrationBuilder.DropColumn( - name: "Key", - table: "Authors"); - - migrationBuilder.AlterColumn( - name: "MangaIds", - table: "MangaTagToManga", - type: "character varying(64)", - nullable: false, - oldClrType: typeof(string), - oldType: "text"); - - migrationBuilder.AddColumn( - name: "MangaId", - table: "Mangas", - type: "character varying(64)", - maxLength: 64, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "IdOnConnectorSite", - table: "Mangas", - type: "character varying(256)", - maxLength: 256, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "MangaConnectorName", - table: "Mangas", - type: "character varying(32)", - maxLength: 32, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "WebsiteUrl", - table: "Mangas", - type: "character varying(512)", - maxLength: 512, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "LocalLibraryId", - table: "LocalLibraries", - type: "character varying(64)", - maxLength: 64, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "LinkId", - table: "Link", - type: "character varying(64)", - maxLength: 64, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "MangaId", - table: "Link", - type: "character varying(64)", - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "JobId", - table: "Jobs", - type: "character varying(64)", - maxLength: 64, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "DependsOnJobsJobId", - table: "JobJob", - type: "character varying(64)", - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "JobId", - table: "JobJob", - type: "character varying(64)", - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "ChapterId", - table: "Chapters", - type: "character varying(64)", - maxLength: 64, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddColumn( - name: "IdOnConnectorSite", - table: "Chapters", - type: "character varying(256)", - maxLength: 256, - nullable: true); - - migrationBuilder.AddColumn( - name: "Url", - table: "Chapters", - type: "character varying(2048)", - maxLength: 2048, - nullable: false, - defaultValue: ""); - - migrationBuilder.AlterColumn( - name: "MangaIds", - table: "AuthorToManga", - type: "character varying(64)", - nullable: false, - oldClrType: typeof(string), - oldType: "text"); - - migrationBuilder.AlterColumn( - name: "AuthorIds", - table: "AuthorToManga", - type: "character varying(64)", - nullable: false, - oldClrType: typeof(string), - oldType: "text"); - - migrationBuilder.AddColumn( - name: "AuthorId", - table: "Authors", - type: "character varying(64)", - maxLength: 64, - nullable: false, - defaultValue: ""); - - migrationBuilder.AddPrimaryKey( - name: "PK_Mangas", - table: "Mangas", - column: "MangaId"); - - migrationBuilder.AddPrimaryKey( - name: "PK_LocalLibraries", - table: "LocalLibraries", - column: "LocalLibraryId"); - - migrationBuilder.AddPrimaryKey( - name: "PK_Link", - table: "Link", - column: "LinkId"); - - migrationBuilder.AddPrimaryKey( - name: "PK_Jobs", - table: "Jobs", - column: "JobId"); - - migrationBuilder.AddPrimaryKey( - name: "PK_JobJob", - table: "JobJob", - columns: new[] { "DependsOnJobsJobId", "JobId" }); - - migrationBuilder.AddPrimaryKey( - name: "PK_Chapters", - table: "Chapters", - column: "ChapterId"); - - migrationBuilder.AddPrimaryKey( - name: "PK_Authors", - table: "Authors", - column: "AuthorId"); - - migrationBuilder.CreateTable( - name: "MangaAltTitle", - columns: table => new - { - AltTitleId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - Language = table.Column(type: "character varying(8)", maxLength: 8, nullable: false), - MangaId = table.Column(type: "character varying(64)", nullable: false), - Title = table.Column(type: "character varying(256)", maxLength: 256, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_MangaAltTitle", x => x.AltTitleId); - table.ForeignKey( - name: "FK_MangaAltTitle_Mangas_MangaId", - column: x => x.MangaId, - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_Mangas_MangaConnectorName", - table: "Mangas", - column: "MangaConnectorName"); - - migrationBuilder.CreateIndex( - name: "IX_Link_MangaId", - table: "Link", - column: "MangaId"); - - migrationBuilder.CreateIndex( - name: "IX_JobJob_JobId", - table: "JobJob", - column: "JobId"); - - migrationBuilder.CreateIndex( - name: "IX_MangaAltTitle_MangaId", - table: "MangaAltTitle", - column: "MangaId"); - - migrationBuilder.AddForeignKey( - name: "FK_AuthorToManga_Authors_AuthorIds", - table: "AuthorToManga", - column: "AuthorIds", - principalTable: "Authors", - principalColumn: "AuthorId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_AuthorToManga_Mangas_MangaIds", - table: "AuthorToManga", - column: "MangaIds", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Chapters_Mangas_ParentMangaId", - table: "Chapters", - column: "ParentMangaId", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_JobJob_Jobs_DependsOnJobsJobId", - table: "JobJob", - column: "DependsOnJobsJobId", - principalTable: "Jobs", - principalColumn: "JobId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_JobJob_Jobs_JobId", - table: "JobJob", - column: "JobId", - principalTable: "Jobs", - principalColumn: "JobId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Chapters_ChapterId", - table: "Jobs", - column: "ChapterId", - principalTable: "Chapters", - principalColumn: "ChapterId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Jobs_ParentJobId", - table: "Jobs", - column: "ParentJobId", - principalTable: "Jobs", - principalColumn: "JobId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_LocalLibraries_ToLibraryId", - table: "Jobs", - column: "ToLibraryId", - principalTable: "LocalLibraries", - principalColumn: "LocalLibraryId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_DownloadAvailableChaptersJob_MangaId", - table: "Jobs", - column: "DownloadAvailableChaptersJob_MangaId", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_MangaId", - table: "Jobs", - column: "MangaId", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_MoveMangaLibraryJob_MangaId", - table: "Jobs", - column: "MoveMangaLibraryJob_MangaId", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_RetrieveChaptersJob_MangaId", - table: "Jobs", - column: "RetrieveChaptersJob_MangaId", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_UpdateChaptersDownloadedJob_MangaId", - table: "Jobs", - column: "UpdateChaptersDownloadedJob_MangaId", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Jobs_Mangas_UpdateCoverJob_MangaId", - table: "Jobs", - column: "UpdateCoverJob_MangaId", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Link_Mangas_MangaId", - table: "Link", - column: "MangaId", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Mangas_LocalLibraries_LibraryId", - table: "Mangas", - column: "LibraryId", - principalTable: "LocalLibraries", - principalColumn: "LocalLibraryId", - onDelete: ReferentialAction.SetNull); - - migrationBuilder.AddForeignKey( - name: "FK_Mangas_MangaConnectors_MangaConnectorName", - table: "Mangas", - column: "MangaConnectorName", - principalTable: "MangaConnectors", - principalColumn: "Name", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_MangaTagToManga_Mangas_MangaIds", - table: "MangaTagToManga", - column: "MangaIds", - principalTable: "Mangas", - principalColumn: "MangaId", - onDelete: ReferentialAction.Cascade); - } - } -} diff --git a/API/Migrations/pgsql/PgsqlContextModelSnapshot.cs b/API/Migrations/pgsql/PgsqlContextModelSnapshot.cs deleted file mode 100644 index a9c2d8a..0000000 --- a/API/Migrations/pgsql/PgsqlContextModelSnapshot.cs +++ /dev/null @@ -1,856 +0,0 @@ -// -using System; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace API.Migrations.pgsql -{ - [DbContext(typeof(PgsqlContext))] - partial class PgsqlContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("API.Schema.Author", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("AuthorName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.HasKey("Key"); - - b.ToTable("Authors"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("ChapterNumber") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Downloaded") - .HasColumnType("boolean"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ParentMangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Title") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("VolumeNumber") - .HasColumnType("integer"); - - b.HasKey("Key"); - - b.HasIndex("ParentMangaId"); - - b.ToTable("Chapters"); - }); - - modelBuilder.Entity("API.Schema.FileLibrary", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("BasePath") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("LibraryName") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("Key"); - - b.ToTable("LocalLibraries"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("JobType") - .HasColumnType("smallint"); - - b.Property("LastExecution") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentJobId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("RecurrenceMs") - .HasColumnType("numeric(20,0)"); - - b.Property("state") - .HasColumnType("smallint"); - - b.HasKey("Key"); - - b.HasIndex("ParentJobId"); - - b.ToTable("Jobs"); - - b.HasDiscriminator("JobType"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("CoverFileNameInCache") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("CoverUrl") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text"); - - b.Property("DirectoryName") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("IgnoreChaptersBefore") - .HasColumnType("real"); - - b.Property("LibraryId") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("OriginalLanguage") - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("ReleaseStatus") - .HasColumnType("smallint"); - - b.Property("Year") - .HasColumnType("bigint"); - - b.HasKey("Key"); - - b.HasIndex("LibraryId"); - - b.ToTable("Mangas"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectorId", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("ObjId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("WebsiteUrl") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("Key"); - - b.HasIndex("MangaConnectorName"); - - b.HasIndex("ObjId"); - - b.ToTable("MangaConnectorToChapter"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectorId", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("IdOnConnectorSite") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("MangaConnectorName") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("ObjId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("WebsiteUrl") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.HasKey("Key"); - - b.HasIndex("MangaConnectorName"); - - b.HasIndex("ObjId"); - - b.ToTable("MangaConnectorToManga"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("API.Schema.MangaTag", b => - { - b.Property("Tag") - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasKey("Tag"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("API.Schema.MetadataFetchers.MetadataEntry", b => - { - b.Property("MetadataFetcherName") - .HasColumnType("text"); - - b.Property("Identifier") - .HasColumnType("text"); - - b.Property("MangaId") - .IsRequired() - .HasColumnType("character varying(64)"); - - b.HasKey("MetadataFetcherName", "Identifier"); - - b.HasIndex("MangaId"); - - b.ToTable("MetadataEntries"); - }); - - modelBuilder.Entity("API.Schema.MetadataFetchers.MetadataFetcher", b => - { - b.Property("MetadataFetcherName") - .HasColumnType("text"); - - b.Property("MetadataEntry") - .IsRequired() - .HasMaxLength(21) - .HasColumnType("character varying(21)"); - - b.HasKey("MetadataFetcherName"); - - b.ToTable("MetadataFetcher"); - - b.HasDiscriminator("MetadataEntry").HasValue("MetadataFetcher"); - - b.UseTphMappingStrategy(); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.Property("AuthorIds") - .HasColumnType("text"); - - b.Property("MangaIds") - .HasColumnType("text"); - - b.HasKey("AuthorIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("AuthorToManga"); - }); - - modelBuilder.Entity("JobJob", b => - { - b.Property("DependsOnJobsKey") - .HasColumnType("text"); - - b.Property("JobKey") - .HasColumnType("text"); - - b.HasKey("DependsOnJobsKey", "JobKey"); - - b.HasIndex("JobKey"); - - b.ToTable("JobJob"); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.Property("MangaTagIds") - .HasColumnType("character varying(64)"); - - b.Property("MangaIds") - .HasColumnType("text"); - - b.HasKey("MangaTagIds", "MangaIds"); - - b.HasIndex("MangaIds"); - - b.ToTable("MangaTagToManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("DownloadAvailableChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)1); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasDiscriminator().HasValue((byte)4); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("ChapterId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("ChapterId"); - - b.HasDiscriminator().HasValue((byte)0); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveFileOrFolderJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("FromLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("ToLocation") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasDiscriminator().HasValue((byte)3); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("ToLibraryId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.HasIndex("ToLibraryId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("MoveMangaLibraryJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)7); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("RetrieveChaptersJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)5); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateChaptersDownloadedJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)6); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateCoverJob", b => - { - b.HasBaseType("API.Schema.Jobs.Job"); - - b.Property("MangaId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.HasIndex("MangaId"); - - b.ToTable("Jobs", t => - { - t.Property("MangaId") - .HasColumnName("UpdateCoverJob_MangaId"); - }); - - b.HasDiscriminator().HasValue((byte)9); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.ComickIo", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("ComickIo"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.Global", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("Global"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b => - { - b.HasBaseType("API.Schema.MangaConnectors.MangaConnector"); - - b.HasDiscriminator().HasValue("MangaDex"); - }); - - modelBuilder.Entity("API.Schema.MetadataFetchers.MyAnimeList", b => - { - b.HasBaseType("API.Schema.MetadataFetchers.MetadataFetcher"); - - b.HasDiscriminator().HasValue("MyAnimeList"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.HasOne("API.Schema.Manga", "ParentManga") - .WithMany("Chapters") - .HasForeignKey("ParentMangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("ParentManga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.Job", b => - { - b.HasOne("API.Schema.Jobs.Job", "ParentJob") - .WithMany() - .HasForeignKey("ParentJobId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentJob"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.HasOne("API.Schema.FileLibrary", "Library") - .WithMany() - .HasForeignKey("LibraryId") - .OnDelete(DeleteBehavior.SetNull); - - b.OwnsMany("API.Schema.AltTitle", "AltTitles", b1 => - { - b1.Property("Key") - .HasColumnType("text"); - - b1.Property("Language") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("character varying(8)"); - - b1.Property("MangaKey") - .IsRequired() - .HasColumnType("text"); - - b1.Property("Title") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b1.HasKey("Key"); - - b1.HasIndex("MangaKey"); - - b1.ToTable("AltTitle"); - - b1.WithOwner() - .HasForeignKey("MangaKey"); - }); - - b.OwnsMany("API.Schema.Link", "Links", b1 => - { - b1.Property("Key") - .HasColumnType("text"); - - b1.Property("LinkProvider") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b1.Property("LinkUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b1.Property("MangaKey") - .IsRequired() - .HasColumnType("text"); - - b1.HasKey("Key"); - - b1.HasIndex("MangaKey"); - - b1.ToTable("Link"); - - b1.WithOwner() - .HasForeignKey("MangaKey"); - }); - - b.Navigation("AltTitles"); - - b.Navigation("Library"); - - b.Navigation("Links"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectorId", b => - { - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Chapter", "Obj") - .WithMany("MangaConnectorIds") - .HasForeignKey("ObjId") - .OnDelete(DeleteBehavior.NoAction) - .IsRequired(); - - b.Navigation("MangaConnector"); - - b.Navigation("Obj"); - }); - - modelBuilder.Entity("API.Schema.MangaConnectorId", b => - { - b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", "Obj") - .WithMany("MangaConnectorIds") - .HasForeignKey("ObjId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("MangaConnector"); - - b.Navigation("Obj"); - }); - - modelBuilder.Entity("API.Schema.MetadataFetchers.MetadataEntry", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MetadataFetchers.MetadataFetcher", "MetadataFetcher") - .WithMany() - .HasForeignKey("MetadataFetcherName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("MetadataFetcher"); - }); - - modelBuilder.Entity("AuthorToManga", b => - { - b.HasOne("API.Schema.Author", null) - .WithMany() - .HasForeignKey("AuthorIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("JobJob", b => - { - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("DependsOnJobsKey") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.Jobs.Job", null) - .WithMany() - .HasForeignKey("JobKey") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("MangaTagToManga", b => - { - b.HasOne("API.Schema.Manga", null) - .WithMany() - .HasForeignKey("MangaIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.MangaTag", null) - .WithMany() - .HasForeignKey("MangaTagIds") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadAvailableChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b => - { - b.HasOne("API.Schema.Chapter", "Chapter") - .WithMany() - .HasForeignKey("ChapterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Chapter"); - }); - - modelBuilder.Entity("API.Schema.Jobs.MoveMangaLibraryJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("API.Schema.FileLibrary", "ToFileLibrary") - .WithMany() - .HasForeignKey("ToLibraryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - - b.Navigation("ToFileLibrary"); - }); - - modelBuilder.Entity("API.Schema.Jobs.RetrieveChaptersJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateChaptersDownloadedJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Jobs.UpdateCoverJob", b => - { - b.HasOne("API.Schema.Manga", "Manga") - .WithMany() - .HasForeignKey("MangaId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Manga"); - }); - - modelBuilder.Entity("API.Schema.Chapter", b => - { - b.Navigation("MangaConnectorIds"); - }); - - modelBuilder.Entity("API.Schema.Manga", b => - { - b.Navigation("Chapters"); - - b.Navigation("MangaConnectorIds"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/API/Program.cs b/API/Program.cs index 7a9553f..1b5cc90 100644 --- a/API/Program.cs +++ b/API/Program.cs @@ -1,10 +1,9 @@ using System.Reflection; using API; -using API.Controllers; -using API.Schema; -using API.Schema.Contexts; -using API.Schema.Jobs; -using API.Schema.MangaConnectors; +using API.Schema.LibraryContext; +using API.Schema.MangaContext; +using API.Schema.MangaContext.MangaConnectors; +using API.Schema.NotificationsContext; using Asp.Versioning; using Asp.Versioning.Builder; using Asp.Versioning.Conventions; @@ -56,17 +55,17 @@ builder.Services.AddSwaggerGen(opt => }); builder.Services.ConfigureOptions(); -string ConnectionString = $"Host={Environment.GetEnvironmentVariable("POSTGRES_HOST") ?? "localhost:5432"}; " + +string connectionString = $"Host={Environment.GetEnvironmentVariable("POSTGRES_HOST") ?? "localhost:5432"}; " + $"Database={Environment.GetEnvironmentVariable("POSTGRES_DB") ?? "postgres"}; " + $"Username={Environment.GetEnvironmentVariable("POSTGRES_USER") ?? "postgres"}; " + $"Password={Environment.GetEnvironmentVariable("POSTGRES_PASSWORD") ?? "postgres"}"; -builder.Services.AddDbContext(options => - options.UseNpgsql(ConnectionString)); +builder.Services.AddDbContext(options => + options.UseNpgsql(connectionString)); builder.Services.AddDbContext(options => - options.UseNpgsql(ConnectionString)); + options.UseNpgsql(connectionString)); builder.Services.AddDbContext(options => - options.UseNpgsql(ConnectionString)); + options.UseNpgsql(connectionString)); builder.Services.AddControllers(options => { @@ -108,52 +107,21 @@ app.UseMiddleware(); using (IServiceScope scope = app.Services.CreateScope()) { - PgsqlContext context = scope.ServiceProvider.GetRequiredService(); - //TODO Remove after migrations complete - if (context.Database.GetMigrations().Contains("20250630182650_OofV2.1") == false) - { - IQueryable<(string, string)> mangas = context.Database.SqlQuery<(string, string)>($"SELECT MangaConnectorName, IdOnConnectorSite as ID FROM Mangas"); - context.Database.Migrate(); - foreach ((string mangaConnectorName, string idOnConnectorSite) manga in mangas) - { - if(context.MangaConnectors.Find(manga.mangaConnectorName) is not { } mangaConnector) - continue; - if(mangaConnector.GetMangaFromId(manga.idOnConnectorSite) is not { } result) - continue; - if (SearchController.AddMangaToContext(result.Item1, result.Item2, context) is { } added) - { - RetrieveChaptersJob retrieveChaptersJob = new (added, "en", 0); - UpdateChaptersDownloadedJob update = new(added, 0, null, [retrieveChaptersJob]); - context.Jobs.AddRange([retrieveChaptersJob, update]); - } - } - } else - context.Database.Migrate(); - + MangaContext context = scope.ServiceProvider.GetRequiredService(); + context.Database.Migrate(); MangaConnector[] connectors = [ new MangaDex(), new ComickIo(), - new Global(scope.ServiceProvider.GetService()!) + new Global(scope.ServiceProvider.GetService()!) ]; MangaConnector[] newConnectors = connectors.Where(c => !context.MangaConnectors.Contains(c)).ToArray(); context.MangaConnectors.AddRange(newConnectors); if (!context.LocalLibraries.Any()) context.LocalLibraries.Add(new FileLibrary(TrangaSettings.downloadLocation, "Default FileLibrary")); - - context.Jobs.AddRange(context.Jobs.Where(j => j.JobType == JobType.DownloadAvailableChaptersJob) - .Include(downloadAvailableChaptersJob => ((DownloadAvailableChaptersJob)downloadAvailableChaptersJob).Manga) - .ToList() - .Select(dacj => new UpdateChaptersDownloadedJob(((DownloadAvailableChaptersJob)dacj).Manga, 0, dacj))); - context.Jobs.RemoveRange(context.Jobs.Where(j => j.state == JobState.Completed && j.RecurrenceMs < 1)); - foreach (Job job in context.Jobs.Where(j => j.state == JobState.Running)) - { - job.state = JobState.FirstExecution; - job.LastExecution = DateTime.UnixEpoch; - } - context.SaveChanges(); + context.Sync(); } using (IServiceScope scope = app.Services.CreateScope()) @@ -164,20 +132,21 @@ using (IServiceScope scope = app.Services.CreateScope()) string[] emojis = { "(•‿•)", "(づ \u25d5‿\u25d5 )づ", "( \u02d8\u25bd\u02d8)っ\u2668", "=\uff3e\u25cf \u22cf \u25cf\uff3e=", "(ΦωΦ)", "(\u272a\u3268\u272a)", "( ノ・o・ )ノ", "(〜^\u2207^ )〜", "~(\u2267ω\u2266)~","૮ \u00b4• ﻌ \u00b4• ა", "(\u02c3ᆺ\u02c2)", "(=\ud83d\udf66 \u0f1d \ud83d\udf66=)"}; context.Notifications.Add(new Notification("Tranga Started", emojis[Random.Shared.Next(0, emojis.Length - 1)], NotificationUrgency.High)); - context.SaveChanges(); + context.Sync(); } +using (IServiceScope scope = app.Services.CreateScope()) +{ + LibraryContext context = scope.ServiceProvider.GetRequiredService(); + context.Database.Migrate(); + + context.Sync(); +} TrangaSettings.Load(); Tranga.StartLogger(); -using (IServiceScope scope = app.Services.CreateScope()) -{ - PgsqlContext context = scope.ServiceProvider.GetRequiredService(); - Tranga.RemoveStaleFiles(context); -} -Tranga.JobStarterThread.Start(app.Services); -//Tranga.NotificationSenderThread.Start(app.Services); //TODO RE-ENABLE +Tranga.PeriodicWorkerStarterThread.Start(app.Services); app.UseCors("AllowAll"); diff --git a/API/Schema/Contexts/TrangaBaseContext.cs b/API/Schema/Contexts/TrangaBaseContext.cs deleted file mode 100644 index 56a1598..0000000 --- a/API/Schema/Contexts/TrangaBaseContext.cs +++ /dev/null @@ -1,19 +0,0 @@ -using log4net; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; - -namespace API.Schema.Contexts; - -public abstract class TrangaBaseContext(DbContextOptions options) : DbContext(options) where T : DbContext -{ - private ILog Log => LogManager.GetLogger(GetType()); - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - base.OnConfiguring(optionsBuilder); - optionsBuilder.LogTo(s => - { - Log.Debug(s); - }, Array.Empty(), LogLevel.Warning, DbContextLoggerOptions.Level | DbContextLoggerOptions.Category | DbContextLoggerOptions.UtcTime); - } -} \ No newline at end of file diff --git a/API/Schema/Identifiable.cs b/API/Schema/Identifiable.cs index 2638cd6..caa87ae 100644 --- a/API/Schema/Identifiable.cs +++ b/API/Schema/Identifiable.cs @@ -3,9 +3,19 @@ using Microsoft.EntityFrameworkCore; namespace API.Schema; [PrimaryKey("Key")] -public abstract class Identifiable(string key) +public abstract class Identifiable { - public string Key { get; init; } = key; + public Identifiable() + { + this.Key = TokenGen.CreateToken(this.GetType()); + } + + public Identifiable(string key) + { + this.Key = key; + } + + public string Key { get; init; } public override string ToString() => Key; } \ No newline at end of file diff --git a/API/Schema/Jobs/DownloadAvailableChaptersJob.cs b/API/Schema/Jobs/DownloadAvailableChaptersJob.cs deleted file mode 100644 index fd768e5..0000000 --- a/API/Schema/Jobs/DownloadAvailableChaptersJob.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Newtonsoft.Json; - -namespace API.Schema.Jobs; - -public class DownloadAvailableChaptersJob : JobWithDownloading -{ - [StringLength(64)] [Required] public string MangaId { get; init; } = null!; - private Manga? _manga; - - [JsonIgnore] - public Manga Manga - { - get => LazyLoader.Load(this, ref _manga) ?? throw new InvalidOperationException(); - init - { - MangaId = value.Key; - _manga = value; - } - } - - public DownloadAvailableChaptersJob(Manga manga, ulong recurrenceMs, Job? parentJob = null, ICollection? dependsOnJobs = null) - : base(TokenGen.CreateToken(typeof(DownloadAvailableChaptersJob)), JobType.DownloadAvailableChaptersJob, recurrenceMs, parentJob, dependsOnJobs) - { - this.Manga = manga; - } - - /// - /// EF ONLY!!! - /// - internal DownloadAvailableChaptersJob(ILazyLoader lazyLoader, string key, string mangaId, ulong recurrenceMs, string? parentJobId) - : base(lazyLoader, key, JobType.DownloadAvailableChaptersJob, recurrenceMs, parentJobId) - { - this.MangaId = mangaId; - } - - protected override IEnumerable RunInternal(PgsqlContext context) - { - // Chapters that aren't downloaded and for which no downloading-Job exists - IEnumerable newChapters = Manga.Chapters - .Where(c => - c.Downloaded == false && - context.Jobs.Any(j => - j.JobType == JobType.DownloadSingleChapterJob && - ((DownloadSingleChapterJob)j).Chapter.ParentMangaId == MangaId) == false); - return newChapters.Select(c => new DownloadSingleChapterJob(c, this)); - } -} \ No newline at end of file diff --git a/API/Schema/Jobs/DownloadMangaCoverJob.cs b/API/Schema/Jobs/DownloadMangaCoverJob.cs deleted file mode 100644 index fca54ee..0000000 --- a/API/Schema/Jobs/DownloadMangaCoverJob.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Newtonsoft.Json; - -namespace API.Schema.Jobs; - -public class DownloadMangaCoverJob : JobWithDownloading -{ - [StringLength(64)] [Required] public string MangaId { get; init; } = null!; - private Manga? _manga; - - [JsonIgnore] - public Manga Manga - { - get => LazyLoader.Load(this, ref _manga) ?? throw new InvalidOperationException(); - init - { - MangaId = value.Key; - _manga = value; - } - } - - public DownloadMangaCoverJob(Manga manga, Job? parentJob = null, ICollection? dependsOnJobs = null) - : base(TokenGen.CreateToken(typeof(DownloadMangaCoverJob)), JobType.DownloadMangaCoverJob, 0, parentJob, dependsOnJobs) - { - this.Manga = manga; - } - - /// - /// EF ONLY!!! - /// - internal DownloadMangaCoverJob(ILazyLoader lazyLoader, string key, string mangaId, ulong recurrenceMs, string? parentJobId) - : base(lazyLoader, key, JobType.DownloadMangaCoverJob, recurrenceMs, parentJobId) - { - this.MangaId = mangaId; - } - - protected override IEnumerable RunInternal(PgsqlContext context) - { - //TODO MangaConnector Selection - MangaConnectorId mcId = Manga.MangaConnectorIds.First(); - try - { - Manga.CoverFileNameInCache = mcId.MangaConnector.SaveCoverImageToCache(mcId); - context.SaveChanges(); - } - catch (DbUpdateException e) - { - Log.Error(e); - } - return []; - } -} \ No newline at end of file diff --git a/API/Schema/Jobs/Job.cs b/API/Schema/Jobs/Job.cs deleted file mode 100644 index cacfcfc..0000000 --- a/API/Schema/Jobs/Job.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using API.Schema.Contexts; -using log4net; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Newtonsoft.Json; - -namespace API.Schema.Jobs; - -[PrimaryKey("Key")] -public abstract class Job : Identifiable, IComparable -{ - [StringLength(64)] public string? ParentJobId { get; private set; } - [JsonIgnore] public Job? ParentJob { get; internal set; } - private ICollection? _dependsOnJobs; - [JsonIgnore] public ICollection DependsOnJobs - { - get => LazyLoader.Load(this, ref _dependsOnJobs) ?? throw new InvalidOperationException(); - init => _dependsOnJobs = value; - } - - [Required] public JobType JobType { get; init; } - - [Required] public ulong RecurrenceMs { get; set; } - - [Required] public DateTime LastExecution { get; internal set; } = DateTime.UnixEpoch; - - [NotMapped] [Required] public DateTime NextExecution => LastExecution.AddMilliseconds(RecurrenceMs); - [Required] public JobState state { get; internal set; } = JobState.FirstExecution; - [Required] public bool Enabled { get; internal set; } = true; - - [JsonIgnore] [NotMapped] internal bool IsCompleted => state is >= (JobState)128 and < (JobState)192; - - [NotMapped] [JsonIgnore] protected ILog Log { get; init; } - [NotMapped] [JsonIgnore] protected ILazyLoader LazyLoader { get; init; } = null!; - - protected Job(string key, JobType jobType, ulong recurrenceMs, Job? parentJob = null, ICollection? dependsOnJobs = null) - : base(key) - { - this.JobType = jobType; - this.RecurrenceMs = recurrenceMs; - this.ParentJobId = parentJob?.Key; - this.ParentJob = parentJob; - this.DependsOnJobs = dependsOnJobs ?? []; - - this.Log = LogManager.GetLogger(this.GetType()); - } - - /// - /// EF ONLY!!! - /// - protected internal Job(ILazyLoader lazyLoader, string key, JobType jobType, ulong recurrenceMs, string? parentJobId) - : base(key) - { - this.LazyLoader = lazyLoader; - this.JobType = jobType; - this.RecurrenceMs = recurrenceMs; - this.ParentJobId = parentJobId; - this.DependsOnJobs = []; - - this.Log = LogManager.GetLogger(this.GetType()); - } - - public IEnumerable Run(PgsqlContext context, ref bool running) - { - Log.Info($"Running job {this}"); - DateTime jobStart = DateTime.UtcNow; - Job[]? ret = null; - - try - { - this.state = JobState.Running; - context.SaveChanges(); - running = true; - ret = RunInternal(context).ToArray(); - Log.Info($"Job {this} completed. Generated {ret.Length} new jobs."); - this.state = this.RecurrenceMs > 0 ? JobState.CompletedWaiting : JobState.Completed; - this.LastExecution = DateTime.UtcNow; - context.SaveChanges(); - } - catch (Exception e) - { - if (e is not DbUpdateException) - { - Log.Error($"Failed to run job {this}", e); - this.state = JobState.Failed; - this.Enabled = false; - this.LastExecution = DateTime.UtcNow; - context.SaveChanges(); - } - else - { - Log.Error($"Failed to update Database {this}", e); - } - } - - try - { - if (ret != null) - { - context.Jobs.AddRange(ret); - context.SaveChanges(); - } - } - catch (DbUpdateException e) - { - Log.Error($"Failed to update Database {this}", e); - } - - Log.Info($"Finished Job {this}! (took {DateTime.UtcNow.Subtract(jobStart).TotalMilliseconds}ms)"); - return ret ?? []; - } - - protected abstract IEnumerable RunInternal(PgsqlContext context); - - public List GetDependenciesAndSelf() - { - List ret = GetDependencies(); - ret.Add(this); - return ret; - } - - public List GetDependencies() - { - List ret = new (); - foreach (Job job in DependsOnJobs) - { - ret.AddRange(job.GetDependenciesAndSelf()); - } - return ret; - } - - public int CompareTo(Job? other) - { - if (other is null) - return -1; - // Sort by missing dependencies - if (this.GetDependencies().Count(job => !job.IsCompleted) < - other.GetDependencies().Count(job => !job.IsCompleted)) - return -1; - // Sort by NextExecution-time - if (this.NextExecution < other.NextExecution) - return -1; - return 1; - } - - public override string ToString() => base.ToString(); -} \ No newline at end of file diff --git a/API/Schema/Jobs/JobState.cs b/API/Schema/Jobs/JobState.cs deleted file mode 100644 index 12e8919..0000000 --- a/API/Schema/Jobs/JobState.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace API.Schema.Jobs; - -public enum JobState : byte -{ - //Values 0-63 Preparation Stages - FirstExecution = 0, - //64-127 Running Stages - Running = 64, - //128-191 Completion Stages - Completed = 128, - CompletedWaiting = 159, - //192-255 Error stages - Failed = 192 -} \ No newline at end of file diff --git a/API/Schema/Jobs/JobType.cs b/API/Schema/Jobs/JobType.cs deleted file mode 100644 index c05e79a..0000000 --- a/API/Schema/Jobs/JobType.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace API.Schema.Jobs; - - -public enum JobType : byte -{ - DownloadSingleChapterJob = 0, - DownloadAvailableChaptersJob = 1, - MoveFileOrFolderJob = 3, - DownloadMangaCoverJob = 4, - RetrieveChaptersJob = 5, - UpdateChaptersDownloadedJob = 6, - MoveMangaLibraryJob = 7, - UpdateCoverJob = 9, -} \ No newline at end of file diff --git a/API/Schema/Jobs/JobWithDownloading.cs b/API/Schema/Jobs/JobWithDownloading.cs deleted file mode 100644 index 92cb76d..0000000 --- a/API/Schema/Jobs/JobWithDownloading.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.EntityFrameworkCore.Infrastructure; - -namespace API.Schema.Jobs; - -public abstract class JobWithDownloading : Job -{ - - public JobWithDownloading(string key, JobType jobType, ulong recurrenceMs, Job? parentJob = null, ICollection? dependsOnJobs = null) - : base(key, jobType, recurrenceMs, parentJob, dependsOnJobs) - { - - } - public JobWithDownloading(ILazyLoader lazyLoader, string key, JobType jobType, ulong recurrenceMs, string? parentJobId) - : base(lazyLoader, key, jobType, recurrenceMs, parentJobId) - { - - } -} \ No newline at end of file diff --git a/API/Schema/Jobs/MoveFileOrFolderJob.cs b/API/Schema/Jobs/MoveFileOrFolderJob.cs deleted file mode 100644 index aa3cf61..0000000 --- a/API/Schema/Jobs/MoveFileOrFolderJob.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore.Infrastructure; - -namespace API.Schema.Jobs; - -public class MoveFileOrFolderJob : Job -{ - [StringLength(256)] - [Required] - public string FromLocation { get; init; } - [StringLength(256)] - [Required] - public string ToLocation { get; init; } - - public MoveFileOrFolderJob(string fromLocation, string toLocation, Job? parentJob = null, ICollection? dependsOnJobs = null) - : base(TokenGen.CreateToken(typeof(MoveFileOrFolderJob)), JobType.MoveFileOrFolderJob, 0, parentJob, dependsOnJobs) - { - this.FromLocation = fromLocation; - this.ToLocation = toLocation; - } - - /// - /// EF ONLY!!! - /// - internal MoveFileOrFolderJob(ILazyLoader lazyLoader, string key, ulong recurrenceMs, string fromLocation, string toLocation, string? parentJobId) - : base(lazyLoader, key, JobType.MoveFileOrFolderJob, recurrenceMs, parentJobId) - { - this.FromLocation = fromLocation; - this.ToLocation = toLocation; - } - - protected override IEnumerable RunInternal(PgsqlContext context) - { - try - { - FileInfo fi = new (FromLocation); - if (!fi.Exists) - { - Log.Error($"File does not exist at {FromLocation}"); - return []; - } - - if (File.Exists(ToLocation))//Do not override existing - { - Log.Error($"File already exists at {ToLocation}"); - return []; - } - if(fi.Attributes.HasFlag(FileAttributes.Directory)) - MoveDirectory(fi, ToLocation); - else - MoveFile(fi, ToLocation); - } - catch (Exception e) - { - Log.Error(e); - } - - return []; - } - - private void MoveDirectory(FileInfo from, string toLocation) - { - Directory.Move(from.FullName, toLocation); - } - - private void MoveFile(FileInfo from, string toLocation) - { - File.Move(from.FullName, toLocation); - } -} \ No newline at end of file diff --git a/API/Schema/Jobs/MoveMangaLibraryJob.cs b/API/Schema/Jobs/MoveMangaLibraryJob.cs deleted file mode 100644 index 5225b9f..0000000 --- a/API/Schema/Jobs/MoveMangaLibraryJob.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Newtonsoft.Json; - -namespace API.Schema.Jobs; - -public class MoveMangaLibraryJob : Job -{ - [StringLength(64)] [Required] public string MangaId { get; init; } = null!; - private Manga? _manga; - - [JsonIgnore] - public Manga Manga - { - get => LazyLoader.Load(this, ref _manga) ?? throw new InvalidOperationException(); - init - { - MangaId = value.Key; - _manga = value; - } - } - - [StringLength(64)] [Required] public string ToLibraryId { get; private set; } = null!; - private FileLibrary? _toFileLibrary; - [JsonIgnore] - public FileLibrary ToFileLibrary - { - get => LazyLoader.Load(this, ref _toFileLibrary) ?? throw new InvalidOperationException(); - init - { - ToLibraryId = value.Key; - _toFileLibrary = value; - } - } - - public MoveMangaLibraryJob(Manga manga, FileLibrary toFileLibrary, Job? parentJob = null, ICollection? dependsOnJobs = null) - : base(TokenGen.CreateToken(typeof(MoveMangaLibraryJob)), JobType.MoveMangaLibraryJob, 0, parentJob, dependsOnJobs) - { - this.Manga = manga; - this.ToFileLibrary = toFileLibrary; - } - - /// - /// EF ONLY!!! - /// - internal MoveMangaLibraryJob(ILazyLoader lazyLoader, string key, ulong recurrenceMs, string mangaId, string toLibraryId, string? parentJobId) - : base(lazyLoader, key, JobType.MoveMangaLibraryJob, recurrenceMs, parentJobId) - { - this.MangaId = mangaId; - this.ToLibraryId = toLibraryId; - } - - protected override IEnumerable RunInternal(PgsqlContext context) - { - context.Entry(Manga).Reference(m => m.Library).Load(); - Dictionary oldPath = Manga.Chapters.ToDictionary(c => c, c => c.FullArchiveFilePath); - Manga.Library = ToFileLibrary; - try - { - context.SaveChanges(); - } - catch (DbUpdateException e) - { - Log.Error(e); - return []; - } - - return Manga.Chapters.Select(c => new MoveFileOrFolderJob(oldPath[c], c.FullArchiveFilePath)); - } -} \ No newline at end of file diff --git a/API/Schema/Jobs/RetrieveChaptersJob.cs b/API/Schema/Jobs/RetrieveChaptersJob.cs deleted file mode 100644 index 939b5f6..0000000 --- a/API/Schema/Jobs/RetrieveChaptersJob.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Newtonsoft.Json; - -namespace API.Schema.Jobs; - -public class RetrieveChaptersJob : JobWithDownloading -{ - [StringLength(64)] [Required] public string MangaId { get; init; } = null!; - private Manga? _manga; - - [JsonIgnore] - public Manga Manga - { - get => LazyLoader.Load(this, ref _manga) ?? throw new InvalidOperationException(); - init - { - MangaId = value.Key; - _manga = value; - } - } - - [StringLength(8)] [Required] public string Language { get; private set; } - - public RetrieveChaptersJob(Manga manga, string language, ulong recurrenceMs, Job? parentJob = null, ICollection? dependsOnJobs = null) - : base(TokenGen.CreateToken(typeof(RetrieveChaptersJob)), JobType.RetrieveChaptersJob, recurrenceMs, parentJob, dependsOnJobs) - { - this.Manga = manga; - this.Language = language; - } - - /// - /// EF ONLY!!! - /// - internal RetrieveChaptersJob(ILazyLoader lazyLoader, string key, string mangaId, ulong recurrenceMs, string language, string? parentJobId) - : base(lazyLoader, key, JobType.RetrieveChaptersJob, recurrenceMs, parentJobId) - { - this.MangaId = mangaId; - this.Language = language; - } - - protected override IEnumerable RunInternal(PgsqlContext context) - { - //TODO MangaConnector Selection - MangaConnectorId mcId = Manga.MangaConnectorIds.First(); - - // This gets all chapters that are not downloaded - (Chapter, MangaConnectorId)[] allChapters = mcId.MangaConnector.GetChapters(mcId, Language).DistinctBy(c => c.Item1.Key).ToArray(); - (Chapter, MangaConnectorId)[] newChapters = allChapters.Where(chapter => Manga.Chapters.Any(ch => chapter.Item1.Key == ch.Key && ch.Downloaded) == false).ToArray(); - Log.Info($"{Manga.Chapters.Count} existing + {newChapters.Length} new chapters."); - - try - { - foreach ((Chapter chapter, MangaConnectorId mcId) newChapter in newChapters) - { - Manga.Chapters.Add(newChapter.chapter); - context.MangaConnectorToChapter.Add(newChapter.mcId); - } - context.SaveChanges(); - } - catch (DbUpdateException e) - { - Log.Error(e); - } - - return []; - } -} \ No newline at end of file diff --git a/API/Schema/Jobs/UpdateChaptersDownloadedJob.cs b/API/Schema/Jobs/UpdateChaptersDownloadedJob.cs deleted file mode 100644 index fc026c2..0000000 --- a/API/Schema/Jobs/UpdateChaptersDownloadedJob.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Newtonsoft.Json; - -namespace API.Schema.Jobs; - -public class UpdateChaptersDownloadedJob : Job -{ - [StringLength(64)] [Required] public string MangaId { get; init; } = null!; - private Manga? _manga; - - [JsonIgnore] - public Manga Manga - { - get => LazyLoader.Load(this, ref _manga) ?? throw new InvalidOperationException(); - init - { - MangaId = value.Key; - _manga = value; - } - } - - public UpdateChaptersDownloadedJob(Manga manga, ulong recurrenceMs, Job? parentJob = null, ICollection? dependsOnJobs = null) - : base(TokenGen.CreateToken(typeof(UpdateChaptersDownloadedJob)), JobType.UpdateChaptersDownloadedJob, recurrenceMs, parentJob, dependsOnJobs) - { - this.Manga = manga; - } - - /// - /// EF ONLY!!! - /// - internal UpdateChaptersDownloadedJob(ILazyLoader lazyLoader, string key, ulong recurrenceMs, string mangaId, string? parentJobId) - : base(lazyLoader, key, JobType.UpdateChaptersDownloadedJob, recurrenceMs, parentJobId) - { - this.MangaId = mangaId; - } - - protected override IEnumerable RunInternal(PgsqlContext context) - { - context.Entry(Manga).Reference(m => m.Library).Load(); - foreach (Chapter mangaChapter in Manga.Chapters) - { - mangaChapter.Downloaded = mangaChapter.CheckDownloaded(); - } - - try - { - context.SaveChanges(); - } - catch (DbUpdateException e) - { - Log.Error(e); - } - return []; - } -} \ No newline at end of file diff --git a/API/Schema/Jobs/UpdateCoverJob.cs b/API/Schema/Jobs/UpdateCoverJob.cs deleted file mode 100644 index ab64c40..0000000 --- a/API/Schema/Jobs/UpdateCoverJob.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Newtonsoft.Json; - -namespace API.Schema.Jobs; - -public class UpdateCoverJob : Job -{ - [StringLength(64)] [Required] public string MangaId { get; init; } = null!; - private Manga? _manga; - - [JsonIgnore] - public Manga Manga - { - get => LazyLoader.Load(this, ref _manga) ?? throw new InvalidOperationException(); - init - { - MangaId = value.Key; - _manga = value; - } - } - - - public UpdateCoverJob(Manga manga, ulong recurrenceMs, Job? parentJob = null, ICollection? dependsOnJobs = null) - : base(TokenGen.CreateToken(typeof(UpdateCoverJob)), JobType.UpdateCoverJob, recurrenceMs, parentJob, dependsOnJobs) - { - this.Manga = manga; - } - - /// - /// EF ONLY!!! - /// - internal UpdateCoverJob(ILazyLoader lazyLoader, string key, string mangaId, ulong recurrenceMs, string? parentJobId) - : base(lazyLoader, key, JobType.UpdateCoverJob, recurrenceMs, parentJobId) - { - this.MangaId = mangaId; - } - - protected override IEnumerable RunInternal(PgsqlContext context) - { - bool keepCover = context.Jobs - .Any(job => job.JobType == JobType.DownloadAvailableChaptersJob - && ((DownloadAvailableChaptersJob)job).MangaId == MangaId); - if (!keepCover) - { - if(File.Exists(Manga.CoverFileNameInCache)) - File.Delete(Manga.CoverFileNameInCache); - try - { - Manga.CoverFileNameInCache = null; - context.Jobs.Remove(this); - context.SaveChanges(); - } - catch (DbUpdateException e) - { - Log.Error(e); - } - } - else - { - return [new DownloadMangaCoverJob(Manga, this)]; - } - return []; - } -} \ No newline at end of file diff --git a/API/Schema/LibraryConnectors/Kavita.cs b/API/Schema/LibraryContext/LibraryConnectors/Kavita.cs similarity index 98% rename from API/Schema/LibraryConnectors/Kavita.cs rename to API/Schema/LibraryContext/LibraryConnectors/Kavita.cs index c6f5964..4543c40 100644 --- a/API/Schema/LibraryConnectors/Kavita.cs +++ b/API/Schema/LibraryContext/LibraryConnectors/Kavita.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Text.Json.Nodes; -namespace API.Schema.LibraryConnectors; +namespace API.Schema.LibraryContext.LibraryConnectors; public class Kavita : LibraryConnector { diff --git a/API/Schema/LibraryConnectors/Komga.cs b/API/Schema/LibraryContext/LibraryConnectors/Komga.cs similarity index 97% rename from API/Schema/LibraryConnectors/Komga.cs rename to API/Schema/LibraryContext/LibraryConnectors/Komga.cs index b56848e..2e94e84 100644 --- a/API/Schema/LibraryConnectors/Komga.cs +++ b/API/Schema/LibraryContext/LibraryConnectors/Komga.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Text.Json.Nodes; -namespace API.Schema.LibraryConnectors; +namespace API.Schema.LibraryContext.LibraryConnectors; public class Komga : LibraryConnector { diff --git a/API/Schema/LibraryConnectors/LibraryConnector.cs b/API/Schema/LibraryContext/LibraryConnectors/LibraryConnector.cs similarity index 94% rename from API/Schema/LibraryConnectors/LibraryConnector.cs rename to API/Schema/LibraryContext/LibraryConnectors/LibraryConnector.cs index ddbacd0..750fd16 100644 --- a/API/Schema/LibraryConnectors/LibraryConnector.cs +++ b/API/Schema/LibraryContext/LibraryConnectors/LibraryConnector.cs @@ -4,7 +4,7 @@ using log4net; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; -namespace API.Schema.LibraryConnectors; +namespace API.Schema.LibraryContext.LibraryConnectors; [PrimaryKey("LibraryConnectorId")] public abstract class LibraryConnector(string libraryConnectorId, LibraryType libraryType, string baseUrl, string auth) diff --git a/API/Schema/LibraryConnectors/LibraryType.cs b/API/Schema/LibraryContext/LibraryConnectors/LibraryType.cs similarity index 52% rename from API/Schema/LibraryConnectors/LibraryType.cs rename to API/Schema/LibraryContext/LibraryConnectors/LibraryType.cs index 3fe500d..b2454a8 100644 --- a/API/Schema/LibraryConnectors/LibraryType.cs +++ b/API/Schema/LibraryContext/LibraryConnectors/LibraryType.cs @@ -1,4 +1,4 @@ -namespace API.Schema.LibraryConnectors; +namespace API.Schema.LibraryContext.LibraryConnectors; public enum LibraryType : byte { diff --git a/API/Schema/LibraryConnectors/NetClient.cs b/API/Schema/LibraryContext/LibraryConnectors/NetClient.cs similarity index 97% rename from API/Schema/LibraryConnectors/NetClient.cs rename to API/Schema/LibraryContext/LibraryConnectors/NetClient.cs index 23579cd..f18e1e5 100644 --- a/API/Schema/LibraryConnectors/NetClient.cs +++ b/API/Schema/LibraryContext/LibraryConnectors/NetClient.cs @@ -2,7 +2,7 @@ using System.Net.Http.Headers; using log4net; -namespace API.Schema.LibraryConnectors; +namespace API.Schema.LibraryContext.LibraryConnectors; public class NetClient { diff --git a/API/Schema/Contexts/LibraryContext.cs b/API/Schema/LibraryContext/LibraryContext.cs similarity index 80% rename from API/Schema/Contexts/LibraryContext.cs rename to API/Schema/LibraryContext/LibraryContext.cs index 6473b5c..91ea485 100644 --- a/API/Schema/Contexts/LibraryContext.cs +++ b/API/Schema/LibraryContext/LibraryContext.cs @@ -1,9 +1,7 @@ -using API.Schema.LibraryConnectors; -using log4net; +using API.Schema.LibraryContext.LibraryConnectors; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; -namespace API.Schema.Contexts; +namespace API.Schema.LibraryContext; public class LibraryContext(DbContextOptions options) : TrangaBaseContext(options) { diff --git a/API/Schema/AltTitle.cs b/API/Schema/MangaContext/AltTitle.cs similarity index 93% rename from API/Schema/AltTitle.cs rename to API/Schema/MangaContext/AltTitle.cs index 2cc0b0d..de0282d 100644 --- a/API/Schema/AltTitle.cs +++ b/API/Schema/MangaContext/AltTitle.cs @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations; using Microsoft.EntityFrameworkCore; -namespace API.Schema; +namespace API.Schema.MangaContext; [PrimaryKey("Key")] public class AltTitle(string language, string title) : Identifiable(TokenGen.CreateToken("AltTitle")) diff --git a/API/Schema/Author.cs b/API/Schema/MangaContext/Author.cs similarity index 91% rename from API/Schema/Author.cs rename to API/Schema/MangaContext/Author.cs index 4517b43..6529f1c 100644 --- a/API/Schema/Author.cs +++ b/API/Schema/MangaContext/Author.cs @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations; using Microsoft.EntityFrameworkCore; -namespace API.Schema; +namespace API.Schema.MangaContext; [PrimaryKey("Key")] public class Author(string authorName) : Identifiable(TokenGen.CreateToken(typeof(Author), authorName)) diff --git a/API/Schema/Chapter.cs b/API/Schema/MangaContext/Chapter.cs similarity index 99% rename from API/Schema/Chapter.cs rename to API/Schema/MangaContext/Chapter.cs index 47cfd66..8da8a23 100644 --- a/API/Schema/Chapter.cs +++ b/API/Schema/MangaContext/Chapter.cs @@ -7,7 +7,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Newtonsoft.Json; -namespace API.Schema; +namespace API.Schema.MangaContext; [PrimaryKey("Key")] public class Chapter : Identifiable, IComparable diff --git a/API/Schema/FileLibrary.cs b/API/Schema/MangaContext/FileLibrary.cs similarity index 93% rename from API/Schema/FileLibrary.cs rename to API/Schema/MangaContext/FileLibrary.cs index c01ab48..1cc61f4 100644 --- a/API/Schema/FileLibrary.cs +++ b/API/Schema/MangaContext/FileLibrary.cs @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations; using Microsoft.EntityFrameworkCore; -namespace API.Schema; +namespace API.Schema.MangaContext; [PrimaryKey("Key")] public class FileLibrary(string basePath, string libraryName) diff --git a/API/Schema/Link.cs b/API/Schema/MangaContext/Link.cs similarity index 93% rename from API/Schema/Link.cs rename to API/Schema/MangaContext/Link.cs index a96bb77..871b6e1 100644 --- a/API/Schema/Link.cs +++ b/API/Schema/MangaContext/Link.cs @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations; using Microsoft.EntityFrameworkCore; -namespace API.Schema; +namespace API.Schema.MangaContext; [PrimaryKey("Key")] public class Link(string linkProvider, string linkUrl) : Identifiable(TokenGen.CreateToken(typeof(Link), linkProvider, linkUrl)) diff --git a/API/Schema/Manga.cs b/API/Schema/MangaContext/Manga.cs similarity index 82% rename from API/Schema/Manga.cs rename to API/Schema/MangaContext/Manga.cs index 5415cb0..77ee7c7 100644 --- a/API/Schema/Manga.cs +++ b/API/Schema/MangaContext/Manga.cs @@ -2,14 +2,13 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Runtime.InteropServices; using System.Text; -using API.Schema.Contexts; -using API.Schema.Jobs; +using API.Workers; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Newtonsoft.Json; using static System.IO.UnixFileMode; -namespace API.Schema; +namespace API.Schema.MangaContext; [PrimaryKey("Key")] public class Manga : Identifiable @@ -157,42 +156,31 @@ public class Manga : Identifiable } /// - /// + /// Merges another Manga (MangaConnectorIds and Chapters) /// - /// - /// - /// - public void MergeFrom(Manga other, PgsqlContext context) + /// The other to merge + /// to use for Database operations + /// An array of for moving to new Directory + public BaseWorker[] MergeFrom(Manga other, MangaContext context) { - try + context.Mangas.Remove(other); + List newJobs = new(); + + this.MangaConnectorIds = this.MangaConnectorIds + .UnionBy(other.MangaConnectorIds, id => id.MangaConnectorName) + .ToList(); + + foreach (Chapter otherChapter in other.Chapters) { - context.Mangas.Remove(other); - List newJobs = new(); - - this.MangaConnectorIds = this.MangaConnectorIds - .UnionBy(other.MangaConnectorIds, id => id.MangaConnectorName) - .ToList(); - - foreach (Chapter otherChapter in other.Chapters) - { - string oldPath = otherChapter.FullArchiveFilePath; - Chapter newChapter = new(this, otherChapter.ChapterNumber, otherChapter.VolumeNumber, - otherChapter.Title); - this.Chapters.Add(newChapter); - string newPath = newChapter.FullArchiveFilePath; - newJobs.Add(new MoveFileOrFolderJob(oldPath, newPath)); - } - - if (other.Chapters.Count > 0) - newJobs.Add(new UpdateChaptersDownloadedJob(this, 0, null, newJobs)); - - context.Jobs.AddRange(newJobs); - context.SaveChanges(); - } - catch (DbUpdateException e) - { - throw new DbUpdateException(e.Message, e.InnerException, e.Entries); + string oldPath = otherChapter.FullArchiveFilePath; + Chapter newChapter = new(this, otherChapter.ChapterNumber, otherChapter.VolumeNumber, + otherChapter.Title); + this.Chapters.Add(newChapter); + string newPath = newChapter.FullArchiveFilePath; + newJobs.Add(new MoveFileOrFolderWorker(newPath, oldPath)); } + + return newJobs.ToArray(); } public override string ToString() => $"{base.ToString()} {Name}"; diff --git a/API/Schema/MangaConnectorId.cs b/API/Schema/MangaContext/MangaConnectorId.cs similarity index 96% rename from API/Schema/MangaConnectorId.cs rename to API/Schema/MangaContext/MangaConnectorId.cs index d4bb47e..ba70755 100644 --- a/API/Schema/MangaConnectorId.cs +++ b/API/Schema/MangaContext/MangaConnectorId.cs @@ -1,10 +1,10 @@ using System.ComponentModel.DataAnnotations; -using API.Schema.MangaConnectors; +using API.Schema.MangaContext.MangaConnectors; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Newtonsoft.Json; -namespace API.Schema; +namespace API.Schema.MangaContext; [PrimaryKey("Key")] public class MangaConnectorId : Identifiable where T : Identifiable diff --git a/API/Schema/MangaConnectors/ComickIo.cs b/API/Schema/MangaContext/MangaConnectors/ComickIo.cs similarity index 99% rename from API/Schema/MangaConnectors/ComickIo.cs rename to API/Schema/MangaContext/MangaConnectors/ComickIo.cs index beb1c7c..a2bac81 100644 --- a/API/Schema/MangaConnectors/ComickIo.cs +++ b/API/Schema/MangaContext/MangaConnectors/ComickIo.cs @@ -2,7 +2,7 @@ using API.MangaDownloadClients; using Newtonsoft.Json.Linq; -namespace API.Schema.MangaConnectors; +namespace API.Schema.MangaContext.MangaConnectors; public class ComickIo : MangaConnector { diff --git a/API/Schema/MangaConnectors/Global.cs b/API/Schema/MangaContext/MangaConnectors/Global.cs similarity index 91% rename from API/Schema/MangaConnectors/Global.cs rename to API/Schema/MangaContext/MangaConnectors/Global.cs index 3c54300..611e4d5 100644 --- a/API/Schema/MangaConnectors/Global.cs +++ b/API/Schema/MangaContext/MangaConnectors/Global.cs @@ -1,11 +1,9 @@ -using API.Schema.Contexts; - -namespace API.Schema.MangaConnectors; +namespace API.Schema.MangaContext.MangaConnectors; public class Global : MangaConnector { - private PgsqlContext context { get; init; } - public Global(PgsqlContext context) : base("Global", ["all"], [""], "") + private MangaContext context { get; init; } + public Global(MangaContext context) : base("Global", ["all"], [""], "") { this.context = context; } diff --git a/API/Schema/MangaConnectors/MangaConnector.cs b/API/Schema/MangaContext/MangaConnectors/MangaConnector.cs similarity index 98% rename from API/Schema/MangaConnectors/MangaConnector.cs rename to API/Schema/MangaContext/MangaConnectors/MangaConnector.cs index 4b82725..3cad612 100644 --- a/API/Schema/MangaConnectors/MangaConnector.cs +++ b/API/Schema/MangaContext/MangaConnectors/MangaConnector.cs @@ -6,7 +6,7 @@ using log4net; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; -namespace API.Schema.MangaConnectors; +namespace API.Schema.MangaContext.MangaConnectors; [PrimaryKey("Name")] public abstract class MangaConnector(string name, string[] supportedLanguages, string[] baseUris, string iconUrl) diff --git a/API/Schema/MangaConnectors/MangaDex.cs b/API/Schema/MangaContext/MangaConnectors/MangaDex.cs similarity index 99% rename from API/Schema/MangaConnectors/MangaDex.cs rename to API/Schema/MangaContext/MangaConnectors/MangaDex.cs index 12576be..00e620e 100644 --- a/API/Schema/MangaConnectors/MangaDex.cs +++ b/API/Schema/MangaContext/MangaConnectors/MangaDex.cs @@ -2,7 +2,7 @@ using API.MangaDownloadClients; using Newtonsoft.Json.Linq; -namespace API.Schema.MangaConnectors; +namespace API.Schema.MangaContext.MangaConnectors; public class MangaDex : MangaConnector { diff --git a/API/Schema/Contexts/PgsqlContext.cs b/API/Schema/MangaContext/MangaContext.cs similarity index 57% rename from API/Schema/Contexts/PgsqlContext.cs rename to API/Schema/MangaContext/MangaContext.cs index 3ab94e1..2371690 100644 --- a/API/Schema/Contexts/PgsqlContext.cs +++ b/API/Schema/MangaContext/MangaContext.cs @@ -1,15 +1,11 @@ -using API.Schema.Jobs; -using API.Schema.MangaConnectors; -using API.Schema.MetadataFetchers; -using log4net; +using API.Schema.MangaContext.MangaConnectors; +using API.Schema.MangaContext.MetadataFetchers; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; -namespace API.Schema.Contexts; +namespace API.Schema.MangaContext; -public class PgsqlContext(DbContextOptions options) : TrangaBaseContext(options) +public class MangaContext(DbContextOptions options) : TrangaBaseContext(options) { - public DbSet Jobs { get; set; } public DbSet MangaConnectors { get; set; } public DbSet Mangas { get; set; } public DbSet LocalLibraries { get; set; } @@ -22,92 +18,6 @@ public class PgsqlContext(DbContextOptions options) : TrangaBaseCo protected override void OnModelCreating(ModelBuilder modelBuilder) { - //Job Types - modelBuilder.Entity() - .HasDiscriminator(j => j.JobType) - .HasValue(JobType.MoveFileOrFolderJob) - .HasValue(JobType.MoveMangaLibraryJob) - .HasValue(JobType.DownloadAvailableChaptersJob) - .HasValue(JobType.DownloadSingleChapterJob) - .HasValue(JobType.DownloadMangaCoverJob) - .HasValue(JobType.RetrieveChaptersJob) - .HasValue(JobType.UpdateCoverJob) - .HasValue(JobType.UpdateChaptersDownloadedJob); - - modelBuilder.Entity() - .HasOne(j => j.Manga) - .WithMany() - .HasForeignKey(j => j.MangaId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .Navigation(j => j.Manga) - .EnableLazyLoading(); - modelBuilder.Entity() - .HasOne(j => j.Manga) - .WithMany() - .HasForeignKey(j => j.MangaId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .Navigation(j => j.Manga) - .EnableLazyLoading(); - modelBuilder.Entity() - .HasOne(j => j.Chapter) - .WithMany() - .HasForeignKey(j => j.ChapterId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .Navigation(j => j.Chapter) - .EnableLazyLoading(); - modelBuilder.Entity() - .HasOne(j => j.Manga) - .WithMany() - .HasForeignKey(j => j.MangaId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .Navigation(j => j.Manga) - .EnableLazyLoading(); - modelBuilder.Entity() - .HasOne(j => j.ToFileLibrary) - .WithMany() - .HasForeignKey(j => j.ToLibraryId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .Navigation(j => j.ToFileLibrary) - .EnableLazyLoading(); - modelBuilder.Entity() - .HasOne(j => j.Manga) - .WithMany() - .HasForeignKey(j => j.MangaId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .Navigation(j => j.Manga) - .EnableLazyLoading(); - modelBuilder.Entity() - .HasOne(j => j.Manga) - .WithMany() - .HasForeignKey(j => j.MangaId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .Navigation(j => j.Manga) - .EnableLazyLoading(); - - //Job has possible ParentJob - modelBuilder.Entity() - .HasOne(childJob => childJob.ParentJob) - .WithMany() - .HasForeignKey(childJob => childJob.ParentJobId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .Navigation(childJob => childJob.ParentJob) - .EnableLazyLoading(); - //Job might be dependent on other Jobs - modelBuilder.Entity() - .HasMany(root => root.DependsOnJobs) - .WithMany(); - modelBuilder.Entity() - .Navigation(j => j.DependsOnJobs) - .EnableLazyLoading(); - //MangaConnector Types modelBuilder.Entity() .HasDiscriminator(c => c.Name) diff --git a/API/Schema/MangaTag.cs b/API/Schema/MangaContext/MangaTag.cs similarity index 89% rename from API/Schema/MangaTag.cs rename to API/Schema/MangaContext/MangaTag.cs index aa2e94b..73de8c3 100644 --- a/API/Schema/MangaTag.cs +++ b/API/Schema/MangaContext/MangaTag.cs @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations; using Microsoft.EntityFrameworkCore; -namespace API.Schema; +namespace API.Schema.MangaContext; [PrimaryKey("Tag")] public class MangaTag(string tag) diff --git a/API/Schema/MetadataFetchers/MetadataEntry.cs b/API/Schema/MangaContext/MetadataFetchers/MetadataEntry.cs similarity index 95% rename from API/Schema/MetadataFetchers/MetadataEntry.cs rename to API/Schema/MangaContext/MetadataFetchers/MetadataEntry.cs index 2c090e4..e8550fa 100644 --- a/API/Schema/MetadataFetchers/MetadataEntry.cs +++ b/API/Schema/MangaContext/MetadataFetchers/MetadataEntry.cs @@ -1,7 +1,7 @@ using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; -namespace API.Schema.MetadataFetchers; +namespace API.Schema.MangaContext.MetadataFetchers; [PrimaryKey("MetadataFetcherName", "Identifier")] public class MetadataEntry diff --git a/API/Schema/MetadataFetchers/MetadataFetcher.cs b/API/Schema/MangaContext/MetadataFetchers/MetadataFetcher.cs similarity index 88% rename from API/Schema/MetadataFetchers/MetadataFetcher.cs rename to API/Schema/MangaContext/MetadataFetchers/MetadataFetcher.cs index 9952f41..48f8104 100644 --- a/API/Schema/MetadataFetchers/MetadataFetcher.cs +++ b/API/Schema/MangaContext/MetadataFetchers/MetadataFetcher.cs @@ -1,8 +1,6 @@ -using System.Diagnostics.CodeAnalysis; -using API.Schema.Contexts; using Microsoft.EntityFrameworkCore; -namespace API.Schema.MetadataFetchers; +namespace API.Schema.MangaContext.MetadataFetchers; [PrimaryKey("MetadataFetcherName")] public abstract class MetadataFetcher @@ -33,5 +31,5 @@ public abstract class MetadataFetcher /// /// Updates the Manga linked in the MetadataEntry /// - public abstract void UpdateMetadata(MetadataEntry metadataEntry, PgsqlContext dbContext); + public abstract void UpdateMetadata(MetadataEntry metadataEntry, MangaContext dbContext); } \ No newline at end of file diff --git a/API/Schema/MetadataFetchers/MetadataSearchResult.cs b/API/Schema/MangaContext/MetadataFetchers/MetadataSearchResult.cs similarity index 71% rename from API/Schema/MetadataFetchers/MetadataSearchResult.cs rename to API/Schema/MangaContext/MetadataFetchers/MetadataSearchResult.cs index abdbb33..9b4b64f 100644 --- a/API/Schema/MetadataFetchers/MetadataSearchResult.cs +++ b/API/Schema/MangaContext/MetadataFetchers/MetadataSearchResult.cs @@ -1,3 +1,3 @@ -namespace API.Schema.MetadataFetchers; +namespace API.Schema.MangaContext.MetadataFetchers; public record MetadataSearchResult(string Identifier, string Name, string Url, string? Description = null, string? CoverUrl = null); \ No newline at end of file diff --git a/API/Schema/MetadataFetchers/MyAnimeList.cs b/API/Schema/MangaContext/MetadataFetchers/MyAnimeList.cs similarity index 96% rename from API/Schema/MetadataFetchers/MyAnimeList.cs rename to API/Schema/MangaContext/MetadataFetchers/MyAnimeList.cs index 14d1a5d..3be2d10 100644 --- a/API/Schema/MetadataFetchers/MyAnimeList.cs +++ b/API/Schema/MangaContext/MetadataFetchers/MyAnimeList.cs @@ -1,9 +1,8 @@ using System.Text.RegularExpressions; -using API.Schema.Contexts; using JikanDotNet; using Microsoft.EntityFrameworkCore; -namespace API.Schema.MetadataFetchers; +namespace API.Schema.MangaContext.MetadataFetchers; public class MyAnimeList : MetadataFetcher { @@ -45,7 +44,7 @@ public class MyAnimeList : MetadataFetcher /// /// /// - public override void UpdateMetadata(MetadataEntry metadataEntry, PgsqlContext dbContext) + public override void UpdateMetadata(MetadataEntry metadataEntry, MangaContext dbContext) { Manga dbManga = dbContext.Mangas.Find(metadataEntry.MangaId)!; MangaFull resultData; diff --git a/API/Schema/Notification.cs b/API/Schema/NotificationsContext/Notification.cs similarity index 96% rename from API/Schema/Notification.cs rename to API/Schema/NotificationsContext/Notification.cs index 02231fe..3253fda 100644 --- a/API/Schema/Notification.cs +++ b/API/Schema/NotificationsContext/Notification.cs @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations; using Microsoft.EntityFrameworkCore; -namespace API.Schema; +namespace API.Schema.NotificationsContext; [PrimaryKey(nameof(Key))] public class Notification : Identifiable diff --git a/API/Schema/NotificationConnectors/NotificationConnector.cs b/API/Schema/NotificationsContext/NotificationConnectors/NotificationConnector.cs similarity index 97% rename from API/Schema/NotificationConnectors/NotificationConnector.cs rename to API/Schema/NotificationsContext/NotificationConnectors/NotificationConnector.cs index b65d455..c3c01cb 100644 --- a/API/Schema/NotificationConnectors/NotificationConnector.cs +++ b/API/Schema/NotificationsContext/NotificationConnectors/NotificationConnector.cs @@ -5,7 +5,7 @@ using log4net; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; -namespace API.Schema.NotificationConnectors; +namespace API.Schema.NotificationsContext.NotificationConnectors; [PrimaryKey("Name")] public class NotificationConnector(string name, string url, Dictionary headers, string httpMethod, string body) diff --git a/API/Schema/Contexts/NotificationsContext.cs b/API/Schema/NotificationsContext/NotificationsContext.cs similarity index 69% rename from API/Schema/Contexts/NotificationsContext.cs rename to API/Schema/NotificationsContext/NotificationsContext.cs index 05d6644..ce942d7 100644 --- a/API/Schema/Contexts/NotificationsContext.cs +++ b/API/Schema/NotificationsContext/NotificationsContext.cs @@ -1,9 +1,7 @@ -using API.Schema.NotificationConnectors; -using log4net; +using API.Schema.NotificationsContext.NotificationConnectors; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; -namespace API.Schema.Contexts; +namespace API.Schema.NotificationsContext; public class NotificationsContext(DbContextOptions options) : TrangaBaseContext(options) { diff --git a/API/Schema/TrangaBaseContext.cs b/API/Schema/TrangaBaseContext.cs new file mode 100644 index 0000000..5ad8947 --- /dev/null +++ b/API/Schema/TrangaBaseContext.cs @@ -0,0 +1,38 @@ +using log4net; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; + +namespace API.Schema; + +public abstract class TrangaBaseContext : DbContext where T : DbContext +{ + private ILog Log { get; init; } + + protected TrangaBaseContext(DbContextOptions options) : base(options) + { + this.Log = LogManager.GetLogger(GetType()); + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + base.OnConfiguring(optionsBuilder); + optionsBuilder.LogTo(s => + { + Log.Debug(s); + }, Array.Empty(), LogLevel.Warning, DbContextLoggerOptions.Level | DbContextLoggerOptions.Category | DbContextLoggerOptions.UtcTime); + } + + internal async Task Sync() + { + try + { + await this.SaveChangesAsync(); + return null; + } + catch (Exception e) + { + Log.Error(null, e); + return e.Message; + } + } +} \ No newline at end of file diff --git a/API/Tranga.cs b/API/Tranga.cs index d0c75c3..ac6eb83 100644 --- a/API/Tranga.cs +++ b/API/Tranga.cs @@ -1,12 +1,7 @@ -using API.Schema; -using API.Schema.Contexts; -using API.Schema.Jobs; -using API.Schema.MangaConnectors; -using API.Schema.MetadataFetchers; -using API.Schema.NotificationConnectors; +using API.Schema.MangaContext.MetadataFetchers; +using API.Workers; using log4net; using log4net.Config; -using Microsoft.EntityFrameworkCore; namespace API; @@ -22,10 +17,9 @@ public static class Tranga " |___| |__| |___._||__|__||___ ||___._|\n" + " |_____| \n\n"; - public static Thread NotificationSenderThread { get; } = new (NotificationSender); - public static Thread JobStarterThread { get; } = new (JobStarter); + public static Thread PeriodicWorkerStarterThread { get; } = new (WorkerStarter); private static readonly ILog Log = LogManager.GetLogger(typeof(Tranga)); - internal static MetadataFetcher[] MetadataFetchers = [new MyAnimeList()]; + internal static readonly MetadataFetcher[] MetadataFetchers = [new MyAnimeList()]; internal static void StartLogger() { @@ -33,88 +27,36 @@ public static class Tranga Log.Info("Logger Configured."); Log.Info(TRANGA); } - - internal static void RemoveStaleFiles(PgsqlContext context) - { - Log.Info("Removing stale files..."); - if (!Directory.Exists(TrangaSettings.coverImageCache)) - return; - string[] usedFiles = context.Mangas.Select(m => m.CoverFileNameInCache).Where(s => s != null).ToArray()!; - string[] extraneousFiles = new DirectoryInfo(TrangaSettings.coverImageCache).GetFiles() - .Where(f => usedFiles.Contains(f.FullName) == false) - .Select(f => f.FullName) - .ToArray(); - foreach (string path in extraneousFiles) - { - Log.Info($"Deleting {path}"); - File.Delete(path); - } - } - private static void NotificationSender(object? serviceProviderObj) + internal static HashSet Workers { get; private set; } = new (); + public static void AddWorker(BaseWorker worker) => Workers.Add(worker); + public static void AddWorkers(IEnumerable workers) { - if (serviceProviderObj is null) + foreach (BaseWorker baseWorker in workers) { - Log.Error("serviceProviderObj is null"); - return; + AddWorker(baseWorker); } - IServiceProvider serviceProvider = (IServiceProvider)serviceProviderObj!; - using IServiceScope scope = serviceProvider.CreateScope(); - NotificationsContext context = scope.ServiceProvider.GetRequiredService(); - - try + } + public static void RemoveWorker(BaseWorker worker) + { + IEnumerable baseWorkers = Workers.Where(w => w.DependenciesAndSelf.Any(w => w == worker)); + foreach (BaseWorker baseWorker in baseWorkers) { - //Removing Notifications from previous runs - IQueryable staleNotifications = - context.Notifications.Where(n => n.Urgency < NotificationUrgency.Normal); - context.Notifications.RemoveRange(staleNotifications); - context.SaveChanges(); - } - catch (DbUpdateException e) - { - Log.Error("Error removing stale notifications.", e); - } - - while (true) - { - SendNotifications(serviceProvider, NotificationUrgency.High); - SendNotifications(serviceProvider, NotificationUrgency.Normal); - SendNotifications(serviceProvider, NotificationUrgency.Low); - - Thread.Sleep(2000); + baseWorker.Cancel(); + Workers.Remove(baseWorker); + if (RunningWorkers.ContainsKey(baseWorker)) + { + RunningWorkers[baseWorker].Abort(); + RunningWorkers.Remove(baseWorker); + } } } - private static void SendNotifications(IServiceProvider serviceProvider, NotificationUrgency urgency) + private static readonly Dictionary RunningWorkers = new(); + public static BaseWorker[] GetRunningWorkers() => RunningWorkers.Keys.ToArray(); + private static void WorkerStarter(object? serviceProviderObj) { - Log.Debug($"Sending notifications for {urgency}"); - using IServiceScope scope = serviceProvider.CreateScope(); - NotificationsContext context = scope.ServiceProvider.GetRequiredService(); - - List notifications = context.Notifications.Where(n => n.Urgency == urgency).ToList(); - if (!notifications.Any()) - return; - - try - { - foreach (NotificationConnector notificationConnector in context.NotificationConnectors) - { - foreach (Notification notification in notifications) - notificationConnector.SendNotification(notification.Title, notification.Message); - } - - context.Notifications.RemoveRange(notifications); - context.SaveChangesAsync(); - } - catch (DbUpdateException e) - { - Log.Error("Error sending notifications.", e); - } - } - private static readonly Dictionary RunningJobs = new(); - private static void JobStarter(object? serviceProviderObj) - { - Log.Info("JobStarter Thread running."); + Log.Info("WorkerStarter Thread running."); if (serviceProviderObj is null) { Log.Error("serviceProviderObj is null"); @@ -123,171 +65,10 @@ public static class Tranga IServiceProvider serviceProvider = (IServiceProvider)serviceProviderObj; while (true) - { - Log.Debug("Starting Job-Cycle..."); - DateTime cycleStart = DateTime.UtcNow; - using IServiceScope scope = serviceProvider.CreateScope(); - PgsqlContext cycleContext = scope.ServiceProvider.GetRequiredService(); - - //Get Running Jobs - List runningJobs = cycleContext.Jobs.GetRunningJobs(); - - DateTime filterStart = DateTime.UtcNow; - Log.Debug("Filtering Jobs..."); - - List waitingJobs = cycleContext.Jobs.GetWaitingJobs(); - List dueJobs = waitingJobs.FilterDueJobs(); - List jobsWithoutDependencies = dueJobs.FilterJobDependencies(); - - List startJobs = dueJobs; - Log.Debug($"Jobs Filtered! (took {DateTime.UtcNow.Subtract(filterStart).TotalMilliseconds}ms)"); - - - //Start Jobs that are allowed to run (preconditions match) - foreach (Job job in startJobs) - { - bool running = false; - Thread t = new(() => - { - using IServiceScope jobScope = serviceProvider.CreateScope(); - PgsqlContext jobContext = jobScope.ServiceProvider.GetRequiredService(); - if (jobContext.Jobs.Find(job.Key) is not { } inContext) - return; - inContext.Run(jobContext, ref running); //FIND the job IN THE NEW CONTEXT!!!!!!! SO WE DON'T GET TRACKING PROBLEMS AND AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - }); - RunningJobs.Add(t, job); - t.Start(); - while(!running) - Thread.Sleep(10); - } - Log.Debug($"Running: {runningJobs.Count}\n" + - $"{string.Join("\n", runningJobs.Select(s => "\t- " + s))}\n" + - $"Waiting: {waitingJobs.Count} Due: {dueJobs.Count}\n" + - $"{string.Join("\n", dueJobs.Select(s => "\t- " + s))}\n" + - $"of which {jobsWithoutDependencies.Count} without missing dependencies, of which\n" + - $"{startJobs.Count} were started:\n" + - $"{string.Join("\n", startJobs.Select(s => "\t- " + s))}"); - - if (Log.IsDebugEnabled && dueJobs.Count < 1) - if(waitingJobs.MinBy(j => j.NextExecution) is { } nextJob) - Log.Debug($"Next job in {nextJob.NextExecution.Subtract(DateTime.UtcNow)} (at {nextJob.NextExecution}): {nextJob.Key}"); - - (Thread, Job)[] removeFromThreadsList = RunningJobs.Where(t => !t.Key.IsAlive) - .Select(t => (t.Key, t.Value)).ToArray(); - Log.Debug($"Remove from Threads List: {removeFromThreadsList.Length}"); - foreach ((Thread thread, Job job) thread in removeFromThreadsList) - { - RunningJobs.Remove(thread.thread); - } - - try - { - cycleContext.SaveChanges(); - } - catch (DbUpdateException e) - { - Log.Error("Failed saving Job changes.", e); - } - Log.Debug($"Job-Cycle over! (took {DateTime.UtcNow.Subtract(cycleStart).TotalMilliseconds}ms"); - Thread.Sleep(TrangaSettings.startNewJobTimeoutMs); - } - } - - private static List GetRunningJobs(this IQueryable jobs) - { - DateTime start = DateTime.UtcNow; - List ret = jobs.Where(j => j.state == JobState.Running).ToList(); - DateTime end = DateTime.UtcNow; - Log.Debug($"Getting running Jobs took {end.Subtract(start).TotalMilliseconds}ms"); - return ret; - } - - private static List GetWaitingJobs(this IQueryable jobs) - { - DateTime start = DateTime.UtcNow; - List ret = jobs.Where(j => j.state == JobState.CompletedWaiting || j.state == JobState.FirstExecution).ToList(); - DateTime end = DateTime.UtcNow; - Log.Debug($"Getting waiting Jobs took {end.Subtract(start).TotalMilliseconds}ms"); - return ret; - } - - - private static List FilterDueJobs(this List jobs) - { - DateTime start = DateTime.UtcNow; - List ret = jobs.Where(j => j.NextExecution < DateTime.UtcNow).ToList(); - DateTime end = DateTime.UtcNow; - Log.Debug($"Filtering Due Jobs took {end.Subtract(start).TotalMilliseconds}ms"); - return ret; - } - - - private static List FilterJobDependencies(this List jobs) - { - DateTime start = DateTime.UtcNow; - List ret = jobs.Where(job => job.DependsOnJobs.All(j => j.IsCompleted)).ToList(); - DateTime end = DateTime.UtcNow; - Log.Debug($"Filtering Dependencies took {end.Subtract(start).TotalMilliseconds}ms"); - return ret; - } - - - private static List FilterJobsWithoutDownloading(this List jobs) - { - JobType[] types = [JobType.MoveFileOrFolderJob, JobType.MoveMangaLibraryJob, JobType.UpdateChaptersDownloadedJob]; - DateTime start = DateTime.UtcNow; - List ret = jobs.Where(j => types.Contains(j.JobType)).ToList(); - DateTime end = DateTime.UtcNow; - Log.Debug($"Filtering Jobs without Download took {end.Subtract(start).TotalMilliseconds}ms"); - return ret; - } - - private static List MatchJobsRunningAndWaiting(Dictionary>> running, - Dictionary>> waiting) - { - Log.Debug($"Matching {running.Count} running Jobs to {waiting.Count} waiting Jobs. Busy Connectors: {string.Join(", ", running.Select(r => r.Key))}"); - DateTime start = DateTime.UtcNow; - List ret = new(); - //Foreach MangaConnector - foreach ((string connector, Dictionary> jobTypeJobsWaiting) in waiting) { - //Check if MangaConnector has a Job running - if (running.TryGetValue(connector, out Dictionary>? jobTypeJobsRunning)) - { - //MangaConnector has running Jobs - //Match per JobType (MangaConnector can have 1 Job per Type running at the same time) - foreach ((JobType jobType, List jobsWaiting) in jobTypeJobsWaiting) - { - if(jobTypeJobsRunning.ContainsKey(jobType)) - //Already a job of Type running on MangaConnector - continue; - if (jobType is not JobType.DownloadSingleChapterJob) - //If it is not a DownloadSingleChapterJob, just add the first - ret.Add(jobsWaiting.First()); - else - //Add the Job with the lowest Chapternumber - ret.Add(jobsWaiting.OrderBy(j => ((DownloadSingleChapterJob)j).Chapter).First()); - } - } - else - { - //MangaConnector has no running Jobs - foreach ((JobType jobType, List jobsWaiting) in jobTypeJobsWaiting) - { - if(ret.Any(j => j.JobType == jobType)) - //Already a job of type to be started - continue; - if (jobType is not JobType.DownloadSingleChapterJob) - //If it is not a DownloadSingleChapterJob, just add the first - ret.Add(jobsWaiting.First()); - else - //Add the Job with the lowest Chapternumber - ret.Add(jobsWaiting.OrderBy(j => ((DownloadSingleChapterJob)j).Chapter).First()); - } - } + using IServiceScope scope = serviceProvider.CreateScope(); + + Thread.Sleep(TrangaSettings.workCycleTimeout); } - DateTime end = DateTime.UtcNow; - Log.Debug($"Getting eligible jobs (not held back by Connector) took {end.Subtract(start).TotalMilliseconds}ms"); - return ret; } } \ No newline at end of file diff --git a/API/TrangaSettings.cs b/API/TrangaSettings.cs index 1857d6c..913c6d6 100644 --- a/API/TrangaSettings.cs +++ b/API/TrangaSettings.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; using API.MangaDownloadClients; -using API.Schema; +using API.Schema.NotificationsContext; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -36,7 +36,7 @@ public static class TrangaSettings [JsonIgnore] public static string coverImageCache => Path.Join(workingDirectory, "imageCache"); public static bool aprilFoolsMode { get; private set; } = true; - public static int startNewJobTimeoutMs { get; private set; } = 20000; + public static int workCycleTimeout { get; private set; } = 20000; [JsonIgnore] internal static readonly Dictionary DefaultRequestLimits = new () { @@ -153,7 +153,7 @@ public static class TrangaSettings jobj.Add("requestLimits", JToken.FromObject(requestLimits)); jobj.Add("compression", JToken.FromObject(compression)); jobj.Add("bwImages", JToken.FromObject(bwImages)); - jobj.Add("startNewJobTimeoutMs", JToken.FromObject(startNewJobTimeoutMs)); + jobj.Add("workCycleTimeout", JToken.FromObject(workCycleTimeout)); jobj.Add("chapterNamingScheme", JToken.FromObject(chapterNamingScheme)); jobj.Add("flareSolverrUrl", JToken.FromObject(flareSolverrUrl)); return jobj; @@ -178,8 +178,8 @@ public static class TrangaSettings compression = ci.Value()!; if (jobj.TryGetValue("bwImages", out JToken? bwi)) bwImages = bwi.Value()!; - if (jobj.TryGetValue("startNewJobTimeoutMs", out JToken? snjt)) - startNewJobTimeoutMs = snjt.Value()!; + if (jobj.TryGetValue("workCycleTimeout", out JToken? snjt)) + workCycleTimeout = snjt.Value()!; if (jobj.TryGetValue("chapterNamingScheme", out JToken? cns)) chapterNamingScheme = cns.Value()!; if (jobj.TryGetValue("flareSolverrUrl", out JToken? fsu)) diff --git a/API/Workers/BaseWorker.cs b/API/Workers/BaseWorker.cs new file mode 100644 index 0000000..497affa --- /dev/null +++ b/API/Workers/BaseWorker.cs @@ -0,0 +1,62 @@ +using API.Schema; +using log4net; + +namespace API.Workers; + +public abstract class BaseWorker : Identifiable +{ + public BaseWorker[] DependsOn { get; init; } + public IEnumerable AllDependencies => DependsOn.Select(d => d.AllDependencies).SelectMany(x => x); + public IEnumerable DependenciesAndSelf => AllDependencies.Append(this); + public IEnumerable MissingDependencies => DependsOn.Where(d => d.State < WorkerExecutionState.Completed); + public bool DependenciesFulfilled => DependsOn.All(d => d.State >= WorkerExecutionState.Completed); + internal WorkerExecutionState State { get; set; } + private static readonly CancellationTokenSource CancellationTokenSource = new(TimeSpan.FromMinutes(10)); + protected ILog Log { get; init; } + public void Cancel() => CancellationTokenSource.Cancel(); + protected void Fail() => this.State = WorkerExecutionState.Failed; + + public BaseWorker(IEnumerable? dependsOn = null) + { + this.DependsOn = dependsOn?.ToArray() ?? []; + this.Log = LogManager.GetLogger(GetType()); + } + + public Task DoWork() + { + this.State = WorkerExecutionState.Waiting; + + BaseWorker[] missingDependenciesThatNeedStarting = MissingDependencies.Where(d => d.State < WorkerExecutionState.Waiting).ToArray(); + if(missingDependenciesThatNeedStarting.Any()) + return new Task(() => missingDependenciesThatNeedStarting); + + if (MissingDependencies.Any()) + return new Task(WaitForDependencies); + + Task task = new (DoWorkInternal, CancellationTokenSource.Token); + task.GetAwaiter().OnCompleted(() => this.State = WorkerExecutionState.Completed); + task.Start(); + this.State = WorkerExecutionState.Running; + return task; + } + + protected abstract BaseWorker[] DoWorkInternal(); + + private BaseWorker[] WaitForDependencies() + { + while (CancellationTokenSource.IsCancellationRequested == false && MissingDependencies.Any()) + { + Thread.Sleep(TrangaSettings.workCycleTimeout); + } + return [this]; + } +} + +public enum WorkerExecutionState +{ + Failed = 0, + Created = 64, + Waiting = 96, + Running = 128, + Completed = 192 +} \ No newline at end of file diff --git a/API/Workers/BaseWorkerWithContext.cs b/API/Workers/BaseWorkerWithContext.cs new file mode 100644 index 0000000..4a58779 --- /dev/null +++ b/API/Workers/BaseWorkerWithContext.cs @@ -0,0 +1,8 @@ +using Microsoft.EntityFrameworkCore; + +namespace API.Workers; + +public abstract class BaseWorkerWithContext(IServiceScope scope, IEnumerable? dependsOn = null) : BaseWorker(dependsOn) where T : DbContext +{ + protected T DbContext { get; init; } = scope.ServiceProvider.GetRequiredService(); +} \ No newline at end of file diff --git a/API/Workers/IPeriodic.cs b/API/Workers/IPeriodic.cs new file mode 100644 index 0000000..4260f9a --- /dev/null +++ b/API/Workers/IPeriodic.cs @@ -0,0 +1,9 @@ +namespace API.Workers; + +public interface IPeriodic where T : BaseWorker +{ + protected DateTime LastExecution { get; set; } + protected TimeSpan Interval { get; set; } + + public DateTime NextExecution => LastExecution.Add(Interval); +} \ No newline at end of file diff --git a/API/Workers/MaintenanceWorkers/CleanupMangaCoversWorker.cs b/API/Workers/MaintenanceWorkers/CleanupMangaCoversWorker.cs new file mode 100644 index 0000000..4c06db3 --- /dev/null +++ b/API/Workers/MaintenanceWorkers/CleanupMangaCoversWorker.cs @@ -0,0 +1,28 @@ +using API.Schema.MangaContext; + +namespace API.Workers.MaintenanceWorkers; + +public class CleanupMangaCoversWorker(IServiceScope scope, IEnumerable? dependsOn = null) : BaseWorkerWithContext(scope, dependsOn), IPeriodic +{ + public DateTime LastExecution { get; set; } = DateTime.UtcNow; + public TimeSpan Interval { get; set; } = TimeSpan.FromMinutes(60); + + protected override BaseWorker[] DoWorkInternal() + { + Log.Info("Removing stale files..."); + if (!Directory.Exists(TrangaSettings.coverImageCache)) + return []; + string[] usedFiles = DbContext.Mangas.Select(m => m.CoverFileNameInCache).Where(s => s != null).ToArray()!; + string[] extraneousFiles = new DirectoryInfo(TrangaSettings.coverImageCache).GetFiles() + .Where(f => usedFiles.Contains(f.FullName) == false) + .Select(f => f.FullName) + .ToArray(); + foreach (string path in extraneousFiles) + { + Log.Info($"Deleting {path}"); + File.Delete(path); + } + + return []; + } +} \ No newline at end of file diff --git a/API/Workers/MaintenanceWorkers/UpdateChaptersDownloadedWorker.cs b/API/Workers/MaintenanceWorkers/UpdateChaptersDownloadedWorker.cs new file mode 100644 index 0000000..905c4fb --- /dev/null +++ b/API/Workers/MaintenanceWorkers/UpdateChaptersDownloadedWorker.cs @@ -0,0 +1,28 @@ +using API.Schema.MangaContext; +using Microsoft.EntityFrameworkCore; + +namespace API.Workers; + +public class UpdateChaptersDownloadedWorker(Manga manga, IServiceScope scope, IEnumerable? dependsOn = null) + : BaseWorkerWithContext(scope, dependsOn), IPeriodic +{ + public DateTime LastExecution { get; set; } = DateTime.UtcNow; + public TimeSpan Interval { get; set; } = TimeSpan.FromMinutes(60); + protected override BaseWorker[] DoWorkInternal() + { + foreach (Chapter mangaChapter in manga.Chapters) + { + mangaChapter.Downloaded = mangaChapter.CheckDownloaded(); + } + + try + { + DbContext.SaveChanges(); + } + catch (DbUpdateException e) + { + Log.Error(e); + } + return []; + } +} \ No newline at end of file diff --git a/API/Schema/Jobs/DownloadSingleChapterJob.cs b/API/Workers/MangaDownloadWorkers/DownloadChapterFromMangaconnectorWorker.cs similarity index 72% rename from API/Schema/Jobs/DownloadSingleChapterJob.cs rename to API/Workers/MangaDownloadWorkers/DownloadChapterFromMangaconnectorWorker.cs index 582d36e..5fe2edd 100644 --- a/API/Schema/Jobs/DownloadSingleChapterJob.cs +++ b/API/Workers/MangaDownloadWorkers/DownloadChapterFromMangaconnectorWorker.cs @@ -1,67 +1,36 @@ -using System.ComponentModel.DataAnnotations; using System.IO.Compression; using System.Runtime.InteropServices; using API.MangaDownloadClients; -using API.Schema.Contexts; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Newtonsoft.Json; +using API.Schema.MangaContext; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Binarization; using static System.IO.UnixFileMode; -namespace API.Schema.Jobs; +namespace API.Workers; -public class DownloadSingleChapterJob : JobWithDownloading +public class DownloadChapterFromMangaconnectorWorker(Chapter chapter, IServiceScope scope, IEnumerable? dependsOn = null) + : BaseWorkerWithContext(scope, dependsOn) { - [StringLength(64)] [Required] public string ChapterId { get; init; } = null!; - private Chapter? _chapter; - - [JsonIgnore] - public Chapter Chapter + protected override BaseWorker[] DoWorkInternal() { - get => LazyLoader.Load(this, ref _chapter) ?? throw new InvalidOperationException(); - init - { - ChapterId = value.Key; - _chapter = value; - } - } - - public DownloadSingleChapterJob(Chapter chapter, Job? parentJob = null, ICollection? dependsOnJobs = null) - : base(TokenGen.CreateToken(typeof(DownloadSingleChapterJob)), JobType.DownloadSingleChapterJob, 0, parentJob, dependsOnJobs) - { - this.Chapter = chapter; - } - - /// - /// EF ONLY!!! - /// - internal DownloadSingleChapterJob(ILazyLoader lazyLoader, string key, string chapterId, ulong recurrenceMs, string? parentJobId) - : base(lazyLoader, key, JobType.DownloadSingleChapterJob, recurrenceMs, parentJobId) - { - this.ChapterId = chapterId; - } - - protected override IEnumerable RunInternal(PgsqlContext context) - { - if (Chapter.Downloaded) + if (chapter.Downloaded) { Log.Info("Chapter was already downloaded."); return []; } //TODO MangaConnector Selection - MangaConnectorId mcId = Chapter.MangaConnectorIds.First(); + MangaConnectorId mcId = chapter.MangaConnectorIds.First(); string[] imageUrls = mcId.MangaConnector.GetChapterImageUrls(mcId); if (imageUrls.Length < 1) { - Log.Info($"No imageUrls for chapter {Chapter}"); + Log.Info($"No imageUrls for chapter {chapter}"); return []; } - string saveArchiveFilePath = Chapter.FullArchiveFilePath; + string saveArchiveFilePath = chapter.FullArchiveFilePath; Log.Debug($"Chapter path: {saveArchiveFilePath}"); //Check if Publication Directory already exists @@ -69,7 +38,7 @@ public class DownloadSingleChapterJob : JobWithDownloading if (directoryPath is null) { Log.Error($"Directory path could not be found: {saveArchiveFilePath}"); - this.state = JobState.Failed; + this.Fail(); return []; } if (!Directory.Exists(directoryPath)) @@ -92,7 +61,7 @@ public class DownloadSingleChapterJob : JobWithDownloading string tempFolder = Directory.CreateTempSubdirectory("trangatemp").FullName; Log.Debug($"Created temp folder: {tempFolder}"); - Log.Info($"Downloading images: {Chapter}"); + Log.Info($"Downloading images: {chapter}"); int chapterNum = 0; //Download all Images to temporary Folder foreach (string imageUrl in imageUrls) @@ -107,31 +76,22 @@ public class DownloadSingleChapterJob : JobWithDownloading } } - CopyCoverFromCacheToDownloadLocation(Chapter.ParentManga); + CopyCoverFromCacheToDownloadLocation(chapter.ParentManga); - Log.Debug($"Creating ComicInfo.xml {Chapter}"); - File.WriteAllText(Path.Join(tempFolder, "ComicInfo.xml"), Chapter.GetComicInfoXmlString()); + Log.Debug($"Creating ComicInfo.xml {chapter}"); + File.WriteAllText(Path.Join(tempFolder, "ComicInfo.xml"), chapter.GetComicInfoXmlString()); - Log.Debug($"Packaging images to archive {Chapter}"); + Log.Debug($"Packaging images to archive {chapter}"); //ZIP-it and ship-it ZipFile.CreateFromDirectory(tempFolder, saveArchiveFilePath); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) File.SetUnixFileMode(saveArchiveFilePath, UserRead | UserWrite | UserExecute | GroupRead | GroupWrite | GroupExecute | OtherRead | OtherExecute); Directory.Delete(tempFolder, true); //Cleanup - Chapter.Downloaded = true; - context.SaveChanges(); + chapter.Downloaded = true; + DbContext.SaveChanges(); - if (context.Jobs.ToList().Any(j => - { - if (j.JobType != JobType.UpdateChaptersDownloadedJob) - return false; - UpdateChaptersDownloadedJob job = (UpdateChaptersDownloadedJob)j; - return job.MangaId == Chapter.ParentMangaId; - })) - return []; - - return [new UpdateChaptersDownloadedJob(Chapter.ParentManga, 0, this.ParentJob)]; + return []; } private void ProcessImage(string imagePath) diff --git a/API/Workers/MangaDownloadWorkers/DownloadCoverFromMangaconnectorWorker.cs b/API/Workers/MangaDownloadWorkers/DownloadCoverFromMangaconnectorWorker.cs new file mode 100644 index 0000000..2f5e839 --- /dev/null +++ b/API/Workers/MangaDownloadWorkers/DownloadCoverFromMangaconnectorWorker.cs @@ -0,0 +1,26 @@ +using API.Schema.MangaContext; +using API.Schema.MangaContext.MangaConnectors; +using Microsoft.EntityFrameworkCore; + +namespace API.Workers; + +public class DownloadCoverFromMangaconnectorWorker(MangaConnectorId mcId, IServiceScope scope, IEnumerable? dependsOn = null) + : BaseWorkerWithContext(scope, dependsOn) +{ + public MangaConnectorId MangaConnectorId { get; init; } = mcId; + protected override BaseWorker[] DoWorkInternal() + { + MangaConnector mangaConnector = MangaConnectorId.MangaConnector; + Manga manga = MangaConnectorId.Obj; + try + { + manga.CoverFileNameInCache = mangaConnector.SaveCoverImageToCache(MangaConnectorId); + DbContext.SaveChanges(); + } + catch (DbUpdateException e) + { + Log.Error(e); + } + return []; + } +} \ No newline at end of file diff --git a/API/Workers/MangaDownloadWorkers/RetrieveMangaChaptersFromMangaconnectorWorker.cs b/API/Workers/MangaDownloadWorkers/RetrieveMangaChaptersFromMangaconnectorWorker.cs new file mode 100644 index 0000000..c1af2b2 --- /dev/null +++ b/API/Workers/MangaDownloadWorkers/RetrieveMangaChaptersFromMangaconnectorWorker.cs @@ -0,0 +1,39 @@ +using API.Schema.MangaContext; +using API.Schema.MangaContext.MangaConnectors; +using Microsoft.EntityFrameworkCore; + +namespace API.Workers; + +public class RetrieveMangaChaptersFromMangaconnectorWorker(MangaConnectorId mcId, string language, IServiceScope scope, IEnumerable? dependsOn = null) + : BaseWorkerWithContext(scope, dependsOn) +{ + public MangaConnectorId MangaConnectorId { get; init; } = mcId; + protected override BaseWorker[] DoWorkInternal() + { + MangaConnector mangaConnector = MangaConnectorId.MangaConnector; + Manga manga = MangaConnectorId.Obj; + // This gets all chapters that are not downloaded + (Chapter, MangaConnectorId)[] allChapters = + mangaConnector.GetChapters(MangaConnectorId, language).DistinctBy(c => c.Item1.Key).ToArray(); + (Chapter, MangaConnectorId)[] newChapters = allChapters.Where(chapter => + manga.Chapters.Any(ch => chapter.Item1.Key == ch.Key && ch.Downloaded) == false).ToArray(); + Log.Info($"{manga.Chapters.Count} existing + {newChapters.Length} new chapters."); + + try + { + foreach ((Chapter chapter, MangaConnectorId mcId) newChapter in newChapters) + { + manga.Chapters.Add(newChapter.chapter); + DbContext.MangaConnectorToChapter.Add(newChapter.mcId); + } + + DbContext.SaveChanges(); + } + catch (DbUpdateException e) + { + Log.Error(e); + } + + return []; + } +} \ No newline at end of file diff --git a/API/Workers/MoveFileOrFolderWorker.cs b/API/Workers/MoveFileOrFolderWorker.cs new file mode 100644 index 0000000..848e5b3 --- /dev/null +++ b/API/Workers/MoveFileOrFolderWorker.cs @@ -0,0 +1,47 @@ +namespace API.Workers; + +public class MoveFileOrFolderWorker(string toLocation, string fromLocation, IEnumerable? dependsOn = null) + : BaseWorker(dependsOn) +{ + public readonly string FromLocation = fromLocation; + public readonly string ToLocation = toLocation; + + protected override BaseWorker[] DoWorkInternal() + { + try + { + FileInfo fi = new (FromLocation); + if (!fi.Exists) + { + Log.Error($"File does not exist at {FromLocation}"); + return []; + } + + if (File.Exists(ToLocation))//Do not override existing + { + Log.Error($"File already exists at {ToLocation}"); + return []; + } + if(fi.Attributes.HasFlag(FileAttributes.Directory)) + MoveDirectory(fi, ToLocation); + else + MoveFile(fi, ToLocation); + } + catch (Exception e) + { + Log.Error(e); + } + + return []; + } + + private void MoveDirectory(FileInfo from, string toLocation) + { + Directory.Move(from.FullName, toLocation); + } + + private void MoveFile(FileInfo from, string toLocation) + { + File.Move(from.FullName, toLocation); + } +} \ No newline at end of file diff --git a/API/Workers/MoveMangaLibraryWorker.cs b/API/Workers/MoveMangaLibraryWorker.cs new file mode 100644 index 0000000..6205271 --- /dev/null +++ b/API/Workers/MoveMangaLibraryWorker.cs @@ -0,0 +1,25 @@ +using API.Schema.MangaContext; +using Microsoft.EntityFrameworkCore; + +namespace API.Workers; + +public class MoveMangaLibraryWorker(Manga manga, FileLibrary toLibrary, IServiceScope scope, IEnumerable? dependsOn = null) + : BaseWorkerWithContext(scope, dependsOn) +{ + protected override BaseWorker[] DoWorkInternal() + { + Dictionary oldPath = manga.Chapters.ToDictionary(c => c, c => c.FullArchiveFilePath); + manga.Library = toLibrary; + try + { + DbContext.SaveChanges(); + } + catch (DbUpdateException e) + { + Log.Error(e); + return []; + } + + return manga.Chapters.Select(c => new MoveFileOrFolderWorker(c.FullArchiveFilePath, oldPath[c])).ToArray(); + } +} \ No newline at end of file diff --git a/API/Workers/SendNotificationsWorker.cs b/API/Workers/SendNotificationsWorker.cs new file mode 100644 index 0000000..7eba22a --- /dev/null +++ b/API/Workers/SendNotificationsWorker.cs @@ -0,0 +1,15 @@ +using API.Schema.NotificationsContext; + +namespace API.Workers; + +public class SendNotificationsWorker(IServiceScope scope, IEnumerable? dependsOn = null) + : BaseWorkerWithContext(scope, dependsOn), IPeriodic +{ + public DateTime LastExecution { get; set; } = DateTime.UtcNow; + public TimeSpan Interval { get; set; } = TimeSpan.FromMinutes(1); + protected override BaseWorker[] DoWorkInternal() + { + throw new NotImplementedException(); + } + +} \ No newline at end of file