Merge pull request #1045 from hishamco/language-management
Add Languages Management
This commit is contained in:
commit
b4aec286ed
97
Oqtane.Client/Modules/Admin/Languages/Add.razor
Normal file
97
Oqtane.Client/Modules/Admin/Languages/Add.razor
Normal file
|
@ -0,0 +1,97 @@
|
|||
@namespace Oqtane.Modules.Admin.Languages
|
||||
@inherits ModuleBase
|
||||
@using System.Globalization
|
||||
@using Microsoft.AspNetCore.Localization
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ILocalizationService LocalizationService
|
||||
@inject ILanguageService LanguageService
|
||||
@inject IStringLocalizer<Add> Localizer
|
||||
|
||||
<table class="table table-borderless">
|
||||
<tr>
|
||||
<td>
|
||||
<Label For="name" HelpText="Name Of The Langauage" ResourceKey="Name">Name:</Label>
|
||||
</td>
|
||||
<td>
|
||||
@if (_supportedCultures?.Count() > 1)
|
||||
{
|
||||
<select id="_code" class="form-control" @bind="@_code">
|
||||
@foreach (var culture in _supportedCultures)
|
||||
{
|
||||
<option value="@culture.Name">@culture.DisplayName</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Label For="isCurrent" HelpText="Indicates Whether Or Not This Language Is The Default One." ResourceKey="IsCurrent">Default?</Label>
|
||||
</td>
|
||||
<td>
|
||||
<select id="isCurrent" class="form-control" @bind="@_isCurrent">
|
||||
<option value="True">@Localizer["Yes"]</option>
|
||||
<option value="False">@Localizer["No"]</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<button type="button" class="btn btn-success @(_supportedCultures?.Count() > 1 ? String.Empty : "disabled")" @onclick="SaveLanguage">@Localizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink>
|
||||
|
||||
@code {
|
||||
private string _code = string.Empty;
|
||||
private string _isCurrent = "False";
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
private IEnumerable<Culture> _supportedCultures;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
_supportedCultures = await LocalizationService.GetCulturesAsync();
|
||||
}
|
||||
|
||||
private async Task SaveLanguage()
|
||||
{
|
||||
var language = new Language
|
||||
{
|
||||
SiteId = PageState.Page.SiteId,
|
||||
Name = CultureInfo.GetCultureInfo(_code).DisplayName,
|
||||
Code = _code,
|
||||
IsCurrent = (_isCurrent == null ? false : Boolean.Parse(_isCurrent))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
language = await LanguageService.AddLanguageAsync(language);
|
||||
|
||||
if (language.IsCurrent)
|
||||
{
|
||||
await SetCultureAsync(language.Code);
|
||||
}
|
||||
|
||||
await logger.LogInformation("Language Added {Language}", language);
|
||||
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Adding Language {Language} {Error}", language, ex.Message);
|
||||
|
||||
AddModuleMessage(Localizer["Error Adding Language"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetCultureAsync(string culture)
|
||||
{
|
||||
if (culture != CultureInfo.CurrentUICulture.Name)
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
|
||||
await interop.SetCookie(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, 360);
|
||||
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
|
||||
}
|
||||
}
|
||||
}
|
56
Oqtane.Client/Modules/Admin/Languages/Index.razor
Normal file
56
Oqtane.Client/Modules/Admin/Languages/Index.razor
Normal file
|
@ -0,0 +1,56 @@
|
|||
@namespace Oqtane.Modules.Admin.Languages
|
||||
@inherits ModuleBase
|
||||
@inject ILanguageService LanguageService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
|
||||
@if (_languages == null)
|
||||
{
|
||||
<p><em>@Localizer["Loading..."]</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ActionLink Action="Add" Text="Add Language" ResourceKey="AddLanguage" />
|
||||
|
||||
<Pager Items="@_languages">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["Name"]</th>
|
||||
<th>@Localizer["Code"]</th>
|
||||
<th>@Localizer["Is Current"]</th>
|
||||
</Header>
|
||||
<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.IsCurrent)" ResourceKey="DeleteLanguage" /></td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Code</td>
|
||||
<td><TriStateCheckBox Value="@(context.IsCurrent)" Disabled="true"></TriStateCheckBox></td>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<Language> _languages;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
_languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId);
|
||||
}
|
||||
|
||||
private async Task DeleteLanguage(Language language)
|
||||
{
|
||||
try
|
||||
{
|
||||
await LanguageService.DeleteLanguageAsync(language.LanguageId);
|
||||
await logger.LogInformation("Language Deleted {Language}", language);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Language {Language} {Error}", language, ex.Message);
|
||||
|
||||
AddModuleMessage(Localizer["Error Deleting Language"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -67,6 +67,7 @@ namespace Oqtane.Client
|
|||
builder.Services.AddScoped<ISqlService, SqlService>();
|
||||
builder.Services.AddScoped<ISystemService, SystemService>();
|
||||
builder.Services.AddScoped<ILocalizationService, LocalizationService>();
|
||||
builder.Services.AddScoped<ILanguageService, LanguageService>();
|
||||
|
||||
await LoadClientAssemblies(httpClient);
|
||||
|
||||
|
|
17
Oqtane.Client/Services/Interfaces/ILanguageService.cs
Normal file
17
Oqtane.Client/Services/Interfaces/ILanguageService.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using Oqtane.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
public interface ILanguageService
|
||||
{
|
||||
Task<List<Language>> GetLanguagesAsync(int siteId);
|
||||
|
||||
Task<Language> GetLanguageAsync(int languageId);
|
||||
|
||||
Task<Language> AddLanguageAsync(Language language);
|
||||
|
||||
Task DeleteLanguageAsync(int languageId);
|
||||
}
|
||||
}
|
38
Oqtane.Client/Services/LanguageService.cs
Normal file
38
Oqtane.Client/Services/LanguageService.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
public class LanguageService : ServiceBase, ILanguageService
|
||||
{
|
||||
|
||||
private readonly SiteState _siteState;
|
||||
|
||||
public LanguageService(HttpClient http, SiteState siteState) : base(http)
|
||||
{
|
||||
_siteState = siteState;
|
||||
}
|
||||
|
||||
private string Apiurl => CreateApiUrl(_siteState.Alias, "Language");
|
||||
|
||||
public async Task<List<Language>> GetLanguagesAsync(int siteId)
|
||||
{
|
||||
var languages = await GetJsonAsync<List<Language>>($"{Apiurl}?siteid={siteId}");
|
||||
|
||||
return languages?.OrderBy(l => l.Name).ToList() ?? Enumerable.Empty<Language>().ToList();
|
||||
}
|
||||
|
||||
public async Task<Language> GetLanguageAsync(int languageId)
|
||||
=> await GetJsonAsync<Language>($"{Apiurl}/{languageId}");
|
||||
|
||||
public async Task<Language> AddLanguageAsync(Language language)
|
||||
=> await PostJsonAsync<Language>(Apiurl, language);
|
||||
|
||||
public async Task DeleteLanguageAsync(int languageId)
|
||||
=> await DeleteAsync($"{Apiurl}/{languageId}");
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
@namespace Oqtane.Themes.Controls
|
||||
@inherits ThemeControlBase
|
||||
@using System.Globalization
|
||||
@using Microsoft.AspNetCore.Localization;
|
||||
@using Microsoft.AspNetCore.Localization
|
||||
@using Oqtane.Models
|
||||
@inject ILocalizationService LocalizationService
|
||||
@inject ILanguageService LanguageService
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
@if (_supportedCultures?.Count() > 1)
|
||||
|
@ -26,7 +26,8 @@
|
|||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
_supportedCultures = await LocalizationService.GetCulturesAsync();
|
||||
var languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId);
|
||||
_supportedCultures = languages.Select(l => new Culture { Name = l.Code, DisplayName = l.Name });
|
||||
}
|
||||
|
||||
private async Task SetCultureAsync(string culture)
|
||||
|
|
52
Oqtane.Server/Controllers/LanguageController.cs
Normal file
52
Oqtane.Server/Controllers/LanguageController.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.Default)]
|
||||
public class LanguageController : Controller
|
||||
{
|
||||
private readonly ILanguageRepository _languages;
|
||||
private readonly ILogManager _logger;
|
||||
|
||||
public LanguageController(ILanguageRepository language, ILogManager logger)
|
||||
{
|
||||
_languages = language;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public IEnumerable<Language> Get(string siteid) => _languages.GetLanguages(int.Parse(siteid));
|
||||
|
||||
[HttpGet("{id}")]
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Language Get(int id) => _languages.GetLanguage(id);
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public Language Post([FromBody] Language language)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
language = _languages.AddLanguage(language);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Language Added {Language}", language);
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public void Delete(int id)
|
||||
{
|
||||
_languages.DeleteLanguage(id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Language Deleted {LanguageId}", id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Oqtane.Models;
|
||||
|
||||
|
@ -21,6 +21,8 @@ namespace Oqtane.Repository
|
|||
public virtual DbSet<Folder> Folder { get; set; }
|
||||
public virtual DbSet<File> File { get; set; }
|
||||
|
||||
public virtual DbSet<Language> Language { get; set; }
|
||||
|
||||
public TenantDBContext(ITenantResolver tenantResolver, IHttpContextAccessor accessor) : base(tenantResolver, accessor)
|
||||
{
|
||||
// DBContextBase handles multi-tenant database connections
|
||||
|
|
16
Oqtane.Server/Repository/Interfaces/ILanguageRepository.cs
Normal file
16
Oqtane.Server/Repository/Interfaces/ILanguageRepository.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System.Collections.Generic;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Repository
|
||||
{
|
||||
public interface ILanguageRepository
|
||||
{
|
||||
IEnumerable<Language> GetLanguages(int siteId);
|
||||
|
||||
Language AddLanguage(Language language);
|
||||
|
||||
Language GetLanguage(int languageId);
|
||||
|
||||
void DeleteLanguage(int languageId);
|
||||
}
|
||||
}
|
41
Oqtane.Server/Repository/LanguageRepository.cs
Normal file
41
Oqtane.Server/Repository/LanguageRepository.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Repository
|
||||
{
|
||||
public class LanguageRepository : ILanguageRepository
|
||||
{
|
||||
private TenantDBContext _db;
|
||||
|
||||
public LanguageRepository(TenantDBContext context)
|
||||
{
|
||||
_db = context;
|
||||
}
|
||||
|
||||
public IEnumerable<Language> GetLanguages(int siteId) => _db.Language.Where(l => l.SiteId == siteId);
|
||||
|
||||
public Language AddLanguage(Language language)
|
||||
{
|
||||
if (language.IsCurrent)
|
||||
{
|
||||
// Ensure all other languages are not set to current
|
||||
_db.Language.ToList().ForEach(l => l.IsCurrent = false);
|
||||
}
|
||||
|
||||
_db.Language.Add(language);
|
||||
_db.SaveChanges();
|
||||
|
||||
return language;
|
||||
}
|
||||
|
||||
public Language GetLanguage(int languageId) => _db.Language.Find(languageId);
|
||||
|
||||
public void DeleteLanguage(int languageId)
|
||||
{
|
||||
var language = _db.Language.Find(languageId);
|
||||
_db.Language.Remove(language);
|
||||
_db.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -502,6 +502,37 @@ namespace Oqtane.Repository
|
|||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Language Management",
|
||||
Parent = "Admin",
|
||||
Path = "admin/languages",
|
||||
Icon = Icons.Text,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PagePermissions = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
}.EncodePermissions(),
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Languages.Index).ToModuleDefinitionName(), Title = "Language Management", Pane = "Content",
|
||||
ModulePermissions = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
}.EncodePermissions(),
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Scheduled Jobs", Parent = "Admin", Path = "admin/jobs", Icon = Icons.Timer, IsNavigation = false, IsPersonalizable = false,
|
||||
PagePermissions = new List<Permission>
|
||||
|
|
27
Oqtane.Server/Scripts/Tenant.02.00.02.00.sql
Normal file
27
Oqtane.Server/Scripts/Tenant.02.00.02.00.sql
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
|
||||
Version 2.0.0 Tenant migration script
|
||||
|
||||
*/
|
||||
|
||||
CREATE TABLE [dbo].[Language](
|
||||
[LanguageId] [int] IDENTITY(1,1) NOT NULL,
|
||||
[Name] [nvarchar](100) NOT NULL,
|
||||
[Code] [nvarchar](10) NOT NULL,
|
||||
[IsCurrent] [bit] NOT NULL,
|
||||
[SiteId] [int],
|
||||
[CreatedBy] [nvarchar](256) NOT NULL,
|
||||
[CreatedOn] [datetime] NOT NULL,
|
||||
[ModifiedBy] [nvarchar](256) NOT NULL,
|
||||
[ModifiedOn] [datetime] NOT NULL,
|
||||
CONSTRAINT [PK_Language] PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[LanguageId] ASC
|
||||
)
|
||||
)
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[Language] WITH CHECK ADD CONSTRAINT [FK_Language_Site] FOREIGN KEY([SiteId])
|
||||
REFERENCES [dbo].[Site] ([SiteId])
|
||||
ON DELETE CASCADE
|
||||
GO
|
|
@ -128,6 +128,7 @@ namespace Oqtane
|
|||
services.AddScoped<ISqlService, SqlService>();
|
||||
services.AddScoped<ISystemService, SystemService>();
|
||||
services.AddScoped<ILocalizationService, LocalizationService>();
|
||||
services.AddScoped<ILanguageService, LanguageService>();
|
||||
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
|
||||
|
@ -213,6 +214,7 @@ namespace Oqtane
|
|||
services.AddTransient<ISiteTemplateRepository, SiteTemplateRepository>();
|
||||
services.AddTransient<ISqlRepository, SqlRepository>();
|
||||
services.AddTransient<IUpgradeManager, UpgradeManager>();
|
||||
services.AddTransient<ILanguageRepository, LanguageRepository>();
|
||||
|
||||
// load the external assemblies into the app domain, install services
|
||||
services.AddOqtane(_runtime, _supportedCultures);
|
||||
|
|
25
Oqtane.Shared/Models/Language.cs
Normal file
25
Oqtane.Shared/Models/Language.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
|
||||
namespace Oqtane.Models
|
||||
{
|
||||
public class Language : IAuditable
|
||||
{
|
||||
public int LanguageId { get; set; }
|
||||
|
||||
public int? SiteId { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Code { get; set; }
|
||||
|
||||
public bool IsCurrent { get; set; }
|
||||
|
||||
public string CreatedBy { get; set; }
|
||||
|
||||
public DateTime CreatedOn { get; set; }
|
||||
|
||||
public string ModifiedBy { get; set; }
|
||||
|
||||
public DateTime ModifiedOn { get; set; }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user