From a1449fb2dd1a2884fe07b9a84898ac61ab222ae4 Mon Sep 17 00:00:00 2001 From: Jim Spillane Date: Sat, 9 May 2020 14:58:39 -0400 Subject: [PATCH 01/10] Fix Uploadable files When testing for allowable file extensions using a comma separated list, like (jpg,mp3,txt,zip), extensions such as .xt or .p3 will return true. Adding Split(',') will test each of the extensions correctly. Adding ToLower() will allow mixed case extensions, like .JPG or .Zip to return true. --- Oqtane.Server/Controllers/FileController.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Oqtane.Server/Controllers/FileController.cs b/Oqtane.Server/Controllers/FileController.cs index 6c3223c9..5a09d5a5 100644 --- a/Oqtane.Server/Controllers/FileController.cs +++ b/Oqtane.Server/Controllers/FileController.cs @@ -194,7 +194,7 @@ namespace Oqtane.Controllers CreateDirectory(folderPath); string filename = url.Substring(url.LastIndexOf("/", StringComparison.Ordinal) + 1); // check for allowable file extensions - if (Constants.UploadableFiles.Contains(Path.GetExtension(filename).Replace(".", ""))) + if (Constants.UploadableFiles.Split(',').Contains(Path.GetExtension(filename).ToLower().Replace(".", ""))) { try { @@ -317,7 +317,7 @@ namespace Oqtane.Controllers } // check for allowable file extensions - if (!Constants.UploadableFiles.Contains(Path.GetExtension(filename)?.Replace(".", ""))) + if (!Constants.UploadableFiles.Split(',').Contains(Path.GetExtension(filename)?.ToLower().Replace(".", ""))) { System.IO.File.Delete(Path.Combine(folder, filename + ".tmp")); } @@ -469,7 +469,7 @@ namespace Oqtane.Controllers file.ImageHeight = 0; file.ImageWidth = 0; - if (Constants.ImageFiles.Contains(file.Extension)) + if (Constants.ImageFiles.Split(',').Contains(file.Extension.ToLower())) { FileStream stream = new FileStream(filepath, FileMode.Open, FileAccess.Read); using (var image = Image.FromStream(stream)) From 7c814a67b30895083daf57262c4a5d370b8e5aae Mon Sep 17 00:00:00 2001 From: Pavel Vesely Date: Mon, 11 May 2020 11:05:17 +0200 Subject: [PATCH 02/10] IServerStartup implementation --- Oqtane.Client/Modules/ModuleBase.cs | 2 +- .../ApplicationBuilderExtensions.cs | 26 +++++++++++++++++++ .../Extensions/AssemblyExtensions.cs | 19 +++++++++++++- .../Extensions/OqtaneMvcBuilderExtensions.cs | 17 ++++++++++++ .../OqtaneServiceCollectionExtensions.cs | 8 +++++- .../Interfaces/IServerStartup.cs | 17 ++++++++++++ Oqtane.Server/Startup.cs | 11 ++++---- 7 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs create mode 100644 Oqtane.Server/Infrastructure/Interfaces/IServerStartup.cs diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index c81f8d10..188da769 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -9,7 +9,7 @@ using Oqtane.UI; namespace Oqtane.Modules { - public class ModuleBase : ComponentBase, IModuleControl + public abstract class ModuleBase : ComponentBase, IModuleControl { private Logger _logger; diff --git a/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs b/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs new file mode 100644 index 00000000..d1c77301 --- /dev/null +++ b/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs @@ -0,0 +1,26 @@ +using System; +using System.Linq; +using System.Reflection; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Oqtane.Infrastructure; + +namespace Oqtane.Extensions +{ + public static class ApplicationBuilderExtensions + { + public static IApplicationBuilder ConfigureOqtaneAssemblies(this IApplicationBuilder app, IWebHostEnvironment env) + { + var startUps = AppDomain.CurrentDomain + .GetOqtaneAssemblies() + .SelectMany(x => x.GetInstances()); + + foreach (var startup in startUps) + { + startup.Configure(app, env); + } + + return app; + } + } +} diff --git a/Oqtane.Server/Extensions/AssemblyExtensions.cs b/Oqtane.Server/Extensions/AssemblyExtensions.cs index 443b8cc6..cc04b6da 100644 --- a/Oqtane.Server/Extensions/AssemblyExtensions.cs +++ b/Oqtane.Server/Extensions/AssemblyExtensions.cs @@ -31,7 +31,24 @@ namespace System.Reflection } return assembly.GetTypes() - .Where(t => t.GetInterfaces().Contains(interfaceType)); + //.Where(t => t.GetInterfaces().Contains(interfaceType)); + .Where(x => interfaceType.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract); + } + + public static IEnumerable GetInstances(this Assembly assembly) where T : class + { + if (assembly is null) + { + throw new ArgumentNullException(nameof(assembly)); + } + var type = typeof(T); + var list = assembly.GetTypes() + .Where(x => type.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract && !x.IsGenericType); + + foreach (var type1 in list) + { + if (Activator.CreateInstance(type1) is T instance) yield return instance; + } } public static bool IsOqtaneAssembly(this Assembly assembly) diff --git a/Oqtane.Server/Extensions/OqtaneMvcBuilderExtensions.cs b/Oqtane.Server/Extensions/OqtaneMvcBuilderExtensions.cs index fdb801df..b3f489bf 100644 --- a/Oqtane.Server/Extensions/OqtaneMvcBuilderExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneMvcBuilderExtensions.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationParts; +using Oqtane.Infrastructure; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection @@ -30,6 +31,22 @@ namespace Microsoft.Extensions.DependencyInjection } } } + + return mvcBuilder; + } + + + public static IMvcBuilder ConfigureOqtaneMvc(this IMvcBuilder mvcBuilder) + { + var startUps = AppDomain.CurrentDomain + .GetOqtaneAssemblies() + .SelectMany(x => x.GetInstances()); + + foreach (var startup in startUps) + { + startup.ConfigureMvc(mvcBuilder); + } + return mvcBuilder; } } diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 5c093f48..64bffb8a 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -53,11 +53,17 @@ namespace Microsoft.Extensions.DependencyInjection services.AddSingleton(hostedServiceType, serviceType); } } + + var startUps = assembly.GetInstances(); + foreach (var startup in startUps) + { + startup.ConfigureServices(services); + } } - return services; } + private static void LoadAssemblies() { var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); diff --git a/Oqtane.Server/Infrastructure/Interfaces/IServerStartup.cs b/Oqtane.Server/Infrastructure/Interfaces/IServerStartup.cs new file mode 100644 index 00000000..bbdff5d6 --- /dev/null +++ b/Oqtane.Server/Infrastructure/Interfaces/IServerStartup.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; + +namespace Oqtane.Infrastructure +{ + public interface IServerStartup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + void ConfigureServices(IServiceCollection services); + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + void Configure(IApplicationBuilder app, IWebHostEnvironment env); + void ConfigureMvc(IMvcBuilder mvcBuilder); + } +} + diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index de4c89a7..d3ba352b 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -14,6 +14,7 @@ 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; @@ -187,14 +188,13 @@ namespace Oqtane services.AddTransient(); services.AddTransient(); - // load the external assemblies into the app domain + // load the external assemblies into the app domain, install services services.AddOqtaneParts(); services.AddMvc() + .AddNewtonsoftJson() .AddOqtaneApplicationParts() // register any Controllers from custom modules - .AddNewtonsoftJson(); - - + .ConfigureOqtaneMvc(); // any additional configuration from IStart classes. services.AddSwaggerGen(c => { @@ -217,14 +217,12 @@ namespace Oqtane // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } - app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseBlazorFrameworkFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); - app.UseSwagger(); app.UseSwaggerUI(c => { @@ -237,6 +235,7 @@ namespace Oqtane endpoints.MapControllers(); endpoints.MapFallbackToPage("/_Host"); }); + app.ConfigureOqtaneAssemblies(env); } } } From 7f157582cc14d1e70de9ff69c6b63d867784898d Mon Sep 17 00:00:00 2001 From: Mike Casas Date: Mon, 11 May 2020 13:47:12 -0400 Subject: [PATCH 03/10] Update IModuleControl.cs Added additional comments. --- Oqtane.Client/Modules/IModuleControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Oqtane.Client/Modules/IModuleControl.cs b/Oqtane.Client/Modules/IModuleControl.cs index c4f2fdee..ee5120ba 100644 --- a/Oqtane.Client/Modules/IModuleControl.cs +++ b/Oqtane.Client/Modules/IModuleControl.cs @@ -7,6 +7,6 @@ namespace Oqtane.Modules SecurityAccessLevel SecurityAccessLevel { get; } // defines the security access level for this control - defaults to View string Title { get; } // title to display for this control - defaults to module title string Actions { get; } // allows for routing by configuration rather than by convention ( comma delimited ) - defaults to using component file name - bool UseAdminContainer { get; } // container for embedding module control - defaults to true + bool UseAdminContainer { get; } // container for embedding module control - defaults to true. false will suppress the default modal UI popup behavior and render the component in the page. } } From da73d519d78d6b8a123800aff9a8d40359ff74e1 Mon Sep 17 00:00:00 2001 From: Pavel Vesely Date: Mon, 11 May 2020 13:10:22 +0200 Subject: [PATCH 04/10] IClientStartup implementation --- Oqtane.Client/Program.cs | 35 +++++++++++++++---- .../Controllers/ModuleDefinitionController.cs | 10 ++++++ .../OqtaneServiceCollectionExtensions.cs | 15 ++++++-- Oqtane.Server/Startup.cs | 9 +++-- .../Extensions/AssemblyExtensions.cs | 11 ++++++ Oqtane.Shared/Interfaces/IClientStartup.cs | 11 ++++++ Oqtane.Shared/Oqtane.Shared.csproj | 1 + 7 files changed, 80 insertions(+), 12 deletions(-) rename {Oqtane.Server => Oqtane.Shared}/Extensions/AssemblyExtensions.cs (84%) create mode 100644 Oqtane.Shared/Interfaces/IClientStartup.cs diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index 74fa8de4..26bac719 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -4,8 +4,10 @@ using System.Threading.Tasks; using Oqtane.Services; using System.Reflection; using System; +using System.Collections.Generic; using System.Linq; using System.Net.Http; +using System.Net.Http.Json; using Oqtane.Modules; using Oqtane.Shared; using Oqtane.Providers; @@ -19,10 +21,9 @@ namespace Oqtane.Client { var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add("app"); + HttpClient httpClient = new HttpClient {BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)}; - builder.Services.AddSingleton( - new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) } - ); + builder.Services.AddSingleton(httpClient); builder.Services.AddOptions(); // register auth services @@ -57,14 +58,16 @@ namespace Oqtane.Client builder.Services.AddScoped(); builder.Services.AddScoped(); + await LoadClientAssemblies(httpClient); + // dynamically register module contexts and repository services Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { - Type[] implementationtypes = assembly.GetTypes() - .Where(item => item.GetInterfaces().Contains(typeof(IService))) - .ToArray(); - foreach (Type implementationtype in implementationtypes) + var implementationTypes = assembly.GetTypes() + .Where(item => item.GetInterfaces().Contains(typeof(IService))); + + foreach (Type implementationtype in implementationTypes) { Type servicetype = Type.GetType(implementationtype.AssemblyQualifiedName.Replace(implementationtype.Name, "I" + implementationtype.Name)); if (servicetype != null) @@ -76,9 +79,27 @@ namespace Oqtane.Client builder.Services.AddScoped(implementationtype, implementationtype); // no interface defined for service } } + + assembly.GetInstances() + .ToList() + .ForEach(x => x.ConfigureServices(builder.Services)); } await builder.Build().RunAsync(); } + + private static async Task LoadClientAssemblies(HttpClient http) + { + var list = await http.GetFromJsonAsync>($"/~/api/ModuleDefinition/load"); + // get list of loaded assemblies on the client ( in the client-side hosting module the browser client has its own app domain ) + var assemblyList = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetName().Name).ToList(); + foreach (var name in list) + { + if (assemblyList.Contains(name)) continue; + // download assembly from server and load + var bytes = await http.GetByteArrayAsync($"/~/api/ModuleDefinition/load/{name}.dll"); + Assembly.Load(bytes); + } + } } } diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index e1b9534c..fcd9dcd8 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -170,6 +170,16 @@ namespace Oqtane.Controllers return null; } } + // GET api//load/assembyname + [HttpGet("load")] + public List Load() + { + var assemblies = AppDomain.CurrentDomain.GetOqtaneClientAssemblies(); + var list = AppDomain.CurrentDomain.GetOqtaneClientAssemblies().Select(a => a.GetName().Name).ToList(); + var deps = assemblies.SelectMany(a => a.GetReferencedAssemblies()).Distinct(); + list.AddRange(deps.Where(a=>a.Name.EndsWith(".oqtane",StringComparison.OrdinalIgnoreCase)).Select(a=>a.Name)); + return list; + } // POST api/?moduleid=x [HttpPost] diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 64bffb8a..3e778869 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -8,21 +8,23 @@ using Microsoft.Extensions.Hosting; using Oqtane.Extensions; using Oqtane.Infrastructure; using Oqtane.Modules; +using Oqtane.Services; using Oqtane.Shared; +using Oqtane.UI; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection { public static class OqtaneServiceCollectionExtensions { - public static IServiceCollection AddOqtaneParts(this IServiceCollection services) + public static IServiceCollection AddOqtaneParts(this IServiceCollection services, Runtime runtime) { LoadAssemblies(); - services.AddOqtaneServices(); + services.AddOqtaneServices(runtime); return services; } - private static IServiceCollection AddOqtaneServices(this IServiceCollection services) + private static IServiceCollection AddOqtaneServices(this IServiceCollection services, Runtime runtime) { if (services is null) { @@ -59,6 +61,13 @@ namespace Microsoft.Extensions.DependencyInjection { startup.ConfigureServices(services); } + + if (runtime == Runtime.Server) + { + assembly.GetInstances() + .ToList() + .ForEach(x => x.ConfigureServices(services)); + } } return services; } diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index d3ba352b..34f73ffe 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -19,7 +19,8 @@ using Oqtane.Infrastructure; using Oqtane.Repository; using Oqtane.Security; using Oqtane.Services; -using Oqtane.Shared; +using Oqtane.Shared; +using Oqtane.UI; namespace Oqtane { @@ -27,6 +28,7 @@ namespace Oqtane { public IConfigurationRoot Configuration { get; } private string _webRoot; + private Runtime _runtime; public Startup(IWebHostEnvironment env) { @@ -34,6 +36,9 @@ namespace Oqtane .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); Configuration = builder.Build(); + + _runtime = (Configuration.GetSection("Runtime").Value == "WebAssembly") ? Runtime.WebAssembly : Runtime.Server; + _webRoot = env.WebRootPath; AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(env.ContentRootPath, "Data")); } @@ -189,7 +194,7 @@ namespace Oqtane services.AddTransient(); // load the external assemblies into the app domain, install services - services.AddOqtaneParts(); + services.AddOqtaneParts(_runtime); services.AddMvc() .AddNewtonsoftJson() diff --git a/Oqtane.Server/Extensions/AssemblyExtensions.cs b/Oqtane.Shared/Extensions/AssemblyExtensions.cs similarity index 84% rename from Oqtane.Server/Extensions/AssemblyExtensions.cs rename to Oqtane.Shared/Extensions/AssemblyExtensions.cs index cc04b6da..e97de64f 100644 --- a/Oqtane.Server/Extensions/AssemblyExtensions.cs +++ b/Oqtane.Shared/Extensions/AssemblyExtensions.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Oqtane.Services; using Oqtane.Shared; // ReSharper disable once CheckNamespace @@ -35,6 +36,11 @@ namespace System.Reflection .Where(x => interfaceType.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract); } + public static IEnumerable GetTypes(this Assembly assembly) + { + return assembly.GetTypes(typeof(T)); + } + public static IEnumerable GetInstances(this Assembly assembly) where T : class { if (assembly is null) @@ -65,5 +71,10 @@ namespace System.Reflection { return appDomain.GetAssemblies().Where(a => a.IsOqtaneAssembly()); } + public static IEnumerable GetOqtaneClientAssemblies(this AppDomain appDomain) + { + return appDomain.GetOqtaneAssemblies() + .Where(a => a.GetTypes().Any()); + } } } diff --git a/Oqtane.Shared/Interfaces/IClientStartup.cs b/Oqtane.Shared/Interfaces/IClientStartup.cs new file mode 100644 index 00000000..c063431c --- /dev/null +++ b/Oqtane.Shared/Interfaces/IClientStartup.cs @@ -0,0 +1,11 @@ + +using Microsoft.Extensions.DependencyInjection; + +namespace Oqtane.Services +{ + public interface IClientStartup + { + // This method gets called by the runtime. Use this method to add services to the container. + void ConfigureServices(IServiceCollection services); + } +} diff --git a/Oqtane.Shared/Oqtane.Shared.csproj b/Oqtane.Shared/Oqtane.Shared.csproj index c50111cd..eca4e4ee 100644 --- a/Oqtane.Shared/Oqtane.Shared.csproj +++ b/Oqtane.Shared/Oqtane.Shared.csproj @@ -18,6 +18,7 @@ + From 6f3fe8d933cf4d6a21c7100a6011bd2d48f0c62f Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 12 May 2020 13:24:51 -0400 Subject: [PATCH 05/10] validate folder names, handle missing files more gracefully --- Oqtane.Client/Modules/Admin/Files/Edit.razor | 14 ++++-- Oqtane.Server/Controllers/FileController.cs | 13 +++-- Oqtane.Server/Controllers/FolderController.cs | 47 ++++++++++++++---- .../Oqtane.Themes.BlazorTheme/Theme.css | 14 +++++- Oqtane.Server/wwwroot/images/error.png | Bin 0 -> 1623 bytes Oqtane.Server/wwwroot/js/interop.js | 40 +++++++++++---- Oqtane.Shared/Shared/Constants.cs | 1 + 7 files changed, 99 insertions(+), 30 deletions(-) create mode 100644 Oqtane.Server/wwwroot/images/error.png diff --git a/Oqtane.Client/Modules/Admin/Files/Edit.razor b/Oqtane.Client/Modules/Admin/Files/Edit.razor index 0083cce0..1d7ddc81 100644 --- a/Oqtane.Client/Modules/Admin/Files/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Files/Edit.razor @@ -149,10 +149,16 @@ { folder = await FolderService.AddFolderAsync(folder); } - - await FolderService.UpdateFolderOrderAsync(folder.SiteId, folder.FolderId, folder.ParentId); - await logger.LogInformation("Folder Saved {Folder}", folder); - NavigationManager.NavigateTo(NavigateUrl()); + if (folder != null) + { + await FolderService.UpdateFolderOrderAsync(folder.SiteId, folder.FolderId, folder.ParentId); + await logger.LogInformation("Folder Saved {Folder}", folder); + NavigationManager.NavigateTo(NavigateUrl()); + } + else + { + AddModuleMessage("An Error Was Encountered Saving The Folder", MessageType.Error); + } } else { diff --git a/Oqtane.Server/Controllers/FileController.cs b/Oqtane.Server/Controllers/FileController.cs index 5a09d5a5..0c30bbdf 100644 --- a/Oqtane.Server/Controllers/FileController.cs +++ b/Oqtane.Server/Controllers/FileController.cs @@ -16,6 +16,7 @@ using System.Net; using Oqtane.Enums; using Oqtane.Infrastructure; using Oqtane.Repository; +using Microsoft.AspNetCore.Routing.Constraints; // ReSharper disable StringIndexOfIsCultureSpecific.1 @@ -396,12 +397,13 @@ namespace Oqtane.Controllers [HttpGet("download/{id}")] public IActionResult Download(int id) { + string errorpath = Path.Combine(GetFolderPath("images"), "error.png"); Models.File file = _files.GetFile(id); if (file != null) { if (_userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions)) { - string filepath = Path.Combine(GetFolderPath(file.Folder) , file.Name); + string filepath = Path.Combine(GetFolderPath(file.Folder), file.Name); if (System.IO.File.Exists(filepath)) { byte[] filebytes = System.IO.File.ReadAllBytes(filepath); @@ -411,21 +413,24 @@ namespace Oqtane.Controllers { _logger.Log(LogLevel.Error, this, LogFunction.Read, "File Does Not Exist {FileId} {FilePath}", id, filepath); HttpContext.Response.StatusCode = 404; - return null; + byte[] filebytes = System.IO.File.ReadAllBytes(errorpath); + return File(filebytes, "application/octet-stream", file.Name); } } else { _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access File {FileId}", id); HttpContext.Response.StatusCode = 401; - return null; + byte[] filebytes = System.IO.File.ReadAllBytes(errorpath); + return File(filebytes, "application/octet-stream", file.Name); } } else { _logger.Log(LogLevel.Error, this, LogFunction.Read, "File Not Found {FileId}", id); HttpContext.Response.StatusCode = 404; - return null; + byte[] filebytes = System.IO.File.ReadAllBytes(errorpath); + return File(filebytes, "application/octet-stream", "error.png"); } } diff --git a/Oqtane.Server/Controllers/FolderController.cs b/Oqtane.Server/Controllers/FolderController.cs index 68a01e23..34c13a1b 100644 --- a/Oqtane.Server/Controllers/FolderController.cs +++ b/Oqtane.Server/Controllers/FolderController.cs @@ -10,7 +10,6 @@ using Oqtane.Extensions; using Oqtane.Infrastructure; using Oqtane.Repository; using Oqtane.Security; -using System.IO; namespace Oqtane.Controllers { @@ -106,13 +105,23 @@ namespace Oqtane.Controllers } if (_userPermissions.IsAuthorized(User,PermissionNames.Edit, permissions)) { - if (string.IsNullOrEmpty(folder.Path) && folder.ParentId != null) + if (FolderPathValid(folder)) { - Folder parent = _folders.GetFolder(folder.ParentId.Value); - folder.Path = Utilities.PathCombine(parent.Path, folder.Name,"\\"); + if (string.IsNullOrEmpty(folder.Path) && folder.ParentId != null) + { + Folder parent = _folders.GetFolder(folder.ParentId.Value); + folder.Path = Utilities.PathCombine(parent.Path, folder.Name); + } + folder.Path = Utilities.PathCombine(folder.Path, "\\"); + folder = _folders.AddFolder(folder); + _logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Added {Folder}", folder); + } + else + { + _logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Name Not Valid {Folder}", folder); + HttpContext.Response.StatusCode = 401; + folder = null; } - folder = _folders.AddFolder(folder); - _logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Added {Folder}", folder); } else { @@ -131,13 +140,23 @@ namespace Oqtane.Controllers { if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Folder, folder.FolderId, PermissionNames.Edit)) { - if (string.IsNullOrEmpty(folder.Path) && folder.ParentId != null) + if (FolderPathValid(folder)) { - Folder parent = _folders.GetFolder(folder.ParentId.Value); - folder.Path = Utilities.PathCombine(parent.Path, folder.Name,"\\"); + if (string.IsNullOrEmpty(folder.Path) && folder.ParentId != null) + { + Folder parent = _folders.GetFolder(folder.ParentId.Value); + folder.Path = Utilities.PathCombine(parent.Path, folder.Name); + } + folder.Path = Utilities.PathCombine(folder.Path, "\\"); + folder = _folders.UpdateFolder(folder); + _logger.Log(LogLevel.Information, this, LogFunction.Update, "Folder Updated {Folder}", folder); + } + else + { + _logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Name Not Valid {Folder}", folder); + HttpContext.Response.StatusCode = 401; + folder = null; } - folder = _folders.UpdateFolder(folder); - _logger.Log(LogLevel.Information, this, LogFunction.Update, "Folder Updated {Folder}", folder); } else { @@ -191,5 +210,11 @@ namespace Oqtane.Controllers HttpContext.Response.StatusCode = 401; } } + + private bool FolderPathValid(Folder folder) + { + // prevent folder path traversal and reserved devices + return (!folder.Name.Contains("\\") && !folder.Name.Contains("/") && !Constants.ReservedDevices.Split(',').Contains(folder.Name.ToUpper())); + } } } diff --git a/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.BlazorTheme/Theme.css b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.BlazorTheme/Theme.css index a9e5c15e..fba5b909 100644 --- a/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.BlazorTheme/Theme.css +++ b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.BlazorTheme/Theme.css @@ -101,6 +101,12 @@ flex-direction: row; } + .app-logo { + display: block; + margin-left: auto; + margin-right: auto; + } + .breadcrumbs { position: fixed; left: 275px; @@ -163,7 +169,13 @@ } } -@media (max-width: 767px) { +@media (max-width: 767px) { + .app-logo { + height: 80px; + display: flex; + align-items: center; + } + .breadcrumbs { position: fixed; top: 150px; diff --git a/Oqtane.Server/wwwroot/images/error.png b/Oqtane.Server/wwwroot/images/error.png new file mode 100644 index 0000000000000000000000000000000000000000..0095d2f13c1c5683e5d8dd61c835fc4e0c40268d GIT binary patch literal 1623 zcmV-d2B`UoP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1?)*gK~#8N?V8Jv z6jc<)t9u$|p(KhTN-#*GVgw%;jV{zEj698xkPsKfjd5Yz_!qcx>(;~=H5lWQ>$Jox1l-*PW_GU}WT$ zAJI00h|xMMvVldJB-3c+=`+J_%Gl1c=J-sM%aX2XY%al zdF@<%Cl@TJJ&he^ti>Gv$g%KzZhW9)Ur0diMFey!<`rlL%fdlKuf>is-s9M}Xg`PT zNE9sUi`RrKa?!)EOz{C>+=cKN5^-P3C%O^Z&Q}jbp~yvx;#RqEX@zk^v3iOm+#7qk z7b;r$CQX2YIB?!Y_9+|2BOKSbgw~m`9owzYcD{xKS{coD-bEpxGGQ!XTw@Aw>>VUw z8@3yv?R@bJ5JfIZ2UHf)1$j0?67IqFLVP@i36MoD3dt%PVcb?TE-Z&$6~>N=;D1pA zW*5O$FbTaXi~~^wTOrJZxfaHODT1wFJaa9K162fDAta&O!Z>h6uoc2`=%z3ZWD#ry zlh93J?CT=va_9tMCUjC5`??4|55I)RJKzcU7)e-<%@eP0vXj^0y_lOkE)j=#{k;mC z84Ku@ukVWBN)o*sI~P%%`0CC8?96+9+lvTn5BA2`Q!c)TFTh`+F@$315;T?~z9Y<} zXR&z+88-o5;4;Xp10-NSw(KR)D;yvJH)FHJ>l^B~BG@aW|D3iHudnZZ3HAy>SC)8v zeOCl~h4i1(ENy-FOR$&76EFJimte18QO^^vukU^d_6k)IOl+2TeN_=uR8<6FRRm#P z#;PKi*nr>R{qWnkm5o2)gV6W;Jp2V8fS<*!Y>dH&;HPox9|T=l;`Mc11btK6!V8C+ z7VF@5I@`cRZKLlKSidd!MrRwCs5|Mq18d)`gqf)A^nDU*3`cb)D76Tlgqs-nUF;~< zferQtI2*sgyXo^9wt+o@9f7{`&W4HFN}qi;u!n24Xfubc67~l)sXMU~*yGJ+{QW{Y z33=j0$3@UBrwt7Fe&UP!(f$at75-#9fr+|kr|K+RV8F)6MB| z8;#n>Sd*KcVJ7u1`no?c6W_vx^K`^)Ddz0e^{Vs$%CnlN~({|Pz!ft{l>}P0F-^RN2wgm2h%V;`l?CY#?&+iv# zQoZj4_gg`~m*Hi!BNBF$alNle$P=%xqdmbh8Q3+d_{*_AfeWC6t>augRXMkoAnFA3 z4o$>QAtZiUmq4HXM*4cq1bwg9(*6MJwTm%|Q_xq?z6Y`HNUg#yqV0VZzr5LuTw2Cr zAs$KYJIc95jBl)2;`K#gN61-FBx8!d0;{0&V89p9r)V{vxt6}p4*SMWD8bjznPh=W zC-^Lk>wmTF1PXI$xWr~+LEtjPyZ*17cEzv;dEZZ_o4MlkO?6TP74HX3Z@{#8u>$Vp zyuruU66CqqS7BPbaMN=?eOF@RF*x?~8xxflFI)z@Iqy!fQ2bKFzr=A`yfCJHN#7#k zMe!oYjjzL6(9VIapfH17Ly(J;C$uI$b1Ke<2D_RXat6n{VGubR@hq}0_g%t$U!;9a zeCAY`^j-A50h=dYU-9n*xv5XS$gZ$|;*PU9|8 zi5DhmP!M!wiPu*ZK}A(X5LQJH=4GrZf{7gj1YKF;^;JbsQB@IyRS|@F85^V}P)ZSW zzim+9exk?{udjF!tkt4NvF_0JI}XD~V4iq=#lI7Tqf=AO;mOJ9B93b$WVqRkMzIa7 zQ*QGA_Hi5y4Mj)m^_u@O%M&k(e&dEkqpzX3+0 Vx%U~ByY>J8002ovPDHLkV1jsB6LSCn literal 0 HcmV?d00001 diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js index 50c8aa9b..5f41709c 100644 --- a/Oqtane.Server/wwwroot/js/interop.js +++ b/Oqtane.Server/wwwroot/js/interop.js @@ -81,14 +81,26 @@ window.interop = { if (link.href !== url) { link.setAttribute('href', url); } - if (type !== "" && link.type !== type) { - link.setAttribute('type', type); + if (type !== "") { + if (link.type !== type) { + link.setAttribute('type', type); + } + } else { + link.removeAttribute('type'); } - if (integrity !== "" && link.integrity !== integrity) { - link.setAttribute('integrity', integrity); + if (integrity !== "") { + if (link.integrity !== integrity) { + link.setAttribute('integrity', integrity); + } + } else { + link.removeAttribute('integrity'); } - if (crossorigin !== "" && link.crossOrigin !== crossorigin) { - link.setAttribute('crossorigin', crossorigin); + if (crossorigin !== "") { + if (link.crossOrigin !== crossorigin) { + link.setAttribute('crossorigin', crossorigin); + } + } else { + link.removeAttribute('crossorigin'); } } }, @@ -126,11 +138,19 @@ window.interop = { if (script.src !== src) { script.src = src; } - if (integrity !== "" && script.integrity !== integrity) { - script.setAttribute('integrity', integrity); + if (integrity !== "") { + if (script.integrity !== integrity) { + script.setAttribute('integrity', integrity); + } + } else { + script.removeAttribute('integrity'); } - if (crossorigin !== "" && script.crossorigin !== crossorigin) { - script.setAttribute('crossorigin', crossorigin); + if (crossorigin !== "") { + if (script.crossOrigin !== crossorigin) { + script.setAttribute('crossorigin', crossorigin); + } + } else { + script.removeAttribute('crossorigin'); } } else { diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index c50347e2..30ca2950 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -43,5 +43,6 @@ public const string ImageFiles = "jpg,jpeg,jpe,gif,bmp,png"; public const string UploadableFiles = "jpg,jpeg,jpe,gif,bmp,png,mov,wmv,avi,mp4,mp3,doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,nupkg"; + public const string ReservedDevices = "CON,NUL,PRN,COM1,COM2,COM3,COM4,COM5,COM6,COM7,COM8,COM9,LPT1,LPT2,LPT3,LPT4,LPT5,LPT6,LPT7,LPT8,LPT9"; } } From f05c7d79e391cbdc5e13ae89f0d980e16fd016f7 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 12 May 2020 14:31:18 -0400 Subject: [PATCH 06/10] add security to site template API --- Oqtane.Server/Controllers/SiteTemplateController.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Oqtane.Server/Controllers/SiteTemplateController.cs b/Oqtane.Server/Controllers/SiteTemplateController.cs index 2f709fb1..c63170c1 100644 --- a/Oqtane.Server/Controllers/SiteTemplateController.cs +++ b/Oqtane.Server/Controllers/SiteTemplateController.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Oqtane.Models; using Oqtane.Repository; +using Oqtane.Shared; namespace Oqtane.Controllers { @@ -17,6 +19,7 @@ namespace Oqtane.Controllers // GET: api/ [HttpGet] + [Authorize(Roles = Constants.HostRole)] public IEnumerable Get() { return _siteTemplates.GetSiteTemplates(); From 9eec0fd86b788feed0c904c1cafe0c3fdc8e4c04 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 12 May 2020 15:04:07 -0400 Subject: [PATCH 07/10] updated HtmlText module to use dependency injection --- Oqtane.Client/Modules/HtmlText/Edit.razor | 16 +++++++--------- Oqtane.Client/Modules/HtmlText/Index.razor | 15 +++------------ .../Modules/HtmlText/Services/HtmlTextService.cs | 2 +- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/Oqtane.Client/Modules/HtmlText/Edit.razor b/Oqtane.Client/Modules/HtmlText/Edit.razor index 9df38687..c9c94bc7 100644 --- a/Oqtane.Client/Modules/HtmlText/Edit.razor +++ b/Oqtane.Client/Modules/HtmlText/Edit.razor @@ -3,9 +3,8 @@ @using Oqtane.Modules.Controls @namespace Oqtane.Modules.HtmlText @inherits ModuleBase +@inject IHtmlTextService HtmlTextService @inject NavigationManager NavigationManager -@inject HttpClient http -@inject SiteState sitestate @if (_content != null) { @@ -14,7 +13,8 @@ Cancel @if (!string.IsNullOrEmpty(_content)) { -

