Merge pull request #7 from oqtane/master

sync with upstream
This commit is contained in:
Shaun Walker 2019-10-08 15:43:32 -04:00 committed by GitHub
commit dce53e10b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 168 additions and 58 deletions

View File

@ -10,7 +10,7 @@
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" readonly />
<input class="form-control" @bind="@name" disabled />
</td>
</tr>
<tr>
@ -18,7 +18,7 @@
<label for="Name" class="control-label">Path: </label>
</td>
<td>
<input class="form-control" @bind="@path" readonly />
<input class="form-control" @bind="@path" disabled />
</td>
</tr>
<tr>
@ -26,7 +26,7 @@
<label for="Name" class="control-label">Parent: </label>
</td>
<td>
<select class="form-control" @bind="@parentid" readonly>
<select class="form-control" @bind="@parentid" disabled>
<option value="">&lt;Select Parent&gt;</option>
@foreach (Page p in PageState.Pages)
{
@ -40,7 +40,7 @@
<label for="Name" class="control-label">Navigation? </label>
</td>
<td>
<select class="form-control" @bind="@isnavigation" readonly>
<select class="form-control" @bind="@isnavigation" disabled>
<option value="True">Yes</option>
<option value="False">No</option>
</select>
@ -51,7 +51,7 @@
<label for="Name" class="control-label">Default Mode? </label>
</td>
<td>
<select class="form-control" @bind="@mode" readonly>
<select class="form-control" @bind="@mode" disabled>
<option value="view">View Mode</option>
<option value="edit">Edit Mode</option>
</select>
@ -62,7 +62,7 @@
<label for="Name" class="control-label">Theme: </label>
</td>
<td>
<select class="form-control" @bind="@themetype" readonly>
<select class="form-control" @bind="@themetype" disabled>
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in themes)
{
@ -76,7 +76,7 @@
<label for="Name" class="control-label">Layout: </label>
</td>
<td>
<select class="form-control" @bind="@layouttype" readonly>
<select class="form-control" @bind="@layouttype" disabled>
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in panelayouts)
{
@ -90,7 +90,7 @@
<label for="Name" class="control-label">Icon: </label>
</td>
<td>
<input class="form-control" @bind="@icon" readonly />
<input class="form-control" @bind="@icon" disabled />
</td>
</tr>
<tr>
@ -98,7 +98,7 @@
<label for="Name" class="control-label">Is Deleted? </label>
</td>
<td>
<select class="form-control" @bind="@isdeleted" readonly>
<select class="form-control" @bind="@isdeleted" disabled>
<option value="True">Yes</option>
<option value="False">No</option>
</select>

View File

@ -16,7 +16,7 @@ else
<label for="Name" class="control-label">Name: </label>
</td>
<td>
<input class="form-control" @bind="@name" readonly />
<input class="form-control" @bind="@name" disabled />
</td>
</tr>
<tr>
@ -24,7 +24,7 @@ else
<label for="Name" class="control-label">Logo: </label>
</td>
<td>
<input class="form-control" @bind="@logo" readonly />
<input class="form-control" @bind="@logo" disabled />
</td>
</tr>
<tr>
@ -32,7 +32,7 @@ else
<label for="Name" class="control-label">Default Theme: </label>
</td>
<td>
<select class="form-control" @bind="@themetype" readonly>
<select class="form-control" @bind="@themetype" disabled>
<option value="">&lt;Select Theme&gt;</option>
@foreach (KeyValuePair<string, string> item in themes)
{
@ -46,7 +46,7 @@ else
<label for="Name" class="control-label">Default Layout: </label>
</td>
<td>
<select class="form-control" @bind="@layouttype" readonly>
<select class="form-control" @bind="@layouttype" disabled>
<option value="">&lt;Select Layout&gt;</option>
@foreach (KeyValuePair<string, string> panelayout in panelayouts)
{
@ -55,9 +55,23 @@ else
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Is Deleted? </label>
</td>
<td>
<select class="form-control" @bind="@isdeleted" disabled>
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="DeleteSite">Delete</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
}
@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()

View File

@ -55,9 +55,23 @@ else
</select>
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Is Deleted? </label>
</td>
<td>
<select class="form-control" @bind="@isdeleted">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
</table>
<button type="button" class="btn btn-success" @onclick="SaveSite">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
}
@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());

View File

@ -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);

View File

@ -5,7 +5,7 @@
@inject IProfileService ProfileService
@inject ISettingService SettingService
@if (profiles != null)
@if (!string.IsNullOrWhiteSpace(username))
{
<table class="table table-borderless">
<tr>
@ -13,7 +13,7 @@
<label for="Name" class="control-label">Username: </label>
</td>
<td>
<input class="form-control" @bind="@username" readonly />
<input class="form-control" @bind="@username" disabled />
</td>
</tr>
<tr>
@ -21,7 +21,7 @@
<label for="Name" class="control-label">Email: </label>
</td>
<td>
<input class="form-control" @bind="@email" readonly />
<input class="form-control" @bind="@email" disabled />
</td>
</tr>
<tr>
@ -29,34 +29,26 @@
<label for="Name" class="control-label">Full Name: </label>
</td>
<td>
<input class="form-control" @bind="@displayname" readonly />
<input class="form-control" @bind="@displayname" disabled />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Is Deleted? </label>
</td>
<td>
<select class="form-control" @bind="@isdeleted" disabled>
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
@foreach (Profile profile in profiles)
{
var p = profile;
if (p.Category != category)
{
<tr>
<th colspan="2" style="text-align: center;">
@p.Category
</th>
</tr>
category = p.Category;
}
<tr>
<td>
<label for="@p.Name" class="control-label">@p.Title: </label>
</td>
<td>
<input class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" readonly />
</td>
</tr>
}
</table>
<button type="button" class="btn btn-primary" @onclick="DeleteUser">Delete</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
}
@code {
@ -66,16 +58,19 @@
string username = "";
string email = "";
string displayname = "";
List<Profile> profiles;
Dictionary<string, string> 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

View File

@ -62,9 +62,23 @@
</td>
</tr>
}
<tr>
<td>
<label for="Name" class="control-label">Is Deleted? </label>
</td>
<td>
<select class="form-control" @bind="@isdeleted">
<option value="True">Yes</option>
<option value="False">No</option>
</select>
</td>
</tr>
</table>
<button type="button" class="btn btn-primary" @onclick="SaveUser">Save</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
}
@code {
@ -78,6 +92,13 @@
List<Profile> profiles;
Dictionary<string, string> 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);

View File

@ -152,9 +152,19 @@ namespace Oqtane.Controllers
// DELETE api/<controller>/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/<controller>/login

View File

@ -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
@ -91,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

View File

@ -2,7 +2,7 @@
namespace Oqtane.Models
{
public class Site : IAuditable
public class Site : IAuditable, IDeletable
{
public int SiteId { get; set; }
public string Name { get; set; }
@ -15,5 +15,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; }
}
}

View File

@ -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; }

View File

@ -11,7 +11,7 @@ Oqtane uses Blazor, a new web framework for .NET Core that lets you build intera
2.&nbsp;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.&nbsp;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.&nbsp;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.
@ -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
@ -40,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.