diff --git a/Moonlight/App/ApiClients/CloudPanel/CloudPanelApiHelper.cs b/Moonlight/App/ApiClients/CloudPanel/CloudPanelApiHelper.cs new file mode 100644 index 00000000..fd6e99fb --- /dev/null +++ b/Moonlight/App/ApiClients/CloudPanel/CloudPanelApiHelper.cs @@ -0,0 +1,83 @@ +using Moonlight.App.Database.Entities; +using Moonlight.App.Models.Plesk.Resources; +using Newtonsoft.Json; +using RestSharp; + +namespace Moonlight.App.ApiClients.CloudPanel; + +public class CloudPanelApiHelper +{ + private readonly RestClient Client; + + public CloudPanelApiHelper() + { + Client = new(); + } + + public async Task Post(Database.Entities.CloudPanel cloudPanel, string resource, object? body) + { + var request = CreateRequest(cloudPanel, resource); + + request.Method = Method.Post; + + if(body != null) + request.AddParameter("text/plain", JsonConvert.SerializeObject(body), ParameterType.RequestBody); + + var response = await Client.ExecuteAsync(request); + + if (!response.IsSuccessful) + { + if (response.StatusCode != 0) + { + throw new CloudPanelException( + $"An error occured: ({response.StatusCode}) {response.Content}", + (int)response.StatusCode + ); + } + else + { + throw new Exception($"An internal error occured: {response.ErrorMessage}"); + } + } + } + + public async Task Delete(Database.Entities.CloudPanel cloudPanel, string resource, object? body) + { + var request = CreateRequest(cloudPanel, resource); + + request.Method = Method.Delete; + + if(body != null) + request.AddParameter("text/plain", JsonConvert.SerializeObject(body), ParameterType.RequestBody); + + var response = await Client.ExecuteAsync(request); + + if (!response.IsSuccessful) + { + if (response.StatusCode != 0) + { + throw new CloudPanelException( + $"An error occured: ({response.StatusCode}) {response.Content}", + (int)response.StatusCode + ); + } + else + { + throw new Exception($"An internal error occured: {response.ErrorMessage}"); + } + } + } + + private RestRequest CreateRequest(Database.Entities.CloudPanel cloudPanel, string resource) + { + var url = $"{cloudPanel.ApiUrl}/" + resource; + + var request = new RestRequest(url); + + request.AddHeader("Content-Type", "application/json"); + request.AddHeader("Accept", "application/json"); + request.AddHeader("Authorization", "Bearer " + cloudPanel.ApiKey); + + return request; + } +} \ No newline at end of file diff --git a/Moonlight/App/ApiClients/CloudPanel/CloudPanelException.cs b/Moonlight/App/ApiClients/CloudPanel/CloudPanelException.cs new file mode 100644 index 00000000..a7610348 --- /dev/null +++ b/Moonlight/App/ApiClients/CloudPanel/CloudPanelException.cs @@ -0,0 +1,32 @@ +using System.Runtime.Serialization; + +namespace Moonlight.App.ApiClients.CloudPanel; + +[Serializable] +public class CloudPanelException : Exception +{ + public int StatusCode { get; set; } + + public CloudPanelException() + { + } + + public CloudPanelException(string message, int statusCode) : base(message) + { + StatusCode = statusCode; + } + + public CloudPanelException(string message) : base(message) + { + } + + public CloudPanelException(string message, Exception inner) : base(message, inner) + { + } + + protected CloudPanelException( + SerializationInfo info, + StreamingContext context) : base(info, context) + { + } +} \ No newline at end of file diff --git a/Moonlight/App/ApiClients/CloudPanel/Requests/AddPhpSite.cs b/Moonlight/App/ApiClients/CloudPanel/Requests/AddPhpSite.cs new file mode 100644 index 00000000..9e04eeff --- /dev/null +++ b/Moonlight/App/ApiClients/CloudPanel/Requests/AddPhpSite.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Moonlight.App.ApiClients.CloudPanel.Requests; + +public class AddPhpSite +{ + [JsonProperty("domainName")] public string DomainName { get; set; } = ""; + + [JsonProperty("siteUser")] public string SiteUser { get; set; } = ""; + + [JsonProperty("siteUserPassword")] public string SiteUserPassword { get; set; } = ""; + + [JsonProperty("vHostTemplate")] public string VHostTemplate { get; set; } = ""; + + [JsonProperty("phpVersion")] public string PhpVersion { get; set; } = ""; +} \ No newline at end of file diff --git a/Moonlight/App/Database/DataContext.cs b/Moonlight/App/Database/DataContext.cs index 7ebac0c5..aeaa61b1 100644 --- a/Moonlight/App/Database/DataContext.cs +++ b/Moonlight/App/Database/DataContext.cs @@ -43,6 +43,10 @@ public class DataContext : DbContext public DbSet Websites { get; set; } public DbSet Statistics { get; set; } public DbSet NewsEntries { get; set; } + + public DbSet CloudPanels { get; set; } + public DbSet Databases { get; set; } + public DbSet WebSpaces { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { diff --git a/Moonlight/App/Database/Entities/CloudPanel.cs b/Moonlight/App/Database/Entities/CloudPanel.cs new file mode 100644 index 00000000..de872b0f --- /dev/null +++ b/Moonlight/App/Database/Entities/CloudPanel.cs @@ -0,0 +1,10 @@ +namespace Moonlight.App.Database.Entities; + +public class CloudPanel +{ + public int Id { get; set; } + public string Name { get; set; } = ""; + public string ApiUrl { get; set; } = ""; + public string ApiKey { get; set; } = ""; + public string Host { get; set; } = ""; +} \ No newline at end of file diff --git a/Moonlight/App/Database/Entities/MySqlDatabase.cs b/Moonlight/App/Database/Entities/MySqlDatabase.cs new file mode 100644 index 00000000..c9cdc6ef --- /dev/null +++ b/Moonlight/App/Database/Entities/MySqlDatabase.cs @@ -0,0 +1,9 @@ +namespace Moonlight.App.Database.Entities; + +public class MySqlDatabase +{ + public int Id { get; set; } + public WebSpace WebSpace { get; set; } + public string UserName { get; set; } = ""; + public string Password { get; set; } = ""; +} \ No newline at end of file diff --git a/Moonlight/App/Database/Entities/WebSpace.cs b/Moonlight/App/Database/Entities/WebSpace.cs new file mode 100644 index 00000000..1112fdf6 --- /dev/null +++ b/Moonlight/App/Database/Entities/WebSpace.cs @@ -0,0 +1,13 @@ +namespace Moonlight.App.Database.Entities; + +public class WebSpace +{ + public int Id { get; set; } + public string Domain { get; set; } = ""; + public string UserName { get; set; } = ""; + public string Password { get; set; } = ""; + public string VHostTemplate { get; set; } = ""; + public User Owner { get; set; } + public List Databases { get; set; } = new(); + public CloudPanel CloudPanel { get; set; } +} \ No newline at end of file diff --git a/Moonlight/App/Database/Migrations/20230419120719_AddedCloudPanelModels.Designer.cs b/Moonlight/App/Database/Migrations/20230419120719_AddedCloudPanelModels.Designer.cs new file mode 100644 index 00000000..26edf52f --- /dev/null +++ b/Moonlight/App/Database/Migrations/20230419120719_AddedCloudPanelModels.Designer.cs @@ -0,0 +1,1099 @@ +// +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("20230419120719_AddedCloudPanelModels")] + partial class AddedCloudPanelModels + { + /// + 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.CloudPanel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiKey") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ApiUrl") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("CloudPanels"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.DdosAttack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("bigint"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NodeId") + .HasColumnType("int"); + + b.Property("Ongoing") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.HasIndex("NodeId"); + + b.ToTable("DdosAttacks"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Default") + .HasColumnType("tinyint(1)"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("DockerImages"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Allocations") + .HasColumnType("int"); + + b.Property("ConfigFiles") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InstallDockerImage") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InstallEntrypoint") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InstallScript") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Startup") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("StartupDetection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("StopCommand") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TagsJson") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Uuid") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("Images"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("ImageVariables"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LoadingMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("LoadingMessages"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.AuditLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AuditLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.ErrorLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Class") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Stacktrace") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("ErrorLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.SecurityLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("SecurityLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.MySqlDatabase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Password") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("WebSpaceId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("WebSpaceId"); + + b.ToTable("Databases"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.NewsEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("Markdown") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Title") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("NewsEntries"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Fqdn") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("HttpPort") + .HasColumnType("int"); + + b.Property("MoonlightDaemonPort") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SftpPort") + .HasColumnType("int"); + + b.Property("Ssl") + .HasColumnType("tinyint(1)"); + + b.Property("Token") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TokenId") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Nodes"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("NodeId") + .HasColumnType("int"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Action") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NotificationClientId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("NotificationClientId"); + + b.ToTable("NotificationActions"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Notification.NotificationClient", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("NotificationClients"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.PleskServer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiKey") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ApiUrl") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("PleskServers"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Revoke", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Identifier") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Revokes"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Cpu") + .HasColumnType("int"); + + b.Property("Disk") + .HasColumnType("bigint"); + + b.Property("DockerImageIndex") + .HasColumnType("int"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Installing") + .HasColumnType("tinyint(1)"); + + b.Property("IsCleanupException") + .HasColumnType("tinyint(1)"); + + b.Property("MainAllocationId") + .HasColumnType("int"); + + b.Property("Memory") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NodeId") + .HasColumnType("int"); + + b.Property("OverrideStartup") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("Suspended") + .HasColumnType("tinyint(1)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Bytes") + .HasColumnType("bigint"); + + b.Property("Created") + .HasColumnType("tinyint(1)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ServerId") + .HasColumnType("int"); + + b.Property("Uuid") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ServerId"); + + b.ToTable("ServerBackups"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ServerId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ServerId"); + + b.ToTable("ServerVariables"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SharedDomain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CloudflareId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("SharedDomains"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.StatisticsData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Chart") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("Value") + .HasColumnType("double"); + + b.HasKey("Id"); + + b.ToTable("Statistics"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Subscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LimitsJson") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Subscriptions"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Answer") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("IsQuestion") + .HasColumnType("tinyint(1)"); + + b.Property("IsSupport") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("RecipientId") + .HasColumnType("int"); + + b.Property("SenderId") + .HasColumnType("int"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Address") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Admin") + .HasColumnType("tinyint(1)"); + + b.Property("City") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Country") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CurrentSubscriptionId") + .HasColumnType("int"); + + b.Property("DiscordId") + .HasColumnType("bigint unsigned"); + + b.Property("Email") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Password") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("State") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("SubscriptionDuration") + .HasColumnType("int"); + + b.Property("SubscriptionSince") + .HasColumnType("datetime(6)"); + + b.Property("SupportPending") + .HasColumnType("tinyint(1)"); + + b.Property("TokenValidTime") + .HasColumnType("datetime(6)"); + + b.Property("TotpEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("TotpSecret") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("CurrentSubscriptionId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CloudPanelId") + .HasColumnType("int"); + + b.Property("Domain") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("Password") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("VHostTemplate") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("CloudPanelId"); + + b.HasIndex("OwnerId"); + + b.ToTable("WebSpaces"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Website", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("BaseDomain") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FtpLogin") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FtpPassword") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("PleskId") + .HasColumnType("int"); + + b.Property("PleskServerId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.HasIndex("PleskServerId"); + + b.ToTable("Websites"); + }); + + 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.MySqlDatabase", b => + { + b.HasOne("Moonlight.App.Database.Entities.WebSpace", "WebSpace") + .WithMany("Databases") + .HasForeignKey("WebSpaceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("WebSpace"); + }); + + 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"); + + 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.User", b => + { + b.HasOne("Moonlight.App.Database.Entities.Subscription", "CurrentSubscription") + .WithMany() + .HasForeignKey("CurrentSubscriptionId"); + + b.Navigation("CurrentSubscription"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b => + { + b.HasOne("Moonlight.App.Database.Entities.CloudPanel", "CloudPanel") + .WithMany() + .HasForeignKey("CloudPanelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CloudPanel"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Website", b => + { + b.HasOne("Moonlight.App.Database.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.PleskServer", "PleskServer") + .WithMany() + .HasForeignKey("PleskServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + + b.Navigation("PleskServer"); + }); + + 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"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b => + { + b.Navigation("Databases"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Moonlight/App/Database/Migrations/20230419120719_AddedCloudPanelModels.cs b/Moonlight/App/Database/Migrations/20230419120719_AddedCloudPanelModels.cs new file mode 100644 index 00000000..845437af --- /dev/null +++ b/Moonlight/App/Database/Migrations/20230419120719_AddedCloudPanelModels.cs @@ -0,0 +1,121 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Moonlight.App.Database.Migrations +{ + /// + public partial class AddedCloudPanelModels : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "CloudPanels", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Name = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + ApiUrl = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + ApiKey = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_CloudPanels", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "WebSpaces", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Domain = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + UserName = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Password = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + VHostTemplate = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + OwnerId = table.Column(type: "int", nullable: false), + CloudPanelId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_WebSpaces", x => x.Id); + table.ForeignKey( + name: "FK_WebSpaces_CloudPanels_CloudPanelId", + column: x => x.CloudPanelId, + principalTable: "CloudPanels", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_WebSpaces_Users_OwnerId", + column: x => x.OwnerId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "Databases", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + WebSpaceId = table.Column(type: "int", nullable: false), + UserName = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Password = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_Databases", x => x.Id); + table.ForeignKey( + name: "FK_Databases_WebSpaces_WebSpaceId", + column: x => x.WebSpaceId, + principalTable: "WebSpaces", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_Databases_WebSpaceId", + table: "Databases", + column: "WebSpaceId"); + + migrationBuilder.CreateIndex( + name: "IX_WebSpaces_CloudPanelId", + table: "WebSpaces", + column: "CloudPanelId"); + + migrationBuilder.CreateIndex( + name: "IX_WebSpaces_OwnerId", + table: "WebSpaces", + column: "OwnerId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Databases"); + + migrationBuilder.DropTable( + name: "WebSpaces"); + + migrationBuilder.DropTable( + name: "CloudPanels"); + } + } +} diff --git a/Moonlight/App/Database/Migrations/20230419125155_AddedHostFieldToCloudPanelModel.Designer.cs b/Moonlight/App/Database/Migrations/20230419125155_AddedHostFieldToCloudPanelModel.Designer.cs new file mode 100644 index 00000000..dda0a9f9 --- /dev/null +++ b/Moonlight/App/Database/Migrations/20230419125155_AddedHostFieldToCloudPanelModel.Designer.cs @@ -0,0 +1,1103 @@ +// +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("20230419125155_AddedHostFieldToCloudPanelModel")] + partial class AddedHostFieldToCloudPanelModel + { + /// + 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.CloudPanel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiKey") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ApiUrl") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Host") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("CloudPanels"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.DdosAttack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("bigint"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NodeId") + .HasColumnType("int"); + + b.Property("Ongoing") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.HasIndex("NodeId"); + + b.ToTable("DdosAttacks"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.DockerImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Default") + .HasColumnType("tinyint(1)"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("DockerImages"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Domain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Allocations") + .HasColumnType("int"); + + b.Property("ConfigFiles") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InstallDockerImage") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InstallEntrypoint") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InstallScript") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Startup") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("StartupDetection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("StopCommand") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TagsJson") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Uuid") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("Images"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("DefaultValue") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("ImageVariables"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LoadingMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("LoadingMessages"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.AuditLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AuditLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.ErrorLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Class") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Stacktrace") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("ErrorLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.SecurityLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("JsonData") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("System") + .HasColumnType("tinyint(1)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("SecurityLog"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.MySqlDatabase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Password") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("WebSpaceId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("WebSpaceId"); + + b.ToTable("Databases"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.NewsEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("Markdown") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Title") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("NewsEntries"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Node", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Fqdn") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("HttpPort") + .HasColumnType("int"); + + b.Property("MoonlightDaemonPort") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SftpPort") + .HasColumnType("int"); + + b.Property("Ssl") + .HasColumnType("tinyint(1)"); + + b.Property("Token") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TokenId") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Nodes"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("NodeId") + .HasColumnType("int"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Action") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NotificationClientId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("NotificationClientId"); + + b.ToTable("NotificationActions"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Notification.NotificationClient", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("NotificationClients"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.PleskServer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiKey") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ApiUrl") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("PleskServers"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Revoke", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Identifier") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Revokes"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Cpu") + .HasColumnType("int"); + + b.Property("Disk") + .HasColumnType("bigint"); + + b.Property("DockerImageIndex") + .HasColumnType("int"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Installing") + .HasColumnType("tinyint(1)"); + + b.Property("IsCleanupException") + .HasColumnType("tinyint(1)"); + + b.Property("MainAllocationId") + .HasColumnType("int"); + + b.Property("Memory") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("NodeId") + .HasColumnType("int"); + + b.Property("OverrideStartup") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("Suspended") + .HasColumnType("tinyint(1)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Bytes") + .HasColumnType("bigint"); + + b.Property("Created") + .HasColumnType("tinyint(1)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ServerId") + .HasColumnType("int"); + + b.Property("Uuid") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ServerId"); + + b.ToTable("ServerBackups"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.ServerVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ServerId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ServerId"); + + b.ToTable("ServerVariables"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SharedDomain", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CloudflareId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("SharedDomains"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.StatisticsData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Chart") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("Value") + .HasColumnType("double"); + + b.HasKey("Id"); + + b.ToTable("Statistics"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Subscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LimitsJson") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Subscriptions"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.SupportMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Answer") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("IsQuestion") + .HasColumnType("tinyint(1)"); + + b.Property("IsSupport") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("RecipientId") + .HasColumnType("int"); + + b.Property("SenderId") + .HasColumnType("int"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Address") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Admin") + .HasColumnType("tinyint(1)"); + + b.Property("City") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Country") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CurrentSubscriptionId") + .HasColumnType("int"); + + b.Property("DiscordId") + .HasColumnType("bigint unsigned"); + + b.Property("Email") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Password") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("State") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("SubscriptionDuration") + .HasColumnType("int"); + + b.Property("SubscriptionSince") + .HasColumnType("datetime(6)"); + + b.Property("SupportPending") + .HasColumnType("tinyint(1)"); + + b.Property("TokenValidTime") + .HasColumnType("datetime(6)"); + + b.Property("TotpEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("TotpSecret") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("CurrentSubscriptionId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CloudPanelId") + .HasColumnType("int"); + + b.Property("Domain") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("Password") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("VHostTemplate") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("CloudPanelId"); + + b.HasIndex("OwnerId"); + + b.ToTable("WebSpaces"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Website", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("BaseDomain") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FtpLogin") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FtpPassword") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("PleskId") + .HasColumnType("int"); + + b.Property("PleskServerId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.HasIndex("PleskServerId"); + + b.ToTable("Websites"); + }); + + 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.MySqlDatabase", b => + { + b.HasOne("Moonlight.App.Database.Entities.WebSpace", "WebSpace") + .WithMany("Databases") + .HasForeignKey("WebSpaceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("WebSpace"); + }); + + 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"); + + 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.User", b => + { + b.HasOne("Moonlight.App.Database.Entities.Subscription", "CurrentSubscription") + .WithMany() + .HasForeignKey("CurrentSubscriptionId"); + + b.Navigation("CurrentSubscription"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b => + { + b.HasOne("Moonlight.App.Database.Entities.CloudPanel", "CloudPanel") + .WithMany() + .HasForeignKey("CloudPanelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CloudPanel"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.Website", b => + { + b.HasOne("Moonlight.App.Database.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.PleskServer", "PleskServer") + .WithMany() + .HasForeignKey("PleskServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + + b.Navigation("PleskServer"); + }); + + 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"); + }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b => + { + b.Navigation("Databases"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Moonlight/App/Database/Migrations/20230419125155_AddedHostFieldToCloudPanelModel.cs b/Moonlight/App/Database/Migrations/20230419125155_AddedHostFieldToCloudPanelModel.cs new file mode 100644 index 00000000..a0273c4d --- /dev/null +++ b/Moonlight/App/Database/Migrations/20230419125155_AddedHostFieldToCloudPanelModel.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Moonlight.App.Database.Migrations +{ + /// + public partial class AddedHostFieldToCloudPanelModel : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Host", + table: "CloudPanels", + type: "longtext", + nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Host", + table: "CloudPanels"); + } + } +} diff --git a/Moonlight/App/Database/Migrations/DataContextModelSnapshot.cs b/Moonlight/App/Database/Migrations/DataContextModelSnapshot.cs index 7a0da1a7..88d74810 100644 --- a/Moonlight/App/Database/Migrations/DataContextModelSnapshot.cs +++ b/Moonlight/App/Database/Migrations/DataContextModelSnapshot.cs @@ -19,6 +19,33 @@ namespace Moonlight.App.Database.Migrations .HasAnnotation("ProductVersion", "7.0.3") .HasAnnotation("Relational:MaxIdentifierLength", 64); + modelBuilder.Entity("Moonlight.App.Database.Entities.CloudPanel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiKey") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ApiUrl") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Host") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("CloudPanels"); + }); + modelBuilder.Entity("Moonlight.App.Database.Entities.DdosAttack", b => { b.Property("Id") @@ -281,6 +308,30 @@ namespace Moonlight.App.Database.Migrations b.ToTable("SecurityLog"); }); + modelBuilder.Entity("Moonlight.App.Database.Entities.MySqlDatabase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Password") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("WebSpaceId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("WebSpaceId"); + + b.ToTable("Databases"); + }); + modelBuilder.Entity("Moonlight.App.Database.Entities.NewsEntry", b => { b.Property("Id") @@ -748,6 +799,43 @@ namespace Moonlight.App.Database.Migrations b.ToTable("Users"); }); + modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CloudPanelId") + .HasColumnType("int"); + + b.Property("Domain") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("Password") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("VHostTemplate") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("CloudPanelId"); + + b.HasIndex("OwnerId"); + + b.ToTable("WebSpaces"); + }); + modelBuilder.Entity("Moonlight.App.Database.Entities.Website", b => { b.Property("Id") @@ -828,6 +916,17 @@ namespace Moonlight.App.Database.Migrations .HasForeignKey("ImageId"); }); + modelBuilder.Entity("Moonlight.App.Database.Entities.MySqlDatabase", b => + { + b.HasOne("Moonlight.App.Database.Entities.WebSpace", "WebSpace") + .WithMany("Databases") + .HasForeignKey("WebSpaceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("WebSpace"); + }); + modelBuilder.Entity("Moonlight.App.Database.Entities.NodeAllocation", b => { b.HasOne("Moonlight.App.Database.Entities.Node", null) @@ -932,6 +1031,25 @@ namespace Moonlight.App.Database.Migrations b.Navigation("CurrentSubscription"); }); + modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b => + { + b.HasOne("Moonlight.App.Database.Entities.CloudPanel", "CloudPanel") + .WithMany() + .HasForeignKey("CloudPanelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Moonlight.App.Database.Entities.User", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CloudPanel"); + + b.Navigation("Owner"); + }); + modelBuilder.Entity("Moonlight.App.Database.Entities.Website", b => { b.HasOne("Moonlight.App.Database.Entities.User", "Owner") @@ -971,6 +1089,11 @@ namespace Moonlight.App.Database.Migrations b.Navigation("Variables"); }); + + modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b => + { + b.Navigation("Databases"); + }); #pragma warning restore 612, 618 } } diff --git a/Moonlight/App/Helpers/Files/SftpFileAccess.cs b/Moonlight/App/Helpers/Files/SftpFileAccess.cs new file mode 100644 index 00000000..f79b4388 --- /dev/null +++ b/Moonlight/App/Helpers/Files/SftpFileAccess.cs @@ -0,0 +1,206 @@ +using Logging.Net; +using Renci.SshNet; +using ConnectionInfo = Renci.SshNet.ConnectionInfo; + +namespace Moonlight.App.Helpers.Files; + +public class SftpFileAccess : FileAccess +{ + private readonly string SftpHost; + private readonly string SftpUser; + private readonly string SftpPassword; + private readonly int SftpPort; + private readonly bool ForceUserDir; + + private readonly SftpClient Client; + + private string InternalPath + { + get + { + if (ForceUserDir) + return $"/home/{SftpUser}{CurrentPath}"; + + return InternalPath; + } + } + + public SftpFileAccess(string sftpHost, string sftpUser, string sftpPassword, int sftpPort, + bool forceUserDir = false) + { + SftpHost = sftpHost; + SftpUser = sftpUser; + SftpPassword = sftpPassword; + SftpPort = sftpPort; + ForceUserDir = forceUserDir; + + Client = new( + new ConnectionInfo( + SftpHost, + SftpPort, + SftpUser, + new PasswordAuthenticationMethod( + SftpUser, + SftpPassword + ) + ) + ); + } + + private void EnsureConnect() + { + if (!Client.IsConnected) + Client.Connect(); + } + + + public override Task Ls() + { + EnsureConnect(); + + var x = new List(); + + foreach (var file in Client.ListDirectory(InternalPath)) + { + if (file.Name != "." && file.Name != "..") + { + x.Add(new() + { + Name = file.Name, + Size = file.Attributes.Size, + IsFile = !file.IsDirectory + }); + } + } + + return Task.FromResult(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 Task Read(FileData fileData) + { + EnsureConnect(); + + var textStream = Client.Open(InternalPath.TrimEnd('/') + "/" + fileData.Name, FileMode.Open); + + if (textStream == null) + return Task.FromResult(""); + + var streamReader = new StreamReader(textStream); + + var text = streamReader.ReadToEnd(); + + streamReader.Close(); + textStream.Close(); + + return Task.FromResult(text); + } + + public override Task Write(FileData fileData, string content) + { + EnsureConnect(); + + var textStream = Client.Open(InternalPath.TrimEnd('/') + "/" + fileData.Name, FileMode.Create); + + var streamWriter = new StreamWriter(textStream); + streamWriter.Write(content); + + streamWriter.Flush(); + textStream.Flush(); + + streamWriter.Close(); + textStream.Close(); + + return Task.CompletedTask; + } + + public override async Task Upload(string name, Stream stream, Action? progressUpdated = null) + { + var dataStream = new SyncStreamAdapter(stream); + + await Task.Factory.FromAsync((x, _) => Client.BeginUploadFile(dataStream, InternalPath + name, x, null, u => + { + progressUpdated?.Invoke((int)((long)u / stream.Length)); + }), + Client.EndUploadFile, null); + } + + public override Task MkDir(string name) + { + Client.CreateDirectory(InternalPath + name); + + return Task.CompletedTask; + } + + public override Task Pwd() + { + return Task.FromResult(CurrentPath); + } + + public override Task DownloadUrl(FileData fileData) + { + throw new NotImplementedException(); + } + + public override Task DownloadStream(FileData fileData) + { + var stream = new MemoryStream(100 * 1024 * 1024); + Client.DownloadFile(InternalPath + fileData.Name, stream); + + return Task.FromResult(stream); + } + + public override Task Delete(FileData fileData) + { + Client.Delete(InternalPath + fileData.Name); + + return Task.CompletedTask; + } + + public override Task Move(FileData fileData, string newPath) + { + Client.RenameFile(InternalPath + fileData.Name, InternalPath + newPath); + + return Task.CompletedTask; + } + + public override Task Compress(params FileData[] files) + { + throw new NotImplementedException(); + } + + public override Task Decompress(FileData fileData) + { + throw new NotImplementedException(); + } + + public override Task GetLaunchUrl() + { + return Task.FromResult($"sftp://{SftpUser}@{SftpHost}:{SftpPort}"); + } + + public override object Clone() + { + return new SftpFileAccess(SftpHost, SftpUser, SftpPassword, SftpPort, ForceUserDir); + } +} \ No newline at end of file diff --git a/Moonlight/App/Helpers/SyncStreamAdapter.cs b/Moonlight/App/Helpers/SyncStreamAdapter.cs new file mode 100644 index 00000000..304b3f12 --- /dev/null +++ b/Moonlight/App/Helpers/SyncStreamAdapter.cs @@ -0,0 +1,58 @@ +namespace Moonlight.App.Helpers; + +public class SyncStreamAdapter : Stream +{ + private readonly Stream _stream; + + public SyncStreamAdapter(Stream stream) + { + _stream = stream ?? throw new ArgumentNullException(nameof(stream)); + } + + public override bool CanRead => _stream.CanRead; + public override bool CanSeek => _stream.CanSeek; + public override bool CanWrite => _stream.CanWrite; + public override long Length => _stream.Length; + + public override long Position + { + get => _stream.Position; + set => _stream.Position = value; + } + + public override void Flush() + { + _stream.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + var task = Task.Run(() => _stream.ReadAsync(buffer, offset, count)); + return task.GetAwaiter().GetResult(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return _stream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + _stream.SetLength(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + var task = Task.Run(() => _stream.WriteAsync(buffer, offset, count)); + task.GetAwaiter().GetResult(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _stream?.Dispose(); + } + base.Dispose(disposing); + } +} \ No newline at end of file diff --git a/Moonlight/App/Models/Forms/CloudPanelDataModel.cs b/Moonlight/App/Models/Forms/CloudPanelDataModel.cs new file mode 100644 index 00000000..d08e9461 --- /dev/null +++ b/Moonlight/App/Models/Forms/CloudPanelDataModel.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; + +namespace Moonlight.App.Models.Forms; + +public class CloudPanelDataModel +{ + [Required(ErrorMessage = "You have to enter a name")] + [MaxLength(32, ErrorMessage = "The name should not be longer than 32 characters")] + public string Name { get; set; } + + [Required(ErrorMessage = "You need to specify the host")] + public string Host { get; set; } + + [Required(ErrorMessage = "You need to enter an api url")] + public string ApiUrl { get; set; } + + [Required(ErrorMessage = "You need to enter an api key")] + public string ApiKey { get; set; } +} \ No newline at end of file diff --git a/Moonlight/App/Repositories/Repository.cs b/Moonlight/App/Repositories/Repository.cs new file mode 100644 index 00000000..1c46f6ab --- /dev/null +++ b/Moonlight/App/Repositories/Repository.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore; +using Moonlight.App.Database; + +namespace Moonlight.App.Repositories; + +public class Repository where TEntity : class +{ + private readonly DataContext DataContext; + private readonly DbSet DbSet; + + public Repository(DataContext dbContext) + { + DataContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); + DbSet = DataContext.Set(); + } + + public DbSet Get() + { + return DbSet; + } + + public TEntity Add(TEntity entity) + { + var x = DbSet.Add(entity); + DataContext.SaveChanges(); + return x.Entity; + } + + public void Update(TEntity entity) + { + DbSet.Update(entity); + DataContext.SaveChanges(); + } + + public void Delete(TEntity entity) + { + DbSet.Remove(entity); + DataContext.SaveChanges(); + } +} \ No newline at end of file diff --git a/Moonlight/App/Services/SmartDeployService.cs b/Moonlight/App/Services/SmartDeployService.cs index 57aa4bc8..e5e69f87 100644 --- a/Moonlight/App/Services/SmartDeployService.cs +++ b/Moonlight/App/Services/SmartDeployService.cs @@ -7,17 +7,17 @@ public class SmartDeployService { private readonly NodeRepository NodeRepository; private readonly PleskServerRepository PleskServerRepository; - private readonly WebsiteService WebsiteService; + private readonly WebSpaceService WebSpaceService; private readonly NodeService NodeService; public SmartDeployService( NodeRepository nodeRepository, - NodeService nodeService, PleskServerRepository pleskServerRepository, WebsiteService websiteService) + NodeService nodeService, PleskServerRepository pleskServerRepository, WebSpaceService webSpaceService) { NodeRepository = nodeRepository; NodeService = nodeService; PleskServerRepository = pleskServerRepository; - WebsiteService = websiteService; + WebSpaceService = webSpaceService; } public async Task GetNode() @@ -44,10 +44,7 @@ public class SmartDeployService foreach (var pleskServer in PleskServerRepository.Get().ToArray()) { - if (await WebsiteService.IsHostUp(pleskServer)) - { - result.Add(pleskServer); - } + result.Add(pleskServer); } return result.FirstOrDefault(); diff --git a/Moonlight/App/Services/Statistics/StatisticsCaptureService.cs b/Moonlight/App/Services/Statistics/StatisticsCaptureService.cs index 3098e5d1..f3a9d59b 100644 --- a/Moonlight/App/Services/Statistics/StatisticsCaptureService.cs +++ b/Moonlight/App/Services/Statistics/StatisticsCaptureService.cs @@ -9,7 +9,7 @@ public class StatisticsCaptureService private readonly ConfigService ConfigService; private readonly StatisticsRepository StatisticsRepository; private readonly IServiceScopeFactory ServiceScopeFactory; - private readonly WebsiteService WebsiteService; + private readonly WebSpaceService WebSpaceService; private readonly PleskServerRepository PleskServerRepository; private PeriodicTimer Timer; @@ -21,7 +21,7 @@ public class StatisticsCaptureService DataContext = provider.GetRequiredService(); ConfigService = configService; StatisticsRepository = provider.GetRequiredService(); - WebsiteService = provider.GetRequiredService(); + WebSpaceService = provider.GetRequiredService(); PleskServerRepository = provider.GetRequiredService(); var config = ConfigService.GetSection("Moonlight").GetSection("Statistics"); @@ -48,7 +48,7 @@ public class StatisticsCaptureService await foreach (var pleskServer in PleskServerRepository.Get()) { - databases += (await WebsiteService.GetDefaultDatabaseServer(pleskServer)).DbCount; + //databases += (await WebsiteService.GetDefaultDatabaseServer(pleskServer)).DbCount; } StatisticsRepository.Add("statistics.databasesCount", databases); diff --git a/Moonlight/App/Services/WebSpaceService.cs b/Moonlight/App/Services/WebSpaceService.cs new file mode 100644 index 00000000..549c44dc --- /dev/null +++ b/Moonlight/App/Services/WebSpaceService.cs @@ -0,0 +1,166 @@ +using Logging.Net; +using Microsoft.EntityFrameworkCore; +using Moonlight.App.ApiClients.CloudPanel; +using Moonlight.App.ApiClients.CloudPanel.Requests; +using Moonlight.App.Database.Entities; +using Moonlight.App.Exceptions; +using Moonlight.App.Helpers; +using Moonlight.App.Helpers.Files; +using Moonlight.App.Models.Plesk.Requests; +using Moonlight.App.Models.Plesk.Resources; +using Moonlight.App.Repositories; +using FileAccess = Moonlight.App.Helpers.Files.FileAccess; + +namespace Moonlight.App.Services; + +public class WebSpaceService +{ + private readonly Repository CloudPanelRepository; + private readonly Repository WebSpaceRepository; + private readonly CloudPanelApiHelper CloudPanelApiHelper; + + public WebSpaceService(Repository cloudPanelRepository, Repository webSpaceRepository, CloudPanelApiHelper cloudPanelApiHelper) + { + CloudPanelRepository = cloudPanelRepository; + WebSpaceRepository = webSpaceRepository; + CloudPanelApiHelper = cloudPanelApiHelper; + } + + public async Task Create(string domain, User owner, CloudPanel? ps = null) + { + if (WebSpaceRepository.Get().Any(x => x.Domain == domain)) + throw new DisplayException("A website with this domain does already exist"); + + var cloudPanel = ps ?? CloudPanelRepository.Get().First(); + + var ftpLogin = domain.Replace(".", "_"); + var ftpPassword = StringHelper.GenerateString(16); + + var phpVersion = "8.1"; // TODO: Add config option or smth + + var w = new WebSpace() + { + CloudPanel = cloudPanel, + Owner = owner, + Domain = domain, + UserName = ftpLogin, + Password = ftpPassword, + VHostTemplate = "Generic" //TODO: Implement as select option + }; + + var webSpace = WebSpaceRepository.Add(w); + + try + { + await CloudPanelApiHelper.Post(cloudPanel, "site/php", new AddPhpSite() + { + VHostTemplate = w.VHostTemplate, + DomainName = w.Domain, + PhpVersion = phpVersion, + SiteUser = w.UserName, + SiteUserPassword = w.Password + }); + } + catch (Exception) + { + WebSpaceRepository.Delete(webSpace); + throw; + } + + return webSpace; + } + + public async Task Delete(WebSpace w) + { + var website = EnsureData(w); + + await CloudPanelApiHelper.Delete(website.CloudPanel, $"site/{website.Domain}", null); + + WebSpaceRepository.Delete(website); + } + + public async Task IsHostUp(CloudPanel cloudPanel) + { + try + { + //var res = await PleskApiHelper.Get(pleskServer, "server"); + + return true; + + //if (res != null) + // return true; + } + catch (Exception e) + { + // ignored + } + + return false; + } + + public async Task IsHostUp(WebSpace w) + { + var webSpace = EnsureData(w); + + return await IsHostUp(webSpace.CloudPanel); + } + + #region SSL + public async Task GetSslCertificates(WebSpace w) + { + var certs = new List(); + return certs.ToArray(); + } + + public async Task CreateSslCertificate(WebSpace w) + { + + } + + public async Task DeleteSslCertificate(WebSpace w, string name) + { + + } + + #endregion + + #region Databases + + public async Task GetDatabases(WebSpace w) + { + return Array.Empty(); + } + + public async Task CreateDatabase(WebSpace w, string name, string password) + { + + } + + public async Task DeleteDatabase(WebSpace w, Models.Plesk.Resources.Database database) + { + + } + + #endregion + + public Task CreateFileAccess(WebSpace w) + { + var webspace = EnsureData(w); + + return Task.FromResult( + new SftpFileAccess(webspace.CloudPanel.Host, webspace.UserName, webspace.Password, 22, true) + ); + } + + private WebSpace EnsureData(WebSpace webSpace) + { + if (webSpace.CloudPanel == null || webSpace.Owner == null) + return WebSpaceRepository + .Get() + .Include(x => x.CloudPanel) + .Include(x => x.Owner) + .First(x => x.Id == webSpace.Id); + + return webSpace; + } +} \ No newline at end of file diff --git a/Moonlight/App/Services/WebsiteService.cs b/Moonlight/App/Services/WebsiteService.cs deleted file mode 100644 index 11906034..00000000 --- a/Moonlight/App/Services/WebsiteService.cs +++ /dev/null @@ -1,383 +0,0 @@ -using Logging.Net; -using Microsoft.EntityFrameworkCore; -using Moonlight.App.Database.Entities; -using Moonlight.App.Exceptions; -using Moonlight.App.Helpers; -using Moonlight.App.Helpers.Files; -using Moonlight.App.Models.Plesk.Requests; -using Moonlight.App.Models.Plesk.Resources; -using Moonlight.App.Repositories; -using FileAccess = Moonlight.App.Helpers.Files.FileAccess; - -namespace Moonlight.App.Services; - -public class WebsiteService -{ - private readonly WebsiteRepository WebsiteRepository; - private readonly PleskServerRepository PleskServerRepository; - private readonly PleskApiHelper PleskApiHelper; - private readonly UserRepository UserRepository; - - public WebsiteService(WebsiteRepository websiteRepository, PleskApiHelper pleskApiHelper, PleskServerRepository pleskServerRepository, UserRepository userRepository) - { - WebsiteRepository = websiteRepository; - PleskApiHelper = pleskApiHelper; - PleskServerRepository = pleskServerRepository; - UserRepository = userRepository; - } - - public async Task Create(string baseDomain, User owner, PleskServer? ps = null) - { - if (WebsiteRepository.Get().Any(x => x.BaseDomain == baseDomain)) - throw new DisplayException("A website with this domain does already exist"); - - var pleskServer = ps ?? PleskServerRepository.Get().First(); - - var ftpLogin = baseDomain; - var ftpPassword = StringHelper.GenerateString(16); - - var w = new Website() - { - PleskServer = pleskServer, - Owner = owner, - BaseDomain = baseDomain, - PleskId = 0, - FtpPassword = ftpPassword, - FtpLogin = ftpLogin - }; - - var website = WebsiteRepository.Add(w); - - try - { - var id = await GetAdminAccount(pleskServer); - - var result = await PleskApiHelper.Post(pleskServer, "domains", new CreateDomain() - { - Description = $"moonlight website {website.Id}", - Name = baseDomain, - HostingType = "virtual", - Plan = new() - { - Name = "Unlimited" - }, - HostingSettings = new() - { - FtpLogin = ftpLogin, - FtpPassword = ftpPassword - }, - OwnerClient = new() - { - Id = id - } - }); - - website.PleskId = result.Id; - - WebsiteRepository.Update(website); - } - catch (Exception e) - { - WebsiteRepository.Delete(website); - throw; - } - - return website; - } - - public async Task Delete(Website w) - { - var website = EnsureData(w); - - await PleskApiHelper.Delete(website.PleskServer, $"domains/{w.PleskId}", null); - - WebsiteRepository.Delete(website); - } - - public async Task IsHostUp(PleskServer pleskServer) - { - try - { - var res = await PleskApiHelper.Get(pleskServer, "server"); - - if (res != null) - return true; - } - catch (Exception e) - { - // ignored - } - - return false; - } - - public async Task IsHostUp(Website w) - { - var website = EnsureData(w); - - try - { - var res = await PleskApiHelper.Get(website.PleskServer, "server"); - - if (res != null) - return true; - } - catch (Exception) - { - // ignored - } - - return false; - } - - #region Get host - - public async Task GetHost(PleskServer pleskServer) - { - return (await PleskApiHelper.Get(pleskServer, "server")).Hostname; - } - - public async Task GetHost(Website w) - { - var website = EnsureData(w); - - return await GetHost(website.PleskServer); - } - - #endregion - - private async Task GetAdminAccount(PleskServer pleskServer) - { - var users = await PleskApiHelper.Get(pleskServer, "clients"); - - var user = users.FirstOrDefault(x => x.Type == "admin"); - - if (user == null) - throw new DisplayException("No admin account in plesk found"); - - return user.Id; - } - - #region SSL - public async Task GetSslCertificates(Website w) - { - var website = EnsureData(w); - var certs = new List(); - - var data = await ExecuteCli(website.PleskServer, "certificate", p => - { - p.Add("-l"); - p.Add("-domain"); - p.Add(w.BaseDomain); - }); - - string[] lines = data.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); - - foreach (string line in lines) - { - if (line.Contains("Lets Encrypt")) - { - string[] parts = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); - - if(parts.Length > 6) - certs.Add($"{parts[4]} {parts[5]} {parts[6]}"); - } - else if (line.Contains("Listing of SSL/TLS certificates repository was successful")) - { - // This line indicates the end of the certificate listing, so we can stop parsing - break; - } - } - - return certs.ToArray(); - } - - public async Task CreateSslCertificate(Website w) - { - var website = EnsureData(w); - - await ExecuteCli(website.PleskServer, "extension", p => - { - p.Add("--exec"); - p.Add("letsencrypt"); - p.Add("cli.php"); - p.Add("-d"); - p.Add(website.BaseDomain); - p.Add("-m"); - p.Add(website.Owner.Email); - }); - } - - public async Task DeleteSslCertificate(Website w, string name) - { - var website = EnsureData(w); - - try - { - await ExecuteCli(website.PleskServer, "site", p => - { - p.Add("-u"); - p.Add(website.BaseDomain); - p.Add("-ssl"); - p.Add("false"); - }); - - try - { - await ExecuteCli(website.PleskServer, "certificate", p => - { - p.Add("--remove"); - p.Add(name); - p.Add("-domain"); - p.Add(website.BaseDomain); - }); - } - catch (Exception e) - { - Logger.Warn("Error removing ssl certificate"); - Logger.Warn(e); - - throw new DisplayException("An unknown error occured while removing ssl certificate"); - } - } - catch (DisplayException) - { - // Redirect all display exception to soft error handler - throw; - } - catch (Exception e) - { - Logger.Warn("Error disabling ssl certificate"); - Logger.Warn(e); - - throw new DisplayException("An unknown error occured while disabling ssl certificate"); - } - } - - #endregion - - #region Databases - - public async Task GetDatabases(Website w) - { - var website = EnsureData(w); - - var dbs = await PleskApiHelper.Get( - website.PleskServer, - $"databases?domain={w.BaseDomain}" - ); - - return dbs; - } - - public async Task CreateDatabase(Website w, string name, string password) - { - var website = EnsureData(w); - - var server = await GetDefaultDatabaseServer(website); - - if (server == null) - throw new DisplayException("No database server marked as default found"); - - var dbReq = new CreateDatabase() - { - Name = name, - Type = "mysql", - ParentDomain = new() - { - Name = website.BaseDomain - }, - ServerId = server.Id - }; - - var db = await PleskApiHelper.Post(website.PleskServer, "databases", dbReq); - - if (db == null) - throw new DisplayException("Unable to create database via api"); - - var dbUserReq = new CreateDatabaseUser() - { - DatabaseId = db.Id, - Login = name, - Password = password - }; - - await PleskApiHelper.Post(website.PleskServer, "dbusers", dbUserReq); - } - - public async Task DeleteDatabase(Website w, Models.Plesk.Resources.Database database) - { - var website = EnsureData(w); - - var dbUsers = await PleskApiHelper.Get( - website.PleskServer, - $"dbusers?dbId={database.Id}" - ); - - foreach (var dbUser in dbUsers) - { - await PleskApiHelper.Delete(website.PleskServer, $"dbusers/{dbUser.Id}", null); - } - - await PleskApiHelper.Delete(website.PleskServer, $"databases/{database.Id}", null); - } - - public async Task GetDefaultDatabaseServer(PleskServer pleskServer) - { - var dbServers = await PleskApiHelper.Get(pleskServer, "dbservers"); - - return dbServers.FirstOrDefault(x => x.IsDefault); - } - - public async Task GetDefaultDatabaseServer(Website w) - { - var website = EnsureData(w); - - return await GetDefaultDatabaseServer(website.PleskServer); - } - - #endregion - - public async Task CreateFileAccess(Website w) - { - var website = EnsureData(w); - var host = await GetHost(website.PleskServer); - - return new FtpFileAccess(host, 21, website.FtpLogin, website.FtpPassword); - } - - private async Task ExecuteCli( - PleskServer server, - string cli, Action>? parameters = null, - Action>? variables = null - ) - { - var p = new List(); - var v = new Dictionary(); - - parameters?.Invoke(p); - variables?.Invoke(v); - - var req = new CliCall() - { - Env = v, - Params = p - }; - - var res = await PleskApiHelper.Post(server, $"cli/{cli}/call", req); - - return res.Stdout; - } - - private Website EnsureData(Website website) - { - if (website.PleskServer == null || website.Owner == null) - return WebsiteRepository - .Get() - .Include(x => x.PleskServer) - .Include(x => x.Owner) - .First(x => x.Id == website.Id); - - return website; - } -} \ No newline at end of file diff --git a/Moonlight/Moonlight.csproj b/Moonlight/Moonlight.csproj index 1c684c61..72e91ab4 100644 --- a/Moonlight/Moonlight.csproj +++ b/Moonlight/Moonlight.csproj @@ -41,6 +41,7 @@ + @@ -67,6 +68,7 @@ + diff --git a/Moonlight/Program.cs b/Moonlight/Program.cs index ffd7894f..eba93a6f 100644 --- a/Moonlight/Program.cs +++ b/Moonlight/Program.cs @@ -2,6 +2,7 @@ using BlazorDownloadFile; using BlazorTable; using CurrieTechnologies.Razor.SweetAlert2; using Logging.Net; +using Moonlight.App.ApiClients.CloudPanel; using Moonlight.App.Database; using Moonlight.App.Helpers; using Moonlight.App.LogMigrator; @@ -76,6 +77,7 @@ namespace Moonlight builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(typeof(Repository<>)); // Services builder.Services.AddSingleton(); @@ -102,7 +104,7 @@ namespace Moonlight builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); - builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -136,6 +138,7 @@ namespace Moonlight builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); // Background services builder.Services.AddSingleton(); diff --git a/Moonlight/Shared/Components/FileManagerPartials/FilePath.razor b/Moonlight/Shared/Components/FileManagerPartials/FilePath.razor index 93982da1..4492bfcf 100644 --- a/Moonlight/Shared/Components/FileManagerPartials/FilePath.razor +++ b/Moonlight/Shared/Components/FileManagerPartials/FilePath.razor @@ -1,4 +1,5 @@ @using Moonlight.App.Helpers.Files +@using Logging.Net
diff --git a/Moonlight/Shared/Components/Navigations/AdminWebsitesNavigation.razor b/Moonlight/Shared/Components/Navigations/AdminWebspacesNavigation.razor similarity index 72% rename from Moonlight/Shared/Components/Navigations/AdminWebsitesNavigation.razor rename to Moonlight/Shared/Components/Navigations/AdminWebspacesNavigation.razor index 40b98026..b7380cc2 100644 --- a/Moonlight/Shared/Components/Navigations/AdminWebsitesNavigation.razor +++ b/Moonlight/Shared/Components/Navigations/AdminWebspacesNavigation.razor @@ -2,13 +2,13 @@
diff --git a/Moonlight/Shared/Components/WebsiteControl/WebsiteDashboard.razor b/Moonlight/Shared/Components/WebsiteControl/WebSpaceDashboard.razor similarity index 92% rename from Moonlight/Shared/Components/WebsiteControl/WebsiteDashboard.razor rename to Moonlight/Shared/Components/WebsiteControl/WebSpaceDashboard.razor index d499e873..ab158cd8 100644 --- a/Moonlight/Shared/Components/WebsiteControl/WebsiteDashboard.razor +++ b/Moonlight/Shared/Components/WebsiteControl/WebSpaceDashboard.razor @@ -1,14 +1,14 @@ @using Moonlight.App.Database.Entities @using Moonlight.App.Services -@inject WebsiteService WebsiteService +@inject WebSpaceService WebSpaceService @inject SmartTranslateService SmartTranslateService
- Website screenshot + Website screenshot
@@ -85,7 +85,7 @@ @code { [CascadingParameter] - public Website CurrentWebsite { get; set; } + public WebSpace CurrentWebSpace { get; set; } private string[] Certs; @@ -94,18 +94,18 @@ private async Task Load(LazyLoader lazyLoader) { await lazyLoader.SetText("Loading certificates"); - Certs = await WebsiteService.GetSslCertificates(CurrentWebsite); + Certs = await WebSpaceService.GetSslCertificates(CurrentWebSpace); } private async Task CreateCertificate() { - await WebsiteService.CreateSslCertificate(CurrentWebsite); + await WebSpaceService.CreateSslCertificate(CurrentWebSpace); await LazyLoader.Reload(); } private async Task DeleteCertificate(string name) { - await WebsiteService.DeleteSslCertificate(CurrentWebsite, name); + await WebSpaceService.DeleteSslCertificate(CurrentWebSpace, name); await LazyLoader.Reload(); } } \ No newline at end of file diff --git a/Moonlight/Shared/Components/WebsiteControl/WebsiteDatabases.razor b/Moonlight/Shared/Components/WebsiteControl/WebSpaceDatabases.razor similarity index 90% rename from Moonlight/Shared/Components/WebsiteControl/WebsiteDatabases.razor rename to Moonlight/Shared/Components/WebsiteControl/WebSpaceDatabases.razor index 2c244069..5b83af5c 100644 --- a/Moonlight/Shared/Components/WebsiteControl/WebsiteDatabases.razor +++ b/Moonlight/Shared/Components/WebsiteControl/WebSpaceDatabases.razor @@ -4,7 +4,7 @@ @using Moonlight.App.Services @inject SmartTranslateService SmartTranslateService -@inject WebsiteService WebsiteService +@inject WebSpaceService WebSpaceService
@@ -93,7 +93,7 @@ else {
- No databases found for this website + No databases found for this webspace
} @@ -101,7 +101,7 @@ @code { [CascadingParameter] - public Website CurrentWebsite { get; set; } + public WebSpace CurrentWebSpace { get; set; } private LazyLoader LazyLoader; private Database[] Databases; @@ -112,25 +112,19 @@ private async Task Load(LazyLoader arg) { - Databases = await WebsiteService.GetDatabases(CurrentWebsite); - - if (Databases.Any()) - { - DatabaseServer = (await WebsiteService.GetDefaultDatabaseServer(CurrentWebsite))!; - Host = await WebsiteService.GetHost(CurrentWebsite); - } + Databases = await WebSpaceService.GetDatabases(CurrentWebSpace); } private async Task OnValidSubmit() { - await WebsiteService.CreateDatabase(CurrentWebsite, Model.Name, Model.Password); + await WebSpaceService.CreateDatabase(CurrentWebSpace, Model.Name, Model.Password); Model = new(); await LazyLoader.Reload(); } private async Task DeleteDatabase(Database database) { - await WebsiteService.DeleteDatabase(CurrentWebsite, database); + await WebSpaceService.DeleteDatabase(CurrentWebSpace, database); await LazyLoader.Reload(); } } \ No newline at end of file diff --git a/Moonlight/Shared/Components/WebsiteControl/WebsiteFiles.razor b/Moonlight/Shared/Components/WebsiteControl/WebSpaceFiles.razor similarity index 69% rename from Moonlight/Shared/Components/WebsiteControl/WebsiteFiles.razor rename to Moonlight/Shared/Components/WebsiteControl/WebSpaceFiles.razor index 84d47508..06444027 100644 --- a/Moonlight/Shared/Components/WebsiteControl/WebsiteFiles.razor +++ b/Moonlight/Shared/Components/WebsiteControl/WebSpaceFiles.razor @@ -3,7 +3,7 @@ @using Moonlight.App.Services @using Moonlight.Shared.Components.FileManagerPartials -@inject WebsiteService WebsiteService +@inject WebSpaceService WebSpaceService @@ -13,12 +13,12 @@ @code { [CascadingParameter] - public Website CurrentWebsite { get; set; } + public WebSpace CurrentWebSpace { get; set; } private FileAccess Access; private async Task Load(LazyLoader arg) { - Access = await WebsiteService.CreateFileAccess(CurrentWebsite); + Access = await WebSpaceService.CreateFileAccess(CurrentWebSpace); } } diff --git a/Moonlight/Shared/Components/WebsiteControl/WebSpaceFtp.razor b/Moonlight/Shared/Components/WebsiteControl/WebSpaceFtp.razor new file mode 100644 index 00000000..ffa1de43 --- /dev/null +++ b/Moonlight/Shared/Components/WebsiteControl/WebSpaceFtp.razor @@ -0,0 +1,55 @@ +@using Moonlight.App.Database.Entities +@using Moonlight.App.Services + +@inject WebSpaceService WebSpaceService + +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +@code +{ + [CascadingParameter] + public WebSpace CurrentWebSpace { get; set; } +} \ No newline at end of file diff --git a/Moonlight/Shared/Components/WebsiteControl/WebsiteNavigation.razor b/Moonlight/Shared/Components/WebsiteControl/WebSpaceNavigation.razor similarity index 76% rename from Moonlight/Shared/Components/WebsiteControl/WebsiteNavigation.razor rename to Moonlight/Shared/Components/WebsiteControl/WebSpaceNavigation.razor index bec6068c..1d28f88c 100644 --- a/Moonlight/Shared/Components/WebsiteControl/WebsiteNavigation.razor +++ b/Moonlight/Shared/Components/WebsiteControl/WebSpaceNavigation.razor @@ -10,8 +10,8 @@
-
@(Website.BaseDomain)
-
@(Website.PleskServer.Name)
+
@(WebSpace.Domain)
+
@(WebSpace.CloudPanel.Name)
@@ -24,22 +24,22 @@
- +
diff --git a/Moonlight/Shared/Views/Admin/Websites/Servers/Edit.razor b/Moonlight/Shared/Views/Admin/Websites/Servers/Edit.razor deleted file mode 100644 index 7cb9ae2a..00000000 --- a/Moonlight/Shared/Views/Admin/Websites/Servers/Edit.razor +++ /dev/null @@ -1,98 +0,0 @@ -@page "/admin/websites/servers/edit/{Id:int}" - -@using Moonlight.App.Models.Forms -@using Moonlight.App.Repositories -@using Moonlight.App.Database.Entities - -@inject PleskServerRepository PleskServerRepository -@inject NavigationManager NavigationManager - - - - @if (PleskServer == null) - { -
-
- Not found image -
-

- Plesk server not found -

-

- A plesk server with that id cannot be found -

-
-
-
- } - else - { -
- - -
- -
- -
- -
- -
- -
-
- -
-
-
- } -
-
- -@code -{ - [Parameter] - public int Id { get; set; } - - private PleskServer? PleskServer; - - private PleskServerDataModel Model = new(); - - private Task OnValidSubmit() - { - PleskServer!.Name = Model.Name; - PleskServer.ApiUrl = Model.ApiUrl; - PleskServer.ApiKey = Model.ApiKey; - - PleskServerRepository.Update(PleskServer); - - NavigationManager.NavigateTo("/admin/websites/servers"); - - return Task.CompletedTask; - } - - private Task Load(LazyLoader arg) - { - PleskServer = PleskServerRepository - .Get() - .FirstOrDefault(x => x.Id == Id); - - if (PleskServer != null) - { - Model.Name = PleskServer.Name; - Model.ApiUrl = PleskServer.ApiUrl; - Model.ApiKey = PleskServer.ApiKey; - } - - return Task.CompletedTask; - } -} diff --git a/Moonlight/Shared/Views/Admin/Websites/Index.razor b/Moonlight/Shared/Views/Admin/Webspaces/Index.razor similarity index 53% rename from Moonlight/Shared/Views/Admin/Websites/Index.razor rename to Moonlight/Shared/Views/Admin/Webspaces/Index.razor index 6b233380..7518ca4a 100644 --- a/Moonlight/Shared/Views/Admin/Websites/Index.razor +++ b/Moonlight/Shared/Views/Admin/Webspaces/Index.razor @@ -1,4 +1,4 @@ -@page "/admin/websites/" +@page "/admin/webspaces/" @using Moonlight.Shared.Components.Navigations @using Moonlight.App.Services @@ -8,53 +8,53 @@ @using BlazorTable @inject SmartTranslateService SmartTranslateService -@inject WebsiteRepository WebsiteRepository -@inject WebsiteService WebsiteService +@inject Repository WebSpaceRepository +@inject WebSpaceService WebSpaceService - +