From c0ed7c79345443f004c46ea0940704ac20f63e55 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Thu, 21 Jan 2021 17:09:34 -0500 Subject: [PATCH] Localization fixes - table definition, SQL script naming, SQL script not marked as Embedded Resource, changed column name from IsCurrrent to IsDefault to reflect intent, set default language for site in _Host --- .../Modules/Admin/Languages/Add.razor | 80 +++++++++++-------- .../Modules/Admin/Languages/Index.razor | 6 +- Oqtane.Server/Controllers/AliasController.cs | 21 +---- Oqtane.Server/Oqtane.Server.csproj | 1 + Oqtane.Server/Pages/_Host.cshtml.cs | 35 ++++++++ Oqtane.Server/Repository/AliasRepository.cs | 23 +++++- .../Repository/Context/DBContextBase.cs | 16 ++-- .../Repository/Context/MasterDBContext.cs | 18 ++++- .../Repository/Interfaces/IAliasRepository.cs | 3 +- .../Repository/LanguageRepository.cs | 4 +- Oqtane.Server/Repository/TenantResolver.cs | 54 ++++++++----- ...02.00.02.00.sql => Tenant.02.00.01.02.sql} | 4 +- Oqtane.Server/Startup.cs | 5 +- Oqtane.Shared/Models/Language.cs | 2 +- 14 files changed, 178 insertions(+), 94 deletions(-) rename Oqtane.Server/Scripts/{Tenant.02.00.02.00.sql => Tenant.02.00.01.02.sql} (90%) diff --git a/Oqtane.Client/Modules/Admin/Languages/Add.razor b/Oqtane.Client/Modules/Admin/Languages/Add.razor index 02b8e0c2..7efbcf85 100644 --- a/Oqtane.Client/Modules/Admin/Languages/Add.razor +++ b/Oqtane.Client/Modules/Admin/Languages/Add.razor @@ -7,41 +7,48 @@ @inject ILanguageService LanguageService @inject IStringLocalizer Localizer - - - - - - - - - -
- - - @if (_supportedCultures?.Count() > 1) - { - - } -
- - - -
- -@Localizer["Cancel"] +@if (_supportedCultures == null) +{ +

@Localizer["Loading..."]

+} +else +{ + @if (_supportedCultures?.Count() > 1) + { + + + + + + + + + +
+ + + +
+ + + +
+ + } + @Localizer["Cancel"] +} @code { private string _code = string.Empty; - private string _isCurrent = "False"; + private string _isDefault = "False"; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; @@ -50,6 +57,10 @@ protected override async Task OnParametersSetAsync() { _supportedCultures = await LocalizationService.GetCulturesAsync(); + if (_supportedCultures.Count() <= 1) + { + AddModuleMessage(Localizer["The Only Supported Culture That Has Been Defined Is English"], MessageType.Warning); + } } private async Task SaveLanguage() @@ -59,14 +70,14 @@ SiteId = PageState.Page.SiteId, Name = CultureInfo.GetCultureInfo(_code).DisplayName, Code = _code, - IsCurrent = (_isCurrent == null ? false : Boolean.Parse(_isCurrent)) + IsDefault = (_isDefault == null ? false : Boolean.Parse(_isDefault)) }; try { language = await LanguageService.AddLanguageAsync(language); - if (language.IsCurrent) + if (language.IsDefault) { await SetCultureAsync(language.Code); } @@ -78,7 +89,6 @@ catch (Exception ex) { await logger.LogError(ex, "Error Adding Language {Language} {Error}", language, ex.Message); - AddModuleMessage(Localizer["Error Adding Language"], MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Languages/Index.razor b/Oqtane.Client/Modules/Admin/Languages/Index.razor index 933903cc..748c875b 100644 --- a/Oqtane.Client/Modules/Admin/Languages/Index.razor +++ b/Oqtane.Client/Modules/Admin/Languages/Index.razor @@ -16,13 +16,13 @@ else   @Localizer["Name"] @Localizer["Code"] - @Localizer["Is Current"] + @Localizer["Default?"] - + @context.Name @context.Code - + } diff --git a/Oqtane.Server/Controllers/AliasController.cs b/Oqtane.Server/Controllers/AliasController.cs index 8956bac7..4d8dac8d 100644 --- a/Oqtane.Server/Controllers/AliasController.cs +++ b/Oqtane.Server/Controllers/AliasController.cs @@ -50,29 +50,13 @@ namespace Oqtane.Controllers [HttpGet("name/{**name}")] public Alias Get(string name, string sync) { - List aliases = _aliases.GetAliases().ToList(); // cached Alias alias = null; + if (_accessor.HttpContext != null) { name = (name == "~") ? "" : name; name = _accessor.HttpContext.Request.Host.Value + "/" + WebUtility.UrlDecode(name); - var segments = name.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - - // iterate segments in reverse order - for (int i = segments.Length; i > 0; i--) - { - name = string.Join("/", segments, 0, i); - alias = aliases.Find(item => item.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); - if (alias != null) - { - break; // found a matching alias - } - } - } - if (alias == null && aliases.Any()) - { - // use first alias if name does not exist - alias = aliases.FirstOrDefault(); + alias = _aliases.GetAlias(name); } // get sync events @@ -81,6 +65,7 @@ namespace Oqtane.Controllers alias.SyncDate = DateTime.UtcNow; alias.SyncEvents = _syncManager.GetSyncEvents(alias.TenantId, DateTime.ParseExact(sync, "yyyyMMddHHmmssfff", CultureInfo.InvariantCulture)); } + return alias; } diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 8176804d..1ac18c29 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -35,6 +35,7 @@ + diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs index c50e5b1f..662beb18 100644 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ b/Oqtane.Server/Pages/_Host.cshtml.cs @@ -7,11 +7,28 @@ using Oqtane.Themes; using System; using System.Linq; using System.Reflection; +using Microsoft.AspNetCore.Http.Extensions; +using Oqtane.Repository; +using Microsoft.AspNetCore.Localization; +using Microsoft.Extensions.Configuration; namespace Oqtane.Pages { public class HostModel : PageModel { + private IConfiguration _configuration; + private readonly SiteState _state; + private readonly IAliasRepository _aliases; + private readonly ILanguageRepository _languages; + + public HostModel(IConfiguration configuration, SiteState state, IAliasRepository aliases, ILanguageRepository languages) + { + _configuration = configuration; + _state = state; + _aliases = aliases; + _languages = languages; + } + public string HeadResources = ""; public string BodyResources = ""; @@ -24,6 +41,24 @@ namespace Oqtane.Pages ProcessModuleControls(assembly); ProcessThemeControls(assembly); } + + // if framework is installed + if (!string.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection"))) + { + Uri uri = new Uri(Request.GetDisplayUrl()); + var alias = _aliases.GetAlias(uri.Authority + "/" + uri.LocalPath.Substring(1)); + _state.Alias = alias; + + // set default language for site + var language = _languages.GetLanguages(alias.SiteId).Where(item => item.IsDefault).FirstOrDefault(); + if (language != null) + { + HttpContext.Response.Cookies.Append( + CookieRequestCultureProvider.DefaultCookieName, + CookieRequestCultureProvider.MakeCookieValue( + new RequestCulture(language.Code))); + } + } } private void ProcessHostResources(Assembly assembly) diff --git a/Oqtane.Server/Repository/AliasRepository.cs b/Oqtane.Server/Repository/AliasRepository.cs index ccb26681..f25c4c03 100644 --- a/Oqtane.Server/Repository/AliasRepository.cs +++ b/Oqtane.Server/Repository/AliasRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; @@ -48,6 +48,27 @@ namespace Oqtane.Repository return _db.Alias.Find(aliasId); } + public Alias GetAlias(string name) + { + Alias alias = null; + + List aliases = GetAliases().ToList(); + var segments = name.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + + // iterate segments in reverse order + for (int i = segments.Length; i > 0; i--) + { + name = string.Join("/", segments, 0, i); + alias = aliases.Find(item => item.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); + if (alias != null) + { + break; // found a matching alias + } + } + + return alias; + } + public void DeleteAlias(int aliasId) { Alias alias = _db.Alias.Find(aliasId); diff --git a/Oqtane.Server/Repository/Context/DBContextBase.cs b/Oqtane.Server/Repository/Context/DBContextBase.cs index 247006bd..522bf0d9 100644 --- a/Oqtane.Server/Repository/Context/DBContextBase.cs +++ b/Oqtane.Server/Repository/Context/DBContextBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; @@ -10,20 +10,24 @@ namespace Oqtane.Repository { public class DBContextBase : IdentityUserContext { - private Tenant _tenant; + private ITenantResolver _tenantResolver; private IHttpContextAccessor _accessor; public DBContextBase(ITenantResolver tenantResolver, IHttpContextAccessor accessor) { - _tenant = tenantResolver.GetTenant(); + _tenantResolver = tenantResolver; _accessor = accessor; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - optionsBuilder.UseSqlServer(_tenant.DBConnectionString - .Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString()) - ); + var tenant = _tenantResolver.GetTenant(); + if (tenant != null) + { + optionsBuilder.UseSqlServer(tenant.DBConnectionString + .Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString()) + ); + } base.OnConfiguring(optionsBuilder); } diff --git a/Oqtane.Server/Repository/Context/MasterDBContext.cs b/Oqtane.Server/Repository/Context/MasterDBContext.cs index 65312819..976874cf 100644 --- a/Oqtane.Server/Repository/Context/MasterDBContext.cs +++ b/Oqtane.Server/Repository/Context/MasterDBContext.cs @@ -1,18 +1,32 @@ -using System; +using System; using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Oqtane.Models; +using Microsoft.Extensions.Configuration; namespace Oqtane.Repository { public class MasterDBContext : DbContext { private IHttpContextAccessor _accessor; + private IConfiguration _configuration; - public MasterDBContext(DbContextOptions options, IHttpContextAccessor accessor) : base(options) + public MasterDBContext(DbContextOptions options, IHttpContextAccessor accessor, IConfiguration configuration) : base(options) { _accessor = accessor; + _configuration = configuration; + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!string.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection"))) + { + optionsBuilder.UseSqlServer(_configuration.GetConnectionString("DefaultConnection") + .Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString()) + ); + } + base.OnConfiguring(optionsBuilder); } public virtual DbSet Alias { get; set; } diff --git a/Oqtane.Server/Repository/Interfaces/IAliasRepository.cs b/Oqtane.Server/Repository/Interfaces/IAliasRepository.cs index 4f258307..5422ab07 100644 --- a/Oqtane.Server/Repository/Interfaces/IAliasRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IAliasRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Oqtane.Models; namespace Oqtane.Repository @@ -9,6 +9,7 @@ namespace Oqtane.Repository Alias AddAlias(Alias alias); Alias UpdateAlias(Alias alias); Alias GetAlias(int aliasId); + Alias GetAlias(string name); void DeleteAlias(int aliasId); } } diff --git a/Oqtane.Server/Repository/LanguageRepository.cs b/Oqtane.Server/Repository/LanguageRepository.cs index ade74f2d..0ee5105b 100644 --- a/Oqtane.Server/Repository/LanguageRepository.cs +++ b/Oqtane.Server/Repository/LanguageRepository.cs @@ -17,10 +17,10 @@ namespace Oqtane.Repository public Language AddLanguage(Language language) { - if (language.IsCurrent) + if (language.IsDefault) { // Ensure all other languages are not set to current - _db.Language.ToList().ForEach(l => l.IsCurrent = false); + _db.Language.ToList().ForEach(l => l.IsDefault = false); } _db.Language.Add(language); diff --git a/Oqtane.Server/Repository/TenantResolver.cs b/Oqtane.Server/Repository/TenantResolver.cs index cd273b3a..815a8c55 100644 --- a/Oqtane.Server/Repository/TenantResolver.cs +++ b/Oqtane.Server/Repository/TenantResolver.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Http; @@ -9,24 +9,49 @@ namespace Oqtane.Repository { public class TenantResolver : ITenantResolver { - private readonly Alias _alias; - private readonly Tenant _tenant; + private readonly IHttpContextAccessor _accessor; + private readonly IAliasRepository _aliasRepository; + private readonly ITenantRepository _tenantRepository; + private readonly SiteState _siteState; + + private Alias _alias; + private Tenant _tenant; public TenantResolver(IHttpContextAccessor accessor, IAliasRepository aliasRepository, ITenantRepository tenantRepository, SiteState siteState) { - int aliasId = -1; + _accessor = accessor; + _aliasRepository = aliasRepository; + _tenantRepository = tenantRepository; + _siteState = siteState; + } - if (siteState != null && siteState.Alias != null) + public Alias GetAlias() + { + if (_alias == null) ResolveTenant(); + return _alias; + } + + public Tenant GetTenant() + { + if (_tenant == null) ResolveTenant(); + return _tenant; + } + + private void ResolveTenant() + { + if (_siteState != null && _siteState.Alias != null) { // background processes can pass in an alias using the SiteState service - _alias = siteState.Alias; + _alias = _siteState.Alias; } else { + int aliasId = -1; + // get aliasid identifier based on request - if (accessor.HttpContext != null) + if (_accessor.HttpContext != null) { - string[] segments = accessor.HttpContext.Request.Path.Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + string[] segments = _accessor.HttpContext.Request.Path.Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); if (segments.Length > 1 && (segments[1] == "api" || segments[1] == "pages") && segments[0] != "~") { aliasId = int.Parse(segments[0]); @@ -34,7 +59,7 @@ namespace Oqtane.Repository } // get the alias - IEnumerable aliases = aliasRepository.GetAliases().ToList(); // cached + IEnumerable aliases = _aliasRepository.GetAliases().ToList(); // cached if (aliasId != -1) { _alias = aliases.FirstOrDefault(item => item.AliasId == aliasId); @@ -44,19 +69,10 @@ namespace Oqtane.Repository if (_alias != null) { // get the tenant - IEnumerable tenants = tenantRepository.GetTenants(); // cached + IEnumerable tenants = _tenantRepository.GetTenants(); // cached _tenant = tenants.FirstOrDefault(item => item.TenantId == _alias.TenantId); } - } - public Alias GetAlias() - { - return _alias; - } - - public Tenant GetTenant() - { - return _tenant; } } } diff --git a/Oqtane.Server/Scripts/Tenant.02.00.02.00.sql b/Oqtane.Server/Scripts/Tenant.02.00.01.02.sql similarity index 90% rename from Oqtane.Server/Scripts/Tenant.02.00.02.00.sql rename to Oqtane.Server/Scripts/Tenant.02.00.01.02.sql index 0e6d04ab..3f3f4976 100644 --- a/Oqtane.Server/Scripts/Tenant.02.00.02.00.sql +++ b/Oqtane.Server/Scripts/Tenant.02.00.01.02.sql @@ -8,8 +8,8 @@ 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], + [IsDefault] [bit] NOT NULL, + [SiteId] [int] NOT NULL, [CreatedBy] [nvarchar](256) NOT NULL, [CreatedOn] [datetime] NOT NULL, [ModifiedBy] [nvarchar](256) NOT NULL, diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 0353bc03..babe9245 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -132,10 +132,7 @@ namespace Oqtane services.AddSingleton(); - services.AddDbContext(options => - options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection") - .Replace("|DataDirectory|", AppContext.GetData("DataDirectory")?.ToString()) - )); + services.AddDbContext(options => { }); services.AddDbContext(options => { }); services.AddIdentityCore(options => { }) diff --git a/Oqtane.Shared/Models/Language.cs b/Oqtane.Shared/Models/Language.cs index 2433d0d0..e0afdd66 100644 --- a/Oqtane.Shared/Models/Language.cs +++ b/Oqtane.Shared/Models/Language.cs @@ -12,7 +12,7 @@ namespace Oqtane.Models public string Code { get; set; } - public bool IsCurrent { get; set; } + public bool IsDefault { get; set; } public string CreatedBy { get; set; }