Added new node manager. Added new login/register screen. AuditLog. Permissions

This commit is contained in:
Marcel Baumgartner 2023-02-17 18:03:52 +01:00
parent 54173637c8
commit 95999eae26
51 changed files with 2979 additions and 116 deletions

10
.gitignore vendored
View file

@ -432,3 +432,13 @@ FodyWeavers.xsd
# JetBrains Rider
*.sln.iml
.idea/.idea.Moonlight/.idea/discord.xml
Moonlight/obj/project.nuget.cache
*.editorconfig
*.cache
Moonlight/obj/Debug/net6.0/Moonlight.assets.cache
Moonlight/obj/Debug/net6.0/Moonlight.csproj.AssemblyReference.cache
Moonlight/obj/Debug/net6.0/Moonlight.GeneratedMSBuildEditorConfig.editorconfig
Moonlight/obj/Moonlight.csproj.nuget.dgspec.json
Moonlight/obj/project.assets.json
Moonlight/obj/project.nuget.cache
Moonlight/obj/project.packagespec.json

View file

@ -24,7 +24,9 @@ public class DataContext : DbContext
public DbSet<ServerVariable> ServerVariables { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<LoadingMessage> LoadingMessages { get; set; }
public DbSet<AuditLogEntry> AuditLog { get; set; }
public DbSet<Entities.Database> Databases { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)

View file

@ -0,0 +1,12 @@
using Moonlight.App.Models.Misc;
namespace Moonlight.App.Database.Entities;
public class AuditLogEntry
{
public int Id { get; set; }
public AuditLogType Type { get; set; }
public string JsonData { get; set; } = "";
public bool System { get; set; }
public string Ip { get; set; } = "";
}

View file

@ -0,0 +1,8 @@
namespace Moonlight.App.Database.Entities;
public class Database
{
public int Id { get; set; }
public int AaPanelId { get; set; }
public User Owner { get; set; }
}

View file

@ -11,4 +11,5 @@ public class Node
public int HttpPort { get; set; }
public int MoonlightDaemonPort { get; set; }
public List<NodeAllocation> Allocations { get; set; } = new();
public bool Ssl { get; set; } = false;
}

View file

