diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor index 700978fc..d5be70fa 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor @@ -10,61 +10,106 @@
-
+
+
+ + +
+
+ + +
+
+
+
+
- + Product
- - @if (_packages != null) - { - if (_packages.Count > 0) - { - - - -

@context.Name

  by:  @context.Owner
- @(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)
- @(String.Format("{0:n0}", context.Downloads)) @SharedLocalizer["Search.Downloads"]  |   - @SharedLocalizer["Search.Released"]: @context.ReleaseDate.ToString("MMM dd, yyyy")  |   - @SharedLocalizer["Search.Version"]: @context.Version - @((MarkupString)(!string.IsNullOrEmpty(context.PackageUrl) ? "  |  " + SharedLocalizer["Search.Source"] + ": " + new Uri(context.PackageUrl).Host + "" : "")) - @((MarkupString)(context.TrialPeriod > 0 ? "  |  " + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "" : "")) - - - @if (context.Price != null && !string.IsNullOrEmpty(context.PackageUrl)) - { - - } - - - @if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl)) - { - @context.Price.Value.ToString("$#,##0.00") - } - else - { - - } - -
-
- } - else - { -
-
- @Localizer["Search.NoResults"] -
- } - } +
+
+ @if (_initialized) + { +
+
+
+

@((_packages != null) ? _packages.Count : 0) @SharedLocalizer["Search.Results"]

+
+
+   +
+
+ +
+
+ + +
+
+
+
+ @if (context.LogoFileId != null) + { + @context.Name + } + else + { + @context.Name + } +
+
+ @SharedLocalizer["Search.Version"]: @context.Version +
@SharedLocalizer["Search.Downloads"]: @(String.Format("{0:n0}", context.Downloads)) +
@SharedLocalizer["Search.Released"]: @context.ReleaseDate.ToString("MM/dd/yyyy") + @if (!string.IsNullOrEmpty(context.PackageUrl)) + { +
@SharedLocalizer["Search.Source"]: @(new Uri(context.PackageUrl).Host) + } +
+
+
+
+

@context.Name


+ @SharedLocalizer["Search.By"]: @context.Owner
+ @(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)
+ @if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl)) + { + @SharedLocalizer["Search.Price"]: @context.Price.Value.ToString("$#,##0.00") + @((MarkupString)(context.TrialPeriod > 0 ? " (" + context.TrialPeriod + " Day Trial)" : "")) + } +
+ @if (!string.IsNullOrEmpty(context.PackageUrl)) + { + + } + @if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl)) + { + @SharedLocalizer["Buy"] + } +
+
+
+
+
+
+
+ } +
+

