From b1e9b02cb364e1172ea62b2822b8e48ea19d3308 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 2 Oct 2019 14:51:00 -0400 Subject: [PATCH 1/9] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 5c44003e..02047ce2 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ Design - Need to cleanly separate site.css Admin -- Need fully functional administrative modules for all core entities ( user, role, site, etc… ) - Need ability to soft delete core entities - Drag and Drop modules From 6be2641ce75eb525ff0cb76e60b1fd17145321d4 Mon Sep 17 00:00:00 2001 From: Jon Matcho Date: Fri, 4 Oct 2019 20:50:52 -0400 Subject: [PATCH 2/9] Minor formatting change. Changed occurrences of ( this format ) to (this format). --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 02047ce2..1dc1e8d4 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Oqtane uses Blazor, a new web framework for .NET Core that lets you build intera 2. Install the latest edition of [Visual Studio 2019](https://visualstudio.com/vs/) with the **ASP.NET and web development** workload. Installing the latest edition will also install the latest version of .NET Core 3.0. - 3. Download or Clone the Oqtane source code to your local system. Open the **Oqtane.sln** solution file. If you want to develop using **server-side** Blazor ( which includes a full debugging experience in Visual Studio ) you should choose to Build the solution using the default Debug configuration. If you want to develop using **client-side** Blazor ( WebAssembly ) you should first choose the "Wasm" configuration option in the Visual Studio toolbar and then Build. + 3. Download or Clone the Oqtane source code to your local system. Open the **Oqtane.sln** solution file. If you want to develop using **server-side** Blazor (which includes a full debugging experience in Visual Studio) you should choose to Build the solution using the default Debug configuration. If you want to develop using **client-side** Blazor (WebAssembly) you should first choose the "Wasm" configuration option in the Visual Studio toolbar and then Build. NOTE: If you have already installed a previous version of Oqtane and you wish to install a newer version, there is currently no upgrade path from one version to the next. The recommended upgrade approach is to get the latest code and build it, and then reset the DefaultConnection value to "" in the appsettings.json file in the Oqtane.server project. This will trigger a re-install when you run the application which will execute the latest database scripts. @@ -39,7 +39,7 @@ Database - Need ability to run on SQLite # Background -Oqtane was created by [Shaun Walker](https://www.linkedin.com/in/shaunbrucewalker/) and is inspired by the DotNetNuke web application framework. Initially created as a proof of concept, Oqtane is a native Blazor application written from the ground up using modern .NET Core technology. It is a modular framework offering a fully dynamic page compositing model, multi-site support, designer friendly templates ( skins ), and extensibility via third party modules. +Oqtane was created by [Shaun Walker](https://www.linkedin.com/in/shaunbrucewalker/) and is inspired by the DotNetNuke web application framework. Initially created as a proof of concept, Oqtane is a native Blazor application written from the ground up using modern .NET Core technology. It is a modular framework offering a fully dynamic page compositing model, multi-site support, designer friendly templates (skins), and extensibility via third party modules. At this point Oqtane offers a minimum of desired functionality and is not recommended for production usage. The expectation is that Oqtane will rapidly evolve as a community driven open source project. At this point in time we do not promise any upgrade path from one version to the next, and developers should expect breaking changes as the framework stabilizes. From d2cd9095de53f7b578275e757e4e69ba204ef412 Mon Sep 17 00:00:00 2001 From: Emanuele Filardo Date: Sat, 5 Oct 2019 23:44:55 +0200 Subject: [PATCH 3/9] Add IDeleteable to Site --- Oqtane.Server/Scripts/00.00.00.sql | 3 +++ Oqtane.Shared/Models/Site.cs | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Oqtane.Server/Scripts/00.00.00.sql b/Oqtane.Server/Scripts/00.00.00.sql index fd1a0233..569101db 100644 --- a/Oqtane.Server/Scripts/00.00.00.sql +++ b/Oqtane.Server/Scripts/00.00.00.sql @@ -14,6 +14,9 @@ CREATE TABLE [dbo].[Site]( [CreatedOn] [datetime] NOT NULL, [ModifiedBy] [nvarchar](256) NOT NULL, [ModifiedOn] [datetime] NOT NULL, + [DeletedBy] [nvarchar](256) NULL, + [DeletedOn] [datetime] NULL, + [IsDeleted][bit] NOT NULL CONSTRAINT [PK_Site] PRIMARY KEY CLUSTERED ( [SiteId] ASC diff --git a/Oqtane.Shared/Models/Site.cs b/Oqtane.Shared/Models/Site.cs index f1384879..af346db4 100644 --- a/Oqtane.Shared/Models/Site.cs +++ b/Oqtane.Shared/Models/Site.cs @@ -1,10 +1,12 @@ using System; +using System.ComponentModel.DataAnnotations; namespace Oqtane.Models { - public class Site : IAuditable + public class Site : IAuditable, IDeletable { public int SiteId { get; set; } + [StringLength(20, ErrorMessage = "Length must be more than 5 and less than 20 characters", MinimumLength = 5)] public string Name { get; set; } public string Logo { get; set; } public string DefaultThemeType { get; set; } @@ -15,5 +17,8 @@ namespace Oqtane.Models public DateTime CreatedOn { get; set; } public string ModifiedBy { get; set; } public DateTime ModifiedOn { get; set; } + public string DeletedBy { get; set; } + public DateTime? DeletedOn { get; set; } + public bool IsDeleted { get; set; } } } From 5a389c198bb0c03f2f356808592d593d0ac3c1e2 Mon Sep 17 00:00:00 2001 From: Emanuele Filardo Date: Tue, 8 Oct 2019 09:57:42 +0200 Subject: [PATCH 4/9] Pages Delete replace readonly with disabled --- Oqtane.Client/Modules/Admin/Pages/Delete.razor | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Pages/Delete.razor b/Oqtane.Client/Modules/Admin/Pages/Delete.razor index 5dff05a2..0f1e9cc8 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Delete.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Delete.razor @@ -10,7 +10,7 @@ - + @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - @foreach (Page p in PageState.Pages) { @@ -40,7 +40,7 @@ - @@ -51,7 +51,7 @@ - @@ -62,7 +62,7 @@ - @foreach (KeyValuePair item in themes) { @@ -76,7 +76,7 @@ - @foreach (KeyValuePair panelayout in panelayouts) { @@ -90,7 +90,7 @@ - + @@ -98,7 +98,7 @@ - From 58427dcd62834ccac2ec983acaae899de747afcb Mon Sep 17 00:00:00 2001 From: Emanuele Filardo Date: Tue, 8 Oct 2019 09:58:28 +0200 Subject: [PATCH 5/9] Add AuditInfo and IsDeleted to Site Edit and Delete --- .../Modules/Admin/Sites/Delete.razor | 37 +++++++++++++++++-- Oqtane.Client/Modules/Admin/Sites/Edit.razor | 32 ++++++++++++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Sites/Delete.razor b/Oqtane.Client/Modules/Admin/Sites/Delete.razor index f57f6e00..b2acba36 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Delete.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Delete.razor @@ -16,7 +16,7 @@ else - + @@ -24,7 +24,7 @@ else - + @@ -32,7 +32,7 @@ else - @foreach (KeyValuePair item in themes) { @@ -46,7 +46,7 @@ else - @foreach (KeyValuePair panelayout in panelayouts) { @@ -55,9 +55,23 @@ else + + + + + + + + Cancel +
+
+ } @code { @@ -70,6 +84,13 @@ else string logo = ""; string themetype; string layouttype; + string createdby; + DateTime createdon; + string modifiedby; + DateTime modifiedon; + string deletedby; + DateTime? deletedon; + string isdeleted; protected override void OnInitialized() { @@ -79,6 +100,14 @@ else logo = PageState.Site.Logo; themetype = PageState.Site.DefaultThemeType; layouttype = PageState.Site.DefaultLayoutType; + + createdby = PageState.Site.CreatedBy; + createdon = PageState.Site.CreatedOn; + modifiedby = PageState.Site.ModifiedBy; + modifiedon = PageState.Site.ModifiedOn; + deletedby = PageState.Site.DeletedBy; + deletedon = PageState.Site.DeletedOn; + isdeleted = PageState.Site.IsDeleted.ToString(); } private async Task DeleteSite() diff --git a/Oqtane.Client/Modules/Admin/Sites/Edit.razor b/Oqtane.Client/Modules/Admin/Sites/Edit.razor index 6ad50046..92f4a0f4 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Edit.razor @@ -55,9 +55,23 @@ else + + + + + + + + Cancel +
+
+ } @code { @@ -71,6 +85,14 @@ else string themetype; string layouttype; + string createdby; + DateTime createdon; + string modifiedby; + DateTime modifiedon; + string deletedby; + DateTime? deletedon; + string isdeleted; + protected override void OnInitialized() { themes = ThemeService.GetThemeTypes(PageState.Themes); @@ -79,6 +101,14 @@ else logo = PageState.Site.Logo; themetype = PageState.Site.DefaultThemeType; layouttype = PageState.Site.DefaultLayoutType; + + createdby = PageState.Site.CreatedBy; + createdon = PageState.Site.CreatedOn; + modifiedby = PageState.Site.ModifiedBy; + modifiedon = PageState.Site.ModifiedOn; + deletedby = PageState.Site.DeletedBy; + deletedon = PageState.Site.DeletedOn; + isdeleted = PageState.Site.IsDeleted.ToString(); } private async Task SaveSite() @@ -88,6 +118,8 @@ else site.Logo = (logo == null ? "" : logo); site.DefaultThemeType = themetype; site.DefaultLayoutType = (layouttype == null ? "" : layouttype); + site.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted)); + site = await SiteService.UpdateSiteAsync(site); NavigationManager.NavigateTo(NavigateUrl()); From 8de502e5049a3decb7500f34c9b0225934f8c7c2 Mon Sep 17 00:00:00 2001 From: Emanuele Filardo Date: Tue, 8 Oct 2019 10:41:39 +0200 Subject: [PATCH 6/9] Add IDeletable to User --- Oqtane.Client/Modules/Admin/Users/Add.razor | 4 ++- Oqtane.Client/Modules/Admin/Users/Edit.razor | 32 +++++++++++++++++++- Oqtane.Server/Scripts/00.00.00.sql | 3 ++ Oqtane.Shared/Models/User.cs | 5 ++- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Users/Add.razor b/Oqtane.Client/Modules/Admin/Users/Add.razor index 587eb406..6ce94d0a 100644 --- a/Oqtane.Client/Modules/Admin/Users/Add.razor +++ b/Oqtane.Client/Modules/Admin/Users/Add.razor @@ -100,8 +100,10 @@ user.Username = username; user.Password = password; user.Email = email; - user.DisplayName = displayname; + user.DisplayName = string.IsNullOrWhiteSpace(user.DisplayName) ? user.Username : user.DisplayName; + user = await UserService.AddUserAsync(user); + if (user != null) { await SettingService.UpdateUserSettingsAsync(settings, user.UserId); diff --git a/Oqtane.Client/Modules/Admin/Users/Edit.razor b/Oqtane.Client/Modules/Admin/Users/Edit.razor index 9c232a7f..974bc6dd 100644 --- a/Oqtane.Client/Modules/Admin/Users/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Users/Edit.razor @@ -62,9 +62,23 @@ } + + + + + + + + Cancel +
+
+ } @code { @@ -78,6 +92,13 @@ List profiles; Dictionary settings; string category = ""; + string createdby; + DateTime createdon; + string modifiedby; + DateTime modifiedon; + string deletedby; + DateTime? deletedon; + string isdeleted; protected override async Task OnInitializedAsync() { @@ -93,6 +114,13 @@ email = user.Email; displayname = user.DisplayName; settings = await SettingService.GetUserSettingsAsync(user.UserId); + createdby = user.CreatedBy; + createdon = user.CreatedOn; + modifiedby = user.ModifiedBy; + modifiedon = user.ModifiedOn; + deletedby = user.DeletedBy; + deletedon = user.DeletedOn; + isdeleted = user.IsDeleted.ToString(); } } catch (Exception ex) @@ -115,7 +143,9 @@ user.Username = username; user.Password = password; user.Email = email; - user.DisplayName = displayname; + user.DisplayName = string.IsNullOrWhiteSpace(user.DisplayName) ? user.Username : user.DisplayName; + user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted)); + user = await UserService.UpdateUserAsync(user); await SettingService.UpdateUserSettingsAsync(settings, user.UserId); diff --git a/Oqtane.Server/Scripts/00.00.00.sql b/Oqtane.Server/Scripts/00.00.00.sql index 569101db..d50dce0a 100644 --- a/Oqtane.Server/Scripts/00.00.00.sql +++ b/Oqtane.Server/Scripts/00.00.00.sql @@ -94,6 +94,9 @@ CREATE TABLE [dbo].[User]( [CreatedOn] [datetime] NOT NULL, [ModifiedBy] [nvarchar](256) NOT NULL, [ModifiedOn] [datetime] NOT NULL, + [DeletedBy] [nvarchar](256) NULL, + [DeletedOn] [datetime] NULL, + [IsDeleted][bit] NOT NULL CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ( [UserId] ASC diff --git a/Oqtane.Shared/Models/User.cs b/Oqtane.Shared/Models/User.cs index 001c4472..bec8f3e2 100644 --- a/Oqtane.Shared/Models/User.cs +++ b/Oqtane.Shared/Models/User.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Oqtane.Models { - public class User : IAuditable + public class User : IAuditable, IDeletable { public int UserId { get; set; } public string Username { get; set; } @@ -19,6 +19,9 @@ namespace Oqtane.Models public DateTime CreatedOn { get; set; } public string ModifiedBy { get; set; } public DateTime ModifiedOn { get; set; } + public string DeletedBy { get; set; } + public DateTime? DeletedOn { get; set; } + public bool IsDeleted { get; set; } [NotMapped] public string Password { get; set; } From 2e43bc127e86e9426ac72d617e98ba0f0e555141 Mon Sep 17 00:00:00 2001 From: Emanuele Filardo Date: Tue, 8 Oct 2019 11:08:14 +0200 Subject: [PATCH 7/9] Delete Users and AspNetUsers tables --- Oqtane.Server/Controllers/UserController.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs index c767e479..a2bbd4bd 100644 --- a/Oqtane.Server/Controllers/UserController.cs +++ b/Oqtane.Server/Controllers/UserController.cs @@ -152,9 +152,19 @@ namespace Oqtane.Controllers // DELETE api//5?siteid=x [HttpDelete("{id}")] [Authorize(Roles = Constants.AdminRole)] - public void Delete(int id) + public async Task Delete(int id) { - Users.DeleteUser(id); + IdentityUser identityuser = await IdentityUserManager.FindByNameAsync(Users.GetUser(id).Username); + + if (identityuser != null) + { + var result = await IdentityUserManager.DeleteAsync(identityuser); + + if (result != null) + { + Users.DeleteUser(id); + } + } } // POST api//login From 7b4eee4d0ce4ca11a1daa8711018a80a288b7edf Mon Sep 17 00:00:00 2001 From: Emanuele Filardo Date: Tue, 8 Oct 2019 11:11:20 +0200 Subject: [PATCH 8/9] Remove not required DataAnnotations --- Oqtane.Shared/Models/Site.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Oqtane.Shared/Models/Site.cs b/Oqtane.Shared/Models/Site.cs index af346db4..05c659ef 100644 --- a/Oqtane.Shared/Models/Site.cs +++ b/Oqtane.Shared/Models/Site.cs @@ -1,12 +1,10 @@ using System; -using System.ComponentModel.DataAnnotations; namespace Oqtane.Models { public class Site : IAuditable, IDeletable { public int SiteId { get; set; } - [StringLength(20, ErrorMessage = "Length must be more than 5 and less than 20 characters", MinimumLength = 5)] public string Name { get; set; } public string Logo { get; set; } public string DefaultThemeType { get; set; } From 5fd4d690347877aab34361d0942ca3777a640655 Mon Sep 17 00:00:00 2001 From: Emanuele Filardo Date: Tue, 8 Oct 2019 11:23:22 +0200 Subject: [PATCH 9/9] Simplified User Delete page --- .../Modules/Admin/Users/Delete.razor | 68 +++++++++---------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Users/Delete.razor b/Oqtane.Client/Modules/Admin/Users/Delete.razor index 7bdef31d..8e68735a 100644 --- a/Oqtane.Client/Modules/Admin/Users/Delete.razor +++ b/Oqtane.Client/Modules/Admin/Users/Delete.razor @@ -5,7 +5,7 @@ @inject IProfileService ProfileService @inject ISettingService SettingService -@if (profiles != null) +@if (!string.IsNullOrWhiteSpace(username)) { @@ -13,7 +13,7 @@ @@ -21,7 +21,7 @@ @@ -29,34 +29,26 @@ + + + + - - @foreach (Profile profile in profiles) - { - var p = profile; - if (p.Category != category) - { - - - - category = p.Category; - } - - - - - }
- +
- +
- + +
+ + +
- @p.Category -
- - - -
Cancel +
+
+ } @code { @@ -66,16 +58,19 @@ string username = ""; string email = ""; string displayname = ""; - List profiles; - Dictionary settings; string category = ""; + string createdby; + DateTime createdon; + string modifiedby; + DateTime modifiedon; + string deletedby; + DateTime? deletedon; + string isdeleted; protected override async Task OnInitializedAsync() { try { - profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId); - userid = Int32.Parse(PageState.QueryString["id"]); User user = await UserService.GetUserAsync(userid, PageState.Site.SiteId); if (user != null) @@ -83,7 +78,13 @@ username = user.Username; email = user.Email; displayname = user.DisplayName; - settings = await SettingService.GetUserSettingsAsync(user.UserId); + createdby = user.CreatedBy; + createdon = user.CreatedOn; + modifiedby = user.ModifiedBy; + modifiedon = user.ModifiedOn; + deletedby = user.DeletedBy; + deletedon = user.DeletedOn; + isdeleted = user.IsDeleted.ToString(); } } catch (Exception ex) @@ -92,11 +93,6 @@ } } - private string GetProfileValue(string SettingName, string DefaultValue) - { - return SettingService.GetSetting(settings, SettingName, DefaultValue); - } - private async Task DeleteUser() { try