+
+
} } @@ -35,8 +35,7 @@ { try { - var htmltextservice = new HtmlTextService(http, sitestate); - var htmltext = await htmltextservice.GetHtmlTextAsync(ModuleState.ModuleId); + var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId); if (htmltext != null) { _content = htmltext.Content; @@ -65,19 +64,18 @@ try { - var htmltextservice = new HtmlTextService(http, sitestate); - var htmltext = await htmltextservice.GetHtmlTextAsync(ModuleState.ModuleId); + var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId); if (htmltext != null) { htmltext.Content = content; - await htmltextservice.UpdateHtmlTextAsync(htmltext); + await HtmlTextService.UpdateHtmlTextAsync(htmltext); } else { htmltext = new HtmlTextInfo(); htmltext.ModuleId = ModuleState.ModuleId; htmltext.Content = content; - await htmltextservice.AddHtmlTextAsync(htmltext); + await HtmlTextService.AddHtmlTextAsync(htmltext); } await logger.LogInformation("Html/Text Content Saved {HtmlText}", htmltext); diff --git a/Oqtane.Client/Modules/HtmlText/Index.razor b/Oqtane.Client/Modules/HtmlText/Index.razor index c76afa02..6821c425 100644 --- a/Oqtane.Client/Modules/HtmlText/Index.razor +++ b/Oqtane.Client/Modules/HtmlText/Index.razor @@ -1,21 +1,13 @@ @using Oqtane.Modules.HtmlText.Services -@using Oqtane.Modules.HtmlText.Models @namespace Oqtane.Modules.HtmlText @inherits ModuleBase -@inject NavigationManager NavigationManager -@inject HttpClient http -@inject SiteState sitestate +@inject IHtmlTextService HtmlTextService @((MarkupString)content) @if (PageState.EditMode) { -
-} - -@if (PageState.EditMode) -{ -

+


} @code { @@ -25,8 +17,7 @@ { try { - var htmltextservice = new HtmlTextService(http, sitestate); - var htmltext = await htmltextservice.GetHtmlTextAsync(ModuleState.ModuleId); + var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId); if (htmltext != null) { content = htmltext.Content; diff --git a/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs b/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs index cb73b9a4..51ab7887 100644 --- a/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs +++ b/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs @@ -8,7 +8,7 @@ using Oqtane.Shared; namespace Oqtane.Modules.HtmlText.Services { - public class HtmlTextService : ServiceBase, IHtmlTextService + public class HtmlTextService : ServiceBase, IHtmlTextService, IService { private readonly SiteState _siteState; From 6fd0efbb7341b7f0593f271f9052564c236b0c14 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 12 May 2020 16:31:53 -0400 Subject: [PATCH 08/10] updated module creator templates to use dependency injection in module components --- .../Admin/ModuleCreator/Templates/External/Client/Edit.razor | 5 +---- .../ModuleCreator/Templates/External/Client/Index.razor | 5 +---- .../ModuleCreator/Templates/External/Client/ModuleInfo.cs | 1 - .../Internal/Oqtane.Client/Modules/[Module]/Edit.razor | 5 +---- .../Internal/Oqtane.Client/Modules/[Module]/Index.razor | 5 +---- .../Internal/Oqtane.Client/Modules/[Module]/ModuleInfo.cs | 1 - 6 files changed, 4 insertions(+), 18 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Client/Edit.razor b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Client/Edit.razor index 84e83aae..4faa3dd5 100644 --- a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Client/Edit.razor +++ b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Client/Edit.razor @@ -4,9 +4,8 @@ @namespace [Owner].[Module]s.Modules @inherits ModuleBase +@inject I[Module]Service [Module]Service @inject NavigationManager NavigationManager -@inject HttpClient http -@inject SiteState sitestate @@ -31,7 +30,6 @@ public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit; public override string Actions => "Add,Edit"; - I[Module]Service [Module]Service; int _id; string _name; string _createdby; @@ -43,7 +41,6 @@ { try { - [Module]Service = new [Module]Service(http, sitestate); if (PageState.Action == "Edit") { _id = Int32.Parse(PageState.QueryString["id"]); diff --git a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Client/Index.razor b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Client/Index.razor index 1c92fc1a..fceedfea 100644 --- a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Client/Index.razor +++ b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Client/Index.razor @@ -3,9 +3,8 @@ @namespace [Owner].[Module]s.Modules @inherits ModuleBase +@inject I[Module]Service [Module]Service @inject NavigationManager NavigationManager -@inject HttpClient http -@inject SiteState sitestate @if (_[Module]s == null) { @@ -71,14 +70,12 @@ else @code { - I[Module]Service [Module]Service; List<[Module]> _[Module]s; protected override async Task OnInitializedAsync() { try { - [Module]Service = new [Module]Service(http, sitestate); _[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId); } catch (Exception ex) diff --git a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Client/ModuleInfo.cs b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Client/ModuleInfo.cs index 35a74a27..6a1f21b1 100644 --- a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Client/ModuleInfo.cs +++ b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Client/ModuleInfo.cs @@ -10,7 +10,6 @@ namespace [Owner].[Module]s.Modules Name = "[Module]", Description = "[Module]", Version = "1.0.0", - Dependencies = "[Owner].[Module]s.Shared.Oqtane", ServerManagerType = "[ServerManagerType]", ReleaseVersions = "1.0.0" }; diff --git a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Client/Modules/[Module]/Edit.razor b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Client/Modules/[Module]/Edit.razor index 84e83aae..4faa3dd5 100644 --- a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Client/Modules/[Module]/Edit.razor +++ b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Client/Modules/[Module]/Edit.razor @@ -4,9 +4,8 @@ @namespace [Owner].[Module]s.Modules @inherits ModuleBase +@inject I[Module]Service [Module]Service @inject NavigationManager NavigationManager -@inject HttpClient http -@inject SiteState sitestate
@@ -31,7 +30,6 @@ public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit; public override string Actions => "Add,Edit"; - I[Module]Service [Module]Service; int _id; string _name; string _createdby; @@ -43,7 +41,6 @@ { try { - [Module]Service = new [Module]Service(http, sitestate); if (PageState.Action == "Edit") { _id = Int32.Parse(PageState.QueryString["id"]); diff --git a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Client/Modules/[Module]/Index.razor b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Client/Modules/[Module]/Index.razor index fdb11b98..c2c129de 100644 --- a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Client/Modules/[Module]/Index.razor +++ b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Client/Modules/[Module]/Index.razor @@ -3,9 +3,8 @@ @namespace [Owner].[Module]s.Modules @inherits ModuleBase +@inject I[Module]Service [Module]Service @inject NavigationManager NavigationManager -@inject HttpClient http -@inject SiteState sitestate @if (_[Module]s == null) { @@ -62,14 +61,12 @@ else @code { - I[Module]Service [Module]Service; List<[Module]> _[Module]s; protected override async Task OnInitializedAsync() { try { - [Module]Service = new [Module]Service(http, sitestate); _[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId); } catch (Exception ex) diff --git a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Client/Modules/[Module]/ModuleInfo.cs b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Client/Modules/[Module]/ModuleInfo.cs index a95a461e..6a1f21b1 100644 --- a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Client/Modules/[Module]/ModuleInfo.cs +++ b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Client/Modules/[Module]/ModuleInfo.cs @@ -10,7 +10,6 @@ namespace [Owner].[Module]s.Modules Name = "[Module]", Description = "[Module]", Version = "1.0.0", - Dependencies = "[Owner].[Module]s.Module.Shared", ServerManagerType = "[ServerManagerType]", ReleaseVersions = "1.0.0" }; From 4c188b782dda8163c2ea6db2ec0e1c065016b703 Mon Sep 17 00:00:00 2001 From: Pavel Vesely Date: Tue, 12 May 2020 23:17:37 +0200 Subject: [PATCH 09/10] ClientAssembly selection criteria changed --- Oqtane.Shared/Extensions/AssemblyExtensions.cs | 4 +++- .../Modules => Oqtane.Shared/Interfaces}/IModuleControl.cs | 0 .../Themes => Oqtane.Shared/Interfaces}/IThemeControl.cs | 0 3 files changed, 3 insertions(+), 1 deletion(-) rename {Oqtane.Client/Modules => Oqtane.Shared/Interfaces}/IModuleControl.cs (100%) rename {Oqtane.Client/Themes => Oqtane.Shared/Interfaces}/IThemeControl.cs (100%) diff --git a/Oqtane.Shared/Extensions/AssemblyExtensions.cs b/Oqtane.Shared/Extensions/AssemblyExtensions.cs index e97de64f..4742d368 100644 --- a/Oqtane.Shared/Extensions/AssemblyExtensions.cs +++ b/Oqtane.Shared/Extensions/AssemblyExtensions.cs @@ -1,8 +1,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Oqtane.Modules; using Oqtane.Services; using Oqtane.Shared; +using Oqtane.Themes; // ReSharper disable once CheckNamespace namespace System.Reflection @@ -74,7 +76,7 @@ namespace System.Reflection public static IEnumerable GetOqtaneClientAssemblies(this AppDomain appDomain) { return appDomain.GetOqtaneAssemblies() - .Where(a => a.GetTypes().Any()); + .Where(a => a.GetTypes().Any() || a.GetTypes().Any() || a.GetTypes().Any()); } } } diff --git a/Oqtane.Client/Modules/IModuleControl.cs b/Oqtane.Shared/Interfaces/IModuleControl.cs similarity index 100% rename from Oqtane.Client/Modules/IModuleControl.cs rename to Oqtane.Shared/Interfaces/IModuleControl.cs diff --git a/Oqtane.Client/Themes/IThemeControl.cs b/Oqtane.Shared/Interfaces/IThemeControl.cs similarity index 100% rename from Oqtane.Client/Themes/IThemeControl.cs rename to Oqtane.Shared/Interfaces/IThemeControl.cs From 560c995564e7611e882a5468c9baf148229feca9 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 12 May 2020 20:31:31 -0400 Subject: [PATCH 10/10] Include AliasId in service API calls ( this is not needed for interacting with the MasterDB repository however it is needed for tenant-based logging ) --- Oqtane.Client/Services/AliasService.cs | 13 +++++++++---- Oqtane.Client/Services/JobLogService.cs | 10 ++++++++-- Oqtane.Client/Services/JobService.cs | 10 ++++++++-- Oqtane.Client/Services/ServiceBase.cs | 4 ++-- Oqtane.Client/Services/SqlService.cs | 10 ++++++++-- Oqtane.Client/Services/TenantService.cs | 10 ++++++++-- 6 files changed, 43 insertions(+), 14 deletions(-) diff --git a/Oqtane.Client/Services/AliasService.cs b/Oqtane.Client/Services/AliasService.cs index 1e0f5ac8..21df7dd0 100644 --- a/Oqtane.Client/Services/AliasService.cs +++ b/Oqtane.Client/Services/AliasService.cs @@ -5,16 +5,21 @@ using System.Linq; using System.Collections.Generic; using System.Net; using System; - +using Oqtane.Shared; namespace Oqtane.Services { public class AliasService : ServiceBase, IAliasService { - - public AliasService(HttpClient http) :base(http) { } - private string Apiurl => CreateApiUrl("Alias"); + private readonly SiteState _siteState; + + public AliasService(HttpClient http, SiteState siteState) : base(http) + { + _siteState = siteState; + } + + private string Apiurl => CreateApiUrl(_siteState.Alias, "Alias"); public async Task> GetAliasesAsync() { diff --git a/Oqtane.Client/Services/JobLogService.cs b/Oqtane.Client/Services/JobLogService.cs index c15940b5..aa518771 100644 --- a/Oqtane.Client/Services/JobLogService.cs +++ b/Oqtane.Client/Services/JobLogService.cs @@ -3,14 +3,20 @@ using System.Threading.Tasks; using System.Net.Http; using System.Linq; using System.Collections.Generic; +using Oqtane.Shared; namespace Oqtane.Services { public class JobLogService : ServiceBase, IJobLogService { - public JobLogService(HttpClient http) :base(http) { } + private readonly SiteState _siteState; - private string Apiurl => CreateApiUrl("JobLog"); + public JobLogService(HttpClient http, SiteState siteState) : base(http) + { + _siteState = siteState; + } + + private string Apiurl => CreateApiUrl(_siteState.Alias, "JobLog"); public async Task> GetJobLogsAsync() { diff --git a/Oqtane.Client/Services/JobService.cs b/Oqtane.Client/Services/JobService.cs index 14cd96ad..3161cd90 100644 --- a/Oqtane.Client/Services/JobService.cs +++ b/Oqtane.Client/Services/JobService.cs @@ -3,15 +3,21 @@ using System.Threading.Tasks; using System.Net.Http; using System.Linq; using System.Collections.Generic; +using Oqtane.Shared; namespace Oqtane.Services { public class JobService : ServiceBase, IJobService { - public JobService(HttpClient http) : base(http) { } + private readonly SiteState _siteState; - private string Apiurl => CreateApiUrl("Job"); + public JobService(HttpClient http, SiteState siteState) : base(http) + { + _siteState = siteState; + } + private string Apiurl => CreateApiUrl(_siteState.Alias, "Job"); + public async Task> GetJobsAsync() { List jobs = await GetJsonAsync>(Apiurl); diff --git a/Oqtane.Client/Services/ServiceBase.cs b/Oqtane.Client/Services/ServiceBase.cs index 57bad2b7..091709f2 100644 --- a/Oqtane.Client/Services/ServiceBase.cs +++ b/Oqtane.Client/Services/ServiceBase.cs @@ -135,13 +135,13 @@ namespace Oqtane.Services //TODO Missing content JSON validation } - // create an API Url which is tenant agnostic ( for use with entities in the MasterDB ) + // create an API Url which is tenant agnostic ( for use during installation ) public string CreateApiUrl(string serviceName) { return CreateApiUrl(null, serviceName); } - // create an API Url which is tenant aware ( for use with entities in the TenantDB ) + // create an API Url which is tenant aware ( for use with repositories ) public string CreateApiUrl(Alias alias, string serviceName) { string apiurl = "/"; diff --git a/Oqtane.Client/Services/SqlService.cs b/Oqtane.Client/Services/SqlService.cs index a99fbd23..719156b2 100644 --- a/Oqtane.Client/Services/SqlService.cs +++ b/Oqtane.Client/Services/SqlService.cs @@ -1,4 +1,5 @@ using Oqtane.Models; +using Oqtane.Shared; using System.Net.Http; using System.Threading.Tasks; @@ -6,9 +7,14 @@ namespace Oqtane.Services { public class SqlService : ServiceBase, ISqlService { - public SqlService(HttpClient http) : base(http) { } + private readonly SiteState _siteState; - private string Apiurl => CreateApiUrl("Sql"); + public SqlService(HttpClient http, SiteState siteState) : base(http) + { + _siteState = siteState; + } + + private string Apiurl => CreateApiUrl(_siteState.Alias, "Sql"); public async Task ExecuteQueryAsync(SqlQuery sqlquery) { diff --git a/Oqtane.Client/Services/TenantService.cs b/Oqtane.Client/Services/TenantService.cs index d8e9be02..d644348e 100644 --- a/Oqtane.Client/Services/TenantService.cs +++ b/Oqtane.Client/Services/TenantService.cs @@ -3,14 +3,20 @@ using System.Net.Http; using System.Threading.Tasks; using System.Collections.Generic; using System.Linq; +using Oqtane.Shared; namespace Oqtane.Services { public class TenantService : ServiceBase, ITenantService { - public TenantService(HttpClient http) : base(http) { } + private readonly SiteState _siteState; - private string Apiurl => CreateApiUrl("Tenant"); + public TenantService(HttpClient http, SiteState siteState) : base(http) + { + _siteState = siteState; + } + + private string Apiurl => CreateApiUrl(_siteState.Alias, "Tenant"); public async Task> GetTenantsAsync() {