@ -0,0 +1,573 @@
// <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("20230217163230_AddNodeSslOption")]
partial class AddNodeSslOption
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("Moonlight.App.Database.Entities.AuditLogEntry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Ip")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("JsonData")
.IsRequired()
.HasColumnType("longtext");
b.Property<bool>("System")
.HasColumnType("tinyint(1)");
b.Property<int>("Type")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("AuditLog");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("AaPanelId")
.HasColumnType("int");
b.Property<int>("OwnerId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("OwnerId");
b.ToTable("Databases");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<bool>("Default")
.HasColumnType("tinyint(1)");
b.Property<int?>("ImageId")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ImageId");
b.ToTable("DockerImages");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ConfigFiles")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("InstallDockerImage")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("InstallEntrypoint")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("InstallScript")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Startup")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("StartupDetection")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("StopCommand")
.IsRequired()
.HasColumnType("longtext");
b.Property<Guid>("Uuid")
.HasColumnType("char(36)");
b.HasKey("Id");
b.ToTable("Images");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int?>("ImageId")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ImageId");
b.ToTable("ImageTags");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("DefaultValue")
.IsRequired()
.HasColumnType("longtext");
b.Property<int?>("ImageId")
.HasColumnType("int");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ImageId");
b.ToTable("ImageVariables");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.LoadingMessage", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Message")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("LoadingMessages");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Fqdn")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("HttpPort")
.HasColumnType("int");
b.Property<int>("MoonlightDaemonPort")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("SftpPort")
.HasColumnType("int");
b.Property<bool>("Ssl")
.HasColumnType("tinyint(1)");
b.Property<string>("Token")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("TokenId")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("Nodes");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int?>("NodeId")
.HasColumnType("int");
b.Property<int>("Port")
.HasColumnType("int");
b.Property<int?>("ServerId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("NodeId");
b.HasIndex("ServerId");
b.ToTable("NodeAllocations");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("Cpu")
.HasColumnType("int");
b.Property<long>("Disk")
.HasColumnType("bigint");
b.Property<int>("DockerImageIndex")
.HasColumnType("int");
b.Property<int>("ImageId")
.HasColumnType("int");
b.Property<bool>("Installing")
.HasColumnType("tinyint(1)");
b.Property<int>("MainAllocationId")
.HasColumnType("int");
b.Property<long>("Memory")
.HasColumnType("bigint");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("NodeId")
.HasColumnType("int");
b.Property<string>("OverrideStartup")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("OwnerId")
.HasColumnType("int");
b.Property<bool>("Suspended")
.HasColumnType("tinyint(1)");
b.Property<Guid>("Uuid")
.HasColumnType("char(36)");
b.HasKey("Id");
b.HasIndex("ImageId");
b.HasIndex("MainAllocationId");
b.HasIndex("NodeId");
b.HasIndex("OwnerId");
b.ToTable("Servers");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerBackup", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<long>("Bytes")
.HasColumnType("bigint");
b.Property<bool>("Created")
.HasColumnType("tinyint(1)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.Property<int?>("ServerId")
.HasColumnType("int");
b.Property<Guid>("Uuid")
.HasColumnType("char(36)");
b.HasKey("Id");
b.HasIndex("ServerId");
b.ToTable("ServerBackups");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("longtext");
b.Property<int?>("ServerId")
.HasColumnType("int");
b.Property<string>("Value")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ServerId");
b.ToTable("ServerVariables");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Address")
.IsRequired()
.HasColumnType("longtext");
b.Property<bool>("Admin")
.HasColumnType("tinyint(1)");
b.Property<string>("City")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Country")
.IsRequired()
.HasColumnType("longtext");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("DiscordDiscriminator")
.IsRequired()
.HasColumnType("longtext");
b.Property<long>("DiscordId")
.HasColumnType("bigint");
b.Property<string>("DiscordUsername")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("LastName")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("State")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("Status")
.HasColumnType("int");
b.Property<DateTime>("TokenValidTime")
.HasColumnType("datetime(6)");
b.Property<bool>("TotpEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("TotpSecret")
.IsRequired()
.HasColumnType("longtext");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
{
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Owner");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Image", null)
.WithMany("DockerImages")
.HasForeignKey("ImageId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Image", null)
.WithMany("Tags")
.HasForeignKey("ImageId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Image", null)
.WithMany("Variables")
.HasForeignKey("ImageId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Node", null)
.WithMany("Allocations")
.HasForeignKey("NodeId");
b.HasOne("Moonlight.App.Database.Entities.Server", null)
.WithMany("Allocations")
.HasForeignKey("ServerId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Image", "Image")
.WithMany()
.HasForeignKey("ImageId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Moonlight.App.Database.Entities.NodeAllocation", "MainAllocation")
.WithMany()
.HasForeignKey("MainAllocationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Moonlight.App.Database.Entities.Node", "Node")
.WithMany()
.HasForeignKey("NodeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Image");
b.Navigation("MainAllocation");
b.Navigation("Node");
b.Navigation("Owner");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerBackup", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Server", null)
.WithMany("Backups")
.HasForeignKey("ServerId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Server", null)
.WithMany("Variables")
.HasForeignKey("ServerId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
{
b.Navigation("DockerImages");
b.Navigation("Tags");
b.Navigation("Variables");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b =>
{
b.Navigation("Allocations");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
{
b.Navigation("Allocations");
b.Navigation("Backups");
b.Navigation("Variables");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class AddNodeSslOption : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "Ssl",
table: "Nodes",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Ssl",
table: "Nodes");
}
}
}

View file

@ -19,6 +19,50 @@ namespace Moonlight.App.Database.Migrations
.HasAnnotation("ProductVersion", "7.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("Moonlight.App.Database.Entities.AuditLogEntry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Ip")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("JsonData")
.IsRequired()
.HasColumnType("longtext");
b.Property<bool>("System")
.HasColumnType("tinyint(1)");
b.Property<int>("Type")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("AuditLog");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("AaPanelId")
.HasColumnType("int");
b.Property<int>("OwnerId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("OwnerId");
b.ToTable("Databases");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b =>
{
b.Property<int>("Id")
@ -174,6 +218,9 @@ namespace Moonlight.App.Database.Migrations
b.Property<int>("SftpPort")
.HasColumnType("int");
b.Property<bool>("Ssl")
.HasColumnType("tinyint(1)");
b.Property<string>("Token")
.IsRequired()
.HasColumnType("longtext");
@ -403,6 +450,17 @@ namespace Moonlight.App.Database.Migrations
b.ToTable("Users");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
{
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Owner");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Image", null)

View file

@ -0,0 +1,570 @@
// <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.DatabaseMigrations
{
[DbContext(typeof(DataContext))]
[Migration("20230217152643_MigratedSomeModels")]
partial class MigratedSomeModels
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("Moonlight.App.Database.Entities.AuditLogEntry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Ip")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("JsonData")
.IsRequired()
.HasColumnType("longtext");
b.Property<bool>("System")
.HasColumnType("tinyint(1)");
b.Property<int>("Type")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("AuditLog");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("AaPanelId")
.HasColumnType("int");
b.Property<int>("OwnerId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("OwnerId");
b.ToTable("Databases");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<bool>("Default")
.HasColumnType("tinyint(1)");
b.Property<int?>("ImageId")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ImageId");
b.ToTable("DockerImages");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ConfigFiles")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("InstallDockerImage")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("InstallEntrypoint")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("InstallScript")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Startup")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("StartupDetection")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("StopCommand")
.IsRequired()
.HasColumnType("longtext");
b.Property<Guid>("Uuid")
.HasColumnType("char(36)");
b.HasKey("Id");
b.ToTable("Images");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int?>("ImageId")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ImageId");
b.ToTable("ImageTags");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("DefaultValue")
.IsRequired()
.HasColumnType("longtext");
b.Property<int?>("ImageId")
.HasColumnType("int");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ImageId");
b.ToTable("ImageVariables");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.LoadingMessage", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Message")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("LoadingMessages");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Fqdn")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("HttpPort")
.HasColumnType("int");
b.Property<int>("MoonlightDaemonPort")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("SftpPort")
.HasColumnType("int");
b.Property<string>("Token")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("TokenId")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("Nodes");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int?>("NodeId")
.HasColumnType("int");
b.Property<int>("Port")
.HasColumnType("int");
b.Property<int?>("ServerId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("NodeId");
b.HasIndex("ServerId");
b.ToTable("NodeAllocations");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("Cpu")
.HasColumnType("int");
b.Property<long>("Disk")
.HasColumnType("bigint");
b.Property<int>("DockerImageIndex")
.HasColumnType("int");
b.Property<int>("ImageId")
.HasColumnType("int");
b.Property<bool>("Installing")
.HasColumnType("tinyint(1)");
b.Property<int>("MainAllocationId")
.HasColumnType("int");
b.Property<long>("Memory")
.HasColumnType("bigint");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("NodeId")
.HasColumnType("int");
b.Property<string>("OverrideStartup")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("OwnerId")
.HasColumnType("int");
b.Property<bool>("Suspended")
.HasColumnType("tinyint(1)");
b.Property<Guid>("Uuid")
.HasColumnType("char(36)");
b.HasKey("Id");
b.HasIndex("ImageId");
b.HasIndex("MainAllocationId");
b.HasIndex("NodeId");
b.HasIndex("OwnerId");
b.ToTable("Servers");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerBackup", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<long>("Bytes")
.HasColumnType("bigint");
b.Property<bool>("Created")
.HasColumnType("tinyint(1)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.Property<int?>("ServerId")
.HasColumnType("int");
b.Property<Guid>("Uuid")
.HasColumnType("char(36)");
b.HasKey("Id");
b.HasIndex("ServerId");
b.ToTable("ServerBackups");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("longtext");
b.Property<int?>("ServerId")
.HasColumnType("int");
b.Property<string>("Value")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ServerId");
b.ToTable("ServerVariables");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Address")
.IsRequired()
.HasColumnType("longtext");
b.Property<bool>("Admin")
.HasColumnType("tinyint(1)");
b.Property<string>("City")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Country")
.IsRequired()
.HasColumnType("longtext");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("DiscordDiscriminator")
.IsRequired()
.HasColumnType("longtext");
b.Property<long>("DiscordId")
.HasColumnType("bigint");
b.Property<string>("DiscordUsername")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("LastName")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("State")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("Status")
.HasColumnType("int");
b.Property<DateTime>("TokenValidTime")
.HasColumnType("datetime(6)");
b.Property<bool>("TotpEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("TotpSecret")
.IsRequired()
.HasColumnType("longtext");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
{
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Owner");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Image", null)
.WithMany("DockerImages")
.HasForeignKey("ImageId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Image", null)
.WithMany("Tags")
.HasForeignKey("ImageId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Image", null)
.WithMany("Variables")
.HasForeignKey("ImageId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Node", null)
.WithMany("Allocations")
.HasForeignKey("NodeId");
b.HasOne("Moonlight.App.Database.Entities.Server", null)
.WithMany("Allocations")
.HasForeignKey("ServerId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Image", "Image")
.WithMany()
.HasForeignKey("ImageId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Moonlight.App.Database.Entities.NodeAllocation", "MainAllocation")
.WithMany()
.HasForeignKey("MainAllocationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Moonlight.App.Database.Entities.Node", "Node")
.WithMany()
.HasForeignKey("NodeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Image");
b.Navigation("MainAllocation");
b.Navigation("Node");
b.Navigation("Owner");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerBackup", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Server", null)
.WithMany("Backups")
.HasForeignKey("ServerId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Server", null)
.WithMany("Variables")
.HasForeignKey("ServerId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
{
b.Navigation("DockerImages");
b.Navigation("Tags");
b.Navigation("Variables");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b =>
{
b.Navigation("Allocations");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
{
b.Navigation("Allocations");
b.Navigation("Backups");
b.Navigation("Variables");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,70 @@
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.DatabaseMigrations
{
/// <inheritdoc />
public partial class MigratedSomeModels : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AuditLog",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Type = table.Column<int>(type: "int", nullable: false),
JsonData = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
System = table.Column<bool>(type: "tinyint(1)", nullable: false),
Ip = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_AuditLog", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "Databases",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
AaPanelId = table.Column<int>(type: "int", nullable: false),
OwnerId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Databases", x => x.Id);
table.ForeignKey(
name: "FK_Databases_Users_OwnerId",
column: x => x.OwnerId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_Databases_OwnerId",
table: "Databases",
column: "OwnerId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AuditLog");
migrationBuilder.DropTable(
name: "Databases");
}
}
}

View file

@ -0,0 +1,12 @@
namespace Moonlight.App.Extensions;
public static class StringExtensions
{
public static string FirstCharToUpper(this string input) =>
input switch
{
null => throw new ArgumentNullException(nameof(input)),
"" => throw new ArgumentException($"{nameof(input)} cannot be empty", nameof(input)),
_ => string.Concat(input[0].ToString().ToUpper(), input.AsSpan(1))
};
}

View file

@ -0,0 +1,37 @@
namespace Moonlight.App.Helpers;
public static class Formatter
{
public static string FormatUptime(double uptime)
{
TimeSpan t = TimeSpan.FromMilliseconds(uptime);
return $"{t.Hours}h {t.Minutes}m {t.Seconds}s";
}
private static double Round(this double d, int decimals)
{
return Math.Round(d, decimals);
}
public static string FormatSize(long bytes)
{
var i = Math.Abs(bytes) / 1024D;
if (i < 1)
{
return bytes + " B";
}
else if (i / 1024D < 1)
{
return i.Round(2) + " KB";
}
else if (i / (1024D * 1024D) < 1)
{
return (i / 1024D).Round(2) + " MB";
}
else
{
return (i / (1024D * 1024D)).Round(2) + " GB";
}
}
}

View file

@ -0,0 +1,33 @@
using System.Text;
namespace Moonlight.App.Helpers;
public static class StringHelper
{
public static string GenerateString(int length)
{
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var stringBuilder = new StringBuilder();
var random = new Random();
for (int i = 0; i < length; i++)
{
stringBuilder.Append(chars[random.Next(chars.Length)]);
}
return stringBuilder.ToString();
}
public static string IntToStringWithLeadingZeros(int number, int n)
{
string result = number.ToString();
int length = result.Length;
for (int i = length; i < n; i++)
{
result = "0" + result;
}
return result;
}
}

View file

@ -0,0 +1,40 @@
using GravatarSharp;
using Microsoft.AspNetCore.Mvc;
using Moonlight.App.Repositories;
namespace Moonlight.App.Http.Controllers.Api.Moonlight;
[ApiController]
[Route("api/moonlight/avatar")]
public class AvatarController : Controller
{
private readonly UserRepository UserRepository;
public AvatarController(UserRepository userRepository)
{
UserRepository = userRepository;
}
[HttpGet("{id:int}")]
public async Task<ActionResult> GetAvatar([FromRoute] int id)
{
var user = UserRepository.Get().FirstOrDefault(x => x.Id == id);
if (user == null)
return NotFound();
try
{
var url = GravatarController.GetImageUrl(user.Email, 100);
using var client = new HttpClient();
var res = await client.GetByteArrayAsync(url);
return File(res, "image/png");
}
catch (Exception)
{
return BadRequest();
}
}
}

View file

@ -5,7 +5,7 @@ namespace Moonlight.App.Http.Controllers.Api.Moonlight;
[ApiController]
[Route("api/moonlight/resources")]
public class Resources : Controller
public class ResourcesController : Controller
{
[HttpGet("images/{name}")]
public ActionResult GetImage([FromRoute] string name)
@ -16,8 +16,14 @@ public class Resources : Controller
return NotFound();
}
var fs = new FileStream($"resources/public/images/{name}", FileMode.Open);
if (System.IO.File.Exists($"resources/public/images/{name}"))
{
var fs = new FileStream($"resources/public/images/{name}", FileMode.Open);
return File(fs, "application/octet-stream", name);
return File(fs, MimeTypes.GetMimeType(name), name);
}
Logger.Debug("404 on resources");
return NotFound();
}
}

View file

@ -0,0 +1,8 @@
namespace Moonlight.App.Models.Misc;
public enum AuditLogType
{
Login,
Register,
LoginFail
}

View file

@ -0,0 +1,6 @@
namespace Moonlight.App.Models.Node;
public class CpuStats
{
public double CpuUsage { get; set; }
}

View file

@ -0,0 +1,6 @@
namespace Moonlight.App.Models.Node;
public class DiskStats
{
public long FreeBytes { get; set; }
}

View file

@ -0,0 +1,17 @@
namespace Moonlight.App.Models.Node;
public class DockerStats
{
public ContainerStats[] Containers { get; set; }
public int NodeId { get; set; }
}
public class ContainerStats
{
public Guid Name { get; set; }
public long Memory { get; set; }
public double Cpu { get; set; }
public long NetworkIn { get; set; }
public long NetworkOut { get; set; }
public int NodeId { get; set; }
}

View file

@ -0,0 +1,8 @@
namespace Moonlight.App.Models.Node;
public class MemoryStats
{
public long Free { get; set; }
public long Used { get; set; }
public long Total { get; set; }
}

View file

@ -0,0 +1,21 @@
using Moonlight.App.Database;
using Moonlight.App.Database.Entities;
namespace Moonlight.App.Repositories;
public class AuditLogRepository : IDisposable
{
private readonly DataContext DataContext;
public AuditLogEntry Add(AuditLogEntry entry)
{
var x = DataContext.AuditLog.Add(entry);
DataContext.SaveChanges();
return x.Entity;
}
public void Dispose()
{
DataContext.Dispose();
}
}

View file

@ -0,0 +1,43 @@
using Microsoft.EntityFrameworkCore;
using Moonlight.App.Database;
namespace Moonlight.App.Repositories;
public class DatabaseRepository : IDisposable
{
private readonly DataContext DataContext;
public DatabaseRepository(DataContext dataContext)
{
DataContext = dataContext;
}
public DbSet<Database.Entities.Database> Get()
{
return DataContext.Databases;
}
public Database.Entities.Database Add(Database.Entities.Database database)
{
var x = DataContext.Databases.Add(database);
DataContext.SaveChanges();
return x.Entity;
}
public void Update(Database.Entities.Database database)
{
DataContext.Databases.Update(database);
DataContext.SaveChanges();
}
public void Delete(Database.Entities.Database database)
{
DataContext.Databases.Remove(database);
DataContext.SaveChanges();
}
public void Dispose()
{
DataContext.Dispose();
}
}

View file

@ -0,0 +1,30 @@
using Moonlight.App.Database.Entities;
using Moonlight.App.Models.Misc;
using Moonlight.App.Repositories;
using Moonlight.App.Services.Sessions;
using Newtonsoft.Json;
namespace Moonlight.App.Services;
public class AuditLogService
{
private readonly AuditLogRepository AuditLogRepository;
private readonly IdentityService IdentityService;
public AuditLogService(AuditLogRepository auditLogRepository, IdentityService identityService)
{
AuditLogRepository = auditLogRepository;
IdentityService = identityService;
}
public void Log(AuditLogType type, object data)
{
AuditLogRepository.Add(new()
{
System = true,
Type = type,
JsonData = JsonConvert.SerializeObject(data),
Ip = IdentityService.GetIp()
});
}
}

View file

@ -0,0 +1,13 @@
using Moonlight.App.Repositories;
namespace Moonlight.App.Services;
public class NodeService
{
private readonly NodeRepository NodeRepository;
public NodeService(NodeRepository nodeRepository)
{
NodeRepository = nodeRepository;
}
}

View file

@ -0,0 +1,25 @@
using Moonlight.App.Models.Misc;
using Moonlight.App.Repositories;
using Newtonsoft.Json;
namespace Moonlight.App.Services;
public class SystemAuditLogService
{
private readonly AuditLogRepository AuditLogRepository;
public SystemAuditLogService(AuditLogRepository auditLogRepository)
{
AuditLogRepository = auditLogRepository;
}
public void Log(AuditLogType type, object data)
{
AuditLogRepository.Add(new()
{
System = true,
Type = type,
JsonData = JsonConvert.SerializeObject(data)
});
}
}

View file

@ -1,5 +1,6 @@
using JWT.Algorithms;
using JWT.Builder;
using Logging.Net;
using Moonlight.App.Database.Entities;
using Moonlight.App.Exceptions;
using Moonlight.App.Models.Misc;
@ -80,13 +81,13 @@ public class UserService
{
var user = UserRepository.Get()
.FirstOrDefault(
x => x.Email.Equals(
email
)
x => x.Email == email
);
if (user == null)
{
Logger.Debug("User not found");
//AuditLogService.Log("login:fail", $"Invalid email: {email}. Password: {password}");
throw new DisplayException("Email and password combination not found");
}

View file

@ -2,13 +2,12 @@
<Router AppAssembly="@typeof(BlazorApp).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<LayoutView Layout="@typeof(NotFoundLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</Router>

View file

@ -17,7 +17,7 @@
<PackageReference Include="BlazorTable" Version="1.17.0" />
<PackageReference Include="CurrieTechnologies.Razor.SweetAlert2" Version="5.4.0" />
<PackageReference Include="Discord.Net" Version="3.9.0" />
<PackageReference Include="GravatarSharp.Core" Version="0.9.0.2" />
<PackageReference Include="GravatarSharp.Core" Version="1.0.1.2" />
<PackageReference Include="JWT" Version="10.0.2" />
<PackageReference Include="Logging.Net" Version="1.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.3">
@ -25,6 +25,10 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.15.1" />
<PackageReference Include="MimeTypes" Version="2.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MineStat" Version="3.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3-beta1" />
<PackageReference Include="Otp.NET" Version="1.3.0" />
@ -56,6 +60,7 @@
<Folder Include="App\Http\Middleware" />
<Folder Include="App\Http\Requests" />
<Folder Include="App\Http\Resources" />
<Folder Include="App\Models\AuditLogData" />
<Folder Include="resources\lang" />
<Folder Include="wwwroot\assets\media" />
</ItemGroup>

View file

@ -33,6 +33,8 @@ namespace Moonlight
builder.Services.AddScoped<NodeRepository>();
builder.Services.AddScoped<ServerRepository>();
builder.Services.AddScoped<ServerBackupRepository>();
builder.Services.AddScoped<AuditLogRepository>();
builder.Services.AddScoped<DatabaseRepository>();
// Services
builder.Services.AddSingleton<ConfigService>();
@ -46,6 +48,9 @@ namespace Moonlight
builder.Services.AddScoped<TotpService>();
builder.Services.AddScoped<ToastService>();
builder.Services.AddScoped<AuditLogService>();
builder.Services.AddScoped<SystemAuditLogService>();
// Helpers
builder.Services.AddSingleton<SmartTranslateHelper>();

View file

@ -10,7 +10,7 @@
<div class="card card-flush w-lg-650px py-5">
<div class="card-body py-15 py-lg-20">
<div class="mb-14">
<img alt="Logo" src="@(moonlightConfig.GetValue<string>("AppUrl"))/api/moonlight/resources/images/logofull.png" class="h-40px">
<img alt="Logo" src="@(moonlightConfig.GetValue<string>("AppUrl"))/api/moonlight/resources/images/logolong.png" class="h-40px">
</div>
<h1 class="fw-bolder text-gray-900 mb-5"><TL>Your account is banned from moonlight</TL></h1>
<div class="fw-semibold fs-6 text-gray-500 mb-8">

View file

@ -10,7 +10,7 @@
<div class="card card-flush w-lg-650px py-5">
<div class="card-body py-15 py-lg-20">
<div class="mb-14">
<img alt="Logo" src="@(moonlightConfig.GetValue<string>("AppUrl"))/api/moonlight/resources/images/logofull.png" class="h-40px">
<img alt="Logo" src="@(moonlightConfig.GetValue<string>("AppUrl"))/api/moonlight/resources/images/logolong.png" class="h-40px">
</div>
<h1 class="fw-bolder text-gray-900 mb-5"><TL>Your moonlight account is disabled</TL></h1>
<div class="fw-semibold fs-6 text-gray-500 mb-8">

View file

@ -0,0 +1,161 @@
@page "/login"
@* This is just a "virtual" route/page. The handling for that is
@* MainLayout doing for us. We need to put that here so the router
@* does not return the 404 page
*@
@using Moonlight.App.Services.Interop
@using Moonlight.App.Services
@using Moonlight.App.Exceptions
@using Logging.Net
@using Moonlight.App.Services.Sessions
@inject AlertService AlertService
@inject UserService UserService
@inject SmartTranslateService SmartTranslateService
@inject CookieService CookieService
@inject NavigationManager NavigationManager
<div class="d-flex flex-center">
<div class="card rounded-3 w-md-550px">
<div class="card-body">
<div class="d-flex flex-center flex-column-fluid pb-15 pb-lg-20">
<div class="form w-100 fv-plugins-bootstrap5 fv-plugins-framework" novalidate="novalidate">
@if (!TotpRequired)
{
<div class="text-center mb-11">
<h1 class="text-dark fw-bolder mb-3">
<TL>Sign In</TL>
</h1>
<div class="text-gray-500 fw-semibold fs-6">
<TL>Sign in to start with moonlight</TL>
</div>
</div>
<div class="row g-3 mb-9">
<div class="col-md-6">
<a href="#" class="btn btn-flex btn-outline btn-text-gray-700 btn-active-color-primary bg-state-light flex-center text-nowrap w-100">
<div class="h-15px me-3">
<i class="bx bx-md bxl-discord-alt"></i>
</div>
<TL>Sign in with Discord</TL>
</a>
</div>
<div class="col-md-6">
<a href="#" class="btn btn-flex btn-outline btn-text-gray-700 btn-active-color-primary bg-state-light flex-center text-nowrap w-100">
<div class="h-15px me-3">
<i class="bx bx-md bxl-google"></i>
</div>
<TL>Sign in with Google</TL>
</a>
</div>
</div>
<div class="separator separator-content my-14">
<span class="w-125px text-gray-500 fw-semibold fs-7">
<TL>Or with email</TL>
</span>
</div>
<div class="fv-row mb-8 fv-plugins-icon-container">
<input @bind="Email" type="text" placeholder="@(SmartTranslateService.Translate("Email"))" class="form-control bg-transparent">
</div>
<div class="fv-row mb-3 fv-plugins-icon-container">
<input @bind="Password" type="password" placeholder="@(SmartTranslateService.Translate("Password"))" class="form-control bg-transparent">
</div>
<div class="d-flex flex-stack flex-wrap gap-3 fs-base fw-semibold mb-8">
<div></div>
<a href="/reset-password" class="link-primary">
<TL>Forgot password?</TL>
</a>
</div>
<div class="d-grid mb-10">
<WButton Text="@(SmartTranslateService.Translate("Sign-in"))"
WorkingText="@(SmartTranslateService.Translate("Working"))"
CssClasses="btn-primary"
OnClick="DoLogin">
</WButton>
</div>
}
else
{
<div class="fv-row mb-8 fv-plugins-icon-container">
<input type="number" class="form-control bg-transparent">
</div>
<div class="d-grid mb-10">
<WButton Text="@(SmartTranslateService.Translate("Sign-in"))"
WorkingText="@(SmartTranslateService.Translate("Working"))"
CssClasses="btn-primary"
OnClick="DoLogin">
</WButton>
</div>
}
<div class="text-gray-500 text-center fw-semibold fs-6">
<TL>Not registered yet?</TL>
<a href="/register" class="link-primary">
<TL>Sign up</TL>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
@code
{
private string Email = "";
private string Password = "";
private bool TotpRequired = false;
private string TotpCode = "";
private async Task DoLogin()
{
try
{
Email = Email.ToLower().Trim();
TotpRequired = await UserService.CheckTotp(Email, Password);
if (!TotpRequired)
{
var token = await UserService.Login(Email, Password);
await CookieService.SetValue("token", token, 10);
if(NavigationManager.Uri.EndsWith("login"))
NavigationManager.NavigateTo("/", true);
else
NavigationManager.NavigateTo(NavigationManager.Uri, true);
}
else
{
await InvokeAsync(StateHasChanged);
}
}
catch (DisplayException e)
{
await AlertService.Error(
SmartTranslateService.Translate("Error"),
SmartTranslateService.Translate(e.Message)
);
}
catch (Exception e)
{
await AlertService.Error(
SmartTranslateService.Translate("Error"),
SmartTranslateService.Translate("An error occured while logging you in")
);
Logger.Error("Error while login");
Logger.Error(e);
}
}
}

View file

@ -0,0 +1,88 @@
@page "/register"
@* This is just a "virtual" route/page. The handling for that is
@* MainLayout doing for us. We need to put that here so the router
@* does not return the 404 page
*@
@using Moonlight.App.Services
@inject SmartTranslateService SmartTranslateService
<div class="d-flex flex-center">
<div class="card rounded-3 w-md-550px">
<div class="card-body">
<div class="d-flex flex-center flex-column-fluid pb-15 pb-lg-20">
<div class="form w-100 fv-plugins-bootstrap5 fv-plugins-framework" novalidate="novalidate">
<div class="text-center mb-11">
<h1 class="text-dark fw-bolder mb-3">
<TL>Sign Up</TL>
</h1>
<div class="text-gray-500 fw-semibold fs-6">
<TL>Sign up to start with moonlight</TL>
</div>
</div>
<div class="row g-3 mb-9">
<div class="col-md-6">
<a href="#" class="btn btn-flex btn-outline btn-text-gray-700 btn-active-color-primary bg-state-light flex-center text-nowrap w-100">
<div class="h-15px me-3">
<i class="bx bx-md bxl-discord-alt"></i>
</div>
<TL>Sign up with Discord</TL>
</a>
</div>
<div class="col-md-6">
<a href="#" class="btn btn-flex btn-outline btn-text-gray-700 btn-active-color-primary bg-state-light flex-center text-nowrap w-100">
<div class="h-15px me-3">
<i class="bx bx-md bxl-google"></i>
</div>
<TL>Sign up with Google</TL>
</a>
</div>
</div>
<div class="separator separator-content my-14">
<span class="w-125px text-gray-500 fw-semibold fs-7">
<TL>Or with email</TL>
</span>
</div>
<div class="fv-row mb-8 fv-plugins-icon-container">
<input type="text" placeholder="@(SmartTranslateService.Translate("Firstname"))" name="text" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8 fv-plugins-icon-container">
<input type="text" placeholder="@(SmartTranslateService.Translate("Lastname"))" name="text"class="form-control bg-transparent">
</div>
<div class="fv-row mb-8 fv-plugins-icon-container">
<input type="text" placeholder="@(SmartTranslateService.Translate("Email"))" name="email" autocomplete="off" class="form-control bg-transparent">
</div>
<div class="fv-row mb-3 fv-plugins-icon-container">
<input type="password" placeholder="@(SmartTranslateService.Translate("Password"))" name="password" autocomplete="off" class="form-control bg-transparent">
</div>
<div class="fv-row mb-5 fv-plugins-icon-container">
<input type="password" placeholder="@(SmartTranslateService.Translate("Repeat password"))" name="password" autocomplete="off" class="form-control bg-transparent">
</div>
<div class="d-grid mb-10">
<button class="btn btn-primary">
<TL>Sign-up</TL>
</button>
</div>
<div class="text-gray-500 text-center fw-semibold fs-6">
<TL>Already registered?</TL>
<a href="/login" class="link-primary">
<TL>Sign in</TL>
</a>
</div>
</div>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,50 @@
@if (loaded)
{
@ChildContent
}
else
{
<div class="d-flex flex-center flex-column">
<span class="fs-1 spinner-border spinner-border-lg align-middle me-2"></span>
<span class="mt-3 fs-5">@(Text)</span>
</div>
}
@code
{
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public Func<LazyLoader, Task> Load { get; set; }
[Parameter]
public string Text { get; set; } = "";
private bool loaded = false;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await Load.Invoke(this);
loaded = true;
await InvokeAsync(StateHasChanged);
}
}
public async Task SetText(string text)
{
Text = text;
await InvokeAsync(StateHasChanged);
}
public async Task Reload()
{
loaded = false;
await InvokeAsync(StateHasChanged);
await Load.Invoke(this);
loaded = true;
await InvokeAsync(StateHasChanged);
}
}

View file

@ -36,43 +36,6 @@ else
<span class="menu-title"><TL>Dashboard</TL></span>
</a>
</div>
<div data-kt-menu-trigger="click" class="menu-item menu-accordion">
<span class="menu-link">
<span class="menu-icon">
<i class="bx bx-cart-alt"></i>
</span>
<span class="menu-title"><TL>Order</TL></span>
<span class="menu-arrow"></span>
</span>
<div class="menu-sub menu-sub-accordion">
<div class="menu-item">
<a class="menu-link" href="/store/website">
<span class="menu-bullet">
<span class="bullet bullet-dot"></span>
</span>
<span class="menu-title"><TL>Website</TL></span>
</a>
</div>
<div class="menu-item">
<a class="menu-link" href="/store/database">
<span class="menu-bullet">
<span class="bullet bullet-dot"></span>
</span>
<span class="menu-title"><TL>Database</TL></span>
</a>
</div>
<div class="menu-item">
<a class="menu-link" href="/store/domain">
<span class="menu-bullet">
<span class="bullet bullet-dot"></span>
</span>
<span class="menu-title"><TL>Domain</TL></span>
</a>
</div>
</div>
</div>
<div class="menu-item">
<a class="menu-link" href="/servers">
<span class="menu-icon">

View file

@ -0,0 +1,36 @@
@using Moonlight.App.Services.Sessions
@using Moonlight.App.Database.Entities
@inject IdentityService IdentityService
@if (User != null)
{
if (User.Admin)
{
@ChildContent
}
else
{
<div class="alert alert-danger">
<TL>Missing admin permissions. This attempt has been logged ;)</TL>
</div>
}
}
@code
{
[Parameter]
public RenderFragment ChildContent { get; set; }
private User? User;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
User = await IdentityService.Get();
await InvokeAsync(StateHasChanged);
}
}
}

View file

@ -1,7 +1,9 @@
@using Moonlight.Shared.Components.ErrorBoundaries
@using Moonlight.Shared.Components.Partials
@using Moonlight.Shared.Components.Alerts
@using Moonlight.Shared.Components.Auth
@using Moonlight.App.Database.Entities
@using Moonlight.App.Extensions
@using Moonlight.App.Models.Misc
@using Moonlight.App.Services.Sessions
@ -15,10 +17,30 @@
@inject NavigationManager NavigationManager
<GlobalErrorBoundary>
@{
var uri = new Uri(NavigationManager.Uri);
var pathParts = uri.LocalPath.Split("/").Reverse();
var title = "";
foreach (var pathPart in pathParts)
{
if (!string.IsNullOrEmpty(pathPart))
{
if(pathPart == pathParts.Last())
title += $"{pathPart.FirstCharToUpper()} ";
else
title += $"{pathPart.FirstCharToUpper()} - ";
}
}
}
<PageTitle>@(string.IsNullOrEmpty(title) ? "Dashboard - " : title)Moonlight</PageTitle>
<div class="d-flex flex-column flex-root app-root" id="kt_app_root">
<div class="app-page flex-column flex-column-fluid" id="kt_app_page">
<canvas id="snow" class="snow-canvas"></canvas>
@{
//TODO: Add a way to disable the snow
}
@ -32,23 +54,38 @@
<div id="kt_app_content_container" class="app-container container-fluid">
<div class="mt-10">
<PageErrorBoundary>
@if (User == null)
@if (uri.LocalPath != "/login" &&
uri.LocalPath != "/register")
{
@Body
}
else
{
if (User.Status == UserStatus.Banned)
if (User == null)
{
<BannedAlert></BannedAlert>
}
else if (User.Status == UserStatus.Disabled)
{
<DisabledAlert></DisabledAlert>
<Login></Login>
}
else
{
@Body
if (User.Status == UserStatus.Banned)
{
<BannedAlert></BannedAlert>
}
else if (User.Status == UserStatus.Disabled)
{
<DisabledAlert></DisabledAlert>
}
else
{
@Body
}
}
}
else
{
if (uri.LocalPath == "/login")
{
<Login></Login>
}
else if (uri.LocalPath == "/register")
{
<Register></Register>
}
}
</PageErrorBoundary>
@ -66,7 +103,7 @@
@code
{
private User? User;
protected override void OnInitialized()
{
AddBodyAttribute("data-kt-app-page-loading", "on");
@ -74,7 +111,7 @@
protected override void OnAfterRender(bool firstRender)
{
//Initialize classes and attributes for layout with dark sidebar
//Initialize classes and attributes for layout with dark sidebar
AddBodyAttribute("data-kt-app-reset-transition", "true");
AddBodyAttribute("data-kt-app-layout", "dark-sidebar");
@ -104,7 +141,7 @@
await InvokeAsync(StateHasChanged);
await Task.Delay(300);
await JsRuntime.InvokeVoidAsync("document.body.removeAttribute", "data-kt-app-reset-transition");
await JsRuntime.InvokeVoidAsync("document.body.removeAttribute", "data-kt-app-page-loading");
await JsRuntime.InvokeVoidAsync("KTMenu.createInstances");
@ -117,7 +154,7 @@
}
catch (Exception)
{
// ignored
// ignored
}
}
}
@ -131,9 +168,9 @@
{
JsRuntime.InvokeVoidAsync("document.body.setAttribute", attribute, value);
}
private void AddBodyClass(string className)
{
JsRuntime.InvokeVoidAsync("document.body.classList.add", className);
}
}
}

View file

@ -0,0 +1,134 @@
@using Moonlight.Shared.Components.ErrorBoundaries
@using Moonlight.App.Database.Entities
@using Moonlight.App.Extensions
@using Moonlight.App.Services.Sessions
@layout ThemeInit
@implements IDisposable
@inherits LayoutComponentBase
@inject IJSRuntime JsRuntime
@inject IdentityService IdentityService
@inject SessionService SessionService
@inject NavigationManager NavigationManager
<GlobalErrorBoundary>
@{
var uri = new Uri(NavigationManager.Uri);
var pathParts = uri.LocalPath.Split("/");
var title = "";
foreach (var pathPart in pathParts)
{
if (!string.IsNullOrEmpty(pathPart))
title += $"{pathPart.FirstCharToUpper()} ";
}
}
<PageTitle>@(string.IsNullOrEmpty(title) ? "Dashboard " : title)- Moonlight</PageTitle>
<div class="d-flex flex-column flex-root app-root" id="kt_app_root">
<div class="app-page flex-column flex-column-fluid" id="kt_app_page">
<canvas id="snow" class="snow-canvas"></canvas>
@{
//TODO: Add a way to disable the snow
}
<PageHeader></PageHeader>
<div class="app-wrapper flex-column flex-row-fluid" id="kt_app_wrapper">
<Sidebar></Sidebar>
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
<div class="d-flex flex-column flex-column-fluid">
<div id="kt_app_content" class="app-content flex-column-fluid">
<div id="kt_app_content_container" class="app-container container-fluid">
<div class="mt-10">
<PageErrorBoundary>
@Body
</PageErrorBoundary>
</div>
</div>
</div>
</div>
<Footer></Footer>
</div>
</div>
</div>
</div>
</GlobalErrorBoundary>
@code
{
private User? User;
protected override void OnInitialized()
{
AddBodyAttribute("data-kt-app-page-loading", "on");
}
protected override void OnAfterRender(bool firstRender)
{
//Initialize classes and attributes for layout with dark sidebar
AddBodyAttribute("data-kt-app-reset-transition", "true");
AddBodyAttribute("data-kt-app-layout", "dark-sidebar");
AddBodyAttribute("data-kt-app-header-fixed", "true");
AddBodyAttribute("data-kt-app-sidebar-fixed", "true");
AddBodyAttribute("data-kt-app-sidebar-hoverable", "true");
AddBodyAttribute("data-kt-app-sidebar-push-header", "true");
AddBodyAttribute("data-kt-app-sidebar-push-toolbar", "true");
AddBodyAttribute("data-kt-app-sidebar-push-footer", "true");
AddBodyAttribute("data-kt-app-toolbar-enabled", "true");
AddBodyClass("app-default");
JsRuntime.InvokeVoidAsync("KTModalUpgradePlan.init");
JsRuntime.InvokeVoidAsync("KTCreateApp.init");
JsRuntime.InvokeVoidAsync("KTModalUserSearch.init");
JsRuntime.InvokeVoidAsync("KTModalNewTarget.init");
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
try
{
User = await IdentityService.Get();
await InvokeAsync(StateHasChanged);
await Task.Delay(300);
await JsRuntime.InvokeVoidAsync("document.body.removeAttribute", "data-kt-app-reset-transition");
await JsRuntime.InvokeVoidAsync("document.body.removeAttribute", "data-kt-app-page-loading");
await JsRuntime.InvokeVoidAsync("KTMenu.createInstances");
await JsRuntime.InvokeVoidAsync("KTDrawer.createInstances");
await JsRuntime.InvokeVoidAsync("createSnow");
await SessionService.Register();
NavigationManager.LocationChanged += (sender, args) => { SessionService.Refresh(); };
}
catch (Exception)
{
// ignored
}
}
}
public void Dispose()
{
SessionService.Close();
}
private void AddBodyAttribute(string attribute, string value)
{
JsRuntime.InvokeVoidAsync("document.body.setAttribute", attribute, value);
}
private void AddBodyClass(string className)
{
JsRuntime.InvokeVoidAsync("document.body.classList.add", className);
}
}

View file

@ -0,0 +1,115 @@
@page "/admin/nodes/edit/{id:int}"
@using Moonlight.App.Repositories
@using Moonlight.App.Database.Entities
@using Moonlight.App.Services
@inject NodeRepository NodeRepository
@inject SmartTranslateService SmartTranslateService
@inject NavigationManager NavigationManager
<OnlyAdmin>
<LazyLoader Load="Load">
@if (Node == null)
{
<div class="alert alert-warning">
<TL>No node with this id found</TL>
</div>
}
else
{
<div class="d-flex flex-center">
<div class="card rounded-3 w-md-550px">
<div class="card-body">
<div class="d-flex flex-center flex-column-fluid">
<div class="form w-100 fv-plugins-bootstrap5 fv-plugins-framework">
<div class="fv-row mb-8">
<label>
<TL>Nodename</TL>
</label>
<input @bind="Node.Name" type="text" placeholder="@(SmartTranslateService.Translate("Nodename"))" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8">
<label>
<TL>FQDN</TL>
</label>
<input @bind="Node.Fqdn" type="text" placeholder="@(SmartTranslateService.Translate("FQDN"))" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8">
<label>
<TL>Token Id</TL>
</label>
<input @bind="Node.TokenId" type="text" placeholder="@(SmartTranslateService.Translate("Toekn Id"))" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8">
<label>
<TL>Token</TL>
</label>
<input @bind="Node.Token" type="text" placeholder="@(SmartTranslateService.Translate("Token"))" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8">
<label>
<TL>Http port</TL>
</label>
<input @bind="Node.HttpPort" type="number" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8">
<label>
<TL>Sftp port</TL>
</label>
<input @bind="Node.SftpPort" type="number" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8">
<label>
<TL>Moonlight daemon port</TL>
</label>
<input @bind="Node.MoonlightDaemonPort" type="number" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8">
<div class="input-group">
<label class="col-lg-4 col-form-label fw-semibold fs-6">
<TL>SSL</TL>
</label>
<div class="col-lg-8 d-flex align-items-center">
<div class="form-check form-check-solid form-switch form-check-custom fv-row">
<input @bind="Node.Ssl" class="form-check-input w-45px h-30px" type="checkbox" id="ssl">
<label class="form-check-label" for="ssl"></label>
</div>
</div>
</div>
</div>
<div class="fv-row mb-9">
<WButton Text="@(SmartTranslateService.Translate("Save"))"
WorkingText="@(SmartTranslateService.Translate("Saving"))"
CssClasses="btn-primary"
OnClick="Save">
</WButton>
</div>
</div>
</div>
</div>
</div>
</div>
}
</LazyLoader>
</OnlyAdmin>
@code
{
[Parameter]
public int Id { get; set; }
private Node? Node;
private async Task Load(LazyLoader arg)
{
Node = NodeRepository.Get().FirstOrDefault(x => x.Id == Id);
}
private Task Save()
{
NodeRepository.Update(Node);
NavigationManager.NavigateTo("/admin/nodes");
return Task.CompletedTask;
}
}

View file

@ -0,0 +1,165 @@
@page "/admin/nodes"
@using Moonlight.App.Repositories
@using Moonlight.App.Database.Entities
@using Moonlight.App.Helpers
@using Moonlight.App.Models.Node
@using Moonlight.App.Services
@inject NodeRepository NodeRepository
@inject SmartTranslateService SmartTranslateService
<OnlyAdmin>
<div class="row mb-5">
<div class="card card-body">
<a class="btn btn-primary" href="/admin/nodes/new"><TL>Add a new node</TL></a>
</div>
</div>
<div class="row">
<LazyLoader Load="Load">
@if (!Nodes.Any())
{
<div class="alert alert-info">
<TL>No nodes found. Start with adding a new node</TL>
</div>
}
else
{
foreach (var node in Nodes)
{
<div class="col-xl-6 mb-xl-10">
<div class="card card-flush h-xl-100">
<div class="card-header pt-5">
<h4 class="card-title d-flex align-items-start flex-column">
<span class="card-label fw-bold text-gray-800">@(node.Name) - (ID: @(node.Id))</span>
</h4>
</div>
<div class="card-body pt-6">
<div class="d-flex flex-stack">
<div class="d-flex align-items-center me-3">
<div class="flex-grow-1">
<span class="text-gray-800 fs-5 fw-bold lh-0">
<TL>CPU Usage</TL>
</span>
<span class="text-gray-400 fw-semibold d-block fs-6">
<TL>In %</TL>
</span>
</div>
</div>
<div class="d-flex align-items-center w-100 mw-125px">
<span class="text-white-400 fw-semibold">
@{
var cpu = CpuCache.ContainsKey(node) ? CpuCache[node] : null;
}
@if (cpu == null)
{
<span>Loading</span>
}
else
{
<span>@(cpu.CpuUsage)%</span>
}
</span>
</div>
</div>
<div class="separator separator-dashed my-3"></div>
<div class="d-flex flex-stack">
<div class="d-flex align-items-center me-3">
<div class="flex-grow-1">
<span class="text-gray-800 fs-5 fw-bold lh-0">
<TL>Memory</TL>
</span>
<span class="text-gray-400 fw-semibold d-block fs-6">
<TL>Used / Available memory</TL>
</span>
</div>
</div>
<div class="d-flex align-items-center w-100 mw-125px">
<span class="text-white-400 fw-semibold">
@{
var memory = MemoryCache.ContainsKey(node) ? MemoryCache[node] : null;
}
@if (memory == null)
{
<span>Loading</span>
}
else
{
<span>@(Formatter.FormatSize(memory.Total - memory.Free)) / @(Formatter.FormatSize(memory.Total))</span>
}
</span>
</div>
</div>
<div class="separator separator-dashed my-3"></div>
<div class="d-flex flex-stack">
<div class="d-flex align-items-center me-3">
<div class="flex-grow-1">
<span class="text-gray-800 fs-5 fw-bold lh-0">
<TL>Storage</TL>
</span>
<span class="text-gray-400 fw-semibold d-block fs-6">
<TL>Available storage</TL>
</span>
</div>
</div>
<div class="d-flex align-items-center w-100 mw-125px">
<span class="text-white-400 fw-semibold">
@{
var disk = DiskCache.ContainsKey(node) ? DiskCache[node] : null;
}
@if (disk == null)
{
<span>Loading</span>
}
else
{
<span>@(Formatter.FormatSize(disk.FreeBytes))</span>
}
</span>
</div>
</div>
<div class="separator my-5"></div>
<div class="d-flex flex-stack">
<div class="align-items-start">
<a class="btn btn-primary" href="/admin/nodes/edit/@(node.Id)">
<TL>Edit</TL>
</a>
<WButton Text="@(SmartTranslateService.Translate("Delete"))"
WorkingText="@(SmartTranslateService.Translate("Deleting"))"
CssClasses="btn-danger"
OnClick="() => Delete(node)"></WButton>
</div>
</div>
</div>
</div>
</div>
}
}
</LazyLoader>
</div>
</OnlyAdmin>
@code
{
private Node[] Nodes;
private Dictionary<Node, CpuStats> CpuCache = new();
private Dictionary<Node, MemoryStats> MemoryCache = new();
private Dictionary<Node, DiskStats> DiskCache = new();
private Task Load(LazyLoader lazyLoader)
{
Nodes = NodeRepository.Get().ToArray();
Task.Run(() => { });
return Task.CompletedTask;
}
private Task Delete(Node node)
{
return Task.CompletedTask;
}
}

View file

@ -0,0 +1,95 @@
@page "/admin/nodes/new"
@using Moonlight.App.Database.Entities
@using Moonlight.App.Helpers
@using Moonlight.App.Repositories
@using Moonlight.App.Services
@inject SmartTranslateService SmartTranslateService
@inject NodeRepository NodeRepository
@inject NavigationManager NavigationManager
<OnlyAdmin>
<div class="d-flex flex-center">
<div class="card rounded-3 w-md-550px">
<div class="card-body">
<div class="d-flex flex-center flex-column-fluid">
<div class="form w-100 fv-plugins-bootstrap5 fv-plugins-framework">
<div class="fv-row mb-8">
<label>
<TL>Nodename</TL>
</label>
<input @bind="NewNode.Name" type="text" placeholder="@(SmartTranslateService.Translate("Nodename"))" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8">
<label>
<TL>FQDN</TL>
</label>
<input @bind="NewNode.Fqdn" type="text" placeholder="@(SmartTranslateService.Translate("FQDN"))" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8">
<label>
<TL>Http port</TL>
</label>
<input @bind="NewNode.HttpPort" type="number" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8">
<label>
<TL>Sftp port</TL>
</label>
<input @bind="NewNode.SftpPort" type="number" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8">
<label>
<TL>Moonlight daemon port</TL>
</label>
<input @bind="NewNode.MoonlightDaemonPort" type="number" class="form-control bg-transparent">
</div>
<div class="fv-row mb-8">
<div class="input-group">
<label class="col-lg-4 col-form-label fw-semibold fs-6">
<TL>SSL</TL>
</label>
<div class="col-lg-8 d-flex align-items-center">
<div class="form-check form-check-solid form-switch form-check-custom fv-row">
<input @bind="NewNode.Ssl" class="form-check-input w-45px h-30px" type="checkbox" id="ssl">
<label class="form-check-label" for="ssl"></label>
</div>
</div>
</div>
</div>
<div class="fv-row mb-9">
<WButton Text="@(SmartTranslateService.Translate("Create"))"
WorkingText="@(SmartTranslateService.Translate("Creating"))"
CssClasses="btn-primary"
OnClick="Create">
</WButton>
</div>
</div>
</div>
</div>
</div>
</div>
</OnlyAdmin>
@code
{
private Node NewNode = new()
{ // Default values
HttpPort = 8080,
SftpPort = 2022,
MoonlightDaemonPort = 8081,
Ssl = true
};
private Task Create()
{
NewNode.Token = StringHelper.GenerateString(65);
NewNode.TokenId = StringHelper.GenerateString(17);
NodeRepository.Add(NewNode);
NavigationManager.NavigateTo("/admin/nodes");
return Task.CompletedTask;
}
}

View file

@ -1,7 +1,232 @@
@page "/"
@using Moonlight.App.Repositories
@using Moonlight.App.Repositories.Servers
<div class="card">
<div class="card-body">
x
@inject DatabaseRepository DatabaseRepository
@inject ServerRepository ServerRepository
<LazyLoader Load="Load">
<div class="row mb-5">
<div class="col-12 col-lg-6 col-xl">
<a class="mt-4 card" href="/servers">
<div class="card-body">
<div class="row align-items-center gx-0">
<div class="col">
<h6 class="text-uppercase text-muted mb-2">
<TL>Servers</TL>
</h6>
<span class="h2 mb-0">
@(ServerCount)
</span>
</div>
<div class="col-auto">
<span class="h2 text-muted mb-0">
<i class="text-primary bx bx-server bx-lg"></i>
</span>
</div>
</div>
</div>
</a>
</div>
</div>
<div class="col-12 col-lg-6 col-xl">
<a class="mt-4 card" href="/websites">
<div class="card-body">
<div class="row align-items-center gx-0">
<div class="col">
<h6 class="text-uppercase text-muted mb-2">
<TL>Websites</TL>
</h6>
<span class="h2 mb-0">
0
</span>
</div>
<div class="col-auto">
<span class="h2 text-muted mb-0">
<i class="text-primary bx bx-globe bx-lg"></i>
</span>
</div>
</div>
</div>
</a>
</div>
<div class="col-12 col-lg-6 col-xl">
<div class="mt-4 card" href="/databases">
<div class="card-body">
<div class="row align-items-center gx-0">
<div class="col">
<h6 class="text-uppercase text-muted mb-2">
<TL>Databases</TL>
</h6>
<span class="h2 mb-0">
@(DatabaseCount)
</span>
</div>
<div class="col-auto">
<span class="h2 text-muted mb-0">
<i class="text-primary bx bx-data bx-lg"></i>
</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6 col-xl">
<a class="mt-4 card" href="/domains">
<div class="card-body">
<div class="row align-items-center gx-0">
<div class="col">
<h6 class="text-uppercase text-muted mb-2">
<TL>Domains</TL>
</h6>
<span class="h2 mb-0">
0
</span>
</div>
<div class="col-auto">
<span class="h2 text-muted mb-">
<i class="text-primary bx bx-purchase-tag bx-lg"></i>
</span>
</div>
</div>
</div>
</a>
</div>
</div>
<div class="d-flex flex-row mb-5">
<div class="card card-body">
<span class="card-title mb-3 fs-3">
<TL>Create something new</TL>
</span>
<div class="flex-row">
<div class="d-flex align-items-center">
<div class="symbol symbol-50px me-3">
<i class="bx bx-md bx-server"></i>
</div>
<div class="d-flex justify-content-start flex-column">
<a href="/servers/create" class="text-gray-800 text-hover-primary mb-1 fs-5">
<TL>Create a gameserver</TL>
</a>
<span class="text-gray-400 fw-semibold d-block fs-6">
<TL>A new gameserver in just a few minutes</TL>
</span>
</div>
</div>
<div class="d-flex align-items-center">
<div class="symbol symbol-50px me-3">
<i class="bx bx-md bx-data"></i>
</div>
<div class="d-flex justify-content-start flex-column">
<a href="/databases/create" class="text-gray-800 text-hover-primary mb-1 fs-5">
<TL>Create a database</TL>
</a>
<span class="text-gray-400 fw-semibold d-block fs-6">
<TL>A quick way to store your data and manage it from all around the world</TL>
</span>
</div>
</div>
<div class="d-flex align-items-center">
<div class="symbol symbol-50px me-3">
<i class="bx bx-md bx-globe"></i>
</div>
<div class="d-flex justify-content-start flex-column">
<a href="/websites/create" class="text-gray-800 text-hover-primary mb-1 fs-5">
<TL>Create a website</TL>
</a>
<span class="text-gray-400 fw-semibold d-block fs-6">
<TL>Make your own websites with a webspace</TL>
</span>
</div>
</div>
<div class="d-flex align-items-center">
<div class="symbol symbol-50px me-3">
<i class="bx bx-md bx-purchase-tag"></i>
</div>
<div class="d-flex justify-content-start flex-column">
<a href="/domains/create" class="text-gray-800 text-hover-primary mb-1 fs-5">
<TL>Create a domain</TL>
</a>
<span class="text-gray-400 fw-semibold d-block fs-6">
<TL>Make your servvices accessible throught your own domain</TL>
</span>
</div>
</div>
</div>
</div>
</div>
<div class="d-flex flex-row">
<div class="card card-body">
<span class="card-title mb-3 fs-3">
<TL>Manage your services</TL>
</span>
<div class="flex-row">
<div class="d-flex align-items-center">
<div class="symbol symbol-50px me-3">
<i class="bx bx-md bx-server"></i>
</div>
<div class="d-flex justify-content-start flex-column">
<a href="/servers" class="text-gray-800 text-hover-primary mb-1 fs-5">
<TL>Manage your gameservers</TL>
</a>
<span class="text-gray-400 fw-semibold d-block fs-6">
<TL>Adjust your gameservers</TL>
</span>
</div>
</div>
<div class="d-flex align-items-center">
<div class="symbol symbol-50px me-3">
<i class="bx bx-md bx-data"></i>
</div>
<div class="d-flex justify-content-start flex-column">
<a href="/databases" class="text-gray-800 text-hover-primary mb-1 fs-5">
<TL>Manage your databases</TL>
</a>
<span class="text-gray-400 fw-semibold d-block fs-6">
<TL>Insert, delete and update the data in your databases</TL>
</span>
</div>
</div>
<div class="d-flex align-items-center">
<div class="symbol symbol-50px me-3">
<i class="bx bx-md bx-globe"></i>
</div>
<div class="d-flex justify-content-start flex-column">
<a href="/websites" class="text-gray-800 text-hover-primary mb-1 fs-5">
<TL>Manage your websites</TL>
</a>
<span class="text-gray-400 fw-semibold d-block fs-6">
<TL>Modify the content of your websites</TL>
</span>
</div>
</div>
<div class="d-flex align-items-center">
<div class="symbol symbol-50px me-3">
<i class="bx bx-md bx-purchase-tag"></i>
</div>
<div class="d-flex justify-content-start flex-column">
<a href="/domains" class="text-gray-800 text-hover-primary mb-1 fs-5">
<TL>Manage your domains</TL>
</a>
<span class="text-gray-400 fw-semibold d-block fs-6">
<TL>Add, edit and delete dns records</TL>
</span>
</div>
</div>
</div>
</div>
</div>
</LazyLoader>
@code
{
private int DatabaseCount = 0;
private int ServerCount = 0;
private Task Load(LazyLoader lazyLoader)
{
DatabaseCount = DatabaseRepository.Get().Count();
ServerCount = ServerRepository.Get().Count();
return Task.CompletedTask;
}
}

View file

@ -5,8 +5,10 @@
@using Moonlight.App.Exceptions
@using Moonlight.App.Services.Interop
@using Logging.Net
@using Moonlight.App.Repositories
@inject UserService UserService
@inject UserRepository UserRepository
@inject SmartTranslateService SmartTranslateService
@inject AlertService AlertService
@inject ToastService ToastService
@ -107,6 +109,10 @@
NewUser.LastName
);
var user = UserRepository.Get().First(x => x.Email == NewUser.Email);
user.Admin = true;
UserRepository.Update(user);
await ToastService.Success(
SmartTranslateService.Translate("User successfully created")
);

