Merge pull request #1318 from sbwalker/dev

Allow installation of Language packages through Language Management
This commit is contained in:
Shaun Walker 2021-05-05 18:59:46 -04:00 committed by GitHub
commit 6625fa7c23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 145 additions and 49 deletions

View File

@ -5,6 +5,7 @@
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject ILocalizationService LocalizationService @inject ILocalizationService LocalizationService
@inject ILanguageService LanguageService @inject ILanguageService LanguageService
@inject IPackageService PackageService
@inject IStringLocalizer<Add> Localizer @inject IStringLocalizer<Add> Localizer
@if (_supportedCultures == null) @if (_supportedCultures == null)
@ -13,42 +14,91 @@
} }
else else
{ {
@if (_supportedCultures?.Count() > 1) <TabStrip>
{ <TabPanel Name="Manage" ResourceKey="Manage">
<table class="table table-borderless"> @if (_supportedCultures?.Count() > 1)
<tr> {
<td> <table class="table table-borderless">
<Label For="name" HelpText="Name Of The Langauage" ResourceKey="Name">Name:</Label> <tr>
</td> <td>
<td> <Label For="name" HelpText="Name Of The Language" ResourceKey="Name">Name:</Label>
<select id="_code" class="form-control" @bind="@_code"> </td>
@foreach (var culture in _supportedCultures) <td>
{ <select id="_code" class="form-control" @bind="@_code">
<option value="@culture.Name">@culture.DisplayName</option> @foreach (var culture in _supportedCultures)
} {
</select> <option value="@culture.Name">@culture.DisplayName</option>
</td> }
</tr> </select>
<tr> </td>
<td> </tr>
<Label For="default" HelpText="Indicates Whether Or Not This Language Is The Default For The Site" ResourceKey="IsDefault">Default?</Label> <tr>
</td> <td>
<td> <Label For="default" HelpText="Indicates Whether Or Not This Language Is The Default For The Site" ResourceKey="IsDefault">Default?</Label>
<select id="default" class="form-control" @bind="@_isDefault"> </td>
<option value="True">@Localizer["Yes"]</option> <td>
<option value="False">@Localizer["No"]</option> <select id="default" class="form-control" @bind="@_isDefault">
</select> <option value="True">@Localizer["Yes"]</option>
</td> <option value="False">@Localizer["No"]</option>
</tr> </select>
</table> </td>
<button type="button" class="btn btn-success" @onclick="SaveLanguage">@Localizer["Save"]</button> </tr>
} </table>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink> <button type="button" class="btn btn-success" @onclick="SaveLanguage">@Localizer["Save"]</button>
}
else
{
<ModuleMessage Type="MessageType.Info" Message="The Only Installed Language Is English"></ModuleMessage>
}
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink>
</TabPanel>
<TabPanel Name="Download" ResourceKey="Download" Security="SecurityAccessLevel.Host">
@if (_packages != null && _packages.Count > 0)
{
<ModuleMessage Type="MessageType.Info" Message="Download one or more language packages from the list below. Once you are ready click Install to complete the installation."></ModuleMessage>
<Pager Items="@_packages">
<Header>
<th>@Localizer["Name"]</th>
<th>@Localizer["Version"]</th>
<th style="width: 1px"></th>
</Header>
<Row>
<td>@context.Name</td>
<td>@context.Version</td>
<td>
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadLanguage(context.PackageId, context.Version))>@Localizer["Download"]</button>
</td>
</Row>
</Pager>
<button type="button" class="btn btn-success" @onclick="InstallLanguages">@Localizer["Install"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink>
}
else
{
<ModuleMessage Type="MessageType.Info" Message="No Language Packages Are Available To Download"></ModuleMessage>
}
</TabPanel>
<TabPanel Name="Upload" ResourceKey="Upload" Security="SecurityAccessLevel.Host">
<table class="table table-borderless">
<tr>
<td>
<Label HelpText="Upload one or more language packages. Once they are uploaded click Install to complete the installation." ResourceKey="Module">Language: </Label>
</td>
<td>
<FileManager Filter="nupkg" ShowFiles="false" Folder="Packages" UploadMultiple="true" />
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="InstallLanguages">@Localizer["Install"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink>
</TabPanel>
</TabStrip>
} }
@code { @code {
private string _code = string.Empty; private string _code = string.Empty;
private string _isDefault = "False"; private string _isDefault = "False";
private List<Package> _packages;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
@ -57,14 +107,8 @@ else
protected override async Task OnParametersSetAsync() protected override async Task OnParametersSetAsync()
{ {
_supportedCultures = await LocalizationService.GetCulturesAsync(); _supportedCultures = await LocalizationService.GetCulturesAsync();
if (_supportedCultures.Count() <= 1) _supportedCultures = _supportedCultures.Where(c => !c.Name.Equals(Constants.DefaultCulture));
{ _packages = await PackageService.GetPackagesAsync("language");
AddModuleMessage(Localizer["The Only Supported Culture That Has Been Defined Is English"], MessageType.Warning);
}
else
{
_supportedCultures = _supportedCultures.Where(c => !c.Name.Equals(Constants.DefaultCulture));
}
} }
private async Task SaveLanguage() private async Task SaveLanguage()
@ -97,6 +141,35 @@ else
} }
} }
private async Task InstallLanguages()
{
try
{
await PackageService.InstallPackagesAsync();
AddModuleMessage(Localizer["Language Packages Installed Successfully. You Must <a href=\"{0}\">Restart</a> Your Application To Apply These Changes.", NavigateUrl("admin/system")], MessageType.Success);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Installing Language Package");
}
}
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["Language Package Downloaded Successfully. Click Install To Complete Installation."], MessageType.Success);
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Language Package {Name} {Version}", packageid, version);
AddModuleMessage(Localizer["Error Downloading Language Package"], MessageType.Error);
}
}
private async Task SetCultureAsync(string culture) private async Task SetCultureAsync(string culture)
{ {
if (culture != CultureInfo.CurrentUICulture.Name) if (culture != CultureInfo.CurrentUICulture.Name)

View File

@ -1,6 +1,7 @@
@namespace Oqtane.Modules.Admin.Languages @namespace Oqtane.Modules.Admin.Languages
@inherits ModuleBase @inherits ModuleBase
@inject ILanguageService LanguageService @inject ILanguageService LanguageService
@inject ILocalizationService LocalizationService
@inject IStringLocalizer<Index> Localizer @inject IStringLocalizer<Index> Localizer
@if (_languages == null) @if (_languages == null)
@ -19,7 +20,7 @@ else
<th>@Localizer["Default?"]</th> <th>@Localizer["Default?"]</th>
</Header> </Header>
<Row> <Row>
<td><ActionDialog Header="Delete Langauge" Message="@Localizer["Are You Sure You Wish To Delete The {0} Language?", context.Name]" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteLanguage(context))" Disabled="@(context.IsDefault)" ResourceKey="DeleteLanguage" /></td> <td><ActionDialog Header="Delete Langauge" Message="@Localizer["Are You Sure You Wish To Delete The {0} Language From This Site?", context.Name]" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteLanguage(context))" Disabled="@(context.IsDefault)" ResourceKey="DeleteLanguage" /></td>
<td>@context.Name</td> <td>@context.Name</td>
<td>@context.Code</td> <td>@context.Code</td>
<td><TriStateCheckBox Value="@(context.IsDefault)" Disabled="true"></TriStateCheckBox></td> <td><TriStateCheckBox Value="@(context.IsDefault)" Disabled="true"></TriStateCheckBox></td>
@ -35,6 +36,12 @@ else
protected override async Task OnParametersSetAsync() protected override async Task OnParametersSetAsync()
{ {
_languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId); _languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId);
if (_languages.Count == 0)
{
var cultures = await LocalizationService.GetCulturesAsync();
var culture = cultures.First(c => c.Name.Equals(Constants.DefaultCulture));
_languages.Add(new Language { Name = culture.DisplayName, Code = culture.Name, IsDefault = culture.IsDefault });
}
} }
private async Task DeleteLanguage(Language language) private async Task DeleteLanguage(Language language)

