Compare commits

...

6 Commits

Author SHA1 Message Date
Kleidukos b3102c2660 Migration files 2026-05-23 16:27:54 +02:00
Kleidukos 6b5c5d0d3b Some changes and missing classes on last commit
- Program.cs updated to services and init database
2026-05-23 16:26:25 +02:00
Kleidukos adbc3a28d6 Services for scraping data from TCGdex 2026-05-23 16:24:51 +02:00
Kleidukos f71283d617 Created models forTCGdex Service to scrape data 2026-05-23 16:24:20 +02:00
Kleidukos ca78d6ace4 Setup DbContext 2026-05-23 16:23:18 +02:00
Kleidukos 400faa2fc3 Created entities for database 2026-05-23 16:22:52 +02:00
45 changed files with 4360 additions and 14 deletions
+171
View File
@@ -0,0 +1,171 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using OakArchive.Entities.CardMarket;
using OakArchive.Entities.Cards;
using OakArchive.Entities.Collection;
using OakArchive.Entities.Grading;
using OakArchive.Entities.Serie;
using OakArchive.Entities.Set;
using OakArchive.Entities.TCGdex;
using OakArchive.Entities.User;
namespace OakArchive.Database;
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Settings> Settings { get; set; } = null!;
public DbSet<Collection> Collections { get; set; } = null!;
public DbSet<CollectedCard> CollectedCards { get; set; } = null!;
public DbSet<Grading> Gradings { get; set; } = null!;
public DbSet<TcgDexCardInfo> TcgDexCardInfos { get; set; } = null!;
public DbSet<TcgDexSetInfo> TcgDexSetInfos { get; set; } = null!;
public DbSet<TcgDexSeriesInfo> TcgDexSeriesInfos { get; set; } = null!;
public DbSet<Serie> Series { get; set; } = null!;
public DbSet<Set> Sets { get; set; } = null!;
public DbSet<Legal> Legals { get; set; } = null!;
public DbSet<CardCount> CardCounts { get; set; } = null!;
public DbSet<Card> Cards { get; set; } = null!;
public DbSet<Attack> Attacks { get; set; } = null!;
public DbSet<Weakness> Weaknesses { get; set; } = null!;
public DbSet<CardMarketSetInfo> CardMarketSetInfos { get; set; } = null!;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 1. Basis-Mapping für ASP.NET Core Identity (Pflicht!)
base.OnModelCreating(modelBuilder);
#region User & Settings
modelBuilder.Entity<ApplicationUser>(entity =>
{
// Konfiguration für das private Feld 'DefaultCollection' als Backing Field
entity.Property<Guid>("DefaultCollectionId");
entity.HasOne<Collection>()
.WithMany()
.HasForeignKey("DefaultCollectionId")
.OnDelete(DeleteBehavior.Restrict);
// n:m Beziehung zwischen Usern und Collections (Members)
entity.HasMany(u => u.Collections)
.WithMany(c => c.Members)
.UsingEntity(j => j.ToTable("UserCollections"));
});
modelBuilder.Entity<Settings>()
.HasOne(s => s.User)
.WithOne(u => u.Settings)
.HasForeignKey<Settings>(s => s.UserId)
.OnDelete(DeleteBehavior.Cascade);
#endregion
#region 1:1 TCGdex & CardMarket Mapping
// EF Core mitgeteilt, auf welcher Seite der FK physisch liegt
modelBuilder.Entity<Card>()
.HasOne(c => c.TcgDexCardInfo)
.WithOne(t => t.Card)
.HasForeignKey<TcgDexCardInfo>(t => t.CardId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Set>()
.HasOne(s => s.SetInfo)
.WithOne(t => t.Set)
.HasForeignKey<TcgDexSetInfo>(t => t.SetIdRef)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Serie>()
.HasOne(s => s.TcgDexSeriesInfo)
.WithOne(t => t.Series)
.HasForeignKey<TcgDexSeriesInfo>(t => t.SeriesIdRef)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Set>()
.HasOne(s => s.CardCount)
.WithOne(c => c.Set)
.HasForeignKey<CardCount>(c => c.SetId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Set>()
.HasOne(s => s.CardMarketSetInfo)
.WithOne(cms => cms.Set)
.HasForeignKey<CardMarketSetInfo>(cms => cms.SetId)
.OnDelete(DeleteBehavior.Cascade);
// Auflösung der geteilten Legal-Tabelle
modelBuilder.Entity<Legal>(entity =>
{
entity.HasOne(l => l.Set)
.WithOne(s => s.Legal)
.HasForeignKey<Legal>(l => l.SetId)
.OnDelete(DeleteBehavior.Cascade);
entity.HasOne(l => l.Card)
.WithOne(c => c.Legal)
.HasForeignKey<Legal>(l => l.CardId)
.OnDelete(DeleteBehavior.Cascade);
});
#endregion
#region Postgres JSONB Columns
modelBuilder.Entity<Card>(entity =>
{
entity.HasOne(c => c.Set)
.WithMany(s => s.Cards)
.HasForeignKey(c => c.SetId)
.OnDelete(DeleteBehavior.Restrict);
// Native .NET Listen als JSONB in Postgres speichern
entity.Property(c => c.Variants).HasColumnType("jsonb");
entity.Property(c => c.Types).HasColumnType("jsonb");
});
modelBuilder.Entity<Attack>(entity =>
{
entity.HasOne(a => a.Card)
.WithMany(c => c.Attacks)
.HasForeignKey(a => a.CardId)
.OnDelete(DeleteBehavior.Cascade);
entity.Property(a => a.Cost).HasColumnType("jsonb");
});
#endregion
#region CollectedCard & Grading
modelBuilder.Entity<CollectedCard>(entity =>
{
entity.HasOne(cc => cc.Collection)
.WithMany(c => c.Cards)
.HasForeignKey(cc => cc.CollectionId)
.OnDelete(DeleteBehavior.Cascade);
entity.HasOne(cc => cc.Card)
.WithMany()
.HasForeignKey(cc => cc.CardId)
.OnDelete(DeleteBehavior.Restrict);
entity.HasOne(cc => cc.ScannedBy)
.WithMany()
.HasForeignKey(cc => cc.ScannedById)
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity<Grading>()
.HasOne(g => g.CollectedCard)
.WithOne(cc => cc.Grading)
.HasForeignKey<Grading>(g => g.CollectedCardId)
.OnDelete(DeleteBehavior.Cascade);
#endregion
}
}
@@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using OakArchive.Entities.Cards;
namespace OakArchive.Entities.CardMarket;
public class CardMarketSetInfo
{
[Key] public Guid Id { get; set; } = Guid.NewGuid();
public string ExpansionId { get; set; } = string.Empty;
[ForeignKey(nameof(Set))] public Guid SetId { get; set; }
public virtual Set.Set Set { get; set; } = null!;
}
+21
View File
@@ -0,0 +1,21 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
namespace OakArchive.Entities.Cards;
public class Attack
{
[Key] public Guid Id { get; set; } = Guid.NewGuid();
public List<string> Cost { get; set; } = [];
public string Name { get; set; } = string.Empty;
public int? Damage { get; set; }
public string Effect { get; set; } = string.Empty;
[ForeignKey(nameof(Card))] public Guid CardId { get; set; }
public virtual Card Card { get; set; } = null!;
}
+57
View File
@@ -0,0 +1,57 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using OakArchive.Entities.CardMarket;
using OakArchive.Entities.Enums;
using OakArchive.Entities.Set;
using OakArchive.Entities.TCGdex;
namespace OakArchive.Entities.Cards;
public class Card
{
[Key] public Guid Id { get; set; } = Guid.NewGuid();
[Required] public string Name { get; set; } = string.Empty;
public string Image { get; set; } = string.Empty;
public int CardNumber { get; set; } = 0;
public ulong PHash { get; set; } = 0;
public int? Hp { get; set; }
public int? Retreat { get; set; }
public string? TrainerType { get; set; }
public string? EnergyType { get; set; }
public string? Illustrator { get; set; }
public string? EvolveFrom { get; set; }
public string? Description { get; set; }
public string? RegulationMark { get; set; }
public Rarity? Rarity { get; set; }
public Category? Category { get; set; }
[Column(TypeName = "jsonb")]
public List<Variant>? Variants { get; set; }
[Column(TypeName = "jsonb")] public List<string>? Types { get; set; }
[ForeignKey(nameof(Set))] public Guid SetId { get; set; }
public virtual Set.Set Set { get; set; } = null!;
public virtual TcgDexCardInfo TcgDexCardInfo { get; set; } = null!;
public virtual Legal? Legal { get; set; }
public virtual ICollection<Attack> Attacks { get; set; } = new List<Attack>();
public virtual ICollection<Weakness> Weaknesses { get; set; } = new List<Weakness>();
}
@@ -0,0 +1,32 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using OakArchive.Entities.Enums;
using OakArchive.Entities.User;
namespace OakArchive.Entities.Cards;
public class CollectedCard
{
[Key] public Guid Id { get; set; } = Guid.NewGuid();
public Variant Variant { get; set; } = Variant.Normal;
public Condition Condition { get; set; } = Condition.Mint;
public int Count { get; set; } = 1;
public Language Language { get; set; } = Language.En;
public DateTime ScannedAt { get; set; } = DateTime.UtcNow;
[ForeignKey(nameof(ScannedBy))] public Guid ScannedById { get; set; }
public ApplicationUser ScannedBy { get; set; } = null!;
[ForeignKey(nameof(Collection))] public Guid CollectionId { get; set; }
public virtual Collection.Collection Collection { get; set; } = null!;
[ForeignKey(nameof(Card))] public Guid CardId { get; set; }
public virtual Card Card { get; set; } = null!;
public virtual Grading.Grading? Grading { get; set; }
}
+16
View File
@@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace OakArchive.Entities.Cards;
public class Weakness
{
[Key] public Guid Id { get; set; } = Guid.NewGuid();
public string Type { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
[ForeignKey(nameof(Card))] public Guid CardId { get; set; }
public virtual Card Card { get; set; } = null!;
}
@@ -0,0 +1,28 @@
using System.ComponentModel.DataAnnotations;
using OakArchive.Entities.Cards;
using OakArchive.Entities.User;
namespace OakArchive.Entities.Collection;
public class Collection
{
[Key]
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; } = string.Empty;
public string? Description { get; set; }
public Guid CreatedBy { get; set; } = Guid.Empty;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public string InviteCode { get; set; } = string.Empty;
public bool IsPublic { get; set; } = false;
public virtual ICollection<ApplicationUser> Members { get; set; } = [];
public virtual ICollection<CollectedCard> Cards { get; set; } = [];
}
+16
View File
@@ -0,0 +1,16 @@
using System.Text.Json.Serialization;
namespace OakArchive.Entities.Enums;
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Category
{
[JsonPropertyName("Energy")]
Energy,
[JsonPropertyName("Pokemon")]
Pokemon,
[JsonPropertyName("Trainer")]
Trainer
}
+12
View File
@@ -0,0 +1,12 @@
namespace OakArchive.Entities.Enums;
public enum Condition
{
Mint = 0,
NearMint = 1,
Excellent = 2,
Good = 3,
LightPlayed = 4,
Played = 5,
Poor = 6
}
@@ -0,0 +1,14 @@
namespace OakArchive.Entities.Enums;
public enum GradingCompany
{
PSA,
BGS,
CGC,
APGrading,
EGS,
AOG,
PCA,
GSG,
Other
}
+25
View File
@@ -0,0 +1,25 @@
using System.ComponentModel;
namespace OakArchive.Entities.Enums;
public enum Language
{
En,
Fr,
Es,
Es_Mx,
It,
Pt,
Pt_Br,
Pt_Pt,
De,
Nl,
Pl,
Ru,
Ja,
Ko,
Zh_Tw,
Id,
Th,
Zh_Cn
}
+124
View File
@@ -0,0 +1,124 @@
using System.Text.Json.Serialization;
namespace OakArchive.Entities.Enums;
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Rarity
{
[JsonPropertyName("ACE SPEC Rare")]
AceSpecRare,
[JsonPropertyName("Amazing Rare")]
AmazingRare,
[JsonPropertyName("Black White Rare")]
BlackWhiteRare,
[JsonPropertyName("Classic Collection")]
ClassicCollection,
[JsonPropertyName("Common")]
Common,
[JsonPropertyName("Crown")]
Crown,
[JsonPropertyName("Double rare")]
DoubleRare,
[JsonPropertyName("Four Diamond")]
FourDiamond,
[JsonPropertyName("Full Art Trainer")]
FullArtTrainer,
[JsonPropertyName("Holo Rare")]
HoloRare,
[JsonPropertyName("Holo Rare V")]
HoloRareV,
[JsonPropertyName("Holo Rare VMAX")]
HoloRareVmax,
[JsonPropertyName("Holo Rare VSTAR")]
HoloRareVstar,
[JsonPropertyName("Hyper rare")]
HyperRare,
[JsonPropertyName("Illustration rare")]
IllustrationRare,
[JsonPropertyName("LEGEND")]
Legend,
[JsonPropertyName("Mega Hyper Rare")]
MegaHyperRare,
[JsonPropertyName("None")]
None,
[JsonPropertyName("One Diamond")]
OneDiamond,
[JsonPropertyName("One Shiny")]
OneShiny,
[JsonPropertyName("One Star")]
OneStar,
[JsonPropertyName("Radiant Rare")]
RadiantRare,
[JsonPropertyName("Rare")]
Rare,
[JsonPropertyName("Rare Holo")]
RareHolo,
[JsonPropertyName("Rare Holo LV.X")]
RareHoloLvX,
[JsonPropertyName("Rare PRIME")]
RarePrime,
[JsonPropertyName("Secret Rare")]
SecretRare,
[JsonPropertyName("Shiny Ultra Rare")]
ShinyUltraRare,
[JsonPropertyName("Shiny rare")]
ShinyRare,
[JsonPropertyName("Shiny rare V")]
ShinyRareV,
[JsonPropertyName("Shiny rare VMAX")]
ShinyRareVmax,
[JsonPropertyName("Special illustration rare")]
SpecialIllustrationRare,
[JsonPropertyName("Three Diamond")]
ThreeDiamond,
[JsonPropertyName("Three Star")]
ThreeStar,
[JsonPropertyName("Two Diamond")]
TwoDiamond,
[JsonPropertyName("Two Shiny")]
TwoShiny,
[JsonPropertyName("Two Star")]
TwoStar,
[JsonPropertyName("Ultra Rare")]
UltraRare,
[JsonPropertyName("Uncommon")]
Uncommon
}
+37
View File
@@ -0,0 +1,37 @@
using System.Text.Json.Serialization;
namespace OakArchive.Entities.Enums;
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Stage
{
[JsonPropertyName("BREAK")]
Break,
[JsonPropertyName("Basic")]
Basic,
[JsonPropertyName("LEVEL-UP")]
LevelUp,
[JsonPropertyName("MEGA")]
Mega,
[JsonPropertyName("RESTORED")]
Restored,
[JsonPropertyName("Stage1")]
Stage1,
[JsonPropertyName("Stage2")]
Stage2,
[JsonPropertyName("V-UNION")]
VUnion,
[JsonPropertyName("VMAX")]
VMax,
[JsonPropertyName("VSTAR")]
VStar
}
+22
View File
@@ -0,0 +1,22 @@
using System.Text.Json.Serialization;
namespace OakArchive.Entities.Enums;
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Variant
{
[JsonPropertyName("firstEdition")]
FirstEdition,
[JsonPropertyName("holo")]
Holo,
[JsonPropertyName("normal")]
Normal,
[JsonPropertyName("reverse")]
Reverse,
[JsonPropertyName("wPromo")]
WPromo
}
+28
View File
@@ -0,0 +1,28 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using OakArchive.Entities.Cards;
using OakArchive.Entities.Enums;
namespace OakArchive.Entities.Grading;
public class Grading
{
[Key] public Guid Id { get; set; } = Guid.NewGuid();
[Required] public GradingCompany Company { get; set; } = GradingCompany.PSA;
[Required] public string CertificateNumber { get; set; } = string.Empty;
public double Grade { get; set; }
public double? Centering { get; set; }
public double? Corners { get; set; }
public double? Edges { get; set; }
public double? Surface { get; set; }
public string? GraderNotes { get; set; }
public DateTime GradedAt { get; set; }
[ForeignKey(nameof(CollectedCard))] public Guid CollectedCardId { get; set; }
public virtual CollectedCard CollectedCard { get; set; } = null!;
}
+24
View File
@@ -0,0 +1,24 @@
using System.ComponentModel.DataAnnotations;
using OakArchive.Entities.Enums;
using OakArchive.Entities.TCGdex;
namespace OakArchive.Entities.Serie;
public class Serie
{
[Key]
public Guid Id { get; set; } = Guid.NewGuid();
[Required]
public string Name { get; set; } = string.Empty;
public string? Logo { get; set; }
public Language? Language { get; set; }
//public DateTime? ReleaseDate { get; set; }
public virtual ICollection<Set.Set> Sets { get; set; } = new List<Set.Set>();
public virtual TcgDexSeriesInfo TcgDexSeriesInfo { get; set; } = null!;
}
+26
View File
@@ -0,0 +1,26 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace OakArchive.Entities.Set;
public class CardCount
{
[Key] public Guid Id { get; set; } = Guid.NewGuid();
public int Total { get; set; } = 0;
public int Official { get; set; } = 0;
public int Normal { get; set; } = 0;
public int Reverse { get; set; } = 0;
public int Holo { get; set; } = 0;
public int FirstEd { get; set; } = 0;
[ForeignKey(nameof(Set))]
public Guid SetId { get; set; }
public virtual Set Set { get; set; } = null!;
}
+22
View File
@@ -0,0 +1,22 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using OakArchive.Entities.Cards;
namespace OakArchive.Entities.Set;
public class Legal
{
[Key] public Guid Id { get; set; } = Guid.NewGuid();
public bool Expanded { get; set; } = false;
public bool Standard { get; set; } = false;
[ForeignKey(nameof(Set))]
public Guid? SetId { get; set; }
public virtual Set? Set { get; set; }
[ForeignKey(nameof(Card))]
public Guid? CardId { get; set; }
public virtual Card? Card { get; set; }
}
+36
View File
@@ -0,0 +1,36 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using OakArchive.Entities.CardMarket;
using OakArchive.Entities.Cards;
using OakArchive.Entities.Enums;
using OakArchive.Entities.TCGdex;
namespace OakArchive.Entities.Set;
public class Set
{
[Key] public Guid Id { get; set; } = Guid.NewGuid();
[Required] public string Name { get; set; } = string.Empty;
public string? Symbol { get; set; }
public string? Logo { get; set; }
public Language Language { get; set; } = Language.En;
public DateTime? ReleaseDate { get; set; }
public ICollection<Card> Cards { get; set; } = new List<Card>();
public virtual TcgDexSetInfo SetInfo { get; set; } = null!;
public virtual CardMarketSetInfo CardMarketSetInfo { get; set; } = null!;
[ForeignKey(nameof(Serie))] public Guid SerieId { get; set; }
public virtual Serie.Serie Serie { get; set; } = null!;
public virtual CardCount CardCount { get; set; } = null!;
public virtual Legal? Legal { get; set; }
}
@@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using OakArchive.Entities.Cards;
namespace OakArchive.Entities.TCGdex;
public class TcgDexCardInfo
{
[Key] public Guid Id { get; set; } = Guid.NewGuid();
[Required] public string FullId { get; set; } = string.Empty;
[Required] public int LocalId { get; set; } = 0;
[ForeignKey(nameof(Card))] public Guid CardId { get; set; }
public virtual Card Card { get; set; } = null!;
}
@@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace OakArchive.Entities.TCGdex;
public class TcgDexSeriesInfo
{
[Key]
public Guid Id { get; set; } = Guid.NewGuid();
[Required]
public string SeriesId { get; set; } = string.Empty;
[ForeignKey(nameof(Set))]
public Guid SeriesIdRef { get; set; }
public virtual Serie.Serie Series { get; set; } = null!;
}
@@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace OakArchive.Entities.TCGdex;
public class TcgDexSetInfo
{
[Key]
public Guid Id { get; set; } = Guid.NewGuid();
[Required]
public string SetId { get; set; } = string.Empty;
[ForeignKey(nameof(Set))]
public Guid SetIdRef { get; set; }
public virtual Set.Set Set { get; set; } = null!;
}
@@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Identity;
namespace OakArchive.Entities.User;
public class ApplicationUser : IdentityUser<Guid>
{
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public virtual Settings Settings { get; set; } = new();
private Collection.Collection DefaultCollection { get; set; } = new();
public virtual ICollection<Collection.Collection> Collections { get; set; } = [];
}
+16
View File
@@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace OakArchive.Entities.User;
public class Settings
{
[Key]
public Guid Id { get; set; } = Guid.NewGuid();
public bool AddCardsToDefaultList { get; set; } = true;
[ForeignKey(nameof(User))]
public Guid UserId { get; set; }
public virtual ApplicationUser User { get; set; } = null!;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,743 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace OakArchive.Migrations
{
/// <inheritdoc />
public partial class Init : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Collections",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Description = table.Column<string>(type: "text", nullable: true),
CreatedBy = table.Column<Guid>(type: "uuid", nullable: false),
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
InviteCode = table.Column<string>(type: "text", nullable: false),
IsPublic = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Collections", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Series",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Logo = table.Column<string>(type: "text", nullable: true),
Language = table.Column<int>(type: "integer", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Series", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RoleId = table.Column<Guid>(type: "uuid", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DefaultCollectionId = table.Column<Guid>(type: "uuid", nullable: false),
UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
PasswordHash = table.Column<string>(type: "text", nullable: true),
SecurityStamp = table.Column<string>(type: "text", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
PhoneNumber = table.Column<string>(type: "text", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
AccessFailedCount = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUsers_Collections_DefaultCollectionId",
column: x => x.DefaultCollectionId,
principalTable: "Collections",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Sets",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Symbol = table.Column<string>(type: "text", nullable: true),
Logo = table.Column<string>(type: "text", nullable: true),
Language = table.Column<int>(type: "integer", nullable: false),
ReleaseDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
SerieId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Sets", x => x.Id);
table.ForeignKey(
name: "FK_Sets_Series_SerieId",
column: x => x.SerieId,
principalTable: "Series",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "TcgDexSeriesInfos",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
SeriesId = table.Column<string>(type: "text", nullable: false),
SeriesIdRef = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_TcgDexSeriesInfos", x => x.Id);
table.ForeignKey(
name: "FK_TcgDexSeriesInfos_Series_SeriesIdRef",
column: x => x.SeriesIdRef,
principalTable: "Series",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "text", nullable: false),
ProviderKey = table.Column<string>(type: "text", nullable: false),
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<Guid>(type: "uuid", nullable: false),
RoleId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<Guid>(type: "uuid", nullable: false),
LoginProvider = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Value = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Settings",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
AddCardsToDefaultList = table.Column<bool>(type: "boolean", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Settings", x => x.Id);
table.ForeignKey(
name: "FK_Settings_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "UserCollections",
columns: table => new
{
CollectionsId = table.Column<Guid>(type: "uuid", nullable: false),
MembersId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_UserCollections", x => new { x.CollectionsId, x.MembersId });
table.ForeignKey(
name: "FK_UserCollections_AspNetUsers_MembersId",
column: x => x.MembersId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_UserCollections_Collections_CollectionsId",
column: x => x.CollectionsId,
principalTable: "Collections",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "CardCounts",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Total = table.Column<int>(type: "integer", nullable: false),
Official = table.Column<int>(type: "integer", nullable: false),
Normal = table.Column<int>(type: "integer", nullable: false),
Reverse = table.Column<int>(type: "integer", nullable: false),
Holo = table.Column<int>(type: "integer", nullable: false),
FirstEd = table.Column<int>(type: "integer", nullable: false),
SetId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CardCounts", x => x.Id);
table.ForeignKey(
name: "FK_CardCounts_Sets_SetId",
column: x => x.SetId,
principalTable: "Sets",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "CardMarketSetInfos",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ExpansionId = table.Column<string>(type: "text", nullable: false),
SetId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CardMarketSetInfos", x => x.Id);
table.ForeignKey(
name: "FK_CardMarketSetInfos_Sets_SetId",
column: x => x.SetId,
principalTable: "Sets",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Cards",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Image = table.Column<string>(type: "text", nullable: false),
CardNumber = table.Column<int>(type: "integer", nullable: false),
PHash = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
Hp = table.Column<int>(type: "integer", nullable: true),
Retreat = table.Column<int>(type: "integer", nullable: true),
TrainerType = table.Column<string>(type: "text", nullable: true),
EnergyType = table.Column<string>(type: "text", nullable: true),
Illustrator = table.Column<string>(type: "text", nullable: true),
EvolveFrom = table.Column<string>(type: "text", nullable: true),
Description = table.Column<string>(type: "text", nullable: true),
RegulationMark = table.Column<string>(type: "text", nullable: true),
Rarity = table.Column<int>(type: "integer", nullable: true),
Category = table.Column<int>(type: "integer", nullable: true),
Variants = table.Column<string>(type: "jsonb", nullable: true),
Types = table.Column<string>(type: "jsonb", nullable: true),
SetId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Cards", x => x.Id);
table.ForeignKey(
name: "FK_Cards_Sets_SetId",
column: x => x.SetId,
principalTable: "Sets",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "TcgDexSetInfos",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
SetId = table.Column<string>(type: "text", nullable: false),
SetIdRef = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_TcgDexSetInfos", x => x.Id);
table.ForeignKey(
name: "FK_TcgDexSetInfos_Sets_SetIdRef",
column: x => x.SetIdRef,
principalTable: "Sets",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Attacks",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Cost = table.Column<string>(type: "jsonb", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Damage = table.Column<int>(type: "integer", nullable: true),
Effect = table.Column<string>(type: "text", nullable: false),
CardId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Attacks", x => x.Id);
table.ForeignKey(
name: "FK_Attacks_Cards_CardId",
column: x => x.CardId,
principalTable: "Cards",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "CollectedCards",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Variant = table.Column<int>(type: "integer", nullable: false),
Condition = table.Column<int>(type: "integer", nullable: false),
Count = table.Column<int>(type: "integer", nullable: false),
Language = table.Column<int>(type: "integer", nullable: false),
ScannedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
ScannedById = table.Column<Guid>(type: "uuid", nullable: false),
CollectionId = table.Column<Guid>(type: "uuid", nullable: false),
CardId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CollectedCards", x => x.Id);
table.ForeignKey(
name: "FK_CollectedCards_AspNetUsers_ScannedById",
column: x => x.ScannedById,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_CollectedCards_Cards_CardId",
column: x => x.CardId,
principalTable: "Cards",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_CollectedCards_Collections_CollectionId",
column: x => x.CollectionId,
principalTable: "Collections",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Legals",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Expanded = table.Column<bool>(type: "boolean", nullable: false),
Standard = table.Column<bool>(type: "boolean", nullable: false),
SetId = table.Column<Guid>(type: "uuid", nullable: true),
CardId = table.Column<Guid>(type: "uuid", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Legals", x => x.Id);
table.ForeignKey(
name: "FK_Legals_Cards_CardId",
column: x => x.CardId,
principalTable: "Cards",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Legals_Sets_SetId",
column: x => x.SetId,
principalTable: "Sets",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "TcgDexCardInfos",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
FullId = table.Column<string>(type: "text", nullable: false),
LocalId = table.Column<int>(type: "integer", nullable: false),
CardId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_TcgDexCardInfos", x => x.Id);
table.ForeignKey(
name: "FK_TcgDexCardInfos_Cards_CardId",
column: x => x.CardId,
principalTable: "Cards",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Weaknesses",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Type = table.Column<string>(type: "text", nullable: false),
Value = table.Column<string>(type: "text", nullable: false),
CardId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Weaknesses", x => x.Id);
table.ForeignKey(
name: "FK_Weaknesses_Cards_CardId",
column: x => x.CardId,
principalTable: "Cards",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Gradings",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Company = table.Column<int>(type: "integer", nullable: false),
CertificateNumber = table.Column<string>(type: "text", nullable: false),
Grade = table.Column<double>(type: "double precision", nullable: false),
Centering = table.Column<double>(type: "double precision", nullable: true),
Corners = table.Column<double>(type: "double precision", nullable: true),
Edges = table.Column<double>(type: "double precision", nullable: true),
Surface = table.Column<double>(type: "double precision", nullable: true),
GraderNotes = table.Column<string>(type: "text", nullable: true),
GradedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
CollectedCardId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Gradings", x => x.Id);
table.ForeignKey(
name: "FK_Gradings_CollectedCards_CollectedCardId",
column: x => x.CollectedCardId,
principalTable: "CollectedCards",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "IX_AspNetUsers_DefaultCollectionId",
table: "AspNetUsers",
column: "DefaultCollectionId");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Attacks_CardId",
table: "Attacks",
column: "CardId");
migrationBuilder.CreateIndex(
name: "IX_CardCounts_SetId",
table: "CardCounts",
column: "SetId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_CardMarketSetInfos_SetId",
table: "CardMarketSetInfos",
column: "SetId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Cards_SetId",
table: "Cards",
column: "SetId");
migrationBuilder.CreateIndex(
name: "IX_CollectedCards_CardId",
table: "CollectedCards",
column: "CardId");
migrationBuilder.CreateIndex(
name: "IX_CollectedCards_CollectionId",
table: "CollectedCards",
column: "CollectionId");
migrationBuilder.CreateIndex(
name: "IX_CollectedCards_ScannedById",
table: "CollectedCards",
column: "ScannedById");
migrationBuilder.CreateIndex(
name: "IX_Gradings_CollectedCardId",
table: "Gradings",
column: "CollectedCardId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Legals_CardId",
table: "Legals",
column: "CardId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Legals_SetId",
table: "Legals",
column: "SetId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Sets_SerieId",
table: "Sets",
column: "SerieId");
migrationBuilder.CreateIndex(
name: "IX_Settings_UserId",
table: "Settings",
column: "UserId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_TcgDexCardInfos_CardId",
table: "TcgDexCardInfos",
column: "CardId",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_TcgDexSeriesInfos_SeriesIdRef",
table: "TcgDexSeriesInfos",
column: "SeriesIdRef",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_TcgDexSetInfos_SetIdRef",
table: "TcgDexSetInfos",
column: "SetIdRef",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_UserCollections_MembersId",
table: "UserCollections",
column: "MembersId");
migrationBuilder.CreateIndex(
name: "IX_Weaknesses_CardId",
table: "Weaknesses",
column: "CardId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "Attacks");
migrationBuilder.DropTable(
name: "CardCounts");
migrationBuilder.DropTable(
name: "CardMarketSetInfos");
migrationBuilder.DropTable(
name: "Gradings");
migrationBuilder.DropTable(
name: "Legals");
migrationBuilder.DropTable(
name: "Settings");
migrationBuilder.DropTable(
name: "TcgDexCardInfos");
migrationBuilder.DropTable(
name: "TcgDexSeriesInfos");
migrationBuilder.DropTable(
name: "TcgDexSetInfos");
migrationBuilder.DropTable(
name: "UserCollections");
migrationBuilder.DropTable(
name: "Weaknesses");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "CollectedCards");
migrationBuilder.DropTable(
name: "AspNetUsers");
migrationBuilder.DropTable(
name: "Cards");
migrationBuilder.DropTable(
name: "Collections");
migrationBuilder.DropTable(
name: "Sets");
migrationBuilder.DropTable(
name: "Series");
}
}
}
@@ -0,0 +1,999 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using OakArchive.Database;
#nullable disable
namespace OakArchive.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.7")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("ApplicationUserCollection", b =>
{
b.Property<Guid>("CollectionsId")
.HasColumnType("uuid");
b.Property<Guid>("MembersId")
.HasColumnType("uuid");
b.HasKey("CollectionsId", "MembersId");
b.HasIndex("MembersId");
b.ToTable("UserCollections", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole<System.Guid>", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<Guid>("RoleId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
{
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.Property<Guid>("RoleId")
.HasColumnType("uuid");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
{
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("OakArchive.Entities.CardMarket.CardMarketSetInfo", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("ExpansionId")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("SetId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("SetId")
.IsUnique();
b.ToTable("CardMarketSetInfos");
});
modelBuilder.Entity("OakArchive.Entities.Cards.Attack", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CardId")
.HasColumnType("uuid");
b.PrimitiveCollection<string>("Cost")
.IsRequired()
.HasColumnType("jsonb");
b.Property<int?>("Damage")
.HasColumnType("integer");
b.Property<string>("Effect")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CardId");
b.ToTable("Attacks");
});
modelBuilder.Entity("OakArchive.Entities.Cards.Card", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int>("CardNumber")
.HasColumnType("integer");
b.Property<int?>("Category")
.HasColumnType("integer");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<string>("EnergyType")
.HasColumnType("text");
b.Property<string>("EvolveFrom")
.HasColumnType("text");
b.Property<int?>("Hp")
.HasColumnType("integer");
b.Property<string>("Illustrator")
.HasColumnType("text");
b.Property<string>("Image")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<decimal>("PHash")
.HasColumnType("numeric(20,0)");
b.Property<int?>("Rarity")
.HasColumnType("integer");
b.Property<string>("RegulationMark")
.HasColumnType("text");
b.Property<int?>("Retreat")
.HasColumnType("integer");
b.Property<Guid>("SetId")
.HasColumnType("uuid");
b.Property<string>("TrainerType")
.HasColumnType("text");
b.PrimitiveCollection<string>("Types")
.HasColumnType("jsonb");
b.PrimitiveCollection<string>("Variants")
.HasColumnType("jsonb");
b.HasKey("Id");
b.HasIndex("SetId");
b.ToTable("Cards");
});
modelBuilder.Entity("OakArchive.Entities.Cards.CollectedCard", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CardId")
.HasColumnType("uuid");
b.Property<Guid>("CollectionId")
.HasColumnType("uuid");
b.Property<int>("Condition")
.HasColumnType("integer");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<int>("Language")
.HasColumnType("integer");
b.Property<DateTime>("ScannedAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("ScannedById")
.HasColumnType("uuid");
b.Property<int>("Variant")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("CardId");
b.HasIndex("CollectionId");
b.HasIndex("ScannedById");
b.ToTable("CollectedCards");
});
modelBuilder.Entity("OakArchive.Entities.Cards.Weakness", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CardId")
.HasColumnType("uuid");
b.Property<string>("Type")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Value")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CardId");
b.ToTable("Weaknesses");
});
modelBuilder.Entity("OakArchive.Entities.Collection.Collection", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("CreatedBy")
.HasColumnType("uuid");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<string>("InviteCode")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsPublic")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Collections");
});
modelBuilder.Entity("OakArchive.Entities.Grading.Grading", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<double?>("Centering")
.HasColumnType("double precision");
b.Property<string>("CertificateNumber")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("CollectedCardId")
.HasColumnType("uuid");
b.Property<int>("Company")
.HasColumnType("integer");
b.Property<double?>("Corners")
.HasColumnType("double precision");
b.Property<double?>("Edges")
.HasColumnType("double precision");
b.Property<double>("Grade")
.HasColumnType("double precision");
b.Property<DateTime>("GradedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("GraderNotes")
.HasColumnType("text");
b.Property<double?>("Surface")
.HasColumnType("double precision");
b.HasKey("Id");
b.HasIndex("CollectedCardId")
.IsUnique();
b.ToTable("Gradings");
});
modelBuilder.Entity("OakArchive.Entities.Serie.Serie", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int?>("Language")
.HasColumnType("integer");
b.Property<string>("Logo")
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Series");
});
modelBuilder.Entity("OakArchive.Entities.Set.CardCount", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int>("FirstEd")
.HasColumnType("integer");
b.Property<int>("Holo")
.HasColumnType("integer");
b.Property<int>("Normal")
.HasColumnType("integer");
b.Property<int>("Official")
.HasColumnType("integer");
b.Property<int>("Reverse")
.HasColumnType("integer");
b.Property<Guid>("SetId")
.HasColumnType("uuid");
b.Property<int>("Total")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("SetId")
.IsUnique();
b.ToTable("CardCounts");
});
modelBuilder.Entity("OakArchive.Entities.Set.Legal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("CardId")
.HasColumnType("uuid");
b.Property<bool>("Expanded")
.HasColumnType("boolean");
b.Property<Guid?>("SetId")
.HasColumnType("uuid");
b.Property<bool>("Standard")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("CardId")
.IsUnique();
b.HasIndex("SetId")
.IsUnique();
b.ToTable("Legals");
});
modelBuilder.Entity("OakArchive.Entities.Set.Set", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int>("Language")
.HasColumnType("integer");
b.Property<string>("Logo")
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime?>("ReleaseDate")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("SerieId")
.HasColumnType("uuid");
b.Property<string>("Symbol")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("SerieId");
b.ToTable("Sets");
});
modelBuilder.Entity("OakArchive.Entities.TCGdex.TcgDexCardInfo", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CardId")
.HasColumnType("uuid");
b.Property<string>("FullId")
.IsRequired()
.HasColumnType("text");
b.Property<int>("LocalId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("CardId")
.IsUnique();
b.ToTable("TcgDexCardInfos");
});
modelBuilder.Entity("OakArchive.Entities.TCGdex.TcgDexSeriesInfo", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("SeriesId")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("SeriesIdRef")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("SeriesIdRef")
.IsUnique();
b.ToTable("TcgDexSeriesInfos");
});
modelBuilder.Entity("OakArchive.Entities.TCGdex.TcgDexSetInfo", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("SetId")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("SetIdRef")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("SetIdRef")
.IsUnique();
b.ToTable("TcgDexSetInfos");
});
modelBuilder.Entity("OakArchive.Entities.User.ApplicationUser", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("DefaultCollectionId")
.HasColumnType("uuid");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("DefaultCollectionId");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("OakArchive.Entities.User.Settings", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("AddCardsToDefaultList")
.HasColumnType("boolean");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("Settings");
});
modelBuilder.Entity("ApplicationUserCollection", b =>
{
b.HasOne("OakArchive.Entities.Collection.Collection", null)
.WithMany()
.HasForeignKey("CollectionsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("OakArchive.Entities.User.ApplicationUser", null)
.WithMany()
.HasForeignKey("MembersId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<System.Guid>", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
{
b.HasOne("OakArchive.Entities.User.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
{
b.HasOne("OakArchive.Entities.User.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<System.Guid>", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("OakArchive.Entities.User.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
{
b.HasOne("OakArchive.Entities.User.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("OakArchive.Entities.CardMarket.CardMarketSetInfo", b =>
{
b.HasOne("OakArchive.Entities.Set.Set", "Set")
.WithOne("CardMarketSetInfo")
.HasForeignKey("OakArchive.Entities.CardMarket.CardMarketSetInfo", "SetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Set");
});
modelBuilder.Entity("OakArchive.Entities.Cards.Attack", b =>
{
b.HasOne("OakArchive.Entities.Cards.Card", "Card")
.WithMany("Attacks")
.HasForeignKey("CardId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Card");
});
modelBuilder.Entity("OakArchive.Entities.Cards.Card", b =>
{
b.HasOne("OakArchive.Entities.Set.Set", "Set")
.WithMany("Cards")
.HasForeignKey("SetId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Set");
});
modelBuilder.Entity("OakArchive.Entities.Cards.CollectedCard", b =>
{
b.HasOne("OakArchive.Entities.Cards.Card", "Card")
.WithMany()
.HasForeignKey("CardId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("OakArchive.Entities.Collection.Collection", "Collection")
.WithMany("Cards")
.HasForeignKey("CollectionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("OakArchive.Entities.User.ApplicationUser", "ScannedBy")
.WithMany()
.HasForeignKey("ScannedById")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Card");
b.Navigation("Collection");
b.Navigation("ScannedBy");
});
modelBuilder.Entity("OakArchive.Entities.Cards.Weakness", b =>
{
b.HasOne("OakArchive.Entities.Cards.Card", "Card")
.WithMany("Weaknesses")
.HasForeignKey("CardId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Card");
});
modelBuilder.Entity("OakArchive.Entities.Grading.Grading", b =>
{
b.HasOne("OakArchive.Entities.Cards.CollectedCard", "CollectedCard")
.WithOne("Grading")
.HasForeignKey("OakArchive.Entities.Grading.Grading", "CollectedCardId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CollectedCard");
});
modelBuilder.Entity("OakArchive.Entities.Set.CardCount", b =>
{
b.HasOne("OakArchive.Entities.Set.Set", "Set")
.WithOne("CardCount")
.HasForeignKey("OakArchive.Entities.Set.CardCount", "SetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Set");
});
modelBuilder.Entity("OakArchive.Entities.Set.Legal", b =>
{
b.HasOne("OakArchive.Entities.Cards.Card", "Card")
.WithOne("Legal")
.HasForeignKey("OakArchive.Entities.Set.Legal", "CardId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("OakArchive.Entities.Set.Set", "Set")
.WithOne("Legal")
.HasForeignKey("OakArchive.Entities.Set.Legal", "SetId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Card");
b.Navigation("Set");
});
modelBuilder.Entity("OakArchive.Entities.Set.Set", b =>
{
b.HasOne("OakArchive.Entities.Serie.Serie", "Serie")
.WithMany("Sets")
.HasForeignKey("SerieId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Serie");
});
modelBuilder.Entity("OakArchive.Entities.TCGdex.TcgDexCardInfo", b =>
{
b.HasOne("OakArchive.Entities.Cards.Card", "Card")
.WithOne("TcgDexCardInfo")
.HasForeignKey("OakArchive.Entities.TCGdex.TcgDexCardInfo", "CardId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Card");
});
modelBuilder.Entity("OakArchive.Entities.TCGdex.TcgDexSeriesInfo", b =>
{
b.HasOne("OakArchive.Entities.Serie.Serie", "Series")
.WithOne("TcgDexSeriesInfo")
.HasForeignKey("OakArchive.Entities.TCGdex.TcgDexSeriesInfo", "SeriesIdRef")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Series");
});
modelBuilder.Entity("OakArchive.Entities.TCGdex.TcgDexSetInfo", b =>
{
b.HasOne("OakArchive.Entities.Set.Set", "Set")
.WithOne("SetInfo")
.HasForeignKey("OakArchive.Entities.TCGdex.TcgDexSetInfo", "SetIdRef")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Set");
});
modelBuilder.Entity("OakArchive.Entities.User.ApplicationUser", b =>
{
b.HasOne("OakArchive.Entities.Collection.Collection", null)
.WithMany()
.HasForeignKey("DefaultCollectionId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("OakArchive.Entities.User.Settings", b =>
{
b.HasOne("OakArchive.Entities.User.ApplicationUser", "User")
.WithOne("Settings")
.HasForeignKey("OakArchive.Entities.User.Settings", "UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("OakArchive.Entities.Cards.Card", b =>
{
b.Navigation("Attacks");
b.Navigation("Legal");
b.Navigation("TcgDexCardInfo")
.IsRequired();
b.Navigation("Weaknesses");
});
modelBuilder.Entity("OakArchive.Entities.Cards.CollectedCard", b =>
{
b.Navigation("Grading");
});
modelBuilder.Entity("OakArchive.Entities.Collection.Collection", b =>
{
b.Navigation("Cards");
});
modelBuilder.Entity("OakArchive.Entities.Serie.Serie", b =>
{
b.Navigation("Sets");
b.Navigation("TcgDexSeriesInfo")
.IsRequired();
});
modelBuilder.Entity("OakArchive.Entities.Set.Set", b =>
{
b.Navigation("CardCount")
.IsRequired();
b.Navigation("CardMarketSetInfo")
.IsRequired();
b.Navigation("Cards");
b.Navigation("Legal");
b.Navigation("SetInfo")
.IsRequired();
});
modelBuilder.Entity("OakArchive.Entities.User.ApplicationUser", b =>
{
b.Navigation("Settings")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}
+18
View File
@@ -0,0 +1,18 @@
using System.Text.Json.Serialization;
namespace OakArchive.Models.TcgDex;
public class Attack
{
[JsonPropertyName("cost")]
public List<string>? Cost { get; set; }
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("effect")]
public string? Effect { get; set; }
[JsonPropertyName("damage")]
public int? Damage { get; set; }
}
+64
View File
@@ -0,0 +1,64 @@
using System.Text.Json.Serialization;
using OakArchive.Entities.Set;
namespace OakArchive.Models.TcgDex;
public class Card
{
[JsonPropertyName("category")]
public string? Category { get; set; }
[JsonPropertyName("id")]
public string? Id { get; set; }
[JsonPropertyName("illustrator")]
public string? Illustrator { get; set; }
[JsonPropertyName("image")]
public string? Image { get; set; }
[JsonPropertyName("localId")]
public int? LocalId { get; set; }
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("rarity")]
public string? Rarity { get; set; }
[JsonPropertyName("set")]
public Entities.Set.Set? Set { get; set; }
[JsonPropertyName("variants")]
public Variants? Variants { get; set; }
[JsonPropertyName("hp")]
public int? Hp { get; set; }
[JsonPropertyName("types")]
public List<string>? Types { get; set; }
[JsonPropertyName("evolveFrom")]
public string? EvolveFrom { get; set; }
[JsonPropertyName("description")]
public string? Description { get; set; }
[JsonPropertyName("stage")]
public string? Stage { get; set; }
[JsonPropertyName("attacks")]
public List<Attack>? Attacks { get; set; }
[JsonPropertyName("weaknesses")]
public List<Weakness>? Weaknesses { get; set; }
[JsonPropertyName("retreat")]
public int? Retreat { get; set; }
[JsonPropertyName("regulationMark")]
public string? RegulationMark { get; set; }
[JsonPropertyName("legal")]
public Legal? Legal { get; set; }
}
+24
View File
@@ -0,0 +1,24 @@
using System.Text.Json.Serialization;
namespace OakArchive.Models.TcgDex;
public class CardCount
{
[JsonPropertyName("firstEd")]
public int? FirstEd { get; set; }
[JsonPropertyName("holo")]
public int? Holo { get; set; }
[JsonPropertyName("normal")]
public int? Normal { get; set; }
[JsonPropertyName("official")]
public int? Official { get; set; }
[JsonPropertyName("reverse")]
public int? Reverse { get; set; }
[JsonPropertyName("total")]
public int? Total { get; set; }
}
+12
View File
@@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
namespace OakArchive.Models.TcgDex;
public class Legal
{
[JsonPropertyName("standard")]
public bool? Standard { get; set; }
[JsonPropertyName("expanded")]
public bool? Expanded { get; set; }
}
+18
View File
@@ -0,0 +1,18 @@
using System.Text.Json.Serialization;
namespace OakArchive.Models.TcgDex;
public class Serie
{
[JsonPropertyName("id")]
public string? Id { get; set; }
[JsonPropertyName("logo")]
public string? Logo { get; set; }
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("sets")]
public List<SetBrief>? Sets { get; set; }
}
+15
View File
@@ -0,0 +1,15 @@
using System.Text.Json.Serialization;
namespace OakArchive.Models.TcgDex;
public class SerieBrief
{
[JsonPropertyName("id")]
public string? Id { get; set; }
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("logo")]
public string? Logo { get; set; }
}
+33
View File
@@ -0,0 +1,33 @@
using System.Text.Json.Serialization;
namespace OakArchive.Models.TcgDex;
public class Set
{
[JsonPropertyName("cardCount")]
public CardCount CardCount { get; set; }
[JsonPropertyName("cards")]
public List<Card> Cards { get; set; }
[JsonPropertyName("id")]
public string Id { get; set; }
[JsonPropertyName("legal")]
public Legal Legal { get; set; }
[JsonPropertyName("logo")]
public string Logo { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("releaseDate")]
public DateTime ReleaseDate { get; set; }
[JsonPropertyName("serie")]
public Serie Serie { get; set; }
[JsonPropertyName("symbol")]
public string Symbol { get; set; }
}
+21
View File
@@ -0,0 +1,21 @@
using System.Text.Json.Serialization;
namespace OakArchive.Models.TcgDex;
public class SetBrief
{
[JsonPropertyName("cardCount")]
public CardCount? CardCount { get; set; }
[JsonPropertyName("id")]
public string? Id { get; set; }
[JsonPropertyName("logo")]
public string? Logo { get; set; }
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("symbol")]
public string? Symbol { get; set; }
}
+21
View File
@@ -0,0 +1,21 @@
using System.Text.Json.Serialization;
namespace OakArchive.Models.TcgDex;
public class Variants
{
[JsonPropertyName("firstEdition")]
public bool? FirstEdition { get; set; }
[JsonPropertyName("holo")]
public bool? Holo { get; set; }
[JsonPropertyName("normal")]
public bool? Normal { get; set; }
[JsonPropertyName("reverse")]
public bool? Reverse { get; set; }
[JsonPropertyName("wPromo")]
public bool? WPromo { get; set; }
}
+12
View File
@@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
namespace OakArchive.Models.TcgDex;
public class Weakness
{
[JsonPropertyName("type")]
public string? Type { get; set; }
[JsonPropertyName("value")]
public string? Value { get; set; }
}
+2 -7
View File
@@ -14,6 +14,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CoenM.ImageSharp.ImageHash" Version="1.3.6" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7">
@@ -28,13 +29,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Controllers\" />
<Folder Include="Entities\CardMarket\" />
<Folder Include="Entities\Cards\" />
<Folder Include="Entities\Collection\" />
<Folder Include="Entities\TCGdex\" />
<Folder Include="Entities\User\" />
<Folder Include="Models\" />
<Folder Include="Controllers\V1\" />
</ItemGroup>
</Project>
+49 -3
View File
@@ -1,21 +1,67 @@
using Microsoft.EntityFrameworkCore;
using OakArchive.Database;
using OakArchive.Services;
namespace OakArchive;
public class Program
{
public static void Main(string[] args)
public static async Task Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(builder.Configuration["DefaultConnection"]));
builder.Services.AddMemoryCache(); // Registriert das native IMemoryCache von Microsoft
builder.Services.AddSingleton<IMemoryCacheService, MemoryCacheService>();
builder.Services.AddHttpClient<ITcgDexService, TcgDexService>(client =>
{
client.BaseAddress = new Uri("https://api.tcgdex.net/v2/");
client.DefaultRequestHeaders.Add("Accept", "application/json");
});
builder.Services.AddScoped<ITcgDexDataUpdater, TcgDexDataUpdater>();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.Lifetime.ApplicationStarted.Register(async () =>
{
// Da ApplicationStarted synchron registriert, machen wir hier einen neuen asynchronen Scope auf
using var scope = app.Services.CreateScope();
try
{
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
Console.WriteLine("[INFO] Prüfe auf ausstehende Datenbank-Migrationen...");
// Führt alle ausstehenden Migrationen auf der PostgreSQL-Datenbank aus.
// Falls die Datenbank noch gar nicht existiert, wird sie hier automatisch erstellt!
await context.Database.MigrateAsync();
var updater = scope.ServiceProvider.GetRequiredService<ITcgDexDataUpdater>();
Console.WriteLine("[INFO] === Starte TCGdex Test-Sync im Hintergrund ===");
var result = await updater.SyncBaseDataFromTcgDex();
Console.WriteLine($"[INFO] === Test-Sync beendet! Neue Daten geladen: {result} ===");
}
catch (Exception ex)
{
Console.WriteLine($"[FEHLER] !!! Fehler beim Test-Sync: {ex.Message} !!!");
Console.WriteLine(ex.StackTrace);
}
});
app.UseAuthorization();
app.UseStaticFiles();
app.MapControllers();
+50
View File
@@ -0,0 +1,50 @@
using Microsoft.Extensions.Caching.Memory;
namespace OakArchive.Services;
public interface IMemoryCacheService
{
Task<T?> GetOrCreateAsync<T>(string cacheKey, Func<Task<T?>> createItem, TimeSpan? expiration = null)
where T : class;
void Remove(string cacheKey);
}
public class MemoryCacheService : IMemoryCacheService
{
private readonly IMemoryCache _memoryCache;
private readonly TimeSpan _defaultExpiration = TimeSpan.FromHours(1);
public MemoryCacheService(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
public async Task<T?> GetOrCreateAsync<T>(string cacheKey, Func<Task<T?>> createItem, TimeSpan? expiration = null)
where T : class
{
if (_memoryCache.TryGetValue(cacheKey, out T? cachedItem))
{
return cachedItem;
}
var item = await createItem();
if (item == null)
{
return null;
}
var cacheOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(expiration ?? _defaultExpiration);
_memoryCache.Set(cacheKey, item, cacheOptions);
return item!;
}
public void Remove(string cacheKey)
{
_memoryCache.Remove(cacheKey);
}
}
+261
View File
@@ -0,0 +1,261 @@
using Microsoft.EntityFrameworkCore;
using OakArchive.Database;
using OakArchive.Entities.CardMarket;
using OakArchive.Entities.Cards;
using OakArchive.Entities.Enums;
using OakArchive.Entities.TCGdex;
using OakArchive.Util;
using OakArchive.Util.Extensions;
using Card = OakArchive.Entities.Cards.Card;
using CardCount = OakArchive.Entities.Set.CardCount;
using Legal = OakArchive.Entities.Set.Legal;
using Set = OakArchive.Entities.Set.Set;
namespace OakArchive.Services;
public interface ITcgDexDataUpdater
{
public Task<bool> SyncBaseDataFromTcgDex();
public Task<Card>
UpdateCard(string set, int id, string language);
}
public class TcgDexDataUpdater : ITcgDexDataUpdater
{
private readonly ITcgDexService _tcgDexService;
private readonly ApplicationDbContext _dbContext;
private readonly List<Language> _languages = Enum.GetValues<Language>().ToList();
public TcgDexDataUpdater(ITcgDexService tcgDexService, ApplicationDbContext dbContext)
{
_tcgDexService = tcgDexService;
_dbContext = dbContext;
}
public async Task<bool> SyncBaseDataFromTcgDex()
{
var hasChanges = false;
int i = 0;
foreach (var language in _languages)
{
var apiSeriesBriefs = await _tcgDexService.GetSeries(language.ToApiCode());
await Task.Delay(500);
foreach (var serieBrief in apiSeriesBriefs)
{
if (i == 1) return true;
i += 1;
if (string.IsNullOrEmpty(serieBrief.Id)) continue;
var dbSerie = await EnsureSerieExistsAsync(serieBrief, language);
var fullApiSerie = await _tcgDexService.GetSetsOfSeries(serieBrief.Id, language.ToApiCode());
if (fullApiSerie?.Sets == null) continue;
await Task.Delay(300);
foreach (var setBrief in fullApiSerie.Sets)
{
if (string.IsNullOrEmpty(setBrief.Id)) continue;
var isSetInDb = dbSerie.Sets.Any(s => s.SetInfo?.SetId == setBrief.Id);
if (isSetInDb) continue;
var fullApiSet = await _tcgDexService.GetSet(setBrief.Id, language.ToApiCode());
if (fullApiSet == null) continue;
var dbSet = await BuildSetEntityWithCardsAsync(setBrief, fullApiSet, language);
dbSerie.Sets.Add(dbSet);
await Task.Delay(500);
}
if (await _dbContext.SaveChangesAsync() > 0)
{
hasChanges = true;
}
}
}
return hasChanges;
}
public async Task<Card> UpdateCard(string set, int id, string language)
{
var tcgDexCardId = $"{set.ToLower()}-{id}";
if (!Enum.TryParse<Language>(language, true, out var langEnum))
{
langEnum = Language.En;
}
var dbCard = await _dbContext.Cards
.Include(c => c.TcgDexCardInfo)
.Include(c => c.Attacks)
.Include(c => c.Weaknesses)
.FirstOrDefaultAsync(c => c.TcgDexCardInfo.FullId == tcgDexCardId && c.Set.Language == langEnum);
if (dbCard == null)
{
throw new KeyNotFoundException(
$"Die Basis-Karte mit der TCGdex-ID '{tcgDexCardId}' wurde für die Sprache '{language}' nicht in der Datenbank gefunden. Führe zuerst den Basis-Sync aus.");
}
var apiCard = await _tcgDexService.GetCard(set, id, language);
if (apiCard == null)
{
throw new HttpRequestException(
$"Die Karte '{tcgDexCardId}' konnte von der TCGdex-API nicht geladen werden.");
}
dbCard.Name = apiCard.Name ?? dbCard.Name;
dbCard.Hp = apiCard.Hp;
dbCard.Retreat = apiCard.Retreat;
dbCard.Illustrator = apiCard.Illustrator;
dbCard.EvolveFrom = apiCard.EvolveFrom;
dbCard.Description = apiCard.Description;
dbCard.RegulationMark = apiCard.RegulationMark;
dbCard.Types = apiCard.Types;
if (!string.IsNullOrEmpty(apiCard.Rarity) &&
Enum.TryParse<Rarity>(apiCard.Rarity.Replace(" ", ""), true, out var parsedRarity))
{
dbCard.Rarity = parsedRarity;
}
if (!string.IsNullOrEmpty(apiCard.Category) &&
Enum.TryParse<Category>(apiCard.Category, true, out var parsedCategory))
{
dbCard.Category = parsedCategory;
}
dbCard.Variants = MapApiVariantsToEnumList(apiCard.Variants);
dbCard.Attacks.Clear();
if (apiCard.Attacks != null)
{
foreach (var apiAttack in apiCard.Attacks)
{
dbCard.Attacks.Add(new Attack
{
Name = apiAttack.Name ?? "Unknown",
Damage = apiAttack.Damage,
Effect = apiAttack.Effect ?? string.Empty,
Cost = apiAttack.Cost ?? []
});
}
}
dbCard.Weaknesses.Clear();
if (apiCard.Weaknesses != null)
{
foreach (var apiWeakness in apiCard.Weaknesses)
{
dbCard.Weaknesses.Add(new Weakness
{
Type = apiWeakness.Type ?? "Unknown",
Value = apiWeakness.Value ?? string.Empty
});
}
}
await _dbContext.SaveChangesAsync();
return dbCard;
}
private List<Variant> MapApiVariantsToEnumList(Models.TcgDex.Variants? apiVariants)
{
var list = new List<Variant>();
if (apiVariants == null) return list;
if (apiVariants.FirstEdition == true) list.Add(Variant.FirstEdition);
if (apiVariants.Holo == true) list.Add(Variant.Holo);
if (apiVariants.Normal == true) list.Add(Variant.Normal);
if (apiVariants.Reverse == true) list.Add(Variant.Reverse);
if (apiVariants.WPromo == true) list.Add(Variant.WPromo);
return list;
}
private async Task<Entities.Serie.Serie> EnsureSerieExistsAsync(Models.TcgDex.SerieBrief brief, Language language)
{
var dbSerie = await _dbContext.Series
.Include(s => s.Sets)
.ThenInclude(s => s.SetInfo)
.FirstOrDefaultAsync(s => s.TcgDexSeriesInfo.SeriesId == brief.Id && s.Language == language);
if (dbSerie != null) return dbSerie;
dbSerie = new Entities.Serie.Serie
{
Language = language,
Name = brief.Name ?? "Unknown",
Logo = brief.Logo,
TcgDexSeriesInfo = new TcgDexSeriesInfo { SeriesId = brief.Id! }
};
_dbContext.Series.Add(dbSerie);
return dbSerie;
}
private async Task<Set> BuildSetEntityWithCardsAsync(Models.TcgDex.SetBrief setBrief, Models.TcgDex.Set fullApiSet,
Language language)
{
DateTime? utcReleaseDate = fullApiSet.ReleaseDate != null
? DateTime.SpecifyKind(fullApiSet.ReleaseDate, DateTimeKind.Utc)
: null;
var dbSet = new Set
{
Language = language,
Name = setBrief.Name ?? "Unknown",
Logo = setBrief.Logo,
ReleaseDate = utcReleaseDate,
Symbol = setBrief.Symbol,
SetInfo = new TcgDexSetInfo { SetId = fullApiSet.Id },
CardMarketSetInfo = new CardMarketSetInfo { ExpansionId = "0" }, // TODO: Späterer Price-Scraper
Legal = new Legal
{
Expanded = fullApiSet.Legal?.Expanded ?? false,
Standard = fullApiSet.Legal?.Standard ?? false
},
CardCount = new CardCount
{
FirstEd = fullApiSet.CardCount?.FirstEd ?? 0,
Holo = fullApiSet.CardCount?.Holo ?? 0,
Normal = fullApiSet.CardCount?.Normal ?? 0,
Official = fullApiSet.CardCount?.Official ?? 0,
Reverse = fullApiSet.CardCount?.Reverse ?? 0,
Total = fullApiSet.CardCount?.Total ?? 0
}
};
if (fullApiSet.Cards is not { Count: > 0 }) return dbSet;
var cardTasks = fullApiSet.Cards.Select(async c =>
{
var localPath = await _tcgDexService.DownloadCardImage(c, language.ToApiCode());
return new Card
{
Name = c.Name ?? "Unknown",
Image = localPath == null ? c.Image : localPath.Item1,
CardNumber = c.LocalId ?? 0,
PHash = localPath == null ? 0 : PerceptualHashHelper.GenerateHash(localPath.Item2),
TcgDexCardInfo = new TcgDexCardInfo
{
FullId = c.Id ?? string.Empty,
LocalId = c.LocalId ?? 0
}
};
});
dbSet.Cards = (await Task.WhenAll(cardTasks)).ToList();
return dbSet;
}
}
+113
View File
@@ -0,0 +1,113 @@
using OakArchive.Models.TcgDex;
namespace OakArchive.Services;
public interface ITcgDexService
{
public Task<List<SerieBrief>> GetSeries(string language);
public Task<Serie?> GetSetsOfSeries(string series, string language);
public Task<Set?> GetSet(string set, string language);
public Task<Card?> GetCard(string set, int id, string language);
public Task<Tuple<string, byte[]>?> DownloadCardImage(Card card, string language);
}
public class TcgDexService : ITcgDexService
{
private readonly HttpClient _httpClient;
private readonly IMemoryCacheService _cacheService;
private readonly string _baseFolder = Path.Combine(Directory.GetCurrentDirectory(), "Cards");
private readonly SemaphoreSlim _downloadSemaphore = new SemaphoreSlim(3, 3);
public TcgDexService(HttpClient httpClient, IMemoryCacheService cacheService)
{
_httpClient = httpClient;
_cacheService = cacheService;
}
public async Task<List<SerieBrief>> GetSeries(string language)
{
var cacheKey = $"tcgdex_series_{language.ToLower()}";
async Task<List<SerieBrief>> FetchFromApi()
{
var res = await _httpClient.GetFromJsonAsync<List<SerieBrief>>($"{language}/series");
return res ?? [];
}
return await _cacheService.GetOrCreateAsync(cacheKey, FetchFromApi, TimeSpan.FromDays(7));
}
public async Task<Serie?> GetSetsOfSeries(string series, string language)
{
var cacheKey = $"tcgdex_serie_{series.ToLower()}_{language.ToLower()}";
async Task<Serie?> FetchFromApi()
{
var res = await _httpClient.GetFromJsonAsync<Serie>($"{language}/series/{series}");
return res;
}
return await _cacheService.GetOrCreateAsync(cacheKey, FetchFromApi, TimeSpan.FromDays(7));
}
public async Task<Set?> GetSet(string set, string language)
{
var cacheKey = $"tcgdex_set_{set.ToLower()}_{language.ToLower()}";
async Task<Set?> FetchFromApi()
{
var res = await _httpClient.GetFromJsonAsync<Set>($"{language}/sets/{set}");
return res;
}
return await _cacheService.GetOrCreateAsync(cacheKey, FetchFromApi, TimeSpan.FromDays(7));
}
public async Task<Card?> GetCard(string set, int id, string language)
{
var cacheKey = $"tcgdex_card_{set.ToLower()}_{language.ToLower()}";
async Task<Card?> FetchFromApi()
{
var res = await _httpClient.GetFromJsonAsync<Card?>($"{language}/cards/{set}-{id}");
return res;
}
return await _cacheService.GetOrCreateAsync(cacheKey, FetchFromApi, TimeSpan.FromDays(7));
}
public async Task<Tuple<string, byte[]>?> DownloadCardImage(Card card, string language)
{
var split = card.Id!.Split("-");
var filePath = Path.Combine(_baseFolder, split[0], language,$"{split[1]}.webp");
if (File.Exists(filePath))
{
var res = await File.ReadAllBytesAsync(filePath);
return Tuple.Create(filePath, res);
}
await _downloadSemaphore.WaitAsync();
try
{
var res = await _httpClient.GetByteArrayAsync(card.Image + "/high.webp");
Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
await File.WriteAllBytesAsync(filePath, res);
await Task.Delay(200);
return Tuple.Create(filePath, res);
}
finally
{
_downloadSemaphore.Release();
}
}
}
@@ -0,0 +1,46 @@
using OakArchive.Entities.Enums;
namespace OakArchive.Util.Extensions;
public static class LanguageExtensions
{
public static string ToApiCode(this Language lang)
{
return lang switch
{
Language.Es_Mx => "es-mx",
Language.Pt_Br => "pt-br",
Language.Pt_Pt => "pt-pt",
Language.Zh_Tw => "zh-tw",
Language.Zh_Cn => "zh-cn",
_ => lang.ToString().ToLower()
};
}
// Ein zusätzliches Feld für deine Avalonia-UI (Anzeigename)
public static string GetDisplayName(this Language lang)
{
return lang switch
{
Language.En => "English",
Language.Fr => "Français",
Language.Es => "Español",
Language.Es_Mx => "Español (México)",
Language.It => "Italiano",
Language.Pt => "Português",
Language.Pt_Br => "Português (Brasil)",
Language.Pt_Pt => "Português (Portugal)",
Language.De => "Deutsch",
Language.Nl => "Nederlands",
Language.Pl => "Polski",
Language.Ru => "Русский",
Language.Ja => "日本語",
Language.Ko => "한국어",
Language.Zh_Tw => "繁體中文 (Taiwan)",
Language.Id => "Bahasa Indonesia",
Language.Th => "ไทย",
Language.Zh_Cn => "简体中文 (China)",
_ => lang.ToString()
};
}
}
+47
View File
@@ -0,0 +1,47 @@
using CoenM.ImageHash.HashAlgorithms;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
namespace OakArchive.Util;
public class PerceptualHashHelper
{
private static readonly PerceptualHash _perceptualHash = new();
private const int TargetWidth = 600;
private const int TargetHeight = 840;
private const int Margin = 15;
public static ulong GenerateHash(byte[] rawImage)
{
using var image = Image.Load<Rgba32>(rawImage);
image.Mutate(x => x.Resize(TargetWidth, TargetHeight));
return _perceptualHash.Hash(image);
}
public static ulong GenerateHashWithMargin(byte[] rawImage)
{
using var image = Image.Load<Rgba32>(rawImage);
const int maxContentWidth = TargetWidth - (2 * Margin);
const int maxContentHeight = TargetHeight - (2 * Margin);
image.Mutate(x => x.Resize(new ResizeOptions
{
Size = new Size(maxContentWidth, maxContentHeight),
Mode = ResizeMode.Max
}));
using var canvas = new Image<Rgba32>(TargetWidth, TargetHeight, Color.Black);
var posX = (TargetWidth - image.Width) / 2;
var posY = (TargetHeight - image.Height) / 2;
canvas.Mutate(x => x.DrawImage(image, new Point(posX, posY), 1f));
return _perceptualHash.Hash(canvas);
}
}
+3 -4
View File
@@ -4,13 +4,12 @@
build:
context: .
dockerfile: OakArchive/Dockerfile
# Falls die DB in einer anderen Datei ist, nimm depends_on raus,
# da Compose nur Services innerhalb derselben Datei überwachen kann.
networks:
- postgres-network
environment:
# WICHTIG: Host muss der 'container_name' oder 'service_name' der DB sein
- CONNECTION_STRING=Host=OmniDB;Database=oak_db;Username=admin;Password=${DB_PASSWORD}
- DefaultConnection=Host=OmniDB;Database=oak_db;Username=admin;Password=${DB_PASSWORD}
volumes:
- C:\Users\larsh\Documents\docker\oakarchive\Cards:/app/Cards
networks:
postgres-network: