Merge branch 'main' into DiscordBot
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Database.Entities.LogsEntries;
|
||||
using Moonlight.App.Database.Entities.Notification;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Services;
|
||||
|
||||
namespace Moonlight.App.Database;
|
||||
@@ -34,14 +35,13 @@ public class DataContext : DbContext
|
||||
|
||||
public DbSet<SharedDomain> SharedDomains { get; set; }
|
||||
public DbSet<Domain> Domains { get; set; }
|
||||
public DbSet<Subscription> Subscriptions { get; set; }
|
||||
public DbSet<SubscriptionLimit> SubscriptionLimits { get; set; }
|
||||
public DbSet<Revoke> Revokes { get; set; }
|
||||
public DbSet<NotificationClient> NotificationClients { get; set; }
|
||||
public DbSet<NotificationAction> NotificationActions { get; set; }
|
||||
public DbSet<AaPanel> AaPanels { get; set; }
|
||||
public DbSet<Website> Websites { get; set; }
|
||||
public DbSet<DdosAttack> DdosAttacks { get; set; }
|
||||
public DbSet<Subscription> Subscriptions { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
|
||||
public class Domain
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
public SharedDomain SharedDomain { get; set; }
|
||||
public User Owner { get; set; }
|
||||
|
||||
@@ -20,4 +20,5 @@ public class Server
|
||||
public NodeAllocation MainAllocation { get; set; } = null!;
|
||||
public Node Node { get; set; } = null!;
|
||||
public User Owner { get; set; } = null!;
|
||||
public bool IsCleanupException { get; set; } = false;
|
||||
}
|
||||
@@ -5,7 +5,5 @@ public class Subscription
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = "";
|
||||
public string Description { get; set; } = "";
|
||||
public string SellPassId { get; set; } = "";
|
||||
public int Duration { get; set; }
|
||||
public List<SubscriptionLimit> Limits { get; set; } = new();
|
||||
public string LimitsJson { get; set; } = "";
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
|
||||
public class SubscriptionLimit
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public Image Image { get; set; } = null!;
|
||||
public int Amount { get; set; }
|
||||
public int Cpu { get; set; }
|
||||
public int Memory { get; set; }
|
||||
public int Disk { get; set; }
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Moonlight.App.Models.Misc;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Moonlight.App.Models.Misc;
|
||||
|
||||
namespace Moonlight.App.Database.Entities;
|
||||
|
||||
@@ -7,14 +8,21 @@ public class User
|
||||
public int Id { get; set; }
|
||||
|
||||
// Personal data
|
||||
|
||||
|
||||
public string FirstName { get; set; } = "";
|
||||
|
||||
public string LastName { get; set; } = "";
|
||||
|
||||
public string Email { get; set; } = "";
|
||||
|
||||
public string Password { get; set; } = "";
|
||||
|
||||
public string Address { get; set; } = "";
|
||||
|
||||
public string City { get; set; } = "";
|
||||
|
||||
public string State { get; set; } = "";
|
||||
|
||||
public string Country { get; set; } = "";
|
||||
|
||||
// States
|
||||
@@ -34,9 +42,10 @@ public class User
|
||||
// Date stuff
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
|
||||
// Subscriptions
|
||||
public Subscription? Subscription { get; set; } = null;
|
||||
public DateTime? SubscriptionSince { get; set; }
|
||||
|
||||
public Subscription? CurrentSubscription { get; set; } = null;
|
||||
public DateTime SubscriptionSince { get; set; } = DateTime.Now;
|
||||
public int SubscriptionDuration { get; set; }
|
||||
}
|
||||
1082
Moonlight/App/Database/Migrations/20230402204329_AddCleanupExceptionsTable.Designer.cs
generated
Normal file
1082
Moonlight/App/Database/Migrations/20230402204329_AddCleanupExceptionsTable.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,170 @@
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddCleanupExceptionsTable : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "State",
|
||||
table: "Users",
|
||||
type: "varchar(64)",
|
||||
maxLength: 64,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext")
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "LastName",
|
||||
table: "Users",
|
||||
type: "varchar(64)",
|
||||
maxLength: 64,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext")
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "FirstName",
|
||||
table: "Users",
|
||||
type: "varchar(64)",
|
||||
maxLength: 64,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext")
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Country",
|
||||
table: "Users",
|
||||
type: "varchar(64)",
|
||||
maxLength: 64,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext")
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "City",
|
||||
table: "Users",
|
||||
type: "varchar(128)",
|
||||
maxLength: 128,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext")
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Address",
|
||||
table: "Users",
|
||||
type: "varchar(128)",
|
||||
maxLength: 128,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext")
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CleanupExceptions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
ServerId = table.Column<int>(type: "int", nullable: false),
|
||||
Note = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CleanupExceptions", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "CleanupExceptions");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "State",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(64)",
|
||||
oldMaxLength: 64)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "LastName",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(64)",
|
||||
oldMaxLength: 64)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "FirstName",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(64)",
|
||||
oldMaxLength: 64)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Country",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(64)",
|
||||
oldMaxLength: 64)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "City",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(128)",
|
||||
oldMaxLength: 128)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Address",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(128)",
|
||||
oldMaxLength: 128)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
}
|
||||
}
|
||||
1098
Moonlight/App/Database/Migrations/20230402215155_ChengedCleanupExceptionModel.Designer.cs
generated
Normal file
1098
Moonlight/App/Database/Migrations/20230402215155_ChengedCleanupExceptionModel.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ChengedCleanupExceptionModel : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "CreatedAt",
|
||||
table: "CleanupExceptions",
|
||||
type: "datetime(6)",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CleanupExceptions_ServerId",
|
||||
table: "CleanupExceptions",
|
||||
column: "ServerId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_CleanupExceptions_Servers_ServerId",
|
||||
table: "CleanupExceptions",
|
||||
column: "ServerId",
|
||||
principalTable: "Servers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_CleanupExceptions_Servers_ServerId",
|
||||
table: "CleanupExceptions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_CleanupExceptions_ServerId",
|
||||
table: "CleanupExceptions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CreatedAt",
|
||||
table: "CleanupExceptions");
|
||||
}
|
||||
}
|
||||
}
|
||||
1067
Moonlight/App/Database/Migrations/20230402220651_RemovedCleanupExceptionChangedServerModel.Designer.cs
generated
Normal file
1067
Moonlight/App/Database/Migrations/20230402220651_RemovedCleanupExceptionChangedServerModel.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class RemovedCleanupExceptionChangedServerModel : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "CleanupExceptions");
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "IsCleanupException",
|
||||
table: "Servers",
|
||||
type: "tinyint(1)",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IsCleanupException",
|
||||
table: "Servers");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CleanupExceptions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
ServerId = table.Column<int>(type: "int", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
Note = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CleanupExceptions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_CleanupExceptions_Servers_ServerId",
|
||||
column: x => x.ServerId,
|
||||
principalTable: "Servers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CleanupExceptions_ServerId",
|
||||
table: "CleanupExceptions",
|
||||
column: "ServerId");
|
||||
}
|
||||
}
|
||||
}
|
||||
962
Moonlight/App/Database/Migrations/20230403130734_RemovedOldSubscriptionData.Designer.cs
generated
Normal file
962
Moonlight/App/Database/Migrations/20230403130734_RemovedOldSubscriptionData.Designer.cs
generated
Normal file
@@ -0,0 +1,962 @@
|
||||
// <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("20230403130734_RemovedOldSubscriptionData")]
|
||||
partial class RemovedOldSubscriptionData
|
||||
{
|
||||
/// <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.AaPanel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("BaseDomain")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("AaPanels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("AaPanelId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("InternalAaPanelId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("OwnerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AaPanelId");
|
||||
|
||||
b.HasIndex("OwnerId");
|
||||
|
||||
b.ToTable("Databases");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.DdosAttack", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<long>("Data")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("Ip")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("NodeId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("Ongoing")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NodeId");
|
||||
|
||||
b.ToTable("DdosAttacks");
|
||||
});
|
||||
|
||||
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.Domain", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("OwnerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SharedDomainId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OwnerId");
|
||||
|
||||
b.HasIndex("SharedDomainId");
|
||||
|
||||
b.ToTable("Domains");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Allocations")
|
||||
.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<string>("TagsJson")
|
||||
.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<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
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.LogsEntries.AuditLogEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
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.LogsEntries.ErrorLogEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Class")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Ip")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("JsonData")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Stacktrace")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("System")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ErrorLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.SecurityLogEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
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("SecurityLog");
|
||||
});
|
||||
|
||||
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.Notification.NotificationAction", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Action")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("NotificationClientId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NotificationClientId");
|
||||
|
||||
b.ToTable("NotificationActions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Notification.NotificationClient", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("NotificationClients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Revoke", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Identifier")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Revokes");
|
||||
});
|
||||
|
||||
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<bool>("IsCleanupException")
|
||||
.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.SharedDomain", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("CloudflareId")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SharedDomains");
|
||||
});
|
||||
|
||||
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<long>("DiscordId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
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.Website", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("AaPanelId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("DomainName")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("FtpPassword")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("FtpUsername")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("InternalAaPanelId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("OwnerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("PhpVersion")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AaPanelId");
|
||||
|
||||
b.HasIndex("OwnerId");
|
||||
|
||||
b.ToTable("Websites");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.AaPanel", "AaPanel")
|
||||
.WithMany()
|
||||
.HasForeignKey("AaPanelId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||
.WithMany()
|
||||
.HasForeignKey("OwnerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AaPanel");
|
||||
|
||||
b.Navigation("Owner");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.DdosAttack", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Node", "Node")
|
||||
.WithMany()
|
||||
.HasForeignKey("NodeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Node");
|
||||
});
|
||||
|
||||
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.Domain", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||
.WithMany()
|
||||
.HasForeignKey("OwnerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.SharedDomain", "SharedDomain")
|
||||
.WithMany()
|
||||
.HasForeignKey("SharedDomainId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Owner");
|
||||
|
||||
b.Navigation("SharedDomain");
|
||||
});
|
||||
|
||||
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.Notification.NotificationAction", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Notification.NotificationClient", "NotificationClient")
|
||||
.WithMany()
|
||||
.HasForeignKey("NotificationClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("NotificationClient");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Notification.NotificationClient", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
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.Website", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.AaPanel", "AaPanel")
|
||||
.WithMany()
|
||||
.HasForeignKey("AaPanelId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||
.WithMany()
|
||||
.HasForeignKey("OwnerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AaPanel");
|
||||
|
||||
b.Navigation("Owner");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
|
||||
{
|
||||
b.Navigation("DockerImages");
|
||||
|
||||
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,269 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class RemovedOldSubscriptionData : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Users_Subscriptions_SubscriptionId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "SubscriptionLimits");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Subscriptions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Users_SubscriptionId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SubscriptionDuration",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SubscriptionId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SubscriptionSince",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "State",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(64)",
|
||||
oldMaxLength: 64)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "LastName",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(64)",
|
||||
oldMaxLength: 64)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "FirstName",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(64)",
|
||||
oldMaxLength: 64)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Country",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(64)",
|
||||
oldMaxLength: 64)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "City",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(128)",
|
||||
oldMaxLength: 128)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Address",
|
||||
table: "Users",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(128)",
|
||||
oldMaxLength: 128)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "State",
|
||||
table: "Users",
|
||||
type: "varchar(64)",
|
||||
maxLength: 64,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext")
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "LastName",
|
||||
table: "Users",
|
||||
type: "varchar(64)",
|
||||
maxLength: 64,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext")
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "FirstName",
|
||||
table: "Users",
|
||||
type: "varchar(64)",
|
||||
maxLength: 64,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext")
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Country",
|
||||
table: "Users",
|
||||
type: "varchar(64)",
|
||||
maxLength: 64,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext")
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "City",
|
||||
table: "Users",
|
||||
type: "varchar(128)",
|
||||
maxLength: 128,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext")
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Address",
|
||||
table: "Users",
|
||||
type: "varchar(128)",
|
||||
maxLength: 128,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext")
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "SubscriptionDuration",
|
||||
table: "Users",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "SubscriptionId",
|
||||
table: "Users",
|
||||
type: "int",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "SubscriptionSince",
|
||||
table: "Users",
|
||||
type: "datetime(6)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Subscriptions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
Description = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
Duration = table.Column<int>(type: "int", nullable: false),
|
||||
Name = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
SellPassId = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Subscriptions", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "SubscriptionLimits",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
ImageId = table.Column<int>(type: "int", nullable: false),
|
||||
Amount = table.Column<int>(type: "int", nullable: false),
|
||||
Cpu = table.Column<int>(type: "int", nullable: false),
|
||||
Disk = table.Column<int>(type: "int", nullable: false),
|
||||
Memory = table.Column<int>(type: "int", nullable: false),
|
||||
SubscriptionId = table.Column<int>(type: "int", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_SubscriptionLimits", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_SubscriptionLimits_Images_ImageId",
|
||||
column: x => x.ImageId,
|
||||
principalTable: "Images",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_SubscriptionLimits_Subscriptions_SubscriptionId",
|
||||
column: x => x.SubscriptionId,
|
||||
principalTable: "Subscriptions",
|
||||
principalColumn: "Id");
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Users_SubscriptionId",
|
||||
table: "Users",
|
||||
column: "SubscriptionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_SubscriptionLimits_ImageId",
|
||||
table: "SubscriptionLimits",
|
||||
column: "ImageId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_SubscriptionLimits_SubscriptionId",
|
||||
table: "SubscriptionLimits",
|
||||
column: "SubscriptionId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Users_Subscriptions_SubscriptionId",
|
||||
table: "Users",
|
||||
column: "SubscriptionId",
|
||||
principalTable: "Subscriptions",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
}
|
||||
}
|
||||
1005
Moonlight/App/Database/Migrations/20230403131343_AddedNewSubscriptionData.Designer.cs
generated
Normal file
1005
Moonlight/App/Database/Migrations/20230403131343_AddedNewSubscriptionData.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddedNewSubscriptionData : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "CurrentSubscriptionId",
|
||||
table: "Users",
|
||||
type: "int",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "SubscriptionDuration",
|
||||
table: "Users",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "SubscriptionSince",
|
||||
table: "Users",
|
||||
type: "datetime(6)",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Subscriptions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
Name = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
Description = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
LimitsJson = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Subscriptions", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Users_CurrentSubscriptionId",
|
||||
table: "Users",
|
||||
column: "CurrentSubscriptionId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Users_Subscriptions_CurrentSubscriptionId",
|
||||
table: "Users",
|
||||
column: "CurrentSubscriptionId",
|
||||
principalTable: "Subscriptions",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Users_Subscriptions_CurrentSubscriptionId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Subscriptions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Users_CurrentSubscriptionId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CurrentSubscriptionId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SubscriptionDuration",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SubscriptionSince",
|
||||
table: "Users");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -482,6 +482,9 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.Property<bool>("Installing")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<bool>("IsCleanupException")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("MainAllocationId")
|
||||
.HasColumnType("int");
|
||||
|
||||
@@ -606,14 +609,11 @@ namespace Moonlight.App.Database.Migrations
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Duration")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
b.Property<string>("LimitsJson")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("SellPassId")
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
@@ -622,39 +622,6 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.ToTable("Subscriptions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.SubscriptionLimit", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Amount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Cpu")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Disk")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ImageId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Memory")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("SubscriptionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ImageId");
|
||||
|
||||
b.HasIndex("SubscriptionId");
|
||||
|
||||
b.ToTable("SubscriptionLimits");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -723,6 +690,9 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<int?>("CurrentSubscriptionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("DiscordId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
@@ -752,10 +722,7 @@ namespace Moonlight.App.Database.Migrations
|
||||
b.Property<int>("SubscriptionDuration")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("SubscriptionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime?>("SubscriptionSince")
|
||||
b.Property<DateTime>("SubscriptionSince")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<bool>("SupportPending")
|
||||
@@ -776,7 +743,7 @@ namespace Moonlight.App.Database.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SubscriptionId");
|
||||
b.HasIndex("CurrentSubscriptionId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
@@ -966,21 +933,6 @@ namespace Moonlight.App.Database.Migrations
|
||||
.HasForeignKey("ServerId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.SubscriptionLimit", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Image", "Image")
|
||||
.WithMany()
|
||||
.HasForeignKey("ImageId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.Subscription", null)
|
||||
.WithMany("Limits")
|
||||
.HasForeignKey("SubscriptionId");
|
||||
|
||||
b.Navigation("Image");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "Recipient")
|
||||
@@ -998,11 +950,11 @@ namespace Moonlight.App.Database.Migrations
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Subscription", "Subscription")
|
||||
b.HasOne("Moonlight.App.Database.Entities.Subscription", "CurrentSubscription")
|
||||
.WithMany()
|
||||
.HasForeignKey("SubscriptionId");
|
||||
.HasForeignKey("CurrentSubscriptionId");
|
||||
|
||||
b.Navigation("Subscription");
|
||||
b.Navigation("CurrentSubscription");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Website", b =>
|
||||
@@ -1044,11 +996,6 @@ namespace Moonlight.App.Database.Migrations
|
||||
|
||||
b.Navigation("Variables");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Subscription", b =>
|
||||
{
|
||||
b.Navigation("Limits");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
|
||||
11
Moonlight/App/Helpers/FieldCssHelper.cs
Normal file
11
Moonlight/App/Helpers/FieldCssHelper.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
|
||||
namespace Moonlight.App.Helpers;
|
||||
|
||||
public class FieldCssHelper : FieldCssClassProvider
|
||||
{
|
||||
public override string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier)
|
||||
{
|
||||
return editContext.GetValidationMessages(fieldIdentifier).Any() ? "is-invalid" : "is-valid";
|
||||
}
|
||||
}
|
||||
8
Moonlight/App/Helpers/Files/ContextAction.cs
Normal file
8
Moonlight/App/Helpers/Files/ContextAction.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Moonlight.App.Helpers.Files;
|
||||
|
||||
public class ContextAction
|
||||
{
|
||||
public string Id { get; set; } = "";
|
||||
public string Name { get; set; } = "";
|
||||
public Action<FileData> Action { get; set; }
|
||||
}
|
||||
24
Moonlight/App/Helpers/Files/FileAccess.cs
Normal file
24
Moonlight/App/Helpers/Files/FileAccess.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Moonlight.App.Helpers.Files;
|
||||
|
||||
public abstract class FileAccess : ICloneable
|
||||
{
|
||||
public string CurrentPath { get; set; } = "/";
|
||||
|
||||
public abstract Task<FileData[]> Ls();
|
||||
public abstract Task Cd(string dir);
|
||||
public abstract Task Up();
|
||||
public abstract Task SetDir(string dir);
|
||||
public abstract Task<string> Read(FileData fileData);
|
||||
public abstract Task Write(FileData fileData, string content);
|
||||
public abstract Task Upload(string name, Stream stream, Action<int>? progressUpdated = null);
|
||||
public abstract Task MkDir(string name);
|
||||
public abstract Task<string> Pwd();
|
||||
public abstract Task<string> DownloadUrl(FileData fileData);
|
||||
public abstract Task<Stream> DownloadStream(FileData fileData);
|
||||
public abstract Task Delete(FileData fileData);
|
||||
public abstract Task Move(FileData fileData, string newPath);
|
||||
public abstract Task Compress(params FileData[] files);
|
||||
public abstract Task Decompress(FileData fileData);
|
||||
public abstract Task<string> GetLaunchUrl();
|
||||
public abstract object Clone();
|
||||
}
|
||||
8
Moonlight/App/Helpers/Files/FileData.cs
Normal file
8
Moonlight/App/Helpers/Files/FileData.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Moonlight.App.Helpers.Files;
|
||||
|
||||
public class FileData
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public long Size { get; set; }
|
||||
public bool IsFile { get; set; }
|
||||
}
|
||||
232
Moonlight/App/Helpers/Files/WingsFileAccess.cs
Normal file
232
Moonlight/App/Helpers/Files/WingsFileAccess.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
using System.Web;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Wings.Requests;
|
||||
using Moonlight.App.Models.Wings.Resources;
|
||||
using Moonlight.App.Services;
|
||||
using RestSharp;
|
||||
|
||||
namespace Moonlight.App.Helpers.Files;
|
||||
|
||||
public class WingsFileAccess : FileAccess
|
||||
{
|
||||
private readonly WingsApiHelper WingsApiHelper;
|
||||
private readonly WingsJwtHelper WingsJwtHelper;
|
||||
private readonly ConfigService ConfigService;
|
||||
private readonly Server Server;
|
||||
private readonly User User;
|
||||
|
||||
public WingsFileAccess(
|
||||
WingsApiHelper wingsApiHelper,
|
||||
WingsJwtHelper wingsJwtHelper,
|
||||
Server server,
|
||||
ConfigService configService,
|
||||
User user)
|
||||
{
|
||||
WingsApiHelper = wingsApiHelper;
|
||||
WingsJwtHelper = wingsJwtHelper;
|
||||
Server = server;
|
||||
ConfigService = configService;
|
||||
User = user;
|
||||
|
||||
if (server.Node == null)
|
||||
{
|
||||
throw new ArgumentException("The wings file access server model needs to include the node data");
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<FileData[]> Ls()
|
||||
{
|
||||
var res = await WingsApiHelper.Get<ListDirectory[]>(
|
||||
Server.Node,
|
||||
$"api/servers/{Server.Uuid}/files/list-directory?directory={CurrentPath}"
|
||||
);
|
||||
|
||||
var x = new List<FileData>();
|
||||
|
||||
foreach (var response in res)
|
||||
{
|
||||
x.Add(new()
|
||||
{
|
||||
Name = response.Name,
|
||||
Size = response.File ? response.Size : 0,
|
||||
IsFile = response.File,
|
||||
});
|
||||
}
|
||||
|
||||
return x.ToArray();
|
||||
}
|
||||
|
||||
public override Task Cd(string dir)
|
||||
{
|
||||
var x = Path.Combine(CurrentPath, dir).Replace("\\", "/") + "/";
|
||||
x = x.Replace("//", "/");
|
||||
CurrentPath = x;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override Task Up()
|
||||
{
|
||||
CurrentPath = Path.GetFullPath(Path.Combine(CurrentPath, "..")).Replace("\\", "/").Replace("C:", "");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override Task SetDir(string dir)
|
||||
{
|
||||
CurrentPath = dir;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task<string> Read(FileData fileData)
|
||||
{
|
||||
return await WingsApiHelper.GetRaw(Server.Node,
|
||||
$"api/servers/{Server.Uuid}/files/contents?file={CurrentPath}{fileData.Name}");
|
||||
}
|
||||
|
||||
public override async Task Write(FileData fileData, string content)
|
||||
{
|
||||
await WingsApiHelper.PostRaw(Server.Node,
|
||||
$"api/servers/{Server.Uuid}/files/write?file={CurrentPath}{fileData.Name}", content);
|
||||
}
|
||||
|
||||
public override async Task Upload(string name, Stream dataStream, Action<int>? progressUpdated = null)
|
||||
{
|
||||
var token = WingsJwtHelper.Generate(
|
||||
Server.Node.Token,
|
||||
claims => { claims.Add("server_uuid", Server.Uuid.ToString()); }
|
||||
);
|
||||
|
||||
var client = new RestClient();
|
||||
var request = new RestRequest();
|
||||
|
||||
if (Server.Node.Ssl)
|
||||
request.Resource =
|
||||
$"https://{Server.Node.Fqdn}:{Server.Node.HttpPort}/upload/file?token={token}&directory={CurrentPath}";
|
||||
else
|
||||
request.Resource =
|
||||
$"http://{Server.Node.Fqdn}:{Server.Node.HttpPort}/upload/file?token={token}&directory={CurrentPath}";
|
||||
|
||||
request.AddParameter("name", "files");
|
||||
request.AddParameter("filename", name);
|
||||
request.AddHeader("Content-Type", "multipart/form-data");
|
||||
request.AddHeader("Origin", ConfigService.GetSection("Moonlight").GetValue<string>("AppUrl"));
|
||||
request.AddFile("files", () =>
|
||||
{
|
||||
return new StreamProgressHelper(dataStream)
|
||||
{
|
||||
Progress = i => { progressUpdated?.Invoke(i); }
|
||||
};
|
||||
}, name);
|
||||
|
||||
await client.ExecutePostAsync(request);
|
||||
|
||||
client.Dispose();
|
||||
dataStream.Close();
|
||||
}
|
||||
|
||||
public override async Task MkDir(string name)
|
||||
{
|
||||
await WingsApiHelper.Post(Server.Node, $"api/servers/{Server.Uuid}/files/create-directory",
|
||||
new CreateDirectory()
|
||||
{
|
||||
Name = name,
|
||||
Path = CurrentPath
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public override Task<string> Pwd()
|
||||
{
|
||||
return Task.FromResult(CurrentPath);
|
||||
}
|
||||
|
||||
public override Task<string> DownloadUrl(FileData fileData)
|
||||
{
|
||||
var token = WingsJwtHelper.Generate(Server.Node.Token, claims =>
|
||||
{
|
||||
claims.Add("server_uuid", Server.Uuid.ToString());
|
||||
claims.Add("file_path", CurrentPath + "/" + fileData.Name);
|
||||
});
|
||||
|
||||
if (Server.Node.Ssl)
|
||||
{
|
||||
return Task.FromResult(
|
||||
$"https://{Server.Node.Fqdn}:{Server.Node.HttpPort}/download/file?token={token}"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Task.FromResult(
|
||||
$"http://{Server.Node.Fqdn}:{Server.Node.HttpPort}/download/file?token={token}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public override Task<Stream> DownloadStream(FileData fileData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override async Task Delete(FileData fileData)
|
||||
{
|
||||
await WingsApiHelper.Post(Server.Node, $"api/servers/{Server.Uuid}/files/delete", new DeleteFiles()
|
||||
{
|
||||
Root = CurrentPath,
|
||||
Files = new()
|
||||
{
|
||||
fileData.Name
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task Move(FileData fileData, string newPath)
|
||||
{
|
||||
var req = new RenameFiles()
|
||||
{
|
||||
Root = "/",
|
||||
Files = new[]
|
||||
{
|
||||
new RenameFilesData()
|
||||
{
|
||||
From = (CurrentPath + fileData.Name),
|
||||
To = newPath
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await WingsApiHelper.Put(Server.Node, $"api/servers/{Server.Uuid}/files/rename", req);
|
||||
}
|
||||
|
||||
public override async Task Compress(params FileData[] files)
|
||||
{
|
||||
var req = new CompressFiles()
|
||||
{
|
||||
Root = CurrentPath,
|
||||
Files = files.Select(x => x.Name).ToArray()
|
||||
};
|
||||
|
||||
await WingsApiHelper.Post(Server.Node, $"api/servers/{Server.Uuid}/files/compress", req);
|
||||
}
|
||||
|
||||
public override async Task Decompress(FileData fileData)
|
||||
{
|
||||
var req = new DecompressFile()
|
||||
{
|
||||
Root = CurrentPath,
|
||||
File = fileData.Name
|
||||
};
|
||||
|
||||
await WingsApiHelper.Post(Server.Node, $"api/servers/{Server.Uuid}/files/decompress", req);
|
||||
}
|
||||
|
||||
public override Task<string> GetLaunchUrl()
|
||||
{
|
||||
return Task.FromResult(
|
||||
$"sftp://{User.Id}.{StringHelper.IntToStringWithLeadingZeros(Server.Id, 8)}@{Server.Node.Fqdn}:{Server.Node.SftpPort}");
|
||||
}
|
||||
|
||||
public override object Clone()
|
||||
{
|
||||
return new WingsFileAccess(WingsApiHelper, WingsJwtHelper, Server, ConfigService, User);
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,11 @@ public class PaperApiHelper
|
||||
else
|
||||
requrl = ApiUrl + "/" + url;
|
||||
|
||||
RestRequest request = new(requrl);
|
||||
RestRequest request = new(requrl, Method.Get);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
|
||||
var response = await client.GetAsync(request);
|
||||
var response = await client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
|
||||
@@ -14,24 +14,13 @@ public class WingsApiHelper
|
||||
Client = new();
|
||||
}
|
||||
|
||||
private string GetApiUrl(Node node)
|
||||
{
|
||||
if(node.Ssl)
|
||||
return $"https://{node.Fqdn}:{node.HttpPort}/";
|
||||
else
|
||||
return $"http://{node.Fqdn}:{node.HttpPort}/";
|
||||
//return $"https://{node.Fqdn}:{node.HttpPort}/";
|
||||
}
|
||||
|
||||
public async Task<T> Get<T>(Node node, string resource)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Get;
|
||||
|
||||
var response = await Client.GetAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -53,13 +42,11 @@ public class WingsApiHelper
|
||||
|
||||
public async Task<string> GetRaw(Node node, string resource)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Get;
|
||||
|
||||
var response = await Client.GetAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -81,18 +68,16 @@ public class WingsApiHelper
|
||||
|
||||
public async Task<T> Post<T>(Node node, string resource, object? body)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Post;
|
||||
|
||||
request.AddParameter("text/plain",
|
||||
JsonConvert.SerializeObject(body),
|
||||
ParameterType.RequestBody
|
||||
);
|
||||
|
||||
var response = await Client.PostAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -114,16 +99,14 @@ public class WingsApiHelper
|
||||
|
||||
public async Task Post(Node node, string resource, object? body)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Post;
|
||||
|
||||
if(body != null)
|
||||
if(body != null)
|
||||
request.AddParameter("text/plain", JsonConvert.SerializeObject(body), ParameterType.RequestBody);
|
||||
|
||||
var response = await Client.PostAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -143,15 +126,13 @@ public class WingsApiHelper
|
||||
|
||||
public async Task PostRaw(Node node, string resource, object body)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Post;
|
||||
|
||||
request.AddParameter("text/plain", body, ParameterType.RequestBody);
|
||||
|
||||
var response = await Client.PostAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -171,16 +152,14 @@ public class WingsApiHelper
|
||||
|
||||
public async Task Delete(Node node, string resource, object? body)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Delete;
|
||||
|
||||
if(body != null)
|
||||
if(body != null)
|
||||
request.AddParameter("text/plain", JsonConvert.SerializeObject(body), ParameterType.RequestBody);
|
||||
|
||||
var response = await Client.DeleteAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -200,15 +179,13 @@ public class WingsApiHelper
|
||||
|
||||
public async Task Put(Node node, string resource, object? body)
|
||||
{
|
||||
RestRequest request = new(GetApiUrl(node) + resource);
|
||||
var request = CreateRequest(node, resource);
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
request.Method = Method.Put;
|
||||
|
||||
request.AddParameter("text/plain", JsonConvert.SerializeObject(body), ParameterType.RequestBody);
|
||||
|
||||
var response = await Client.PutAsync(request);
|
||||
var response = await Client.ExecuteAsync(request);
|
||||
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
@@ -225,4 +202,20 @@ public class WingsApiHelper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RestRequest CreateRequest(Node node, string resource)
|
||||
{
|
||||
var url = (node.Ssl ? "https" : "http") + $"://{node.Fqdn}:{node.HttpPort}/" + resource;
|
||||
|
||||
var request = new RestRequest(url)
|
||||
{
|
||||
Timeout = 60 * 15
|
||||
};
|
||||
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
request.AddHeader("Authorization", "Bearer " + node.Token);
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,13 @@ public class WingsServerConverter
|
||||
wingsServer.Settings.Environment.Add(v.Key, v.Value);
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
foreach (var allocation in server.Allocations)
|
||||
{
|
||||
wingsServer.Settings.Environment.Add("ML_PORT_" + i, allocation.Port.ToString());
|
||||
i++;
|
||||
}
|
||||
|
||||
// Stop
|
||||
if (image.StopCommand.StartsWith("!"))
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moonlight.App.Services;
|
||||
|
||||
namespace Moonlight.App.Http.Controllers.Api.Moonlight;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/moonlight/payments")]
|
||||
public class PaymentsController : Controller
|
||||
{
|
||||
private readonly ConfigService ConfigService;
|
||||
private readonly SubscriptionService SubscriptionService;
|
||||
|
||||
public PaymentsController(ConfigService configService, SubscriptionService subscriptionService)
|
||||
{
|
||||
ConfigService = configService;
|
||||
SubscriptionService = subscriptionService;
|
||||
}
|
||||
|
||||
[HttpGet("generate")]
|
||||
public async Task<ActionResult> GenerateGet([FromQuery] string key, [FromQuery] int subscriptionId)
|
||||
{
|
||||
var validKey = ConfigService
|
||||
.GetSection("Moonlight")
|
||||
.GetSection("Payments")
|
||||
.GetValue<string>("Key");
|
||||
|
||||
if (key != validKey)
|
||||
return StatusCode(403);
|
||||
|
||||
var token = await SubscriptionService.ProcessGenerate(subscriptionId);
|
||||
|
||||
return Ok(token);
|
||||
}
|
||||
|
||||
[HttpPost("generate")]
|
||||
public async Task<ActionResult> GeneratePost([FromQuery] string key, [FromQuery] int subscriptionId)
|
||||
{
|
||||
var validKey = ConfigService
|
||||
.GetSection("Moonlight")
|
||||
.GetSection("Payments")
|
||||
.GetValue<string>("Key");
|
||||
|
||||
if (key != validKey)
|
||||
return StatusCode(403);
|
||||
|
||||
var token = await SubscriptionService.ProcessGenerate(subscriptionId);
|
||||
|
||||
return Ok(token);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,10 @@ public class ResourcesController : Controller
|
||||
{
|
||||
if (name.Contains(".."))
|
||||
{
|
||||
await SecurityLogService.Log(SecurityLogType.PathTransversal, name);
|
||||
await SecurityLogService.Log(SecurityLogType.PathTransversal, x =>
|
||||
{
|
||||
x.Add<string>(name);
|
||||
});
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public class WingsFileAccess : IFileAccess
|
||||
|
||||
public async Task<FileManagerObject[]> GetDirectoryContent()
|
||||
{
|
||||
var res = await WingsApiHelper.Get<ListDirectoryRequest[]>(Node,
|
||||
var res = await WingsApiHelper.Get<ListDirectory[]>(Node,
|
||||
$"api/servers/{Server.Uuid}/files/list-directory?directory={Path}");
|
||||
|
||||
var x = new List<FileManagerObject>();
|
||||
@@ -130,7 +130,7 @@ public class WingsFileAccess : IFileAccess
|
||||
public async Task CreateDirectory(string name)
|
||||
{
|
||||
await WingsApiHelper.Post(Node, $"api/servers/{Server.Uuid}/files/create-directory",
|
||||
new CreateDirectoryRequest()
|
||||
new CreateDirectory()
|
||||
{
|
||||
Name = name,
|
||||
Path = Path
|
||||
@@ -171,7 +171,7 @@ public class WingsFileAccess : IFileAccess
|
||||
|
||||
public async Task Delete(FileManagerObject managerObject)
|
||||
{
|
||||
await WingsApiHelper.Post(Node, $"api/servers/{Server.Uuid}/files/delete", new DeleteFilesRequest()
|
||||
await WingsApiHelper.Post(Node, $"api/servers/{Server.Uuid}/files/delete", new DeleteFiles()
|
||||
{
|
||||
Root = Path,
|
||||
Files = new()
|
||||
@@ -183,7 +183,7 @@ public class WingsFileAccess : IFileAccess
|
||||
|
||||
public async Task Move(FileManagerObject managerObject, string newPath)
|
||||
{
|
||||
await WingsApiHelper.Put(Node, $"api/servers/{Server.Uuid}/files/rename", new RenameFilesRequest()
|
||||
await WingsApiHelper.Put(Node, $"api/servers/{Server.Uuid}/files/rename", new RenameFiles()
|
||||
{
|
||||
Root = "/",
|
||||
Files = new[]
|
||||
|
||||
8
Moonlight/App/Models/Files/FileContextAction.cs
Normal file
8
Moonlight/App/Models/Files/FileContextAction.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Moonlight.App.Models.Files;
|
||||
|
||||
public class FileContextAction
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public Action<FileManagerObject> Action { get; set; }
|
||||
}
|
||||
14
Moonlight/App/Models/Forms/LoginDataModel.cs
Normal file
14
Moonlight/App/Models/Forms/LoginDataModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
public class LoginDataModel
|
||||
{
|
||||
[Required(ErrorMessage = "You need to enter an email address")]
|
||||
[EmailAddress(ErrorMessage = "You need to enter a valid email address")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "You need to enter a password")]
|
||||
[MinLength(8, ErrorMessage = "You need to enter a password with minimum 8 characters in lenght")]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
9
Moonlight/App/Models/Forms/LoginTotpDataModel.cs
Normal file
9
Moonlight/App/Models/Forms/LoginTotpDataModel.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
public class LoginTotpDataModel
|
||||
{
|
||||
[Required(ErrorMessage = "You need to enter a 2fa code")]
|
||||
public string Code { get; set; } = "";
|
||||
}
|
||||
14
Moonlight/App/Models/Forms/NameModel.cs
Normal file
14
Moonlight/App/Models/Forms/NameModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
public class NameModel
|
||||
{
|
||||
[Required]
|
||||
[MinLength(2, ErrorMessage = "Do you think, that works?")]
|
||||
public string FirstName { get; set; }
|
||||
|
||||
[Required]
|
||||
[MinLength(2, ErrorMessage = "Do you think, that works?")]
|
||||
public string LastName { get; set; }
|
||||
}
|
||||
10
Moonlight/App/Models/Forms/PasswordModel.cs
Normal file
10
Moonlight/App/Models/Forms/PasswordModel.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
public class PasswordModel
|
||||
{
|
||||
[Required(ErrorMessage = "You need to enter a password")]
|
||||
[MinLength(8, ErrorMessage = "You need to enter a password with minimum 8 characters in lenght")]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
13
Moonlight/App/Models/Forms/SubscriptionDataModel.cs
Normal file
13
Moonlight/App/Models/Forms/SubscriptionDataModel.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
public class SubscriptionDataModel
|
||||
{
|
||||
[Required(ErrorMessage = "You need to enter a name")]
|
||||
[MaxLength(32, ErrorMessage = "Max lenght for name is 32")]
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
[Required(ErrorMessage = "You need to enter a description")]
|
||||
public string Description { get; set; } = "";
|
||||
}
|
||||
7
Moonlight/App/Models/Log/LogData.cs
Normal file
7
Moonlight/App/Models/Log/LogData.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Moonlight.App.Models.Log;
|
||||
|
||||
public class LogData
|
||||
{
|
||||
public Type Type { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
@@ -19,5 +19,9 @@ public enum AuditLogType
|
||||
AddDomainRecord,
|
||||
UpdateDomainRecord,
|
||||
DeleteDomainRecord,
|
||||
PasswordReset
|
||||
PasswordReset,
|
||||
CleanupEnabled,
|
||||
CleanupDisabled,
|
||||
CleanupTriggered,
|
||||
PasswordChange,
|
||||
}
|
||||
14
Moonlight/App/Models/Misc/SubscriptionLimit.cs
Normal file
14
Moonlight/App/Models/Misc/SubscriptionLimit.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Moonlight.App.Models.Misc;
|
||||
|
||||
public class SubscriptionLimit
|
||||
{
|
||||
public string Identifier { get; set; } = "";
|
||||
public int Amount { get; set; }
|
||||
public List<LimitOption> Options { get; set; } = new();
|
||||
|
||||
public class LimitOption
|
||||
{
|
||||
public string Key { get; set; } = "";
|
||||
public string Value { get; set; } = "";
|
||||
}
|
||||
}
|
||||
@@ -9,5 +9,6 @@ public enum UserStatus
|
||||
Warned,
|
||||
Banned,
|
||||
Disabled,
|
||||
DataPending
|
||||
DataPending,
|
||||
PasswordPending
|
||||
}
|
||||
12
Moonlight/App/Models/Wings/Requests/CompressFiles.cs
Normal file
12
Moonlight/App/Models/Wings/Requests/CompressFiles.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Moonlight.App.Models.Wings.Requests;
|
||||
|
||||
public class CompressFiles
|
||||
{
|
||||
[JsonProperty("root")]
|
||||
public string Root { get; set; }
|
||||
|
||||
[JsonProperty("files")]
|
||||
public string[] Files { get; set; }
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Moonlight.App.Models.Wings.Requests;
|
||||
|
||||
public class CreateBackupRequest
|
||||
public class CreateBackup
|
||||
{
|
||||
[JsonProperty("adapter")]
|
||||
public string Adapter { get; set; }
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Moonlight.App.Models.Wings.Requests;
|
||||
|
||||
public class CreateDirectoryRequest
|
||||
public class CreateDirectory
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Moonlight.App.Models.Wings.Requests;
|
||||
|
||||
public class CreateServerRequest
|
||||
public class CreateServer
|
||||
{
|
||||
[JsonProperty("uuid")]
|
||||
public Guid Uuid { get; set; }
|
||||
12
Moonlight/App/Models/Wings/Requests/DecompressFile.cs
Normal file
12
Moonlight/App/Models/Wings/Requests/DecompressFile.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Moonlight.App.Models.Wings.Requests;
|
||||
|
||||
public class DecompressFile
|
||||
{
|
||||
[JsonProperty("root")]
|
||||
public string Root { get; set; }
|
||||
|
||||
[JsonProperty("file")]
|
||||
public string File { get; set; }
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Moonlight.App.Models.Wings.Requests;
|
||||
|
||||
public class DeleteFilesRequest
|
||||
public class DeleteFiles
|
||||
{
|
||||
[JsonProperty("root")]
|
||||
public string Root { get; set; }
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Moonlight.App.Models.Wings.Requests;
|
||||
|
||||
public class RenameFilesRequest
|
||||
public class RenameFiles
|
||||
{
|
||||
[JsonProperty("root")]
|
||||
public string Root { get; set; }
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Moonlight.App.Models.Wings.Requests;
|
||||
|
||||
public class RestoreBackupRequest
|
||||
public class RestoreBackup
|
||||
{
|
||||
[JsonProperty("adapter")]
|
||||
public string Adapter { get; set; }
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Moonlight.App.Models.Wings.Requests;
|
||||
|
||||
public class ServerPowerRequest
|
||||
public class ServerPower
|
||||
{
|
||||
[JsonProperty("action")]
|
||||
public string Action { get; set; }
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Moonlight.App.Models.Wings.Resources;
|
||||
|
||||
public class ListDirectoryRequest
|
||||
public class ListDirectory
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Moonlight.App.Models.Wings.Resources;
|
||||
|
||||
public class ServerDetailsResponse
|
||||
public class ServerDetails
|
||||
{
|
||||
[JsonProperty("state")]
|
||||
public string State { get; set; }
|
||||
@@ -11,9 +11,9 @@ public class ServerDetailsResponse
|
||||
public bool IsSuspended { get; set; }
|
||||
|
||||
[JsonProperty("utilization")]
|
||||
public ServerDetailsResponseUtilization Utilization { get; set; }
|
||||
public ServerDetailsUtilization Utilization { get; set; }
|
||||
|
||||
public class ServerDetailsResponseUtilization
|
||||
public class ServerDetailsUtilization
|
||||
{
|
||||
[JsonProperty("memory_bytes")]
|
||||
public long MemoryBytes { get; set; }
|
||||
@@ -25,7 +25,7 @@ public class ServerDetailsResponse
|
||||
public double CpuAbsolute { get; set; }
|
||||
|
||||
[JsonProperty("network")]
|
||||
public ServerDetailsResponseNetwork Network { get; set; }
|
||||
public ServerDetailsNetwork Network { get; set; }
|
||||
|
||||
[JsonProperty("uptime")]
|
||||
public long Uptime { get; set; }
|
||||
@@ -37,7 +37,7 @@ public class ServerDetailsResponse
|
||||
public long DiskBytes { get; set; }
|
||||
}
|
||||
|
||||
public class ServerDetailsResponseNetwork
|
||||
public class ServerDetailsNetwork
|
||||
{
|
||||
[JsonProperty("rx_bytes")]
|
||||
public long RxBytes { get; set; }
|
||||
@@ -2,7 +2,7 @@
|
||||
using Moonlight.App.Database;
|
||||
using Moonlight.App.Database.Entities;
|
||||
|
||||
namespace Moonlight.App.Repositories.Subscriptions;
|
||||
namespace Moonlight.App.Repositories;
|
||||
|
||||
public class SubscriptionRepository : IDisposable
|
||||
{
|
||||
@@ -1,44 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moonlight.App.Database;
|
||||
using Moonlight.App.Database.Entities;
|
||||
|
||||
namespace Moonlight.App.Repositories.Subscriptions;
|
||||
|
||||
public class SubscriptionLimitRepository : IDisposable
|
||||
{
|
||||
private readonly DataContext DataContext;
|
||||
|
||||
public SubscriptionLimitRepository(DataContext dataContext)
|
||||
{
|
||||
DataContext = dataContext;
|
||||
}
|
||||
|
||||
public DbSet<SubscriptionLimit> Get()
|
||||
{
|
||||
return DataContext.SubscriptionLimits;
|
||||
}
|
||||
|
||||
public SubscriptionLimit Add(SubscriptionLimit subscription)
|
||||
{
|
||||
var x = DataContext.SubscriptionLimits.Add(subscription);
|
||||
DataContext.SaveChanges();
|
||||
return x.Entity;
|
||||
}
|
||||
|
||||
public void Update(SubscriptionLimit subscription)
|
||||
{
|
||||
DataContext.SubscriptionLimits.Update(subscription);
|
||||
DataContext.SaveChanges();
|
||||
}
|
||||
|
||||
public void Delete(SubscriptionLimit subscription)
|
||||
{
|
||||
DataContext.SubscriptionLimits.Remove(subscription);
|
||||
DataContext.SaveChanges();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DataContext.Dispose();
|
||||
}
|
||||
}
|
||||
216
Moonlight/App/Services/CleanupService.cs
Normal file
216
Moonlight/App/Services/CleanupService.cs
Normal file
@@ -0,0 +1,216 @@
|
||||
using System.Diagnostics;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MineStatLib;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Daemon.Resources;
|
||||
using Moonlight.App.Models.Wings;
|
||||
using Moonlight.App.Repositories;
|
||||
using Moonlight.App.Repositories.Servers;
|
||||
using Logging.Net;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Moonlight.App.Services;
|
||||
|
||||
public class CleanupService
|
||||
{
|
||||
#region Stats
|
||||
public DateTime StartedAt { get; private set; }
|
||||
public DateTime CompletedAt { get; private set; }
|
||||
public int ServersCleaned { get; private set; }
|
||||
public int CleanupsPerformed { get; private set; }
|
||||
public int ServersRunning { get; private set; }
|
||||
public bool IsRunning { get; private set; }
|
||||
#endregion
|
||||
|
||||
private readonly ConfigService ConfigService;
|
||||
private readonly MessageService MessageService;
|
||||
private readonly IServiceScopeFactory ServiceScopeFactory;
|
||||
private readonly PeriodicTimer Timer;
|
||||
|
||||
public CleanupService(
|
||||
ConfigService configService,
|
||||
IServiceScopeFactory serviceScopeFactory,
|
||||
MessageService messageService)
|
||||
{
|
||||
ServiceScopeFactory = serviceScopeFactory;
|
||||
MessageService = messageService;
|
||||
ConfigService = configService;
|
||||
|
||||
StartedAt = DateTime.Now;
|
||||
CompletedAt = DateTime.Now;
|
||||
IsRunning = false;
|
||||
|
||||
var config = ConfigService.GetSection("Moonlight").GetSection("Cleanup");
|
||||
|
||||
if (!config.GetValue<bool>("Enable") || ConfigService.DebugMode)
|
||||
{
|
||||
Logger.Info("Disabling cleanup service");
|
||||
return;
|
||||
}
|
||||
|
||||
Timer = new(TimeSpan.FromMinutes(config.GetValue<int>("Wait")));
|
||||
|
||||
Task.Run(Run);
|
||||
}
|
||||
|
||||
private async Task Run()
|
||||
{
|
||||
while (await Timer.WaitForNextTickAsync())
|
||||
{
|
||||
IsRunning = true;
|
||||
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
var config = ConfigService.GetSection("Moonlight").GetSection("Cleanup");
|
||||
|
||||
var maxCpu = config.GetValue<int>("Cpu");
|
||||
var minMemory = config.GetValue<int>("Memory");
|
||||
var maxUptime = config.GetValue<int>("Uptime");
|
||||
var minUptime = config.GetValue<int>("MinUptime");
|
||||
|
||||
var nodeRepository = scope.ServiceProvider.GetRequiredService<NodeRepository>();
|
||||
var nodeService = scope.ServiceProvider.GetRequiredService<NodeService>();
|
||||
|
||||
var nodes = nodeRepository
|
||||
.Get()
|
||||
.ToArray();
|
||||
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
try
|
||||
{
|
||||
var cpuStats = await nodeService.GetCpuStats(node);
|
||||
var memoryStats = await nodeService.GetMemoryStats(node);
|
||||
|
||||
if (cpuStats.Usage > maxCpu || memoryStats.Free < minMemory)
|
||||
{
|
||||
var containerStats = await nodeService.GetContainerStats(node);
|
||||
|
||||
var serverRepository = scope.ServiceProvider.GetRequiredService<ServerRepository>();
|
||||
var imageRepository = scope.ServiceProvider.GetRequiredService<ImageRepository>();
|
||||
|
||||
var images = imageRepository
|
||||
.Get()
|
||||
.ToArray();
|
||||
|
||||
var imagesWithFlag = images
|
||||
.Where(x =>
|
||||
(JsonConvert.DeserializeObject<string[]>(x.TagsJson) ?? Array.Empty<string>()).Contains("cleanup")
|
||||
)
|
||||
.ToArray();
|
||||
|
||||
var containerMappedToServers = new Dictionary<ContainerStats.Container, Server>();
|
||||
|
||||
foreach (var container in containerStats.Containers)
|
||||
{
|
||||
if (Guid.TryParse(container.Name, out Guid uuid))
|
||||
{
|
||||
var server = serverRepository
|
||||
.Get()
|
||||
.Include(x => x.Image)
|
||||
.Include(x => x.MainAllocation)
|
||||
.Include(x => x.Variables)
|
||||
.FirstOrDefault(x => x.Uuid == uuid);
|
||||
|
||||
if (server != null && imagesWithFlag.Any(y => y.Id == server.Image.Id))
|
||||
{
|
||||
containerMappedToServers.Add(container, server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var serverService = scope.ServiceProvider.GetRequiredService<ServerService>();
|
||||
|
||||
foreach (var containerMapped in containerMappedToServers)
|
||||
{
|
||||
var server = containerMapped.Value;
|
||||
|
||||
try
|
||||
{
|
||||
var stats = await serverService.GetDetails(server);
|
||||
|
||||
if (server.IsCleanupException)
|
||||
{
|
||||
if (stats.Utilization.Uptime > TimeSpan.FromHours(maxUptime).TotalMilliseconds)
|
||||
{
|
||||
var players = GetPlayers(node, server.MainAllocation);
|
||||
|
||||
if (players == 0)
|
||||
{
|
||||
await serverService.SetPowerState(server, PowerSignal.Restart);
|
||||
|
||||
ServersCleaned++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ServersRunning++;
|
||||
}
|
||||
|
||||
await MessageService.Emit("cleanup.updated", null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stats.Utilization.Uptime > TimeSpan.FromMinutes(minUptime).TotalMilliseconds)
|
||||
{
|
||||
var players = GetPlayers(node, server.MainAllocation);
|
||||
|
||||
if (players < 1)
|
||||
{
|
||||
var j2SVar = server.Variables.FirstOrDefault(x => x.Key == "J2S");
|
||||
var handleJ2S = j2SVar != null && j2SVar.Value == "1";
|
||||
|
||||
if (handleJ2S)
|
||||
{
|
||||
await serverService.SetPowerState(server, PowerSignal.Restart);
|
||||
}
|
||||
else
|
||||
{
|
||||
await serverService.SetPowerState(server, PowerSignal.Stop);
|
||||
}
|
||||
|
||||
ServersCleaned++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ServersRunning++;
|
||||
}
|
||||
|
||||
await MessageService.Emit("cleanup.updated", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warn($"Error checking server {server.Name} ({server.Id})");
|
||||
Logger.Warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error performing cleanup on node {node.Name} ({node.Id})");
|
||||
Logger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
IsRunning = false;
|
||||
CleanupsPerformed++;
|
||||
await MessageService.Emit("cleanup.updated", null);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetPlayers(Node node, NodeAllocation allocation)
|
||||
{
|
||||
var ms = new MineStat(node.Fqdn, (ushort)allocation.Port);
|
||||
|
||||
//TODO: Add fake player check
|
||||
|
||||
if (ms.ServerUp)
|
||||
{
|
||||
return ms.CurrentPlayersInt;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text;
|
||||
using Logging.Net;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Moonlight.App.Helpers;
|
||||
|
||||
@@ -21,6 +22,9 @@ public class ConfigService : IConfiguration
|
||||
|
||||
if (debugVar != null)
|
||||
DebugMode = bool.Parse(debugVar);
|
||||
|
||||
if(DebugMode)
|
||||
Logger.Debug("Debug mode enabled");
|
||||
}
|
||||
|
||||
public IEnumerable<IConfigurationSection> GetChildren()
|
||||
|
||||
@@ -169,7 +169,11 @@ public class DomainService
|
||||
}));
|
||||
}
|
||||
|
||||
await AuditLogService.Log(AuditLogType.AddDomainRecord, new[] { d.Id.ToString(), dnsRecord.Name });
|
||||
await AuditLogService.Log(AuditLogType.AddDomainRecord, x =>
|
||||
{
|
||||
x.Add<Domain>(d.Id);
|
||||
x.Add<DnsRecord>(dnsRecord.Name);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task UpdateDnsRecord(Domain d, DnsRecord dnsRecord)
|
||||
@@ -199,7 +203,11 @@ public class DomainService
|
||||
}));
|
||||
}
|
||||
|
||||
await AuditLogService.Log(AuditLogType.UpdateDomainRecord, new[] { d.Id.ToString(), dnsRecord.Name });
|
||||
await AuditLogService.Log(AuditLogType.UpdateDomainRecord, x =>
|
||||
{
|
||||
x.Add<Domain>(d.Id);
|
||||
x.Add<DnsRecord>(dnsRecord.Name);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task DeleteDnsRecord(Domain d, DnsRecord dnsRecord)
|
||||
@@ -210,7 +218,11 @@ public class DomainService
|
||||
await Client.Zones.DnsRecords.DeleteAsync(domain.SharedDomain.CloudflareId, dnsRecord.Id)
|
||||
);
|
||||
|
||||
await AuditLogService.Log(AuditLogType.DeleteDomainRecord, new[] { d.Id.ToString(), dnsRecord.Name });
|
||||
await AuditLogService.Log(AuditLogType.DeleteDomainRecord, x =>
|
||||
{
|
||||
x.Add<Domain>(d.Id);
|
||||
x.Add<DnsRecord>(dnsRecord.Name);
|
||||
});
|
||||
}
|
||||
|
||||
private Domain EnsureData(Domain domain)
|
||||
|
||||
23
Moonlight/App/Services/Interop/ModalService.cs
Normal file
23
Moonlight/App/Services/Interop/ModalService.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace Moonlight.App.Services.Interop;
|
||||
|
||||
public class ModalService
|
||||
{
|
||||
private readonly IJSRuntime JsRuntime;
|
||||
|
||||
public ModalService(IJSRuntime jsRuntime)
|
||||
{
|
||||
JsRuntime = jsRuntime;
|
||||
}
|
||||
|
||||
public async Task Show(string name)
|
||||
{
|
||||
await JsRuntime.InvokeVoidAsync("moonlight.modals.show", name);
|
||||
}
|
||||
|
||||
public async Task Hide(string name)
|
||||
{
|
||||
await JsRuntime.InvokeVoidAsync("moonlight.modals.hide", name);
|
||||
}
|
||||
}
|
||||
@@ -30,4 +30,19 @@ public class ToastService
|
||||
{
|
||||
await JsRuntime.InvokeVoidAsync("showSuccessToast", message);
|
||||
}
|
||||
|
||||
public async Task CreateProcessToast(string id, string text)
|
||||
{
|
||||
await JsRuntime.InvokeVoidAsync("createToast", id, text);
|
||||
}
|
||||
|
||||
public async Task UpdateProcessToast(string id, string text)
|
||||
{
|
||||
await JsRuntime.InvokeVoidAsync("modifyToast", id, text);
|
||||
}
|
||||
|
||||
public async Task RemoveProcessToast(string id)
|
||||
{
|
||||
await JsRuntime.InvokeVoidAsync("removeToast", id);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Moonlight.App.Database.Entities.LogsEntries;
|
||||
using Moonlight.App.Models.Log;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Repositories.LogEntries;
|
||||
using Moonlight.App.Services.Sessions;
|
||||
@@ -19,16 +20,18 @@ public class AuditLogService
|
||||
HttpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public Task Log(AuditLogType type, params object[] data)
|
||||
public Task Log(AuditLogType type, Action<AuditLogParameters> data)
|
||||
{
|
||||
var ip = GetIp();
|
||||
var al = new AuditLogParameters();
|
||||
data(al);
|
||||
|
||||
var entry = new AuditLogEntry()
|
||||
{
|
||||
Ip = ip,
|
||||
Type = type,
|
||||
System = false,
|
||||
JsonData = data.Length == 0 ? "" : JsonConvert.SerializeObject(data)
|
||||
JsonData = al.Build()
|
||||
};
|
||||
|
||||
Repository.Add(entry);
|
||||
@@ -36,13 +39,16 @@ public class AuditLogService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task LogSystem(AuditLogType type, params object[] data)
|
||||
public Task LogSystem(AuditLogType type, Action<AuditLogParameters> data)
|
||||
{
|
||||
var al = new AuditLogParameters();
|
||||
data(al);
|
||||
|
||||
var entry = new AuditLogEntry()
|
||||
{
|
||||
Type = type,
|
||||
System = true,
|
||||
JsonData = data.Length == 0 ? "" : JsonConvert.SerializeObject(data)
|
||||
JsonData = al.Build()
|
||||
};
|
||||
|
||||
Repository.Add(entry);
|
||||
@@ -62,4 +68,23 @@ public class AuditLogService
|
||||
|
||||
return HttpContextAccessor.HttpContext.Connection.RemoteIpAddress!.ToString();
|
||||
}
|
||||
|
||||
public class AuditLogParameters
|
||||
{
|
||||
private List<LogData> Data = new List<LogData>();
|
||||
|
||||
public void Add<T>(object data)
|
||||
{
|
||||
Data.Add(new LogData()
|
||||
{
|
||||
Type = typeof(T),
|
||||
Value = data.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
internal string Build()
|
||||
{
|
||||
return JsonConvert.SerializeObject(Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using Moonlight.App.Database.Entities.LogsEntries;
|
||||
using Moonlight.App.Models.Log;
|
||||
using Moonlight.App.Repositories.LogEntries;
|
||||
using Moonlight.App.Services.Sessions;
|
||||
using Newtonsoft.Json;
|
||||
@@ -18,15 +19,17 @@ public class ErrorLogService
|
||||
HttpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public Task Log(Exception exception, params object[] objects)
|
||||
public Task Log(Exception exception, Action<ErrorLogParameters> data)
|
||||
{
|
||||
var ip = GetIp();
|
||||
var al = new ErrorLogParameters();
|
||||
data(al);
|
||||
|
||||
var entry = new ErrorLogEntry()
|
||||
{
|
||||
Ip = ip,
|
||||
System = false,
|
||||
JsonData = !objects.Any() ? "" : JsonConvert.SerializeObject(objects),
|
||||
JsonData = al.Build(),
|
||||
Class = NameOfCallingClass(),
|
||||
Stacktrace = exception.ToStringDemystified()
|
||||
};
|
||||
@@ -36,12 +39,15 @@ public class ErrorLogService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task LogSystem(Exception exception, params object[] objects)
|
||||
public Task LogSystem(Exception exception, Action<ErrorLogParameters> data)
|
||||
{
|
||||
var al = new ErrorLogParameters();
|
||||
data(al);
|
||||
|
||||
var entry = new ErrorLogEntry()
|
||||
{
|
||||
System = true,
|
||||
JsonData = !objects.Any() ? "" : JsonConvert.SerializeObject(objects),
|
||||
JsonData = al.Build(),
|
||||
Class = NameOfCallingClass(),
|
||||
Stacktrace = exception.ToStringDemystified()
|
||||
};
|
||||
@@ -87,4 +93,23 @@ public class ErrorLogService
|
||||
|
||||
return HttpContextAccessor.HttpContext.Connection.RemoteIpAddress!.ToString();
|
||||
}
|
||||
|
||||
public class ErrorLogParameters
|
||||
{
|
||||
private List<LogData> Data = new List<LogData>();
|
||||
|
||||
public void Add<T>(object data)
|
||||
{
|
||||
Data.Add(new LogData()
|
||||
{
|
||||
Type = typeof(T),
|
||||
Value = data.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
internal string Build()
|
||||
{
|
||||
return JsonConvert.SerializeObject(Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Moonlight.App.Database.Entities.LogsEntries;
|
||||
using Moonlight.App.Models.Log;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Repositories.LogEntries;
|
||||
using Moonlight.App.Services.Sessions;
|
||||
@@ -17,16 +18,18 @@ public class SecurityLogService
|
||||
HttpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public Task Log(SecurityLogType type, params object[] data)
|
||||
public Task Log(SecurityLogType type, Action<SecurityLogParameters> data)
|
||||
{
|
||||
var ip = GetIp();
|
||||
var al = new SecurityLogParameters();
|
||||
data(al);
|
||||
|
||||
var entry = new SecurityLogEntry()
|
||||
{
|
||||
Ip = ip,
|
||||
Type = type,
|
||||
System = false,
|
||||
JsonData = data.Length == 0 ? "" : JsonConvert.SerializeObject(data)
|
||||
JsonData = al.Build()
|
||||
};
|
||||
|
||||
Repository.Add(entry);
|
||||
@@ -34,13 +37,16 @@ public class SecurityLogService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task LogSystem(SecurityLogType type, params object[] data)
|
||||
public Task LogSystem(SecurityLogType type, Action<SecurityLogParameters> data)
|
||||
{
|
||||
var al = new SecurityLogParameters();
|
||||
data(al);
|
||||
|
||||
var entry = new SecurityLogEntry()
|
||||
{
|
||||
Type = type,
|
||||
System = true,
|
||||
JsonData = data.Length == 0 ? "" : JsonConvert.SerializeObject(data)
|
||||
JsonData = al.Build()
|
||||
};
|
||||
|
||||
Repository.Add(entry);
|
||||
@@ -60,4 +66,24 @@ public class SecurityLogService
|
||||
|
||||
return HttpContextAccessor.HttpContext.Connection.RemoteIpAddress!.ToString();
|
||||
}
|
||||
|
||||
|
||||
public class SecurityLogParameters
|
||||
{
|
||||
private List<LogData> Data = new List<LogData>();
|
||||
|
||||
public void Add<T>(object data)
|
||||
{
|
||||
Data.Add(new LogData()
|
||||
{
|
||||
Type = typeof(T),
|
||||
Value = data.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
internal string Build()
|
||||
{
|
||||
return JsonConvert.SerializeObject(Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,10 @@ public class OneTimeJwtService
|
||||
}
|
||||
catch (SignatureVerificationException)
|
||||
{
|
||||
await SecurityLogService.LogSystem(SecurityLogType.ManipulatedJwt, token);
|
||||
await SecurityLogService.LogSystem(SecurityLogType.ManipulatedJwt, x =>
|
||||
{
|
||||
x.Add<string>(token);
|
||||
});
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -75,11 +75,11 @@ public class ServerService
|
||||
return s;
|
||||
}
|
||||
|
||||
public async Task<ServerDetailsResponse> GetDetails(Server s)
|
||||
public async Task<ServerDetails> GetDetails(Server s)
|
||||
{
|
||||
Server server = EnsureNodeData(s);
|
||||
|
||||
return await WingsApiHelper.Get<ServerDetailsResponse>(
|
||||
return await WingsApiHelper.Get<ServerDetails>(
|
||||
server.Node,
|
||||
$"api/servers/{server.Uuid}"
|
||||
);
|
||||
@@ -91,12 +91,16 @@ public class ServerService
|
||||
|
||||
var rawSignal = signal.ToString().ToLower();
|
||||
|
||||
await WingsApiHelper.Post(server.Node, $"api/servers/{server.Uuid}/power", new ServerPowerRequest()
|
||||
await WingsApiHelper.Post(server.Node, $"api/servers/{server.Uuid}/power", new ServerPower()
|
||||
{
|
||||
Action = rawSignal
|
||||
});
|
||||
|
||||
await AuditLogService.Log(AuditLogType.ChangePowerState, new[] { server.Uuid.ToString(), rawSignal });
|
||||
await AuditLogService.Log(AuditLogType.ChangePowerState, x =>
|
||||
{
|
||||
x.Add<Server>(server.Uuid);
|
||||
x.Add<PowerSignal>(rawSignal);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<ServerBackup> CreateBackup(Server server)
|
||||
@@ -118,7 +122,7 @@ public class ServerService
|
||||
serverData.Backups.Add(backup);
|
||||
ServerRepository.Update(serverData);
|
||||
|
||||
await WingsApiHelper.Post(serverData.Node, $"api/servers/{serverData.Uuid}/backup", new CreateBackupRequest()
|
||||
await WingsApiHelper.Post(serverData.Node, $"api/servers/{serverData.Uuid}/backup", new CreateBackup()
|
||||
{
|
||||
Adapter = "wings",
|
||||
Uuid = backup.Uuid,
|
||||
@@ -126,7 +130,11 @@ public class ServerService
|
||||
});
|
||||
|
||||
await AuditLogService.Log(AuditLogType.CreateBackup,
|
||||
new[] { serverData.Uuid.ToString(), backup.Uuid.ToString() });
|
||||
x =>
|
||||
{
|
||||
x.Add<Server>(server.Uuid);
|
||||
x.Add<ServerBackup>(backup.Uuid);
|
||||
});
|
||||
|
||||
return backup;
|
||||
}
|
||||
@@ -158,13 +166,17 @@ public class ServerService
|
||||
Server server = EnsureNodeData(s);
|
||||
|
||||
await WingsApiHelper.Post(server.Node, $"api/servers/{server.Uuid}/backup/{serverBackup.Uuid}/restore",
|
||||
new RestoreBackupRequest()
|
||||
new RestoreBackup()
|
||||
{
|
||||
Adapter = "wings"
|
||||
});
|
||||
|
||||
await AuditLogService.Log(AuditLogType.RestoreBackup,
|
||||
new[] { s.Uuid.ToString(), serverBackup.Uuid.ToString() });
|
||||
x =>
|
||||
{
|
||||
x.Add<Server>(server.Uuid);
|
||||
x.Add<ServerBackup>(serverBackup.Uuid);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task DeleteBackup(Server server, ServerBackup serverBackup)
|
||||
@@ -186,7 +198,11 @@ public class ServerService
|
||||
await MessageService.Emit("wings.backups.delete", backup);
|
||||
|
||||
await AuditLogService.Log(AuditLogType.DeleteBackup,
|
||||
new[] { serverBackup.Uuid.ToString(), serverBackup.Uuid.ToString() });
|
||||
x =>
|
||||
{
|
||||
x.Add<Server>(server.Uuid);
|
||||
x.Add<ServerBackup>(backup.Uuid);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<string> DownloadBackup(Server s, ServerBackup serverBackup)
|
||||
@@ -200,7 +216,11 @@ public class ServerService
|
||||
});
|
||||
|
||||
await AuditLogService.Log(AuditLogType.DownloadBackup,
|
||||
new[] { serverBackup.Uuid.ToString(), serverBackup.Uuid.ToString() });
|
||||
x =>
|
||||
{
|
||||
x.Add<Server>(server.Uuid);
|
||||
x.Add<ServerBackup>(serverBackup.Uuid);
|
||||
});
|
||||
|
||||
return $"https://{server.Node.Fqdn}:{server.Node.HttpPort}/download/backup?token={token}";
|
||||
}
|
||||
@@ -299,19 +319,26 @@ public class ServerService
|
||||
|
||||
try
|
||||
{
|
||||
await WingsApiHelper.Post(node, $"api/servers", new CreateServerRequest()
|
||||
await WingsApiHelper.Post(node, $"api/servers", new CreateServer()
|
||||
{
|
||||
Uuid = newServerData.Uuid,
|
||||
StartOnCompletion = false
|
||||
});
|
||||
|
||||
await AuditLogService.Log(AuditLogType.CreateServer, newServerData.Uuid.ToString());
|
||||
await AuditLogService.Log(AuditLogType.CreateServer, x =>
|
||||
{
|
||||
x.Add<Server>(newServerData.Uuid);
|
||||
});
|
||||
|
||||
return newServerData;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ErrorLogService.Log(e, new[] { newServerData.Uuid.ToString(), node.Id.ToString() });
|
||||
await ErrorLogService.Log(e, x =>
|
||||
{
|
||||
x.Add<Server>(newServerData.Uuid);
|
||||
x.Add<Node>(node.Id);
|
||||
});
|
||||
|
||||
ServerRepository.Delete(newServerData);
|
||||
|
||||
@@ -325,7 +352,10 @@ public class ServerService
|
||||
|
||||
await WingsApiHelper.Post(server.Node, $"api/servers/{server.Uuid}/reinstall", null);
|
||||
|
||||
await AuditLogService.Log(AuditLogType.ReinstallServer, server.Uuid.ToString());
|
||||
await AuditLogService.Log(AuditLogType.ReinstallServer, x =>
|
||||
{
|
||||
x.Add<Server>(server.Uuid);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<Server> SftpServerLogin(int serverId, int id, string password)
|
||||
@@ -334,7 +364,10 @@ public class ServerService
|
||||
|
||||
if (server == null)
|
||||
{
|
||||
await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, serverId);
|
||||
await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, x =>
|
||||
{
|
||||
x.Add<int>(id);
|
||||
});
|
||||
throw new Exception("Server not found");
|
||||
}
|
||||
|
||||
|
||||
@@ -89,12 +89,15 @@ public class IdentityService
|
||||
}
|
||||
catch (SignatureVerificationException)
|
||||
{
|
||||
await SecurityLogService.Log(SecurityLogType.ManipulatedJwt, token);
|
||||
await SecurityLogService.Log(SecurityLogType.ManipulatedJwt, x =>
|
||||
{
|
||||
x.Add<string>(token);
|
||||
});
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ErrorLogService.Log(e);
|
||||
await ErrorLogService.Log(e, x => {});
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -130,7 +133,7 @@ public class IdentityService
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ErrorLogService.Log(e);
|
||||
await ErrorLogService.Log(e, x => {});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
45
Moonlight/App/Services/SubscriptionAdminService.cs
Normal file
45
Moonlight/App/Services/SubscriptionAdminService.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Repositories;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Moonlight.App.Services;
|
||||
|
||||
public class SubscriptionAdminService
|
||||
{
|
||||
private readonly SubscriptionRepository SubscriptionRepository;
|
||||
private readonly OneTimeJwtService OneTimeJwtService;
|
||||
|
||||
public SubscriptionAdminService(OneTimeJwtService oneTimeJwtService, SubscriptionRepository subscriptionRepository)
|
||||
{
|
||||
OneTimeJwtService = oneTimeJwtService;
|
||||
SubscriptionRepository = subscriptionRepository;
|
||||
}
|
||||
|
||||
public Task<SubscriptionLimit[]> GetLimits(Subscription subscription)
|
||||
{
|
||||
return Task.FromResult(
|
||||
JsonConvert.DeserializeObject<SubscriptionLimit[]>(subscription.LimitsJson)
|
||||
?? Array.Empty<SubscriptionLimit>()
|
||||
);
|
||||
}
|
||||
|
||||
public Task SaveLimits(Subscription subscription, SubscriptionLimit[] limits)
|
||||
{
|
||||
subscription.LimitsJson = JsonConvert.SerializeObject(limits);
|
||||
SubscriptionRepository.Update(subscription);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<string> GenerateCode(Subscription subscription, int duration)
|
||||
{
|
||||
return Task.FromResult(
|
||||
OneTimeJwtService.Generate(data =>
|
||||
{
|
||||
data.Add("subscription", subscription.Id.ToString());
|
||||
data.Add("duration", duration.ToString());
|
||||
}, TimeSpan.FromDays(10324))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,126 +3,138 @@ using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Exceptions;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Repositories;
|
||||
using Moonlight.App.Repositories.Subscriptions;
|
||||
using Moonlight.App.Services.LogServices;
|
||||
using Moonlight.App.Services.Sessions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Moonlight.App.Services;
|
||||
|
||||
public class SubscriptionService
|
||||
{
|
||||
private readonly SubscriptionRepository SubscriptionRepository;
|
||||
private readonly UserRepository UserRepository;
|
||||
private readonly IdentityService IdentityService;
|
||||
private readonly ConfigService ConfigService;
|
||||
private readonly OneTimeJwtService OneTimeJwtService;
|
||||
private readonly AuditLogService AuditLogService;
|
||||
private readonly IdentityService IdentityService;
|
||||
private readonly UserRepository UserRepository;
|
||||
private readonly ConfigService ConfigService;
|
||||
|
||||
public SubscriptionService(SubscriptionRepository subscriptionRepository,
|
||||
UserRepository userRepository,
|
||||
IdentityService identityService,
|
||||
ConfigService configService,
|
||||
public SubscriptionService(
|
||||
SubscriptionRepository subscriptionRepository,
|
||||
OneTimeJwtService oneTimeJwtService,
|
||||
AuditLogService auditLogService)
|
||||
IdentityService identityService,
|
||||
UserRepository userRepository,
|
||||
ConfigService configService)
|
||||
{
|
||||
SubscriptionRepository = subscriptionRepository;
|
||||
UserRepository = userRepository;
|
||||
IdentityService = identityService;
|
||||
ConfigService = configService;
|
||||
OneTimeJwtService = oneTimeJwtService;
|
||||
AuditLogService = auditLogService;
|
||||
IdentityService = identityService;
|
||||
UserRepository = userRepository;
|
||||
ConfigService = configService;
|
||||
}
|
||||
|
||||
public async Task<Subscription?> Get()
|
||||
public async Task<Subscription?> GetCurrent()
|
||||
{
|
||||
var user = await IdentityService.Get();
|
||||
var advancedUser = UserRepository
|
||||
.Get()
|
||||
.Include(x => x.Subscription)
|
||||
.First(x => x.Id == user!.Id);
|
||||
var user = await GetCurrentUser();
|
||||
|
||||
if (advancedUser.Subscription == null)
|
||||
if (user == null || user.CurrentSubscription == null)
|
||||
return null;
|
||||
|
||||
return SubscriptionRepository
|
||||
.Get()
|
||||
.Include(x => x.Limits)
|
||||
.Include("Limits.Image")
|
||||
.First(x => x.Id == advancedUser.Subscription.Id);
|
||||
}
|
||||
public async Task Cancel()
|
||||
{
|
||||
var user = await IdentityService.Get();
|
||||
user!.Subscription = null;
|
||||
UserRepository.Update(user!);
|
||||
var subscriptionEnd = user.SubscriptionSince.ToUniversalTime().AddDays(user.SubscriptionDuration);
|
||||
|
||||
await AuditLogService.Log(AuditLogType.CancelSubscription, new[] { user.Email });
|
||||
}
|
||||
public Task<Subscription[]> GetAvailable()
|
||||
{
|
||||
return Task.FromResult(
|
||||
SubscriptionRepository
|
||||
.Get()
|
||||
.Include(x => x.Limits)
|
||||
.ToArray()
|
||||
);
|
||||
}
|
||||
public Task<string> GenerateBuyUrl(Subscription subscription)
|
||||
{
|
||||
var url = ConfigService
|
||||
.GetSection("Moonlight")
|
||||
.GetSection("Payments")
|
||||
.GetValue<string>("BaseUrl");
|
||||
if (subscriptionEnd > DateTime.UtcNow)
|
||||
{
|
||||
return user.CurrentSubscription;
|
||||
}
|
||||
|
||||
return Task.FromResult<string>($"{url}/products/{subscription.SellPassId}");
|
||||
}
|
||||
public Task<string> ProcessGenerate(int subscriptionId)
|
||||
{
|
||||
var subscription = SubscriptionRepository
|
||||
.Get()
|
||||
.FirstOrDefault(x => x.Id == subscriptionId);
|
||||
|
||||
if (subscription == null)
|
||||
throw new DisplayException("Unknown subscription id");
|
||||
|
||||
var token = OneTimeJwtService.Generate(
|
||||
options =>
|
||||
{
|
||||
options.Add("id", subscription.Id.ToString());
|
||||
}
|
||||
);
|
||||
|
||||
return Task.FromResult(token);
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task ApplyCode(string code)
|
||||
{
|
||||
var user = (await IdentityService.Get())!;
|
||||
var values = await OneTimeJwtService.Validate(code);
|
||||
var data = await OneTimeJwtService.Validate(code);
|
||||
|
||||
if (values == null)
|
||||
throw new DisplayException("Invalid subscription code");
|
||||
if (data == null)
|
||||
throw new DisplayException("Invalid or expired subscription code");
|
||||
|
||||
if (!values.ContainsKey("id"))
|
||||
throw new DisplayException("Subscription code is missing the id");
|
||||
|
||||
var id = int.Parse(values["id"]);
|
||||
var id = int.Parse(data["subscription"]);
|
||||
var duration = int.Parse(data["duration"]);
|
||||
|
||||
var subscription = SubscriptionRepository
|
||||
.Get()
|
||||
.FirstOrDefault(x => x.Id == id);
|
||||
|
||||
if (subscription == null)
|
||||
throw new DisplayException("The subscription the code is referring does not exist");
|
||||
throw new DisplayException("The subscription the code is associated with does not exist");
|
||||
|
||||
user.Subscription = subscription;
|
||||
user.SubscriptionDuration = subscription.Duration;
|
||||
user.SubscriptionSince = DateTime.Now;
|
||||
var user = await GetCurrentUser();
|
||||
|
||||
if (user == null)
|
||||
throw new DisplayException("Unable to determine current user");
|
||||
|
||||
user.CurrentSubscription = subscription;
|
||||
user.SubscriptionDuration = duration;
|
||||
user.SubscriptionSince = DateTime.UtcNow;
|
||||
|
||||
UserRepository.Update(user);
|
||||
|
||||
await OneTimeJwtService.Revoke(code);
|
||||
|
||||
await AuditLogService.Log(AuditLogType.ApplySubscriptionCode, new[] { user.Email, subscription.Id.ToString() });
|
||||
await OneTimeJwtService.Revoke(code);
|
||||
}
|
||||
|
||||
public async Task<SubscriptionLimit> GetLimit(string identifier)
|
||||
{
|
||||
var configSection = ConfigService.GetSection("Moonlight").GetSection("Subscriptions");
|
||||
|
||||
var defaultLimits = configSection.GetValue<SubscriptionLimit[]>("defaultLimits");
|
||||
|
||||
var subscription = await GetCurrent();
|
||||
|
||||
if (subscription == null)
|
||||
{
|
||||
var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier);
|
||||
|
||||
if (foundDefault != null)
|
||||
return foundDefault;
|
||||
|
||||
return new()
|
||||
{
|
||||
Identifier = identifier,
|
||||
Amount = 0
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var subscriptionLimits =
|
||||
JsonConvert.DeserializeObject<SubscriptionLimit[]>(subscription.LimitsJson)
|
||||
?? Array.Empty<SubscriptionLimit>();
|
||||
|
||||
var foundLimit = subscriptionLimits.FirstOrDefault(x => x.Identifier == identifier);
|
||||
|
||||
if (foundLimit != null)
|
||||
return foundLimit;
|
||||
|
||||
var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier);
|
||||
|
||||
if (foundDefault != null)
|
||||
return foundDefault;
|
||||
|
||||
return new()
|
||||
{
|
||||
Identifier = identifier,
|
||||
Amount = 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<User?> GetCurrentUser()
|
||||
{
|
||||
var user = await IdentityService.Get();
|
||||
|
||||
if (user == null)
|
||||
return null;
|
||||
|
||||
var userWithData = UserRepository
|
||||
.Get()
|
||||
.Include(x => x.CurrentSubscription)
|
||||
.First(x => x.Id == user.Id);
|
||||
|
||||
return userWithData;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Models.Misc;
|
||||
using Moonlight.App.Repositories;
|
||||
using Moonlight.App.Services.LogServices;
|
||||
using Moonlight.App.Services.Sessions;
|
||||
@@ -46,13 +47,23 @@ public class TotpService
|
||||
public async Task Enable()
|
||||
{
|
||||
var user = (await IdentityService.Get())!;
|
||||
|
||||
user.TotpEnabled = true;
|
||||
|
||||
user.TotpSecret = GenerateSecret();
|
||||
|
||||
UserRepository.Update(user);
|
||||
|
||||
await AuditLogService.Log(AuditLogType.EnableTotp, user.Email);
|
||||
await AuditLogService.Log(AuditLogType.EnableTotp, x =>
|
||||
{
|
||||
x.Add<User>(user.Email);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task EnforceTotpLogin()
|
||||
{
|
||||
var user = (await IdentityService.Get())!;
|
||||
|
||||
user.TotpEnabled = true;
|
||||
UserRepository.Update(user);
|
||||
}
|
||||
|
||||
public async Task Disable()
|
||||
@@ -63,7 +74,10 @@ public class TotpService
|
||||
|
||||
UserRepository.Update(user);
|
||||
|
||||
await AuditLogService.Log(AuditLogType.DisableTotp, user.Email);
|
||||
await AuditLogService.Log(AuditLogType.DisableTotp,x =>
|
||||
{
|
||||
x.Add<User>(user.Email);
|
||||
});
|
||||
}
|
||||
|
||||
private string GenerateSecret()
|
||||
|
||||
@@ -77,7 +77,10 @@ public class UserService
|
||||
});
|
||||
|
||||
await MailService.SendMail(user!, "register", values => {});
|
||||
await AuditLogService.Log(AuditLogType.Register, user.Email);
|
||||
await AuditLogService.Log(AuditLogType.Register, x =>
|
||||
{
|
||||
x.Add<User>(user.Email);
|
||||
});
|
||||
|
||||
return await GenerateToken(user);
|
||||
}
|
||||
@@ -91,7 +94,11 @@ public class UserService
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
await SecurityLogService.Log(SecurityLogType.LoginFail, new[] { email, password });
|
||||
await SecurityLogService.Log(SecurityLogType.LoginFail, x =>
|
||||
{
|
||||
x.Add<User>(email);
|
||||
x.Add<string>(password);
|
||||
});
|
||||
throw new DisplayException("Email and password combination not found");
|
||||
}
|
||||
|
||||
@@ -100,7 +107,11 @@ public class UserService
|
||||
return user.TotpEnabled;
|
||||
}
|
||||
|
||||
await SecurityLogService.Log(SecurityLogType.LoginFail, new[] { email, password });
|
||||
await SecurityLogService.Log(SecurityLogType.LoginFail, x =>
|
||||
{
|
||||
x.Add<User>(email);
|
||||
x.Add<string>(password);
|
||||
});
|
||||
throw new DisplayException("Email and password combination not found");;
|
||||
}
|
||||
|
||||
@@ -125,18 +136,28 @@ public class UserService
|
||||
|
||||
if (totpCodeValid)
|
||||
{
|
||||
await AuditLogService.Log(AuditLogType.Login, email);
|
||||
await AuditLogService.Log(AuditLogType.Login, x =>
|
||||
{
|
||||
x.Add<User>(email);
|
||||
});
|
||||
return await GenerateToken(user, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
await SecurityLogService.Log(SecurityLogType.LoginFail, new[] { email, password });
|
||||
await SecurityLogService.Log(SecurityLogType.LoginFail, x =>
|
||||
{
|
||||
x.Add<User>(email);
|
||||
x.Add<string>(password);
|
||||
});
|
||||
throw new DisplayException("2FA code invalid");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await AuditLogService.Log(AuditLogType.Login, email);
|
||||
await AuditLogService.Log(AuditLogType.Login, x =>
|
||||
{
|
||||
x.Add<User>(email);
|
||||
});
|
||||
return await GenerateToken(user!, true);
|
||||
}
|
||||
}
|
||||
@@ -149,7 +170,10 @@ public class UserService
|
||||
|
||||
if (isSystemAction)
|
||||
{
|
||||
await AuditLogService.LogSystem(AuditLogType.ChangePassword, user.Email);
|
||||
await AuditLogService.LogSystem(AuditLogType.ChangePassword, x=>
|
||||
{
|
||||
x.Add<User>(user.Email);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -160,7 +184,10 @@ public class UserService
|
||||
values.Add("Location", "In your walls");
|
||||
});
|
||||
|
||||
await AuditLogService.Log(AuditLogType.ChangePassword, user.Email);
|
||||
await AuditLogService.Log(AuditLogType.ChangePassword, x =>
|
||||
{
|
||||
x.Add<User>(user.Email);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,17 +197,27 @@ public class UserService
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, id);
|
||||
await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, x =>
|
||||
{
|
||||
x.Add<int>(id);
|
||||
});
|
||||
throw new Exception("Invalid username");
|
||||
}
|
||||
|
||||
if (BCrypt.Net.BCrypt.Verify(password, user.Password))
|
||||
{
|
||||
await AuditLogService.LogSystem(AuditLogType.Login, user.Email);
|
||||
await AuditLogService.LogSystem(AuditLogType.Login, x =>
|
||||
{
|
||||
x.Add<User>(user.Email);
|
||||
});
|
||||
return user;
|
||||
}
|
||||
|
||||
await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, new[] { id.ToString(), password });
|
||||
await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, x =>
|
||||
{
|
||||
x.Add<int>(id);
|
||||
x.Add<string>(password);
|
||||
});
|
||||
throw new Exception("Invalid userid or password");
|
||||
}
|
||||
|
||||
@@ -218,7 +255,7 @@ public class UserService
|
||||
var newPassword = StringHelper.GenerateString(16);
|
||||
await ChangePassword(user, newPassword, true);
|
||||
|
||||
await AuditLogService.Log(AuditLogType.PasswordReset);
|
||||
await AuditLogService.Log(AuditLogType.PasswordReset, x => {});
|
||||
|
||||
await MailService.SendMail(user, "passwordReset", values =>
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user