From a41a929e7f9f365e6eff6cf8f1b82967dd656222 Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Mon, 3 Apr 2023 19:45:01 +0200 Subject: [PATCH 1/4] Added subscription edit --- .../Views/Admin/Subscriptions/Edit.razor | 168 ++++++++++++++++++ Moonlight/resources/lang/de_de.lang | 1 + 2 files changed, 169 insertions(+) create mode 100644 Moonlight/Shared/Views/Admin/Subscriptions/Edit.razor diff --git a/Moonlight/Shared/Views/Admin/Subscriptions/Edit.razor b/Moonlight/Shared/Views/Admin/Subscriptions/Edit.razor new file mode 100644 index 00000000..87dd733c --- /dev/null +++ b/Moonlight/Shared/Views/Admin/Subscriptions/Edit.razor @@ -0,0 +1,168 @@ +@page "/admin/subscriptions/edit/{Id:int}" +@using Moonlight.App.Models.Forms +@using Moonlight.App.Models.Misc +@using Moonlight.App.Repositories +@using Moonlight.App.Services +@using Moonlight.App.Database.Entities + +@inject NavigationManager NavigationManager +@inject SubscriptionRepository SubscriptionRepository +@inject SubscriptionAdminService SubscriptionAdminService + + +
+ + @if (Subscription == null) + { +
+ No subscription with this id has been found +
+ } + else + { + + +
+ +
+ +
+ +
+ +
+ @foreach (var limitPart in Limits.Chunk(3)) + { +
+ @foreach (var limit in limitPart) + { +
+
+ +
+ +
+ +
+ +
+
+
+ Options +
+
+ +
+
+ + +
+
+
+
+ } +
+ } +
+ +
+ + +
+
+ } +
+
+
+ +@code +{ + [Parameter] + public int Id { get; set; } + + private Subscription? Subscription; + + private SubscriptionDataModel Model = new(); + private List Limits = new(); + + private async Task OnSubmit() + { + Subscription!.Name = Model.Name; + Subscription.Description = Model.Description; + + SubscriptionRepository.Update(Subscription); + + await SubscriptionAdminService.SaveLimits(Subscription, Limits.ToArray()); + + NavigationManager.NavigateTo("/admin/subscriptions"); + } + + private async Task Load(LazyLoader arg) + { + Subscription = SubscriptionRepository + .Get() + .FirstOrDefault(x => x.Id == Id); + + if (Subscription != null) + { + Model.Name = Subscription.Name; + Model.Description = Subscription.Description; + + Limits = (await SubscriptionAdminService.GetLimits(Subscription)).ToList(); + } + } +} \ No newline at end of file diff --git a/Moonlight/resources/lang/de_de.lang b/Moonlight/resources/lang/de_de.lang index 0cfc0d21..b56f294a 100644 --- a/Moonlight/resources/lang/de_de.lang +++ b/Moonlight/resources/lang/de_de.lang @@ -462,3 +462,4 @@ Create subscription;Create subscription Options;Options Amount;Amount Do you really want to delete it?;Do you really want to delete it? +Save subscription;Save subscription From 2298bab71e98cc3ae60bd8e04a22f60284db4c9a Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Mon, 3 Apr 2023 21:23:27 +0200 Subject: [PATCH 2/4] Base implementation of smart deploy for servers, order screen, subscription service --- .../App/Models/Forms/ServerOrderDataModel.cs | 14 ++ .../App/Models/Misc/SubscriptionLimit.cs | 6 + Moonlight/App/Services/SmartDeployService.cs | 64 +++++++ Moonlight/App/Services/SubscriptionService.cs | 22 ++- Moonlight/Program.cs | 1 + Moonlight/Shared/Layouts/MainLayout.razor | 3 +- .../{Servers.razor => Servers/Index.razor} | 0 Moonlight/Shared/Views/Servers/New.razor | 174 ++++++++++++++++++ Moonlight/resources/lang/de_de.lang | 12 ++ 9 files changed, 287 insertions(+), 9 deletions(-) create mode 100644 Moonlight/App/Models/Forms/ServerOrderDataModel.cs create mode 100644 Moonlight/App/Services/SmartDeployService.cs rename Moonlight/Shared/Views/{Servers.razor => Servers/Index.razor} (100%) create mode 100644 Moonlight/Shared/Views/Servers/New.razor diff --git a/Moonlight/App/Models/Forms/ServerOrderDataModel.cs b/Moonlight/App/Models/Forms/ServerOrderDataModel.cs new file mode 100644 index 00000000..778096f5 --- /dev/null +++ b/Moonlight/App/Models/Forms/ServerOrderDataModel.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; +using Moonlight.App.Database.Entities; + +namespace Moonlight.App.Models.Forms; + +public class ServerOrderDataModel +{ + [Required(ErrorMessage = "You need to enter a name")] + [MaxLength(32, ErrorMessage = "The name cannot be longer that 32 characters")] + public string Name { get; set; } = ""; + + [Required(ErrorMessage = "You need to specify a server image")] + public Image Image { get; set; } +} \ No newline at end of file diff --git a/Moonlight/App/Models/Misc/SubscriptionLimit.cs b/Moonlight/App/Models/Misc/SubscriptionLimit.cs index 6e77abaf..21d59100 100644 --- a/Moonlight/App/Models/Misc/SubscriptionLimit.cs +++ b/Moonlight/App/Models/Misc/SubscriptionLimit.cs @@ -5,6 +5,12 @@ public class SubscriptionLimit public string Identifier { get; set; } = ""; public int Amount { get; set; } public List Options { get; set; } = new(); + + public string? ReadValue(string key) + { + var d = Options.FirstOrDefault(x => string.Equals(x.Key, key, StringComparison.InvariantCultureIgnoreCase)); + return d?.Value; + } public class LimitOption { diff --git a/Moonlight/App/Services/SmartDeployService.cs b/Moonlight/App/Services/SmartDeployService.cs new file mode 100644 index 00000000..0585c1dd --- /dev/null +++ b/Moonlight/App/Services/SmartDeployService.cs @@ -0,0 +1,64 @@ +using Moonlight.App.Database.Entities; +using Moonlight.App.Repositories; + +namespace Moonlight.App.Services; + +public class SmartDeployService +{ + private readonly NodeRepository NodeRepository; + private readonly NodeService NodeService; + + public SmartDeployService(NodeRepository nodeRepository, NodeService nodeService) + { + NodeRepository = nodeRepository; + NodeService = nodeService; + } + + public async Task GetNode() + { + var data = new Dictionary(); + + foreach (var node in NodeRepository.Get().ToArray()) + { + var u = await GetUsageScore(node); + + if(u != 0) + data.Add(node, u); + } + + if (!data.Any()) + return null; + + return data.MaxBy(x => x.Value).Key; + } + + private async Task GetUsageScore(Node node) + { + var score = 0; + + try + { + var cpuStats = await NodeService.GetCpuStats(node); + var memoryStats = await NodeService.GetMemoryStats(node); + var diskStats = await NodeService.GetDiskStats(node); + + var cpuWeight = 0.5; // Weight of CPU usage in the final score + var memoryWeight = 0.3; // Weight of memory usage in the final score + var diskSpaceWeight = 0.2; // Weight of free disk space in the final score + + var cpuScore = (1 - cpuStats.Usage) * cpuWeight; // CPU score is based on the inverse of CPU usage + var memoryScore = (1 - (memoryStats.Used / 1024)) * memoryWeight; // Memory score is based on the percentage of free memory + var diskSpaceScore = (double) diskStats.FreeBytes / 1000000000 * diskSpaceWeight; // Disk space score is based on the amount of free disk space in GB + + var finalScore = cpuScore + memoryScore + diskSpaceScore; + + return finalScore; + } + catch (Exception e) + { + // ignored + } + + return score; + } +} \ No newline at end of file diff --git a/Moonlight/App/Services/SubscriptionService.cs b/Moonlight/App/Services/SubscriptionService.cs index f5e77c95..9d35fe4b 100644 --- a/Moonlight/App/Services/SubscriptionService.cs +++ b/Moonlight/App/Services/SubscriptionService.cs @@ -82,16 +82,19 @@ public class SubscriptionService { var configSection = ConfigService.GetSection("Moonlight").GetSection("Subscriptions"); - var defaultLimits = configSection.GetValue("defaultLimits"); + var defaultLimits = configSection.GetValue("DefaultLimits"); var subscription = await GetCurrent(); if (subscription == null) { - var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier); + if (defaultLimits != null) + { + var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier); - if (foundDefault != null) - return foundDefault; + if (foundDefault != null) + return foundDefault; + } return new() { @@ -109,11 +112,14 @@ public class SubscriptionService if (foundLimit != null) return foundLimit; - - var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier); - if (foundDefault != null) - return foundDefault; + if (defaultLimits != null) + { + var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier); + + if (foundDefault != null) + return foundDefault; + } return new() { diff --git a/Moonlight/Program.cs b/Moonlight/Program.cs index d7629715..cb4fdcf3 100644 --- a/Moonlight/Program.cs +++ b/Moonlight/Program.cs @@ -91,6 +91,7 @@ namespace Moonlight builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/Moonlight/Shared/Layouts/MainLayout.razor b/Moonlight/Shared/Layouts/MainLayout.razor index b2de0364..f4f29aa4 100644 --- a/Moonlight/Shared/Layouts/MainLayout.razor +++ b/Moonlight/Shared/Layouts/MainLayout.razor @@ -153,7 +153,8 @@ await JsRuntime.InvokeVoidAsync("document.body.removeAttribute", "data-kt-app-page-loading"); await JsRuntime.InvokeVoidAsync("KTMenu.createInstances"); await JsRuntime.InvokeVoidAsync("KTDrawer.createInstances"); - await JsRuntime.InvokeVoidAsync("createSnow"); + + //await JsRuntime.InvokeVoidAsync("createSnow"); await SessionService.Register(); diff --git a/Moonlight/Shared/Views/Servers.razor b/Moonlight/Shared/Views/Servers/Index.razor similarity index 100% rename from Moonlight/Shared/Views/Servers.razor rename to Moonlight/Shared/Views/Servers/Index.razor diff --git a/Moonlight/Shared/Views/Servers/New.razor b/Moonlight/Shared/Views/Servers/New.razor new file mode 100644 index 00000000..5fb01f0e --- /dev/null +++ b/Moonlight/Shared/Views/Servers/New.razor @@ -0,0 +1,174 @@ +@page "/servers/new" +@using Moonlight.App.Services +@using Moonlight.App.Database.Entities +@using Moonlight.App.Models.Forms +@using Moonlight.App.Models.Misc +@using Moonlight.App.Repositories + +@inject SubscriptionService SubscriptionService +@inject ImageRepository ImageRepository +@inject SmartTranslateService SmartTranslateService +@inject SmartDeployService SmartDeployService + + + @if (DeployNode == null) + { +
+
+ Not found image +
+

+ No node found +

+

+ No node found to deploy to found +

+
+
+
+ } + else + { +
+
+
+
+
+

+ Server details +

+
+
+
+
+
+ +
@(DeployNode.Name)
+
+ @if (Model.Image != null) + { + var limit = Images[Model.Image]; + +
+ +
@(Model.Image.Name)
+
+ +
+ +
+ @{ + var cpu = limit.ReadValue("cpu"); + + if (cpu == null) + cpu = "N/A"; + else + cpu = (int.Parse(cpu) / 100).ToString(); + } + @(cpu) Cores +
+
+ +
+ +
@(limit.ReadValue("memory")) MB
+
+ +
+ +
@(limit.ReadValue("disk")) MB
+
+ } +
+
+
+
+
+
+
+
+

+ Configure your server +

+
+
+
+ + +
+ +
+ @if (Images.Any()) + { + + + + + + } + else + { +
+ + You reached the maximum amount of servers for every image of your subscription: @(Subscription == null ? SmartTranslateService.Translate("Default") : Subscription.Name) + +
+ } +
+
+
+
+
+ } +
+ +@code +{ + private Node? DeployNode; + private Subscription? Subscription; + + private Dictionary Images = new(); + + private ServerOrderDataModel Model = new(); + + private async Task Load(LazyLoader lazyLoader) + { + // Reset state + Images.Clear(); + Model = new(); + + await lazyLoader.SetText(SmartTranslateService.Translate("Loading your subscription")); + Subscription = await SubscriptionService.GetCurrent(); + + await lazyLoader.SetText(SmartTranslateService.Translate("Searching for deploy node")); + + DeployNode = await SmartDeployService.GetNode(); + + await lazyLoader.SetText(SmartTranslateService.Translate("Searching for available images")); + + var images = ImageRepository.Get().ToArray(); + + foreach (var image in images) + { + var limit = await SubscriptionService.GetLimit("image." + image.Id); + + if (limit.Amount > 0) + { + Images.Add(image, limit); + } + } + } + + private async Task OnValidSubmit() + { + } +} \ No newline at end of file diff --git a/Moonlight/resources/lang/de_de.lang b/Moonlight/resources/lang/de_de.lang index b56f294a..bcb775a2 100644 --- a/Moonlight/resources/lang/de_de.lang +++ b/Moonlight/resources/lang/de_de.lang @@ -463,3 +463,15 @@ Options;Options Amount;Amount Do you really want to delete it?;Do you really want to delete it? Save subscription;Save subscription +Loading your subscription;Loading your subscription +Searching for deploy node;Searching for deploy node +Searching for available images;Searching for available images +Server details;Server details +Configure your server;Configure your server +Default;Default +No images available;No images available +You reached the maximum amount of servers for every image of your subscription;You reached the maximum amount of servers for every image of your subscription +No node found;No node found +No node found to deploy to found;No node found to deploy to found +You need to specify a server image;You need to specify a server image +CPU;CPU From bb7be3b820bc1ef5f20d51a111f398309064bc79 Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Tue, 4 Apr 2023 01:23:07 +0200 Subject: [PATCH 3/4] Added subscription ui for user --- .../App/Services/Interop/AlertService.cs | 47 +++++++- .../App/Services/Interop/ClipboardService.cs | 5 + Moonlight/App/Services/SubscriptionService.cs | 62 ++++------ .../Views/Admin/Subscriptions/Index.razor | 35 +++++- .../Shared/Views/Profile/Subscriptions.razor | 112 ++++++++++++++++++ .../Views/Servers/{New.razor => Create.razor} | 56 ++++++++- Moonlight/resources/lang/de_de.lang | 16 +++ .../wwwroot/assets/media/svg/subscription.svg | 38 ++++++ 8 files changed, 329 insertions(+), 42 deletions(-) create mode 100644 Moonlight/Shared/Views/Profile/Subscriptions.razor rename Moonlight/Shared/Views/Servers/{New.razor => Create.razor} (78%) create mode 100644 Moonlight/wwwroot/assets/media/svg/subscription.svg diff --git a/Moonlight/App/Services/Interop/AlertService.cs b/Moonlight/App/Services/Interop/AlertService.cs index d03d4ef9..7e6bcb25 100644 --- a/Moonlight/App/Services/Interop/AlertService.cs +++ b/Moonlight/App/Services/Interop/AlertService.cs @@ -5,10 +5,12 @@ namespace Moonlight.App.Services.Interop; public class AlertService { private readonly SweetAlertService SweetAlertService; + private readonly SmartTranslateService SmartTranslateService; - public AlertService(SweetAlertService service) + public AlertService(SweetAlertService service, SmartTranslateService smartTranslateService) { SweetAlertService = service; + SmartTranslateService = smartTranslateService; } public async Task Info(string title, string desciption) @@ -21,6 +23,11 @@ public class AlertService }); } + public async Task Info(string desciption) + { + await Info("", desciption); + } + public async Task Success(string title, string desciption) { await SweetAlertService.FireAsync(new SweetAlertOptions() @@ -31,6 +38,11 @@ public class AlertService }); } + public async Task Success(string desciption) + { + await Success("", desciption); + } + public async Task Warning(string title, string desciption) { await SweetAlertService.FireAsync(new SweetAlertOptions() @@ -41,6 +53,11 @@ public class AlertService }); } + public async Task Warning(string desciption) + { + await Warning("", desciption); + } + public async Task Error(string title, string desciption) { await SweetAlertService.FireAsync(new SweetAlertOptions() @@ -51,6 +68,11 @@ public class AlertService }); } + public async Task Error(string desciption) + { + await Error("", desciption); + } + public async Task YesNo(string title, string desciption, string yesText, string noText) { var result = await SweetAlertService.FireAsync(new SweetAlertOptions() @@ -79,4 +101,27 @@ public class AlertService return result.Value; } + + public async Task ConfirmMath() + { + var r = new Random(); + var i1 = r.Next(5, 15); + var i2 = r.Next(5, 15); + + var input = await Text( + SmartTranslateService.Translate("Confirm"), + SmartTranslateService.Translate($"{i1} + {i2} ="), + "" + ); + + if (int.TryParse(input, out int i)) + { + if (i == i1 + i2) + { + return true; + } + } + + return false; + } } \ No newline at end of file diff --git a/Moonlight/App/Services/Interop/ClipboardService.cs b/Moonlight/App/Services/Interop/ClipboardService.cs index 79fa4202..a7c806c9 100644 --- a/Moonlight/App/Services/Interop/ClipboardService.cs +++ b/Moonlight/App/Services/Interop/ClipboardService.cs @@ -15,4 +15,9 @@ public class ClipboardService { await JsRuntime.InvokeVoidAsync("copyTextToClipboard", data); } + public async Task Copy(string data) + { + await JsRuntime.InvokeVoidAsync("copyTextToClipboard", data); + } + } \ No newline at end of file diff --git a/Moonlight/App/Services/SubscriptionService.cs b/Moonlight/App/Services/SubscriptionService.cs index 9d35fe4b..de23692a 100644 --- a/Moonlight/App/Services/SubscriptionService.cs +++ b/Moonlight/App/Services/SubscriptionService.cs @@ -78,55 +78,45 @@ public class SubscriptionService await OneTimeJwtService.Revoke(code); } + public async Task Cancel() + { + if (await GetCurrent() != null) + { + var user = await GetCurrentUser(); + + user.CurrentSubscription = null; + + UserRepository.Update(user); + } + } + public async Task GetLimit(string identifier) { - var configSection = ConfigService.GetSection("Moonlight").GetSection("Subscriptions"); - - var defaultLimits = configSection.GetValue("DefaultLimits"); - var subscription = await GetCurrent(); if (subscription == null) { - if (defaultLimits != null) - { - var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier); - - if (foundDefault != null) - return foundDefault; - } - return new() { Identifier = identifier, Amount = 0 }; } - else + + var subscriptionLimits = + JsonConvert.DeserializeObject(subscription.LimitsJson) + ?? Array.Empty(); + + var foundLimit = subscriptionLimits.FirstOrDefault(x => x.Identifier == identifier); + + if (foundLimit != null) + return foundLimit; + + return new() { - var subscriptionLimits = - JsonConvert.DeserializeObject(subscription.LimitsJson) - ?? Array.Empty(); - - var foundLimit = subscriptionLimits.FirstOrDefault(x => x.Identifier == identifier); - - if (foundLimit != null) - return foundLimit; - - if (defaultLimits != null) - { - var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier); - - if (foundDefault != null) - return foundDefault; - } - - return new() - { - Identifier = identifier, - Amount = 0 - }; - } + Identifier = identifier, + Amount = 0 + }; } private async Task GetCurrentUser() diff --git a/Moonlight/Shared/Views/Admin/Subscriptions/Index.razor b/Moonlight/Shared/Views/Admin/Subscriptions/Index.razor index 83c20654..e7182f6a 100644 --- a/Moonlight/Shared/Views/Admin/Subscriptions/Index.razor +++ b/Moonlight/Shared/Views/Admin/Subscriptions/Index.razor @@ -3,10 +3,15 @@ @using Moonlight.App.Database.Entities @using Moonlight.App.Repositories @using BlazorTable +@using Moonlight.App.Services.Interop @inject SmartTranslateService SmartTranslateService @inject SubscriptionRepository SubscriptionRepository +@inject SubscriptionAdminService SubscriptionAdminService +@inject AlertService AlertService +@inject ClipboardService ClipboardService +
@@ -36,9 +41,16 @@ - + @@ -66,7 +78,24 @@ private async Task Delete(Subscription subscription) { SubscriptionRepository.Delete(subscription); - + await LazyLoader.Reload(); } + + private async Task GenerateCode(Subscription subscription) + { + var durationText = await AlertService.Text( + SmartTranslateService.Translate("Duration"), + SmartTranslateService.Translate("Enter duration of subscription"), + "30" + ); + + if (int.TryParse(durationText, out int duration)) + { + var code = await SubscriptionAdminService.GenerateCode(subscription, duration); + + await ClipboardService.Copy(code); + await AlertService.Success(SmartTranslateService.Translate("Copied code to clipboard")); + } + } } \ No newline at end of file diff --git a/Moonlight/Shared/Views/Profile/Subscriptions.razor b/Moonlight/Shared/Views/Profile/Subscriptions.razor new file mode 100644 index 00000000..c8382775 --- /dev/null +++ b/Moonlight/Shared/Views/Profile/Subscriptions.razor @@ -0,0 +1,112 @@ +@page "/profile/subscriptions" + +@using Moonlight.Shared.Components.Navigations +@using Moonlight.App.Services +@using Moonlight.App.Database.Entities +@using Moonlight.App.Helpers +@using Moonlight.App.Services.Interop + +@inject ConfigService ConfigService +@inject AlertService AlertService +@inject SubscriptionService SubscriptionService +@inject SmartTranslateService SmartTranslateService + + + +
+
+
+ Subscription +
+
+
+ + @if (Subscription == null) + { + var config = ConfigService + .GetSection("Moonlight") + .GetSection("Subscriptions") + .GetSection("Sellpass"); + + var enableSellpass = config.GetValue("Enable"); + var url = config.GetValue("Url"); + +

+
+ + + +
+

+ + if (enableSellpass) + { + + } + } + else + { + var d = User.SubscriptionSince.AddDays(User.SubscriptionDuration).ToUniversalTime(); + +

+ Active until @(Formatter.FormatDateOnly(d)) +

+

+ Current subscription: @(Subscription.Name) +

+

+ @(Subscription.Description) +

+

+ We will send you a notification upon subscription expiration +

+
+ + +
+ } +
+
+
+
+
+ +@code +{ + [CascadingParameter] + public User User { get; set; } + + private Subscription? Subscription; + private LazyLoader LazyLoader; + + private string Code = ""; + + private async Task Load(LazyLoader arg) + { + Subscription = await SubscriptionService.GetCurrent(); + } + + private async Task Cancel() + { + if (await AlertService.ConfirmMath()) + { + await SubscriptionService.Cancel(); + await LazyLoader.Reload(); + } + } + + private async Task OnSubmit() + { + await SubscriptionService.ApplyCode(Code); + Code = ""; + await LazyLoader.Reload(); + } +} \ No newline at end of file diff --git a/Moonlight/Shared/Views/Servers/New.razor b/Moonlight/Shared/Views/Servers/Create.razor similarity index 78% rename from Moonlight/Shared/Views/Servers/New.razor rename to Moonlight/Shared/Views/Servers/Create.razor index 5fb01f0e..85ec9d91 100644 --- a/Moonlight/Shared/Views/Servers/New.razor +++ b/Moonlight/Shared/Views/Servers/Create.razor @@ -1,14 +1,20 @@ -@page "/servers/new" +@page "/servers/create" @using Moonlight.App.Services @using Moonlight.App.Database.Entities @using Moonlight.App.Models.Forms @using Moonlight.App.Models.Misc @using Moonlight.App.Repositories +@using Moonlight.App.Repositories.Servers +@using Microsoft.EntityFrameworkCore +@using Moonlight.App.Exceptions @inject SubscriptionService SubscriptionService @inject ImageRepository ImageRepository @inject SmartTranslateService SmartTranslateService @inject SmartDeployService SmartDeployService +@inject ServerRepository ServerRepository +@inject NavigationManager NavigationManager +@inject ServerService ServerService @if (DeployNode == null) @@ -133,6 +139,9 @@ @code { + [CascadingParameter] + public User User { get; set; } + private Node? DeployNode; private Subscription? Subscription; @@ -163,12 +172,55 @@ if (limit.Amount > 0) { - Images.Add(image, limit); + var serversCount = ServerRepository + .Get() + .Include(x => x.Owner) + .Include(x => x.Image) + .Where(x => x.Owner.Id == User.Id) + .Count(x => x.Image.Id == image.Id); + + if(serversCount < limit.Amount) + Images.Add(image, limit); } } } private async Task OnValidSubmit() { + var limit = await SubscriptionService.GetLimit("image." + Model.Image.Id); + + if (limit.Amount > 0) + { + var serversCount = ServerRepository + .Get() + .Include(x => x.Owner) + .Include(x => x.Image) + .Where(x => x.Owner.Id == User.Id) + .Count(x => x.Image.Id == Model.Image.Id); + + if (serversCount < limit.Amount) + { + if(int.TryParse(limit.ReadValue("cpu"), out int cpu) && + int.TryParse(limit.ReadValue("memory"), out int memory) && + int.TryParse(limit.ReadValue("disk"), out int disk)) + { + var server = await ServerService.Create( + Model.Name, + cpu, + memory, + disk, + User, + Model.Image, + DeployNode + ); + + NavigationManager.NavigateTo($"/server/{server.Uuid}"); + } + else + { + throw new DisplayException("Limits cannot be parsed"); + } + } + } } } \ No newline at end of file diff --git a/Moonlight/resources/lang/de_de.lang b/Moonlight/resources/lang/de_de.lang index bcb775a2..23a0c02f 100644 --- a/Moonlight/resources/lang/de_de.lang +++ b/Moonlight/resources/lang/de_de.lang @@ -475,3 +475,19 @@ No node found;No node found No node found to deploy to found;No node found to deploy to found You need to specify a server image;You need to specify a server image CPU;CPU +Compress;Compress +Decompress;Decompress +Cleanup exception;Cleanup exception +Error creating server on wings;Error creating server on wings +Enter code;Enter code +Create code;Create code +Duration;Duration +Enter duration of subscription;Enter duration of subscription +Copied code to clipboard;Copied code to clipboard +Current subscription;Current subscription +7 + 7 =;7 + 7 = +1 + 8 =;1 + 8 = +8 + 4 =;8 + 4 = +8 + 1 =;8 + 1 = +1 + 1 =;1 + 1 = +6 + 6 =;6 + 6 = diff --git a/Moonlight/wwwroot/assets/media/svg/subscription.svg b/Moonlight/wwwroot/assets/media/svg/subscription.svg new file mode 100644 index 00000000..6022690d --- /dev/null +++ b/Moonlight/wwwroot/assets/media/svg/subscription.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 52bd991a72a72fcbb9342685a509879a16d2bff7 Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Tue, 4 Apr 2023 01:24:15 +0200 Subject: [PATCH 4/4] Update AlertService.cs --- Moonlight/App/Services/Interop/AlertService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moonlight/App/Services/Interop/AlertService.cs b/Moonlight/App/Services/Interop/AlertService.cs index 7e6bcb25..24a15fa4 100644 --- a/Moonlight/App/Services/Interop/AlertService.cs +++ b/Moonlight/App/Services/Interop/AlertService.cs @@ -110,7 +110,7 @@ public class AlertService var input = await Text( SmartTranslateService.Translate("Confirm"), - SmartTranslateService.Translate($"{i1} + {i2} ="), + $"{i1} + {i2} =", "" );