View file

@ -31,6 +31,14 @@ build_metadata.AdditionalFiles.CssScope =
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQWxlcnRzXFNldHVwQ29tcGxldGVkQWxlcnQucmF6b3I=
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Components/Auth/Login.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXV0aFxMb2dpbi5yYXpvcg==
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Components/Auth/Register.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcQXV0aFxSZWdpc3Rlci5yYXpvcg==
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Components/ErrorBoundaries/ComponentErrorBoundary.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcRXJyb3JCb3VuZGFyaWVzXENvbXBvbmVudEVycm9yQm91bmRhcnkucmF6b3I=
build_metadata.AdditionalFiles.CssScope =
@ -51,6 +59,10 @@ build_metadata.AdditionalFiles.CssScope =
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcUGFydGlhbHNcRm9vdGVyLnJhem9y
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Components/Partials/LazyLoader.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcUGFydGlhbHNcTGF6eUxvYWRlci5yYXpvcg==
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Components/Partials/Navbar.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcUGFydGlhbHNcTmF2YmFyLnJhem9y
build_metadata.AdditionalFiles.CssScope =
@ -83,14 +95,34 @@ build_metadata.AdditionalFiles.CssScope =
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcU3RhdGVMb2dpY1xOb25TZXR1cC5yYXpvcg==
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Components/StateLogic/OnlyAdmin.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXENvbXBvbmVudHNcU3RhdGVMb2dpY1xPbmx5QWRtaW4ucmF6b3I=
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Layouts/MainLayout.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXExheW91dHNcTWFpbkxheW91dC5yYXpvcg==
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Layouts/NotFoundLayout.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXExheW91dHNcTm90Rm91bmRMYXlvdXQucmF6b3I=
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Layouts/ThemeInit.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXExheW91dHNcVGhlbWVJbml0LnJhem9y
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Views/Admin/Nodes/Edit.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXE5vZGVzXEVkaXQucmF6b3I=
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Views/Admin/Nodes/Index.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXE5vZGVzXEluZGV4LnJhem9y
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Views/Admin/Nodes/New.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEFkbWluXE5vZGVzXE5ldy5yYXpvcg==
build_metadata.AdditionalFiles.CssScope =
[C:/Users/marce/source/repos/MoonlightPublic/Moonlight/Moonlight/Shared/Views/Index.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFZpZXdzXEluZGV4LnJhem9y
build_metadata.AdditionalFiles.CssScope =

View file

@ -76,7 +76,7 @@
},
"GravatarSharp.Core": {
"target": "Package",
"version": "[0.9.0.2, )"
"version": "[1.0.1.2, )"
},
"JWT": {
"target": "Package",
@ -96,6 +96,12 @@
"target": "Package",
"version": "[1.15.1, )"
},
"MimeTypes": {
"include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive",
"suppressParent": "All",
"target": "Package",
"version": "[2.4.0, )"
},
"MineStat": {
"target": "Package",
"version": "[3.1.1, )"

View file

@ -225,16 +225,16 @@
"lib/net6.0/Discord.Net.WebSocket.dll": {}
}
},
"GravatarSharp.Core/0.9.0.2": {
"GravatarSharp.Core/1.0.1.2": {
"type": "package",
"dependencies": {
"Newtonsoft.Json": "13.0.1"
"Newtonsoft.Json": "13.0.2"
},
"compile": {
"lib/net46/GravatarSharp.Core.dll": {}
"lib/netstandard2.1/GravatarSharp.dll": {}
},
"runtime": {
"lib/net46/GravatarSharp.Core.dll": {}
"lib/netstandard2.1/GravatarSharp.dll": {}
}
},
"Humanizer.Core/2.14.1": {
@ -617,6 +617,17 @@
"build/Microsoft.VisualStudio.Azure.Containers.Tools.Targets.targets": {}
}
},
"MimeTypes/2.4.0": {
"type": "package",
"contentFiles": {
"contentFiles/cs/netcoreapp3.0/MimeTypes.cs.pp": {
"buildAction": "Compile",
"codeLanguage": "cs",
"copyToOutput": false,
"ppOutputPath": "MimeTypes.cs"
}
}
},
"MineStat/3.1.1": {
"type": "package",
"compile": {
@ -1440,18 +1451,17 @@
"lib/netstandard2.1/Discord.Net.WebSocket.xml"
]
},
"GravatarSharp.Core/0.9.0.2": {
"sha512": "+UfeBl5kBzAhl3ZakHC+5t7cBhhiV91zQCKna+Uwu99JC9OtAA4BgHAoz3Dk1GRkLjxh5gk0I/mwShbRC3IRDw==",
"GravatarSharp.Core/1.0.1.2": {
"sha512": "zSucyFwx5RHjMo69UeDXK1tCKJj9ziBc6vA8XtGhSar3cqciVVoBBuK882p31UyXZlva6xjpb2Pw5onKJzZP5g==",
"type": "package",
"path": "gravatarsharp.core/0.9.0.2",
"path": "gravatarsharp.core/1.0.1.2",
"files": [
".nupkg.metadata",
".signature.p7s",
"gravatarsharp.core.0.9.0.2.nupkg.sha512",
"Gravatar-01.png",
"gravatarsharp.core.1.0.1.2.nupkg.sha512",
"gravatarsharp.core.nuspec",
"icon.png",
"lib/net46/GravatarSharp.Core.XML",
"lib/net46/GravatarSharp.Core.dll"
"lib/netstandard2.1/GravatarSharp.dll"
]
},
"Humanizer.Core/2.14.1": {
@ -2195,6 +2205,22 @@
"tools/zh-Hant/Microsoft.VisualStudio.Containers.Tools.Tasks.resources.dll"
]
},
"MimeTypes/2.4.0": {
"sha512": "jbdJlfoz5YtmuvyM12G5KY22kkXZUG0HgU8ahnZPM0JtXPRvL5m3jURqXL47or/FCbc1qb4GDhg6ip3yOgeFaw==",
"type": "package",
"path": "mimetypes/2.4.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"contentFiles/cs/net472/MimeTypes.NullableAttributes.cs.pp",
"contentFiles/cs/netcoreapp3.0/MimeTypes.cs.pp",
"contentFiles/cs/netstandard2.0/MimeTypes.NullableAttributes.cs.pp",
"contentFiles/cs/netstandard2.1/MimeTypes.cs.pp",
"images/nuget-icon.png",
"mimetypes.2.4.0.nupkg.sha512",
"mimetypes.nuspec"
]
},
"MineStat/3.1.1": {
"sha512": "yF+grj87r7+LSu6hnL1g5V1wtpvZIw46taeEjIRD6KuXXXmqRT/WjBMRJMfoKuSinPQBeQiCT0sCIGvuiZ3kfw==",
"type": "package",
@ -2771,11 +2797,12 @@
"BlazorTable >= 1.17.0",
"CurrieTechnologies.Razor.SweetAlert2 >= 5.4.0",
"Discord.Net >= 3.9.0",
"GravatarSharp.Core >= 0.9.0.2",
"GravatarSharp.Core >= 1.0.1.2",
"JWT >= 10.0.2",
"Logging.Net >= 1.1.0",
"Microsoft.EntityFrameworkCore.Design >= 7.0.3",
"Microsoft.VisualStudio.Azure.Containers.Tools.Targets >= 1.15.1",
"MimeTypes >= 2.4.0",
"MineStat >= 3.1.1",
"Newtonsoft.Json >= 13.0.3-beta1",
"Otp.NET >= 1.3.0",
@ -2865,7 +2892,7 @@
},
"GravatarSharp.Core": {
"target": "Package",
"version": "[0.9.0.2, )"
"version": "[1.0.1.2, )"
},
"JWT": {
"target": "Package",
@ -2885,6 +2912,12 @@
"target": "Package",
"version": "[1.15.1, )"
},
"MimeTypes": {
"include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive",
"suppressParent": "All",
"target": "Package",
"version": "[2.4.0, )"
},
"MineStat": {
"target": "Package",
"version": "[3.1.1, )"
@ -2947,17 +2980,5 @@
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\6.0.300\\RuntimeIdentifierGraph.json"
}
}
},
"logs": [
{
"code": "NU1701",
"level": "Warning",
"warningLevel": 1,
"message": "Package 'GravatarSharp.Core 0.9.0.2' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' instead of the project target framework 'net6.0'. This package may not be fully compatible with your project.",
"libraryId": "GravatarSharp.Core",
"targetGraphs": [
"net6.0"
]
}
]
}
}

