Merge pull request #1606 from sbwalker/dev
add support for free/paid in module, theme, translation installation
This commit is contained in:
		| @ -53,13 +53,16 @@ else | ||||
|         </TabPanel> | ||||
|         <TabPanel Name="Download" ResourceKey="Download" Security="SecurityAccessLevel.Host"> | ||||
|             <ModuleMessage Type="MessageType.Info" Message="Download one or more translations from the list below. Once you are ready click Install to complete the installation."></ModuleMessage> | ||||
|             <div class="container"> | ||||
|                 <div class="row mb-1 align-items-center"> | ||||
|                     <div class="col-sm-9"> | ||||
|  | ||||
|             <div class="row justify-content-center mb-3"> | ||||
|                 <div class="col-sm-6"> | ||||
|                     <div class="input-group"> | ||||
|                         <select id="price" class="form-select custom-select" @onchange="(e => PriceChanged(e))"> | ||||
|                             <option value="free">@SharedLocalizer["Free"]</option> | ||||
|                             <option value="paid">@SharedLocalizer["Paid"]</option> | ||||
|                         </select> | ||||
|                         <input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" /> | ||||
|                     </div> | ||||
|                     <div class="col-sm-3"> | ||||
|                         <button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>  | ||||
|                         <button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button> | ||||
|                         <button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button> | ||||
|                     </div> | ||||
|                 </div> | ||||
| @ -77,7 +80,7 @@ else | ||||
|                                 <strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"]  |   @SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong>  |  @SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>  |  @SharedLocalizer["Search.Source"]: <strong>@context.PackageUrl</strong> | ||||
|                             </td> | ||||
|                             <td style="vertical-align: middle;"> | ||||
|                                 <button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadLanguage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button> | ||||
|                                 <button type="button" class="btn btn-primary" @onclick=@(async () => await GetLanguage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button> | ||||
|                             </td> | ||||
|                         </Row> | ||||
|                     </Pager> | ||||
| @ -108,6 +111,38 @@ else | ||||
|     </TabStrip> | ||||
| } | ||||
|  | ||||
| @if (_productname != "") | ||||
| { | ||||
|     <div class="app-actiondialog"> | ||||
|         <div class="modal" tabindex="-1" role="dialog"> | ||||
|             <div class="modal-dialog"> | ||||
|                 <div class="modal-content"> | ||||
|                     <div class="modal-header"> | ||||
|                         <h5 class="modal-title">@_productname  @Localizer["License Terms"]</h5> | ||||
|                         <button type="button" class="btn-close" aria-label="Close" @onclick="HideModal"></button> | ||||
|                     </div> | ||||
|                     <div class="modal-body"> | ||||
|                         <p style="height: 200px; overflow-y: scroll;"> | ||||
|                             @if (!string.IsNullOrEmpty(_license)) | ||||
|                             { | ||||
|                                 @((MarkupString)_license) | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 @Localizer["License Not Specified"] | ||||
|                             } | ||||
|                         </p> | ||||
|                     </div> | ||||
|                     <div class="modal-footer"> | ||||
|                         <button type="button" class="btn btn-success" @onclick="DownloadPackage">@Localizer["Accept"]</button> | ||||
|                         <button type="button" class="btn btn-secondary" @onclick="HideModal">@Localizer["Cancel"]</button> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| } | ||||
|  | ||||
| @code { | ||||
|     private ElementReference form; | ||||
|     private bool validated = false; | ||||
| @ -118,7 +153,12 @@ else | ||||
|     private IEnumerable<Culture> _supportedCultures; | ||||
|     private IEnumerable<Culture> _availableCultures; | ||||
|     private List<Package> _packages; | ||||
|     private string _price = "free"; | ||||
|     private string _search = ""; | ||||
|     private string _productname = ""; | ||||
|     private string _license = ""; | ||||
|     private string _packageid = ""; | ||||
|     private string _version = ""; | ||||
|  | ||||
|     public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; | ||||
|  | ||||
| @ -144,9 +184,24 @@ else | ||||
|  | ||||
|     private async Task LoadTranslations() | ||||
|     { | ||||
|         _packages = await PackageService.GetPackagesAsync("translation", _search); | ||||
|         _packages = await PackageService.GetPackagesAsync("translation", _search, _price); | ||||
|     } | ||||
|  | ||||
|     private async void PriceChanged(ChangeEventArgs e) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             _price = (string)e.Value; | ||||
|             _search = ""; | ||||
|             await LoadTranslations(); | ||||
|             StateHasChanged(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             await logger.LogError(ex, "Error On PriceChanged"); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     private async Task Search() | ||||
|     { | ||||
|         try | ||||
| @ -211,6 +266,51 @@ else | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     private void HideModal() | ||||
|     { | ||||
|         _productname = ""; | ||||
|         _license = ""; | ||||
|         StateHasChanged(); | ||||
|     } | ||||
|  | ||||
|     private async Task GetLanguage(string packageid, string version) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var package = await PackageService.GetPackageAsync(packageid, version); | ||||
|             if (package != null) | ||||
|             { | ||||
|                 _productname = package.Name; | ||||
|                 _license = package.License.Replace("\n", "<br />"); | ||||
|                 _packageid = package.PackageId; | ||||
|                 _version = package.Version; | ||||
|             } | ||||
|             StateHasChanged(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", packageid, version); | ||||
|             AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task DownloadPackage() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await PackageService.DownloadPackageAsync(_packageid, _version, "Packages"); | ||||
|             await logger.LogInformation("Language Package {Name} {Version} Downloaded Successfully", _packageid, _version); | ||||
|             AddModuleMessage(Localizer["Success.Language.Download"], MessageType.Success); | ||||
|             StateHasChanged(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             await logger.LogError(ex, "Error Downloading Translation {Name} {Version}", _packageid, _version); | ||||
|             AddModuleMessage(Localizer["Error.Language.Download"], MessageType.Error); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task InstallLanguages() | ||||
|     { | ||||
|         try | ||||
| @ -224,22 +324,6 @@ else | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task DownloadLanguage(string packageid, string version) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await PackageService.DownloadPackageAsync(packageid, version, "Packages"); | ||||
|             await logger.LogInformation("Language Paclage {Name} {Version} Downloaded Successfully", packageid, version); | ||||
|             AddModuleMessage(Localizer["Success.Language.Download"], MessageType.Success); | ||||
|             StateHasChanged(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             await logger.LogError(ex, "Error Downloading Translation {Name} {Version}", packageid, version); | ||||
|             AddModuleMessage(Localizer["Error.Language.Download"], MessageType.Error); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task SetCultureAsync(string culture) | ||||
|     { | ||||
|         if (culture != CultureInfo.CurrentUICulture.Name) | ||||
|  | ||||
| @ -14,6 +14,10 @@ | ||||
|         <div class="row justify-content-center mb-3"> | ||||
|             <div class="col-sm-6"> | ||||
|                 <div class="input-group"> | ||||
|                     <select id="price" class="form-select custom-select" @onchange="(e => PriceChanged(e))"> | ||||
|                         <option value="free">@SharedLocalizer["Free"]</option> | ||||
|                         <option value="paid">@SharedLocalizer["Paid"]</option> | ||||
|                     </select> | ||||
|                     <input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" /> | ||||
|                     <button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button> | ||||
|                     <button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button> | ||||
| @ -30,7 +34,11 @@ | ||||
|                         <td> | ||||
|                             <h3 style="display: inline;"><a href="@context.ProductUrl" target="_new">@context.Name</a></h3>  by:  <strong><a href="@context.OwnerUrl" target="new">@context.Owner</a></strong><br /> | ||||
|                             @(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)<br /> | ||||
|                             <strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"]  |   @SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong>  |  @SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>  |  @SharedLocalizer["Search.Source"]: <strong>@context.PackageUrl</strong> | ||||
|                             <strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"]  |   | ||||
|                             @SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong>  |   | ||||
|                             @SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>  |   | ||||
|                             @SharedLocalizer["Search.Source"]: <strong>@context.PackageUrl</strong>  |   | ||||
|                             @SharedLocalizer["Search.Price"]: <strong>@((context.Price == 0) ? "FREE" : context.Price.ToString("$#,##0.00") )</strong> | ||||
|                         </td> | ||||
|                         <td style="vertical-align: middle;"> | ||||
|                             <button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button> | ||||
| @ -96,6 +104,7 @@ | ||||
|  | ||||
| @code { | ||||
|     private List<Package> _packages; | ||||
|     private string _price = "free"; | ||||
|     private string _search = ""; | ||||
|     private string _productname = ""; | ||||
|     private string _license = ""; | ||||
| @ -120,7 +129,7 @@ | ||||
|     private async Task LoadModuleDefinitions() | ||||
|     { | ||||
|         var moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId); | ||||
|         _packages = await PackageService.GetPackagesAsync("module", _search); | ||||
|         _packages = await PackageService.GetPackagesAsync("module", _search, _price); | ||||
|  | ||||
|         if (_packages != null) | ||||
|         { | ||||
| @ -134,6 +143,21 @@ | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async void PriceChanged(ChangeEventArgs e) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             _price = (string)e.Value; | ||||
|             _search = ""; | ||||
|             await LoadModuleDefinitions(); | ||||
|             StateHasChanged(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             await logger.LogError(ex, "Error On PriceChanged"); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     private async Task Search() | ||||
|     { | ||||
|         try | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
| <form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate> | ||||
|     <div class="container"> | ||||
|         <div class="row mb-1 align-items-center"> | ||||
|             <Label Class="col-sm-3" For="content" HelpText="Enter the module content" ResourceKey="Content">Content: </Label> | ||||
|             <Label Class="col-sm-3" For="content" HelpText="Enter The Module Content To Import" ResourceKey="Content">Content: </Label> | ||||
|             <div class="col-sm-9"> | ||||
|                 <textarea id="content" class="form-control" @bind="@_content" rows="5" required></textarea> | ||||
|  | ||||
|  | ||||
| @ -14,6 +14,10 @@ | ||||
|         <div class="row justify-content-center mb-3"> | ||||
|             <div class="col-sm-6"> | ||||
|                 <div class="input-group"> | ||||
|                     <select id="price" class="form-select custom-select" @onchange="(e => PriceChanged(e))"> | ||||
|                         <option value="free">@SharedLocalizer["Free"]</option> | ||||
|                         <option value="paid">@SharedLocalizer["Paid"]</option> | ||||
|                     </select> | ||||
|                     <input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" /> | ||||
|                     <button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button> | ||||
|                     <button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button> | ||||
| @ -97,6 +101,7 @@ | ||||
|  | ||||
| @code { | ||||
|     private List<Package> _packages; | ||||
|     private string _price = "free"; | ||||
|     private string _search = ""; | ||||
|     private string _productname = ""; | ||||
|     private string _license = ""; | ||||
| @ -121,7 +126,7 @@ | ||||
|     private async Task LoadThemes() | ||||
|     { | ||||
|         var themes = await ThemeService.GetThemesAsync(); | ||||
|         _packages = await PackageService.GetPackagesAsync("theme", _search); | ||||
|         _packages = await PackageService.GetPackagesAsync("theme", _search, _price); | ||||
|  | ||||
|         if (_packages != null) | ||||
|         { | ||||
| @ -135,6 +140,21 @@ | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async void PriceChanged(ChangeEventArgs e) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             _price = (string)e.Value; | ||||
|             _search = ""; | ||||
|             await LoadThemes(); | ||||
|             StateHasChanged(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             await logger.LogError(ex, "Error On PriceChanged"); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     private async Task Search() | ||||
|     { | ||||
|         try | ||||
|  | ||||
| @ -282,4 +282,13 @@ | ||||
|   <data name="Message.InfoRequired" xml:space="preserve"> | ||||
|     <value>Please Provide All Required Information</value> | ||||
|   </data> | ||||
|   <data name="Free" xml:space="preserve"> | ||||
|     <value>Free</value> | ||||
|   </data> | ||||
|   <data name="Paid" xml:space="preserve"> | ||||
|     <value>Paid</value> | ||||
|   </data> | ||||
|   <data name="Search.Price" xml:space="preserve"> | ||||
|     <value>price</value> | ||||
|   </data> | ||||
| </root> | ||||
| @ -7,7 +7,7 @@ namespace Oqtane.Services | ||||
|     public interface IPackageService | ||||
|     { | ||||
|         Task<List<Package>> GetPackagesAsync(string type); | ||||
|         Task<List<Package>> GetPackagesAsync(string type, string search); | ||||
|         Task<List<Package>> GetPackagesAsync(string type, string search, string price); | ||||
|         Task<Package> GetPackageAsync(string packageId, string version); | ||||
|         Task DownloadPackageAsync(string packageId, string version, string folder); | ||||
|         Task InstallPackagesAsync(); | ||||
|  | ||||
| @ -22,12 +22,12 @@ namespace Oqtane.Services | ||||
|  | ||||
|         public async Task<List<Package>> GetPackagesAsync(string type) | ||||
|         { | ||||
|             return await GetPackagesAsync(type, ""); | ||||
|             return await GetPackagesAsync(type, "", ""); | ||||
|         } | ||||
|  | ||||
|         public async Task<List<Package>> GetPackagesAsync(string type, string search) | ||||
|         public async Task<List<Package>> GetPackagesAsync(string type, string search, string price) | ||||
|         { | ||||
|             return await GetJsonAsync<List<Package>>($"{Apiurl}?type={type}&search={WebUtility.UrlEncode(search)}"); | ||||
|             return await GetJsonAsync<List<Package>>($"{Apiurl}?type={type}&search={WebUtility.UrlEncode(search)}&price={price}"); | ||||
|         } | ||||
|  | ||||
|         public async Task<Package> GetPackageAsync(string packageId, string version) | ||||
|  | ||||
| @ -32,10 +32,10 @@ namespace Oqtane.Controllers | ||||
|             _logger = logger; | ||||
|         } | ||||
|  | ||||
|         // GET: api/<controller>?type=x&search=y | ||||
|         // GET: api/<controller>?type=x&search=y&license=z | ||||
|         [HttpGet] | ||||
|         [Authorize(Roles = RoleNames.Host)] | ||||
|         public async Task<IEnumerable<Package>> Get(string type, string search) | ||||
|         public async Task<IEnumerable<Package>> Get(string type, string search, string price) | ||||
|         { | ||||
|             // get packages | ||||
|             List<Package> packages = new List<Package>(); | ||||
| @ -45,7 +45,7 @@ namespace Oqtane.Controllers | ||||
|                 { | ||||
|                     client.DefaultRequestHeaders.Add("Referer", HttpContext.Request.Scheme + "://" + HttpContext.Request.Host.Value); | ||||
|                     client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(Constants.PackageId, Constants.Version)); | ||||
|                     packages = await GetJson<List<Package>>(client, Constants.PackageRegistryUrl + $"/api/registry/packages/?id={_configManager.GetInstallationId()}&type={type.ToLower()}&version={Constants.Version}&search={search}"); | ||||
|                     packages = await GetJson<List<Package>>(client, Constants.PackageRegistryUrl + $"/api/registry/packages/?id={_configManager.GetInstallationId()}&type={type.ToLower()}&version={Constants.Version}&search={search}&price={price}"); | ||||
|                 } | ||||
|             } | ||||
|             return packages; | ||||
|  | ||||
| @ -66,5 +66,10 @@ namespace Oqtane.Models | ||||
|         /// Indicates if any known security vulnerabilities exist  | ||||
|         /// </summary> | ||||
|         public int Vulnerabilities { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// The price of the package  | ||||
|         /// </summary> | ||||
|         public decimal Price { get; set; } | ||||
|     } | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Shaun Walker
					Shaun Walker