diff --git a/Oqtane.Client/App.razor b/Oqtane.Client/App.razor index 3d13adff..ca4b25bd 100644 --- a/Oqtane.Client/App.razor +++ b/Oqtane.Client/App.razor @@ -1,31 +1,39 @@ -@inject IInstallationService InstallationService +@inject IInstallationService InstallationService @if (_initialized) { - @if (!_installed) + @if (!_installation.Success) { } else { - - - - - + @if (string.IsNullOrEmpty(_installation.Message)) + { + + + + + + } + else + { +
+ @_installation.Message +
+ } } } @code { + private Installation _installation; private bool _initialized; - private bool _installed; private PageState PageState { get; set; } protected override async Task OnParametersSetAsync() { - var installation = await InstallationService.IsInstalled(); - _installed = installation.Success; + _installation = await InstallationService.IsInstalled(); _initialized = true; } diff --git a/Oqtane.Client/Modules/Admin/Files/Edit.razor b/Oqtane.Client/Modules/Admin/Files/Edit.razor index 892f0559..b2ac3b64 100644 --- a/Oqtane.Client/Modules/Admin/Files/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Files/Edit.razor @@ -36,7 +36,7 @@ - + diff --git a/Oqtane.Client/Modules/Admin/Login/Index.razor b/Oqtane.Client/Modules/Admin/Login/Index.razor index bbd2428a..86ec7b0a 100644 --- a/Oqtane.Client/Modules/Admin/Login/Index.razor +++ b/Oqtane.Client/Modules/Admin/Login/Index.razor @@ -11,26 +11,28 @@ } - -
- -
- -
-
+ @code { - public override string Name => "Default"; + public override string Name => "Default Theme"; public override string Panes => string.Empty; diff --git a/Oqtane.Client/UI/ContainerBuilder.razor b/Oqtane.Client/UI/ContainerBuilder.razor index 6992c34a..174f251f 100644 --- a/Oqtane.Client/UI/ContainerBuilder.razor +++ b/Oqtane.Client/UI/ContainerBuilder.razor @@ -1,11 +1,21 @@ @namespace Oqtane.UI - @DynamicComponent + @if (_useadminborder) + { +
+ @DynamicComponent +
+ } + else + { + @DynamicComponent + }
@code { private Module _moduleState; + private bool _useadminborder = false; [CascadingParameter] protected PageState PageState { get; set; } @@ -24,6 +34,15 @@ container = (!string.IsNullOrEmpty(PageState.Site.AdminContainerType)) ? PageState.Site.AdminContainerType : Constants.DefaultAdminContainer; } + if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) && PageState.Action == Constants.DefaultAction) + { + _useadminborder = true; + } + else + { + _useadminborder = false; + } + DynamicComponent = builder => { Type containerType = Type.GetType(container); diff --git a/Oqtane.Client/UI/Interop.cs b/Oqtane.Client/UI/Interop.cs index 3964b070..b54fde6f 100644 --- a/Oqtane.Client/UI/Interop.cs +++ b/Oqtane.Client/UI/Interop.cs @@ -1,3 +1,4 @@ +using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; using System.Threading.Tasks; @@ -232,5 +233,19 @@ namespace Oqtane.UI return Task.CompletedTask; } } + + public ValueTask FormValid(ElementReference form) + { + try + { + return _jsRuntime.InvokeAsync( + "Oqtane.Interop.formValid", + form); + } + catch + { + return new ValueTask(Task.FromResult(false)); + } + } } } diff --git a/Oqtane.Client/UI/Pane.razor b/Oqtane.Client/UI/Pane.razor index 0c04ff94..fe71f45e 100644 --- a/Oqtane.Client/UI/Pane.razor +++ b/Oqtane.Client/UI/Pane.razor @@ -6,7 +6,7 @@ @if (_useadminborder) { -
+
@((MarkupString)_panetitle) @DynamicComponent
@@ -18,7 +18,6 @@ else @code { private bool _useadminborder = false; - private string _paneadminborder = "container"; private string _panetitle = ""; [CascadingParameter] @@ -31,15 +30,14 @@ else protected override void OnParametersSet() { - if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) && Name != PaneNames.Admin) + if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) && PageState.Action == Constants.DefaultAction) { _useadminborder = true; - _paneadminborder = "app-pane-admin-border"; _panetitle = "
" + Name + " Pane
"; } else { - _paneadminborder = "container"; + _useadminborder = false; _panetitle = ""; } @@ -130,4 +128,4 @@ else builder.SetKey(module.PageModuleId); builder.CloseComponent(); } -} \ No newline at end of file +} diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 6b42f15b..70bda7df 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -80,7 +80,7 @@ var urlparameters = string.Empty; var editmode = false; var reload = Reload.None; - var lastsyncdate = DateTime.UtcNow; + var lastsyncdate = DateTime.UtcNow.AddHours(-1); var runtime = GetRuntime(); Uri uri = new Uri(_absoluteUri); @@ -107,9 +107,14 @@ SiteState.Alias = alias; // set state for services lastsyncdate = alias.SyncDate; - // process any sync events for site + // process any sync events if (reload != Reload.Site && alias.SyncEvents.Any()) { + // if running on WebAssembly reload the client application if the server application was restarted + if (runtime == Shared.Runtime.WebAssembly && PageState != null && alias.SyncEvents.Exists(item => item.TenantId == -1)) + { + NavigationManager.NavigateTo(_absoluteUri + (!_absoluteUri.Contains("?") ? "?" : "&") + "reload", true); + } if (alias.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == alias.SiteId)) { reload = Reload.Site; diff --git a/Oqtane.Client/wwwroot/Themes/Siliqon.TestTheme/Theme.css b/Oqtane.Client/wwwroot/Themes/Siliqon.TestTheme/Theme.css new file mode 100644 index 00000000..93d1b672 --- /dev/null +++ b/Oqtane.Client/wwwroot/Themes/Siliqon.TestTheme/Theme.css @@ -0,0 +1,83 @@ +/* Oqtane Styles */ + +body { + padding-top: 7rem; +} + +.controls { + z-index: 2000; + padding-top: 15px; + padding-bottom: 15px; + margin-right: 10px; +} + +.app-menu .nav-item { + font-size: 0.9rem; + padding-bottom: 0.5rem; +} + +.app-menu .nav-item a { + border-radius: 4px; + height: 3rem; + display: flex; + align-items: center; + line-height: 3rem; +} + +.app-menu .nav-item a.active { + background-color: rgba(255,255,255,0.25); + color: white; +} + +.app-menu .nav-item a:hover { + background-color: rgba(255,255,255,0.1); + color: white; +} + +.app-menu .nav-link .oi { + width: 1.5rem; + font-size: 1.1rem; + vertical-align: text-top; + top: -2px; +} + +.navbar-toggler { + background-color: rgba(255, 255, 255, 0.1); + margin-left: auto; +} + +div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu { + color:#ffffff; +} + +@media (max-width: 767px) { + + .app-menu { + width: 100% + } + + .navbar { + position: fixed; + top: 60px; + width: 100%; + } + + .controls { + height: 60px; + top: 15px; + position: fixed; + top: 0px; + width: 100%; + background-color: rgb(0, 0, 0); + } + + .controls-group { + float: right; + margin-right: 25px; + } + + .content { + position: relative; + top: 60px; + } +} diff --git a/Oqtane.Server/Controllers/FolderController.cs b/Oqtane.Server/Controllers/FolderController.cs index aad20a77..a3fcb03a 100644 --- a/Oqtane.Server/Controllers/FolderController.cs +++ b/Oqtane.Server/Controllers/FolderController.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; @@ -69,6 +69,10 @@ namespace Oqtane.Controllers public Folder GetByPath(int siteId, string path) { var folderPath = WebUtility.UrlDecode(path); + if (!(folderPath.EndsWith(System.IO.Path.DirectorySeparatorChar) || folderPath.EndsWith(System.IO.Path.AltDirectorySeparatorChar))) + { + folderPath = Utilities.PathCombine(folderPath, System.IO.Path.DirectorySeparatorChar.ToString()); + } Folder folder = _folders.GetFolder(siteId, folderPath); if (folder != null) if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions)) diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index cac15728..2d8491d6 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -55,8 +55,7 @@ namespace Oqtane.Controllers [HttpGet("installed")] public Installation IsInstalled() { - bool isInstalled = _databaseManager.IsInstalled(); - return new Installation {Success = isInstalled, Message = string.Empty}; + return _databaseManager.IsInstalled(); } [HttpGet("upgrade")] @@ -130,7 +129,14 @@ namespace Oqtane.Controllers var instance = Activator.CreateInstance(type) as IModule; foreach (string name in instance.ModuleDefinition.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { - if (!list.Contains(name)) list.Insert(0, name); + if (System.IO.File.Exists(Path.Combine(binFolder, name + ".dll"))) + { + if (!list.Contains(name)) list.Insert(0, name); + } + else + { + Console.WriteLine("Module " + instance.ModuleDefinition.ModuleDefinitionName + " dependency " + name + ".dll does not exist"); + } } } foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(ITheme)))) @@ -138,7 +144,14 @@ namespace Oqtane.Controllers var instance = Activator.CreateInstance(type) as ITheme; foreach (string name in instance.Theme.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { - if (!list.Contains(name)) list.Insert(0, name); + if (System.IO.File.Exists(Path.Combine(binFolder, name + ".dll"))) + { + if (!list.Contains(name)) list.Insert(0, name); + } + else + { + Console.WriteLine("Theme " + instance.Theme.ThemeName + " dependency " + name + ".dll does not exist" ); + } } } } diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index f417ce33..b9d7d47f 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -13,8 +13,6 @@ using Oqtane.Repository; using Oqtane.Security; using System; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Configuration; -using System.Xml.Linq; using System.Text.Json; namespace Oqtane.Controllers @@ -174,7 +172,21 @@ namespace Oqtane.Controllers } } - // POST api/?moduleid=x + // GET: api//templates + [HttpGet("templates")] + [Authorize(Roles = RoleNames.Host)] + public List GetTemplates() + { + var templates = new List(); + string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", Path.DirectorySeparatorChar.ToString()); + foreach (string directory in Directory.GetDirectories(templatePath)) + { + templates.Add(directory.Replace(templatePath, "")); + } + return templates; + } + + // POST api/ [HttpPost] [Authorize(Roles = RoleNames.Host)] public ModuleDefinition Post([FromBody] ModuleDefinition moduleDefinition) @@ -185,30 +197,12 @@ namespace Oqtane.Controllers DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath); string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", moduleDefinition.Template,Path.DirectorySeparatorChar.ToString()); - if (moduleDefinition.Template == "internal") - { - rootPath = Utilities.PathCombine(rootFolder.FullName,Path.DirectorySeparatorChar.ToString()); - moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", Oqtane.Client"; - moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, Oqtane.Server"; - } - else - { - rootPath = Utilities.PathCombine(rootFolder.Parent.FullName , moduleDefinition.Owner + "." + moduleDefinition.Name,Path.DirectorySeparatorChar.ToString()); - moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Client.Oqtane"; - moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Server.Oqtane"; - } + rootPath = Utilities.PathCombine(rootFolder.Parent.FullName , moduleDefinition.Owner + "." + moduleDefinition.Name,Path.DirectorySeparatorChar.ToString()); + moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Client.Oqtane"; + moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Server.Oqtane"; ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, moduleDefinition); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Module Definition Created {ModuleDefinition}", moduleDefinition); - - if (moduleDefinition.Template == "internal") - { - // add embedded resources to project file - List resources = new List(); - resources.Add(Utilities.PathCombine("Modules", moduleDefinition.Owner + "." + moduleDefinition.Name, "Scripts", moduleDefinition.Owner + "." + moduleDefinition.Name + ".1.0.0.sql")); - resources.Add(Utilities.PathCombine("Modules", moduleDefinition.Owner + "." + moduleDefinition.Name, "Scripts", moduleDefinition.Owner + "." + moduleDefinition.Name + ".Uninstall.sql")); - EmbedResourceFiles(Utilities.PathCombine(rootPath, "Oqtane.Server", "Oqtane.Server.csproj"), resources); - } } return moduleDefinition; @@ -269,19 +263,5 @@ namespace Oqtane.Controllers } } } - - private void EmbedResourceFiles(string projectfile, List resources) - { - XDocument project = XDocument.Load(projectfile); - var itemGroup = project.Descendants("ItemGroup").Descendants("EmbeddedResource").FirstOrDefault().Parent; - if (itemGroup != null) - { - foreach (var resource in resources) - { - itemGroup.Add(new XElement("EmbeddedResource", new XAttribute("Include", resource))); - } - } - project.Save(projectfile); - } } } diff --git a/Oqtane.Server/Controllers/NotificationController.cs b/Oqtane.Server/Controllers/NotificationController.cs index 5c73eb78..8fbb4872 100644 --- a/Oqtane.Server/Controllers/NotificationController.cs +++ b/Oqtane.Server/Controllers/NotificationController.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using Oqtane.Enums; @@ -65,7 +65,7 @@ namespace Oqtane.Controllers if (IsAuthorized(notification.FromUserId)) { notification = _notifications.AddNotification(notification); - _logger.Log(LogLevel.Information, this, LogFunction.Create, "Notification Added {Notification}", notification); + _logger.Log(LogLevel.Information, this, LogFunction.Create, "Notification Added {NotificationId}", notification.NotificationId); } return notification; } @@ -78,7 +78,7 @@ namespace Oqtane.Controllers if (IsAuthorized(notification.FromUserId)) { notification = _notifications.UpdateNotification(notification); - _logger.Log(LogLevel.Information, this, LogFunction.Update, "Notification Updated {Folder}", notification); + _logger.Log(LogLevel.Information, this, LogFunction.Update, "Notification Updated {NotificationId}", notification.NotificationId); } return notification; } diff --git a/Oqtane.Server/Controllers/ThemeController.cs b/Oqtane.Server/Controllers/ThemeController.cs index 851aeb68..6b2f7892 100644 --- a/Oqtane.Server/Controllers/ThemeController.cs +++ b/Oqtane.Server/Controllers/ThemeController.cs @@ -103,5 +103,91 @@ namespace Oqtane.Controllers } } + // GET: api//templates + [HttpGet("templates")] + [Authorize(Roles = RoleNames.Host)] + public List GetTemplates() + { + var templates = new List(); + string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Themes", "Templates", Path.DirectorySeparatorChar.ToString()); + foreach (string directory in Directory.GetDirectories(templatePath)) + { + templates.Add(directory.Replace(templatePath, "")); + } + return templates; + } + + // POST api/ + [HttpPost] + [Authorize(Roles = RoleNames.Host)] + public Theme Post([FromBody] Theme theme) + { + if (ModelState.IsValid) + { + string rootPath; + DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath); + string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Themes", "Templates", theme.Template, Path.DirectorySeparatorChar.ToString()); + + rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, theme.Owner + "." + theme.Name, Path.DirectorySeparatorChar.ToString()); + theme.ThemeName = theme.Owner + "." + theme.Name + ", " + theme.Owner + "." + theme.Name + ".Client.Oqtane"; + + ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, theme); + _logger.Log(LogLevel.Information, this, LogFunction.Create, "Theme Created {Theme}", theme); + } + + return theme; + } + + private void ProcessTemplatesRecursively(DirectoryInfo current, string rootPath, string rootFolder, string templatePath, Theme theme) + { + // process folder + string folderPath = Utilities.PathCombine(rootPath, current.FullName.Replace(templatePath, "")); + folderPath = folderPath.Replace("[Owner]", theme.Owner); + folderPath = folderPath.Replace("[Theme]", theme.Name); + if (!Directory.Exists(folderPath)) + { + Directory.CreateDirectory(folderPath); + } + + FileInfo[] files = current.GetFiles("*.*"); + if (files != null) + { + foreach (FileInfo file in files) + { + // process file + string filePath = Path.Combine(folderPath, file.Name); + filePath = filePath.Replace("[Owner]", theme.Owner); + filePath = filePath.Replace("[Theme]", theme.Name); + + string text = System.IO.File.ReadAllText(file.FullName); + text = text.Replace("[Owner]", theme.Owner); + text = text.Replace("[Theme]", theme.Name); + text = text.Replace("[RootPath]", rootPath); + text = text.Replace("[RootFolder]", rootFolder); + text = text.Replace("[Folder]", folderPath); + text = text.Replace("[File]", Path.GetFileName(filePath)); + if (theme.Version == "local") + { + text = text.Replace("[FrameworkVersion]", Constants.Version); + text = text.Replace("[ClientReference]", "..\\..\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Client.dll"); + text = text.Replace("[SharedReference]", "..\\..\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Shared.dll"); + } + else + { + text = text.Replace("[FrameworkVersion]", theme.Version); + text = text.Replace("[ClientReference]", ""); + text = text.Replace("[SharedReference]", ""); + } + System.IO.File.WriteAllText(filePath, text); + } + + DirectoryInfo[] folders = current.GetDirectories(); + + foreach (DirectoryInfo folder in folders.Reverse()) + { + ProcessTemplatesRecursively(folder, rootPath, rootFolder, templatePath, theme); + } + } + } } } diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs index 9819994b..4d3f1abc 100644 --- a/Oqtane.Server/Controllers/UserController.cs +++ b/Oqtane.Server/Controllers/UserController.cs @@ -111,7 +111,6 @@ namespace Oqtane.Controllers return null; } - //TODO shoud be moved to another layer private async Task CreateUser(User user) { User newUser = null; @@ -261,18 +260,50 @@ namespace Oqtane.Controllers // DELETE api//5?siteid=x [HttpDelete("{id}")] [Authorize(Roles = RoleNames.Admin)] - public async Task Delete(int id) + public async Task Delete(int id, string siteid) { - IdentityUser identityuser = await _identityUserManager.FindByNameAsync(_users.GetUser(id).Username); - - if (identityuser != null) + User user = _users.GetUser(id); + if (user != null) { - var result = await _identityUserManager.DeleteAsync(identityuser); - - if (result != null) + // remove user roles for site + foreach (UserRole userrole in _userRoles.GetUserRoles(user.UserId, Int32.Parse(siteid)).ToList()) { - _users.DeleteUser(id); - _logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Deleted {UserId}", id); + _userRoles.DeleteUserRole(userrole.UserRoleId); + _logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Role Deleted {UserRole}", userrole); + } + + // remove user folder for site + var folder = _folders.GetFolder(Int32.Parse(siteid), Utilities.PathCombine("Users", user.UserId.ToString(), Path.DirectorySeparatorChar.ToString())); + if (folder != null) + { + if (Directory.Exists(_folders.GetFolderPath(folder))) + { + Directory.Delete(_folders.GetFolderPath(folder), true); + } + _folders.DeleteFolder(folder.FolderId); + _logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Folder Deleted {Folder}", folder); + } + + // delete user if they are not a member of any other sites + if (!_userRoles.GetUserRoles(user.UserId, -1).Any()) + { + // get identity user + IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username); + if (identityuser != null) + { + // delete identity user + var result = await _identityUserManager.DeleteAsync(identityuser); + if (result != null) + { + // delete user + _users.DeleteUser(user.UserId); + _logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Deleted {UserId}", user.UserId); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Delete, "Error Deleting User {UserId}", user.UserId, result.ToString()); + } + } } } } diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 18dc820f..99e67e57 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -37,27 +37,30 @@ namespace Oqtane.Infrastructure _cache = cache; } - public bool IsInstalled() + public Installation IsInstalled() { - var defaultConnectionString = NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey)); - var result = !string.IsNullOrEmpty(defaultConnectionString); - if (result) + var result = new Installation { Success = false, Message = string.Empty }; + if (!string.IsNullOrEmpty(_config.GetConnectionString(SettingKeys.ConnectionStringKey))) { + result.Success = true; using (var scope = _serviceScopeFactory.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); - result = db.Database.CanConnect(); - if (result) + if (db.Database.CanConnect()) { try { - result = db.Tenant.Any(); + var provisioned = db.Tenant.Any(); } catch { - result = false; + result.Message = "Master Database Not Installed Correctly"; } } + else + { + result.Message = "Cannot Connect To Master Database"; + } } } return result; @@ -84,7 +87,8 @@ namespace Oqtane.Infrastructure IsNewTenant = false }; - if (!IsInstalled()) + var installation = IsInstalled(); + if (!installation.Success) { install.Aliases = GetInstallationConfig(SettingKeys.DefaultAliasKey, string.Empty); install.HostPassword = GetInstallationConfig(SettingKeys.HostPasswordKey, string.Empty); @@ -107,6 +111,14 @@ namespace Oqtane.Infrastructure install.ConnectionString = ""; } } + else + { + if (!string.IsNullOrEmpty(installation.Message)) + { + // problem with prior installation + install.ConnectionString = ""; + } + } } else { diff --git a/Oqtane.Server/Infrastructure/Interfaces/IDatabaseManager.cs b/Oqtane.Server/Infrastructure/Interfaces/IDatabaseManager.cs index ffb0ff9c..6257db16 100644 --- a/Oqtane.Server/Infrastructure/Interfaces/IDatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/Interfaces/IDatabaseManager.cs @@ -1,11 +1,11 @@ -using Oqtane.Models; +using Oqtane.Models; using Oqtane.Shared; namespace Oqtane.Infrastructure { public interface IDatabaseManager { - bool IsInstalled(); + Installation IsInstalled(); Installation Install(); Installation Install(InstallConfig install); } diff --git a/Oqtane.Server/Infrastructure/SiteTemplates/DefaultSiteTemplate.cs b/Oqtane.Server/Infrastructure/SiteTemplates/DefaultSiteTemplate.cs index e21629d8..2c7f6603 100644 --- a/Oqtane.Server/Infrastructure/SiteTemplates/DefaultSiteTemplate.cs +++ b/Oqtane.Server/Infrastructure/SiteTemplates/DefaultSiteTemplate.cs @@ -48,7 +48,7 @@ namespace Oqtane.SiteTemplates new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions() , PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Welcome To Oqtane...", Pane = "Content", + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Welcome To Oqtane...", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Everyone, true), new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -70,7 +70,7 @@ namespace Oqtane.SiteTemplates "

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