View file

@ -1,6 +1,6 @@
{
"version": 2,
"dgSpecHash": "kweG9cyheq0lvUg6tPkk+sPoY2pPlReL0QP5jHLJNWl9pUpDd+CJp7bLfFE9WjjPi9DegeiFh5tJQ1eO1r96RA==",
"dgSpecHash": "pQgIHNaG7q9d70t4chS097wnXaBcGVs4M1KNaxW4kyPiCyrsd3TNRJ260ThoX5FTLByZYWNfqf9FNIzWLSOXTQ==",
"success": true,
"projectFilePath": "C:\\Users\\marce\\source\\repos\\MoonlightPublic\\Moonlight\\Moonlight\\Moonlight.csproj",
"expectedPackageFiles": [
@ -18,7 +18,7 @@
"C:\\Users\\marce\\.nuget\\packages\\discord.net.rest\\3.9.0\\discord.net.rest.3.9.0.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\discord.net.webhook\\3.9.0\\discord.net.webhook.3.9.0.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\discord.net.websocket\\3.9.0\\discord.net.websocket.3.9.0.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\gravatarsharp.core\\0.9.0.2\\gravatarsharp.core.0.9.0.2.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\gravatarsharp.core\\1.0.1.2\\gravatarsharp.core.1.0.1.2.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\humanizer.core\\2.14.1\\humanizer.core.2.14.1.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\jwt\\10.0.2\\jwt.10.0.2.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\linqkit.core\\1.1.26\\linqkit.core.1.1.26.nupkg.sha512",
@ -49,6 +49,7 @@
"C:\\Users\\marce\\.nuget\\packages\\microsoft.extensions.primitives\\7.0.0\\microsoft.extensions.primitives.7.0.0.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\microsoft.jsinterop\\6.0.9\\microsoft.jsinterop.6.0.9.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\microsoft.visualstudio.azure.containers.tools.targets\\1.15.1\\microsoft.visualstudio.azure.containers.tools.targets.1.15.1.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\mimetypes\\2.4.0\\mimetypes.2.4.0.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\minestat\\3.1.1\\minestat.3.1.1.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\mono.texttemplating\\2.2.1\\mono.texttemplating.2.2.1.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\mysqlconnector\\2.2.5\\mysqlconnector.2.2.5.nupkg.sha512",
@ -72,16 +73,5 @@
"C:\\Users\\marce\\.nuget\\packages\\uaparser\\3.1.47\\uaparser.3.1.47.nupkg.sha512",
"C:\\Users\\marce\\.nuget\\packages\\xtermblazor\\1.6.1\\xtermblazor.1.6.1.nupkg.sha512"
],
"logs": [
{
"code": "NU1701",
"level": "Warning",
"warningLevel": 1,
"message": "Package 'GravatarSharp.Core 0.9.0.2' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' instead of the project target framework 'net6.0'. This package may not be fully compatible with your project.",
"libraryId": "GravatarSharp.Core",
"targetGraphs": [
"net6.0"
]
}
]
"logs": []
}

