Implemented basic theme feature. Missing are import, export and asset proxy
This commit is contained in:
parent
f57aac4f6c
commit
a67829035e
16 changed files with 1025 additions and 10 deletions
|
@ -16,6 +16,12 @@ public class ConfigV1
|
|||
|
||||
[JsonProperty("Store")] public StoreData Store { get; set; } = new();
|
||||
|
||||
[JsonProperty("Theme")] public ThemeData Theme { get; set; } = new();
|
||||
public class ThemeData
|
||||
{
|
||||
[JsonProperty("EnableDefault")] public bool EnableDefault { get; set; } = true;
|
||||
}
|
||||
|
||||
public class StoreData
|
||||
{
|
||||
[JsonProperty("Currency")]
|
||||
|
|
|
@ -34,6 +34,9 @@ public class DataContext : DbContext
|
|||
// Tickets
|
||||
public DbSet<Ticket> Tickets { get; set; }
|
||||
public DbSet<TicketMessage> TicketMessages { get; set; }
|
||||
|
||||
// Themes
|
||||
public DbSet<Theme> Themes { get; set; }
|
||||
|
||||
public DataContext(ConfigService configService)
|
||||
{
|
||||
|
|
13
Moonlight/App/Database/Entities/Theme.cs
Normal file
13
Moonlight/App/Database/Entities/Theme.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace Moonlight.App.Database.Entities;
|
||||
|
||||
public class Theme
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = "";
|
||||
public string Author { get; set; } = "";
|
||||
public string? DonateUrl { get; set; } = "";
|
||||
public string CssUrl { get; set; } = "";
|
||||
public string? JsUrl { get; set; } = "";
|
||||
|
||||
public bool Enabled { get; set; } = false;
|
||||
}
|
697
Moonlight/App/Database/Migrations/20231222100225_AddThemeModel.Designer.cs
generated
Normal file
697
Moonlight/App/Database/Migrations/20231222100225_AddThemeModel.Designer.cs
generated
Normal file
|
@ -0,0 +1,697 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Moonlight.App.Database;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
[DbContext(typeof(DataContext))]
|
||||
[Migration("20231222100225_AddThemeModel")]
|
||||
partial class AddThemeModel
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AuthorId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AuthorId");
|
||||
|
||||
b.ToTable("Posts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostComment", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AuthorId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("PostId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AuthorId");
|
||||
|
||||
b.HasIndex("PostId");
|
||||
|
||||
b.ToTable("PostComments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostLike", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("PostId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PostId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("PostLikes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.WordFilter", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Filter")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("WordFilters");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Category", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Categories");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Coupon", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Amount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Percent")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Coupons");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("CouponId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CouponId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("CouponUses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Amount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<double>("Value")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("GiftCodes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("GiftCodeId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GiftCodeId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("GiftCodeUses");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("CategoryId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConfigJson")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Duration")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("MaxPerUser")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<double>("Price")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Stock")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CategoryId");
|
||||
|
||||
b.ToTable("Products");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConfigJsonOverride")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Nickname")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("OwnerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ProductId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("RenewAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Suspended")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OwnerId");
|
||||
|
||||
b.HasIndex("ProductId");
|
||||
|
||||
b.ToTable("Services");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("ServiceId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ServiceId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("ServiceShares");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Transaction", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("Price")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<string>("Text")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Transaction");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Theme", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Author")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CssUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DonateUrl")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Enabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("JsUrl")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Themes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Tickets.Ticket", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("CreatorId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Open")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Priority")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("ServiceId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Tries")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("ServiceId");
|
||||
|
||||
b.ToTable("Tickets");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Tickets.TicketMessage", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Attachment")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsSupport")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("SenderId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("TicketId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SenderId");
|
||||
|
||||
b.HasIndex("TicketId");
|
||||
|
||||
b.ToTable("TicketMessages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Avatar")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<double>("Balance")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Flags")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Permissions")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("TokenValidTimestamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("TotpKey")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "Author")
|
||||
.WithMany()
|
||||
.HasForeignKey("AuthorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Author");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostComment", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "Author")
|
||||
.WithMany()
|
||||
.HasForeignKey("AuthorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.Community.Post", null)
|
||||
.WithMany("Comments")
|
||||
.HasForeignKey("PostId");
|
||||
|
||||
b.Navigation("Author");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostLike", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Community.Post", null)
|
||||
.WithMany("Likes")
|
||||
.HasForeignKey("PostId");
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Store.Coupon", "Coupon")
|
||||
.WithMany()
|
||||
.HasForeignKey("CouponId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||
.WithMany("CouponUses")
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("Coupon");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Store.GiftCode", "GiftCode")
|
||||
.WithMany()
|
||||
.HasForeignKey("GiftCodeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||
.WithMany("GiftCodeUses")
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("GiftCode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Store.Category", "Category")
|
||||
.WithMany()
|
||||
.HasForeignKey("CategoryId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Category");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||
.WithMany()
|
||||
.HasForeignKey("OwnerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.Store.Product", "Product")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProductId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Owner");
|
||||
|
||||
b.Navigation("Product");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Store.Service", null)
|
||||
.WithMany("Shares")
|
||||
.HasForeignKey("ServiceId");
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Transaction", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||
.WithMany("Transactions")
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Tickets.Ticket", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "Creator")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.Store.Service", "Service")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServiceId");
|
||||
|
||||
b.Navigation("Creator");
|
||||
|
||||
b.Navigation("Service");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Tickets.TicketMessage", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "Sender")
|
||||
.WithMany()
|
||||
.HasForeignKey("SenderId");
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.Tickets.Ticket", null)
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("TicketId");
|
||||
|
||||
b.Navigation("Sender");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
|
||||
{
|
||||
b.Navigation("Comments");
|
||||
|
||||
b.Navigation("Likes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||
{
|
||||
b.Navigation("Shares");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Tickets.Ticket", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||
{
|
||||
b.Navigation("CouponUses");
|
||||
|
||||
b.Navigation("GiftCodeUses");
|
||||
|
||||
b.Navigation("Transactions");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddThemeModel : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Themes",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
Name = table.Column<string>(type: "TEXT", nullable: false),
|
||||
Author = table.Column<string>(type: "TEXT", nullable: false),
|
||||
DonateUrl = table.Column<string>(type: "TEXT", nullable: true),
|
||||
CssUrl = table.Column<string>(type: "TEXT", nullable: false),
|
||||
JsUrl = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Enabled = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Themes", x => x.Id);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Themes");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -357,6 +357,38 @@ namespace Moonlight.App.Database.Migrations
|
|||
b.ToTable("Transaction");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Theme", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Author")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CssUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DonateUrl")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Enabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("JsUrl")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Themes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Tickets.Ticket", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
|
12
Moonlight/App/Models/Abstractions/ApplicationTheme.cs
Normal file
12
Moonlight/App/Models/Abstractions/ApplicationTheme.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
namespace Moonlight.App.Models.Abstractions;
|
||||
|
||||
public class ApplicationTheme
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public string Author { get; set; } = "";
|
||||
public string? DonateUrl { get; set; } = "";
|
||||
public string CssUrl { get; set; } = "";
|
||||
public string? JsUrl { get; set; } = "";
|
||||
|
||||
public bool Enabled { get; set; } = false;
|
||||
}
|
23
Moonlight/App/Models/Forms/Admin/Sys/Themes/AddThemeForm.cs
Normal file
23
Moonlight/App/Models/Forms/Admin/Sys/Themes/AddThemeForm.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.App.Models.Forms.Admin.Sys.Themes;
|
||||
|
||||
public class AddThemeForm
|
||||
{
|
||||
[Required(ErrorMessage = "You need to specify a name for your theme")]
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
[Required(ErrorMessage = "You need to specify an author for your theme")]
|
||||
public string Author { get; set; } = "";
|
||||
|
||||
[Description("Enter a url to date for your theme here in order to show up when other people use this theme")]
|
||||
public string? DonateUrl { get; set; } = "";
|
||||
|
||||
[Required(ErrorMessage = "You need to specify a style sheet url")]
|
||||
[Description("A url to your stylesheet")]
|
||||
public string CssUrl { get; set; } = "";
|
||||
|
||||
[Description("(Optional) A url to your javascript file")]
|
||||
public string? JsUrl { get; set; } = null;
|
||||
}
|
26
Moonlight/App/Models/Forms/Admin/Sys/Themes/EditThemeForm.cs
Normal file
26
Moonlight/App/Models/Forms/Admin/Sys/Themes/EditThemeForm.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.App.Models.Forms.Admin.Sys.Themes;
|
||||
|
||||
public class EditThemeForm
|
||||
{
|
||||
[Required(ErrorMessage = "You need to specify a name for your theme")]
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
[Required(ErrorMessage = "You need to specify an author for your theme")]
|
||||
public string Author { get; set; } = "";
|
||||
|
||||
[Description("Enter a url to date for your theme here in order to show up when other people use this theme")]
|
||||
public string? DonateUrl { get; set; } = "";
|
||||
|
||||
[Required(ErrorMessage = "You need to specify a style sheet url")]
|
||||
[Description("A url to your stylesheet")]
|
||||
public string CssUrl { get; set; } = "";
|
||||
|
||||
[Description("(Optional) A url to your javascript file")]
|
||||
public string? JsUrl { get; set; } = null;
|
||||
|
||||
[Description("Enable the theme for this instance")]
|
||||
public bool Enabled { get; set; } = false;
|
||||
}
|
|
@ -7,11 +7,15 @@ namespace Moonlight.App.Services.Sys;
|
|||
public class MoonlightService // This service can be used to perform strictly panel specific actions
|
||||
{
|
||||
private readonly ConfigService ConfigService;
|
||||
public WebApplication Application { get; set; } // Do NOT modify using a plugin
|
||||
private readonly IServiceProvider ServiceProvider;
|
||||
|
||||
public MoonlightService(ConfigService configService)
|
||||
public WebApplication Application { get; set; } // Do NOT modify using a plugin
|
||||
public MoonlightThemeService Theme { get; set; }
|
||||
|
||||
public MoonlightService(ConfigService configService, IServiceProvider serviceProvider)
|
||||
{
|
||||
ConfigService = configService;
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public async Task Restart()
|
||||
|
|
57
Moonlight/App/Services/Sys/MoonlightThemeService.cs
Normal file
57
Moonlight/App/Services/Sys/MoonlightThemeService.cs
Normal file
|
@ -0,0 +1,57 @@
|
|||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Abstractions;
|
||||
using Moonlight.App.Repositories;
|
||||
|
||||
namespace Moonlight.App.Services.Sys;
|
||||
|
||||
public class MoonlightThemeService
|
||||
{
|
||||
private readonly IServiceProvider ServiceProvider;
|
||||
private readonly ConfigService ConfigService;
|
||||
|
||||
public MoonlightThemeService(IServiceProvider serviceProvider, ConfigService configService)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
ConfigService = configService;
|
||||
}
|
||||
|
||||
public Task<ApplicationTheme[]> GetInstalled()
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var themeRepo = scope.ServiceProvider.GetRequiredService<Repository<Theme>>();
|
||||
|
||||
var themes = new List<ApplicationTheme>();
|
||||
|
||||
themes.AddRange(themeRepo
|
||||
.Get()
|
||||
.ToArray()
|
||||
.Select(x => new ApplicationTheme()
|
||||
{
|
||||
Name = x.Name,
|
||||
Author = x.Author,
|
||||
CssUrl = x.CssUrl,
|
||||
JsUrl = x.JsUrl,
|
||||
Enabled = x.Enabled,
|
||||
DonateUrl = x.DonateUrl
|
||||
}));
|
||||
|
||||
if (ConfigService.Get().Theme.EnableDefault)
|
||||
{
|
||||
themes.Insert(0, new()
|
||||
{
|
||||
Name = "Moonlight Default",
|
||||
Author = "MasuOwO",
|
||||
Enabled = true,
|
||||
CssUrl = "/css/theme.css",
|
||||
DonateUrl = "https://ko-fi.com/masuowo"
|
||||
});
|
||||
}
|
||||
|
||||
return Task.FromResult(themes.ToArray());
|
||||
}
|
||||
|
||||
public async Task<ApplicationTheme[]> GetEnabled() =>
|
||||
(await GetInstalled())
|
||||
.Where(x => x.Enabled)
|
||||
.ToArray();
|
||||
}
|
|
@ -1,8 +1,15 @@
|
|||
@page "/"
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Moonlight.App.Services.Sys
|
||||
@namespace Moonlight.Pages
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
||||
@inject MoonlightThemeService MoonlightThemeService
|
||||
|
||||
@{
|
||||
var themes = await MoonlightThemeService.GetEnabled();
|
||||
}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<head>
|
||||
|
@ -10,12 +17,17 @@
|
|||
<base href="~/"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Moonlight</title>
|
||||
|
||||
|
||||
<link rel="shortcut icon" href="/img/logo.svg">
|
||||
|
||||
|
||||
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered"/>
|
||||
|
||||
<link href="/css/theme.css" rel="stylesheet" type="text/css"/>
|
||||
|
||||
@foreach (var theme in themes)
|
||||
{
|
||||
<!-- Theme: @(theme.Name) by @(theme.Author) -->
|
||||
<link href="@(theme.CssUrl)" rel="stylesheet" type="text/css"/>
|
||||
}
|
||||
|
||||
<link href="/css/utils.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="/css/blazor.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="/css/boxicons.min.css" rel="stylesheet" type="text/css"/>
|
||||
|
@ -40,6 +52,16 @@
|
|||
<script src="/_content/BlazorTable/BlazorTable.min.js"></script>
|
||||
<script src="/js/sweetalert2.js"></script>
|
||||
<script src="/js/ckeditor.js"></script>
|
||||
|
||||
@foreach (var theme in themes)
|
||||
{
|
||||
if (theme.JsUrl != null)
|
||||
{
|
||||
<!-- Theme: @(theme.Name) by @(theme.Author) -->
|
||||
<script src="@(theme.JsUrl)"></script>
|
||||
}
|
||||
}
|
||||
|
||||
<script src="/_framework/blazor.server.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -19,7 +19,6 @@ using Moonlight.App.Services.Utils;
|
|||
using Serilog;
|
||||
|
||||
var configService = new ConfigService();
|
||||
var moonlightService = new MoonlightService(configService);
|
||||
|
||||
Directory.CreateDirectory(PathBuilder.Dir("storage"));
|
||||
Directory.CreateDirectory(PathBuilder.Dir("storage", "logs"));
|
||||
|
@ -95,7 +94,8 @@ builder.Services.AddSingleton(configService);
|
|||
builder.Services.AddSingleton<SessionService>();
|
||||
builder.Services.AddSingleton<BucketService>();
|
||||
builder.Services.AddSingleton<MailService>();
|
||||
builder.Services.AddSingleton(moonlightService);
|
||||
builder.Services.AddSingleton<MoonlightService>();
|
||||
builder.Services.AddSingleton<MoonlightThemeService>();
|
||||
|
||||
builder.Services.AddRazorPages();
|
||||
builder.Services.AddServerSideBlazor();
|
||||
|
@ -112,7 +112,6 @@ var config =
|
|||
builder.Logging.AddConfiguration(config.Build());
|
||||
|
||||
var app = builder.Build();
|
||||
moonlightService.Application = app;
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
|
@ -124,8 +123,10 @@ app.MapControllers();
|
|||
// Auto start background services
|
||||
app.Services.GetRequiredService<AutoMailSendService>();
|
||||
|
||||
var serviceService = app.Services.GetRequiredService<ServiceDefinitionService>();
|
||||
var moonlightService = app.Services.GetRequiredService<MoonlightService>();
|
||||
moonlightService.Application = app;
|
||||
|
||||
var serviceService = app.Services.GetRequiredService<ServiceDefinitionService>();
|
||||
serviceService.Register<DummyServiceDefinition>(ServiceType.Server);
|
||||
|
||||
await pluginService.RunPrePost(app);
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
<i class="bx bx-sm bx-cog me-2"></i> Settings
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item mt-2">
|
||||
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 2 ? "active" : "")" href="/admin/sys/themes">
|
||||
<i class="bx bx-sm bx-palette me-2"></i> Themes
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
72
Moonlight/Shared/Views/Admin/Sys/Themes.razor
Normal file
72
Moonlight/Shared/Views/Admin/Sys/Themes.razor
Normal file
|
@ -0,0 +1,72 @@
|
|||
@page "/admin/sys/themes"
|
||||
|
||||
@using Moonlight.App.Extensions.Attributes
|
||||
@using Moonlight.App.Models.Enums
|
||||
@using Moonlight.App.Models.Forms.Admin.Sys.Themes
|
||||
@using Moonlight.App.Repositories
|
||||
@using Moonlight.App.Services.Sys
|
||||
@using BlazorTable
|
||||
@using Moonlight.App.Models.Abstractions
|
||||
|
||||
@attribute [RequirePermission(Permission.AdminRoot)]
|
||||
|
||||
@inject MoonlightThemeService MoonlightThemeService
|
||||
|
||||
<AdminSysNavigation Index="2"/>
|
||||
|
||||
<div class="mt-5">
|
||||
<AutoCrud TItem="Theme"
|
||||
TCreateForm="AddThemeForm"
|
||||
TUpdateForm="EditThemeForm"
|
||||
Title="Manage themes"
|
||||
Load="LoadData">
|
||||
<Column TableItem="Theme" Title="Id" Field="@(x => x.Id)" Sortable="true" Filterable="true"/>
|
||||
<Column TableItem="Theme" Title="Name" Field="@(x => x.Name)" Sortable="true" Filterable="true"/>
|
||||
<Column TableItem="Theme" Title="Author" Field="@(x => x.Author)" Sortable="true" Filterable="true"/>
|
||||
<Column TableItem="Theme" Field="@(x => x.Id)" Title="" Filterable="false" Sortable="false">
|
||||
<Template>
|
||||
@if (EnabledThemes
|
||||
.Any(x => x.Name == context.Name && x.Author == context.Author))
|
||||
{
|
||||
<span class="text-success">Enabled</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-muted">Disabled</span>
|
||||
}
|
||||
</Template>
|
||||
</Column>
|
||||
<Column TableItem="Theme" Field="@(x => x.Id)" Title="" Filterable="false" Sortable="false">
|
||||
<Template>
|
||||
<div class="text-end">
|
||||
<div class="btn-group">
|
||||
@if (context.DonateUrl != null)
|
||||
{
|
||||
<a class="btn btn-sm btn-info" href="@(context.DonateUrl)" target="_blank">Donate</a>
|
||||
}
|
||||
<WButton OnClick="() => ExportTheme(context)" Text="Export" CssClasses="btn btn-sm btn-secondary"/>
|
||||
</div>
|
||||
</div>
|
||||
</Template>
|
||||
</Column>
|
||||
<Pager ShowPageNumber="true" ShowTotalCount="true" AlwaysShow="true"/>
|
||||
</AutoCrud>
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
private ApplicationTheme[] EnabledThemes;
|
||||
|
||||
private Theme[] LoadData(Repository<Theme> repository)
|
||||
{
|
||||
// No async => .Result needs to be used. :c
|
||||
EnabledThemes = MoonlightThemeService.GetEnabled().Result;
|
||||
|
||||
return repository.Get().ToArray();
|
||||
}
|
||||
|
||||
private Task ExportTheme(Theme theme)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
3
Moonlight/wwwroot/css/demotheme.css
vendored
Normal file
3
Moonlight/wwwroot/css/demotheme.css
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
body {
|
||||
background-color: #0d8ddc !important;
|
||||
}
|
Loading…
Reference in a new issue