From 73b13d7a5455e081acfc8e75f97ffcef73f5d136 Mon Sep 17 00:00:00 2001 From: hishamco Date: Sun, 18 Apr 2021 02:25:40 +0300 Subject: [PATCH 01/22] Add Oqtane extension methods for clean startup --- .../OqtaneServiceCollectionExtensions.cs | 194 ++++++++++++++++++ Oqtane.Server/Startup.cs | 164 ++------------- 2 files changed, 214 insertions(+), 144 deletions(-) diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 36c41601..c429b282 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -1,11 +1,21 @@ using System; using System.IO; using System.Linq; +using System.Net.Http; using System.Reflection; using System.Runtime.Loader; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; +using Microsoft.OpenApi.Models; using Oqtane.Infrastructure; using Oqtane.Modules; +using Oqtane.Repository; +using Oqtane.Security; using Oqtane.Services; using Oqtane.Shared; @@ -23,6 +33,190 @@ namespace Microsoft.Extensions.DependencyInjection return services; } + public static IServiceCollection AddOqtaneDbContext(this IServiceCollection services) + { + services.AddDbContext(options => { }); + services.AddDbContext(options => { }); + + services.AddIdentityCore(options => { }) + .AddEntityFrameworkStores() + .AddSignInManager() + .AddDefaultTokenProviders(); + + return services; + } + + public static IServiceCollection AddOqtaneAuthorizationPolicies(this IServiceCollection services) + { + services.AddAuthorizationCore(options => + { + options.AddPolicy(PolicyNames.ViewPage, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Page, PermissionNames.View))); + options.AddPolicy(PolicyNames.EditPage, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Page, PermissionNames.Edit))); + options.AddPolicy(PolicyNames.ViewModule, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Module, PermissionNames.View))); + options.AddPolicy(PolicyNames.EditModule, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Module, PermissionNames.Edit))); + options.AddPolicy(PolicyNames.ViewFolder, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Folder, PermissionNames.View))); + options.AddPolicy(PolicyNames.EditFolder, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Folder, PermissionNames.Edit))); + options.AddPolicy(PolicyNames.ListFolder, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Folder, PermissionNames.Browse))); + }); + + return services; + } + + internal static IServiceCollection AddOqtaneScopedServices(this IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + return services; + } + + internal static IServiceCollection AddOqtaneSingletonServices(this IServiceCollection services, IConfigurationRoot configurationRoot) + { + services.AddSingleton(configurationRoot); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + return services; + } + + internal static IServiceCollection AddOqtaneTransientServices(this IServiceCollection services) + { + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + return services; + } + + public static IServiceCollection ConfigureOqtaneCookieOptions(this IServiceCollection services) + { + services.ConfigureApplicationCookie(options => + { + options.Cookie.HttpOnly = false; + options.Events.OnRedirectToLogin = context => + { + context.Response.StatusCode = 401; + + return Task.CompletedTask; + }; + }); + + return services; + } + + public static IServiceCollection ConfigureOqtaneIdentityOptions(this IServiceCollection services) + { + services.Configure(options => + { + // Password settings + options.Password.RequireDigit = false; + options.Password.RequiredLength = 6; + options.Password.RequireNonAlphanumeric = false; + options.Password.RequireUppercase = false; + options.Password.RequireLowercase = false; + + // Lockout settings + options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30); + options.Lockout.MaxFailedAccessAttempts = 10; + options.Lockout.AllowedForNewUsers = true; + + // User settings + options.User.RequireUniqueEmail = false; + }); + + return services; + } + + internal static IServiceCollection TryAddHttpClientWithAuthenticationCookie(this IServiceCollection services) + { + if (!services.Any(x => x.ServiceType == typeof(HttpClient))) + { + services.AddScoped(s => + { + // creating the URI helper needs to wait until the JS Runtime is initialized, so defer it. + var navigationManager = s.GetRequiredService(); + var httpContextAccessor = s.GetRequiredService(); + var authToken = httpContextAccessor.HttpContext.Request.Cookies[".AspNetCore.Identity.Application"]; + var client = new HttpClient(new HttpClientHandler { UseCookies = false }); + if (authToken != null) + { + client.DefaultRequestHeaders.Add("Cookie", ".AspNetCore.Identity.Application=" + authToken); + } + + client.BaseAddress = new Uri(navigationManager.Uri); + + return client; + }); + } + + return services; + } + + internal static IServiceCollection TryAddSwagger(this IServiceCollection services, bool useSwagger) + { + if (useSwagger) + { + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Oqtane", Version = "v1" }); + }); + } + + return services; + } + private static IServiceCollection AddOqtaneServices(this IServiceCollection services, Runtime runtime) { if (services is null) diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 1e744c01..f2c44365 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -1,35 +1,25 @@ using System; -using System.Collections; using System.IO; -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.OpenApi.Models; using Oqtane.Extensions; using Oqtane.Infrastructure; -using Oqtane.Repository; using Oqtane.Security; -using Oqtane.Services; using Oqtane.Shared; namespace Oqtane { public class Startup { - private Runtime _runtime; - private bool _useSwagger; - private IWebHostEnvironment _env; - private string[] _supportedCultures; + private readonly Runtime _runtime; + private readonly bool _useSwagger; + private readonly IWebHostEnvironment _env; + private readonly string[] _supportedCultures; public IConfigurationRoot Configuration { get; } @@ -59,157 +49,46 @@ namespace Oqtane // Register localization services services.AddLocalization(options => options.ResourcesPath = "Resources"); - services.AddServerSideBlazor().AddCircuitOptions(options => - { - if (_env.IsDevelopment()) + services.AddServerSideBlazor() + .AddCircuitOptions(options => { - options.DetailedErrors = true; - } - }); + if (_env.IsDevelopment()) + { + options.DetailedErrors = true; + } + }); // setup HttpClient for server side in a client side compatible fashion ( with auth cookie ) - if (!services.Any(x => x.ServiceType == typeof(HttpClient))) - { - services.AddScoped(s => - { - // creating the URI helper needs to wait until the JS Runtime is initialized, so defer it. - var navigationManager = s.GetRequiredService(); - var httpContextAccessor = s.GetRequiredService(); - var authToken = httpContextAccessor.HttpContext.Request.Cookies[".AspNetCore.Identity.Application"]; - var client = new HttpClient(new HttpClientHandler {UseCookies = false}); - if (authToken != null) - { - client.DefaultRequestHeaders.Add("Cookie", ".AspNetCore.Identity.Application=" + authToken); - } - client.BaseAddress = new Uri(navigationManager.Uri); - return client; - }); - } + services.TryAddHttpClientWithAuthenticationCookie(); // register custom authorization policies - services.AddAuthorizationCore(options => - { - options.AddPolicy(PolicyNames.ViewPage, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Page, PermissionNames.View))); - options.AddPolicy(PolicyNames.EditPage, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Page, PermissionNames.Edit))); - options.AddPolicy(PolicyNames.ViewModule, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Module, PermissionNames.View))); - options.AddPolicy(PolicyNames.EditModule, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Module, PermissionNames.Edit))); - options.AddPolicy(PolicyNames.ViewFolder, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Folder, PermissionNames.View))); - options.AddPolicy(PolicyNames.EditFolder, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Folder, PermissionNames.Edit))); - options.AddPolicy(PolicyNames.ListFolder, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Folder, PermissionNames.Browse))); - }); + services.AddOqtaneAuthorizationPolicies(); // register scoped core services - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); + services.AddOqtaneScopedServices(); services.AddSingleton(); - services.AddDbContext(options => { }); - services.AddDbContext(options => { }); + services.AddOqtaneDbContext(); - services.AddIdentityCore(options => { }) - .AddEntityFrameworkStores() - .AddSignInManager() - .AddDefaultTokenProviders(); - - services.Configure(options => - { - // Password settings - options.Password.RequireDigit = false; - options.Password.RequiredLength = 6; - options.Password.RequireNonAlphanumeric = false; - options.Password.RequireUppercase = false; - options.Password.RequireLowercase = false; - - // Lockout settings - options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30); - options.Lockout.MaxFailedAccessAttempts = 10; - options.Lockout.AllowedForNewUsers = true; - - // User settings - options.User.RequireUniqueEmail = false; - }); + services.ConfigureOqtaneIdentityOptions(); services.AddAuthentication(IdentityConstants.ApplicationScheme) .AddCookie(IdentityConstants.ApplicationScheme); - services.ConfigureApplicationCookie(options => - { - options.Cookie.HttpOnly = false; - options.Events.OnRedirectToLogin = context => - { - context.Response.StatusCode = 401; - return Task.CompletedTask; - }; - }); + services.ConfigureOqtaneCookieOptions(); // register custom claims principal factory for role claims services.AddTransient, ClaimsPrincipalFactory>(); // register singleton scoped core services - services.AddSingleton(Configuration); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddOqtaneSingletonServices(Configuration); // 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); // register transient scoped core services - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddOqtaneTransientServices(); // load the external assemblies into the app domain, install services services.AddOqtane(_runtime, _supportedCultures); @@ -219,10 +98,7 @@ namespace Oqtane .AddOqtaneApplicationParts() // register any Controllers from custom modules .ConfigureOqtaneMvc(); // any additional configuration from IStart classes. - if (_useSwagger) - { - services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo {Title = "Oqtane", Version = "v1"}); }); - } + services.TryAddSwagger(_useSwagger); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. From a018e853a8173327fcc7b07538c548f8fbbcceff Mon Sep 17 00:00:00 2001 From: hishamco Date: Sun, 18 Apr 2021 02:27:31 +0300 Subject: [PATCH 02/22] Register configuration in startup --- Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs | 4 +--- Oqtane.Server/Startup.cs | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index c429b282..bfa20cd5 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; using Oqtane.Infrastructure; @@ -96,9 +95,8 @@ namespace Microsoft.Extensions.DependencyInjection return services; } - internal static IServiceCollection AddOqtaneSingletonServices(this IServiceCollection services, IConfigurationRoot configurationRoot) + internal static IServiceCollection AddOqtaneSingletonServices(this IServiceCollection services) { - services.AddSingleton(configurationRoot); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index f2c44365..1a5de4df 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -82,7 +82,8 @@ namespace Oqtane services.AddTransient, ClaimsPrincipalFactory>(); // register singleton scoped core services - services.AddOqtaneSingletonServices(Configuration); + services.AddSingleton(Configuration) + .AddOqtaneSingletonServices(); // 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); From f7d8888232ea875fdbb6a2c4698ca44a83137228 Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 20 Apr 2021 19:01:56 +0300 Subject: [PATCH 03/22] Refactor Program.cs --- .../OqtaneServiceCollectionExtensions.cs | 52 +++++++ Oqtane.Client/Program.cs | 128 ++++++++---------- .../OqtaneServiceCollectionExtensions.cs | 1 - 3 files changed, 112 insertions(+), 69 deletions(-) create mode 100644 Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs diff --git a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs new file mode 100644 index 00000000..e06b991e --- /dev/null +++ b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs @@ -0,0 +1,52 @@ +using Microsoft.AspNetCore.Components.Authorization; +using Oqtane.Providers; +using Oqtane.Services; +using Oqtane.Shared; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class OqtaneServiceCollectionExtensions + { + public static IServiceCollection AddOqtaneAuthorization(this IServiceCollection services) + { + services.AddAuthorizationCore(); + services.AddScoped(); + services.AddScoped(s => s.GetRequiredService()); + + return services; + } + + internal static IServiceCollection AddOqtaneScopedServices(this IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + return services; + } + } +} diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index fdc5145f..184ff75d 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -8,14 +8,12 @@ using System.Net.Http; using System.Reflection; using System.Runtime.Loader; using System.Threading.Tasks; -using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using Microsoft.AspNetCore.Localization; using Microsoft.Extensions.DependencyInjection; using Microsoft.JSInterop; using Oqtane.Interfaces; using Oqtane.Modules; -using Oqtane.Providers; using Oqtane.Services; using Oqtane.Shared; using Oqtane.UI; @@ -28,7 +26,8 @@ namespace Oqtane.Client { var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add("app"); - HttpClient httpClient = new HttpClient {BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)}; + + var httpClient = new HttpClient {BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)}; builder.Services.AddSingleton(httpClient); builder.Services.AddOptions(); @@ -37,38 +36,10 @@ namespace Oqtane.Client builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); // register auth services - builder.Services.AddAuthorizationCore(); - builder.Services.AddScoped(); - builder.Services.AddScoped(s => s.GetRequiredService()); + builder.Services.AddOqtaneAuthorization(); // register scoped core services - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); + builder.Services.AddOqtaneScopedServices(); await LoadClientAssemblies(httpClient); @@ -76,49 +47,18 @@ namespace Oqtane.Client foreach (var assembly in assemblies) { // dynamically register module services - var implementationTypes = assembly.GetInterfaces(); - foreach (var implementationType in implementationTypes) - { - if (implementationType.AssemblyQualifiedName != null) - { - var serviceType = Type.GetType(implementationType.AssemblyQualifiedName.Replace(implementationType.Name, $"I{implementationType.Name}")); - builder.Services.AddScoped(serviceType ?? implementationType, implementationType); - } - } + RegisterModuleServices(assembly, builder.Services); // dynamically register database providers - var databaseTypes = assembly.GetInterfaces(); - foreach (var databaseType in databaseTypes) - { - if (databaseType.AssemblyQualifiedName != null) - { - var serviceType = Type.GetType("Oqtane.Interfaces.IDatabase, Oqtane.Shared"); - builder.Services.AddScoped(serviceType ?? databaseType, databaseType); - } - } + RegisterDatabaseProviders(assembly, builder.Services); // register client startup services - var startUps = assembly.GetInstances(); - foreach (var startup in startUps) - { - startup.ConfigureServices(builder.Services); - } + RegisterClientStartups(assembly, builder.Services); } var host = builder.Build(); - var jsRuntime = host.Services.GetRequiredService(); - var interop = new Interop(jsRuntime); - var localizationCookie = await interop.GetCookie(CookieRequestCultureProvider.DefaultCookieName); - var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie).UICultures[0].Value; - var localizationService = host.Services.GetRequiredService(); - var cultures = await localizationService.GetCulturesAsync(); - if (culture == null || !cultures.Any(c => c.Name.Equals(culture, StringComparison.OrdinalIgnoreCase))) - { - culture = cultures.Single(c => c.IsDefault).Name; - } - - SetCulture(culture); + await SetCultureFromLocalizationCookie(host.Services); ServiceActivator.Configure(host.Services); @@ -174,6 +114,58 @@ namespace Oqtane.Client } } + private static void RegisterModuleServices(Assembly assembly, IServiceCollection services) + { + var implementationTypes = assembly.GetInterfaces(); + foreach (var implementationType in implementationTypes) + { + if (implementationType.AssemblyQualifiedName != null) + { + var serviceType = Type.GetType(implementationType.AssemblyQualifiedName.Replace(implementationType.Name, $"I{implementationType.Name}")); + services.AddScoped(serviceType ?? implementationType, implementationType); + } + } + } + + private static void RegisterDatabaseProviders(Assembly assembly, IServiceCollection services) + { + var databaseTypes = assembly.GetInterfaces(); + foreach (var databaseType in databaseTypes) + { + if (databaseType.AssemblyQualifiedName != null) + { + var serviceType = Type.GetType("Oqtane.Interfaces.IDatabase, Oqtane.Shared"); + services.AddScoped(serviceType ?? databaseType, databaseType); + } + } + } + + private static void RegisterClientStartups(Assembly assembly, IServiceCollection services) + { + var startUps = assembly.GetInstances(); + foreach (var startup in startUps) + { + startup.ConfigureServices(services); + } + } + + private static async Task SetCultureFromLocalizationCookie(IServiceProvider serviceProvider) + { + var jsRuntime = serviceProvider.GetRequiredService(); + var interop = new Interop(jsRuntime); + var localizationCookie = await interop.GetCookie(CookieRequestCultureProvider.DefaultCookieName); + var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie).UICultures[0].Value; + var localizationService = serviceProvider.GetRequiredService(); + var cultures = await localizationService.GetCulturesAsync(); + + if (culture == null || !cultures.Any(c => c.Name.Equals(culture, StringComparison.OrdinalIgnoreCase))) + { + culture = cultures.Single(c => c.IsDefault).Name; + } + + SetCulture(culture); + } + private static void SetCulture(string culture) { var cultureInfo = CultureInfo.GetCultureInfo(culture); diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 432d01c3..6dd5186e 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -19,7 +19,6 @@ using Oqtane.Security; using Oqtane.Services; using Oqtane.Shared; -// ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection { public static class OqtaneServiceCollectionExtensions From 97fb6ede7ea4abc587d340722094e9f236e5697b Mon Sep 17 00:00:00 2001 From: hishamco Date: Tue, 20 Apr 2021 19:10:06 +0300 Subject: [PATCH 04/22] Reuse AddOqtaneScopedServices() --- Oqtane.Client/AssemblyInfo.cs | 4 ++- .../OqtaneServiceCollectionExtensions.cs | 34 ------------------- Oqtane.Server/Startup.cs | 4 ++- 3 files changed, 6 insertions(+), 36 deletions(-) diff --git a/Oqtane.Client/AssemblyInfo.cs b/Oqtane.Client/AssemblyInfo.cs index d598bfb9..159ad127 100644 --- a/Oqtane.Client/AssemblyInfo.cs +++ b/Oqtane.Client/AssemblyInfo.cs @@ -1,3 +1,5 @@ -using Microsoft.Extensions.Localization; +using System.Runtime.CompilerServices; +using Microsoft.Extensions.Localization; [assembly: RootNamespace("Oqtane")] +[assembly: InternalsVisibleTo("Oqtane.Server")] diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 6dd5186e..fa438356 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -57,40 +57,6 @@ namespace Microsoft.Extensions.DependencyInjection return services; } - internal static IServiceCollection AddOqtaneScopedServices(this IServiceCollection services) - { - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - return services; - } - internal static IServiceCollection AddOqtaneSingletonServices(this IServiceCollection services) { services.AddSingleton(); diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 9793510c..6f86bcc4 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -65,7 +66,8 @@ namespace Oqtane services.AddOqtaneAuthorizationPolicies(); // register scoped core services - services.AddOqtaneScopedServices(); + services.AddScoped() + .AddOqtaneScopedServices(); services.AddSingleton(); From 7c181b65cd32b7a7003206a93267a8b22bc1342b Mon Sep 17 00:00:00 2001 From: hishamco Date: Sat, 12 Jun 2021 00:18:57 +0300 Subject: [PATCH 05/22] Fix merge conflict --- .../OqtaneServiceCollectionExtensions.cs | 2 ++ Oqtane.Client/Program.cs | 16 ---------------- .../OqtaneServiceCollectionExtensions.cs | 16 +++++++++++++--- Oqtane.Server/Startup.cs | 6 ++---- 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs index e06b991e..40db5da5 100644 --- a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs @@ -45,6 +45,8 @@ namespace Microsoft.Extensions.DependencyInjection services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); return services; } diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index cbb1e60c..ff27f5c0 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -48,9 +48,6 @@ namespace Oqtane.Client // dynamically register module services RegisterModuleServices(assembly, builder.Services); - // dynamically register database providers - RegisterDatabaseProviders(assembly, builder.Services); - // register client startup services RegisterClientStartups(assembly, builder.Services); } @@ -126,19 +123,6 @@ namespace Oqtane.Client } } - private static void RegisterDatabaseProviders(Assembly assembly, IServiceCollection services) - { - var databaseTypes = assembly.GetInterfaces(); - foreach (var databaseType in databaseTypes) - { - if (databaseType.AssemblyQualifiedName != null) - { - var serviceType = Type.GetType("Oqtane.Interfaces.IDatabase, Oqtane.Shared"); - services.AddScoped(serviceType ?? databaseType, databaseType); - } - } - } - private static void RegisterClientStartups(Assembly assembly, IServiceCollection services) { var startUps = assembly.GetInstances(); diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 92bcb688..d939110b 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using System.Net; using System.Net.Http; using System.Reflection; using System.Runtime.Loader; @@ -34,7 +35,6 @@ namespace Microsoft.Extensions.DependencyInjection public static IServiceCollection AddOqtaneDbContext(this IServiceCollection services) { - services.AddScoped(); services.AddDbContext(options => { }); services.AddDbContext(options => { }); @@ -62,6 +62,7 @@ namespace Microsoft.Extensions.DependencyInjection services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); return services; } @@ -96,6 +97,8 @@ namespace Microsoft.Extensions.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + // obsolete - replaced by ITenantManager + services.AddTransient(); return services; } @@ -105,12 +108,19 @@ namespace Microsoft.Extensions.DependencyInjection services.ConfigureApplicationCookie(options => { options.Cookie.HttpOnly = false; + options.Cookie.SameSite = SameSiteMode.Strict; + options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; options.Events.OnRedirectToLogin = context => { - context.Response.StatusCode = 401; - + context.Response.StatusCode = (int)HttpStatusCode.Forbidden; return Task.CompletedTask; }; + options.Events.OnRedirectToAccessDenied = context => + { + context.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return Task.CompletedTask; + }; + options.Events.OnValidatePrincipal = PrincipalValidator.ValidateAsync; }); return services; diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index fec5fa6e..d1fa176f 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -1,10 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -56,6 +52,8 @@ namespace Oqtane // Register localization services services.AddLocalization(options => options.ResourcesPath = "Resources"); + services.AddOptions>().Bind(Configuration.GetSection(SettingKeys.AvailableDatabasesSection)); + services.AddServerSideBlazor() .AddCircuitOptions(options => { From 28694fc11f7c30bd92d68d7d8cd750cd95984439 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Mon, 14 Jun 2021 17:29:23 -0400 Subject: [PATCH 06/22] added defensive logic to app.razor, relocated shared resource definition in preparation for utilizing shared resources --- Oqtane.Client/App.razor | 9 +++- Oqtane.Client/Localization/SharedResources.cs | 47 ------------------- Oqtane.Client/Resources/.gitkeep | 0 Oqtane.Client/Resources/SharedResources.cs | 7 +++ Oqtane.Server/Pages/_Host.cshtml | 7 --- Oqtane.Server/Pages/_Host.cshtml.cs | 1 - Oqtane.Server/Repository/SiteRepository.cs | 43 +++++++++-------- 7 files changed, 36 insertions(+), 78 deletions(-) delete mode 100644 Oqtane.Client/Localization/SharedResources.cs delete mode 100644 Oqtane.Client/Resources/.gitkeep create mode 100644 Oqtane.Client/Resources/SharedResources.cs diff --git a/Oqtane.Client/App.razor b/Oqtane.Client/App.razor index 405bbd3a..01022680 100644 --- a/Oqtane.Client/App.razor +++ b/Oqtane.Client/App.razor @@ -40,7 +40,14 @@ var interop = new Interop(JSRuntime); SiteState.AntiForgeryToken = await interop.GetElementByName(Constants.RequestVerificationToken); _installation = await InstallationService.IsInstalled(); - SiteState.Alias = _installation.Alias; + if (_installation.Alias != null) + { + SiteState.Alias = _installation.Alias; + } + else + { + _installation.Message = "Site Not Configured Correctly - No Matching Alias Exists For Host Name"; + } _initialized = true; StateHasChanged(); } diff --git a/Oqtane.Client/Localization/SharedResources.cs b/Oqtane.Client/Localization/SharedResources.cs deleted file mode 100644 index 77cb9d36..00000000 --- a/Oqtane.Client/Localization/SharedResources.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace Oqtane -{ - public class SharedResources - { - public static readonly string UserLogin = "User Login"; - - public static readonly string UserRegistration = "User Registration"; - - public static readonly string PasswordReset = "Password Reset"; - - public static readonly string UserProfile = "User Profile"; - - public static readonly string AdminDashboard = "Admin Dashboard"; - - public static readonly string SiteSettings = "Site Settings"; - - public static readonly string PageManagement = "Page Management"; - - public static readonly string UserManagement = "User Management"; - - public static readonly string ProfileManagement = "Profile Management"; - - public static readonly string RoleManagement = "Role Management"; - - public static readonly string FileManagement = "File Management"; - - public static readonly string RecycleBin = "Recycle Bin"; - - public static readonly string EventLog = "Event Log"; - - public static readonly string SiteManagement = "Site Management"; - - public static readonly string ModuleManagement = "Module Management"; - - public static readonly string ThemeManagement = "Theme Management"; - - public static readonly string LanguageManagement = "Language Management"; - - public static readonly string ScheduledJobs = "Scheduled Jobs"; - - public static readonly string SqlManagement = "Sql Management"; - - public static readonly string SystemInfo = "System Info"; - - public static readonly string SystemUpdate = "System Update"; - } -} diff --git a/Oqtane.Client/Resources/.gitkeep b/Oqtane.Client/Resources/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/Oqtane.Client/Resources/SharedResources.cs b/Oqtane.Client/Resources/SharedResources.cs new file mode 100644 index 00000000..2c1d6f25 --- /dev/null +++ b/Oqtane.Client/Resources/SharedResources.cs @@ -0,0 +1,7 @@ +namespace Oqtane +{ + public class SharedResources + { + + } +} diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml index ccb24679..cfd3b78c 100644 --- a/Oqtane.Server/Pages/_Host.cshtml +++ b/Oqtane.Server/Pages/_Host.cshtml @@ -34,13 +34,6 @@ 🗙 - @if (Model.Message != "") - { -
- @Model.Message -
- } - @if (Model.Runtime == "WebAssembly") diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs index 7537831f..c0333760 100644 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ b/Oqtane.Server/Pages/_Host.cshtml.cs @@ -38,7 +38,6 @@ namespace Oqtane.Pages public RenderMode RenderMode = RenderMode.Server; public string HeadResources = ""; public string BodyResources = ""; - public string Message = ""; public void OnGet() { diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index 98c5feab..6200de2c 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -5,7 +5,6 @@ using System.Linq; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Localization; using Oqtane.Extensions; using Oqtane.Infrastructure; using Oqtane.Models; @@ -67,7 +66,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = SharedResources.UserLogin, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "User Login", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -96,7 +95,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Register.Index).ToModuleDefinitionName(), Title = SharedResources.UserRegistration, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Register.Index).ToModuleDefinitionName(), Title = "User Registration", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -126,7 +125,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Reset.Index).ToModuleDefinitionName(), Title = SharedResources.PasswordReset, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Reset.Index).ToModuleDefinitionName(), Title = "Password Reset", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -155,7 +154,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UserProfile.Index).ToModuleDefinitionName(), Title = SharedResources.UserProfile, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UserProfile.Index).ToModuleDefinitionName(), Title = "User Profile", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -180,7 +179,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Dashboard.Index).ToModuleDefinitionName(), Title = SharedResources.AdminDashboard, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Dashboard.Index).ToModuleDefinitionName(), Title = "Admin Dashboard", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -207,7 +206,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Site.Index).ToModuleDefinitionName(), Title = SharedResources.SiteSettings, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Site.Index).ToModuleDefinitionName(), Title = "Site Settings", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -234,7 +233,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Pages.Index).ToModuleDefinitionName(), Title = SharedResources.PageManagement, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Pages.Index).ToModuleDefinitionName(), Title = "Page Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -261,7 +260,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Users.Index).ToModuleDefinitionName(), Title = SharedResources.UserManagement, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Users.Index).ToModuleDefinitionName(), Title = "User Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -288,7 +287,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Profiles.Index).ToModuleDefinitionName(), Title = SharedResources.ProfileManagement, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Profiles.Index).ToModuleDefinitionName(), Title = "Profile Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -315,7 +314,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Roles.Index).ToModuleDefinitionName(), Title = SharedResources.RoleManagement, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Roles.Index).ToModuleDefinitionName(), Title = "Role Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -342,7 +341,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Files.Index).ToModuleDefinitionName(), Title = SharedResources.FileManagement, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Files.Index).ToModuleDefinitionName(), Title = "File Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -369,7 +368,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.RecycleBin.Index).ToModuleDefinitionName(), Title = SharedResources.RecycleBin, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.RecycleBin.Index).ToModuleDefinitionName(), Title = "Recycle Bin", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -398,7 +397,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Logs.Index).ToModuleDefinitionName(), Title = SharedResources.EventLog, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Logs.Index).ToModuleDefinitionName(), Title = "Event Log", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -420,7 +419,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sites.Index).ToModuleDefinitionName(), Title = SharedResources.SiteManagement, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sites.Index).ToModuleDefinitionName(), Title = "Site Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -442,7 +441,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.ModuleDefinitions.Index).ToModuleDefinitionName(), Title = SharedResources.ModuleManagement, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.ModuleDefinitions.Index).ToModuleDefinitionName(), Title = "Module Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -464,7 +463,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Themes.Index).ToModuleDefinitionName(), Title = SharedResources.ThemeManagement, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Themes.Index).ToModuleDefinitionName(), Title = "Theme Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -493,7 +492,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Languages.Index).ToModuleDefinitionName(), Title = SharedResources.LanguageManagement, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Languages.Index).ToModuleDefinitionName(), Title = "Language Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -517,7 +516,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Jobs.Index).ToModuleDefinitionName(), Title = SharedResources.ScheduledJobs, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Jobs.Index).ToModuleDefinitionName(), Title = "Scheduled Jobs", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -539,7 +538,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sql.Index).ToModuleDefinitionName(), Title = SharedResources.SqlManagement, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sql.Index).ToModuleDefinitionName(), Title = "Sql Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -561,7 +560,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.SystemInfo.Index).ToModuleDefinitionName(), Title = SharedResources.SystemInfo, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.SystemInfo.Index).ToModuleDefinitionName(), Title = "System Info", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -583,7 +582,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Upgrade.Index).ToModuleDefinitionName(), Title = SharedResources.SystemUpdate, Pane = PaneNames.Admin, + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Upgrade.Index).ToModuleDefinitionName(), Title = "System Update", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), From f2b3d6bc5f695d19df68c159ed1e3bfe5ce8cd8a Mon Sep 17 00:00:00 2001 From: Leigh Date: Tue, 15 Jun 2021 07:09:22 +0200 Subject: [PATCH 07/22] SharedResources to reside at the project root. Namespace was changed from Oqtane to Oqtane.Client --- Oqtane.Client/Oqtane.Client.csproj | 4 ++++ Oqtane.Client/Resources/SharedResources.cs | 7 ------- Oqtane.Client/SharedResources.cs | 13 +++++++++++++ 3 files changed, 17 insertions(+), 7 deletions(-) delete mode 100644 Oqtane.Client/Resources/SharedResources.cs create mode 100644 Oqtane.Client/SharedResources.cs diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index 24e2efb7..f589591a 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -33,4 +33,8 @@ + + + + diff --git a/Oqtane.Client/Resources/SharedResources.cs b/Oqtane.Client/Resources/SharedResources.cs deleted file mode 100644 index 2c1d6f25..00000000 --- a/Oqtane.Client/Resources/SharedResources.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Oqtane -{ - public class SharedResources - { - - } -} diff --git a/Oqtane.Client/SharedResources.cs b/Oqtane.Client/SharedResources.cs new file mode 100644 index 00000000..83390e8a --- /dev/null +++ b/Oqtane.Client/SharedResources.cs @@ -0,0 +1,13 @@ +namespace Oqtane.Client +{ + /// + /// Dummy class used to collect shared resource strings for this application + /// + /// + /// This class is mostly used with IStringLocalizer and IHtmlLocalizer interfaces. + /// The class must reside at the project root. + /// + public class SharedResources + { + } +} From 9558894a4f485daef33c69a2b76233e9efc10aa3 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 15 Jun 2021 07:43:12 -0400 Subject: [PATCH 08/22] moved SharedResources class to proper location --- Oqtane.Client/Resources/SharedResources.resx | 207 ++++++++++++++++++ .../{Resources => }/SharedResources.cs | 0 2 files changed, 207 insertions(+) create mode 100644 Oqtane.Client/Resources/SharedResources.resx rename Oqtane.Client/{Resources => }/SharedResources.cs (100%) diff --git a/Oqtane.Client/Resources/SharedResources.resx b/Oqtane.Client/Resources/SharedResources.resx new file mode 100644 index 00000000..5296443a --- /dev/null +++ b/Oqtane.Client/Resources/SharedResources.resx @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + False + + + Yes + + + No + + + Save + + + Update + + + Delete + + + Cancel + + + Admin Dashboard + + + User Login + + + User Registration + + + Password Reset + + + User Profile + + + Site Settings + + + Page Management + + + User Management + + + Profile Management + + + Role Management + + + File Management + + + Recycle Bin + + + Event Log + + + Site Management + + + Module Management + + + Theme Management + + + Language Management + + + Scheduled Jobs + + + Sql Management + + + System Info + + + System Update + + \ No newline at end of file diff --git a/Oqtane.Client/Resources/SharedResources.cs b/Oqtane.Client/SharedResources.cs similarity index 100% rename from Oqtane.Client/Resources/SharedResources.cs rename to Oqtane.Client/SharedResources.cs From 0fd16fbb59914f82b7c8e30ce50e6027e8487356 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 15 Jun 2021 07:59:05 -0400 Subject: [PATCH 09/22] added Oqtane.Client to _Imports so it can find the new SharedResources class --- Oqtane.Client/_Imports.razor | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Oqtane.Client/_Imports.razor b/Oqtane.Client/_Imports.razor index cbf43e76..45403934 100644 --- a/Oqtane.Client/_Imports.razor +++ b/Oqtane.Client/_Imports.razor @@ -10,6 +10,7 @@ @using Microsoft.Extensions.Localization @using Microsoft.JSInterop +@using Oqtane.Client @using Oqtane.Models @using Oqtane.Modules @using Oqtane.Modules.Controls @@ -22,3 +23,4 @@ @using Oqtane.UI @using Oqtane.Enums @using Oqtane.Installer +@using Oqtane.Interfaces From f6cc11bd3b8d59a9803853e5ca19ded53487394c Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 15 Jun 2021 08:23:26 -0400 Subject: [PATCH 10/22] add logic removed in #1245 back to HttpClient creation --- .../OqtaneServiceCollectionExtensions.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index d939110b..812dc0d8 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -6,14 +6,12 @@ using System.Net.Http; using System.Reflection; using System.Runtime.Loader; using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; using Oqtane.Infrastructure; -using Oqtane.Interfaces; using Oqtane.Modules; using Oqtane.Repository; using Oqtane.Security; @@ -157,16 +155,16 @@ namespace Microsoft.Extensions.DependencyInjection { // creating the URI helper needs to wait until the JS Runtime is initialized, so defer it. var navigationManager = s.GetRequiredService(); - var httpContextAccessor = s.GetRequiredService(); - var authToken = httpContextAccessor.HttpContext.Request.Cookies[".AspNetCore.Identity.Application"]; var client = new HttpClient(new HttpClientHandler { UseCookies = false }); - if (authToken != null) - { - client.DefaultRequestHeaders.Add("Cookie", ".AspNetCore.Identity.Application=" + authToken); - } - client.BaseAddress = new Uri(navigationManager.Uri); + // set the cookies to allow HttpClient API calls to be authenticated + var httpContextAccessor = s.GetRequiredService(); + foreach (var cookie in httpContextAccessor.HttpContext.Request.Cookies) + { + client.DefaultRequestHeaders.Add("Cookie", cookie.Key + "=" + cookie.Value); + } + return client; }); } From 0a2293119ed07cd8be2634abf7ed94abbef28b10 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 15 Jun 2021 08:32:39 -0400 Subject: [PATCH 11/22] added back missing ITenantManager registration removed in #1245 --- Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 812dc0d8..0f8ba283 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -67,6 +67,7 @@ namespace Microsoft.Extensions.DependencyInjection internal static IServiceCollection AddOqtaneTransientServices(this IServiceCollection services) { + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); From ffbabcfb287803ae628fade337e289a4747bef90 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 15 Jun 2021 09:18:17 -0400 Subject: [PATCH 12/22] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index c36daac5..782b97c3 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,6 @@ V.2.1.0 ( Jun 4, 2021 ) - [x] Centralize package installation and uninstall - [x] Enable pre-rendering support for Blazor Server - [x] Allow run-time installation of Language packages -- [x] Add support for Shared localization resources V.2.0.2 ( Apr 19, 2021 ) - [x] Assorted fixes and user experience improvements From 65a14da5a918a34f5a063dfc57e5a07c2944ef77 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 15 Jun 2021 19:11:00 -0400 Subject: [PATCH 13/22] improve validation and exception handling in API Controllers --- .../Modules/Admin/Dashboard/Index.razor | 4 +- .../Services/Interfaces/IJobLogService.cs | 8 +--- .../Services/Interfaces/ITenantService.cs | 21 --------- Oqtane.Client/Services/JobLogService.cs | 14 ------ Oqtane.Client/Services/TenantService.cs | 15 ------ Oqtane.Server/Controllers/AliasController.cs | 15 ++++-- Oqtane.Server/Controllers/JobController.cs | 46 ++++++++++++++++--- Oqtane.Server/Controllers/JobLogController.cs | 41 +---------------- Oqtane.Server/Controllers/TenantController.cs | 35 -------------- Oqtane.Server/Controllers/ThemeController.cs | 12 +++++ Oqtane.Server/Repository/AliasRepository.cs | 19 ++++++-- .../Repository/Interfaces/IAliasRepository.cs | 3 +- .../Repository/Interfaces/IJobRepository.cs | 3 +- Oqtane.Server/Repository/JobRepository.cs | 15 +++++- 14 files changed, 101 insertions(+), 150 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Dashboard/Index.razor b/Oqtane.Client/Modules/Admin/Dashboard/Index.razor index 0c7cd842..6c665ba2 100644 --- a/Oqtane.Client/Modules/Admin/Dashboard/Index.razor +++ b/Oqtane.Client/Modules/Admin/Dashboard/Index.razor @@ -2,7 +2,7 @@ @inherits ModuleBase @inject IPageService PageService @inject IUserService UserService -@inject IStringLocalizer Localizer +@inject IStringLocalizer SharedLocalizer
@foreach (var p in _pages) @@ -12,7 +12,7 @@ string url = NavigateUrl(p.Path);
-

@Localizer[p.Name] +

@SharedLocalizer[p.Name]
} diff --git a/Oqtane.Client/Services/Interfaces/IJobLogService.cs b/Oqtane.Client/Services/Interfaces/IJobLogService.cs index 015d83f0..e198bf9f 100644 --- a/Oqtane.Client/Services/Interfaces/IJobLogService.cs +++ b/Oqtane.Client/Services/Interfaces/IJobLogService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Collections.Generic; using System.Threading.Tasks; @@ -9,11 +9,5 @@ namespace Oqtane.Services Task> GetJobLogsAsync(); Task GetJobLogAsync(int jobLogId); - - Task AddJobLogAsync(JobLog jobLog); - - Task UpdateJobLogAsync(JobLog jobLog); - - Task DeleteJobLogAsync(int jobLogId); } } diff --git a/Oqtane.Client/Services/Interfaces/ITenantService.cs b/Oqtane.Client/Services/Interfaces/ITenantService.cs index 12738f58..cbb4e526 100644 --- a/Oqtane.Client/Services/Interfaces/ITenantService.cs +++ b/Oqtane.Client/Services/Interfaces/ITenantService.cs @@ -21,26 +21,5 @@ namespace Oqtane.Services /// ID-reference of the /// Task GetTenantAsync(int tenantId); - - /// - /// Add / save another to the database - /// - /// A object containing the configuration - /// - Task AddTenantAsync(Tenant tenant); - - /// - /// Update the information in the database. - /// - /// - /// - Task UpdateTenantAsync(Tenant tenant); - - /// - /// Delete / remove a - /// - /// - /// - Task DeleteTenantAsync(int tenantId); } } diff --git a/Oqtane.Client/Services/JobLogService.cs b/Oqtane.Client/Services/JobLogService.cs index 6d9a3e56..6c2f0a73 100644 --- a/Oqtane.Client/Services/JobLogService.cs +++ b/Oqtane.Client/Services/JobLogService.cs @@ -30,19 +30,5 @@ namespace Oqtane.Services { return await GetJsonAsync($"{Apiurl}/{jobLogId}"); } - - public async Task AddJobLogAsync(JobLog joblog) - { - return await PostJsonAsync(Apiurl, joblog); - } - - public async Task UpdateJobLogAsync(JobLog joblog) - { - return await PutJsonAsync($"{Apiurl}/{joblog.JobLogId}", joblog); - } - public async Task DeleteJobLogAsync(int jobLogId) - { - await DeleteAsync($"{Apiurl}/{jobLogId}"); - } } } diff --git a/Oqtane.Client/Services/TenantService.cs b/Oqtane.Client/Services/TenantService.cs index 52b3d345..6c02b9a9 100644 --- a/Oqtane.Client/Services/TenantService.cs +++ b/Oqtane.Client/Services/TenantService.cs @@ -30,20 +30,5 @@ namespace Oqtane.Services { return await GetJsonAsync($"{Apiurl}/{tenantId}"); } - - public async Task AddTenantAsync(Tenant tenant) - { - return await PostJsonAsync(Apiurl, tenant); - } - - public async Task UpdateTenantAsync(Tenant tenant) - { - return await PutJsonAsync($"{Apiurl}/{tenant.TenantId}", tenant); - } - - public async Task DeleteTenantAsync(int tenantId) - { - await DeleteAsync($"{Apiurl}/{tenantId}"); - } } } diff --git a/Oqtane.Server/Controllers/AliasController.cs b/Oqtane.Server/Controllers/AliasController.cs index a61f2ed4..644fa278 100644 --- a/Oqtane.Server/Controllers/AliasController.cs +++ b/Oqtane.Server/Controllers/AliasController.cs @@ -72,7 +72,7 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Host)] public Alias Put(int id, [FromBody] Alias alias) { - if (ModelState.IsValid) + if (ModelState.IsValid && _aliases.GetAlias(alias.AliasId, false) != null) { alias = _aliases.UpdateAlias(alias); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Alias Updated {Alias}", alias); @@ -91,8 +91,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Host)] public void Delete(int id) { - _aliases.DeleteAlias(id); - _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Alias Deleted {AliasId}", id); + var alias = _aliases.GetAlias(id); + if (alias != null) + { + _aliases.DeleteAlias(id); + _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Alias Deleted {AliasId}", id); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Alias Delete Attempt {AliasId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } } } diff --git a/Oqtane.Server/Controllers/JobController.cs b/Oqtane.Server/Controllers/JobController.cs index db4f4bfb..356fd75f 100644 --- a/Oqtane.Server/Controllers/JobController.cs +++ b/Oqtane.Server/Controllers/JobController.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.DependencyInjection; using Oqtane.Enums; using Oqtane.Infrastructure; using Oqtane.Repository; +using System.Net; namespace Oqtane.Controllers { @@ -52,6 +53,12 @@ namespace Oqtane.Controllers job = _jobs.AddJob(job); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Job Added {Job}", job); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Job Post Attempt {Alias}", job); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + job = null; + } return job; } @@ -60,11 +67,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Host)] public Job Put(int id, [FromBody] Job job) { - if (ModelState.IsValid) + if (ModelState.IsValid && _jobs.GetJob(job.JobId, false) != null) { job = _jobs.UpdateJob(job); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Job Updated {Job}", job); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Job Put Attempt {Alias}", job); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + job = null; + } return job; } @@ -73,8 +86,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Host)] public void Delete(int id) { - _jobs.DeleteJob(id); - _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Job Deleted {JobId}", id); + var job = _jobs.GetJob(id); + if (job != null) + { + _jobs.DeleteJob(id); + _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Job Deleted {JobId}", id); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Job Delete Attempt {JobId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } // GET api//start @@ -83,12 +105,17 @@ namespace Oqtane.Controllers public void Start(int id) { Job job = _jobs.GetJob(id); - Type jobtype = Type.GetType(job.JobType); - if (jobtype != null) + if (job != null) { + Type jobtype = Type.GetType(job.JobType); var jobobject = ActivatorUtilities.CreateInstance(_serviceProvider, jobtype); ((IHostedService)jobobject).StartAsync(new System.Threading.CancellationToken()); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Job Start Attempt {JobId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } // GET api//stop @@ -97,12 +124,17 @@ namespace Oqtane.Controllers public void Stop(int id) { Job job = _jobs.GetJob(id); - Type jobtype = Type.GetType(job.JobType); - if (jobtype != null) + if (job != null) { + Type jobtype = Type.GetType(job.JobType); var jobobject = ActivatorUtilities.CreateInstance(_serviceProvider, jobtype); ((IHostedService)jobobject).StopAsync(new System.Threading.CancellationToken()); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Job Stop Attempt {JobId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } } } diff --git a/Oqtane.Server/Controllers/JobLogController.cs b/Oqtane.Server/Controllers/JobLogController.cs index 39fd8ac9..5f711e4f 100644 --- a/Oqtane.Server/Controllers/JobLogController.cs +++ b/Oqtane.Server/Controllers/JobLogController.cs @@ -1,10 +1,8 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; -using Oqtane.Enums; using Oqtane.Models; using Oqtane.Shared; -using Oqtane.Infrastructure; using Oqtane.Repository; namespace Oqtane.Controllers @@ -13,12 +11,10 @@ namespace Oqtane.Controllers public class JobLogController : Controller { private readonly IJobLogRepository _jobLogs; - private readonly ILogManager _logger; - public JobLogController(IJobLogRepository jobLogs, ILogManager logger) + public JobLogController(IJobLogRepository jobLogs) { _jobLogs = jobLogs; - _logger = logger; } // GET: api/ @@ -36,40 +32,5 @@ namespace Oqtane.Controllers { return _jobLogs.GetJobLog(id); } - - // POST api/ - [HttpPost] - [Authorize(Roles = RoleNames.Host)] - public JobLog Post([FromBody] JobLog jobLog) - { - if (ModelState.IsValid) - { - jobLog = _jobLogs.AddJobLog(jobLog); - _logger.Log(LogLevel.Information, this, LogFunction.Create, "Job Log Added {JobLog}", jobLog); - } - return jobLog; - } - - // PUT api//5 - [HttpPut("{id}")] - [Authorize(Roles = RoleNames.Host)] - public JobLog Put(int id, [FromBody] JobLog jobLog) - { - if (ModelState.IsValid) - { - jobLog = _jobLogs.UpdateJobLog(jobLog); - _logger.Log(LogLevel.Information, this, LogFunction.Update, "Job Log Updated {JobLog}", jobLog); - } - return jobLog; - } - - // DELETE api//5 - [HttpDelete("{id}")] - [Authorize(Roles = RoleNames.Host)] - public void Delete(int id) - { - _jobLogs.DeleteJobLog(id); - _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Job Log Deleted {JobLogId}", id); - } } } diff --git a/Oqtane.Server/Controllers/TenantController.cs b/Oqtane.Server/Controllers/TenantController.cs index 6f6fb4e8..1b01d0f1 100644 --- a/Oqtane.Server/Controllers/TenantController.cs +++ b/Oqtane.Server/Controllers/TenantController.cs @@ -36,40 +36,5 @@ namespace Oqtane.Controllers { return _tenants.GetTenant(id); } - - // POST api/ - [HttpPost] - [Authorize(Roles = RoleNames.Host)] - public Tenant Post([FromBody] Tenant tenant) - { - if (ModelState.IsValid) - { - tenant = _tenants.AddTenant(tenant); - _logger.Log(LogLevel.Information, this, LogFunction.Create, "Tenant Added {TenantId}", tenant.TenantId); - } - return tenant; - } - - // PUT api//5 - [HttpPut("{id}")] - [Authorize(Roles = RoleNames.Host)] - public Tenant Put(int id, [FromBody] Tenant tenant) - { - if (ModelState.IsValid) - { - tenant = _tenants.UpdateTenant(tenant); - _logger.Log(LogLevel.Information, this, LogFunction.Update, "Tenant Updated {TenantId}", tenant.TenantId); - } - return tenant; - } - - // DELETE api//5 - [HttpDelete("{id}")] - [Authorize(Roles = RoleNames.Host)] - public void Delete(int id) - { - _tenants.DeleteTenant(id); - _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Tenant Deleted {TenantId}", id); - } } } diff --git a/Oqtane.Server/Controllers/ThemeController.cs b/Oqtane.Server/Controllers/ThemeController.cs index 7c05b0ba..dd8bae6f 100644 --- a/Oqtane.Server/Controllers/ThemeController.cs +++ b/Oqtane.Server/Controllers/ThemeController.cs @@ -11,6 +11,7 @@ using Oqtane.Enums; using Oqtane.Infrastructure; using Oqtane.Repository; using System.Text.Json; +using System.Net; // ReSharper disable StringIndexOfIsCultureSpecific.1 @@ -84,6 +85,11 @@ namespace Oqtane.Controllers _themes.DeleteTheme(theme.ThemeName); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Removed For {ThemeName}", theme.ThemeName); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Theme Delete Attempt {Themename}", themename); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } // GET: api//templates @@ -141,6 +147,12 @@ namespace Oqtane.Controllers ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, theme); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Theme Created {Theme}", theme); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Theme Post Attempt {Theme}", theme); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + theme = null; + } return theme; } diff --git a/Oqtane.Server/Repository/AliasRepository.cs b/Oqtane.Server/Repository/AliasRepository.cs index 619724dc..9e4e82d9 100644 --- a/Oqtane.Server/Repository/AliasRepository.cs +++ b/Oqtane.Server/Repository/AliasRepository.cs @@ -45,15 +45,28 @@ namespace Oqtane.Repository public Alias GetAlias(int aliasId) { - return _db.Alias.Find(aliasId); + return GetAlias(aliasId, true); } - public Alias GetAlias(string name) + public Alias GetAlias(int aliasId, bool tracking) + { + if (tracking) + { + return _db.Alias.Find(aliasId); + } + else + { + return _db.Alias.AsNoTracking().FirstOrDefault(item => item.AliasId == aliasId); + } + } + + // lookup alias based on url - note that alias values are hierarchical + public Alias GetAlias(string url) { Alias alias = null; List aliases = GetAliases().ToList(); - var segments = name.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + var segments = url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); // iterate segments to find keywords int start = segments.Length; diff --git a/Oqtane.Server/Repository/Interfaces/IAliasRepository.cs b/Oqtane.Server/Repository/Interfaces/IAliasRepository.cs index 5422ab07..81a42d68 100644 --- a/Oqtane.Server/Repository/Interfaces/IAliasRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IAliasRepository.cs @@ -9,7 +9,8 @@ namespace Oqtane.Repository Alias AddAlias(Alias alias); Alias UpdateAlias(Alias alias); Alias GetAlias(int aliasId); - Alias GetAlias(string name); + Alias GetAlias(int aliasId, bool tracking); + Alias GetAlias(string url); void DeleteAlias(int aliasId); } } diff --git a/Oqtane.Server/Repository/Interfaces/IJobRepository.cs b/Oqtane.Server/Repository/Interfaces/IJobRepository.cs index 12be85c1..e45b0231 100644 --- a/Oqtane.Server/Repository/Interfaces/IJobRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IJobRepository.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 Job AddJob(Job job); Job UpdateJob(Job job); Job GetJob(int jobId); + Job GetJob(int jobId, bool tracking); void DeleteJob(int jobId); } } diff --git a/Oqtane.Server/Repository/JobRepository.cs b/Oqtane.Server/Repository/JobRepository.cs index cbe51c19..37b38521 100644 --- a/Oqtane.Server/Repository/JobRepository.cs +++ b/Oqtane.Server/Repository/JobRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; @@ -48,6 +48,19 @@ namespace Oqtane.Repository return _db.Job.Find(jobId); } + public Job GetJob(int jobId, bool tracking) + { + if (tracking) + { + return _db.Job.Find(jobId); + } + else + { + return _db.Job.AsNoTracking().FirstOrDefault(item => item.JobId == jobId); + } + + } + public void DeleteJob(int jobId) { Job job = _db.Job.Find(jobId); From 4fcfb2ab4e53202995334ae6fc63406e1aae0f78 Mon Sep 17 00:00:00 2001 From: Leigh Date: Wed, 16 Jun 2021 09:46:33 +0200 Subject: [PATCH 14/22] Introduce SharedResource Localisation Updated the ControlPanel to use Shared resources for; Add, Edit, Delete, Cancel Corrected the SharedResources.cs namespace. --- Oqtane.Client/SharedResources.cs | 2 +- .../Themes/Controls/Theme/ControlPanel.razor | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Oqtane.Client/SharedResources.cs b/Oqtane.Client/SharedResources.cs index da203b14..1ea66d42 100644 --- a/Oqtane.Client/SharedResources.cs +++ b/Oqtane.Client/SharedResources.cs @@ -1,4 +1,4 @@ -namespace Oqtane.Client +namespace Oqtane { /// /// Dummy class used to collect shared resource strings for this application diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor index 14e985e1..652a14ff 100644 --- a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor @@ -10,6 +10,7 @@ @inject ILogService logger @inject ISettingService SettingService @inject IStringLocalizer Localizer +@inject IStringLocalizer SharedLocalizer @if (_moduleDefinitions != null && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions)) { @@ -36,18 +37,18 @@
- +
- +
- +
- +