" + "

THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

" }, - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Secure Content", Pane = "Content", + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Secure Content", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Registered, true), new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -94,7 +94,7 @@ namespace Oqtane.SiteTemplates new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Secure Content", Pane = "Content", + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Secure Content", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Registered, true), new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -118,7 +118,7 @@ namespace Oqtane.SiteTemplates new Permission(PermissionNames.Edit, RoleNames.Admin, true) }.EncodePermissions(), PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "My Page", Pane = "Content", + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "My Page", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Everyone, true), new Permission(PermissionNames.View, RoleNames.Admin, true), diff --git a/Oqtane.Server/Infrastructure/SyncManager.cs b/Oqtane.Server/Infrastructure/SyncManager.cs index f41c01b0..d70cc456 100644 --- a/Oqtane.Server/Infrastructure/SyncManager.cs +++ b/Oqtane.Server/Infrastructure/SyncManager.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System; using System.Collections.Generic; using System.Linq; @@ -17,7 +17,7 @@ namespace Oqtane.Infrastructure public List GetSyncEvents(int tenantId, DateTime lastSyncDate) { - return SyncEvents.Where(item => item.TenantId == tenantId && item.ModifiedOn >= lastSyncDate).ToList(); + return SyncEvents.Where(item => (item.TenantId == tenantId || item.TenantId == -1) && item.ModifiedOn >= lastSyncDate).ToList(); } public void AddSyncEvent(int tenantId, string entityName, int entityId) diff --git a/Oqtane.Server/Infrastructure/UpgradeManager.cs b/Oqtane.Server/Infrastructure/UpgradeManager.cs index 0344de6e..fc435f10 100644 --- a/Oqtane.Server/Infrastructure/UpgradeManager.cs +++ b/Oqtane.Server/Infrastructure/UpgradeManager.cs @@ -1,9 +1,10 @@ -using Microsoft.Extensions.DependencyInjection; -using Oqtane.Extensions; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; using Oqtane.Models; using Oqtane.Repository; using Oqtane.Shared; using System.Collections.Generic; +using System.IO; using System.Linq; namespace Oqtane.Infrastructure @@ -12,80 +13,105 @@ namespace Oqtane.Infrastructure { private readonly IAliasRepository _aliases; private readonly IServiceScopeFactory _serviceScopeFactory; + private readonly IWebHostEnvironment _environment; - public UpgradeManager(IAliasRepository aliases, IServiceScopeFactory serviceScopeFactory) + public UpgradeManager(IAliasRepository aliases, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment) { _aliases = aliases; _serviceScopeFactory = serviceScopeFactory; + _environment = environment; } public void Upgrade(Tenant tenant, string version) { - // core framework upgrade logic - note that you can check if current tenant is Master if you only want to execute logic once - var pageTemplates = new List(); - - switch (version) + // core framework upgrade logic - executed for every tenant + using (var scope = _serviceScopeFactory.CreateScope()) { - case "0.9.0": - // add a page to all existing sites on upgrade + // set SiteState based on tenant + var siteState = scope.ServiceProvider.GetRequiredService(); + siteState.Alias = new Alias { TenantId = tenant.TenantId }; - //pageTemplates.Add(new PageTemplate - //{ - // Name = "Test", - // Parent = "", - // Path = "test", - // Icon = Icons.Badge, - // IsNavigation = true, - // IsPersonalizable = false, - // EditMode = 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 = "Test", Pane = "Content", - // 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 = "" - // } - // } - //}); - CreateSitePages(tenant, pageTemplates); - break; + switch (version) + { + case "1.0.0": + Upgrade_1_0_0(tenant, scope); + break; + case "2.0.2": + Upgrade_2_0_2(tenant, scope); + break; + } } } - private void CreateSitePages(Tenant tenant, List pageTemplates) + private void Upgrade_1_0_0(Tenant tenant, IServiceScope scope) + { + var pageTemplates = new List(); + + // **Note: this code is commented out on purpose - it provides an example of how to programmatically add a page to all existing sites on upgrade + + //pageTemplates.Add(new PageTemplate + //{ + // Name = "Test", + // Parent = "", + // Path = "test", + // Icon = Icons.Badge, + // IsNavigation = true, + // IsPersonalizable = false, + // EditMode = 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 = "Test", Pane = "Content", + // 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 = "" + // } + // } + //}); + + CreateSitePages(scope, pageTemplates); + } + + private void Upgrade_2_0_2(Tenant tenant, IServiceScope scope) + { + if (tenant.Name == TenantNames.Master) + { + // remove Internal module template files as they are no longer supported + var internalTemplatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", "Internal", Path.DirectorySeparatorChar.ToString()); + if (Directory.Exists(internalTemplatePath)) + { + Directory.Delete(internalTemplatePath, true); + } + } + + // initialize SiteGuid + var sites = scope.ServiceProvider.GetRequiredService(); + foreach (Site site in sites.GetSites().ToList()) + { + site.SiteGuid = System.Guid.NewGuid().ToString(); + sites.UpdateSite(site); + } + } + + private void CreateSitePages(IServiceScope scope, List pageTemplates) { if (pageTemplates.Count != 0) { - var processed = new List(); - foreach (Alias alias in _aliases.GetAliases().Where(item => item.TenantId == tenant.TenantId)) + var sites = scope.ServiceProvider.GetRequiredService(); + foreach (Site site in sites.GetSites().ToList()) { - if (!processed.Exists(item => item.SiteId == alias.SiteId)) - { - using (var scope = _serviceScopeFactory.CreateScope()) - { - var siteState = scope.ServiceProvider.GetRequiredService(); - siteState.Alias = alias; - var sites = scope.ServiceProvider.GetRequiredService(); - var site = sites.GetSite(alias.SiteId); - if (site != null) - { - sites.CreatePages(site, pageTemplates); - } - processed.Add(site); - } - } + sites.CreatePages(site, pageTemplates); } } } diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml index cf2d69f0..74b13c99 100644 --- a/Oqtane.Server/Pages/_Host.cshtml +++ b/Oqtane.Server/Pages/_Host.cshtml @@ -1,4 +1,4 @@ -@page "/" +@page "/" @namespace Oqtane.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @using Microsoft.Extensions.Configuration @@ -15,6 +15,7 @@ + @Html.Raw(@Model.HeadResources) @@ -35,6 +36,13 @@ 🗙
+ @if (Model.Message != "") + { +
+ @Model.Message +
+ } + @if (Configuration.GetSection("Runtime").Value == "WebAssembly") diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs index 4dc9cb7e..156b5fac 100644 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ b/Oqtane.Server/Pages/_Host.cshtml.cs @@ -39,6 +39,7 @@ namespace Oqtane.Pages public string HeadResources = ""; public string BodyResources = ""; + public string Message = ""; public void OnGet() { @@ -54,20 +55,28 @@ namespace Oqtane.Pages if (HttpContext.Request.Cookies[CookieRequestCultureProvider.DefaultCookieName] == null && !string.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection"))) { var uri = new Uri(Request.GetDisplayUrl()); - var alias = _aliases.GetAlias(uri.Authority + "/" + uri.LocalPath.Substring(1)); - _state.Alias = alias; - - // set default language for site if the culture is not supported - var languages = _languages.GetLanguages(alias.SiteId); - if (languages.Any() && languages.All(l => l.Code != CultureInfo.CurrentUICulture.Name)) + var hostname = uri.Authority + "/" + uri.LocalPath.Substring(1); + var alias = _aliases.GetAlias(hostname); + if (alias != null) { - var defaultLanguage = languages.Where(l => l.IsDefault).SingleOrDefault() ?? languages.First(); + _state.Alias = alias; - SetLocalizationCookie(defaultLanguage.Code); + // set default language for site if the culture is not supported + var languages = _languages.GetLanguages(alias.SiteId); + if (languages.Any() && languages.All(l => l.Code != CultureInfo.CurrentUICulture.Name)) + { + var defaultLanguage = languages.Where(l => l.IsDefault).SingleOrDefault() ?? languages.First(); + + SetLocalizationCookie(defaultLanguage.Code); + } + else + { + SetLocalizationCookie(_localizationManager.GetDefaultCulture()); + } } else { - SetLocalizationCookie(_localizationManager.GetDefaultCulture()); + Message = $"No Matching Alias For Host Name {hostname}"; } } } diff --git a/Oqtane.Server/Repository/Interfaces/IFolderRepository.cs b/Oqtane.Server/Repository/Interfaces/IFolderRepository.cs index 5ce7467f..dba914a7 100644 --- a/Oqtane.Server/Repository/Interfaces/IFolderRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IFolderRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Oqtane.Models; namespace Oqtane.Repository diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index ba23d218..af4f2b06 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -68,7 +68,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "User Login", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "User Login", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -97,7 +97,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Register.Index).ToModuleDefinitionName(), Title = "User Registration", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Register.Index).ToModuleDefinitionName(), Title = "User Registration", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -127,7 +127,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Reset.Index).ToModuleDefinitionName(), Title = "Password Reset", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Reset.Index).ToModuleDefinitionName(), Title = "Password Reset", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -156,7 +156,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UserProfile.Index).ToModuleDefinitionName(), Title = "User Profile", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UserProfile.Index).ToModuleDefinitionName(), Title = "User Profile", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -181,7 +181,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Dashboard.Index).ToModuleDefinitionName(), Title = "Admin Dashboard", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Dashboard.Index).ToModuleDefinitionName(), Title = "Admin Dashboard", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -208,7 +208,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Site.Index).ToModuleDefinitionName(), Title = "Site Settings", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Site.Index).ToModuleDefinitionName(), Title = "Site Settings", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -235,7 +235,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Pages.Index).ToModuleDefinitionName(), Title = "Page Management", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Pages.Index).ToModuleDefinitionName(), Title = "Page Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -262,7 +262,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Users.Index).ToModuleDefinitionName(), Title = "User Management", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Users.Index).ToModuleDefinitionName(), Title = "User Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -289,7 +289,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Profiles.Index).ToModuleDefinitionName(), Title = "Profile Management", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Profiles.Index).ToModuleDefinitionName(), Title = "Profile Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -316,7 +316,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Roles.Index).ToModuleDefinitionName(), Title = "Role Management", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Roles.Index).ToModuleDefinitionName(), Title = "Role Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -343,7 +343,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Files.Index).ToModuleDefinitionName(), Title = "File Management", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Files.Index).ToModuleDefinitionName(), Title = "File Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -370,7 +370,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.RecycleBin.Index).ToModuleDefinitionName(), Title = "Recycle Bin", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.RecycleBin.Index).ToModuleDefinitionName(), Title = "Recycle Bin", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Admin, true), @@ -399,7 +399,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Logs.Index).ToModuleDefinitionName(), Title = "Event Log", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Logs.Index).ToModuleDefinitionName(), Title = "Event Log", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -421,7 +421,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sites.Index).ToModuleDefinitionName(), Title = "Site Management", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sites.Index).ToModuleDefinitionName(), Title = "Site Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -443,7 +443,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.ModuleDefinitions.Index).ToModuleDefinitionName(), Title = "Module Management", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.ModuleDefinitions.Index).ToModuleDefinitionName(), Title = "Module Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -465,7 +465,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Themes.Index).ToModuleDefinitionName(), Title = "Theme Management", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Themes.Index).ToModuleDefinitionName(), Title = "Theme Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -494,7 +494,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Languages.Index).ToModuleDefinitionName(), Title = "Language Management", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Languages.Index).ToModuleDefinitionName(), Title = "Language Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -518,7 +518,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Jobs.Index).ToModuleDefinitionName(), Title = "Scheduled Jobs", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Jobs.Index).ToModuleDefinitionName(), Title = "Scheduled Jobs", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -540,7 +540,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sql.Index).ToModuleDefinitionName(), Title = "Sql Management", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sql.Index).ToModuleDefinitionName(), Title = "Sql Management", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -562,7 +562,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.SystemInfo.Index).ToModuleDefinitionName(), Title = "System Info", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.SystemInfo.Index).ToModuleDefinitionName(), Title = "System Info", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -584,7 +584,7 @@ namespace Oqtane.Repository { new PageTemplateModule { - ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Upgrade.Index).ToModuleDefinitionName(), Title = "System Update", Pane = "Content", + ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Upgrade.Index).ToModuleDefinitionName(), Title = "System Update", Pane = PaneNames.Admin, ModulePermissions = new List { new Permission(PermissionNames.View, RoleNames.Host, true), @@ -605,7 +605,7 @@ namespace Oqtane.Repository public Site AddSite(Site site) { - + site.SiteGuid = System.Guid.NewGuid().ToString(); _db.Site.Add(site); _db.SaveChanges(); CreateSite(site); diff --git a/Oqtane.Server/Repository/UserRoleRepository.cs b/Oqtane.Server/Repository/UserRoleRepository.cs index 79f8a629..b47bd6f7 100644 --- a/Oqtane.Server/Repository/UserRoleRepository.cs +++ b/Oqtane.Server/Repository/UserRoleRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; using Oqtane.Models; @@ -27,7 +27,7 @@ namespace Oqtane.Repository return _db.UserRole.Where(item => item.UserId == userId) .Include(item => item.Role) // eager load roles .Include(item => item.User) // eager load users - .Where(item => item.Role.SiteId == siteId || item.Role.SiteId == null); + .Where(item => item.Role.SiteId == siteId || item.Role.SiteId == null || siteId == -1); } public UserRole AddUserRole(UserRole userRole) diff --git a/Oqtane.Server/Scripts/Tenant.02.00.02.01.sql b/Oqtane.Server/Scripts/Tenant.02.00.02.01.sql new file mode 100644 index 00000000..03e5c566 --- /dev/null +++ b/Oqtane.Server/Scripts/Tenant.02.00.02.01.sql @@ -0,0 +1,10 @@ +/* + +Version 2.0.2 Tenant migration script + +*/ + +ALTER TABLE [dbo].[Site] ADD + [SiteGuid] [char](36) NULL +GO + diff --git a/Oqtane.Server/Scripts/Tenant.02.00.02.02.sql b/Oqtane.Server/Scripts/Tenant.02.00.02.02.sql new file mode 100644 index 00000000..64a08e76 --- /dev/null +++ b/Oqtane.Server/Scripts/Tenant.02.00.02.02.sql @@ -0,0 +1,20 @@ +/* + +Version 2.0.2 Tenant migration script + +*/ + +UPDATE [dbo].[Site] SET DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client' WHERE DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'; +GO +UPDATE [dbo].[Site] SET DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client' WHERE DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'; +GO + +UPDATE [dbo].[Page] SET DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client' WHERE DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'; +GO +UPDATE [dbo].[Page] SET DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client' WHERE DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'; +GO + +UPDATE [dbo].[PageModule] SET ContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client' WHERE ContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'; +GO +UPDATE [dbo].[PageModule] SET ContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client' WHERE ContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'; +GO diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 60ae50b8..f337238e 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -227,7 +227,7 @@ namespace Oqtane } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncManager sync) { ServiceActivator.Configure(app.ApplicationServices); @@ -265,6 +265,9 @@ namespace Oqtane endpoints.MapControllers(); endpoints.MapFallbackToPage("/_Host"); }); + + // create a sync event to identify server application startup + sync.AddSyncEvent(-1, "Application", -1); } } } diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Edit.razor b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Edit.razor similarity index 72% rename from Oqtane.Server/wwwroot/Modules/Templates/External/Client/Edit.razor rename to Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Edit.razor index 339879f8..9858a044 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Edit.razor +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Edit.razor @@ -74,22 +74,29 @@ { try { - if (PageState.Action == "Add") + if (string.IsNullOrEmpty(_name)) { - [Module] [Module] = new [Module](); - [Module].ModuleId = ModuleState.ModuleId; - [Module].Name = _name; - [Module] = await [Module]Service.Add[Module]Async([Module]); - await logger.LogInformation("[Module] Added {[Module]}", [Module]); + if (PageState.Action == "Add") + { + [Module] [Module] = new [Module](); + [Module].ModuleId = ModuleState.ModuleId; + [Module].Name = _name; + [Module] = await [Module]Service.Add[Module]Async([Module]); + await logger.LogInformation("[Module] Added {[Module]}", [Module]); + } + else + { + [Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId); + [Module].Name = _name; + await [Module]Service.Update[Module]Async([Module]); + await logger.LogInformation("[Module] Updated {[Module]}", [Module]); + } + NavigationManager.NavigateTo(NavigateUrl()); } else { - [Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId); - [Module].Name = _name; - await [Module]Service.Update[Module]Async([Module]); - await logger.LogInformation("[Module] Updated {[Module]}", [Module]); + AddModuleMessage("The Name Is Required", MessageType.Warning); } - NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Index.razor b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Index.razor similarity index 100% rename from Oqtane.Server/wwwroot/Modules/Templates/External/Client/Index.razor rename to Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Index.razor diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/ModuleInfo.cs b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/ModuleInfo.cs similarity index 100% rename from Oqtane.Server/wwwroot/Modules/Templates/External/Client/ModuleInfo.cs rename to Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/ModuleInfo.cs diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Settings.razor b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Settings.razor similarity index 100% rename from Oqtane.Server/wwwroot/Modules/Templates/External/Client/Settings.razor rename to Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].[Module]/Settings.razor diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Edit.razor b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Edit.razor deleted file mode 100644 index 339879f8..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Edit.razor +++ /dev/null @@ -1,100 +0,0 @@ -@using Oqtane.Modules.Controls -@using [Owner].[Module].Services -@using [Owner].[Module].Models - -@namespace [Owner].[Module] -@inherits ModuleBase -@inject I[Module]Service [Module]Service -@inject NavigationManager NavigationManager - - - - - - -
- - - -
- -Cancel -
-
-@if (PageState.Action == "Edit") -{ - -} - -@code { - public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit; - - public override string Actions => "Add,Edit"; - - public override string Title => "Manage [Module]"; - - public override List Resources => new List() - { - new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" } - }; - - int _id; - string _name; - string _createdby; - DateTime _createdon; - string _modifiedby; - DateTime _modifiedon; - - protected override async Task OnInitializedAsync() - { - try - { - if (PageState.Action == "Edit") - { - _id = Int32.Parse(PageState.QueryString["id"]); - [Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId); - if ([Module] != null) - { - _name = [Module].Name; - _createdby = [Module].CreatedBy; - _createdon = [Module].CreatedOn; - _modifiedby = [Module].ModifiedBy; - _modifiedon = [Module].ModifiedOn; - } - } - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading [Module] {[Module]Id} {Error}", _id, ex.Message); - AddModuleMessage("Error Loading [Module]", MessageType.Error); - } - } - - private async Task Save() - { - try - { - if (PageState.Action == "Add") - { - [Module] [Module] = new [Module](); - [Module].ModuleId = ModuleState.ModuleId; - [Module].Name = _name; - [Module] = await [Module]Service.Add[Module]Async([Module]); - await logger.LogInformation("[Module] Added {[Module]}", [Module]); - } - else - { - [Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId); - [Module].Name = _name; - await [Module]Service.Update[Module]Async([Module]); - await logger.LogInformation("[Module] Updated {[Module]}", [Module]); - } - NavigationManager.NavigateTo(NavigateUrl()); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Saving [Module] {Error}", ex.Message); - AddModuleMessage("Error Saving [Module]", MessageType.Error); - } - } -} diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Index.razor b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Index.razor deleted file mode 100644 index 37cfef2a..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Index.razor +++ /dev/null @@ -1,100 +0,0 @@ -@using [Owner].[Module].Services -@using [Owner].[Module].Models - -@namespace [Owner].[Module] -@inherits ModuleBase -@inject I[Module]Service [Module]Service -@inject NavigationManager NavigationManager - -@if (_[Module]s == null) -{ -

Loading...

-} -else -{ - -
-
- @if (@_[Module]s.Count != 0) - { - -
-   -   - Name -
- - - - @context.Name - -
- } - else - { -

No [Module]s To Display

- } -} - - - -
-[Module] Module Created Successfully. Use Edit Mode To Add A [Module]. You Can Access The Files At The Following Locations:

-[RootPath]Oqtane.Client\Modules\[Module]\
-- Edit.razor - component for adding or editing content
-- Index.razor - main component for your module **the content you are reading is in this file**
-- ModuleInfo.cs - implements IModule interface to provide configuration settings for your module
-- Settings.razor - component for managing module settings
-- Services\I[Module]Service.cs - interface for defining service API methods
-- Services\[Module]Service.cs - implements service API interface methods

-[RootPath]Oqtane.Server\Modules\[Module]\
-- Controllers\[Module]Controller.cs - API methods implemented using a REST pattern
-- Manager\[Module]Manager.cs - implements optional module interfaces for features such as import/export of content
-- Repository\I[Module]Repository.cs - interface for defining repository methods
-- Repository\[Module]Respository.cs - implements repository interface methods for data access using EF Core
-- Repository\[Module]Context.cs - provides a DB Context for data access
-- Scripts\[Owner].[Module]s.1.0.0.sql - database schema definition script
-- Scripts\[Owner].[Module]s.Uninstall.sql - database uninstall script

-[RootPath]Oqtane.Shared\Modules\[Module]\
-- Models\[Module].cs - model definition

- - - -@code { - public override List Resources => new List() - { - new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }, - new Resource { ResourceType = ResourceType.Script, Url = ModulePath() + "Module.js" } - }; - - List<[Module]> _[Module]s; - - protected override async Task OnInitializedAsync() - { - try - { - _[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading [Module] {Error}", ex.Message); - AddModuleMessage("Error Loading [Module]", MessageType.Error); - } - } - - private async Task Delete([Module] [Module]) - { - try - { - await [Module]Service.Delete[Module]Async([Module].[Module]Id, ModuleState.ModuleId); - await logger.LogInformation("[Module] Deleted {[Module]}", [Module]); - _[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId); - StateHasChanged(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Deleting [Module] {[Module]} {Error}", [Module], ex.Message); - AddModuleMessage("Error Deleting [Module]", MessageType.Error); - } - } -} \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Interop.cs b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Interop.cs deleted file mode 100644 index 9d6f0a4e..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Interop.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.JSInterop; -using System.Threading.Tasks; - -namespace [Owner].[Module] -{ - public class Interop - { - private readonly IJSRuntime _jsRuntime; - - public Interop(IJSRuntime jsRuntime) - { - _jsRuntime = jsRuntime; - } - } -} diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/ModuleInfo.cs b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/ModuleInfo.cs deleted file mode 100644 index 6586d51d..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/ModuleInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Oqtane.Models; -using Oqtane.Modules; - -namespace [Owner].[Module] -{ - public class ModuleInfo : IModule - { - public ModuleDefinition ModuleDefinition => new ModuleDefinition - { - Name = "[Module]", - Description = "[Module]", - Version = "1.0.0", - ServerManagerType = "[ServerManagerType]", - ReleaseVersions = "1.0.0" - }; - } -} diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Services/I[Module]Service.cs b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Services/I[Module]Service.cs deleted file mode 100644 index 601eba6a..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Services/I[Module]Service.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using [Owner].[Module].Models; - -namespace [Owner].[Module].Services -{ - public interface I[Module]Service - { - Task> Get[Module]sAsync(int ModuleId); - - Task Get[Module]Async(int [Module]Id, int ModuleId); - - Task Add[Module]Async(Models.[Module] [Module]); - - Task Update[Module]Async(Models.[Module] [Module]); - - Task Delete[Module]Async(int [Module]Id, int ModuleId); - } -} diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Services/[Module]Service.cs b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Services/[Module]Service.cs deleted file mode 100644 index 05a85ac7..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Services/[Module]Service.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; -using Oqtane.Modules; -using Oqtane.Services; -using Oqtane.Shared; -using [Owner].[Module].Models; - -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 = siteState; - } - - private string Apiurl => CreateApiUrl(_siteState.Alias, "[Module]"); - - public async Task> Get[Module]sAsync(int ModuleId) - { - List [Module]s = await GetJsonAsync>(CreateAuthorizationPolicyUrl($"{Apiurl}?moduleid={ModuleId}", ModuleId)); - return [Module]s.OrderBy(item => item.Name).ToList(); - } - - public async Task Get[Module]Async(int [Module]Id, int ModuleId) - { - return await GetJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{[Module]Id}", ModuleId)); - } - - public async Task Add[Module]Async(Models.[Module] [Module]) - { - return await PostJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}", [Module].ModuleId), [Module]); - } - - public async Task Update[Module]Async(Models.[Module] [Module]) - { - return await PutJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{[Module].[Module]Id}", [Module].ModuleId), [Module]); - } - - public async Task Delete[Module]Async(int [Module]Id, int ModuleId) - { - await DeleteAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{[Module]Id}", ModuleId)); - } - } -} diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Settings.razor b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Settings.razor deleted file mode 100644 index 7989d7c9..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Client/Modules/[Owner].[Module]/Settings.razor +++ /dev/null @@ -1,47 +0,0 @@ -@namespace [Owner].[Module] -@inherits ModuleBase -@inject ISettingService SettingService - - - - - - -
- - - -
- -@code { - public override string Title => "[Module] Settings"; - - string _value; - - protected override async Task OnInitializedAsync() - { - try - { - Dictionary settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId); - _value = SettingService.GetSetting(settings, "SettingName", ""); - } - catch (Exception ex) - { - ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error); - } - } - - public async Task UpdateSettings() - { - try - { - Dictionary settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId); - SettingService.SetSetting(settings, "SettingName", _value); - await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId); - } - catch (Exception ex) - { - ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error); - } - } -} diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Controllers/[Module]Controller.cs b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Controllers/[Module]Controller.cs deleted file mode 100644 index 3e2fe7b8..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Controllers/[Module]Controller.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Authorization; -using System.Collections.Generic; -using Microsoft.AspNetCore.Http; -using Oqtane.Shared; -using Oqtane.Enums; -using Oqtane.Infrastructure; -using [Owner].[Module].Models; -using [Owner].[Module].Repository; - -namespace [Owner].[Module].Controllers -{ - [Route(ControllerRoutes.Default)] - public class [Module]Controller : Controller - { - private readonly I[Module]Repository _[Module]Repository; - private readonly ILogManager _logger; - protected int _entityId = -1; - - public [Module]Controller(I[Module]Repository [Module]Repository, ILogManager logger, IHttpContextAccessor accessor) - { - _[Module]Repository = [Module]Repository; - _logger = logger; - - if (accessor.HttpContext.Request.Query.ContainsKey("entityid")) - { - _entityId = int.Parse(accessor.HttpContext.Request.Query["entityid"]); - } - } - - // GET: api/?moduleid=x - [HttpGet] - [Authorize(Policy = PolicyNames.ViewModule)] - public IEnumerable Get(string moduleid) - { - return _[Module]Repository.Get[Module]s(int.Parse(moduleid)); - } - - // GET api//5 - [HttpGet("{id}")] - [Authorize(Policy = PolicyNames.ViewModule)] - public Models.[Module] Get(int id) - { - Models.[Module] [Module] = _[Module]Repository.Get[Module](id); - if ([Module] != null && [Module].ModuleId != _entityId) - { - [Module] = null; - } - return [Module]; - } - - // POST api/ - [HttpPost] - [Authorize(Policy = PolicyNames.EditModule)] - public Models.[Module] Post([FromBody] Models.[Module] [Module]) - { - if (ModelState.IsValid && [Module].ModuleId == _entityId) - { - [Module] = _[Module]Repository.Add[Module]([Module]); - _logger.Log(LogLevel.Information, this, LogFunction.Create, "[Module] Added {[Module]}", [Module]); - } - return [Module]; - } - - // PUT api//5 - [HttpPut("{id}")] - [Authorize(Policy = PolicyNames.EditModule)] - public Models.[Module] Put(int id, [FromBody] Models.[Module] [Module]) - { - if (ModelState.IsValid && [Module].ModuleId == _entityId) - { - [Module] = _[Module]Repository.Update[Module]([Module]); - _logger.Log(LogLevel.Information, this, LogFunction.Update, "[Module] Updated {[Module]}", [Module]); - } - return [Module]; - } - - // DELETE api//5 - [HttpDelete("{id}")] - [Authorize(Policy = PolicyNames.EditModule)] - public void Delete(int id) - { - Models.[Module] [Module] = _[Module]Repository.Get[Module](id); - if ([Module] != null && [Module].ModuleId == _entityId) - { - _[Module]Repository.Delete[Module](id); - _logger.Log(LogLevel.Information, this, LogFunction.Delete, "[Module] Deleted {[Module]Id}", id); - } - } - } -} diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Manager/[Module]Manager.cs b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Manager/[Module]Manager.cs deleted file mode 100644 index 486c8ddf..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Manager/[Module]Manager.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text.Json; -using Oqtane.Modules; -using Oqtane.Models; -using Oqtane.Infrastructure; -using Oqtane.Repository; -using [Owner].[Module].Models; -using [Owner].[Module].Repository; - -namespace [Owner].[Module].Manager -{ - public class [Module]Manager : IInstallable, IPortable - { - private I[Module]Repository _[Module]Repository; - private ISqlRepository _sql; - - public [Module]Manager(I[Module]Repository [Module]Repository, ISqlRepository sql) - { - _[Module]Repository = [Module]Repository; - _sql = sql; - } - - public bool Install(Tenant tenant, string version) - { - return _sql.ExecuteScript(tenant, GetType().Assembly, "[Owner].[Module]." + version + ".sql"); - } - - public bool Uninstall(Tenant tenant) - { - return _sql.ExecuteScript(tenant, GetType().Assembly, "[Owner].[Module].Uninstall.sql"); - } - - public string ExportModule(Module module) - { - string content = ""; - List [Module]s = _[Module]Repository.Get[Module]s(module.ModuleId).ToList(); - if ([Module]s != null) - { - content = JsonSerializer.Serialize([Module]s); - } - return content; - } - - public void ImportModule(Module module, string content, string version) - { - List [Module]s = null; - if (!string.IsNullOrEmpty(content)) - { - [Module]s = JsonSerializer.Deserialize>(content); - } - if ([Module]s != null) - { - foreach(var [Module] in [Module]s) - { - _[Module]Repository.Add[Module](new Models.[Module] { ModuleId = module.ModuleId, Name = [Module].Name }); - } - } - } - } -} \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Repository/I[Module]Repository.cs b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Repository/I[Module]Repository.cs deleted file mode 100644 index 52b7913a..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Repository/I[Module]Repository.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; -using [Owner].[Module].Models; - -namespace [Owner].[Module].Repository -{ - public interface I[Module]Repository - { - IEnumerable Get[Module]s(int ModuleId); - Models.[Module] Get[Module](int [Module]Id); - 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/Internal/Oqtane.Server/Modules/[Owner].[Module]/Repository/[Module]Context.cs b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Repository/[Module]Context.cs deleted file mode 100644 index a10d7219..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Repository/[Module]Context.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.AspNetCore.Http; -using Oqtane.Modules; -using Oqtane.Repository; -using [Owner].[Module].Models; - -namespace [Owner].[Module].Repository -{ - public class [Module]Context : DBContextBase, IService - { - public virtual DbSet [Module] { get; set; } - - public [Module]Context(ITenantResolver tenantResolver, IHttpContextAccessor accessor) : base(tenantResolver, accessor) - { - // ContextBase handles multi-tenant database connections - } - } -} diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Repository/[Module]Repository.cs b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Repository/[Module]Repository.cs deleted file mode 100644 index 9c8c3628..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Repository/[Module]Repository.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using System.Linq; -using System.Collections.Generic; -using Oqtane.Modules; -using [Owner].[Module].Models; - -namespace [Owner].[Module].Repository -{ - public class [Module]Repository : I[Module]Repository, IService - { - private readonly [Module]Context _db; - - public [Module]Repository([Module]Context context) - { - _db = context; - } - - public IEnumerable Get[Module]s(int ModuleId) - { - return _db.[Module].Where(item => item.ModuleId == ModuleId); - } - - public Models.[Module] Get[Module](int [Module]Id) - { - return _db.[Module].Find([Module]Id); - } - - public Models.[Module] Add[Module](Models.[Module] [Module]) - { - _db.[Module].Add([Module]); - _db.SaveChanges(); - return [Module]; - } - - public Models.[Module] Update[Module](Models.[Module] [Module]) - { - _db.Entry([Module]).State = EntityState.Modified; - _db.SaveChanges(); - return [Module]; - } - - public void Delete[Module](int [Module]Id) - { - Models.[Module] [Module] = _db.[Module].Find([Module]Id); - _db.[Module].Remove([Module]); - _db.SaveChanges(); - } - } -} diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Scripts/[Owner].[Module].1.0.0.sql b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Scripts/[Owner].[Module].1.0.0.sql deleted file mode 100644 index 7a1b99ea..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Scripts/[Owner].[Module].1.0.0.sql +++ /dev/null @@ -1,26 +0,0 @@ -/* -Create [Owner][Module] table -*/ - -CREATE TABLE [dbo].[[Owner][Module]]( - [[Module]Id] [int] IDENTITY(1,1) NOT NULL, - [ModuleId] [int] NOT NULL, - [Name] [nvarchar](256) NOT NULL, - [CreatedBy] [nvarchar](256) NOT NULL, - [CreatedOn] [datetime] NOT NULL, - [ModifiedBy] [nvarchar](256) NOT NULL, - [ModifiedOn] [datetime] NOT NULL, - CONSTRAINT [PK_[Owner][Module]] PRIMARY KEY CLUSTERED - ( - [[Module]Id] ASC - ) -) -GO - -/* -Create foreign key relationships -*/ -ALTER TABLE [dbo].[[Owner][Module]] WITH CHECK ADD CONSTRAINT [FK_[Owner][Module]_Module] FOREIGN KEY([ModuleId]) -REFERENCES [dbo].Module ([ModuleId]) -ON DELETE CASCADE -GO \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Scripts/[Owner].[Module].Uninstall.sql b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Scripts/[Owner].[Module].Uninstall.sql deleted file mode 100644 index 47baecc9..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/Modules/[Owner].[Module]/Scripts/[Owner].[Module].Uninstall.sql +++ /dev/null @@ -1,6 +0,0 @@ -/* -Remove [Owner][Module] table -*/ - -DROP TABLE [dbo].[[Owner][Module]] -GO diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/wwwroot/Modules/[Owner].[Module]/Module.css b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/wwwroot/Modules/[Owner].[Module]/Module.css deleted file mode 100644 index 0856a263..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/wwwroot/Modules/[Owner].[Module]/Module.css +++ /dev/null @@ -1 +0,0 @@ -/* Module Custom Styles */ \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/wwwroot/Modules/[Owner].[Module]/Module.js b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/wwwroot/Modules/[Owner].[Module]/Module.js deleted file mode 100644 index 8f072470..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Server/wwwroot/Modules/[Owner].[Module]/Module.js +++ /dev/null @@ -1,5 +0,0 @@ -/* Module Script */ -var [Owner] = [Owner] || {}; - -[Owner].[Module] = { -}; \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Shared/Modules/[Owner].[Module]/Models/[Module].cs b/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Shared/Modules/[Owner].[Module]/Models/[Module].cs deleted file mode 100644 index 94f73ffa..00000000 --- a/Oqtane.Server/wwwroot/Modules/Templates/Internal/Oqtane.Shared/Modules/[Owner].[Module]/Models/[Module].cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations.Schema; -using Oqtane.Models; - -namespace [Owner].[Module].Models -{ - [Table("[Owner][Module]")] - public class [Module] : IAuditable - { - public int [Module]Id { get; set; } - public int ModuleId { get; set; } - public string Name { get; set; } - - public string CreatedBy { get; set; } - public DateTime CreatedOn { get; set; } - public string ModifiedBy { get; set; } - public DateTime ModifiedOn { get; set; } - } -} diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/AssemblyInfo.cs b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/AssemblyInfo.cs new file mode 100644 index 00000000..91d5ec4b --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Resources; +using Microsoft.Extensions.Localization; + +[assembly: RootNamespace("[Owner].[Theme].Client")] \ No newline at end of file diff --git a/Oqtane.Client/Themes/OqtaneTheme/Container.razor b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/Containers/Container1.razor similarity index 79% rename from Oqtane.Client/Themes/OqtaneTheme/Container.razor rename to Oqtane.Server/wwwroot/Themes/Templates/External/Client/Containers/Container1.razor index 6d0148fa..2778aa22 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/Container.razor +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/Containers/Container1.razor @@ -1,5 +1,6 @@ -@namespace Oqtane.Themes.OqtaneTheme +@namespace [Owner].[Theme] @inherits ContainerBase +
@@ -15,5 +16,5 @@
@code { - public override string Name => "Standard Header"; + public override string Name => "Container1"; } \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs new file mode 100644 index 00000000..3f543b38 --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs @@ -0,0 +1,15 @@ +using Oqtane.Models; +using Oqtane.Themes; + +namespace [Owner].[Theme] +{ + public class ThemeInfo : ITheme + { + public Theme Theme => new Theme + { + Name = "[Theme]", + Version = "1.0.0" + }; + + } +} diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/Themes/Theme1.razor b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/Themes/Theme1.razor new file mode 100644 index 00000000..7ffefe5f --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/Themes/Theme1.razor @@ -0,0 +1,107 @@ +@namespace [Owner].[Theme] +@inherits ThemeBase + +
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+
+ +
+ +@code { + public override string Name => "Theme1"; + + public override string Panes => "Content,Top Full Width,Top 100%,Left 50%,Right 50%,Left 33%,Center 33%,Right 33%,Left Outer 25%,Left Inner 25%,Right Inner 25%,Right Outer 25%,Left 25%,Center 50%,Right 25%,Left Sidebar 66%,Right Sidebar 33%,Left Sidebar 33%,Right Sidebar 66%,Bottom 100%,Bottom Full Width"; + + public override List Resources => new List() + { + new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css", Integrity = "sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk", CrossOrigin = "anonymous" }, + new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://code.jquery.com/jquery-3.5.1.slim.min.js", Integrity = "sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj", CrossOrigin = "anonymous" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js", Integrity = "sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo", CrossOrigin = "anonymous" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js", Integrity = "sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI", CrossOrigin = "anonymous" } + }; +} diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/[Owner].[Theme].Client.csproj b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/[Owner].[Theme].Client.csproj new file mode 100644 index 00000000..746694b4 --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/[Owner].[Theme].Client.csproj @@ -0,0 +1,34 @@ + + + + net5.0 + 3.0 + 1.0.0 + [Owner] + [Owner] + [Description] + [Owner].[Theme] + [Owner] + [Owner].[Theme].Client.Oqtane + + + + + + + + + + + + [ClientReference] + [SharedReference] + + + + + false + false + + + diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/_Imports.razor b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/_Imports.razor new file mode 100644 index 00000000..d206b36e --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/_Imports.razor @@ -0,0 +1,21 @@ +@using System +@using System.Linq +@using System.Collections.Generic +@using System.Net.Http +@using System.Net.Http.Json + +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.JSInterop + +@using Oqtane.Models +@using Oqtane.Modules +@using Oqtane.Modules.Controls +@using Oqtane.Providers +@using Oqtane.Security +@using Oqtane.Services +@using Oqtane.Shared +@using Oqtane.Themes +@using Oqtane.Themes.Controls +@using Oqtane.UI +@using Oqtane.Enums \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].[Theme]/Theme.css b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].[Theme]/Theme.css new file mode 100644 index 00000000..b8056c79 --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].[Theme]/Theme.css @@ -0,0 +1,83 @@ +/* Oqtane Styles */ + +body { + padding-top: 7rem; +} + +.controls { + z-index: 2000; + padding-top: 15px; + padding-bottom: 15px; + margin-right: 10px; +} + +.app-menu .nav-item { + font-size: 0.9rem; + padding-bottom: 0.5rem; +} + +.app-menu .nav-item a { + border-radius: 4px; + height: 3rem; + display: flex; + align-items: center; + line-height: 3rem; +} + +.app-menu .nav-item a.active { + background-color: rgba(255,255,255,0.25); + color: white; +} + +.app-menu .nav-item a:hover { + background-color: rgba(255,255,255,0.1); + color: white; +} + +.app-menu .nav-link .oi { + width: 1.5rem; + font-size: 1.1rem; + vertical-align: text-top; + top: -2px; +} + +.navbar-toggler { + background-color: rgba(255, 255, 255, 0.1); + margin-left: auto; +} + +div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu { + color:#ffffff; +} + +@media (max-width: 767px) { + + .app-menu { + width: 100% + } + + .navbar { + position: fixed; + top: 60px; + width: 100%; + } + + .controls { + height: 60px; + top: 15px; + position: fixed; + top: 0px; + width: 100%; + background-color: rgb(0, 0, 0); + } + + .controls-group { + float: right; + margin-right: 25px; + } + + .content { + position: relative; + top: 60px; + } +} diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Package/[Owner].[Theme].Package.csproj b/Oqtane.Server/wwwroot/Themes/Templates/External/Package/[Owner].[Theme].Package.csproj new file mode 100644 index 00000000..30043010 --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Package/[Owner].[Theme].Package.csproj @@ -0,0 +1,17 @@ + + + + net5.0 + false + + + + + + + + + + + + diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Package/[Owner].[Theme].nuspec b/Oqtane.Server/wwwroot/Themes/Templates/External/Package/[Owner].[Theme].nuspec new file mode 100644 index 00000000..e73d4618 --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Package/[Owner].[Theme].nuspec @@ -0,0 +1,27 @@ + + + + [Owner].[Theme] + 1.0.0 + [Owner] + [Owner] + [Theme] + [Theme] + [Owner] + false + MIT + https://github.com/oqtane/oqtane.framework + https://www.oqtane.org/Portals/0/icon.jpg + oqtane module + + + + + + + + + + + + \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Package/debug.cmd b/Oqtane.Server/wwwroot/Themes/Templates/External/Package/debug.cmd new file mode 100644 index 00000000..7eea5a36 --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Package/debug.cmd @@ -0,0 +1,3 @@ +XCOPY "..\Client\bin\Debug\net5.0\[Owner].[Theme].Client.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net5.0\" /Y +XCOPY "..\Client\bin\Debug\net5.0\[Owner].[Theme].Client.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net5.0\" /Y +XCOPY "..\Client\wwwroot\*" "..\..\[RootFolder]\Oqtane.Client\wwwroot\" /Y /S /I diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/Package/release.cmd b/Oqtane.Server/wwwroot/Themes/Templates/External/Package/release.cmd new file mode 100644 index 00000000..3d4edfe1 --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/Package/release.cmd @@ -0,0 +1,2 @@ +"..\..\[RootFolder]\oqtane.package\nuget.exe" pack [Owner].[Theme].nuspec +XCOPY "*.nupkg" "..\..\[RootFolder]\Oqtane.Server\wwwroot\Themes\" /Y diff --git a/Oqtane.Server/wwwroot/Themes/Templates/External/[Owner].[Theme].sln b/Oqtane.Server/wwwroot/Themes/Templates/External/[Owner].[Theme].sln new file mode 100644 index 00000000..7c1739bd --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Templates/External/[Owner].[Theme].sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28621.142 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "[Owner].[Theme].Client", "Client\[Owner].[Theme].Client.csproj", "{AA8E58A1-CD09-4208-BF66-A8BB341FD669}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "[Owner].[Theme].Package", "Package\[Owner].[Theme].Package.csproj", "{C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + Wasm|Any CPU = Wasm|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Release|Any CPU.Build.0 = Release|Any CPU + {AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Wasm|Any CPU.ActiveCfg = Release|Any CPU + {AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Wasm|Any CPU.Build.0 = Release|Any CPU + {C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Release|Any CPU.Build.0 = Release|Any CPU + {C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Wasm|Any CPU.ActiveCfg = Debug|Any CPU + {C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Wasm|Any CPU.Build.0 = Debug|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1D016F15-46FE-4726-8DFD-2E4FD4DC7668} + EndGlobalSection +EndGlobal diff --git a/Oqtane.Server/wwwroot/css/app.css b/Oqtane.Server/wwwroot/css/app.css index ce87887d..35a44e3f 100644 --- a/Oqtane.Server/wwwroot/css/app.css +++ b/Oqtane.Server/wwwroot/css/app.css @@ -1,4 +1,4 @@ -@import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); +@import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); html, body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; @@ -90,6 +90,17 @@ app { color: gray; } +.app-moduleactions .dropdown-submenu { + position: relative; +} + + .app-moduleactions .dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: 0px; + margin-left: 0px; + } + .app-progress-indicator { background: rgba(0,0,0,0.2) url('../loading.gif') no-repeat 50% 50%; width: 100%; @@ -125,6 +136,13 @@ app { vertical-align: inherit; } +.app-alert { + padding: 20px; + background-color: #f44336; /* red */ + color: white; + margin-bottom: 15px; +} + /* Tooltips */ .app-tooltip { cursor: help; @@ -207,4 +225,4 @@ app { position: absolute; right: 0.75rem; top: 0.5rem; -} \ No newline at end of file +} diff --git a/Oqtane.Server/wwwroot/js/app.js b/Oqtane.Server/wwwroot/js/app.js new file mode 100644 index 00000000..2c5d837e --- /dev/null +++ b/Oqtane.Server/wwwroot/js/app.js @@ -0,0 +1,8 @@ +function subMenu(a) { + event.preventDefault(); + event.stopPropagation(); + + var li = a.parentElement, submenu = li.getElementsByTagName('ul')[0]; + submenu.style.display = submenu.style.display == "block" ? "none" : "block"; + return false; +} \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js index 2e4092e4..6d1b549d 100644 --- a/Oqtane.Server/wwwroot/js/interop.js +++ b/Oqtane.Server/wwwroot/js/interop.js @@ -362,5 +362,8 @@ Oqtane.Interop = { setInterval(function () { window.location.href = url; }, wait * 1000); + }, + formValid: function (formRef) { + return formRef.checkValidity(); } }; diff --git a/Oqtane.Shared/Models/Site.cs b/Oqtane.Shared/Models/Site.cs index 49f3524e..5adf1318 100644 --- a/Oqtane.Shared/Models/Site.cs +++ b/Oqtane.Shared/Models/Site.cs @@ -18,6 +18,7 @@ namespace Oqtane.Models public int? PwaAppIconFileId { get; set; } public int? PwaSplashIconFileId { get; set; } public bool AllowRegistration { get; set; } + public string SiteGuid { get; set; } public string CreatedBy { get; set; } public DateTime CreatedOn { get; set; } diff --git a/Oqtane.Shared/Models/Theme.cs b/Oqtane.Shared/Models/Theme.cs index ee420dd9..398cc537 100644 --- a/Oqtane.Shared/Models/Theme.cs +++ b/Oqtane.Shared/Models/Theme.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; namespace Oqtane.Models @@ -14,6 +14,7 @@ namespace Oqtane.Models Contact = ""; License = ""; Dependencies = ""; + Template = ""; } public string ThemeName { get; set; } @@ -28,6 +29,7 @@ namespace Oqtane.Models public List Themes { get; set; } public List Layouts { get; set; } public List Containers { get; set; } + public string Template { get; set; } //[Obsolete("This property is obsolete. Use Themes instead.", false)] public string ThemeControls { get; set; } diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index 60106dd2..89d0e9a7 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -13,7 +13,7 @@ namespace Oqtane.Shared { public const string DefaultTheme = "Oqtane.Themes.OqtaneTheme.Default, Oqtane.Client"; public const string DefaultLayout = "Oqtane.Themes.OqtaneTheme.SinglePane, Oqtane.Client"; - public const string DefaultContainer = "Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client"; + public const string DefaultContainer = "Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client"; public const string DefaultAdminContainer = "Oqtane.Themes.AdminContainer, Oqtane.Client"; public const string ActionToken = "{Action}"; diff --git a/Oqtane.Shared/Shared/PaneNames.cs b/Oqtane.Shared/Shared/PaneNames.cs index 063924f9..7806f821 100644 --- a/Oqtane.Shared/Shared/PaneNames.cs +++ b/Oqtane.Shared/Shared/PaneNames.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace Oqtane.Shared { public class PaneNames { - public const string Admin = "Admin"; + public const string Admin = "Content"; } }