@@ -116,8 +161,10 @@ @SharedLocalizer["Cancel"] @code { + private bool _initialized = false; private List _packages; private string _price = "free"; + private string _sort = "popularity"; private string _search = ""; private string _productname = ""; private string _packageid = ""; @@ -131,6 +178,7 @@ try { await LoadModuleDefinitions(); + _initialized = true; } catch (Exception ex) { @@ -141,8 +189,10 @@ private async Task LoadModuleDefinitions() { + ShowProgressIndicator(); + var moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId); - _packages = await PackageService.GetPackagesAsync("module", _search, _price, ""); + _packages = await PackageService.GetPackagesAsync("module", _search, _price, "", _sort); if (_packages != null) { @@ -154,21 +204,22 @@ } } } + + HideProgressIndicator(); } - private async void PriceChanged(ChangeEventArgs e) + private string GetLogo(int fileid) { - try - { - _price = (string)e.Value; - _search = ""; - await LoadModuleDefinitions(); - StateHasChanged(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error On PriceChanged"); - } + var url = ImageUrl(fileid, 100, 100); + url = (!string.IsNullOrEmpty(PageState.Alias.Path)) ? url.Substring(PageState.Alias.Path.Length + 1) : url; + return Constants.PackageRegistryUrl + url; + } + + private async void PriceChanged(string price) + { + _price = price; + await LoadModuleDefinitions(); + StateHasChanged(); } private async Task Search() @@ -196,6 +247,12 @@ } } + private async void SortChanged(ChangeEventArgs e) + { + _sort = (string)e.Value; + await LoadModuleDefinitions(); + } + private void HideModal() { _productname = ""; diff --git a/Oqtane.Client/Modules/Admin/Themes/Add.razor b/Oqtane.Client/Modules/Admin/Themes/Add.razor index 7c4bd170..df48d6a0 100644 --- a/Oqtane.Client/Modules/Admin/Themes/Add.razor +++ b/Oqtane.Client/Modules/Admin/Themes/Add.razor @@ -10,61 +10,108 @@
-
+
+
+ + +
+
+ + +
+
+
+
+
- + Product
+
+
+ @if (_initialized) + { +
+
+
+

@((_packages != null) ? _packages.Count : 0) @SharedLocalizer["Search.Results"]

+
+
+   +
+
+ +
+
+ + +
+
+
+
+ @if (context.LogoFileId != null) + { + @context.Name + } + else + { + @context.Name + } +
+
+ @SharedLocalizer["Search.Version"]: @context.Version +
@SharedLocalizer["Search.Downloads"]: @(String.Format("{0:n0}", context.Downloads)) +
@SharedLocalizer["Search.Released"]: @context.ReleaseDate.ToString("MM/dd/yyyy") + @if (!string.IsNullOrEmpty(context.PackageUrl)) + { +
- @if (_packages != null) - { - if (_packages.Count > 0) - { - - - -

@context.Name

  @SharedLocalizer["Search.By"]:  @context.Owner
- @(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)
- @(String.Format("{0:n0}", context.Downloads)) @SharedLocalizer["Search.Downloads"]  |   - @SharedLocalizer["Search.Released"]: @context.ReleaseDate.ToString("MMM dd, yyyy")  |   - @SharedLocalizer["Search.Version"]: @context.Version - @((MarkupString)(!string.IsNullOrEmpty(context.PackageUrl) ? "  |  " + SharedLocalizer["Search.Source"] + ": " + new Uri(context.PackageUrl).Host + "" : "")) - @((MarkupString)(context.TrialPeriod > 0 ? "  |  " + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "" : "")) - - - @if (context.Price != null && !string.IsNullOrEmpty(context.PackageUrl)) - { - - } - - - @if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl)) - { - @context.Price.Value.ToString("$#,##0.00") - } - else - { - - } - -
-
- } - else - { -
-
- @Localizer["Search.NoResults"] -
- } - } + @SharedLocalizer["Search.Source"]: @(new Uri(context.PackageUrl).Host) + } +
+
+
+
+

@context.Name


+ @SharedLocalizer["Search.By"]: @context.Owner
+ @(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)
+ @if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl)) + { + @SharedLocalizer["Search.Price"]: @context.Price.Value.ToString("$#,##0.00") + @((MarkupString)(context.TrialPeriod > 0 ? " (" + context.TrialPeriod + " Day Trial)" : "")) + } +
+ @if (!string.IsNullOrEmpty(context.PackageUrl)) + { + + } + @if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl)) + { + @SharedLocalizer["Buy"] + } +
+
+
+
+
+
+
+ } +
+