View File

@ -1,4 +1,4 @@
using Oqtane.Models; using Oqtane.Models;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -8,5 +8,6 @@ namespace Oqtane.Services
{ {
Task<List<Package>> GetPackagesAsync(string tag); Task<List<Package>> GetPackagesAsync(string tag);
Task DownloadPackageAsync(string packageId, string version, string folder); Task DownloadPackageAsync(string packageId, string version, string folder);
Task InstallPackagesAsync();
} }
} }

View File

@ -1,4 +1,4 @@
using Oqtane.Models; using Oqtane.Models;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -22,5 +22,10 @@ namespace Oqtane.Services
{ {
await PostAsync($"{Apiurl}?packageid={packageId}&version={version}&folder={folder}"); await PostAsync($"{Apiurl}?packageid={packageId}&version={version}&folder={folder}");
} }
public async Task InstallPackagesAsync()
{
await GetJsonAsync<List<string>>($"{Apiurl}/install");
}
} }
} }

View File

@ -1,16 +1,17 @@
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Oqtane.Models; using Oqtane.Models;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Oqtane.Shared; using Oqtane.Shared;
using Oqtane.Infrastructure;
using Oqtane.Enums;
// ReSharper disable PartialTypeWithSinglePart // ReSharper disable PartialTypeWithSinglePart
namespace Oqtane.Controllers namespace Oqtane.Controllers
@ -18,11 +19,15 @@ namespace Oqtane.Controllers
[Route(ControllerRoutes.Default)] [Route(ControllerRoutes.Default)]
public class PackageController : Controller public class PackageController : Controller
{ {
private readonly IInstallationManager _installationManager;
private readonly IWebHostEnvironment _environment; private readonly IWebHostEnvironment _environment;
private readonly ILogManager _logger;
public PackageController(IWebHostEnvironment environment) public PackageController(IInstallationManager installationManager, IWebHostEnvironment environment, ILogManager logger)
{ {
_installationManager = installationManager;
_environment = environment; _environment = environment;
_logger = logger;
} }
// GET: api/<controller>?tag=x // GET: api/<controller>?tag=x
@ -86,6 +91,14 @@ namespace Oqtane.Controllers
} }
} }
} }
[HttpGet("install")]
[Authorize(Roles = RoleNames.Host)]
public void InstallPackages()
{
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Packages Installed");
_installationManager.InstallPackages("Packages");
}
} }
public partial class SearchResult public partial class SearchResult

