Added support chat. Added resource service. Added server backups
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -442,3 +442,4 @@ Moonlight/obj/Moonlight.csproj.nuget.dgspec.json
|
|||||||
Moonlight/obj/project.assets.json
|
Moonlight/obj/project.assets.json
|
||||||
Moonlight/obj/project.nuget.cache
|
Moonlight/obj/project.nuget.cache
|
||||||
Moonlight/obj/project.packagespec.json
|
Moonlight/obj/project.packagespec.json
|
||||||
|
Moonlight/obj/Debug/net6.0/Moonlight.GeneratedMSBuildEditorConfig.editorconfig
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public class DataContext : DbContext
|
|||||||
public DbSet<LoadingMessage> LoadingMessages { get; set; }
|
public DbSet<LoadingMessage> LoadingMessages { get; set; }
|
||||||
public DbSet<AuditLogEntry> AuditLog { get; set; }
|
public DbSet<AuditLogEntry> AuditLog { get; set; }
|
||||||
public DbSet<Entities.Database> Databases { get; set; }
|
public DbSet<Entities.Database> Databases { get; set; }
|
||||||
|
public DbSet<SupportMessage> SupportMessages { get; set; }
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
|
|||||||
17
Moonlight/App/Database/Entities/SupportMessage.cs
Normal file
17
Moonlight/App/Database/Entities/SupportMessage.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using Moonlight.App.Models.Misc;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
public class SupportMessage
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Message { get; set; } = "";
|
||||||
|
public User? Sender { get; set; } = null;
|
||||||
|
public User? Recipient { get; set; } = null;
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
public bool IsQuestion { get; set; } = false;
|
||||||
|
public QuestionType Type { get; set; }
|
||||||
|
public string Answer { get; set; } = "";
|
||||||
|
public bool IsSystem { get; set; } = false;
|
||||||
|
public bool IsSupport { get; set; } = false;
|
||||||
|
}
|
||||||
@@ -14,13 +14,14 @@ public class User
|
|||||||
public string State { get; set; } = "";
|
public string State { get; set; } = "";
|
||||||
public string Country { get; set; } = "";
|
public string Country { get; set; } = "";
|
||||||
public UserStatus Status { get; set; } = UserStatus.Unverified;
|
public UserStatus Status { get; set; } = UserStatus.Unverified;
|
||||||
public bool TotpEnabled { get; set; }
|
public bool TotpEnabled { get; set; } = false;
|
||||||
public string TotpSecret { get; set; } = "";
|
public string TotpSecret { get; set; } = "";
|
||||||
public DateTime TokenValidTime { get; set; } = DateTime.Now;
|
public DateTime TokenValidTime { get; set; } = DateTime.Now;
|
||||||
public long DiscordId { get; set; }
|
public long DiscordId { get; set; } = -1;
|
||||||
public string DiscordUsername { get; set; } = "";
|
public string DiscordUsername { get; set; } = "";
|
||||||
public string DiscordDiscriminator { get; set; } = "";
|
public string DiscordDiscriminator { get; set; } = "";
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
public DateTime UpdatedAt { get; set; }
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||||
public bool Admin { get; set; }
|
public bool Admin { get; set; } = false;
|
||||||
|
public bool SupportPending { get; set; } = false;
|
||||||
}
|
}
|
||||||
617
Moonlight/App/Database/Migrations/20230221173242_AddSupportMessage.Designer.cs
generated
Normal file
617
Moonlight/App/Database/Migrations/20230221173242_AddSupportMessage.Designer.cs
generated
Normal file
@@ -0,0 +1,617 @@
|
|||||||
|
// <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("20230221173242_AddSupportMessage")]
|
||||||
|
partial class AddSupportMessage
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "7.0.3")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.AuditLogEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Ip")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("JsonData")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("System")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("AuditLog");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("AaPanelId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.ToTable("Databases");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("Default")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
|
b.ToTable("DockerImages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigFiles")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("InstallDockerImage")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("InstallEntrypoint")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("InstallScript")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Startup")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("StartupDetection")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("StopCommand")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<Guid>("Uuid")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Images");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
|
b.ToTable("ImageTags");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("DefaultValue")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
|
b.ToTable("ImageVariables");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.LoadingMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("LoadingMessages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Fqdn")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("HttpPort")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("MoonlightDaemonPort")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("SftpPort")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("Ssl")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Token")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("TokenId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Nodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("NodeId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Port")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NodeId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("NodeAllocations");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Cpu")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<long>("Disk")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<int>("DockerImageIndex")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("ImageId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("Installing")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<int>("MainAllocationId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<long>("Memory")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("NodeId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("OverrideStartup")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("Suspended")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<Guid>("Uuid")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
|
b.HasIndex("MainAllocationId");
|
||||||
|
|
||||||
|
b.HasIndex("NodeId");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.ToTable("Servers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerBackup", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<long>("Bytes")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<bool>("Created")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<Guid>("Uuid")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("ServerBackups");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("ServerVariables");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Answer")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsQuestion")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("SenderId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SenderId");
|
||||||
|
|
||||||
|
b.ToTable("SupportMessages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("Admin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("DiscordDiscriminator")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<long>("DiscordId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("DiscordUsername")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("FirstName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("State")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TokenValidTime")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<bool>("TotpEnabled")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("TotpSecret")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Image", null)
|
||||||
|
.WithMany("DockerImages")
|
||||||
|
.HasForeignKey("ImageId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Image", null)
|
||||||
|
.WithMany("Tags")
|
||||||
|
.HasForeignKey("ImageId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Image", null)
|
||||||
|
.WithMany("Variables")
|
||||||
|
.HasForeignKey("ImageId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Node", null)
|
||||||
|
.WithMany("Allocations")
|
||||||
|
.HasForeignKey("NodeId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Server", null)
|
||||||
|
.WithMany("Allocations")
|
||||||
|
.HasForeignKey("ServerId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Image", "Image")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ImageId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.NodeAllocation", "MainAllocation")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("MainAllocationId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Node", "Node")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("NodeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Image");
|
||||||
|
|
||||||
|
b.Navigation("MainAllocation");
|
||||||
|
|
||||||
|
b.Navigation("Node");
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerBackup", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Server", null)
|
||||||
|
.WithMany("Backups")
|
||||||
|
.HasForeignKey("ServerId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Server", null)
|
||||||
|
.WithMany("Variables")
|
||||||
|
.HasForeignKey("ServerId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Sender")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("SenderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Sender");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("DockerImages");
|
||||||
|
|
||||||
|
b.Navigation("Tags");
|
||||||
|
|
||||||
|
b.Navigation("Variables");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Allocations");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Allocations");
|
||||||
|
|
||||||
|
b.Navigation("Backups");
|
||||||
|
|
||||||
|
b.Navigation("Variables");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddSupportMessage : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SupportMessages",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Message = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
SenderId = table.Column<int>(type: "int", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
IsQuestion = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||||
|
Type = table.Column<int>(type: "int", nullable: false),
|
||||||
|
Answer = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SupportMessages", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SupportMessages_Users_SenderId",
|
||||||
|
column: x => x.SenderId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SupportMessages_SenderId",
|
||||||
|
table: "SupportMessages",
|
||||||
|
column: "SenderId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SupportMessages");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -374,6 +374,50 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.ToTable("ServerVariables");
|
b.ToTable("ServerVariables");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Answer")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsQuestion")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSupport")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSystem")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("RecipientId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("SenderId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RecipientId");
|
||||||
|
|
||||||
|
b.HasIndex("SenderId");
|
||||||
|
|
||||||
|
b.ToTable("SupportMessages");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -432,6 +476,9 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.Property<int>("Status")
|
b.Property<int>("Status")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("SupportPending")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
b.Property<DateTime>("TokenValidTime")
|
b.Property<DateTime>("TokenValidTime")
|
||||||
.HasColumnType("datetime(6)");
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
@@ -542,6 +589,21 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
.HasForeignKey("ServerId");
|
.HasForeignKey("ServerId");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Recipient")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RecipientId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Sender")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("SenderId");
|
||||||
|
|
||||||
|
b.Navigation("Recipient");
|
||||||
|
|
||||||
|
b.Navigation("Sender");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("DockerImages");
|
b.Navigation("DockerImages");
|
||||||
|
|||||||
635
Moonlight/App/Databse/Migrations/20230221183730_UpdatedSupportAndUserModel.Designer.cs
generated
Normal file
635
Moonlight/App/Databse/Migrations/20230221183730_UpdatedSupportAndUserModel.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 Moonlight.App.Database;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Databse.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20230221183730_UpdatedSupportAndUserModel")]
|
||||||
|
partial class UpdatedSupportAndUserModel
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "7.0.3")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.AuditLogEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Ip")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("JsonData")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("System")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("AuditLog");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("AaPanelId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.ToTable("Databases");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("Default")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
|
b.ToTable("DockerImages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigFiles")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("InstallDockerImage")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("InstallEntrypoint")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("InstallScript")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Startup")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("StartupDetection")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("StopCommand")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<Guid>("Uuid")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Images");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
|
b.ToTable("ImageTags");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("DefaultValue")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ImageId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
|
b.ToTable("ImageVariables");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.LoadingMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("LoadingMessages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Fqdn")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("HttpPort")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("MoonlightDaemonPort")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("SftpPort")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("Ssl")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Token")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("TokenId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Nodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("NodeId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Port")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NodeId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("NodeAllocations");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Cpu")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<long>("Disk")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<int>("DockerImageIndex")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("ImageId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("Installing")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<int>("MainAllocationId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<long>("Memory")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("NodeId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("OverrideStartup")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("Suspended")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<Guid>("Uuid")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ImageId");
|
||||||
|
|
||||||
|
b.HasIndex("MainAllocationId");
|
||||||
|
|
||||||
|
b.HasIndex("NodeId");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.ToTable("Servers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerBackup", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<long>("Bytes")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<bool>("Created")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<Guid>("Uuid")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("ServerBackups");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("ServerVariables");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Answer")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsQuestion")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSupport")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSystem")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("RecipientId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("SenderId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RecipientId");
|
||||||
|
|
||||||
|
b.HasIndex("SenderId");
|
||||||
|
|
||||||
|
b.ToTable("SupportMessages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("Admin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("DiscordDiscriminator")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<long>("DiscordId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("DiscordUsername")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("FirstName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("State")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("SupportPending")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TokenValidTime")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<bool>("TotpEnabled")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("TotpSecret")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Image", null)
|
||||||
|
.WithMany("DockerImages")
|
||||||
|
.HasForeignKey("ImageId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Image", null)
|
||||||
|
.WithMany("Tags")
|
||||||
|
.HasForeignKey("ImageId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Image", null)
|
||||||
|
.WithMany("Variables")
|
||||||
|
.HasForeignKey("ImageId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Node", null)
|
||||||
|
.WithMany("Allocations")
|
||||||
|
.HasForeignKey("NodeId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Server", null)
|
||||||
|
.WithMany("Allocations")
|
||||||
|
.HasForeignKey("ServerId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Image", "Image")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ImageId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.NodeAllocation", "MainAllocation")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("MainAllocationId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Node", "Node")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("NodeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Image");
|
||||||
|
|
||||||
|
b.Navigation("MainAllocation");
|
||||||
|
|
||||||
|
b.Navigation("Node");
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerBackup", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Server", null)
|
||||||
|
.WithMany("Backups")
|
||||||
|
.HasForeignKey("ServerId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Server", null)
|
||||||
|
.WithMany("Variables")
|
||||||
|
.HasForeignKey("ServerId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Recipient")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RecipientId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Sender")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("SenderId");
|
||||||
|
|
||||||
|
b.Navigation("Recipient");
|
||||||
|
|
||||||
|
b.Navigation("Sender");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("DockerImages");
|
||||||
|
|
||||||
|
b.Navigation("Tags");
|
||||||
|
|
||||||
|
b.Navigation("Variables");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Allocations");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Allocations");
|
||||||
|
|
||||||
|
b.Navigation("Backups");
|
||||||
|
|
||||||
|
b.Navigation("Variables");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Databse.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class UpdatedSupportAndUserModel : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_SupportMessages_Users_SenderId",
|
||||||
|
table: "SupportMessages");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "SupportPending",
|
||||||
|
table: "Users",
|
||||||
|
type: "tinyint(1)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "SenderId",
|
||||||
|
table: "SupportMessages",
|
||||||
|
type: "int",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "int");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsSupport",
|
||||||
|
table: "SupportMessages",
|
||||||
|
type: "tinyint(1)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsSystem",
|
||||||
|
table: "SupportMessages",
|
||||||
|
type: "tinyint(1)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "RecipientId",
|
||||||
|
table: "SupportMessages",
|
||||||
|
type: "int",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SupportMessages_RecipientId",
|
||||||
|
table: "SupportMessages",
|
||||||
|
column: "RecipientId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_SupportMessages_Users_RecipientId",
|
||||||
|
table: "SupportMessages",
|
||||||
|
column: "RecipientId",
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_SupportMessages_Users_SenderId",
|
||||||
|
table: "SupportMessages",
|
||||||
|
column: "SenderId",
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_SupportMessages_Users_RecipientId",
|
||||||
|
table: "SupportMessages");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_SupportMessages_Users_SenderId",
|
||||||
|
table: "SupportMessages");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_SupportMessages_RecipientId",
|
||||||
|
table: "SupportMessages");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "SupportPending",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsSupport",
|
||||||
|
table: "SupportMessages");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsSystem",
|
||||||
|
table: "SupportMessages");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "RecipientId",
|
||||||
|
table: "SupportMessages");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "SenderId",
|
||||||
|
table: "SupportMessages",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0,
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "int",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_SupportMessages_Users_SenderId",
|
||||||
|
table: "SupportMessages",
|
||||||
|
column: "SenderId",
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace Moonlight.App.Helpers;
|
using Moonlight.App.Services;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
public static class Formatter
|
public static class Formatter
|
||||||
{
|
{
|
||||||
@@ -34,4 +36,32 @@ public static class Formatter
|
|||||||
return (i / (1024D * 1024D)).Round(2) + " GB";
|
return (i / (1024D * 1024D)).Round(2) + " GB";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string FormatAgoFromDateTime(DateTime dt, SmartTranslateService translateService = null)
|
||||||
|
{
|
||||||
|
TimeSpan timeSince = DateTime.UtcNow.Subtract(dt);
|
||||||
|
|
||||||
|
if (timeSince.TotalMilliseconds < 1)
|
||||||
|
return translateService == null ? "just now" : translateService.Translate("just now");
|
||||||
|
|
||||||
|
if (timeSince.TotalMinutes < 1)
|
||||||
|
return translateService == null ? "less than a minute ago" : translateService.Translate("less than a minute ago");
|
||||||
|
|
||||||
|
if (timeSince.TotalMinutes < 2)
|
||||||
|
return translateService == null ? "1 minute ago" : translateService.Translate("1 minute ago");
|
||||||
|
|
||||||
|
if (timeSince.TotalMinutes < 60)
|
||||||
|
return Math.Round(timeSince.TotalMinutes) + (translateService == null ? " minutes ago" : translateService.Translate(" minutes ago"));
|
||||||
|
|
||||||
|
if (timeSince.TotalHours < 2)
|
||||||
|
return translateService == null ? "1 hour ago" : translateService.Translate("1 hour ago");
|
||||||
|
|
||||||
|
if (timeSince.TotalHours < 24)
|
||||||
|
return Math.Round(timeSince.TotalHours) + (translateService == null ? " hours ago" : translateService.Translate(" hours ago"));
|
||||||
|
|
||||||
|
if (timeSince.TotalDays < 2)
|
||||||
|
return translateService == null ? "1 day ago" : translateService.Translate("1 day ago");
|
||||||
|
|
||||||
|
return Math.Round(timeSince.TotalDays) + (translateService == null ? " days ago" : translateService.Translate(" days ago"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Moonlight.App.Http.Requests.Wings;
|
||||||
|
using Moonlight.App.Repositories;
|
||||||
|
using Moonlight.App.Repositories.Servers;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Http.Controllers.Api.Remote;
|
||||||
|
|
||||||
|
[Route("api/remote/backups")]
|
||||||
|
[ApiController]
|
||||||
|
public class BackupController : Controller
|
||||||
|
{
|
||||||
|
private readonly ServerBackupRepository ServerBackupRepository;
|
||||||
|
private readonly MessageService MessageService;
|
||||||
|
private readonly NodeRepository NodeRepository;
|
||||||
|
|
||||||
|
public BackupController(
|
||||||
|
ServerBackupRepository serverBackupRepository,
|
||||||
|
NodeRepository nodeRepository,
|
||||||
|
MessageService messageService)
|
||||||
|
{
|
||||||
|
ServerBackupRepository = serverBackupRepository;
|
||||||
|
NodeRepository = nodeRepository;
|
||||||
|
MessageService = messageService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{uuid}")]
|
||||||
|
public ActionResult<string> Download(Guid uuid)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{uuid}")]
|
||||||
|
public async Task<ActionResult> SetStatus([FromRoute] Guid uuid, [FromBody] ReportBackupCompleteRequest request)
|
||||||
|
{
|
||||||
|
var tokenData = Request.Headers.Authorization.ToString().Replace("Bearer ", "");
|
||||||
|
var id = tokenData.Split(".")[0];
|
||||||
|
var token = tokenData.Split(".")[1];
|
||||||
|
|
||||||
|
var node = NodeRepository.Get().FirstOrDefault(x => x.TokenId == id);
|
||||||
|
|
||||||
|
if (node == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (token != node.Token)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
var backup = ServerBackupRepository.Get().FirstOrDefault(x => x.Uuid == uuid);
|
||||||
|
|
||||||
|
if (backup == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (request.Successful)
|
||||||
|
{
|
||||||
|
backup.Created = true;
|
||||||
|
backup.Bytes = request.Size;
|
||||||
|
|
||||||
|
ServerBackupRepository.Update(backup);
|
||||||
|
|
||||||
|
await MessageService.Emit($"wings.backups.create", backup);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await MessageService.Emit($"wings.backups.createfailed", backup);
|
||||||
|
ServerBackupRepository.Delete(backup);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{uuid}/restore")]
|
||||||
|
public async Task<ActionResult> SetRestoreStatus([FromRoute] Guid uuid)
|
||||||
|
{
|
||||||
|
var tokenData = Request.Headers.Authorization.ToString().Replace("Bearer ", "");
|
||||||
|
var id = tokenData.Split(".")[0];
|
||||||
|
var token = tokenData.Split(".")[1];
|
||||||
|
|
||||||
|
var node = NodeRepository.Get().FirstOrDefault(x => x.TokenId == id);
|
||||||
|
|
||||||
|
if (node == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (token != node.Token)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
var backup = ServerBackupRepository.Get().FirstOrDefault(x => x.Uuid == uuid);
|
||||||
|
|
||||||
|
if (backup == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
await MessageService.Emit($"wings.backups.restore", backup);
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
115
Moonlight/App/Http/Controllers/Api/Remote/SftpAuthController.cs
Normal file
115
Moonlight/App/Http/Controllers/Api/Remote/SftpAuthController.cs
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Moonlight.App.Http.Requests.Wings;
|
||||||
|
using Moonlight.App.Http.Resources.Wings;
|
||||||
|
using Moonlight.App.Repositories;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Http.Controllers.Api.Remote;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/remote/sftp/auth")]
|
||||||
|
public class SftpAuthController : Controller
|
||||||
|
{
|
||||||
|
private readonly ServerService ServerService;
|
||||||
|
private readonly NodeRepository NodeRepository;
|
||||||
|
|
||||||
|
public SftpAuthController(
|
||||||
|
ServerService serverService,
|
||||||
|
NodeRepository nodeRepository)
|
||||||
|
{
|
||||||
|
ServerService = serverService;
|
||||||
|
NodeRepository = nodeRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<ActionResult<SftpLoginResult>> Login(SftpLoginRequest request)
|
||||||
|
{
|
||||||
|
var tokenData = Request.Headers.Authorization.ToString().Replace("Bearer ", "");
|
||||||
|
var tokenId = tokenData.Split(".")[0];
|
||||||
|
var token = tokenData.Split(".")[1];
|
||||||
|
|
||||||
|
var node = NodeRepository.Get().FirstOrDefault(x => x.TokenId == tokenId);
|
||||||
|
|
||||||
|
if (node == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
if (token != node.Token)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
if (request.Type == "public_key") // Deny public key authentication, because moonlight does not implement that
|
||||||
|
{
|
||||||
|
return StatusCode(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the username
|
||||||
|
var parts = request.Username.Split(".");
|
||||||
|
|
||||||
|
if (parts.Length < 2)
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
if (!int.TryParse(parts[0], out int id))
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
if (!int.TryParse(parts[1], out int serverId))
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var server = await ServerService.SftpServerLogin(serverId, id, request.Password);
|
||||||
|
|
||||||
|
return Ok(new SftpLoginResult()
|
||||||
|
{
|
||||||
|
Server = server.Uuid.ToString(),
|
||||||
|
User = "",
|
||||||
|
Permissions = new()
|
||||||
|
{
|
||||||
|
"control.console",
|
||||||
|
"control.start",
|
||||||
|
"control.stop",
|
||||||
|
"control.restart",
|
||||||
|
"websocket.connect",
|
||||||
|
"file.create",
|
||||||
|
"file.read",
|
||||||
|
"file.read-content",
|
||||||
|
"file.update",
|
||||||
|
"file.delete",
|
||||||
|
"file.archive",
|
||||||
|
"file.sftp",
|
||||||
|
"user.create",
|
||||||
|
"user.read",
|
||||||
|
"user.update",
|
||||||
|
"user.delete",
|
||||||
|
"backup.create",
|
||||||
|
"backup.read",
|
||||||
|
"backup.delete",
|
||||||
|
"backup.download",
|
||||||
|
"backup.restore",
|
||||||
|
"allocation.read",
|
||||||
|
"allocation.create",
|
||||||
|
"allocation.update",
|
||||||
|
"allocation.delete",
|
||||||
|
"startup.read",
|
||||||
|
"startup.update",
|
||||||
|
"startup.docker-image",
|
||||||
|
"database.create",
|
||||||
|
"database.read",
|
||||||
|
"database.update",
|
||||||
|
"database.delete",
|
||||||
|
"database.view_password",
|
||||||
|
"schedule.create",
|
||||||
|
"schedule.read",
|
||||||
|
"schedule.update",
|
||||||
|
"schedule.delete",
|
||||||
|
"settings.rename",
|
||||||
|
"settings.reinstall"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Most of the exception here will be because of stuff like a invalid server id and simular things
|
||||||
|
// so we ignore them and return 403
|
||||||
|
return StatusCode(403);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
Moonlight/App/Models/Misc/QuestionType.cs
Normal file
6
Moonlight/App/Models/Misc/QuestionType.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Moonlight.App.Models.Misc;
|
||||||
|
|
||||||
|
public enum QuestionType
|
||||||
|
{
|
||||||
|
ServerUrl
|
||||||
|
}
|
||||||
44
Moonlight/App/Repositories/SupportMessageRepository.cs
Normal file
44
Moonlight/App/Repositories/SupportMessageRepository.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Repositories;
|
||||||
|
|
||||||
|
public class SupportMessageRepository : IDisposable
|
||||||
|
{
|
||||||
|
private readonly DataContext DataContext;
|
||||||
|
|
||||||
|
public SupportMessageRepository(DataContext dataContext)
|
||||||
|
{
|
||||||
|
DataContext = dataContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbSet<SupportMessage> Get()
|
||||||
|
{
|
||||||
|
return DataContext.SupportMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SupportMessage Add(SupportMessage message)
|
||||||
|
{
|
||||||
|
var x = DataContext.SupportMessages.Add(message);
|
||||||
|
DataContext.SaveChanges();
|
||||||
|
return x.Entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(SupportMessage message)
|
||||||
|
{
|
||||||
|
DataContext.SupportMessages.Update(message);
|
||||||
|
DataContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(SupportMessage message)
|
||||||
|
{
|
||||||
|
DataContext.SupportMessages.Remove(message);
|
||||||
|
DataContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
DataContext.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
23
Moonlight/App/Services/ResourceService.cs
Normal file
23
Moonlight/App/Services/ResourceService.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Services;
|
||||||
|
|
||||||
|
public class ResourceService
|
||||||
|
{
|
||||||
|
private readonly string AppUrl;
|
||||||
|
|
||||||
|
public ResourceService(ConfigService configService)
|
||||||
|
{
|
||||||
|
AppUrl = configService.GetSection("Moonlight").GetValue<string>("AppUrl");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Image(string name)
|
||||||
|
{
|
||||||
|
return $"{AppUrl}/api/moonlight/resources/images/{name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Avatar(User user)
|
||||||
|
{
|
||||||
|
return $"{AppUrl}/api/moonlight/avatar/{user.Id}";
|
||||||
|
}
|
||||||
|
}
|
||||||
67
Moonlight/App/Services/Support/SupportAdminServer.cs
Normal file
67
Moonlight/App/Services/Support/SupportAdminServer.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Services.Sessions;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Services.Support;
|
||||||
|
|
||||||
|
public class SupportAdminServer
|
||||||
|
{
|
||||||
|
private readonly SupportServerService SupportServerService;
|
||||||
|
private readonly IdentityService IdentityService;
|
||||||
|
private readonly MessageService MessageService;
|
||||||
|
|
||||||
|
public EventHandler<SupportMessage> OnNewMessage;
|
||||||
|
|
||||||
|
private User Self;
|
||||||
|
private User Recipient;
|
||||||
|
|
||||||
|
public SupportAdminServer(
|
||||||
|
SupportServerService supportServerService,
|
||||||
|
IdentityService identityService,
|
||||||
|
MessageService messageService)
|
||||||
|
{
|
||||||
|
SupportServerService = supportServerService;
|
||||||
|
IdentityService = identityService;
|
||||||
|
MessageService = messageService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Start(User user)
|
||||||
|
{
|
||||||
|
Self = (await IdentityService.Get())!;
|
||||||
|
Recipient = user;
|
||||||
|
|
||||||
|
MessageService.Subscribe<SupportClientService, SupportMessage>(
|
||||||
|
$"support.{Recipient.Id}.message",
|
||||||
|
this,
|
||||||
|
message =>
|
||||||
|
{
|
||||||
|
OnNewMessage?.Invoke(this, message);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SupportMessage[]> GetMessages()
|
||||||
|
{
|
||||||
|
return await SupportServerService.GetMessages(Recipient);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendMessage(string content)
|
||||||
|
{
|
||||||
|
var message = new SupportMessage()
|
||||||
|
{
|
||||||
|
Message = content
|
||||||
|
};
|
||||||
|
|
||||||
|
await SupportServerService.SendMessage(
|
||||||
|
Recipient,
|
||||||
|
message,
|
||||||
|
Self,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
MessageService.Unsubscribe($"support.{Recipient.Id}.message", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
64
Moonlight/App/Services/Support/SupportClientService.cs
Normal file
64
Moonlight/App/Services/Support/SupportClientService.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Services.Sessions;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Services.Support;
|
||||||
|
|
||||||
|
public class SupportClientService : IDisposable
|
||||||
|
{
|
||||||
|
private readonly SupportServerService SupportServerService;
|
||||||
|
private readonly IdentityService IdentityService;
|
||||||
|
private readonly MessageService MessageService;
|
||||||
|
|
||||||
|
public EventHandler<SupportMessage> OnNewMessage;
|
||||||
|
|
||||||
|
private User Self;
|
||||||
|
|
||||||
|
public SupportClientService(
|
||||||
|
SupportServerService supportServerService,
|
||||||
|
IdentityService identityService,
|
||||||
|
MessageService messageService)
|
||||||
|
{
|
||||||
|
SupportServerService = supportServerService;
|
||||||
|
IdentityService = identityService;
|
||||||
|
MessageService = messageService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Start()
|
||||||
|
{
|
||||||
|
Self = (await IdentityService.Get())!;
|
||||||
|
|
||||||
|
MessageService.Subscribe<SupportClientService, SupportMessage>(
|
||||||
|
$"support.{Self.Id}.message",
|
||||||
|
this,
|
||||||
|
message =>
|
||||||
|
{
|
||||||
|
OnNewMessage?.Invoke(this, message);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SupportMessage[]> GetMessages()
|
||||||
|
{
|
||||||
|
return await SupportServerService.GetMessages(Self);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendMessage(string content)
|
||||||
|
{
|
||||||
|
var message = new SupportMessage()
|
||||||
|
{
|
||||||
|
Message = content
|
||||||
|
};
|
||||||
|
|
||||||
|
await SupportServerService.SendMessage(
|
||||||
|
Self,
|
||||||
|
message,
|
||||||
|
Self
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
MessageService.Unsubscribe($"support.{Self.Id}.message", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
104
Moonlight/App/Services/Support/SupportServerService.cs
Normal file
104
Moonlight/App/Services/Support/SupportServerService.cs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
using Logging.Net;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Repositories;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Services.Support;
|
||||||
|
|
||||||
|
public class SupportServerService : IDisposable
|
||||||
|
{
|
||||||
|
private SupportMessageRepository SupportMessageRepository;
|
||||||
|
private MessageService MessageService;
|
||||||
|
private UserRepository UserRepository;
|
||||||
|
private readonly IServiceScopeFactory ServiceScopeFactory;
|
||||||
|
private IServiceScope ServiceScope;
|
||||||
|
|
||||||
|
public SupportServerService(IServiceScopeFactory serviceScopeFactory)
|
||||||
|
{
|
||||||
|
ServiceScopeFactory = serviceScopeFactory;
|
||||||
|
|
||||||
|
Task.Run(Run);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendMessage(User r, SupportMessage message, User s, bool isSupport = false)
|
||||||
|
{
|
||||||
|
var recipient = UserRepository.Get().First(x => x.Id == r.Id);
|
||||||
|
var sender = UserRepository.Get().First(x => x.Id == s.Id);
|
||||||
|
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
message.CreatedAt = DateTime.UtcNow;
|
||||||
|
message.Sender = sender;
|
||||||
|
message.Recipient = recipient;
|
||||||
|
message.IsSupport = isSupport;
|
||||||
|
|
||||||
|
SupportMessageRepository.Add(message);
|
||||||
|
|
||||||
|
await MessageService.Emit($"support.{recipient.Id}.message", message);
|
||||||
|
|
||||||
|
if (!recipient.SupportPending)
|
||||||
|
{
|
||||||
|
recipient.SupportPending = true;
|
||||||
|
UserRepository.Update(recipient);
|
||||||
|
|
||||||
|
var systemMessage = new SupportMessage()
|
||||||
|
{
|
||||||
|
Recipient = recipient,
|
||||||
|
Sender = null,
|
||||||
|
IsSystem = true,
|
||||||
|
Message = "The support team has been notified. Please be patient"
|
||||||
|
};
|
||||||
|
|
||||||
|
SupportMessageRepository.Add(systemMessage);
|
||||||
|
|
||||||
|
await MessageService.Emit($"support.{recipient.Id}.message", systemMessage);
|
||||||
|
|
||||||
|
Logger.Info("Support ticket created: " + recipient.Id);
|
||||||
|
//TODO: Ping or so
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<SupportMessage[]> GetMessages(User r)
|
||||||
|
{
|
||||||
|
var recipient = UserRepository.Get().First(x => x.Id == r.Id);
|
||||||
|
|
||||||
|
var messages = SupportMessageRepository
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.Recipient)
|
||||||
|
.Include(x => x.Sender)
|
||||||
|
.Where(x => x.Recipient.Id == recipient.Id)
|
||||||
|
.AsEnumerable()
|
||||||
|
.TakeLast(50)
|
||||||
|
.OrderBy(x => x.Id)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return Task.FromResult(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task Run()
|
||||||
|
{
|
||||||
|
ServiceScope = ServiceScopeFactory.CreateScope();
|
||||||
|
|
||||||
|
SupportMessageRepository = ServiceScope
|
||||||
|
.ServiceProvider
|
||||||
|
.GetRequiredService<SupportMessageRepository>();
|
||||||
|
|
||||||
|
MessageService = ServiceScope
|
||||||
|
.ServiceProvider
|
||||||
|
.GetRequiredService<MessageService>();
|
||||||
|
|
||||||
|
UserRepository = ServiceScope
|
||||||
|
.ServiceProvider
|
||||||
|
.GetRequiredService<UserRepository>();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
SupportMessageRepository.Dispose();
|
||||||
|
UserRepository.Dispose();
|
||||||
|
ServiceScope.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,7 @@
|
|||||||
<Folder Include="App\Http\Middleware" />
|
<Folder Include="App\Http\Middleware" />
|
||||||
<Folder Include="App\Models\AuditLogData" />
|
<Folder Include="App\Models\AuditLogData" />
|
||||||
<Folder Include="resources\lang" />
|
<Folder Include="resources\lang" />
|
||||||
|
<Folder Include="Shared\Views\Admin\Support" />
|
||||||
<Folder Include="wwwroot\assets\media" />
|
<Folder Include="wwwroot\assets\media" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Moonlight.App.Repositories.Servers;
|
|||||||
using Moonlight.App.Services;
|
using Moonlight.App.Services;
|
||||||
using Moonlight.App.Services.Interop;
|
using Moonlight.App.Services.Interop;
|
||||||
using Moonlight.App.Services.Sessions;
|
using Moonlight.App.Services.Sessions;
|
||||||
|
using Moonlight.App.Services.Support;
|
||||||
|
|
||||||
namespace Moonlight
|
namespace Moonlight
|
||||||
{
|
{
|
||||||
@@ -36,6 +37,7 @@ namespace Moonlight
|
|||||||
builder.Services.AddScoped<AuditLogRepository>();
|
builder.Services.AddScoped<AuditLogRepository>();
|
||||||
builder.Services.AddScoped<DatabaseRepository>();
|
builder.Services.AddScoped<DatabaseRepository>();
|
||||||
builder.Services.AddScoped<ImageRepository>();
|
builder.Services.AddScoped<ImageRepository>();
|
||||||
|
builder.Services.AddScoped<SupportMessageRepository>();
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
builder.Services.AddSingleton<ConfigService>();
|
builder.Services.AddSingleton<ConfigService>();
|
||||||
@@ -53,10 +55,16 @@ namespace Moonlight
|
|||||||
builder.Services.AddScoped<ServerService>();
|
builder.Services.AddScoped<ServerService>();
|
||||||
builder.Services.AddSingleton<PaperService>();
|
builder.Services.AddSingleton<PaperService>();
|
||||||
builder.Services.AddScoped<ClipboardService>();
|
builder.Services.AddScoped<ClipboardService>();
|
||||||
|
builder.Services.AddSingleton<ResourceService>();
|
||||||
|
|
||||||
builder.Services.AddScoped<AuditLogService>();
|
builder.Services.AddScoped<AuditLogService>();
|
||||||
builder.Services.AddScoped<SystemAuditLogService>();
|
builder.Services.AddScoped<SystemAuditLogService>();
|
||||||
|
|
||||||
|
// Support
|
||||||
|
builder.Services.AddSingleton<SupportServerService>();
|
||||||
|
builder.Services.AddScoped<SupportAdminServer>();
|
||||||
|
builder.Services.AddScoped<SupportClientService>();
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
builder.Services.AddSingleton<SmartTranslateHelper>();
|
builder.Services.AddSingleton<SmartTranslateHelper>();
|
||||||
builder.Services.AddScoped<WingsApiHelper>();
|
builder.Services.AddScoped<WingsApiHelper>();
|
||||||
@@ -89,6 +97,9 @@ namespace Moonlight
|
|||||||
app.MapBlazorHub();
|
app.MapBlazorHub();
|
||||||
app.MapFallbackToPage("/_Host");
|
app.MapFallbackToPage("/_Host");
|
||||||
|
|
||||||
|
// Support service
|
||||||
|
var supportServerService = app.Services.GetRequiredService<SupportServerService>();
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,7 @@
|
|||||||
<SidebarMenu></SidebarMenu>
|
<SidebarMenu></SidebarMenu>
|
||||||
|
|
||||||
<div class="app-sidebar-footer flex-column-auto pt-2 pb-6 px-6" id="kt_app_sidebar_footer">
|
<div class="app-sidebar-footer flex-column-auto pt-2 pb-6 px-6" id="kt_app_sidebar_footer">
|
||||||
<a id="support_ticket_toggle_sidebar"
|
<a href="/support" class="btn btn-flex flex-center btn-custom btn-primary overflow-hidden text-nowrap px-0 h-40px w-100 btn-label">
|
||||||
class="btn btn-flex flex-center btn-custom btn-primary overflow-hidden text-nowrap px-0 h-40px w-100 btn-label">
|
|
||||||
<TL>Open support</TL>
|
<TL>Open support</TL>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
@using Moonlight.App.Database.Entities
|
@using Moonlight.App.Database.Entities
|
||||||
@using Moonlight.App.Extensions
|
@using Moonlight.App.Extensions
|
||||||
@using Moonlight.App.Models.Misc
|
@using Moonlight.App.Models.Misc
|
||||||
|
@using Moonlight.App.Services
|
||||||
|
@using Moonlight.App.Services.Interop
|
||||||
@using Moonlight.App.Services.Sessions
|
@using Moonlight.App.Services.Sessions
|
||||||
|
|
||||||
@layout ThemeInit
|
@layout ThemeInit
|
||||||
@@ -15,6 +17,8 @@
|
|||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@inject SessionService SessionService
|
@inject SessionService SessionService
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject MessageService MessageService
|
||||||
|
@inject ToastService ToastService
|
||||||
|
|
||||||
<GlobalErrorBoundary>
|
<GlobalErrorBoundary>
|
||||||
@{
|
@{
|
||||||
@@ -151,10 +155,21 @@
|
|||||||
await SessionService.Register();
|
await SessionService.Register();
|
||||||
|
|
||||||
NavigationManager.LocationChanged += (sender, args) => { SessionService.Refresh(); };
|
NavigationManager.LocationChanged += (sender, args) => { SessionService.Refresh(); };
|
||||||
|
|
||||||
|
MessageService.Subscribe<MainLayout, SupportMessage>(
|
||||||
|
$"support.{User.Id}.message",
|
||||||
|
this,
|
||||||
|
async message =>
|
||||||
|
{
|
||||||
|
if (!NavigationManager.Uri.EndsWith("/support") && (message.IsSupport || message.IsSystem))
|
||||||
|
{
|
||||||
|
await ToastService.Info($"Support: {message.Message}");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,6 +177,11 @@
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
SessionService.Close();
|
SessionService.Close();
|
||||||
|
|
||||||
|
if (User != null)
|
||||||
|
{
|
||||||
|
MessageService.Unsubscribe($"support.{User.Id}.message", this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddBodyAttribute(string attribute, string value)
|
private void AddBodyAttribute(string attribute, string value)
|
||||||
|
|||||||
135
Moonlight/Shared/Views/Admin/Index.razor
Normal file
135
Moonlight/Shared/Views/Admin/Index.razor
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
@page "/admin"
|
||||||
|
@using Moonlight.App.Repositories.Servers
|
||||||
|
@using Moonlight.App.Repositories
|
||||||
|
|
||||||
|
@inject ServerRepository ServerRepository
|
||||||
|
@inject DatabaseRepository DatabaseRepository
|
||||||
|
@inject UserRepository UserRepository
|
||||||
|
|
||||||
|
<OnlyAdmin>
|
||||||
|
<LazyLoader Load="Load">
|
||||||
|
<div class="row mb-5">
|
||||||
|
<div class="col-12 col-lg-6 col-xl">
|
||||||
|
<a class="mt-4 card" href="/servers">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row align-items-center gx-0">
|
||||||
|
<div class="col">
|
||||||
|
<h6 class="text-uppercase text-muted mb-2">
|
||||||
|
<TL>Servers</TL>
|
||||||
|
</h6>
|
||||||
|
<span class="h2 mb-0">
|
||||||
|
@(ServerCount)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<span class="h2 text-muted mb-0">
|
||||||
|
<i class="text-primary bx bx-server bx-lg"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-6 col-xl">
|
||||||
|
<a class="mt-4 card" href="/websites">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row align-items-center gx-0">
|
||||||
|
<div class="col">
|
||||||
|
<h6 class="text-uppercase text-muted mb-2">
|
||||||
|
<TL>Websites</TL>
|
||||||
|
</h6>
|
||||||
|
<span class="h2 mb-0">
|
||||||
|
0
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<span class="h2 text-muted mb-0">
|
||||||
|
<i class="text-primary bx bx-globe bx-lg"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-6 col-xl">
|
||||||
|
<div class="mt-4 card" href="/databases">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row align-items-center gx-0">
|
||||||
|
<div class="col">
|
||||||
|
<h6 class="text-uppercase text-muted mb-2">
|
||||||
|
<TL>Databases</TL>
|
||||||
|
</h6>
|
||||||
|
<span class="h2 mb-0">
|
||||||
|
@(DatabaseCount)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<span class="h2 text-muted mb-0">
|
||||||
|
<i class="text-primary bx bx-data bx-lg"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-6 col-xl">
|
||||||
|
<a class="mt-4 card" href="/domains">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row align-items-center gx-0">
|
||||||
|
<div class="col">
|
||||||
|
<h6 class="text-uppercase text-muted mb-2">
|
||||||
|
<TL>Domains</TL>
|
||||||
|
</h6>
|
||||||
|
<span class="h2 mb-0">
|
||||||
|
0
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<span class="h2 text-muted mb-">
|
||||||
|
<i class="text-primary bx bx-purchase-tag bx-lg"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-6 col-xl">
|
||||||
|
<a class="mt-4 card" href="/domains">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row align-items-center gx-0">
|
||||||
|
<div class="col">
|
||||||
|
<h6 class="text-uppercase text-muted mb-2">
|
||||||
|
<TL>Users</TL>
|
||||||
|
</h6>
|
||||||
|
<span class="h2 mb-0">
|
||||||
|
@(UserCount)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<span class="h2 text-muted mb-">
|
||||||
|
<i class="text-primary bx bx-user bx-lg"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</LazyLoader>
|
||||||
|
</OnlyAdmin>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
private int DatabaseCount = 0;
|
||||||
|
private int ServerCount = 0;
|
||||||
|
private int UserCount = 0;
|
||||||
|
|
||||||
|
private Task Load(LazyLoader lazyLoader)
|
||||||
|
{
|
||||||
|
DatabaseCount = DatabaseRepository.Get().Count();
|
||||||
|
ServerCount = ServerRepository.Get().Count();
|
||||||
|
UserCount = UserRepository.Get().Count();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
144
Moonlight/Shared/Views/Support.razor
Normal file
144
Moonlight/Shared/Views/Support.razor
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
@page "/support"
|
||||||
|
@using Moonlight.App.Services
|
||||||
|
@using Moonlight.App.Services.Sessions
|
||||||
|
@using Moonlight.App.Database.Entities
|
||||||
|
@using Moonlight.App.Helpers
|
||||||
|
@using Moonlight.App.Services.Support
|
||||||
|
|
||||||
|
@inject ResourceService ResourceService
|
||||||
|
@inject IdentityService IdentityService
|
||||||
|
@inject SupportClientService SupportClientService
|
||||||
|
@inject SmartTranslateService SmartTranslateService
|
||||||
|
|
||||||
|
<LazyLoader Load="Load">
|
||||||
|
<div class="row">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="scroll-y me-n5 pe-5" style="max-height: 65vh; display: flex; flex-direction: column-reverse;">
|
||||||
|
@foreach (var message in Messages)
|
||||||
|
{
|
||||||
|
if (message.IsSystem || message.IsSupport)
|
||||||
|
{
|
||||||
|
<div class="d-flex justify-content-start mb-10 ">
|
||||||
|
<div class="d-flex flex-column align-items-start">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<div class="symbol symbol-35px symbol-circle ">
|
||||||
|
<img alt="Logo" src="@(ResourceService.Image("logo.svg"))">
|
||||||
|
</div>
|
||||||
|
<div class="ms-3">
|
||||||
|
<a class="fs-5 fw-bold text-gray-900 text-hover-primary me-1">
|
||||||
|
@if (message.IsSupport && !message.IsSystem)
|
||||||
|
{
|
||||||
|
<span>@(message.Sender!.FirstName) @(message.Sender!.LastName)</span>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span>System</span>
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
<span class="text-muted fs-7 mb-1">@(Formatter.FormatAgoFromDateTime(message.CreatedAt, SmartTranslateService))</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-5 rounded bg-light-info text-dark fw-semibold mw-lg-400px text-start">
|
||||||
|
@(message.Message)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="d-flex justify-content-end mb-10 ">
|
||||||
|
<div class="d-flex flex-column align-items-end">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<div class="me-3">
|
||||||
|
<span class="text-muted fs-7 mb-1">@(Formatter.FormatAgoFromDateTime(message.CreatedAt, SmartTranslateService))</span>
|
||||||
|
<a class="fs-5 fw-bold text-gray-900 text-hover-primary ms-1">
|
||||||
|
<span>@(message.Sender!.FirstName) @(message.Sender!.LastName)</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="symbol symbol-35px symbol-circle ">
|
||||||
|
<img alt="Avatar" src="@(ResourceService.Avatar(message.Sender))">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-5 rounded bg-light-primary text-dark fw-semibold mw-lg-400px text-end">
|
||||||
|
@(message.Message)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<div class="d-flex justify-content-start mb-10 ">
|
||||||
|
<div class="d-flex flex-column align-items-start">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<div class="symbol symbol-35px symbol-circle ">
|
||||||
|
<img alt="Logo" src="@(ResourceService.Image("logo.svg"))">
|
||||||
|
</div>
|
||||||
|
<div class="ms-3">
|
||||||
|
<a class="fs-5 fw-bold text-gray-900 text-hover-primary me-1">
|
||||||
|
<span>System</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-5 rounded bg-light-info text-dark fw-semibold mw-lg-400px text-start">
|
||||||
|
<TL>Welcome to the support chat. Ask your question here and we will help you</TL>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<textarea @bind="Content" class="form-control form-control-flush mb-3" rows="1" placeholder="Type a message">
|
||||||
|
</textarea>
|
||||||
|
<div class="d-flex flex-stack">
|
||||||
|
<div class="d-flex align-items-center me-2">
|
||||||
|
<button class="btn btn-sm btn-icon btn-active-light-primary me-1" type="button">
|
||||||
|
<i class="bx bx-upload fs-3"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<WButton Text="@(SmartTranslateService.Translate("Send"))"
|
||||||
|
WorkingText="@(SmartTranslateService.Translate("Sending"))"
|
||||||
|
CssClasses="btn-primary"
|
||||||
|
OnClick="Send">
|
||||||
|
</WButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</LazyLoader>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
private User User;
|
||||||
|
|
||||||
|
private SupportMessage[] Messages;
|
||||||
|
private string Content = "";
|
||||||
|
|
||||||
|
private async Task Load(LazyLoader lazyLoader)
|
||||||
|
{
|
||||||
|
User = (await IdentityService.Get())!;
|
||||||
|
|
||||||
|
await lazyLoader.SetText("Starting chat client");
|
||||||
|
|
||||||
|
SupportClientService.OnNewMessage += OnNewMessage;
|
||||||
|
|
||||||
|
await SupportClientService.Start();
|
||||||
|
|
||||||
|
Messages = (await SupportClientService.GetMessages()).Reverse().ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void OnNewMessage(object? sender, SupportMessage e)
|
||||||
|
{
|
||||||
|
Messages = (await SupportClientService.GetMessages()).Reverse().ToArray();
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Send()
|
||||||
|
{
|
||||||
|
await SupportClientService.SendMessage(Content);
|
||||||
|
Content = "";
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -167,6 +167,10 @@ build_metadata.AdditionalFiles.CssScope =
|
|||||||
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXExheW91dHNcVGhlbWVJbml0LnJhem9y
|
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXExheW91dHNcVGhlbWVJbml0LnJhem9y
|
||||||
build_metadata.AdditionalFiles.CssScope =
|
build_metadata.AdditionalFiles.CssScope =
|
||||||
|
|
||||||
|
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Views/Admin/Index.razor]
|
||||||
|
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXEluZGV4LnJhem9y
|
||||||
|
build_metadata.AdditionalFiles.CssScope =
|
||||||
|
|
||||||
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Views/Admin/Nodes/Edit.razor]
|
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Views/Admin/Nodes/Edit.razor]
|
||||||
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXE5vZGVzXEVkaXQucmF6b3I=
|
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXE5vZGVzXEVkaXQucmF6b3I=
|
||||||
build_metadata.AdditionalFiles.CssScope =
|
build_metadata.AdditionalFiles.CssScope =
|
||||||
@@ -223,6 +227,10 @@ build_metadata.AdditionalFiles.CssScope =
|
|||||||
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXFNldHVwXFVzZXJzLnJhem9y
|
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXFNldHVwXFVzZXJzLnJhem9y
|
||||||
build_metadata.AdditionalFiles.CssScope =
|
build_metadata.AdditionalFiles.CssScope =
|
||||||
|
|
||||||
|
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Views/Support.razor]
|
||||||
|
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXFN1cHBvcnQucmF6b3I=
|
||||||
|
build_metadata.AdditionalFiles.CssScope =
|
||||||
|
|
||||||
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/_Imports.razor]
|
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/_Imports.razor]
|
||||||
build_metadata.AdditionalFiles.TargetPath = X0ltcG9ydHMucmF6b3I=
|
build_metadata.AdditionalFiles.TargetPath = X0ltcG9ydHMucmF6b3I=
|
||||||
build_metadata.AdditionalFiles.CssScope =
|
build_metadata.AdditionalFiles.CssScope =
|
||||||
|
|||||||
@@ -193,3 +193,25 @@ Running;Running
|
|||||||
Loading backups;Loading backups
|
Loading backups;Loading backups
|
||||||
Started backup creation;Started backup creation
|
Started backup creation;Started backup creation
|
||||||
Backup is going to be created;Backup is going to be created
|
Backup is going to be created;Backup is going to be created
|
||||||
|
Rename;Rename
|
||||||
|
Move;Move
|
||||||
|
Archive;Archive
|
||||||
|
Unarchive;Unarchive
|
||||||
|
Download;Download
|
||||||
|
Starting download;Starting download
|
||||||
|
Backup successfully created;Backup successfully created
|
||||||
|
Restore;Restore
|
||||||
|
Copy url;Copy url
|
||||||
|
Backup deletion started;Backup deletion started
|
||||||
|
Backup successfully deleted;Backup successfully deleted
|
||||||
|
Primary;Primary
|
||||||
|
This feature is currently not available;This feature is currently not available
|
||||||
|
Send;Send
|
||||||
|
Sending;Sending
|
||||||
|
Welcome to the support chat. Ask your question here and we will help you;Welcome to the support chat. Ask your question here and we will help you
|
||||||
|
minutes ago; minutes ago
|
||||||
|
just now;just now
|
||||||
|
less than a minute ago;less than a minute ago
|
||||||
|
1 hour ago;1 hour ago
|
||||||
|
1 minute ago;1 minute ago
|
||||||
|
Failed;Failed
|
||||||
|
|||||||
Reference in New Issue
Block a user