@@ -81,8 +82,8 @@

Are You Sure You Want To Delete This Page?

From c62a4ae8ae1c3bb0db3d194968cd406f23e975ec Mon Sep 17 00:00:00 2001 From: hishamco Date: Wed, 16 Jun 2021 11:02:12 +0300 Subject: [PATCH 15/22] Fix parsing localization cookie when the value is not present --- Oqtane.Client/Program.cs | 2 +- .../LocalizationCookieTests.cs | 30 +++++++++++++++++++ Oqtane.Test/Oqtane.Test.csproj | 3 +- 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 Oqtane.Test/Oqtane.Client.Tests/LocalizationCookieTests.cs diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index ff27f5c0..f27f0c2e 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -137,7 +137,7 @@ namespace Oqtane.Client var jsRuntime = serviceProvider.GetRequiredService(); var interop = new Interop(jsRuntime); var localizationCookie = await interop.GetCookie(CookieRequestCultureProvider.DefaultCookieName); - var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie).UICultures[0].Value; + var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie)?.UICultures?[0].Value; var localizationService = serviceProvider.GetRequiredService(); var cultures = await localizationService.GetCulturesAsync(); diff --git a/Oqtane.Test/Oqtane.Client.Tests/LocalizationCookieTests.cs b/Oqtane.Test/Oqtane.Client.Tests/LocalizationCookieTests.cs new file mode 100644 index 00000000..4acc1bb9 --- /dev/null +++ b/Oqtane.Test/Oqtane.Client.Tests/LocalizationCookieTests.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Localization; +using Xunit; + +namespace Oqtane.Oqtane.Client.Tests +{ + public class LocalizationCookieTests + { + [Theory] + [InlineData("c=ar|uic=ar", "ar")] + [InlineData("c=ar", null)] + [InlineData("", null)] + [InlineData(null, null)] + public void ParseCookie(string localizationCookie, string expectedCulture) + { + // Arrange + var localizationCookieValue = CookieRequestCultureProvider.ParseCookieValue(localizationCookie); + + // Act + var culture = localizationCookieValue?.UICultures?[0].Value; + + // Assert + Assert.Equal(expectedCulture, culture); + } + } +} diff --git a/Oqtane.Test/Oqtane.Test.csproj b/Oqtane.Test/Oqtane.Test.csproj index 2705c3c5..b8b7748f 100644 --- a/Oqtane.Test/Oqtane.Test.csproj +++ b/Oqtane.Test/Oqtane.Test.csproj @@ -18,7 +18,8 @@ false - + + From 1bfe4fbd4ff2647f6d451a5f2e4db14600c0920f Mon Sep 17 00:00:00 2001 From: hishamco Date: Wed, 16 Jun 2021 11:55:36 +0300 Subject: [PATCH 16/22] Add missing Oqtane.Server to Databases solutions --- Oqtane.Databases.sln | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Oqtane.Databases.sln b/Oqtane.Databases.sln index 379afe97..67deb124 100644 --- a/Oqtane.Databases.sln +++ b/Oqtane.Databases.sln @@ -18,6 +18,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oqtane.Database.Sqlite", "O EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oqtane.Database.SqlServer", "Oqtane.Database.SqlServer\Oqtane.Database.SqlServer.csproj", "{033DCA37-6354-4A3D-8250-4EC20740EE19}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oqtane.Server", "Oqtane.Server\Oqtane.Server.csproj", "{6A60C4DD-67E6-42A7-B9AA-A1EE45AD45C7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -40,6 +42,10 @@ Global {033DCA37-6354-4A3D-8250-4EC20740EE19}.Debug|Any CPU.Build.0 = Debug|Any CPU {033DCA37-6354-4A3D-8250-4EC20740EE19}.Release|Any CPU.ActiveCfg = Release|Any CPU {033DCA37-6354-4A3D-8250-4EC20740EE19}.Release|Any CPU.Build.0 = Release|Any CPU + {6A60C4DD-67E6-42A7-B9AA-A1EE45AD45C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6A60C4DD-67E6-42A7-B9AA-A1EE45AD45C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6A60C4DD-67E6-42A7-B9AA-A1EE45AD45C7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6A60C4DD-67E6-42A7-B9AA-A1EE45AD45C7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From cec24e7446955990254aab1ec089cb10e8f6a108 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 16 Jun 2021 08:30:41 -0400 Subject: [PATCH 17/22] improve multi-tenancy navigation --- Oqtane.Client/Modules/Admin/Sites/Index.razor | 5 ++--- Oqtane.Client/UI/SiteRouter.razor | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Sites/Index.razor b/Oqtane.Client/Modules/Admin/Sites/Index.razor index 5728905b..d181fe68 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Index.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Index.razor @@ -51,12 +51,11 @@ else private void Edit(string name) { - NavigationManager.NavigateTo(_scheme + name + "/admin/site", true); + NavigationManager.NavigateTo(_scheme + name + "/admin/site/?redirect"); } private void Browse(string name) { - NavigationManager.NavigateTo(_scheme + name, true); + NavigationManager.NavigateTo(_scheme + name + "/?redirect", true); } - } diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index ed5548f4..6c690fe8 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -94,6 +94,15 @@ { reload = Reload.Site; } + else + { + // reload the client application if the user navigated to a site with a different alias or there is a forced redirect + if ((!path.StartsWith(SiteState.Alias.Path) && SiteState.Alias.Path != "") || querystring.ContainsKey("redirect")) + { + NavigationManager.NavigateTo(_absoluteUri.Replace("?redirect", ""), true); + return; + } + } if (PageState != null) { @@ -109,7 +118,8 @@ // if running on WebAssembly reload the client application if the server application was restarted if (runtime == Shared.Runtime.WebAssembly && PageState != null && sync.SyncEvents.Exists(item => item.TenantId == -1)) { - NavigationManager.NavigateTo(_absoluteUri + (!_absoluteUri.Contains("?") ? "?" : "&") + "reload", true); + NavigationManager.NavigateTo(_absoluteUri, true); + return; } if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId)) { @@ -169,7 +179,7 @@ path += "/"; } - if (SiteState.Alias.Path != "") + if (SiteState.Alias.Path != "" && path.StartsWith(SiteState.Alias.Path)) { path = path.Substring(SiteState.Alias.Path.Length + 1); } From 72ff6fa0e79d42d107bd8ad1c0b2703a1556a709 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 16 Jun 2021 16:31:02 -0400 Subject: [PATCH 18/22] improvements to refresh logic, module template enhancements --- Oqtane.Client/Modules/Admin/Login/Index.razor | 2 +- .../Admin/ModuleDefinitions/Index.razor | 2 +- Oqtane.Client/Modules/Admin/Sites/Index.razor | 4 +- .../Modules/Admin/Themes/Index.razor | 2 +- Oqtane.Client/Modules/ModuleBase.cs | 10 ++ .../Controls/Container/ModuleActionsBase.cs | 16 +- .../Themes/Controls/Theme/ControlPanel.razor | 2 +- .../Themes/Controls/Theme/LoginBase.cs | 2 +- Oqtane.Client/Themes/ThemeBase.cs | 10 ++ Oqtane.Client/UI/{Reload.cs => Refresh.cs} | 4 +- Oqtane.Client/UI/SiteRouter.razor | 34 ++--- .../Modules/[Owner].[Module]/Edit.razor | 39 +++-- .../Modules/[Owner].[Module]/Index.razor | 15 +- .../Modules/[Owner].[Module]/Settings.razor | 3 +- .../Resources/[Owner].[Module]/Edit.resx | 141 ++++++++++++++++++ .../Resources/[Owner].[Module]/Index.resx | 138 +++++++++++++++++ .../Resources/[Owner].[Module]/Settings.resx | 126 ++++++++++++++++ .../Server/Controllers/[Module]Controller.cs | 39 ++++- .../Server/Repository/I[Module]Repository.cs | 1 + .../Server/Repository/[Module]Repository.cs | 14 +- 20 files changed, 540 insertions(+), 64 deletions(-) rename Oqtane.Client/UI/{Reload.cs => Refresh.cs} (62%) create mode 100644 Oqtane.Server/wwwroot/Modules/Templates/External/Client/Resources/[Owner].[Module]/Edit.resx create mode 100644 Oqtane.Server/wwwroot/Modules/Templates/External/Client/Resources/[Owner].[Module]/Index.resx create mode 100644 Oqtane.Server/wwwroot/Modules/Templates/External/Client/Resources/[Owner].[Module]/Settings.resx diff --git a/Oqtane.Client/Modules/Admin/Login/Index.razor b/Oqtane.Client/Modules/Admin/Login/Index.razor index 45f4e246..790265c7 100644 --- a/Oqtane.Client/Modules/Admin/Login/Index.razor +++ b/Oqtane.Client/Modules/Admin/Login/Index.razor @@ -142,7 +142,7 @@ await logger.LogInformation("Login Successful For Username {Username}", _username); var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider)); authstateprovider.NotifyAuthenticationChanged(); - NavigationManager.NavigateTo(NavigateUrl(_returnUrl, "reload")); + NavigationManager.NavigateTo(NavigateUrl(_returnUrl, true)); } else { diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor index c9c47456..44bc1b8f 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor @@ -103,7 +103,7 @@ else { await ModuleDefinitionService.DeleteModuleDefinitionAsync(moduleDefinition.ModuleDefinitionId, moduleDefinition.SiteId); AddModuleMessage(Localizer["Module Deleted Successfully"], MessageType.Success); - NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "reload")); + NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true)); } catch (Exception ex) { diff --git a/Oqtane.Client/Modules/Admin/Sites/Index.razor b/Oqtane.Client/Modules/Admin/Sites/Index.razor index d181fe68..0f0ef0fc 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Index.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Index.razor @@ -51,11 +51,11 @@ else private void Edit(string name) { - NavigationManager.NavigateTo(_scheme + name + "/admin/site/?redirect"); + NavigationManager.NavigateTo(_scheme + name + "/admin/site/?reload"); } private void Browse(string name) { - NavigationManager.NavigateTo(_scheme + name + "/?redirect", true); + NavigationManager.NavigateTo(_scheme + name + "/?reload"); } } diff --git a/Oqtane.Client/Modules/Admin/Themes/Index.razor b/Oqtane.Client/Modules/Admin/Themes/Index.razor index fc13417f..7cbba5f3 100644 --- a/Oqtane.Client/Modules/Admin/Themes/Index.razor +++ b/Oqtane.Client/Modules/Admin/Themes/Index.razor @@ -104,7 +104,7 @@ else { await ThemeService.DeleteThemeAsync(Theme.ThemeName); AddModuleMessage(Localizer["Theme Deleted Successfully"], MessageType.Success); - NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "reload")); + NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true)); } catch (Exception ex) { diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index 3fd548ac..e7c6658d 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -84,11 +84,21 @@ namespace Oqtane.Modules return NavigateUrl(path, ""); } + public string NavigateUrl(bool refresh) + { + return NavigateUrl(PageState.Page.Path, refresh); + } + public string NavigateUrl(string path, string parameters) { return Utilities.NavigateUrl(PageState.Alias.Path, path, parameters); } + public string NavigateUrl(string path, bool refresh) + { + return Utilities.NavigateUrl(PageState.Alias.Path, path, refresh ? "refresh" : ""); + } + public string EditUrl(string action) { return EditUrl(ModuleState.ModuleId, action); diff --git a/Oqtane.Client/Themes/Controls/Container/ModuleActionsBase.cs b/Oqtane.Client/Themes/Controls/Container/ModuleActionsBase.cs index f8b0b065..edf5b8e4 100644 --- a/Oqtane.Client/Themes/Controls/Container/ModuleActionsBase.cs +++ b/Oqtane.Client/Themes/Controls/Container/ModuleActionsBase.cs @@ -115,7 +115,7 @@ namespace Oqtane.Themes.Controls await PageModuleService.UpdatePageModuleAsync(pagemodule); await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane); await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, oldPane); - return NavigateUrl(url, "reload"); + return NavigateUrl(url, true); } private async Task DeleteModule(string url, PageModule pagemodule) @@ -123,7 +123,7 @@ namespace Oqtane.Themes.Controls pagemodule.IsDeleted = true; await PageModuleService.UpdatePageModuleAsync(pagemodule); await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane); - return NavigateUrl(url, "reload"); + return NavigateUrl(url, true); } private async Task Settings(string url, PageModule pagemodule) @@ -148,7 +148,7 @@ namespace Oqtane.Themes.Controls } pagemodule.Module.Permissions = UserSecurity.SetPermissionStrings(permissions); await ModuleService.UpdateModuleAsync(pagemodule.Module); - return NavigateUrl(s, "reload"); + return NavigateUrl(s, true); } private async Task Unpublish(string s, PageModule pagemodule) @@ -166,7 +166,7 @@ namespace Oqtane.Themes.Controls } pagemodule.Module.Permissions = UserSecurity.SetPermissionStrings(permissions); await ModuleService.UpdateModuleAsync(pagemodule.Module); - return NavigateUrl(s, "reload"); + return NavigateUrl(s, true); } private async Task MoveTop(string s, PageModule pagemodule) @@ -174,7 +174,7 @@ namespace Oqtane.Themes.Controls pagemodule.Order = 0; await PageModuleService.UpdatePageModuleAsync(pagemodule); await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane); - return NavigateUrl(s, "reload"); + return NavigateUrl(s, true); } private async Task MoveBottom(string s, PageModule pagemodule) @@ -182,7 +182,7 @@ namespace Oqtane.Themes.Controls pagemodule.Order = int.MaxValue; await PageModuleService.UpdatePageModuleAsync(pagemodule); await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane); - return NavigateUrl(s, "reload"); + return NavigateUrl(s, true); } private async Task MoveUp(string s, PageModule pagemodule) @@ -190,7 +190,7 @@ namespace Oqtane.Themes.Controls pagemodule.Order -= 3; await PageModuleService.UpdatePageModuleAsync(pagemodule); await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane); - return NavigateUrl(s, "reload"); + return NavigateUrl(s, true); } private async Task MoveDown(string s, PageModule pagemodule) @@ -198,7 +198,7 @@ namespace Oqtane.Themes.Controls pagemodule.Order += 3; await PageModuleService.UpdatePageModuleAsync(pagemodule); await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane); - return NavigateUrl(s, "reload"); + return NavigateUrl(s, true); } public class ActionViewModel diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor index 14e985e1..51486db8 100644 --- a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor @@ -537,7 +537,7 @@ } page.Permissions = UserSecurity.SetPermissionStrings(permissions); await PageService.UpdatePageAsync(page); - NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "reload")); + NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true)); } } diff --git a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs index 972f005c..cc454412 100644 --- a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs +++ b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs @@ -47,7 +47,7 @@ namespace Oqtane.Themes.Controls // client-side Blazor var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider)); authstateprovider.NotifyAuthenticationChanged(); - NavigationManager.NavigateTo(NavigateUrl(!authorizedtoviewpage ? PageState.Alias.Path : PageState.Page.Path, "reload")); + NavigationManager.NavigateTo(NavigateUrl(!authorizedtoviewpage ? PageState.Alias.Path : PageState.Page.Path, true)); } } } diff --git a/Oqtane.Client/Themes/ThemeBase.cs b/Oqtane.Client/Themes/ThemeBase.cs index a2ca3c86..158321f9 100644 --- a/Oqtane.Client/Themes/ThemeBase.cs +++ b/Oqtane.Client/Themes/ThemeBase.cs @@ -64,6 +64,16 @@ namespace Oqtane.Themes return NavigateUrl(path, ""); } + public string NavigateUrl(bool refresh) + { + return NavigateUrl(PageState.Page.Path, refresh); + } + + public string NavigateUrl(string path, bool refresh) + { + return Utilities.NavigateUrl(PageState.Alias.Path, path, refresh ? "refresh" : ""); + } + public string NavigateUrl(string path, string parameters) { return Utilities.NavigateUrl(PageState.Alias.Path, path, parameters); diff --git a/Oqtane.Client/UI/Reload.cs b/Oqtane.Client/UI/Refresh.cs similarity index 62% rename from Oqtane.Client/UI/Reload.cs rename to Oqtane.Client/UI/Refresh.cs index 6fb632c6..0c0d7871 100644 --- a/Oqtane.Client/UI/Reload.cs +++ b/Oqtane.Client/UI/Refresh.cs @@ -1,6 +1,6 @@ -namespace Oqtane.UI +namespace Oqtane.UI { - public enum Reload + public enum Refresh { None, Page, diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 6c690fe8..cbe7783a 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -77,7 +77,7 @@ var action = Constants.DefaultAction; var urlparameters = string.Empty; var editmode = false; - var reload = Reload.None; + var refresh = UI.Refresh.None; var lastsyncdate = DateTime.UtcNow.AddHours(-1); var runtime = GetRuntime(); @@ -89,17 +89,17 @@ // parse querystring var querystring = ParseQueryString(uri.Query); - // the reload parameter is used to reload the PageState - if (querystring.ContainsKey("reload")) + // the refresh parameter is used to refresh the PageState + if (querystring.ContainsKey("refresh")) { - reload = Reload.Site; + refresh = UI.Refresh.Site; } else { - // reload the client application if the user navigated to a site with a different alias or there is a forced redirect - if ((!path.StartsWith(SiteState.Alias.Path) && SiteState.Alias.Path != "") || querystring.ContainsKey("redirect")) + // reload the client application if the user navigated to a site with a different alias or there is a forced reload + if ((!path.StartsWith(SiteState.Alias.Path) && SiteState.Alias.Path != "") || querystring.ContainsKey("reload")) { - NavigationManager.NavigateTo(_absoluteUri.Replace("?redirect", ""), true); + NavigationManager.NavigateTo(_absoluteUri.Replace("?reload", ""), true); return; } } @@ -113,7 +113,7 @@ // process any sync events var sync = await SyncService.GetSyncAsync(lastsyncdate); lastsyncdate = sync.SyncDate; - if (reload != Reload.Site && sync.SyncEvents.Any()) + if (refresh != UI.Refresh.Site && sync.SyncEvents.Any()) { // if running on WebAssembly reload the client application if the server application was restarted if (runtime == Shared.Runtime.WebAssembly && PageState != null && sync.SyncEvents.Exists(item => item.TenantId == -1)) @@ -123,14 +123,14 @@ } if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId)) { - reload = Reload.Site; + refresh = UI.Refresh.Site; } } - if (reload == Reload.Site || PageState == null || PageState.Alias.SiteId != SiteState.Alias.SiteId) + if (refresh == UI.Refresh.Site || PageState == null || PageState.Alias.SiteId != SiteState.Alias.SiteId) { site = await SiteService.GetSiteAsync(SiteState.Alias.SiteId); - reload = Reload.Site; + refresh = UI.Refresh.Site; } else { @@ -139,7 +139,7 @@ if (site != null) { - if (PageState == null || reload == Reload.Site) + if (PageState == null || refresh == UI.Refresh.Site) { // get user var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); @@ -154,15 +154,15 @@ } // process any sync events for user - if (reload != Reload.Site && user != null && sync.SyncEvents.Any()) + if (refresh != UI.Refresh.Site && user != null && sync.SyncEvents.Any()) { if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.User && item.EntityId == user.UserId)) { - reload = Reload.Site; + refresh = UI.Refresh.Site; } } - if (PageState == null || reload == Reload.Site) + if (PageState == null || refresh == UI.Refresh.Site) { pages = await PageService.GetPagesAsync(site.SiteId); } @@ -239,7 +239,7 @@ // remove trailing slash so it can be used as a key for Pages if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1); - if (PageState == null || reload == Reload.Site) + if (PageState == null || refresh == UI.Refresh.Site) { page = pages.FirstOrDefault(item => item.Path.Equals(path, StringComparison.OrdinalIgnoreCase)); } @@ -274,7 +274,7 @@ { page = await ProcessPage(page, site, user); - if (PageState == null || reload == Reload.Site) + if (PageState == null || refresh == UI.Refresh.Site) { modules = await ModuleService.GetModulesAsync(site.SiteId); } diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Edit.razor b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Edit.razor index b866069a..d901cb4f 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Edit.razor +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Edit.razor @@ -6,25 +6,27 @@ @inherits ModuleBase @inject I[Module]Service [Module]Service @inject NavigationManager NavigationManager +@inject IStringLocalizer Localizer +
- + - +
- -Cancel -
-
+ +@Localizer["Cancel"] +

@if (PageState.Action == "Edit") { } +
@code { public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit; @@ -38,12 +40,15 @@ new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" } }; - int _id; - string _name; - string _createdby; - DateTime _createdon; - string _modifiedby; - DateTime _modifiedon; + private ElementReference form; + private bool validated = false; + + private int _id; + private string _name; + private string _createdby; + private DateTime _createdon; + private string _modifiedby; + private DateTime _modifiedon; protected override async Task OnInitializedAsync() { @@ -66,7 +71,7 @@ catch (Exception ex) { await logger.LogError(ex, "Error Loading [Module] {[Module]Id} {Error}", _id, ex.Message); - AddModuleMessage("Error Loading [Module]", MessageType.Error); + AddModuleMessage(Localizer["Message.LoadError"], MessageType.Error); } } @@ -74,7 +79,9 @@ { try { - if (!string.IsNullOrEmpty(_name)) + validated = true; + var interop = new Interop(JSRuntime); + if (await interop.FormValid(form)) { if (PageState.Action == "Add") { @@ -95,13 +102,13 @@ } else { - AddModuleMessage("The Name Is Required", MessageType.Warning); + AddModuleMessage(Localizer["Message.SaveValidation"], MessageType.Warning); } } catch (Exception ex) { await logger.LogError(ex, "Error Saving [Module] {Error}", ex.Message); - AddModuleMessage("Error Saving [Module]", MessageType.Error); + AddModuleMessage(Localizer["Message.SaveError"], MessageType.Error); } } } diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Index.razor b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Index.razor index 4f5e0f37..d93cdb20 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Index.razor +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Index.razor @@ -5,6 +5,7 @@ @inherits ModuleBase @inject I[Module]Service [Module]Service @inject NavigationManager NavigationManager +@inject IStringLocalizer Localizer @if (_[Module]s == null) { @@ -12,7 +13,7 @@ } else { - +

@if (@_[Module]s.Count != 0) @@ -21,18 +22,18 @@ else
    - Name + @Localizer["Name"]
- - + + @context.Name } else { -

No [Module]s To Display

+

@Localizer["Message.DisplayNone"]

} } @@ -54,7 +55,7 @@ else catch (Exception ex) { await logger.LogError(ex, "Error Loading [Module] {Error}", ex.Message); - AddModuleMessage("Error Loading [Module]", MessageType.Error); + AddModuleMessage(Localizer["Message.LoadError"], MessageType.Error); } } @@ -70,7 +71,7 @@ else catch (Exception ex) { await logger.LogError(ex, "Error Deleting [Module] {[Module]} {Error}", [Module], ex.Message); - AddModuleMessage("Error Deleting [Module]", MessageType.Error); + AddModuleMessage(Localizer["Message.DeleteError"], MessageType.Error); } } } \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Settings.razor b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Settings.razor index 7989d7c9..20e042fd 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Settings.razor +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Settings.razor @@ -1,11 +1,12 @@ @namespace [Owner].[Module] @inherits ModuleBase @inject ISettingService SettingService +@inject IStringLocalizer Localizer
- + diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Resources/[Owner].[Module]/Edit.resx b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Resources/[Owner].[Module]/Edit.resx new file mode 100644 index 00000000..eebd66cd --- /dev/null +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Resources/[Owner].[Module]/Edit.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Name: + + + Enter the name + + + Save + + + Cancel + + + Error Loading [Module] + + + Please Provide All Required Information + + + Error Saving [Module] + + \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Resources/[Owner].[Module]/Index.resx b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Resources/[Owner].[Module]/Index.resx new file mode 100644 index 00000000..2c863947 --- /dev/null +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Resources/[Owner].[Module]/Index.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Name + + + Edit + + + Delete + + + No [Module]s To Display + + + Error Loading [Module] + + + Error Deleting [Module] + + \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Resources/[Owner].[Module]/Settings.resx b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Resources/[Owner].[Module]/Settings.resx new file mode 100644 index 00000000..ba0390d8 --- /dev/null +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Resources/[Owner].[Module]/Settings.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Name: + + + Enter a value + + \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Controllers/[Module]Controller.cs b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Controllers/[Module]Controller.cs index a42767ba..ca2d4bea 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Controllers/[Module]Controller.cs +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Controllers/[Module]Controller.cs @@ -7,6 +7,7 @@ using Oqtane.Enums; using Oqtane.Infrastructure; using [Owner].[Module].Repository; using Oqtane.Controllers; +using System.Net; namespace [Owner].[Module].Controllers { @@ -25,12 +26,15 @@ namespace [Owner].[Module].Controllers [Authorize(Policy = PolicyNames.ViewModule)] public IEnumerable Get(string moduleid) { - if (int.Parse(moduleid) == _authEntityId[EntityNames.Module]) + int ModuleId; + if (int.TryParse(moduleid, out ModuleId) == _authEntityId[EntityNames.Module]) { - return _[Module]Repository.Get[Module]s(int.Parse(moduleid)); + return _[Module]Repository.Get[Module]s(int.Parse(ModuleId)); } else { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Get Attempt {ModuleId}", moduleid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } @@ -43,12 +47,18 @@ namespace [Owner].[Module].Controllers Models.[Module] [Module] = _[Module]Repository.Get[Module](id); if ([Module] != null && [Module].ModuleId != _authEntityId[EntityNames.Module]) { - [Module] = null; + return [Module]; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Get Attempt {[Module]Id}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; } - return [Module]; } // POST api/ + [ValidateAntiForgeryToken] [HttpPost] [Authorize(Policy = PolicyNames.EditModule)] public Models.[Module] Post([FromBody] Models.[Module] [Module]) @@ -58,23 +68,37 @@ namespace [Owner].[Module].Controllers [Module] = _[Module]Repository.Add[Module]([Module]); _logger.Log(LogLevel.Information, this, LogFunction.Create, "[Module] Added {[Module]}", [Module]); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Post Attempt {[Module]}", [Module]); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + [Module] = null; + } return [Module]; } // PUT api//5 + [ValidateAntiForgeryToken] [HttpPut("{id}")] [Authorize(Policy = PolicyNames.EditModule)] public Models.[Module] Put(int id, [FromBody] Models.[Module] [Module]) { - if (ModelState.IsValid && [Module].ModuleId == _authEntityId[EntityNames.Module]) + if (ModelState.IsValid && [Module].ModuleId == _authEntityId[EntityNames.Module] && _[Module]Repository.Get[Module]([Module].[Module]Id, false) != null) { [Module] = _[Module]Repository.Update[Module]([Module]); _logger.Log(LogLevel.Information, this, LogFunction.Update, "[Module] Updated {[Module]}", [Module]); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Put Attempt {[Module]}", [Module]); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + [Module] = null; + } return [Module]; } // DELETE api//5 + [ValidateAntiForgeryToken] [HttpDelete("{id}")] [Authorize(Policy = PolicyNames.EditModule)] public void Delete(int id) @@ -85,6 +109,11 @@ namespace [Owner].[Module].Controllers _[Module]Repository.Delete[Module](id); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "[Module] Deleted {[Module]Id}", id); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized [Module] Delete Attempt {[Module]Id}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } } } diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Repository/I[Module]Repository.cs b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Repository/I[Module]Repository.cs index 52b7913a..da2db55f 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Repository/I[Module]Repository.cs +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Repository/I[Module]Repository.cs @@ -7,6 +7,7 @@ namespace [Owner].[Module].Repository { IEnumerable Get[Module]s(int ModuleId); Models.[Module] Get[Module](int [Module]Id); + Models.[Module] Get[Module](int [Module]Id, bool tracking); Models.[Module] Add[Module](Models.[Module] [Module]); Models.[Module] Update[Module](Models.[Module] [Module]); void Delete[Module](int [Module]Id); diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Repository/[Module]Repository.cs b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Repository/[Module]Repository.cs index 9c8c3628..238546dc 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Repository/[Module]Repository.cs +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Repository/[Module]Repository.cs @@ -22,7 +22,19 @@ namespace [Owner].[Module].Repository public Models.[Module] Get[Module](int [Module]Id) { - return _db.[Module].Find([Module]Id); + return Get[Module]([Module]Id, true); + } + + public Models.[Module] Get[Module](int [Module]Id, bool tracking) + { + if (tracking) + { + return _db.[Module].Find([Module]Id); + } + else + { + return _db.[Module].AsNoTracking().FirstOrDefault(item => item.[Module]Id == [Module]Id); + } } public Models.[Module] Add[Module](Models.[Module] [Module]) From d32b622f7eed102f017c3bb6ab8cc1542fa1b9c9 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 16 Jun 2021 17:24:45 -0400 Subject: [PATCH 19/22] allow order to be defined in page templates --- Oqtane.Server/Repository/SiteRepository.cs | 1164 ++++++++++---------- Oqtane.Shared/Models/SiteTemplate.cs | 3 +- 2 files changed, 612 insertions(+), 555 deletions(-) diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index 6200de2c..c47f3977 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -43,559 +43,6 @@ namespace Oqtane.Repository _config = config; } - private List CreateAdminPages(List pageTemplates = null) - { - if (pageTemplates == null) pageTemplates = new List(); - - // user pages - pageTemplates.Add(new PageTemplate - { - Name = "Login", - Parent = "", - Path = "login", - Icon = Icons.LockLocked, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.View, RoleNames.Everyone, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "User Login", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.View, RoleNames.Everyone, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "Register", - Parent = "", - Path = "register", - Icon = Icons.Person, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.View, RoleNames.Everyone, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Register.Index).ToModuleDefinitionName(), Title = "User Registration", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.View, RoleNames.Everyone, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - Content = "" - } - } - }); - - pageTemplates.Add(new PageTemplate - { - Name = "Reset", - Parent = "", - Path = "reset", - Icon = Icons.Person, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.View, RoleNames.Everyone, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Reset.Index).ToModuleDefinitionName(), Title = "Password Reset", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.View, RoleNames.Everyone, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "Profile", - Parent = "", - Path = "profile", - Icon = Icons.Person, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.View, RoleNames.Registered, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UserProfile.Index).ToModuleDefinitionName(), Title = "User Profile", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.View, RoleNames.Registered, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - Content = "" - } - } - }); - - // admin pages - pageTemplates.Add(new PageTemplate - { - Name = "Admin", Parent = "", Path = "admin", Icon = "", IsNavigation = false, IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Dashboard.Index).ToModuleDefinitionName(), Title = "Admin Dashboard", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "Site Settings", - Parent = "Admin", - Path = "admin/site", - Icon = Icons.Home, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Site.Index).ToModuleDefinitionName(), Title = "Site Settings", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "Page Management", - Parent = "Admin", - Path = "admin/pages", - Icon = Icons.Layers, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Pages.Index).ToModuleDefinitionName(), Title = "Page Management", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "User Management", - Parent = "Admin", - Path = "admin/users", - Icon = Icons.People, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Users.Index).ToModuleDefinitionName(), Title = "User Management", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "Profile Management", - Parent = "Admin", - Path = "admin/profiles", - Icon = Icons.Person, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Profiles.Index).ToModuleDefinitionName(), Title = "Profile Management", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "Role Management", - Parent = "Admin", - Path = "admin/roles", - Icon = Icons.LockLocked, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Roles.Index).ToModuleDefinitionName(), Title = "Role Management", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "File Management", - Parent = "Admin", - Path = "admin/files", - Icon = Icons.File, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Files.Index).ToModuleDefinitionName(), Title = "File Management", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "Recycle Bin", - Parent = "Admin", - Path = "admin/recyclebin", - Icon = Icons.Trash, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.RecycleBin.Index).ToModuleDefinitionName(), Title = "Recycle Bin", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Admin, true), - new Permission(PermissionNames.Edit, RoleNames.Admin, true) - }.EncodePermissions(), - Content = "" - } - } - }); - - // host pages - pageTemplates.Add(new PageTemplate - { - Name = "Event Log", - Parent = "Admin", - Path = "admin/log", - Icon = Icons.MagnifyingGlass, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Logs.Index).ToModuleDefinitionName(), Title = "Event Log", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "Site Management", Parent = "Admin", Path = "admin/sites", Icon = Icons.Globe, IsNavigation = false, IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sites.Index).ToModuleDefinitionName(), Title = "Site Management", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "Module Management", Parent = "Admin", Path = "admin/modules", Icon = Icons.Browser, IsNavigation = false, IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.ModuleDefinitions.Index).ToModuleDefinitionName(), Title = "Module Management", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "Theme Management", Parent = "Admin", Path = "admin/themes", Icon = Icons.Brush, IsNavigation = false, IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Themes.Index).ToModuleDefinitionName(), Title = "Theme Management", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "Language Management", - Parent = "Admin", - Path = "admin/languages", - Icon = Icons.Text, - IsNavigation = false, - IsPersonalizable = false, - PagePermissions = new List - { - 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 - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Languages.Index).ToModuleDefinitionName(), Title = "Language Management", Pane = PaneNames.Admin, - ModulePermissions = new List - { - 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 - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Jobs.Index).ToModuleDefinitionName(), Title = "Scheduled Jobs", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "Sql Management", Parent = "Admin", Path = "admin/sql", Icon = Icons.Spreadsheet, IsNavigation = false, IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sql.Index).ToModuleDefinitionName(), Title = "Sql Management", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "System Info", Parent = "Admin", Path = "admin/system", Icon = Icons.MedicalCross, IsNavigation = false, IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.SystemInfo.Index).ToModuleDefinitionName(), Title = "System Info", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - Content = "" - } - } - }); - pageTemplates.Add(new PageTemplate - { - Name = "System Update", Parent = "Admin", Path = "admin/update", Icon = Icons.Aperture, IsNavigation = false, IsPersonalizable = false, - PagePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - PageTemplateModules = new List - { - new PageTemplateModule - { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Upgrade.Index).ToModuleDefinitionName(), Title = "System Update", Pane = PaneNames.Admin, - ModulePermissions = new List - { - new Permission(PermissionNames.View, RoleNames.Host, true), - new Permission(PermissionNames.Edit, RoleNames.Host, true) - }.EncodePermissions(), - Content = "" - } - } - }); - - return pageTemplates; - } - public IEnumerable GetSites() { return _db.Site; @@ -759,7 +206,7 @@ namespace Oqtane.Repository Name = pagetemplate.Name, Title = "", Path = pagetemplate.Path, - Order = 1, + Order = (pagetemplate.Order == 0) ? 1 : pagetemplate.Order, Url = "", IsNavigation = pagetemplate.IsNavigation, ThemeType = "", @@ -820,5 +267,614 @@ namespace Oqtane.Repository } } } + + private List CreateAdminPages(List pageTemplates = null) + { + if (pageTemplates == null) pageTemplates = new List(); + + // user pages + pageTemplates.Add(new PageTemplate + { + Name = "Login", + Parent = "", + Path = "login", + Icon = Icons.LockLocked, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "User Login", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "Register", + Parent = "", + Path = "register", + Icon = Icons.Person, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Register.Index).ToModuleDefinitionName(), Title = "User Registration", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "" + } + } + }); + + pageTemplates.Add(new PageTemplate + { + Name = "Reset", + Parent = "", + Path = "reset", + Icon = Icons.Person, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Reset.Index).ToModuleDefinitionName(), Title = "Password Reset", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "Profile", + Parent = "", + Path = "profile", + Icon = Icons.Person, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Registered, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UserProfile.Index).ToModuleDefinitionName(), Title = "User Profile", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.View, RoleNames.Registered, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "" + } + } + }); + + // admin pages + pageTemplates.Add(new PageTemplate + { + Name = "Admin", + Parent = "", + Path = "admin", + Icon = "", + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Dashboard.Index).ToModuleDefinitionName(), Title = "Admin Dashboard", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "Site Settings", + Parent = "Admin", + Order = 1, + Path = "admin/site", + Icon = Icons.Home, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Site.Index).ToModuleDefinitionName(), Title = "Site Settings", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "Page Management", + Parent = "Admin", + Order = 3, + Path = "admin/pages", + Icon = Icons.Layers, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Pages.Index).ToModuleDefinitionName(), Title = "Page Management", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "User Management", + Parent = "Admin", + Order = 5, + Path = "admin/users", + Icon = Icons.People, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Users.Index).ToModuleDefinitionName(), Title = "User Management", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "Profile Management", + Parent = "Admin", + Order = 7, + Path = "admin/profiles", + Icon = Icons.Person, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Profiles.Index).ToModuleDefinitionName(), Title = "Profile Management", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "Role Management", + Parent = "Admin", + Order = 9, + Path = "admin/roles", + Icon = Icons.LockLocked, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Roles.Index).ToModuleDefinitionName(), Title = "Role Management", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "File Management", + Parent = "Admin", + Order = 11, + Path = "admin/files", + Icon = Icons.File, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Files.Index).ToModuleDefinitionName(), Title = "File Management", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "Recycle Bin", + Parent = "Admin", + Order = 13, + Path = "admin/recyclebin", + Icon = Icons.Trash, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.RecycleBin.Index).ToModuleDefinitionName(), Title = "Recycle Bin", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "" + } + } + }); + + // host pages + pageTemplates.Add(new PageTemplate + { + Name = "Event Log", + Parent = "Admin", + Order = 15, + Path = "admin/log", + Icon = Icons.MagnifyingGlass, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Logs.Index).ToModuleDefinitionName(), Title = "Event Log", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "Site Management", + Parent = "Admin", + Order = 17, + Path = "admin/sites", + Icon = Icons.Globe, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sites.Index).ToModuleDefinitionName(), Title = "Site Management", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "Module Management", + Parent = "Admin", + Order = 19, + Path = "admin/modules", + Icon = Icons.Browser, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.ModuleDefinitions.Index).ToModuleDefinitionName(), Title = "Module Management", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "Theme Management", + Parent = "Admin", + Order = 21, + Path = "admin/themes", + Icon = Icons.Brush, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Themes.Index).ToModuleDefinitionName(), Title = "Theme Management", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "Language Management", + Parent = "Admin", + Order = 23, + Path = "admin/languages", + Icon = Icons.Text, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + 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 + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Languages.Index).ToModuleDefinitionName(), Title = "Language Management", Pane = PaneNames.Admin, + ModulePermissions = new List + { + 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", + Order = 25, + Path = "admin/jobs", + Icon = Icons.Timer, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Jobs.Index).ToModuleDefinitionName(), Title = "Scheduled Jobs", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "Sql Management", + Parent = "Admin", + Order = 27, + Path = "admin/sql", + Icon = Icons.Spreadsheet, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sql.Index).ToModuleDefinitionName(), Title = "Sql Management", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "System Info", + Parent = "Admin", + Order = 29, + Path = "admin/system", + Icon = Icons.MedicalCross, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.SystemInfo.Index).ToModuleDefinitionName(), Title = "System Info", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + Content = "" + } + } + }); + pageTemplates.Add(new PageTemplate + { + Name = "System Update", + Parent = "Admin", + Order = 31, + Path = "admin/update", + Icon = Icons.Aperture, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule + { + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Upgrade.Index).ToModuleDefinitionName(), Title = "System Update", Pane = PaneNames.Admin, + ModulePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Host, true), + new Permission(PermissionNames.Edit, RoleNames.Host, true) + }.EncodePermissions(), + Content = "" + } + } + }); + + return pageTemplates; + } } } diff --git a/Oqtane.Shared/Models/SiteTemplate.cs b/Oqtane.Shared/Models/SiteTemplate.cs index 74d259bb..7ef52696 100644 --- a/Oqtane.Shared/Models/SiteTemplate.cs +++ b/Oqtane.Shared/Models/SiteTemplate.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; namespace Oqtane.Models @@ -13,6 +13,7 @@ namespace Oqtane.Models { public string Name { get; set; } public string Parent { get; set; } + public int Order { get; set; } public string Path { get; set; } public string Icon { get; set; } public bool IsNavigation { get; set; } From f330c4fcb60c7875d0d18a64fc51ea05112f5f7e Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 16 Jun 2021 22:16:48 -0400 Subject: [PATCH 20/22] add extension method for Localization which allows specification of key and value --- .../OqtaneLocalizationExtensions.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Oqtane.Client/Extensions/OqtaneLocalizationExtensions.cs diff --git a/Oqtane.Client/Extensions/OqtaneLocalizationExtensions.cs b/Oqtane.Client/Extensions/OqtaneLocalizationExtensions.cs new file mode 100644 index 00000000..6ee9c1eb --- /dev/null +++ b/Oqtane.Client/Extensions/OqtaneLocalizationExtensions.cs @@ -0,0 +1,22 @@ +namespace Microsoft.Extensions.Localization +{ + public static class OqtaneLocalizationExtensions + { + /// + /// Gets the string resource for the specified key and returns the value if the resource does not exist + /// + /// + /// the static key used to identify the string resource + /// the default value if the resource for the static key does not exist + /// + public static string GetString(this IStringLocalizer localizer, string key, string value) + { + string localizedValue = localizer[key]; + if (localizedValue == key) // not localized + { + localizedValue = value; + } + return localizedValue; + } + } +} From 32c49f74d359b067cf9a86aa049c84e23813e421 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Thu, 17 Jun 2021 12:12:19 -0400 Subject: [PATCH 21/22] fix module template issues --- .../Extensions/OqtaneLocalizationExtensions.cs | 2 +- .../Controllers/ModuleDefinitionController.cs | 2 +- .../Client/Modules/[Owner].[Module]/Edit.razor | 2 +- .../External/Client/Services/[Module]Service.cs | 9 ++------- .../Modules/Templates/External/Client/_Imports.razor | 5 ++++- .../Server/Controllers/[Module]Controller.cs | 12 ++++++------ 6 files changed, 15 insertions(+), 17 deletions(-) diff --git a/Oqtane.Client/Extensions/OqtaneLocalizationExtensions.cs b/Oqtane.Client/Extensions/OqtaneLocalizationExtensions.cs index 6ee9c1eb..8bb5372a 100644 --- a/Oqtane.Client/Extensions/OqtaneLocalizationExtensions.cs +++ b/Oqtane.Client/Extensions/OqtaneLocalizationExtensions.cs @@ -12,7 +12,7 @@ namespace Microsoft.Extensions.Localization public static string GetString(this IStringLocalizer localizer, string key, string value) { string localizedValue = localizer[key]; - if (localizedValue == key) // not localized + if (localizedValue == key && !string.IsNullOrEmpty(value)) // not localized { localizedValue = value; } diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index 6e945f6b..e5cf3af3 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -103,7 +103,7 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Host)] public ModuleDefinition Post([FromBody] ModuleDefinition moduleDefinition) { - if (ModelState.IsValid && moduleDefinition.SiteId == _alias.SiteId) + if (ModelState.IsValid) { string rootPath; DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath); diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Edit.razor b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Edit.razor index d901cb4f..471f5eae 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Edit.razor +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Edit.razor @@ -80,7 +80,7 @@ try { validated = true; - var interop = new Interop(JSRuntime); + var interop = new Oqtane.UI.Interop(JSRuntime); if (await interop.FormValid(form)) { if (PageState.Action == "Add") diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Services/[Module]Service.cs b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Services/[Module]Service.cs index 5e807628..cd154052 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Services/[Module]Service.cs +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Services/[Module]Service.cs @@ -11,14 +11,9 @@ namespace [Owner].[Module].Services { public class [Module]Service : ServiceBase, I[Module]Service, IService { - private readonly SiteState _siteState; + public [Module]Service(HttpClient http, SiteState siteState) : base(http, siteState) { } - public [Module]Service(HttpClient http, SiteState siteState) : base(http) - { - _siteState = siteState; - } - - private string Apiurl => CreateApiUrl("[Module]", _siteState.Alias); + private string Apiurl => CreateApiUrl("[Module]"); public async Task> Get[Module]sAsync(int ModuleId) { diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/_Imports.razor b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/_Imports.razor index d206b36e..5932080a 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/_Imports.razor +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/_Imports.razor @@ -4,8 +4,10 @@ @using System.Net.Http @using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web +@using Microsoft.Extensions.Localization @using Microsoft.JSInterop @using Oqtane.Models @@ -18,4 +20,5 @@ @using Oqtane.Themes @using Oqtane.Themes.Controls @using Oqtane.UI -@using Oqtane.Enums \ No newline at end of file +@using Oqtane.Enums +@using Oqtane.Interfaces \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Controllers/[Module]Controller.cs b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Controllers/[Module]Controller.cs index ca2d4bea..ca3eeec5 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Controllers/[Module]Controller.cs +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Server/Controllers/[Module]Controller.cs @@ -27,9 +27,9 @@ namespace [Owner].[Module].Controllers public IEnumerable Get(string moduleid) { int ModuleId; - if (int.TryParse(moduleid, out ModuleId) == _authEntityId[EntityNames.Module]) + if (int.TryParse(moduleid, out ModuleId) && ModuleId == AuthEntityId(EntityNames.Module)) { - return _[Module]Repository.Get[Module]s(int.Parse(ModuleId)); + return _[Module]Repository.Get[Module]s(ModuleId); } else { @@ -45,7 +45,7 @@ namespace [Owner].[Module].Controllers public Models.[Module] Get(int id) { Models.[Module] [Module] = _[Module]Repository.Get[Module](id); - if ([Module] != null && [Module].ModuleId != _authEntityId[EntityNames.Module]) + if ([Module] != null && [Module].ModuleId != AuthEntityId(EntityNames.Module)) { return [Module]; } @@ -63,7 +63,7 @@ namespace [Owner].[Module].Controllers [Authorize(Policy = PolicyNames.EditModule)] public Models.[Module] Post([FromBody] Models.[Module] [Module]) { - if (ModelState.IsValid && [Module].ModuleId == _authEntityId[EntityNames.Module]) + if (ModelState.IsValid && [Module].ModuleId == AuthEntityId(EntityNames.Module)) { [Module] = _[Module]Repository.Add[Module]([Module]); _logger.Log(LogLevel.Information, this, LogFunction.Create, "[Module] Added {[Module]}", [Module]); @@ -83,7 +83,7 @@ namespace [Owner].[Module].Controllers [Authorize(Policy = PolicyNames.EditModule)] public Models.[Module] Put(int id, [FromBody] Models.[Module] [Module]) { - if (ModelState.IsValid && [Module].ModuleId == _authEntityId[EntityNames.Module] && _[Module]Repository.Get[Module]([Module].[Module]Id, false) != null) + if (ModelState.IsValid && [Module].ModuleId == AuthEntityId(EntityNames.Module) && _[Module]Repository.Get[Module]([Module].[Module]Id, false) != null) { [Module] = _[Module]Repository.Update[Module]([Module]); _logger.Log(LogLevel.Information, this, LogFunction.Update, "[Module] Updated {[Module]}", [Module]); @@ -104,7 +104,7 @@ namespace [Owner].[Module].Controllers public void Delete(int id) { Models.[Module] [Module] = _[Module]Repository.Get[Module](id); - if ([Module] != null && [Module].ModuleId == _authEntityId[EntityNames.Module]) + if ([Module] != null && [Module].ModuleId == AuthEntityId(EntityNames.Module)) { _[Module]Repository.Delete[Module](id); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "[Module] Deleted {[Module]Id}", id); From 3bc57440077111e815fb4d5603a878bc7ca31fb7 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Fri, 18 Jun 2021 13:01:42 -0400 Subject: [PATCH 22/22] improved error handling, improved consistency of console error messages, added ability to add a Decimal column in Migrations --- Oqtane.Server/Controllers/InstallationController.cs | 7 ++++--- .../Extensions/OqtaneServiceCollectionExtensions.cs | 13 +++++++------ Oqtane.Server/Infrastructure/ConfigManager.cs | 5 +++-- Oqtane.Server/Infrastructure/DatabaseManager.cs | 10 ++++++++-- .../Migrations/EntityBuilders/BaseEntityBuilder.cs | 11 +++++++++++ Oqtane.Server/Modules/MigratableModuleBase.cs | 6 +++--- Oqtane.Server/Program.cs | 9 +++++++-- .../Repository/ModuleDefinitionRepository.cs | 3 ++- Oqtane.Server/Repository/ThemeRepository.cs | 3 +++ Oqtane.Shared/Extensions/AssemblyExtensions.cs | 9 +++++---- 10 files changed, 53 insertions(+), 23 deletions(-) diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index cf4f7048..dc51076f 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -15,6 +15,7 @@ using Microsoft.Extensions.Caching.Memory; using System.Net; using Oqtane.Repository; using Microsoft.AspNetCore.Http; +using System.Diagnostics; namespace Oqtane.Controllers { @@ -130,7 +131,7 @@ namespace Oqtane.Controllers } else { - Console.WriteLine($"The satellite assemblies folder named '{culture}' is not found."); + Debug.WriteLine($"Oqtane Error: The Satellite Assembly Folder For {culture} Does Not Exist"); } } @@ -148,7 +149,7 @@ namespace Oqtane.Controllers } else { - Console.WriteLine("Module " + instance.ModuleDefinition.ModuleDefinitionName + " dependency " + name + ".dll does not exist"); + Debug.WriteLine($"Oqtane Error: Module {instance.ModuleDefinition.ModuleDefinitionName} Dependency {name}.dll Does Not Exist"); } } } @@ -163,7 +164,7 @@ namespace Oqtane.Controllers } else { - Console.WriteLine("Theme " + instance.Theme.ThemeName + " dependency " + name + ".dll does not exist" ); + Debug.WriteLine($"Oqtane Error: Theme {instance.Theme.ThemeName} Dependency {name}.dll Does Not Exist"); } } } diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 0f8ba283..77270f90 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.IO; using System.Linq; using System.Net; @@ -257,7 +258,7 @@ namespace Microsoft.Extensions.DependencyInjection } catch { - Console.WriteLine($"Not Assembly : {dll.Name}"); + Debug.WriteLine($"Oqtane Error: Cannot Get Assembly Name For {dll.Name}"); continue; } @@ -298,24 +299,24 @@ namespace Microsoft.Extensions.DependencyInjection } catch { - Console.WriteLine($"Not Satellite Assembly : {assemblyFile.Name}"); + Debug.WriteLine($"Oqtane Error: Cannot Get Satellite Assembly Name For {assemblyFile.Name}"); continue; } try { Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(assemblyFile.FullName))); - Console.WriteLine($"Loaded : {assemblyName}"); + Debug.WriteLine($"Oqtane Info: Loaded Assembly {assemblyName}"); } - catch (Exception e) + catch (Exception ex) { - Console.WriteLine($"Failed : {assemblyName}\n{e}"); + Debug.WriteLine($"Oqtane Error: Unable To Load Assembly {assemblyName} - {ex}"); } } } else { - Console.WriteLine($"The satellite assemblies folder named '{culture}' is not found."); + Debug.WriteLine($"Oqtane Error: The Satellite Assembly Folder For {culture} Does Not Exist"); } } } diff --git a/Oqtane.Server/Infrastructure/ConfigManager.cs b/Oqtane.Server/Infrastructure/ConfigManager.cs index 3b35b027..6d752a70 100644 --- a/Oqtane.Server/Infrastructure/ConfigManager.cs +++ b/Oqtane.Server/Infrastructure/ConfigManager.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.IO; using Microsoft.Extensions.Configuration; using Newtonsoft.Json; @@ -57,7 +58,7 @@ namespace Oqtane.Infrastructure } catch (Exception ex) { - Console.WriteLine("Error modifying app settings {0}", ex); + Debug.WriteLine($"Oqtane Error: Error Updating App Setting {key} - {ex}"); } } @@ -78,7 +79,7 @@ namespace Oqtane.Infrastructure } catch (Exception ex) { - Console.WriteLine("Error modifying app settings {0}", ex); + Debug.WriteLine($"Oqtane Error: Error Removing App Setting {key} - {ex}"); } } diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index c2d577ee..455fecd6 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -483,11 +483,17 @@ namespace Oqtane.Infrastructure { tenantManager.SetTenant(tenant.TenantId); var moduleObject = ActivatorUtilities.CreateInstance(scope.ServiceProvider, moduleType) as IInstallable; - moduleObject?.Install(tenant, versions[i]); + if (moduleObject == null || !moduleObject.Install(tenant, versions[i])) + { + result.Message = "An Error Occurred Executing IInstallable Interface For " + moduleDefinition.ServerManagerType; + } } else { - sql.ExecuteScript(tenant, moduleType.Assembly, Utilities.GetTypeName(moduleDefinition.ModuleDefinitionName) + "." + versions[i] + ".sql"); + if (!sql.ExecuteScript(tenant, moduleType.Assembly, Utilities.GetTypeName(moduleDefinition.ModuleDefinitionName) + "." + versions[i] + ".sql")) + { + result.Message = "An Error Occurred Executing Database Script " + Utilities.GetTypeName(moduleDefinition.ModuleDefinitionName) + "." + versions[i] + ".sql"; + } } } catch (Exception ex) diff --git a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs index fb2fd69a..f7336e6c 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.NetworkInformation; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; @@ -109,6 +110,16 @@ namespace Oqtane.Migrations.EntityBuilders _migrationBuilder.AlterColumn(RewriteName(name), RewriteName(EntityTableName), maxLength: length, nullable: nullable, unicode: unicode); } + public void AddDecimalColumn(string name, int precision, int scale, bool nullable = false) + { + _migrationBuilder.AddColumn(RewriteName(name), RewriteName(EntityTableName), nullable: nullable, precision: precision, scale: scale); + } + + protected OperationBuilder AddDecimalColumn(ColumnsBuilder table, string name, int precision, int scale, bool nullable = false) + { + return table.Column(name: RewriteName(name), nullable: nullable, precision: precision, scale: scale); + } + public void DropColumn(string name) { _migrationBuilder.DropColumn(RewriteName(name), RewriteName(EntityTableName)); diff --git a/Oqtane.Server/Modules/MigratableModuleBase.cs b/Oqtane.Server/Modules/MigratableModuleBase.cs index 11dbc081..8d682e26 100644 --- a/Oqtane.Server/Modules/MigratableModuleBase.cs +++ b/Oqtane.Server/Modules/MigratableModuleBase.cs @@ -1,10 +1,10 @@ using System; +using System.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Oqtane.Enums; using Oqtane.Models; using Oqtane.Repository; -using Oqtane.Shared; namespace Oqtane.Modules { @@ -28,9 +28,9 @@ namespace Oqtane.Modules migrator.Migrate(); } } - catch (Exception e) + catch (Exception ex) { - Console.WriteLine(e); + Debug.WriteLine($"Oqtane Error: Error Executing Migration - {ex}"); result = false; } diff --git a/Oqtane.Server/Program.cs b/Oqtane.Server/Program.cs index 1ac0797e..e7dd23fc 100644 --- a/Oqtane.Server/Program.cs +++ b/Oqtane.Server/Program.cs @@ -1,9 +1,10 @@ -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.AspNetCore; using Microsoft.Extensions.DependencyInjection; using Oqtane.Infrastructure; +using System.Diagnostics; namespace Oqtane.Server { @@ -15,7 +16,11 @@ namespace Oqtane.Server using (var serviceScope = host.Services.GetRequiredService().CreateScope()) { var databaseManager = serviceScope.ServiceProvider.GetService(); - databaseManager.Install(); + var install = databaseManager.Install(); + if (!string.IsNullOrEmpty(install.Message)) + { + Debug.WriteLine($"Oqtane Error: {install.Message}"); + } } host.Run(); } diff --git a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs index 1b72d3f8..33ae7cd5 100644 --- a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs +++ b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -264,7 +265,7 @@ namespace Oqtane.Repository }.EncodePermissions(); } - Console.WriteLine($"Registering module: {moduledefinition.ModuleDefinitionName}"); + Debug.WriteLine($"Oqtane Info: Registering Module {moduledefinition.ModuleDefinitionName}"); moduledefinitions.Add(moduledefinition); index = moduledefinitions.FindIndex(item => item.ModuleDefinitionName == qualifiedModuleType); } diff --git a/Oqtane.Server/Repository/ThemeRepository.cs b/Oqtane.Server/Repository/ThemeRepository.cs index e338c080..e5943cbe 100644 --- a/Oqtane.Server/Repository/ThemeRepository.cs +++ b/Oqtane.Server/Repository/ThemeRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -104,6 +105,8 @@ namespace Oqtane.Repository { theme.PackageName = Utilities.GetTypeName(theme.ThemeName); } + + Debug.WriteLine($"Oqtane Info: Registering Theme {theme.ThemeName}"); themes.Add(theme); index = themes.FindIndex(item => item.ThemeName == qualifiedThemeType); } diff --git a/Oqtane.Shared/Extensions/AssemblyExtensions.cs b/Oqtane.Shared/Extensions/AssemblyExtensions.cs index db29c5e2..d2b667ea 100644 --- a/Oqtane.Shared/Extensions/AssemblyExtensions.cs +++ b/Oqtane.Shared/Extensions/AssemblyExtensions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.Loader; @@ -100,7 +101,7 @@ namespace System.Reflection } catch { - Console.WriteLine($"Not Assembly : {dll.Name}"); + Debug.WriteLine($"Oqtane Error: Cannot Get Assembly Name For {dll.Name}"); } loadContext.LoadOqtaneAssembly(dll, assemblyName); @@ -122,11 +123,11 @@ namespace System.Reflection { assembly = loadContext.LoadFromStream(new MemoryStream(File.ReadAllBytes(dll.FullName))); } - Console.WriteLine($"Loaded : {assemblyName}"); + Debug.WriteLine($"Oqtane Info: Loaded Assembly {assemblyName}"); } - catch (Exception e) + catch (Exception ex) { - Console.WriteLine($"Failed : {assemblyName}\n{e}"); + Debug.WriteLine($"Oqtane Error: Unable To Load Assembly {assemblyName} - {ex}"); } } }