@@ -116,8 +163,10 @@ @SharedLocalizer["Cancel"] @code { + private bool _initialized = false; private List _packages; private string _price = "free"; + private string _sort = "popularity"; private string _search = ""; private string _productname = ""; private string _license = ""; @@ -131,6 +180,7 @@ try { await LoadThemes(); + _initialized = true; } catch (Exception ex) { @@ -141,8 +191,10 @@ private async Task LoadThemes() { + ShowProgressIndicator(); + var themes = await ThemeService.GetThemesAsync(); - _packages = await PackageService.GetPackagesAsync("theme", _search, _price, ""); + _packages = await PackageService.GetPackagesAsync("theme", _search, _price, "", _sort); if (_packages != null) { @@ -154,21 +206,22 @@ } } } + + HideProgressIndicator(); } - private async void PriceChanged(ChangeEventArgs e) + private string GetLogo(int fileid) { - try - { - _price = (string)e.Value; - _search = ""; - await LoadThemes(); - StateHasChanged(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error On PriceChanged"); - } + var url = ImageUrl(fileid, 100, 100); + url = (!string.IsNullOrEmpty(PageState.Alias.Path)) ? url.Substring(PageState.Alias.Path.Length + 1) : url; + return Constants.PackageRegistryUrl + url; + } + + private async void PriceChanged(string price) + { + _price = price; + await LoadThemes(); + StateHasChanged(); } private async Task Search() @@ -196,6 +249,12 @@ } } + private async void SortChanged(ChangeEventArgs e) + { + _sort = (string)e.Value; + await LoadThemes(); + } + private void HideModal() { _productname = ""; diff --git a/Oqtane.Client/Resources/Modules/Admin/ModuleDefinitions/Add.resx b/Oqtane.Client/Resources/Modules/Admin/ModuleDefinitions/Add.resx index 9db1c83a..4d6bd593 100644 --- a/Oqtane.Client/Resources/Modules/Admin/ModuleDefinitions/Add.resx +++ b/Oqtane.Client/Resources/Modules/Admin/ModuleDefinitions/Add.resx @@ -136,7 +136,7 @@ No Modules Match The Criteria Provided Or Package Service Is Disabled - Download + Marketplace Upload diff --git a/Oqtane.Client/Resources/Modules/Admin/Themes/Add.resx b/Oqtane.Client/Resources/Modules/Admin/Themes/Add.resx index b7a18332..9ceeae29 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Themes/Add.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Themes/Add.resx @@ -135,4 +135,10 @@ No Themes Match The Criteria Provided Or Package Service Is Disabled + + Marketplace + + + Upload + \ No newline at end of file diff --git a/Oqtane.Client/Resources/SharedResources.resx b/Oqtane.Client/Resources/SharedResources.resx index 89823584..d02dfa0a 100644 --- a/Oqtane.Client/Resources/SharedResources.resx +++ b/Oqtane.Client/Resources/SharedResources.resx @@ -223,13 +223,13 @@ by - downloads + Downloads - released + Released - version + Version Edit @@ -277,19 +277,19 @@ Installed Version - source + Source Please Provide All Required Information - Free + Open Source - Paid + Commercial - price + Price Accept @@ -390,4 +390,16 @@ Support + + Alphabetical + + + Buy Now + + + Popularity + + + Results + \ No newline at end of file diff --git a/Oqtane.Client/Services/AliasService.cs b/Oqtane.Client/Services/AliasService.cs index c2e59799..714f1061 100644 --- a/Oqtane.Client/Services/AliasService.cs +++ b/Oqtane.Client/Services/AliasService.cs @@ -22,7 +22,7 @@ namespace Oqtane.Services /// public async Task> GetAliasesAsync() { - List aliases = await GetJsonAsync>(ApiUrl); + List aliases = await GetJsonAsync>(ApiUrl, Enumerable.Empty().ToList()); return aliases.OrderBy(item => item.Name).ToList(); } diff --git a/Oqtane.Client/Services/ServiceBase.cs b/Oqtane.Client/Services/ServiceBase.cs index fb81b65b..d5a65dea 100644 --- a/Oqtane.Client/Services/ServiceBase.cs +++ b/Oqtane.Client/Services/ServiceBase.cs @@ -145,10 +145,19 @@ namespace Oqtane.Services { return await response.Content.ReadFromJsonAsync(); } - return default; } + protected async Task GetJsonAsync(string uri, T defaultResult) + { + var response = await GetHttpClient().GetAsync(uri, HttpCompletionOption.ResponseHeadersRead, CancellationToken.None); + if (await CheckResponse(response, uri) && ValidateJsonContent(response.Content)) + { + return await response.Content.ReadFromJsonAsync(); + } + return defaultResult; + } + protected async Task PutAsync(string uri) { var response = await GetHttpClient().PutAsync(uri, null); diff --git a/Oqtane.Client/UI/ThemeBuilder.razor b/Oqtane.Client/UI/ThemeBuilder.razor index ebe824ab..cae90f09 100644 --- a/Oqtane.Client/UI/ThemeBuilder.razor +++ b/Oqtane.Client/UI/ThemeBuilder.razor @@ -70,7 +70,7 @@ var elements = (">" + content.Replace("\n", "") + "<").Split("><"); foreach (var element in elements) { - if (!string.IsNullOrEmpty(element) && !element.Contains("script")) + if (!string.IsNullOrEmpty(element) && !element.ToLower().StartsWith("script")) { if (!headcontent.Contains("<" + element + ">")) { diff --git a/Oqtane.Package/release.cmd b/Oqtane.Package/release.cmd index c3e281c9..299aa439 100644 --- a/Oqtane.Package/release.cmd +++ b/Oqtane.Package/release.cmd @@ -14,7 +14,7 @@ dotnet publish ..\Oqtane.Server\Oqtane.Server.csproj /p:Configuration=Release del /F/Q/S "..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Content" > NUL rmdir /Q/S "..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Content" setlocal ENABLEDELAYEDEXPANSION -set retain=Oqtane.Modules.Admin.Login,Oqtane.Modules.HtmlText,Templates +set retain=Oqtane.Modules.Admin.Login,Oqtane.Modules.HtmlText for /D %%i in ("..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Modules\*") do ( set /A found=0 for %%j in (%retain%) do ( @@ -22,7 +22,7 @@ if "%%~nxi" == "%%j" set /A found=1 ) if not !found! == 1 rmdir /Q/S "%%i" ) -set retain=Oqtane.Themes.BlazorTheme,Oqtane.Themes.OqtaneTheme,Templates +set retain=Oqtane.Themes.BlazorTheme,Oqtane.Themes.OqtaneTheme for /D %%i in ("..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Themes\*") do ( set /A found=0 for %%j in (%retain%) do ( diff --git a/Oqtane.Server/Controllers/FileController.cs b/Oqtane.Server/Controllers/FileController.cs index 31ed3c80..636803b1 100644 --- a/Oqtane.Server/Controllers/FileController.cs +++ b/Oqtane.Server/Controllers/FileController.cs @@ -572,7 +572,7 @@ namespace Oqtane.Controllers // validation if (!Enum.TryParse(mode, true, out ResizeMode _)) mode = "crop"; if (!Enum.TryParse(position, true, out AnchorPositionMode _)) position = "center"; - if (!Color.TryParseHex("#" + background, out _)) background = "000000"; + if (!Color.TryParseHex("#" + background, out _)) background = "transparent"; if (!int.TryParse(rotate, out _)) rotate = "0"; rotate = (int.Parse(rotate) < 0 || int.Parse(rotate) > 360) ? "0" : rotate; if (!bool.TryParse(recreate, out _)) recreate = "false"; @@ -644,10 +644,23 @@ namespace Oqtane.Controllers Mode = resizemode, Position = anchorpositionmode, Size = new Size(width, height) - }) - .BackgroundColor(Color.ParseHex("#" + background))); + })); - image.Save(imagepath, new PngEncoder()); + if (background != "transparent") + { + image.Mutate(x => x + .BackgroundColor(Color.ParseHex("#" + background))); + } + + PngEncoder encoder = new PngEncoder + { + ColorType = PngColorType.RgbWithAlpha, + TransparentColorMode = PngTransparentColorMode.Preserve, + BitDepth = PngBitDepth.Bit8, + CompressionLevel = PngCompressionLevel.BestSpeed + }; + + image.Save(imagepath, encoder); } } } @@ -677,7 +690,14 @@ namespace Oqtane.Controllers path = Utilities.PathCombine(path, folder, Path.DirectorySeparatorChar.ToString()); if (!Directory.Exists(path)) { - Directory.CreateDirectory(path); + try + { + Directory.CreateDirectory(path); + } + catch (Exception ex) + { + _logger.Log(LogLevel.Error, this, LogFunction.Create, ex, "Unable To Create Folder {Folder}", path); + } } } } diff --git a/Oqtane.Server/Controllers/FolderController.cs b/Oqtane.Server/Controllers/FolderController.cs index 31121b60..24d252a7 100644 --- a/Oqtane.Server/Controllers/FolderController.cs +++ b/Oqtane.Server/Controllers/FolderController.cs @@ -88,6 +88,7 @@ namespace Oqtane.Controllers public Folder GetByPath(int siteId, string path) { var folderPath = WebUtility.UrlDecode(path).Replace("\\", "/"); + folderPath = (folderPath == "/") ? "" : folderPath; if (!folderPath.EndsWith("/") && folderPath != "") { folderPath += "/"; diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index 21379582..95380bef 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -283,23 +283,26 @@ namespace Oqtane.Controllers var templates = new List