mirror of
https://github.com/C9Glax/tranga.git
synced 2025-04-13 03:43:17 +02:00
Arbitrary Webhook for NotificationConnectors
Backend only deals in REST Webhooks The API has custom Endpoints for Ntfy, Gotify, Lunasea that create pre-formatted Webhooks #297 #259
This commit is contained in:
parent
3a8b400851
commit
022ebe2bcc
@ -1,7 +1,6 @@
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats;
|
||||
|
||||
namespace API;
|
||||
namespace API.APIEndpointRecords;
|
||||
|
||||
public record CoverFormatRequestRecord(Size size)
|
||||
{
|
16
API/APIEndpointRecords/GotifyRecord.cs
Normal file
16
API/APIEndpointRecords/GotifyRecord.cs
Normal file
@ -0,0 +1,16 @@
|
||||
namespace API.APIEndpointRecords;
|
||||
|
||||
public record GotifyRecord(string endpoint, string appToken, int priority)
|
||||
{
|
||||
public bool Validate()
|
||||
{
|
||||
if (endpoint == string.Empty)
|
||||
return false;
|
||||
if (appToken == string.Empty)
|
||||
return false;
|
||||
if (priority < 0 || priority > 10)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
16
API/APIEndpointRecords/LunaseaRecord.cs
Normal file
16
API/APIEndpointRecords/LunaseaRecord.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace API.APIEndpointRecords;
|
||||
|
||||
public record LunaseaRecord(string id)
|
||||
{
|
||||
private static Regex validateRex = new(@"(?:device|user)\/[0-9a-zA-Z\-]+");
|
||||
public bool Validate()
|
||||
{
|
||||
if (id == string.Empty)
|
||||
return false;
|
||||
if (!validateRex.IsMatch(id))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
namespace API;
|
||||
namespace API.APIEndpointRecords;
|
||||
|
||||
public record ModifyJobRecord(ulong? RecurrenceMs, bool? Enabled);
|
17
API/APIEndpointRecords/NtfyRecord.cs
Normal file
17
API/APIEndpointRecords/NtfyRecord.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace API.APIEndpointRecords;
|
||||
|
||||
public record NtfyRecord(string endpoint, string username, string password, string topic, int priority)
|
||||
{
|
||||
public bool Validate()
|
||||
{
|
||||
if (endpoint == string.Empty)
|
||||
return false;
|
||||
if (username == string.Empty)
|
||||
return false;
|
||||
if (password == string.Empty)
|
||||
return false;
|
||||
if (priority < 1 || priority > 5)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using API.Schema;
|
||||
using API.APIEndpointRecords;
|
||||
using API.Schema;
|
||||
using API.Schema.Jobs;
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using API.Schema;
|
||||
using API.APIEndpointRecords;
|
||||
using API.Schema;
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
@ -1,4 +1,6 @@
|
||||
using API.Schema;
|
||||
using System.Text;
|
||||
using API.APIEndpointRecords;
|
||||
using API.Schema;
|
||||
using API.Schema.NotificationConnectors;
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -44,16 +46,21 @@ public class NotificationConnectorController(PgsqlContext context) : Controller
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Notification-Connector
|
||||
/// Creates a new REST-Notification-Connector
|
||||
/// </summary>
|
||||
/// <remarks>Formatting placeholders: "%title" and "%text" can be placed in url, header-values and body and will be replaced when notifications are sent</remarks>
|
||||
/// <param name="notificationConnector">Notification-Connector</param>
|
||||
/// <response code="201"></response>
|
||||
/// <response code="409">A NotificationConnector with name already exists</response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
[HttpPut]
|
||||
[ProducesResponseType<NotificationConnector[]>(Status200OK, "application/json")]
|
||||
[ProducesResponseType(Status201Created)]
|
||||
[ProducesResponseType(Status409Conflict)]
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult CreateConnector([FromBody]NotificationConnector notificationConnector)
|
||||
{
|
||||
if (context.NotificationConnectors.Find(notificationConnector.Name) is not null)
|
||||
return Conflict();
|
||||
try
|
||||
{
|
||||
context.NotificationConnectors.Add(notificationConnector);
|
||||
@ -66,6 +73,91 @@ public class NotificationConnectorController(PgsqlContext context) : Controller
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Gotify-Notification-Connector
|
||||
/// </summary>
|
||||
/// <remarks>Priority needs to be between 0 and 10</remarks>
|
||||
/// <response code="201"></response>
|
||||
/// <response code="400"></response>
|
||||
/// <response code="409">A NotificationConnector with name already exists</response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
[HttpPut("Gotify")]
|
||||
[ProducesResponseType(Status201Created)]
|
||||
[ProducesResponseType(Status400BadRequest)]
|
||||
[ProducesResponseType(Status409Conflict)]
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult CreateGotifyConnector([FromBody]GotifyRecord gotifyData)
|
||||
{
|
||||
if(!gotifyData.Validate())
|
||||
return BadRequest();
|
||||
|
||||
NotificationConnector gotifyConnector = new NotificationConnector(TokenGen.CreateToken("Gotify"),
|
||||
gotifyData.endpoint,
|
||||
new Dictionary<string, string>() { { "X-Gotify-Key", gotifyData.appToken } },
|
||||
"POST",
|
||||
$"{{\"message\": \"%text\", \"title\": \"%title\", \"priority\": {gotifyData.priority}}}");
|
||||
return CreateConnector(gotifyConnector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Ntfy-Notification-Connector
|
||||
/// </summary>
|
||||
/// <remarks>Priority needs to be between 1 and 5</remarks>
|
||||
/// <response code="201"></response>
|
||||
/// <response code="400"></response>
|
||||
/// <response code="409">A NotificationConnector with name already exists</response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
[HttpPut("Ntfy")]
|
||||
[ProducesResponseType(Status201Created)]
|
||||
[ProducesResponseType(Status400BadRequest)]
|
||||
[ProducesResponseType(Status409Conflict)]
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult CreateNtfyConnector([FromBody]NtfyRecord ntfyRecord)
|
||||
{
|
||||
if(!ntfyRecord.Validate())
|
||||
return BadRequest();
|
||||
|
||||
string authHeader = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes($"{ntfyRecord.username}:{ntfyRecord.password}"));
|
||||
string auth = Convert.ToBase64String(Encoding.UTF8.GetBytes(authHeader)).Replace("=","");
|
||||
|
||||
NotificationConnector ntfyConnector = new NotificationConnector(TokenGen.CreateToken("Ntfy"),
|
||||
$"{ntfyRecord.endpoint}?auth={auth}",
|
||||
new Dictionary<string, string>()
|
||||
{
|
||||
{"Title", "%title"},
|
||||
{"Priority", ntfyRecord.priority.ToString()},
|
||||
},
|
||||
"POST",
|
||||
"%text");
|
||||
return CreateConnector(ntfyConnector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Lunasea-Notification-Connector
|
||||
/// </summary>
|
||||
/// <remarks>https://docs.lunasea.app/lunasea/notifications/custom-notifications for id. Either device/:device_id or user/:user_id</remarks>
|
||||
/// <response code="201"></response>
|
||||
/// <response code="400"></response>
|
||||
/// <response code="409">A NotificationConnector with name already exists</response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
[HttpPut("Lunasea")]
|
||||
[ProducesResponseType(Status201Created)]
|
||||
[ProducesResponseType(Status400BadRequest)]
|
||||
[ProducesResponseType(Status409Conflict)]
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult CreateLunaseaConnector([FromBody]LunaseaRecord lunaseaRecord)
|
||||
{
|
||||
if(!lunaseaRecord.Validate())
|
||||
return BadRequest();
|
||||
|
||||
NotificationConnector lunaseaConnector = new NotificationConnector(TokenGen.CreateToken("Lunasea"),
|
||||
$"https://notify.lunasea.app/v1/custom/{lunaseaRecord.id}",
|
||||
new Dictionary<string, string>(),
|
||||
"POST",
|
||||
"{\"title\": \"%title\", \"body\": \"%text\"}");
|
||||
return CreateConnector(lunaseaConnector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the Notification-Connector with the requested ID
|
||||
/// </summary>
|
||||
|
669
API/Migrations/20250307143019_dev-070325-3.Designer.cs
generated
Normal file
669
API/Migrations/20250307143019_dev-070325-3.Designer.cs
generated
Normal file
@ -0,0 +1,669 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using API.Schema;
|
||||
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
|
||||
{
|
||||
[DbContext(typeof(PgsqlContext))]
|
||||
[Migration("20250307143019_dev-070325-3")]
|
||||
partial class dev0703253
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.2")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("API.Schema.Author", b =>
|
||||
{
|
||||
b.Property<string>("AuthorId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("AuthorName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("AuthorId");
|
||||
|
||||
b.ToTable("Authors");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Chapter", b =>
|
||||
{
|
||||
b.Property<string>("ChapterId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("ArchiveFileName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ChapterNumber")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("character varying(10)");
|
||||
|
||||
b.Property<bool>("Downloaded")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("ParentMangaId")
|
||||
.IsRequired()
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int?>("VolumeNumber")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ChapterId");
|
||||
|
||||
b.HasIndex("ParentMangaId");
|
||||
|
||||
b.ToTable("Chapters");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.Job", b =>
|
||||
{
|
||||
b.Property<string>("JobId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.PrimitiveCollection<string[]>("DependsOnJobsIds")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.Property<bool>("Enabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("JobId1")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<byte>("JobType")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.Property<DateTime>("LastExecution")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("ParentJobId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<decimal>("RecurrenceMs")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<byte>("state")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.HasKey("JobId");
|
||||
|
||||
b.HasIndex("JobId1");
|
||||
|
||||
b.HasIndex("ParentJobId");
|
||||
|
||||
b.ToTable("Jobs");
|
||||
|
||||
b.HasDiscriminator<byte>("JobType");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.LibraryConnectors.LibraryConnector", b =>
|
||||
{
|
||||
b.Property<string>("LibraryConnectorId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Auth")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("BaseUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<byte>("LibraryType")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.HasKey("LibraryConnectorId");
|
||||
|
||||
b.ToTable("LibraryConnectors");
|
||||
|
||||
b.HasDiscriminator<byte>("LibraryType");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Link", b =>
|
||||
{
|
||||
b.Property<string>("LinkId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("LinkProvider")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("LinkUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasKey("LinkId");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("Link");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Manga", b =>
|
||||
{
|
||||
b.Property<string>("MangaId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("ConnectorId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("CoverFileNameInCache")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("CoverUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("FolderName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<float>("IgnoreChapterBefore")
|
||||
.HasColumnType("real");
|
||||
|
||||
b.Property<string>("MangaConnectorId")
|
||||
.IsRequired()
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("OriginalLanguage")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<byte>("ReleaseStatus")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.Property<string>("WebsiteUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long>("Year")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("MangaId");
|
||||
|
||||
b.HasIndex("MangaConnectorId");
|
||||
|
||||
b.ToTable("Manga");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaAltTitle", b =>
|
||||
{
|
||||
b.Property<string>("AltTitleId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Language")
|
||||
.IsRequired()
|
||||
.HasMaxLength(8)
|
||||
.HasColumnType("character varying(8)");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("AltTitleId");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("AltTitles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b =>
|
||||
{
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.PrimitiveCollection<string[]>("BaseUris")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.Property<bool>("Enabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.PrimitiveCollection<string[]>("SupportedLanguages")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.HasKey("Name");
|
||||
|
||||
b.ToTable("MangaConnectors");
|
||||
|
||||
b.HasDiscriminator<string>("Name").HasValue("MangaConnector");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaTag", b =>
|
||||
{
|
||||
b.Property<string>("Tag")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Tag");
|
||||
|
||||
b.ToTable("Tags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Notification", b =>
|
||||
{
|
||||
b.Property<string>("NotificationId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<byte>("Urgency")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.HasKey("NotificationId");
|
||||
|
||||
b.ToTable("Notifications");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.NotificationConnectors.NotificationConnector", b =>
|
||||
{
|
||||
b.Property<string>("NotificationConnectorId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Body")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Dictionary<string, string>>("Headers")
|
||||
.IsRequired()
|
||||
.HasColumnType("hstore");
|
||||
|
||||
b.Property<string>("HttpMethod")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("NotificationConnectorId");
|
||||
|
||||
b.ToTable("NotificationConnectors");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AuthorManga", b =>
|
||||
{
|
||||
b.Property<string>("AuthorsAuthorId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasKey("AuthorsAuthorId", "MangaId");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("AuthorManga");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MangaMangaTag", b =>
|
||||
{
|
||||
b.Property<string>("MangaId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("TagsTag")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("MangaId", "TagsTag");
|
||||
|
||||
b.HasIndex("TagsTag");
|
||||
|
||||
b.ToTable("MangaMangaTag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.Jobs.Job");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("Jobs", t =>
|
||||
{
|
||||
t.Property("MangaId")
|
||||
.HasColumnName("DownloadMangaCoverJob_MangaId");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)4);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.DownloadNewChaptersJob", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.Jobs.Job");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)1);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.Jobs.Job");
|
||||
|
||||
b.Property<string>("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<string>("FromLocation")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ToLocation")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)3);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.UpdateMetadataJob", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.Jobs.Job");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("Jobs", t =>
|
||||
{
|
||||
t.Property("MangaId")
|
||||
.HasColumnName("UpdateMetadataJob_MangaId");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)2);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.AsuraToon", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("AsuraToon");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.Bato", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("Bato");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("MangaDex");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.MangaHere", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("MangaHere");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.MangaKatana", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("MangaKatana");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.Mangaworld", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("Mangaworld");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.ManhuaPlus", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("ManhuaPlus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.Weebcentral", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("Weebcentral");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Chapter", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", "ParentManga")
|
||||
.WithMany()
|
||||
.HasForeignKey("ParentMangaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ParentManga");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.Job", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Jobs.Job", null)
|
||||
.WithMany("DependsOnJobs")
|
||||
.HasForeignKey("JobId1");
|
||||
|
||||
b.HasOne("API.Schema.Jobs.Job", "ParentJob")
|
||||
.WithMany()
|
||||
.HasForeignKey("ParentJobId");
|
||||
|
||||
b.Navigation("ParentJob");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Link", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", null)
|
||||
.WithMany("Links")
|
||||
.HasForeignKey("MangaId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Manga", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector")
|
||||
.WithMany()
|
||||
.HasForeignKey("MangaConnectorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("MangaConnector");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaAltTitle", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", null)
|
||||
.WithMany("AltTitles")
|
||||
.HasForeignKey("MangaId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AuthorManga", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Author", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("AuthorsAuthorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("API.Schema.Manga", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("MangaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MangaMangaTag", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("MangaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("API.Schema.MangaTag", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("TagsTag")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
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.DownloadNewChaptersJob", 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.UpdateMetadataJob", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", "Manga")
|
||||
.WithMany()
|
||||
.HasForeignKey("MangaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Manga");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.Job", b =>
|
||||
{
|
||||
b.Navigation("DependsOnJobs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Manga", b =>
|
||||
{
|
||||
b.Navigation("AltTitles");
|
||||
|
||||
b.Navigation("Links");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
139
API/Migrations/20250307143019_dev-070325-3.cs
Normal file
139
API/Migrations/20250307143019_dev-070325-3.cs
Normal file
@ -0,0 +1,139 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace API.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class dev0703253 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "AppToken",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Auth",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Endpoint",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Id",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "NotificationConnectorType",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Ntfy_Endpoint",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Topic",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.AlterDatabase()
|
||||
.Annotation("Npgsql:PostgresExtension:hstore", ",,");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Body",
|
||||
table: "NotificationConnectors",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<Dictionary<string, string>>(
|
||||
name: "Headers",
|
||||
table: "NotificationConnectors",
|
||||
type: "hstore",
|
||||
nullable: false);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "HttpMethod",
|
||||
table: "NotificationConnectors",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Url",
|
||||
table: "NotificationConnectors",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Body",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Headers",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "HttpMethod",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Url",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.AlterDatabase()
|
||||
.OldAnnotation("Npgsql:PostgresExtension:hstore", ",,");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "AppToken",
|
||||
table: "NotificationConnectors",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Auth",
|
||||
table: "NotificationConnectors",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Endpoint",
|
||||
table: "NotificationConnectors",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Id",
|
||||
table: "NotificationConnectors",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<byte>(
|
||||
name: "NotificationConnectorType",
|
||||
table: "NotificationConnectors",
|
||||
type: "smallint",
|
||||
nullable: false,
|
||||
defaultValue: (byte)0);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Ntfy_Endpoint",
|
||||
table: "NotificationConnectors",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Topic",
|
||||
table: "NotificationConnectors",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
673
API/Migrations/20250307143254_dev-070325-4.Designer.cs
generated
Normal file
673
API/Migrations/20250307143254_dev-070325-4.Designer.cs
generated
Normal file
@ -0,0 +1,673 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using API.Schema;
|
||||
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
|
||||
{
|
||||
[DbContext(typeof(PgsqlContext))]
|
||||
[Migration("20250307143254_dev-070325-4")]
|
||||
partial class dev0703254
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.2")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("API.Schema.Author", b =>
|
||||
{
|
||||
b.Property<string>("AuthorId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("AuthorName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("AuthorId");
|
||||
|
||||
b.ToTable("Authors");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Chapter", b =>
|
||||
{
|
||||
b.Property<string>("ChapterId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("ArchiveFileName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ChapterNumber")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("character varying(10)");
|
||||
|
||||
b.Property<bool>("Downloaded")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("ParentMangaId")
|
||||
.IsRequired()
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int?>("VolumeNumber")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ChapterId");
|
||||
|
||||
b.HasIndex("ParentMangaId");
|
||||
|
||||
b.ToTable("Chapters");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.Job", b =>
|
||||
{
|
||||
b.Property<string>("JobId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.PrimitiveCollection<string[]>("DependsOnJobsIds")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.Property<bool>("Enabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("JobId1")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<byte>("JobType")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.Property<DateTime>("LastExecution")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("ParentJobId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<decimal>("RecurrenceMs")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<byte>("state")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.HasKey("JobId");
|
||||
|
||||
b.HasIndex("JobId1");
|
||||
|
||||
b.HasIndex("ParentJobId");
|
||||
|
||||
b.ToTable("Jobs");
|
||||
|
||||
b.HasDiscriminator<byte>("JobType");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.LibraryConnectors.LibraryConnector", b =>
|
||||
{
|
||||
b.Property<string>("LibraryConnectorId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Auth")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("BaseUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<byte>("LibraryType")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.HasKey("LibraryConnectorId");
|
||||
|
||||
b.ToTable("LibraryConnectors");
|
||||
|
||||
b.HasDiscriminator<byte>("LibraryType");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Link", b =>
|
||||
{
|
||||
b.Property<string>("LinkId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("LinkProvider")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("LinkUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasKey("LinkId");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("Link");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Manga", b =>
|
||||
{
|
||||
b.Property<string>("MangaId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("ConnectorId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("CoverFileNameInCache")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("CoverUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("FolderName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<float>("IgnoreChapterBefore")
|
||||
.HasColumnType("real");
|
||||
|
||||
b.Property<string>("MangaConnectorId")
|
||||
.IsRequired()
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("OriginalLanguage")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<byte>("ReleaseStatus")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.Property<string>("WebsiteUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long>("Year")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("MangaId");
|
||||
|
||||
b.HasIndex("MangaConnectorId");
|
||||
|
||||
b.ToTable("Manga");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaAltTitle", b =>
|
||||
{
|
||||
b.Property<string>("AltTitleId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Language")
|
||||
.IsRequired()
|
||||
.HasMaxLength(8)
|
||||
.HasColumnType("character varying(8)");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("AltTitleId");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("AltTitles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b =>
|
||||
{
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.PrimitiveCollection<string[]>("BaseUris")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.Property<bool>("Enabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.PrimitiveCollection<string[]>("SupportedLanguages")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.HasKey("Name");
|
||||
|
||||
b.ToTable("MangaConnectors");
|
||||
|
||||
b.HasDiscriminator<string>("Name").HasValue("MangaConnector");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaTag", b =>
|
||||
{
|
||||
b.Property<string>("Tag")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Tag");
|
||||
|
||||
b.ToTable("Tags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Notification", b =>
|
||||
{
|
||||
b.Property<string>("NotificationId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<byte>("Urgency")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.HasKey("NotificationId");
|
||||
|
||||
b.ToTable("Notifications");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.NotificationConnectors.NotificationConnector", b =>
|
||||
{
|
||||
b.Property<string>("NotificationConnectorId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Body")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Dictionary<string, string>>("Headers")
|
||||
.IsRequired()
|
||||
.HasColumnType("hstore");
|
||||
|
||||
b.Property<string>("HttpMethod")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("NotificationConnectorId");
|
||||
|
||||
b.ToTable("NotificationConnectors");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AuthorManga", b =>
|
||||
{
|
||||
b.Property<string>("AuthorsAuthorId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasKey("AuthorsAuthorId", "MangaId");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("AuthorManga");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MangaMangaTag", b =>
|
||||
{
|
||||
b.Property<string>("MangaId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("TagsTag")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("MangaId", "TagsTag");
|
||||
|
||||
b.HasIndex("TagsTag");
|
||||
|
||||
b.ToTable("MangaMangaTag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.Jobs.Job");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("Jobs", t =>
|
||||
{
|
||||
t.Property("MangaId")
|
||||
.HasColumnName("DownloadMangaCoverJob_MangaId");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)4);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.DownloadNewChaptersJob", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.Jobs.Job");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)1);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.Jobs.Job");
|
||||
|
||||
b.Property<string>("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<string>("FromLocation")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ToLocation")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)3);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.UpdateMetadataJob", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.Jobs.Job");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("Jobs", t =>
|
||||
{
|
||||
t.Property("MangaId")
|
||||
.HasColumnName("UpdateMetadataJob_MangaId");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)2);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.AsuraToon", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("AsuraToon");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.Bato", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("Bato");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("MangaDex");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.MangaHere", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("MangaHere");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.MangaKatana", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("MangaKatana");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.Mangaworld", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("Mangaworld");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.ManhuaPlus", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("ManhuaPlus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.Weebcentral", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("Weebcentral");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Chapter", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", "ParentManga")
|
||||
.WithMany()
|
||||
.HasForeignKey("ParentMangaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ParentManga");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.Job", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Jobs.Job", null)
|
||||
.WithMany("DependsOnJobs")
|
||||
.HasForeignKey("JobId1");
|
||||
|
||||
b.HasOne("API.Schema.Jobs.Job", "ParentJob")
|
||||
.WithMany()
|
||||
.HasForeignKey("ParentJobId");
|
||||
|
||||
b.Navigation("ParentJob");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Link", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", null)
|
||||
.WithMany("Links")
|
||||
.HasForeignKey("MangaId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Manga", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector")
|
||||
.WithMany()
|
||||
.HasForeignKey("MangaConnectorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("MangaConnector");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaAltTitle", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", null)
|
||||
.WithMany("AltTitles")
|
||||
.HasForeignKey("MangaId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AuthorManga", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Author", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("AuthorsAuthorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("API.Schema.Manga", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("MangaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MangaMangaTag", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("MangaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("API.Schema.MangaTag", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("TagsTag")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
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.DownloadNewChaptersJob", 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.UpdateMetadataJob", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", "Manga")
|
||||
.WithMany()
|
||||
.HasForeignKey("MangaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Manga");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.Job", b =>
|
||||
{
|
||||
b.Navigation("DependsOnJobs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Manga", b =>
|
||||
{
|
||||
b.Navigation("AltTitles");
|
||||
|
||||
b.Navigation("Links");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
29
API/Migrations/20250307143254_dev-070325-4.cs
Normal file
29
API/Migrations/20250307143254_dev-070325-4.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace API.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class dev0703254 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Name",
|
||||
table: "NotificationConnectors",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Name",
|
||||
table: "NotificationConnectors");
|
||||
}
|
||||
}
|
||||
}
|
669
API/Migrations/20250307143442_dev-070325-5.Designer.cs
generated
Normal file
669
API/Migrations/20250307143442_dev-070325-5.Designer.cs
generated
Normal file
@ -0,0 +1,669 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using API.Schema;
|
||||
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
|
||||
{
|
||||
[DbContext(typeof(PgsqlContext))]
|
||||
[Migration("20250307143442_dev-070325-5")]
|
||||
partial class dev0703255
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.2")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("API.Schema.Author", b =>
|
||||
{
|
||||
b.Property<string>("AuthorId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("AuthorName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("AuthorId");
|
||||
|
||||
b.ToTable("Authors");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Chapter", b =>
|
||||
{
|
||||
b.Property<string>("ChapterId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("ArchiveFileName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ChapterNumber")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("character varying(10)");
|
||||
|
||||
b.Property<bool>("Downloaded")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("ParentMangaId")
|
||||
.IsRequired()
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int?>("VolumeNumber")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("ChapterId");
|
||||
|
||||
b.HasIndex("ParentMangaId");
|
||||
|
||||
b.ToTable("Chapters");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.Job", b =>
|
||||
{
|
||||
b.Property<string>("JobId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.PrimitiveCollection<string[]>("DependsOnJobsIds")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.Property<bool>("Enabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("JobId1")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<byte>("JobType")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.Property<DateTime>("LastExecution")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("ParentJobId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<decimal>("RecurrenceMs")
|
||||
.HasColumnType("numeric(20,0)");
|
||||
|
||||
b.Property<byte>("state")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.HasKey("JobId");
|
||||
|
||||
b.HasIndex("JobId1");
|
||||
|
||||
b.HasIndex("ParentJobId");
|
||||
|
||||
b.ToTable("Jobs");
|
||||
|
||||
b.HasDiscriminator<byte>("JobType");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.LibraryConnectors.LibraryConnector", b =>
|
||||
{
|
||||
b.Property<string>("LibraryConnectorId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Auth")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("BaseUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<byte>("LibraryType")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.HasKey("LibraryConnectorId");
|
||||
|
||||
b.ToTable("LibraryConnectors");
|
||||
|
||||
b.HasDiscriminator<byte>("LibraryType");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Link", b =>
|
||||
{
|
||||
b.Property<string>("LinkId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("LinkProvider")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("LinkUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasKey("LinkId");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("Link");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Manga", b =>
|
||||
{
|
||||
b.Property<string>("MangaId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("ConnectorId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("CoverFileNameInCache")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("CoverUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("FolderName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<float>("IgnoreChapterBefore")
|
||||
.HasColumnType("real");
|
||||
|
||||
b.Property<string>("MangaConnectorId")
|
||||
.IsRequired()
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("OriginalLanguage")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<byte>("ReleaseStatus")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.Property<string>("WebsiteUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<long>("Year")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("MangaId");
|
||||
|
||||
b.HasIndex("MangaConnectorId");
|
||||
|
||||
b.ToTable("Manga");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaAltTitle", b =>
|
||||
{
|
||||
b.Property<string>("AltTitleId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Language")
|
||||
.IsRequired()
|
||||
.HasMaxLength(8)
|
||||
.HasColumnType("character varying(8)");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("AltTitleId");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("AltTitles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.MangaConnector", b =>
|
||||
{
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.PrimitiveCollection<string[]>("BaseUris")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.Property<bool>("Enabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.PrimitiveCollection<string[]>("SupportedLanguages")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.HasKey("Name");
|
||||
|
||||
b.ToTable("MangaConnectors");
|
||||
|
||||
b.HasDiscriminator<string>("Name").HasValue("MangaConnector");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaTag", b =>
|
||||
{
|
||||
b.Property<string>("Tag")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Tag");
|
||||
|
||||
b.ToTable("Tags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Notification", b =>
|
||||
{
|
||||
b.Property<string>("NotificationId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<byte>("Urgency")
|
||||
.HasColumnType("smallint");
|
||||
|
||||
b.HasKey("NotificationId");
|
||||
|
||||
b.ToTable("Notifications");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.NotificationConnectors.NotificationConnector", b =>
|
||||
{
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Body")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Dictionary<string, string>>("Headers")
|
||||
.IsRequired()
|
||||
.HasColumnType("hstore");
|
||||
|
||||
b.Property<string>("HttpMethod")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Name");
|
||||
|
||||
b.ToTable("NotificationConnectors");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AuthorManga", b =>
|
||||
{
|
||||
b.Property<string>("AuthorsAuthorId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasKey("AuthorsAuthorId", "MangaId");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("AuthorManga");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MangaMangaTag", b =>
|
||||
{
|
||||
b.Property<string>("MangaId")
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("TagsTag")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("MangaId", "TagsTag");
|
||||
|
||||
b.HasIndex("TagsTag");
|
||||
|
||||
b.ToTable("MangaMangaTag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.DownloadMangaCoverJob", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.Jobs.Job");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("Jobs", t =>
|
||||
{
|
||||
t.Property("MangaId")
|
||||
.HasColumnName("DownloadMangaCoverJob_MangaId");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)4);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.DownloadNewChaptersJob", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.Jobs.Job");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)1);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.DownloadSingleChapterJob", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.Jobs.Job");
|
||||
|
||||
b.Property<string>("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<string>("FromLocation")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ToLocation")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)3);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.UpdateMetadataJob", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.Jobs.Job");
|
||||
|
||||
b.Property<string>("MangaId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.HasIndex("MangaId");
|
||||
|
||||
b.ToTable("Jobs", t =>
|
||||
{
|
||||
t.Property("MangaId")
|
||||
.HasColumnName("UpdateMetadataJob_MangaId");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)2);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.AsuraToon", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("AsuraToon");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.Bato", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("Bato");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.MangaDex", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("MangaDex");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.MangaHere", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("MangaHere");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.MangaKatana", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("MangaKatana");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.Mangaworld", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("Mangaworld");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.ManhuaPlus", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("ManhuaPlus");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaConnectors.Weebcentral", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.MangaConnectors.MangaConnector");
|
||||
|
||||
b.HasDiscriminator().HasValue("Weebcentral");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Chapter", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", "ParentManga")
|
||||
.WithMany()
|
||||
.HasForeignKey("ParentMangaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ParentManga");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.Job", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Jobs.Job", null)
|
||||
.WithMany("DependsOnJobs")
|
||||
.HasForeignKey("JobId1");
|
||||
|
||||
b.HasOne("API.Schema.Jobs.Job", "ParentJob")
|
||||
.WithMany()
|
||||
.HasForeignKey("ParentJobId");
|
||||
|
||||
b.Navigation("ParentJob");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Link", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", null)
|
||||
.WithMany("Links")
|
||||
.HasForeignKey("MangaId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Manga", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.MangaConnectors.MangaConnector", "MangaConnector")
|
||||
.WithMany()
|
||||
.HasForeignKey("MangaConnectorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("MangaConnector");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.MangaAltTitle", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", null)
|
||||
.WithMany("AltTitles")
|
||||
.HasForeignKey("MangaId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AuthorManga", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Author", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("AuthorsAuthorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("API.Schema.Manga", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("MangaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MangaMangaTag", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("MangaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("API.Schema.MangaTag", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("TagsTag")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
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.DownloadNewChaptersJob", 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.UpdateMetadataJob", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", "Manga")
|
||||
.WithMany()
|
||||
.HasForeignKey("MangaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Manga");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Jobs.Job", b =>
|
||||
{
|
||||
b.Navigation("DependsOnJobs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Manga", b =>
|
||||
{
|
||||
b.Navigation("AltTitles");
|
||||
|
||||
b.Navigation("Links");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
66
API/Migrations/20250307143442_dev-070325-5.cs
Normal file
66
API/Migrations/20250307143442_dev-070325-5.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace API.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class dev0703255 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_NotificationConnectors",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "NotificationConnectorId",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Name",
|
||||
table: "NotificationConnectors",
|
||||
type: "character varying(64)",
|
||||
maxLength: 64,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_NotificationConnectors",
|
||||
table: "NotificationConnectors",
|
||||
column: "Name");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_NotificationConnectors",
|
||||
table: "NotificationConnectors");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Name",
|
||||
table: "NotificationConnectors",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(64)",
|
||||
oldMaxLength: 64);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "NotificationConnectorId",
|
||||
table: "NotificationConnectors",
|
||||
type: "character varying(64)",
|
||||
maxLength: 64,
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_NotificationConnectors",
|
||||
table: "NotificationConnectors",
|
||||
column: "NotificationConnectorId");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using API.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
@ -20,6 +21,7 @@ namespace API.Migrations
|
||||
.HasAnnotation("ProductVersion", "9.0.2")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("API.Schema.Author", b =>
|
||||
@ -316,20 +318,29 @@ namespace API.Migrations
|
||||
|
||||
modelBuilder.Entity("API.Schema.NotificationConnectors.NotificationConnector", b =>
|
||||
{
|
||||
b.Property<string>("NotificationConnectorId")
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<byte>("NotificationConnectorType")
|
||||
.HasColumnType("smallint");
|
||||
b.Property<string>("Body")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("NotificationConnectorId");
|
||||
b.Property<Dictionary<string, string>>("Headers")
|
||||
.IsRequired()
|
||||
.HasColumnType("hstore");
|
||||
|
||||
b.Property<string>("HttpMethod")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Name");
|
||||
|
||||
b.ToTable("NotificationConnectors");
|
||||
|
||||
b.HasDiscriminator<byte>("NotificationConnectorType");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AuthorManga", b =>
|
||||
@ -515,57 +526,6 @@ namespace API.Migrations
|
||||
b.HasDiscriminator().HasValue("Weebcentral");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.NotificationConnectors.Gotify", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.NotificationConnectors.NotificationConnector");
|
||||
|
||||
b.Property<string>("AppToken")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Endpoint")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)0);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.NotificationConnectors.Lunasea", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.NotificationConnectors.NotificationConnector");
|
||||
|
||||
b.Property<string>("Id")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)1);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.NotificationConnectors.Ntfy", b =>
|
||||
{
|
||||
b.HasBaseType("API.Schema.NotificationConnectors.NotificationConnector");
|
||||
|
||||
b.Property<string>("Auth")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Endpoint")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Topic")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.ToTable("NotificationConnectors", t =>
|
||||
{
|
||||
t.Property("Endpoint")
|
||||
.HasColumnName("Ntfy_Endpoint");
|
||||
});
|
||||
|
||||
b.HasDiscriminator().HasValue((byte)2);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("API.Schema.Chapter", b =>
|
||||
{
|
||||
b.HasOne("API.Schema.Manga", "ParentManga")
|
||||
|
@ -1,42 +0,0 @@
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace API.Schema.NotificationConnectors;
|
||||
|
||||
public class Gotify(string endpoint, string appToken)
|
||||
: NotificationConnector(TokenGen.CreateToken(typeof(Gotify), endpoint), NotificationConnectorType.Gotify)
|
||||
{
|
||||
public string Endpoint { get; init; } = endpoint;
|
||||
public string AppToken { get; init; } = appToken;
|
||||
|
||||
public override void SendNotification(string title, string notificationText)
|
||||
{
|
||||
MessageData message = new(title, notificationText);
|
||||
HttpRequestMessage request = new(HttpMethod.Post, $"{endpoint}/message");
|
||||
request.Headers.Add("X-Gotify-Key", this.AppToken);
|
||||
request.Content = new StringContent(JsonConvert.SerializeObject(message, Formatting.None), Encoding.UTF8, "application/json");
|
||||
HttpResponseMessage response = _client.Send(request);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
StreamReader sr = new (response.Content.ReadAsStream());
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
|
||||
private class MessageData
|
||||
{
|
||||
// ReSharper disable four times UnusedAutoPropertyAccessor.Local
|
||||
public string message { get; }
|
||||
public long priority { get; }
|
||||
public string title { get; }
|
||||
public Dictionary<string, object> extras { get; }
|
||||
|
||||
public MessageData(string title, string message)
|
||||
{
|
||||
this.title = title;
|
||||
this.message = message;
|
||||
this.extras = new();
|
||||
this.priority = 4;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace API.Schema.NotificationConnectors;
|
||||
|
||||
public class Lunasea(string id)
|
||||
: NotificationConnector(TokenGen.CreateToken(typeof(Lunasea), id), NotificationConnectorType.LunaSea)
|
||||
{
|
||||
public string Id { get; init; } = id;
|
||||
public override void SendNotification(string title, string notificationText)
|
||||
{
|
||||
MessageData message = new(title, notificationText);
|
||||
HttpRequestMessage request = new(HttpMethod.Post, $"https://notify.lunasea.app/v1/custom/{id}");
|
||||
request.Content = new StringContent(JsonConvert.SerializeObject(message, Formatting.None), Encoding.UTF8, "application/json");
|
||||
HttpResponseMessage response = _client.Send(request);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
StreamReader sr = new (response.Content.ReadAsStream());
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
|
||||
private class MessageData
|
||||
{
|
||||
// ReSharper disable twice UnusedAutoPropertyAccessor.Local
|
||||
public string title { get; }
|
||||
public string body { get; }
|
||||
|
||||
public MessageData(string title, string body)
|
||||
{
|
||||
this.title = title;
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +1,65 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace API.Schema.NotificationConnectors;
|
||||
|
||||
[PrimaryKey("NotificationConnectorId")]
|
||||
public abstract class NotificationConnector(string notificationConnectorId, NotificationConnectorType notificationConnectorType)
|
||||
[PrimaryKey("Name")]
|
||||
public class NotificationConnector(string name, string url, Dictionary<string, string> headers, string httpMethod, string body)
|
||||
{
|
||||
[MaxLength(64)]
|
||||
public string NotificationConnectorId { get; } = notificationConnectorId;
|
||||
public NotificationConnectorType NotificationConnectorType { get; init; } = notificationConnectorType;
|
||||
public string Name { get; init; } = name;
|
||||
|
||||
public string Url { get; internal set; } = url;
|
||||
|
||||
public Dictionary<string, string> Headers { get; internal set; } = headers;
|
||||
|
||||
public string HttpMethod { get; internal set; } = httpMethod;
|
||||
|
||||
public string Body { get; internal set; } = body;
|
||||
|
||||
[JsonIgnore]
|
||||
[NotMapped]
|
||||
protected readonly HttpClient _client = new();
|
||||
|
||||
public abstract void SendNotification(string title, string notificationText);
|
||||
private readonly HttpClient Client = new()
|
||||
{
|
||||
DefaultRequestHeaders = { { "User-Agent", TrangaSettings.userAgent } }
|
||||
};
|
||||
|
||||
public void SendNotification(string title, string notificationText)
|
||||
{
|
||||
CustomWebhookFormatProvider formatProvider = new CustomWebhookFormatProvider(title, notificationText);
|
||||
string formattedUrl = string.Format(formatProvider, Url);
|
||||
string formattedBody = string.Format(formatProvider, Body, title, notificationText);
|
||||
Dictionary<string, string> formattedHeaders = Headers.ToDictionary(h => h.Key,
|
||||
h => string.Format(formatProvider, h.Value, title, notificationText));
|
||||
|
||||
HttpRequestMessage request = new(System.Net.Http.HttpMethod.Parse(HttpMethod), formattedUrl);
|
||||
foreach (var (key, value) in formattedHeaders)
|
||||
request.Headers.Add(key, value);
|
||||
request.Content = new StringContent(formattedBody);
|
||||
|
||||
HttpResponseMessage response = Client.Send(request);
|
||||
}
|
||||
|
||||
private class CustomWebhookFormatProvider(string title, string text) : IFormatProvider
|
||||
{
|
||||
public object? GetFormat(Type? formatType)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public string Format(string fmt, object arg, IFormatProvider provider)
|
||||
{
|
||||
if(arg.GetType() != typeof(string))
|
||||
return arg.ToString() ?? string.Empty;
|
||||
|
||||
StringBuilder sb = new StringBuilder(fmt);
|
||||
sb.Replace("%title", title);
|
||||
sb.Replace("%text", text);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace API.Schema.NotificationConnectors;
|
||||
|
||||
|
||||
public enum NotificationConnectorType : byte
|
||||
{
|
||||
Gotify = 0,
|
||||
LunaSea = 1,
|
||||
Ntfy = 2
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace API.Schema.NotificationConnectors;
|
||||
|
||||
public class Ntfy : NotificationConnector
|
||||
{
|
||||
private NotificationConnector _notificationConnectorImplementation;
|
||||
public string Endpoint { get; init; }
|
||||
public string Auth { get; init; }
|
||||
public string Topic { get; init; }
|
||||
|
||||
public Ntfy(string endpoint, string auth, string topic): base(TokenGen.CreateToken(typeof(Ntfy), endpoint), NotificationConnectorType.Ntfy)
|
||||
{
|
||||
Endpoint = endpoint;
|
||||
Auth = auth;
|
||||
Topic = topic;
|
||||
}
|
||||
|
||||
public Ntfy(string endpoint, string username, string password, string? topic = null) :
|
||||
this(EndpointAndTopicFromUrl(endpoint)[0], topic??EndpointAndTopicFromUrl(endpoint)[1], AuthFromUsernamePassword(username, password))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private static string AuthFromUsernamePassword(string username, string password)
|
||||
{
|
||||
string authHeader = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}"));
|
||||
string authParam = Convert.ToBase64String(Encoding.UTF8.GetBytes(authHeader)).Replace("=","");
|
||||
return authParam;
|
||||
}
|
||||
|
||||
private static string[] EndpointAndTopicFromUrl(string url)
|
||||
{
|
||||
string[] ret = new string[2];
|
||||
Regex rootUriRex = new(@"(https?:\/\/[a-zA-Z0-9-\.]+\.[a-zA-Z0-9]+)(?:\/([a-zA-Z0-9-\.]+))?.*");
|
||||
Match match = rootUriRex.Match(url);
|
||||
if(!match.Success)
|
||||
throw new ArgumentException($"Error getting URI from provided endpoint-URI: {url}");
|
||||
|
||||
ret[0] = match.Groups[1].Value;
|
||||
ret[1] = match.Groups[2].Success && match.Groups[2].Value.Length > 0 ? match.Groups[2].Value : "tranga";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override void SendNotification(string title, string notificationText)
|
||||
{
|
||||
MessageData message = new(title, Topic, notificationText);
|
||||
HttpRequestMessage request = new(HttpMethod.Post, $"{this.Endpoint}?auth={this.Auth}");
|
||||
request.Content = new StringContent(JsonConvert.SerializeObject(message, Formatting.None), Encoding.UTF8, "application/json");
|
||||
HttpResponseMessage response = _client.Send(request);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
StreamReader sr = new (response.Content.ReadAsStream());
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
|
||||
private class MessageData
|
||||
{
|
||||
// ReSharper disable UnusedAutoPropertyAccessor.Local
|
||||
public string topic { get; }
|
||||
public string title { get; }
|
||||
public string message { get; }
|
||||
public int priority { get; }
|
||||
|
||||
public MessageData(string title, string topic, string message)
|
||||
{
|
||||
this.topic = topic;
|
||||
this.title = title;
|
||||
this.message = message;
|
||||
this.priority = 3;
|
||||
}
|
||||
}
|
||||
}
|
@ -36,11 +36,6 @@ public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(op
|
||||
.HasDiscriminator<LibraryType>(l => l.LibraryType)
|
||||
.HasValue<Komga>(LibraryType.Komga)
|
||||
.HasValue<Kavita>(LibraryType.Kavita);
|
||||
modelBuilder.Entity<NotificationConnector>()
|
||||
.HasDiscriminator<NotificationConnectorType>(n => n.NotificationConnectorType)
|
||||
.HasValue<Gotify>(NotificationConnectorType.Gotify)
|
||||
.HasValue<Ntfy>(NotificationConnectorType.Ntfy)
|
||||
.HasValue<Lunasea>(NotificationConnectorType.LunaSea);
|
||||
|
||||
modelBuilder.Entity<Job>()
|
||||
.HasDiscriminator<JobType>(j => j.JobType)
|
||||
|
Loading…
x
Reference in New Issue
Block a user