View file

@ -1 +1 @@
"restore":{"projectUniqueName":"C:\\Users\\marce\\source\\repos\\MoonlightPublic\\Moonlight\\Moonlight\\Moonlight.csproj","projectName":"Moonlight","projectPath":"C:\\Users\\marce\\source\\repos\\MoonlightPublic\\Moonlight\\Moonlight\\Moonlight.csproj","outputPath":"C:\\Users\\marce\\source\\repos\\MoonlightPublic\\Moonlight\\Moonlight\\obj\\","projectStyle":"PackageReference","fallbackFolders":["C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages","C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"],"originalTargetFrameworks":["net6.0"],"sources":{"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\":{},"C:\\Users\\marce\\source\\repos\\Logging.Net\\LoggingNet\\LoggingNet\\bin\\Release\\net5.0\\newpublish":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net6.0":{"targetAlias":"net6.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]}}"frameworks":{"net6.0":{"targetAlias":"net6.0","dependencies":{"BCrypt.Net-Next":{"target":"Package","version":"[4.0.3, )"},"Ben.Demystifier":{"target":"Package","version":"[0.4.1, )"},"Blazor.ContextMenu":{"target":"Package","version":"[1.15.0, )"},"BlazorMonaco":{"target":"Package","version":"[3.0.0, )"},"BlazorTable":{"target":"Package","version":"[1.17.0, )"},"CurrieTechnologies.Razor.SweetAlert2":{"target":"Package","version":"[5.4.0, )"},"Discord.Net":{"target":"Package","version":"[3.9.0, )"},"GravatarSharp.Core":{"target":"Package","version":"[0.9.0.2, )"},"JWT":{"target":"Package","version":"[10.0.2, )"},"Logging.Net":{"target":"Package","version":"[1.1.0, )"},"Microsoft.EntityFrameworkCore.Design":{"include":"Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive","suppressParent":"All","target":"Package","version":"[7.0.3, )"},"Microsoft.VisualStudio.Azure.Containers.Tools.Targets":{"target":"Package","version":"[1.15.1, )"},"MineStat":{"target":"Package","version":"[3.1.1, )"},"Newtonsoft.Json":{"target":"Package","version":"[13.0.3-beta1, )"},"Otp.NET":{"target":"Package","version":"[1.3.0, )"},"Pomelo.EntityFrameworkCore.MySql":{"target":"Package","version":"[7.0.0, )"},"PteroConsole.NET":{"target":"Package","version":"[1.0.4, )"},"QRCoder":{"target":"Package","version":"[1.4.3, )"},"RestSharp":{"target":"Package","version":"[109.0.0-preview.1, )"},"UAParser":{"target":"Package","version":"[3.1.47, )"},"XtermBlazor":{"target":"Package","version":"[1.6.1, )"},"aaPanelSharp":{"target":"Package","version":"[1.0.0, )"}},"imports":["net461","net462","net47","net471","net472","net48"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.AspNetCore.App":{"privateAssets":"none"},"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Program Files\\dotnet\\sdk\\6.0.300\\RuntimeIdentifierGraph.json"}}
"restore":{"projectUniqueName":"C:\\Users\\marce\\source\\repos\\MoonlightPublic\\Moonlight\\Moonlight\\Moonlight.csproj","projectName":"Moonlight","projectPath":"C:\\Users\\marce\\source\\repos\\MoonlightPublic\\Moonlight\\Moonlight\\Moonlight.csproj","outputPath":"C:\\Users\\marce\\source\\repos\\MoonlightPublic\\Moonlight\\Moonlight\\obj\\","projectStyle":"PackageReference","fallbackFolders":["C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages","C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"],"originalTargetFrameworks":["net6.0"],"sources":{"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\":{},"C:\\Users\\marce\\source\\repos\\Logging.Net\\LoggingNet\\LoggingNet\\bin\\Release\\net5.0\\newpublish":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net6.0":{"targetAlias":"net6.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]}}"frameworks":{"net6.0":{"targetAlias":"net6.0","dependencies":{"BCrypt.Net-Next":{"target":"Package","version":"[4.0.3, )"},"Ben.Demystifier":{"target":"Package","version":"[0.4.1, )"},"Blazor.ContextMenu":{"target":"Package","version":"[1.15.0, )"},"BlazorMonaco":{"target":"Package","version":"[3.0.0, )"},"BlazorTable":{"target":"Package","version":"[1.17.0, )"},"CurrieTechnologies.Razor.SweetAlert2":{"target":"Package","version":"[5.4.0, )"},"Discord.Net":{"target":"Package","version":"[3.9.0, )"},"GravatarSharp.Core":{"target":"Package","version":"[1.0.1.2, )"},"JWT":{"target":"Package","version":"[10.0.2, )"},"Logging.Net":{"target":"Package","version":"[1.1.0, )"},"Microsoft.EntityFrameworkCore.Design":{"include":"Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive","suppressParent":"All","target":"Package","version":"[7.0.3, )"},"Microsoft.VisualStudio.Azure.Containers.Tools.Targets":{"target":"Package","version":"[1.15.1, )"},"MimeTypes":{"include":"Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive","suppressParent":"All","target":"Package","version":"[2.4.0, )"},"MineStat":{"target":"Package","version":"[3.1.1, )"},"Newtonsoft.Json":{"target":"Package","version":"[13.0.3-beta1, )"},"Otp.NET":{"target":"Package","version":"[1.3.0, )"},"Pomelo.EntityFrameworkCore.MySql":{"target":"Package","version":"[7.0.0, )"},"PteroConsole.NET":{"target":"Package","version":"[1.0.4, )"},"QRCoder":{"target":"Package","version":"[1.4.3, )"},"RestSharp":{"target":"Package","version":"[109.0.0-preview.1, )"},"UAParser":{"target":"Package","version":"[3.1.47, )"},"XtermBlazor":{"target":"Package","version":"[1.6.1, )"},"aaPanelSharp":{"target":"Package","version":"[1.0.0, )"}},"imports":["net461","net462","net47","net471","net472","net48"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.AspNetCore.App":{"privateAssets":"none"},"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Program Files\\dotnet\\sdk\\6.0.300\\RuntimeIdentifierGraph.json"}}

View file

@ -32,3 +32,94 @@ This page is crashed. The error has been reported to the moonlight team. Meanwhi
Setup complete;Setup complete
It looks like this moonlight instance is ready to go;It looks like this moonlight instance is ready to go
User successfully created;User successfully created
Ooops. Your moonlight client is crashed;Ooops. Your moonlight client is crashed
This error has been reported to the moonlight team;This error has been reported to the moonlight team
Sign In;Sign In
Sign in to start with moonlight;Sign in to start with moonlight
Sign in with Discord;Sign in with Discord
Or with email;Or with email
Forgot password?;Forgot password?
Sign-in;Sign-in
Not registered yet?;Not registered yet?
Sign up;Sign up
Authenticating;Authenticating
Sign in with Google;Sign in with Google
Working;Working
Error;Error
Email and password combination not found;Email and password combination not found
Email;Email
Password;Password
Account settings;Account settings
Logout;Logout
Dashboard;Dashboard
Order;Order
Website;Website
Database;Database
Domain;Domain
Servers;Servers
Websites;Websites
Databases;Databases
Domains;Domains
Changelog;Changelog
Firstname;Firstname
Lastname;Lastname
Repeat password;Repeat password
Sign Up;Sign Up
Sign up to start with moonlight;Sign up to start with moonlight
Sign up with Discord;Sign up with Discord
Sign up with Google;Sign up with Google
Sign-up;Sign-up
Already registered?;Already registered?
Sign in;Sign in
Create something new;Create something new
Create a gameserver;Create a gameserver
A new gameserver in just a few minutes;A new gameserver in just a few minutes
Create a database;Create a database
A quick way to store your data and manage it from all around the world;A quick way to store your data and manage it from all around the world
Manage your services;Manage your services
Manage your gameservers;Manage your gameservers
Adjust your gameservers;Adjust your gameservers
Manage your databases;Manage your databases
Insert, delete and update the data in your databases;Insert, delete and update the data in your databases
Create a website;Create a website
Make your own websites with a webspace;Make your own websites with a webspace
Create a domain;Create a domain
Make your servvices accessible throught your own domain;Make your servvices accessible throught your own domain
Manage your websites;Manage your websites
Modify the content of your websites;Modify the content of your websites
Manage your domains;Manage your domains
Add, edit and delete dns records;Add, edit and delete dns records
Admin;Admin
System;System
Overview;Overview
Manager;Manager
Cleanup;Cleanup
Nodes;Nodes
Images;Images
aaPanel;aaPanel
Users;Users
Support;Support
Statistics;Statistics
No nodes found. Start with adding a new node;No nodes found. Start with adding a new node
Nodename;Nodename
FQDN;FQDN
Create;Create
Creating;Creating
Http port;Http port
Sftp port;Sftp port
Moonlight daemon port;Moonlight daemon port
SSL;SSL
CPU Usage;CPU Usage
In %;In %
Memory;Memory
Used / Available memory;Used / Available memory
Storage;Storage
Available storage;Available storage
Add a new node;Add a new node
Delete;Delete
Deleting;Deleting
Edit;Edit
Toekn Id;Toekn Id
Token;Token
Save;Save
Token Id;Token Id