Compare commits
2 Commits
efb8a41065
...
defa00d0d3
| Author | SHA1 | Date | |
|---|---|---|---|
| defa00d0d3 | |||
| eebc5f1d6d |
@@ -3,3 +3,4 @@ end_of_line = lf
|
|||||||
charset = utf-8
|
charset = utf-8
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
indent_style = tab
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Shadow.Controllers;
|
|
||||||
using Shadow.Data;
|
|
||||||
using Shadow.Entities;
|
|
||||||
|
|
||||||
namespace Shadow.Controllers;
|
|
||||||
public class Seeder
|
|
||||||
{
|
|
||||||
private readonly ApplicationDbContext db;
|
|
||||||
private readonly GeneralUseHelpers guhf;
|
|
||||||
|
|
||||||
public Seeder(ApplicationDbContext _db, GeneralUseHelpers _guhf)
|
|
||||||
{
|
|
||||||
db = _db;
|
|
||||||
guhf = _guhf;
|
|
||||||
}
|
|
||||||
public void Seed()
|
|
||||||
{
|
|
||||||
|
|
||||||
// TODO: Ensure [unknown album], [unknown artist] exist
|
|
||||||
|
|
||||||
// TODO: Force add a new user through CLI if no users exist
|
|
||||||
|
|
||||||
|
|
||||||
Console.WriteLine($"You're running Shadow, commit {ThisAssembly.Git.Commit} of branch {ThisAssembly.Git.Branch} ({ThisAssembly.Git.CommitDate})\n");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,6 +17,7 @@ public class ApplicationDbContext : DbContext
|
|||||||
public DbSet<Artist> Artists => Set<Artist>();
|
public DbSet<Artist> Artists => Set<Artist>();
|
||||||
public DbSet<Genre> Genres => Set<Genre>();
|
public DbSet<Genre> Genres => Set<Genre>();
|
||||||
public DbSet<GenreSong> GenreSongs => Set<GenreSong>();
|
public DbSet<GenreSong> GenreSongs => Set<GenreSong>();
|
||||||
|
public DbSet<Global> Globals => Set<Global>();
|
||||||
public DbSet<Image> Images => Set<Image>();
|
public DbSet<Image> Images => Set<Image>();
|
||||||
public DbSet<Playlist> Playlists => Set<Playlist>();
|
public DbSet<Playlist> Playlists => Set<Playlist>();
|
||||||
public DbSet<PlaylistSong> PlaylistSongs => Set<PlaylistSong>();
|
public DbSet<PlaylistSong> PlaylistSongs => Set<PlaylistSong>();
|
||||||
@@ -52,6 +53,9 @@ public class ApplicationDbContext : DbContext
|
|||||||
builder.Entity<Genre>(g => {
|
builder.Entity<Genre>(g => {
|
||||||
g.HasIndex(g => g.NormalizedName).IsUnique();
|
g.HasIndex(g => g.NormalizedName).IsUnique();
|
||||||
});
|
});
|
||||||
|
builder.Entity<Global>(c => {
|
||||||
|
c.HasIndex(c => c.Key).IsUnique();
|
||||||
|
});
|
||||||
builder.Entity<Playlist>(p => {
|
builder.Entity<Playlist>(p => {
|
||||||
p.HasIndex(p => p.Uri).IsUnique();
|
p.HasIndex(p => p.Uri).IsUnique();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Shadow.Entities;
|
namespace Shadow.Entities;
|
||||||
public class Album
|
public class Album
|
||||||
{
|
{
|
||||||
required public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
public required string Uri { get; set; }
|
public required string Uri { get; set; }
|
||||||
public int State { get; set; } = 0;
|
public int State { get; set; } = 0;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Shadow.Entities;
|
namespace Shadow.Entities;
|
||||||
public class AlbumInteraction
|
public class AlbumInteraction
|
||||||
{
|
{
|
||||||
required public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
required public int AlbumId { get; set; }
|
required public int AlbumId { get; set; }
|
||||||
required public int UserId { get; set; }
|
required public int UserId { get; set; }
|
||||||
public DateTime? PlayDate { get; set; } = null;
|
public DateTime? PlayDate { get; set; } = null;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Shadow.Entities;
|
namespace Shadow.Entities;
|
||||||
public class Artist
|
public class Artist
|
||||||
{
|
{
|
||||||
required public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
required public string Name { get; set; }
|
required public string Name { get; set; }
|
||||||
required public string NormalizedName { get; set; }
|
required public string NormalizedName { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Shadow.Entities;
|
namespace Shadow.Entities;
|
||||||
public class Genre
|
public class Genre
|
||||||
{
|
{
|
||||||
required public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
required public string Name { get; set; }
|
required public string Name { get; set; }
|
||||||
required public string NormalizedName { get; set; }
|
required public string NormalizedName { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ namespace Shadow.Entities;
|
|||||||
public class GenreSong
|
public class GenreSong
|
||||||
{
|
{
|
||||||
// Composite keys
|
// Composite keys
|
||||||
required public int GenreId { get; set; }
|
public int GenreId { get; set; }
|
||||||
required public int SongId { get; set; }
|
required public int SongId { get; set; }
|
||||||
|
|
||||||
required public Genre Genre { get; set; }
|
required public Genre Genre { get; set; }
|
||||||
|
|||||||
7
Entities/Global.cs
Normal file
7
Entities/Global.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Shadow.Entities;
|
||||||
|
public class Global
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
required public string Key { get; set; }
|
||||||
|
public string? Value { get; set; } = null;
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
namespace Shadow.Entities;
|
namespace Shadow.Entities;
|
||||||
public class Image
|
public class Image
|
||||||
{
|
{
|
||||||
required public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
required public string Uri { get; set; }
|
required public string Uri { get; set; }
|
||||||
|
required public string Filetype { get; set; }
|
||||||
public int State { get; set; }
|
public int State { get; set; }
|
||||||
public int? SongId { get; set; } = null;
|
public int? SongId { get; set; } = null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Shadow.Entities;
|
namespace Shadow.Entities;
|
||||||
public class Playlist
|
public class Playlist
|
||||||
{
|
{
|
||||||
required public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
required public string Name { get; set; }
|
required public string Name { get; set; }
|
||||||
required public string Uri { get; set; }
|
required public string Uri { get; set; }
|
||||||
required public string Description { get; set; }
|
required public string Description { get; set; }
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Shadow.Entities;
|
namespace Shadow.Entities;
|
||||||
public class Radio
|
public class Radio
|
||||||
{
|
{
|
||||||
required public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
required public string Name { get; set; }
|
required public string Name { get; set; }
|
||||||
required public string NormalizedName { get; set; }
|
required public string NormalizedName { get; set; }
|
||||||
public string? Homepage { get; set; } = null;
|
public string? Homepage { get; set; } = null;
|
||||||
|
|||||||
608
Migrations/20251209000751_InitialMigration.Designer.cs
generated
608
Migrations/20251209000751_InitialMigration.Designer.cs
generated
@@ -1,608 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
using Shadow.Data;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace Shadow.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(ApplicationDbContext))]
|
|
||||||
[Migration("20251209000751_InitialMigration")]
|
|
||||||
partial class InitialMigration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "10.0.0")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Album", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<int?>("ArtistId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("State")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Uri")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("ArtistId");
|
|
||||||
|
|
||||||
b.HasIndex("Uri")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Albums");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.AlbumInteraction", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("AlbumId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("UserId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("PlayDate")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<bool>("Starred")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.HasKey("AlbumId", "UserId");
|
|
||||||
|
|
||||||
b.HasIndex("UserId");
|
|
||||||
|
|
||||||
b.ToTable("AlbumInteractions");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Artist", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedName")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Artists");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Genre", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedName")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Genres");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.GenreSong", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("GenreId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("SongId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.HasKey("GenreId", "SongId");
|
|
||||||
|
|
||||||
b.HasIndex("SongId");
|
|
||||||
|
|
||||||
b.ToTable("GenreSongs");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Image", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<int?>("SongId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("State")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Uri")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("SongId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Images");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Playlist", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<int>("CreatorId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Description")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Uri")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("CreatorId");
|
|
||||||
|
|
||||||
b.HasIndex("Uri")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Playlists");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.PlaylistSong", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("PlaylistId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("SongId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("Index")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.HasKey("PlaylistId", "SongId");
|
|
||||||
|
|
||||||
b.HasIndex("SongId");
|
|
||||||
|
|
||||||
b.ToTable("PlaylistSongs");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.PlaylistUser", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("PlaylistId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("UserId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.HasKey("PlaylistId", "UserId");
|
|
||||||
|
|
||||||
b.HasIndex("UserId");
|
|
||||||
|
|
||||||
b.ToTable("PlaylistUsers");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Radio", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("Homepage")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Url")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("UserId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedName")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.HasIndex("UserId");
|
|
||||||
|
|
||||||
b.ToTable("Radios");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Song", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<int>("AlbumId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("ArtistId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int?>("BitDepth")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("Bitrate")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("Channels")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Comment")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<DateTime>("Date")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<int?>("DiscNumber")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("Duration")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Filepath")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Filetype")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int?>("ImageId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("Index")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("SamplingRate")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("Size")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("State")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Title")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int?>("TrackNumber")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Uri")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("AlbumId");
|
|
||||||
|
|
||||||
b.HasIndex("ArtistId");
|
|
||||||
|
|
||||||
b.HasIndex("Uri")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Songs");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.SongInteraction", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("SongId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("UserId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("PlayCount")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("Rating")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<bool?>("Starred")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.HasKey("SongId", "UserId");
|
|
||||||
|
|
||||||
b.HasIndex("UserId");
|
|
||||||
|
|
||||||
b.ToTable("SongInteractions");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Password")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("Role")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("Name")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Users");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Album", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Shadow.Entities.Artist", "Artist")
|
|
||||||
.WithMany("Albums")
|
|
||||||
.HasForeignKey("ArtistId");
|
|
||||||
|
|
||||||
b.Navigation("Artist");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.AlbumInteraction", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Shadow.Entities.Album", "Album")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("AlbumId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("Shadow.Entities.User", "User")
|
|
||||||
.WithMany("AlbumInteractions")
|
|
||||||
.HasForeignKey("UserId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Navigation("Album");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.GenreSong", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Shadow.Entities.Genre", "Genre")
|
|
||||||
.WithMany("GenreSongPair")
|
|
||||||
.HasForeignKey("GenreId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("Shadow.Entities.Song", "Song")
|
|
||||||
.WithMany("GenreSongPair")
|
|
||||||
.HasForeignKey("SongId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Navigation("Genre");
|
|
||||||
|
|
||||||
b.Navigation("Song");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Image", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Shadow.Entities.Song", "Song")
|
|
||||||
.WithOne("Image")
|
|
||||||
.HasForeignKey("Shadow.Entities.Image", "SongId");
|
|
||||||
|
|
||||||
b.Navigation("Song");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Playlist", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Shadow.Entities.User", "Creator")
|
|
||||||
.WithMany("Playlists")
|
|
||||||
.HasForeignKey("CreatorId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Navigation("Creator");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.PlaylistSong", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Shadow.Entities.Playlist", "Playlist")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("PlaylistId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("Shadow.Entities.Song", "Song")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("SongId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Navigation("Playlist");
|
|
||||||
|
|
||||||
b.Navigation("Song");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.PlaylistUser", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Shadow.Entities.Playlist", "Playlist")
|
|
||||||
.WithMany("AuthorizedPlaylistUsers")
|
|
||||||
.HasForeignKey("PlaylistId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("Shadow.Entities.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Navigation("Playlist");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Radio", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Shadow.Entities.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Song", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Shadow.Entities.Album", "Album")
|
|
||||||
.WithMany("Songs")
|
|
||||||
.HasForeignKey("AlbumId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("Shadow.Entities.Artist", "Artist")
|
|
||||||
.WithMany("Songs")
|
|
||||||
.HasForeignKey("ArtistId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Navigation("Album");
|
|
||||||
|
|
||||||
b.Navigation("Artist");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.SongInteraction", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Shadow.Entities.Song", "Song")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("SongId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("Shadow.Entities.User", "User")
|
|
||||||
.WithMany("SongInteractions")
|
|
||||||
.HasForeignKey("UserId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Navigation("Song");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Album", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("Songs");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Artist", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("Albums");
|
|
||||||
|
|
||||||
b.Navigation("Songs");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Genre", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("GenreSongPair");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Playlist", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("AuthorizedPlaylistUsers");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Song", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("GenreSongPair");
|
|
||||||
|
|
||||||
b.Navigation("Image");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.User", b =>
|
|
||||||
{
|
|
||||||
b.Navigation("AlbumInteractions");
|
|
||||||
|
|
||||||
b.Navigation("Playlists");
|
|
||||||
|
|
||||||
b.Navigation("SongInteractions");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,458 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace Shadow.Migrations
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class InitialMigration : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Artists",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
Name = table.Column<string>(type: "text", nullable: false),
|
|
||||||
NormalizedName = table.Column<string>(type: "text", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Artists", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Genres",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
Name = table.Column<string>(type: "text", nullable: false),
|
|
||||||
NormalizedName = table.Column<string>(type: "text", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Genres", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Users",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
Name = table.Column<string>(type: "text", nullable: false),
|
|
||||||
NormalizedName = table.Column<string>(type: "text", nullable: false),
|
|
||||||
Password = table.Column<string>(type: "text", nullable: false),
|
|
||||||
Role = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Users", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Albums",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
Name = table.Column<string>(type: "text", nullable: false),
|
|
||||||
Uri = table.Column<string>(type: "text", nullable: false),
|
|
||||||
State = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
ArtistId = table.Column<int>(type: "integer", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Albums", x => x.Id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_Albums_Artists_ArtistId",
|
|
||||||
column: x => x.ArtistId,
|
|
||||||
principalTable: "Artists",
|
|
||||||
principalColumn: "Id");
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Playlists",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
Name = table.Column<string>(type: "text", nullable: false),
|
|
||||||
Uri = table.Column<string>(type: "text", nullable: false),
|
|
||||||
Description = table.Column<string>(type: "text", nullable: false),
|
|
||||||
CreatorId = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Playlists", x => x.Id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_Playlists_Users_CreatorId",
|
|
||||||
column: x => x.CreatorId,
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Radios",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
Name = table.Column<string>(type: "text", nullable: false),
|
|
||||||
NormalizedName = table.Column<string>(type: "text", nullable: false),
|
|
||||||
Homepage = table.Column<string>(type: "text", nullable: true),
|
|
||||||
Url = table.Column<string>(type: "text", nullable: false),
|
|
||||||
UserId = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Radios", x => x.Id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_Radios_Users_UserId",
|
|
||||||
column: x => x.UserId,
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "AlbumInteractions",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
AlbumId = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
UserId = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
Id = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
PlayDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
|
||||||
Starred = table.Column<bool>(type: "boolean", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_AlbumInteractions", x => new { x.AlbumId, x.UserId });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_AlbumInteractions_Albums_AlbumId",
|
|
||||||
column: x => x.AlbumId,
|
|
||||||
principalTable: "Albums",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_AlbumInteractions_Users_UserId",
|
|
||||||
column: x => x.UserId,
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Songs",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
Title = table.Column<string>(type: "text", nullable: false),
|
|
||||||
Uri = table.Column<string>(type: "text", nullable: false),
|
|
||||||
Filepath = table.Column<string>(type: "text", nullable: false),
|
|
||||||
State = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
Filetype = table.Column<string>(type: "text", nullable: false),
|
|
||||||
Date = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
|
||||||
Duration = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
Bitrate = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
Size = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
Comment = table.Column<string>(type: "text", nullable: true),
|
|
||||||
Channels = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
SamplingRate = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
BitDepth = table.Column<int>(type: "integer", nullable: true),
|
|
||||||
Index = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
TrackNumber = table.Column<int>(type: "integer", nullable: true),
|
|
||||||
DiscNumber = table.Column<int>(type: "integer", nullable: true),
|
|
||||||
AlbumId = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
ArtistId = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
ImageId = table.Column<int>(type: "integer", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Songs", x => x.Id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_Songs_Albums_AlbumId",
|
|
||||||
column: x => x.AlbumId,
|
|
||||||
principalTable: "Albums",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_Songs_Artists_ArtistId",
|
|
||||||
column: x => x.ArtistId,
|
|
||||||
principalTable: "Artists",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "PlaylistUsers",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
PlaylistId = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
UserId = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_PlaylistUsers", x => new { x.PlaylistId, x.UserId });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_PlaylistUsers_Playlists_PlaylistId",
|
|
||||||
column: x => x.PlaylistId,
|
|
||||||
principalTable: "Playlists",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_PlaylistUsers_Users_UserId",
|
|
||||||
column: x => x.UserId,
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "GenreSongs",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
GenreId = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
SongId = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_GenreSongs", x => new { x.GenreId, x.SongId });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_GenreSongs_Genres_GenreId",
|
|
||||||
column: x => x.GenreId,
|
|
||||||
principalTable: "Genres",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_GenreSongs_Songs_SongId",
|
|
||||||
column: x => x.SongId,
|
|
||||||
principalTable: "Songs",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Images",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
Uri = table.Column<string>(type: "text", nullable: false),
|
|
||||||
State = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
SongId = table.Column<int>(type: "integer", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Images", x => x.Id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_Images_Songs_SongId",
|
|
||||||
column: x => x.SongId,
|
|
||||||
principalTable: "Songs",
|
|
||||||
principalColumn: "Id");
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "PlaylistSongs",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
PlaylistId = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
SongId = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
Index = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_PlaylistSongs", x => new { x.PlaylistId, x.SongId });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_PlaylistSongs_Playlists_PlaylistId",
|
|
||||||
column: x => x.PlaylistId,
|
|
||||||
principalTable: "Playlists",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_PlaylistSongs_Songs_SongId",
|
|
||||||
column: x => x.SongId,
|
|
||||||
principalTable: "Songs",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "SongInteractions",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
SongId = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
UserId = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
Id = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
PlayCount = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
Starred = table.Column<bool>(type: "boolean", nullable: true),
|
|
||||||
Rating = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_SongInteractions", x => new { x.SongId, x.UserId });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_SongInteractions_Songs_SongId",
|
|
||||||
column: x => x.SongId,
|
|
||||||
principalTable: "Songs",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_SongInteractions_Users_UserId",
|
|
||||||
column: x => x.UserId,
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AlbumInteractions_UserId",
|
|
||||||
table: "AlbumInteractions",
|
|
||||||
column: "UserId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Albums_ArtistId",
|
|
||||||
table: "Albums",
|
|
||||||
column: "ArtistId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Albums_Uri",
|
|
||||||
table: "Albums",
|
|
||||||
column: "Uri",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Artists_NormalizedName",
|
|
||||||
table: "Artists",
|
|
||||||
column: "NormalizedName",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Genres_NormalizedName",
|
|
||||||
table: "Genres",
|
|
||||||
column: "NormalizedName",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_GenreSongs_SongId",
|
|
||||||
table: "GenreSongs",
|
|
||||||
column: "SongId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Images_SongId",
|
|
||||||
table: "Images",
|
|
||||||
column: "SongId",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Playlists_CreatorId",
|
|
||||||
table: "Playlists",
|
|
||||||
column: "CreatorId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Playlists_Uri",
|
|
||||||
table: "Playlists",
|
|
||||||
column: "Uri",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_PlaylistSongs_SongId",
|
|
||||||
table: "PlaylistSongs",
|
|
||||||
column: "SongId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_PlaylistUsers_UserId",
|
|
||||||
table: "PlaylistUsers",
|
|
||||||
column: "UserId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Radios_NormalizedName",
|
|
||||||
table: "Radios",
|
|
||||||
column: "NormalizedName",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Radios_UserId",
|
|
||||||
table: "Radios",
|
|
||||||
column: "UserId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_SongInteractions_UserId",
|
|
||||||
table: "SongInteractions",
|
|
||||||
column: "UserId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Songs_AlbumId",
|
|
||||||
table: "Songs",
|
|
||||||
column: "AlbumId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Songs_ArtistId",
|
|
||||||
table: "Songs",
|
|
||||||
column: "ArtistId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Songs_Uri",
|
|
||||||
table: "Songs",
|
|
||||||
column: "Uri",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Users_Name",
|
|
||||||
table: "Users",
|
|
||||||
column: "Name",
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "AlbumInteractions");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "GenreSongs");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Images");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "PlaylistSongs");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "PlaylistUsers");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Radios");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "SongInteractions");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Genres");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Playlists");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Songs");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Users");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Albums");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Artists");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
635
Migrations/20251216025633_InitialMigration.Designer.cs
generated
Normal file
635
Migrations/20251216025633_InitialMigration.Designer.cs
generated
Normal file
@@ -0,0 +1,635 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
using Shadow.Data;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Shadow.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20251216025633_InitialMigration")]
|
||||||
|
partial class InitialMigration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.1")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Album", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int?>("ArtistId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("State")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Uri")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ArtistId");
|
||||||
|
|
||||||
|
b.HasIndex("Uri")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Albums");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.AlbumInteraction", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AlbumId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("PlayDate")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<bool>("Starred")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.HasKey("AlbumId", "UserId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AlbumInteractions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Artist", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Artists");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Genre", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Genres");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.GenreSong", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("GenreId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("SongId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("GenreId", "SongId");
|
||||||
|
|
||||||
|
b.HasIndex("SongId");
|
||||||
|
|
||||||
|
b.ToTable("GenreSongs");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Global", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Key")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Globals");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Image", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Filetype")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int?>("SongId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("State")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Uri")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SongId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Images");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Playlist", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("CreatorId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Uri")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CreatorId");
|
||||||
|
|
||||||
|
b.HasIndex("Uri")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Playlists");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.PlaylistSong", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("PlaylistId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("SongId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Index")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("PlaylistId", "SongId");
|
||||||
|
|
||||||
|
b.HasIndex("SongId");
|
||||||
|
|
||||||
|
b.ToTable("PlaylistSongs");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.PlaylistUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("PlaylistId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("PlaylistId", "UserId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("PlaylistUsers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Radio", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Homepage")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Url")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Radios");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Song", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("AlbumId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("ArtistId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int?>("BitDepth")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Bitrate")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Channels")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Comment")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Date")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<int?>("DiscNumber")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Duration")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Filepath")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Filetype")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Index")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("SamplingRate")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Size")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("State")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int?>("TrackNumber")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Uri")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AlbumId");
|
||||||
|
|
||||||
|
b.HasIndex("ArtistId");
|
||||||
|
|
||||||
|
b.HasIndex("Uri")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Songs");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.SongInteraction", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("SongId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("PlayCount")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("Rating")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<bool?>("Starred")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.HasKey("SongId", "UserId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("SongInteractions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Role")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Album", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Shadow.Entities.Artist", "Artist")
|
||||||
|
.WithMany("Albums")
|
||||||
|
.HasForeignKey("ArtistId");
|
||||||
|
|
||||||
|
b.Navigation("Artist");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.AlbumInteraction", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Shadow.Entities.Album", "Album")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AlbumId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Shadow.Entities.User", "User")
|
||||||
|
.WithMany("AlbumInteractions")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Album");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.GenreSong", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Shadow.Entities.Genre", "Genre")
|
||||||
|
.WithMany("GenreSongPair")
|
||||||
|
.HasForeignKey("GenreId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Shadow.Entities.Song", "Song")
|
||||||
|
.WithMany("GenreSongPair")
|
||||||
|
.HasForeignKey("SongId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Genre");
|
||||||
|
|
||||||
|
b.Navigation("Song");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Image", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Shadow.Entities.Song", "Song")
|
||||||
|
.WithOne("Image")
|
||||||
|
.HasForeignKey("Shadow.Entities.Image", "SongId");
|
||||||
|
|
||||||
|
b.Navigation("Song");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Playlist", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Shadow.Entities.User", "Creator")
|
||||||
|
.WithMany("Playlists")
|
||||||
|
.HasForeignKey("CreatorId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Creator");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.PlaylistSong", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Shadow.Entities.Playlist", "Playlist")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("PlaylistId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Shadow.Entities.Song", "Song")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("SongId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Playlist");
|
||||||
|
|
||||||
|
b.Navigation("Song");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.PlaylistUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Shadow.Entities.Playlist", "Playlist")
|
||||||
|
.WithMany("AuthorizedPlaylistUsers")
|
||||||
|
.HasForeignKey("PlaylistId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Shadow.Entities.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Playlist");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Radio", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Shadow.Entities.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Song", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Shadow.Entities.Album", "Album")
|
||||||
|
.WithMany("Songs")
|
||||||
|
.HasForeignKey("AlbumId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Shadow.Entities.Artist", "Artist")
|
||||||
|
.WithMany("Songs")
|
||||||
|
.HasForeignKey("ArtistId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Album");
|
||||||
|
|
||||||
|
b.Navigation("Artist");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.SongInteraction", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Shadow.Entities.Song", "Song")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("SongId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Shadow.Entities.User", "User")
|
||||||
|
.WithMany("SongInteractions")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Song");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Album", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Songs");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Artist", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Albums");
|
||||||
|
|
||||||
|
b.Navigation("Songs");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Genre", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("GenreSongPair");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Playlist", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("AuthorizedPlaylistUsers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Song", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("GenreSongPair");
|
||||||
|
|
||||||
|
b.Navigation("Image");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("AlbumInteractions");
|
||||||
|
|
||||||
|
b.Navigation("Playlists");
|
||||||
|
|
||||||
|
b.Navigation("SongInteractions");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
482
Migrations/20251216025633_InitialMigration.cs
Normal file
482
Migrations/20251216025633_InitialMigration.cs
Normal file
@@ -0,0 +1,482 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Shadow.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class InitialMigration : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Artists",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
NormalizedName = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Artists", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Genres",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
NormalizedName = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Genres", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Globals",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
Key = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Value = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Globals", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Users",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
NormalizedName = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Password = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Role = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Users", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Albums",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Uri = table.Column<string>(type: "text", nullable: false),
|
||||||
|
State = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
ArtistId = table.Column<int>(type: "integer", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Albums", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Albums_Artists_ArtistId",
|
||||||
|
column: x => x.ArtistId,
|
||||||
|
principalTable: "Artists",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Playlists",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Uri = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Description = table.Column<string>(type: "text", nullable: false),
|
||||||
|
CreatorId = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Playlists", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Playlists_Users_CreatorId",
|
||||||
|
column: x => x.CreatorId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Radios",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
NormalizedName = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Homepage = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Url = table.Column<string>(type: "text", nullable: false),
|
||||||
|
UserId = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Radios", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Radios_Users_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AlbumInteractions",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
AlbumId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
UserId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
PlayDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||||
|
Starred = table.Column<bool>(type: "boolean", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AlbumInteractions", x => new { x.AlbumId, x.UserId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AlbumInteractions_Albums_AlbumId",
|
||||||
|
column: x => x.AlbumId,
|
||||||
|
principalTable: "Albums",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AlbumInteractions_Users_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Songs",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
Title = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Uri = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Filepath = table.Column<string>(type: "text", nullable: false),
|
||||||
|
State = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Filetype = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Date = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||||
|
Duration = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Bitrate = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Size = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Comment = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Channels = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
SamplingRate = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
BitDepth = table.Column<int>(type: "integer", nullable: true),
|
||||||
|
Index = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
TrackNumber = table.Column<int>(type: "integer", nullable: true),
|
||||||
|
DiscNumber = table.Column<int>(type: "integer", nullable: true),
|
||||||
|
AlbumId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
ArtistId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
ImageId = table.Column<int>(type: "integer", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Songs", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Songs_Albums_AlbumId",
|
||||||
|
column: x => x.AlbumId,
|
||||||
|
principalTable: "Albums",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Songs_Artists_ArtistId",
|
||||||
|
column: x => x.ArtistId,
|
||||||
|
principalTable: "Artists",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PlaylistUsers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
PlaylistId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
UserId = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PlaylistUsers", x => new { x.PlaylistId, x.UserId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PlaylistUsers_Playlists_PlaylistId",
|
||||||
|
column: x => x.PlaylistId,
|
||||||
|
principalTable: "Playlists",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PlaylistUsers_Users_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "GenreSongs",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
GenreId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
SongId = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_GenreSongs", x => new { x.GenreId, x.SongId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_GenreSongs_Genres_GenreId",
|
||||||
|
column: x => x.GenreId,
|
||||||
|
principalTable: "Genres",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_GenreSongs_Songs_SongId",
|
||||||
|
column: x => x.SongId,
|
||||||
|
principalTable: "Songs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Images",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
Uri = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Filetype = table.Column<string>(type: "text", nullable: false),
|
||||||
|
State = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
SongId = table.Column<int>(type: "integer", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Images", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Images_Songs_SongId",
|
||||||
|
column: x => x.SongId,
|
||||||
|
principalTable: "Songs",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PlaylistSongs",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
PlaylistId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
SongId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Index = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PlaylistSongs", x => new { x.PlaylistId, x.SongId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PlaylistSongs_Playlists_PlaylistId",
|
||||||
|
column: x => x.PlaylistId,
|
||||||
|
principalTable: "Playlists",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PlaylistSongs_Songs_SongId",
|
||||||
|
column: x => x.SongId,
|
||||||
|
principalTable: "Songs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SongInteractions",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
SongId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
UserId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
PlayCount = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Starred = table.Column<bool>(type: "boolean", nullable: true),
|
||||||
|
Rating = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SongInteractions", x => new { x.SongId, x.UserId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SongInteractions_Songs_SongId",
|
||||||
|
column: x => x.SongId,
|
||||||
|
principalTable: "Songs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SongInteractions_Users_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AlbumInteractions_UserId",
|
||||||
|
table: "AlbumInteractions",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Albums_ArtistId",
|
||||||
|
table: "Albums",
|
||||||
|
column: "ArtistId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Albums_Uri",
|
||||||
|
table: "Albums",
|
||||||
|
column: "Uri",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Artists_NormalizedName",
|
||||||
|
table: "Artists",
|
||||||
|
column: "NormalizedName",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Genres_NormalizedName",
|
||||||
|
table: "Genres",
|
||||||
|
column: "NormalizedName",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_GenreSongs_SongId",
|
||||||
|
table: "GenreSongs",
|
||||||
|
column: "SongId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Globals_Key",
|
||||||
|
table: "Globals",
|
||||||
|
column: "Key",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Images_SongId",
|
||||||
|
table: "Images",
|
||||||
|
column: "SongId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Playlists_CreatorId",
|
||||||
|
table: "Playlists",
|
||||||
|
column: "CreatorId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Playlists_Uri",
|
||||||
|
table: "Playlists",
|
||||||
|
column: "Uri",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PlaylistSongs_SongId",
|
||||||
|
table: "PlaylistSongs",
|
||||||
|
column: "SongId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PlaylistUsers_UserId",
|
||||||
|
table: "PlaylistUsers",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Radios_NormalizedName",
|
||||||
|
table: "Radios",
|
||||||
|
column: "NormalizedName",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Radios_UserId",
|
||||||
|
table: "Radios",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SongInteractions_UserId",
|
||||||
|
table: "SongInteractions",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Songs_AlbumId",
|
||||||
|
table: "Songs",
|
||||||
|
column: "AlbumId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Songs_ArtistId",
|
||||||
|
table: "Songs",
|
||||||
|
column: "ArtistId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Songs_Uri",
|
||||||
|
table: "Songs",
|
||||||
|
column: "Uri",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Users_Name",
|
||||||
|
table: "Users",
|
||||||
|
column: "Name",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AlbumInteractions");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "GenreSongs");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Globals");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Images");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "PlaylistSongs");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "PlaylistUsers");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Radios");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SongInteractions");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Genres");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Playlists");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Songs");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Albums");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Artists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
@@ -17,7 +17,7 @@ namespace Shadow.Migrations
|
|||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "10.0.0")
|
.HasAnnotation("ProductVersion", "10.0.1")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
@@ -141,6 +141,29 @@ namespace Shadow.Migrations
|
|||||||
b.ToTable("GenreSongs");
|
b.ToTable("GenreSongs");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Shadow.Entities.Global", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Key")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Globals");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Shadow.Entities.Image", b =>
|
modelBuilder.Entity("Shadow.Entities.Image", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -149,6 +172,10 @@ namespace Shadow.Migrations
|
|||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Filetype")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<int?>("SongId")
|
b.Property<int?>("SongId")
|
||||||
.HasColumnType("integer");
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
|||||||
10
Program.cs
10
Program.cs
@@ -1,8 +1,8 @@
|
|||||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.OpenApi;
|
using Microsoft.OpenApi;
|
||||||
using Shadow.Controllers;
|
|
||||||
using Shadow.Data;
|
using Shadow.Data;
|
||||||
|
using Shadow.Tools;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
@@ -66,12 +66,13 @@ builder.Services.AddSwaggerGen(options =>
|
|||||||
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||||
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
|
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
|
||||||
});
|
});
|
||||||
|
builder.Services.AddHttpLogging();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
bool shutdown = false;
|
||||||
if (args.FirstOrDefault() is not null)
|
if (args.FirstOrDefault() is not null)
|
||||||
{
|
{
|
||||||
// Handle CLI if arguments have been passed.
|
// Handle CLI if arguments have been passed.
|
||||||
bool shutdown = false;
|
|
||||||
using (IServiceScope scope = app.Services.CreateScope())
|
using (IServiceScope scope = app.Services.CreateScope())
|
||||||
{
|
{
|
||||||
ApplicationDbContext db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
ApplicationDbContext db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
||||||
@@ -87,9 +88,9 @@ using (IServiceScope scope = app.Services.CreateScope())
|
|||||||
ApplicationDbContext db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
ApplicationDbContext db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
||||||
GeneralUseHelpers guhf = scope.ServiceProvider.GetRequiredService<GeneralUseHelpers>();
|
GeneralUseHelpers guhf = scope.ServiceProvider.GetRequiredService<GeneralUseHelpers>();
|
||||||
Seeder seeder = new(db, guhf);
|
Seeder seeder = new(db, guhf);
|
||||||
seeder.Seed();
|
shutdown = seeder.Seed();
|
||||||
}
|
}
|
||||||
|
if (shutdown) return;
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
@@ -97,6 +98,7 @@ if (app.Environment.IsDevelopment())
|
|||||||
app.MapOpenApi();
|
app.MapOpenApi();
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
app.UseSwaggerUI();
|
app.UseSwaggerUI();
|
||||||
|
app.UseHttpLogging();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
|||||||
@@ -23,15 +23,17 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.0" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.0">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
||||||
<PackageReference Include="Npgsql" Version="10.0.0" />
|
<PackageReference Include="Npgsql" Version="10.0.0" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
|
||||||
|
<PackageReference Include="Quartz" Version="3.15.1" />
|
||||||
|
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.15.1" />
|
||||||
<PackageReference Include="SharpExifTool" Version="13.32.0.1" />
|
<PackageReference Include="SharpExifTool" Version="13.32.0.1" />
|
||||||
<PackageReference Include="SkiaSharp" Version="3.119.1" />
|
<PackageReference Include="SkiaSharp" Version="3.119.1" />
|
||||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="3.119.1" />
|
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="3.119.1" />
|
||||||
@@ -42,6 +44,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Folder Include="Controllers\" />
|
||||||
<Folder Include="Migrations\" />
|
<Folder Include="Migrations\" />
|
||||||
<Folder Include="Mapping\" />
|
<Folder Include="Mapping\" />
|
||||||
<Folder Include="DTOs\" />
|
<Folder Include="DTOs\" />
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
using Shadow.Data;
|
using Shadow.Data;
|
||||||
using Shadow.Entities;
|
using Shadow.Entities;
|
||||||
|
|
||||||
namespace Shadow.Controllers;
|
namespace Shadow.Tools;
|
||||||
public class Cli
|
public class Cli
|
||||||
{
|
{
|
||||||
private readonly ApplicationDbContext db;
|
private readonly ApplicationDbContext db;
|
||||||
private readonly GeneralUseHelpers guhf;
|
private readonly GeneralUseHelpers guhf;
|
||||||
private readonly string[] args;
|
private readonly string[] args;
|
||||||
|
|
||||||
// TODO: Add "changeUser"
|
// TODO: Add "changeUser", "fullRescan", "destructiveRescan"
|
||||||
|
|
||||||
public Cli(ApplicationDbContext _db, GeneralUseHelpers _guhf, string[] _args)
|
public Cli(ApplicationDbContext _db, GeneralUseHelpers _guhf, string[] _args)
|
||||||
{
|
{
|
||||||
@@ -28,12 +28,18 @@ public class Cli
|
|||||||
switch (args[0].ToLower())
|
switch (args[0].ToLower())
|
||||||
{
|
{
|
||||||
case "adduser":
|
case "adduser":
|
||||||
|
case "--adduser":
|
||||||
|
case "--add-user":
|
||||||
AddUser();
|
AddUser();
|
||||||
break;
|
break;
|
||||||
case "resetpassword":
|
case "resetpassword":
|
||||||
|
case "--resetpassword":
|
||||||
|
case "--reset-password":
|
||||||
ResetPassword();
|
ResetPassword();
|
||||||
break;
|
break;
|
||||||
case "removeuser":
|
case "removeuser":
|
||||||
|
case "--removeuser":
|
||||||
|
case "--remove-user":
|
||||||
RemoveUser();
|
RemoveUser();
|
||||||
break;
|
break;
|
||||||
case "help":
|
case "help":
|
||||||
@@ -45,6 +51,15 @@ public class Cli
|
|||||||
case "?":
|
case "?":
|
||||||
ShowHelp();
|
ShowHelp();
|
||||||
break;
|
break;
|
||||||
|
case "setupwizard":
|
||||||
|
case "--setupwizard":
|
||||||
|
case "--setup-wizard":
|
||||||
|
case "setup":
|
||||||
|
case "--setup":
|
||||||
|
case "configure":
|
||||||
|
case "--configure":
|
||||||
|
SetupWizard();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Console.WriteLine($"Unknown option: \"{args[0]}\". See \"help\" for available arguments.");
|
Console.WriteLine($"Unknown option: \"{args[0]}\". See \"help\" for available arguments.");
|
||||||
break;
|
break;
|
||||||
@@ -242,6 +257,68 @@ public class Cli
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool SetupWizard()
|
||||||
|
{
|
||||||
|
// Returns true if setup successful. Otherwise false.
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
Console.WriteLine("[Shadow] Setup wizard\n" +
|
||||||
|
" Welcome to Shadow's setup wizard. Here, you can customize:\n" +
|
||||||
|
" - Shadow's music library path, used to scan for audio files,\n" +
|
||||||
|
" - Shadow's image thumbnails path, used to provide cover art extracted from media.\n" +
|
||||||
|
" Finally, you will be asked if you want your changes saved.\n");
|
||||||
|
|
||||||
|
Global? musicLibraryPath = db.Globals.FirstOrDefault(g => g.Key == "musicLibraryPath");
|
||||||
|
Global? musicThumbnailPath = db.Globals.FirstOrDefault(g => g.Key == "musicThumbnailPath");
|
||||||
|
|
||||||
|
if (musicLibraryPath is not null || musicThumbnailPath is not null)
|
||||||
|
{
|
||||||
|
Console.WriteLine(" Found existing configuration:");
|
||||||
|
if (musicLibraryPath is not null)
|
||||||
|
Console.WriteLine($" - for music library: {musicLibraryPath.Value}");
|
||||||
|
if (musicThumbnailPath is not null)
|
||||||
|
Console.WriteLine($" - for image thumbnails: {musicThumbnailPath.Value}");
|
||||||
|
Console.WriteLine(" They will be OVERWRITTEN if you'll commit your changes.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine(" No existing configuration found.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
string newMusicLibraryPath = DefaultPrompt("Please enter your new music library path", musicLibraryPath?.Value).TrimEnd(['\\', '/']);
|
||||||
|
string newMusicThumbnailPath = DefaultPrompt("Please enter your new image thumbnail path", musicThumbnailPath?.Value ?? Path.Combine(newMusicLibraryPath, ".shadow")).TrimEnd(['\\', '/']);
|
||||||
|
|
||||||
|
bool confirmed = YesNoPrompt("Are you sure you want:\n" +
|
||||||
|
$"- \"{newMusicLibraryPath}\" as your new music library path,\n" +
|
||||||
|
$"- \"{newMusicThumbnailPath}\" as your new image thumbnail path?\n" +
|
||||||
|
$"Please answer yes or no [y/N]: ", false);
|
||||||
|
|
||||||
|
if (!confirmed)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Changes not saved.");
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.Write("Saving changes... ");
|
||||||
|
|
||||||
|
musicLibraryPath ??= new Global() { Key = "musicLibraryPath" };
|
||||||
|
musicThumbnailPath ??= new Global() { Key = "musicThumbnailPath" };
|
||||||
|
|
||||||
|
musicLibraryPath.Value = newMusicLibraryPath;
|
||||||
|
musicThumbnailPath.Value = newMusicThumbnailPath;
|
||||||
|
|
||||||
|
// UpdateRange can both Add and Update rows.
|
||||||
|
db.Globals.UpdateRange(musicLibraryPath, musicThumbnailPath);
|
||||||
|
db.SaveChanges();
|
||||||
|
|
||||||
|
Console.WriteLine("success!");
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
public string ReadPassword(string prompt = " Enter password (will not be echoed back): ")
|
public string ReadPassword(string prompt = " Enter password (will not be echoed back): ")
|
||||||
{
|
{
|
||||||
// https://www.silicloud.com/blog/how-to-hide-content-in-the-console-using-c/
|
// https://www.silicloud.com/blog/how-to-hide-content-in-the-console-using-c/
|
||||||
@@ -281,12 +358,14 @@ public class Cli
|
|||||||
// user will be asked repeatedly.
|
// user will be asked repeatedly.
|
||||||
bool exit = false;
|
bool exit = false;
|
||||||
bool response = false;
|
bool response = false;
|
||||||
|
string? input = null;
|
||||||
|
|
||||||
Console.Write(prompt);
|
|
||||||
string? input = Console.ReadLine();
|
|
||||||
|
|
||||||
while (!exit)
|
while (!exit)
|
||||||
{
|
{
|
||||||
|
Console.Write(prompt);
|
||||||
|
input = Console.ReadLine();
|
||||||
|
|
||||||
if (input is not null && input.Length > 0)
|
if (input is not null && input.Length > 0)
|
||||||
{
|
{
|
||||||
if (input.ToLower().StartsWith("y"))
|
if (input.ToLower().StartsWith("y"))
|
||||||
@@ -308,4 +387,25 @@ public class Cli
|
|||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string DefaultPrompt(string prompt, string? default_value = null)
|
||||||
|
{
|
||||||
|
// Prompt the user repeatedly for answer. If default value
|
||||||
|
// is specified, an enter will be treated as if the user
|
||||||
|
// entered the default value.
|
||||||
|
string response = String.Empty;
|
||||||
|
string? input;
|
||||||
|
|
||||||
|
while (response.Trim() == String.Empty)
|
||||||
|
{
|
||||||
|
Console.Write($"{prompt}" + (default_value is not null ? $" [{default_value}]" : "") + ": ");
|
||||||
|
input = Console.ReadLine();
|
||||||
|
|
||||||
|
if (input is not null && input.Length > 0)
|
||||||
|
response = input;
|
||||||
|
else if (default_value is not null)
|
||||||
|
response = default_value;
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ using Shadow.Data;
|
|||||||
using Shadow.Entities;
|
using Shadow.Entities;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Shadow.Controllers;
|
namespace Shadow.Tools;
|
||||||
|
|
||||||
public class GeneralUseHelpers(ApplicationDbContext db, IConfiguration appsettings)
|
public class GeneralUseHelpers(ApplicationDbContext db, IConfiguration appsettings)
|
||||||
{
|
{
|
||||||
93
Tools/Seeder.cs
Normal file
93
Tools/Seeder.cs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Shadow.Data;
|
||||||
|
using Shadow.Entities;
|
||||||
|
|
||||||
|
namespace Shadow.Tools;
|
||||||
|
public class Seeder
|
||||||
|
{
|
||||||
|
private readonly ApplicationDbContext db;
|
||||||
|
private readonly GeneralUseHelpers guhf;
|
||||||
|
|
||||||
|
public Seeder(ApplicationDbContext _db, GeneralUseHelpers _guhf)
|
||||||
|
{
|
||||||
|
db = _db;
|
||||||
|
guhf = _guhf;
|
||||||
|
}
|
||||||
|
public bool Seed()
|
||||||
|
{
|
||||||
|
// Will return true if application should be shut down.
|
||||||
|
// Otherwise returns false.
|
||||||
|
bool shutdown = false;
|
||||||
|
|
||||||
|
Console.WriteLine($"You're running Shadow, commit {ThisAssembly.Git.Commit} of branch {ThisAssembly.Git.Branch} ({ThisAssembly.Git.CommitDate})\n");
|
||||||
|
|
||||||
|
// Check if this is a clean, first run. If so, run the setup wizard.
|
||||||
|
Global? lastVersion = db.Globals.FirstOrDefault(c => c.Key == "lastVersion");
|
||||||
|
if (lastVersion is null)
|
||||||
|
{
|
||||||
|
shutdown = true;
|
||||||
|
bool setupSuccessfull = false;
|
||||||
|
Console.WriteLine("This seems to be a fresh install. Running setup wizard for you.\n");
|
||||||
|
Cli cli = new(db, guhf, []);
|
||||||
|
setupSuccessfull = cli.SetupWizard();
|
||||||
|
|
||||||
|
if (setupSuccessfull)
|
||||||
|
{
|
||||||
|
// Cli.SetupWizard() takes care of musicLibraryPath and musicThumbnailPath
|
||||||
|
lastVersion = new Global() { Key = "lastVersion", Value = ThisAssembly.Git.Commit };
|
||||||
|
Global lastVersionDate = new Global() { Key = "lastVersionDate", Value = ThisAssembly.Git.CommitDate };
|
||||||
|
Global runs = new Global() { Key = "runs", Value = "0" };
|
||||||
|
Global libraryState = new Global() { Key = "libraryState", Value = "00000000000000000000000000000000" };
|
||||||
|
db.Globals.AddRange(lastVersion, lastVersionDate, runs, libraryState);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Console.WriteLine("Setup wizard failed. Please try running it again using \"Shadow setupWizard\".");
|
||||||
|
|
||||||
|
db.SaveChanges();
|
||||||
|
return shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if running a newer (different) version
|
||||||
|
if (lastVersion.Value != ThisAssembly.Git.Commit)
|
||||||
|
{
|
||||||
|
Global? lastVersionDate = db.Globals.FirstOrDefault(c => c.Key == "lastVersionDate");
|
||||||
|
if (lastVersionDate is not null && String.Compare(lastVersionDate.Value, ThisAssembly.Git.CommitDate) > 0)
|
||||||
|
{
|
||||||
|
// User is running an earlier version of the application.
|
||||||
|
Console.WriteLine("Downgrade detected! Waiting 30 seconds.\n" +
|
||||||
|
"Please consider stopping Shadow in order to avoid accidental data loss!");
|
||||||
|
}
|
||||||
|
Console.WriteLine("Upgrade detected. Make sure you're using the most recent migrations.\n" +
|
||||||
|
"If not, apply them with `dotnet ef database update`.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any user/admin exist. Display appropriate warnings if not.
|
||||||
|
int userCount = db.Users.Count();
|
||||||
|
if (userCount == 0)
|
||||||
|
Console.WriteLine("[Warn]: No user accounts found. Running a server no one can access! Consider creating an account with `Shadow addUser`.");
|
||||||
|
|
||||||
|
int adminCount = db.Users.Count(u => u.IsAdmin());
|
||||||
|
if (adminCount == 0 && userCount > 0)
|
||||||
|
Console.WriteLine("[Warn]: No admin accounts exist. Consider creating one with `Shadow addUser`.");
|
||||||
|
|
||||||
|
// Ensure [Unknown Album], [Unknown Artist] exist
|
||||||
|
Album unknownAlbum = db.Albums.FirstOrDefault(a => a.Name == "[Unknown Album]") ?? new Album()
|
||||||
|
{
|
||||||
|
Name = "[Unknown Album]",
|
||||||
|
Uri = "00000000000000000000000000000000"
|
||||||
|
};
|
||||||
|
|
||||||
|
Artist unknownArtist = db.Artists.FirstOrDefault(a => a.Name == "[Unknown Artist]") ?? new Artist()
|
||||||
|
{
|
||||||
|
Name = "[Unknown Artist]",
|
||||||
|
NormalizedName = "[unknown artist]"
|
||||||
|
};
|
||||||
|
|
||||||
|
// UpdateRange works both as an Add and Update.
|
||||||
|
db.UpdateRange(unknownAlbum, unknownArtist);
|
||||||
|
db.SaveChanges();
|
||||||
|
|
||||||
|
return shutdown;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user