View File

@ -175,7 +175,7 @@ namespace Oqtane
services.AddSingleton<IDatabaseManager, DatabaseManager>(); services.AddSingleton<IDatabaseManager, DatabaseManager>();
// install any modules or themes ( this needs to occur BEFORE the assemblies are loaded into the app domain ) // install any modules or themes ( this needs to occur BEFORE the assemblies are loaded into the app domain )
InstallationManager.InstallPackages("Modules,Themes", _env.WebRootPath, _env.ContentRootPath); InstallationManager.InstallPackages("Modules,Themes,Packages", _env.WebRootPath, _env.ContentRootPath);
// register transient scoped core services // register transient scoped core services
services.AddTransient<IModuleDefinitionRepository, ModuleDefinitionRepository>(); services.AddTransient<IModuleDefinitionRepository, ModuleDefinitionRepository>();

View File

@ -1 +0,0 @@
/* Module Custom Styles */

View File

@ -1 +0,0 @@
/* Module Script */

View File

@ -1 +0,0 @@
["\\bin\\Debug\\net5.0\\Oqtane.Blogs.Client.Oqtane.dll","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Client.Oqtane.pdb","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Server.Oqtane.dll","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Server.Oqtane.pdb","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Shared.Oqtane.dll","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Shared.Oqtane.pdb","\\wwwroot\\Modules\\Oqtane.Blogs\\Module.css","\\wwwroot\\Modules\\Oqtane.Blogs\\Module.js"]