Cleanup
This commit is contained in:
@@ -14,4 +14,9 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.7" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_ContentIncludedByDefault Remove="wwwroot\bootstrap\bootstrap.min.css" />
|
||||||
|
<_ContentIncludedByDefault Remove="wwwroot\bootstrap\bootstrap.min.css.map" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ if (!app.Environment.IsDevelopment()) {
|
|||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
//app.UseAntiforgery();
|
app.UseAntiforgery();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseMiddleware<AuthMiddleware>();
|
app.UseMiddleware<AuthMiddleware>();
|
||||||
|
|
||||||
app.MapRazorComponents<App>()
|
app.MapRazorComponents<App>()
|
||||||
.AddHopFramePages()
|
.AddHopFrameAdminPages()
|
||||||
.AddInteractiveServerRenderMode();
|
.AddInteractiveServerRenderMode();
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,6 +5,8 @@
|
|||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>disable</Nullable>
|
<Nullable>disable</Nullable>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -12,4 +14,8 @@
|
|||||||
<ProjectReference Include="..\HopFrame.Security\HopFrame.Security.csproj" />
|
<ProjectReference Include="..\HopFrame.Security\HopFrame.Security.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="README.md" Pack="true" PackagePath="\"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
namespace HopFrame.Api.Models;
|
namespace HopFrame.Api.Models;
|
||||||
|
|
||||||
public class UserPasswordValidation {
|
public sealed class UserPasswordValidation {
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
}
|
}
|
||||||
2
HopFrame.Api/README.md
Normal file
2
HopFrame.Api/README.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# HopFrame API module
|
||||||
|
This module contains some useful endpoints for user login / register management.
|
||||||
@@ -5,10 +5,16 @@
|
|||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>disable</Nullable>
|
<Nullable>disable</Nullable>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.7" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="README.md" Pack="true" PackagePath="\"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
2
HopFrame.Database/README.md
Normal file
2
HopFrame.Database/README.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# HopFrame Database module
|
||||||
|
This module contains all the logic for the database communication
|
||||||
@@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Http;
|
|||||||
|
|
||||||
namespace HopFrame.Security.Claims;
|
namespace HopFrame.Security.Claims;
|
||||||
|
|
||||||
internal class TokenContextImplementor<TDbContext>(IHttpContextAccessor accessor, TDbContext context) : ITokenContext where TDbContext : HopDbContextBase {
|
internal sealed class TokenContextImplementor<TDbContext>(IHttpContextAccessor accessor, TDbContext context) : ITokenContext where TDbContext : HopDbContextBase {
|
||||||
public bool IsAuthenticated => !string.IsNullOrEmpty(accessor.HttpContext?.User.GetAccessTokenId());
|
public bool IsAuthenticated => !string.IsNullOrEmpty(accessor.HttpContext?.User.GetAccessTokenId());
|
||||||
|
|
||||||
public User User => context.Users
|
public User User => context.Users
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>disable</Nullable>
|
<Nullable>disable</Nullable>
|
||||||
<RootNamespace>HopFrame.Security</RootNamespace>
|
<RootNamespace>HopFrame.Security</RootNamespace>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -17,4 +19,8 @@
|
|||||||
<ProjectReference Include="..\HopFrame.Database\HopFrame.Database.csproj" />
|
<ProjectReference Include="..\HopFrame.Database\HopFrame.Database.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="README.md" Pack="true" PackagePath="\"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
2
HopFrame.Security/README.md
Normal file
2
HopFrame.Security/README.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# HopFrame Security module
|
||||||
|
this module contains all handlers for the login and register validation. It also checks the user permissions.
|
||||||
@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Http;
|
|||||||
|
|
||||||
namespace HopFrame.Web;
|
namespace HopFrame.Web;
|
||||||
|
|
||||||
public class AuthMiddleware(IAuthService auth, IPermissionService perms) : IMiddleware {
|
public sealed class AuthMiddleware(IAuthService auth, IPermissionService perms) : IMiddleware {
|
||||||
public async Task InvokeAsync(HttpContext context, RequestDelegate next) {
|
public async Task InvokeAsync(HttpContext context, RequestDelegate next) {
|
||||||
var loggedIn = await auth.IsLoggedIn();
|
var loggedIn = await auth.IsLoggedIn();
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
@using BlazorStrap.V5
|
@using BlazorStrap.V5
|
||||||
@using CurrieTechnologies.Razor.SweetAlert2
|
@using CurrieTechnologies.Razor.SweetAlert2
|
||||||
@using HopFrame.Database.Models
|
@using HopFrame.Database.Models
|
||||||
|
@using HopFrame.Security.Claims
|
||||||
@using HopFrame.Security.Services
|
@using HopFrame.Security.Services
|
||||||
@using HopFrame.Web.Model
|
@using HopFrame.Web.Model
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@
|
|||||||
@if (!_isEdit) {
|
@if (!_isEdit) {
|
||||||
<BSInputGroup>
|
<BSInputGroup>
|
||||||
<span class="@BS.Input_Group_Text">group.</span>
|
<span class="@BS.Input_Group_Text">group.</span>
|
||||||
<BSInput InputType="InputType.Text" @bind-Value="_group.GroupName"/>
|
<BSInput InputType="InputType.Text" @bind-Value="_group.GroupName" required/>
|
||||||
</BSInputGroup>
|
</BSInputGroup>
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -116,6 +117,7 @@
|
|||||||
|
|
||||||
@inject IPermissionService Permissions
|
@inject IPermissionService Permissions
|
||||||
@inject SweetAlertService Alerts
|
@inject SweetAlertService Alerts
|
||||||
|
@inject ITokenContext Context
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter] public Func<Task> ReloadPage { get; set; }
|
[Parameter] public Func<Task> ReloadPage { get; set; }
|
||||||
@@ -165,6 +167,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_isEdit) {
|
if (_isEdit) {
|
||||||
|
if (!(await Permissions.HasPermission(AdminPermissions.EditGroup, Context.User.Id))) {
|
||||||
|
await NoEditPermissions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await Permissions.AddPermission(_group, _permissionToAdd);
|
await Permissions.AddPermission(_group, _permissionToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,6 +202,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_isEdit) {
|
if (_isEdit) {
|
||||||
|
if (!(await Permissions.HasPermission(AdminPermissions.EditGroup, Context.User.Id))) {
|
||||||
|
await NoEditPermissions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await Permissions.AddPermission(_group, _groupToAdd);
|
await Permissions.AddPermission(_group, _groupToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,6 +219,11 @@
|
|||||||
|
|
||||||
private async Task AddGroup() {
|
private async Task AddGroup() {
|
||||||
if (_isEdit) {
|
if (_isEdit) {
|
||||||
|
if (!(await Permissions.HasPermission(AdminPermissions.EditGroup, Context.User.Id))) {
|
||||||
|
await NoEditPermissions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await Permissions.EditPermissionGroup(_group);
|
await Permissions.EditPermissionGroup(_group);
|
||||||
|
|
||||||
if (ReloadPage is not null)
|
if (ReloadPage is not null)
|
||||||
@@ -222,6 +239,11 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(await Permissions.HasPermission(AdminPermissions.AddGroup, Context.User.Id))) {
|
||||||
|
await NoAddPermissions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_allGroups.Any(group => group.Name == _group.Name)) {
|
if (_allGroups.Any(group => group.Name == _group.Name)) {
|
||||||
await Alerts.FireAsync(new SweetAlertOptions {
|
await Alerts.FireAsync(new SweetAlertOptions {
|
||||||
Title = "Something went wrong!",
|
Title = "Something went wrong!",
|
||||||
@@ -249,4 +271,20 @@
|
|||||||
ShowConfirmButton = false
|
ShowConfirmButton = false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task NoEditPermissions() {
|
||||||
|
await Alerts.FireAsync(new SweetAlertOptions {
|
||||||
|
Title = "Unauthorized!",
|
||||||
|
Text = "You don't have the required permissions to edit a group!",
|
||||||
|
Icon = SweetAlertIcon.Error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task NoAddPermissions() {
|
||||||
|
await Alerts.FireAsync(new SweetAlertOptions {
|
||||||
|
Title = "Unauthorized!",
|
||||||
|
Text = "You don't have the required permissions to add a group!",
|
||||||
|
Icon = SweetAlertIcon.Error
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,17 +16,17 @@
|
|||||||
<BSModalContent>
|
<BSModalContent>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<BSLabel>E-Mail</BSLabel>
|
<BSLabel>E-Mail</BSLabel>
|
||||||
<BSInput InputType="InputType.Email" @bind-Value="_user.Email" />
|
<BSInput InputType="InputType.Email" @bind-Value="_user.Email" required/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<BSLabel>Username</BSLabel>
|
<BSLabel>Username</BSLabel>
|
||||||
<BSInput InputType="InputType.Text" @bind-Value="_user.Username" />
|
<BSInput InputType="InputType.Text" @bind-Value="_user.Username" required/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<BSLabel>Password</BSLabel>
|
<BSLabel>Password</BSLabel>
|
||||||
<BSInput InputType="InputType.Password" @bind-Value="_user.Password" />
|
<BSInput InputType="InputType.Password" @bind-Value="_user.Password" required/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
private async Task NoAddPermissions() {
|
private async Task NoAddPermissions() {
|
||||||
await Alerts.FireAsync(new SweetAlertOptions {
|
await Alerts.FireAsync(new SweetAlertOptions {
|
||||||
Title = "Unauthorized!",
|
Title = "Unauthorized!",
|
||||||
Text = "You don't have the required Permissions to edit a user!",
|
Text = "You don't have the required permissions to add a user!",
|
||||||
Icon = SweetAlertIcon.Error
|
Icon = SweetAlertIcon.Error
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
@using HopFrame.Security.Claims
|
@using HopFrame.Security.Claims
|
||||||
@using HopFrame.Security.Services
|
@using HopFrame.Security.Services
|
||||||
@using HopFrame.Web.Model
|
@using HopFrame.Web.Model
|
||||||
@using HopFrame.Web.Services
|
|
||||||
|
|
||||||
<BSModal DataId="edit-user-modal" HideOnValidSubmit="true" IsStaticBackdrop="true" @ref="_modal">
|
<BSModal DataId="edit-user-modal" HideOnValidSubmit="true" IsStaticBackdrop="true" @ref="_modal">
|
||||||
<BSForm Model="_user" OnValidSubmit="EditUser">
|
<BSForm Model="_user" OnValidSubmit="EditUser">
|
||||||
@@ -25,11 +24,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<BSLabel>E-Mail</BSLabel>
|
<BSLabel>E-Mail</BSLabel>
|
||||||
<BSInput InputType="InputType.Email" @bind-Value="_user.Email" />
|
<BSInput InputType="InputType.Email" @bind-Value="_user.Email" required/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<BSLabel>Username</BSLabel>
|
<BSLabel>Username</BSLabel>
|
||||||
<BSInput InputType="InputType.Text" @bind-Value="_user.Username" />
|
<BSInput InputType="InputType.Text" @bind-Value="_user.Username" required/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<BSLabel>Password</BSLabel>
|
<BSLabel>Password</BSLabel>
|
||||||
@@ -300,7 +299,7 @@
|
|||||||
private async Task NoEditPermissions() {
|
private async Task NoEditPermissions() {
|
||||||
await Alerts.FireAsync(new SweetAlertOptions {
|
await Alerts.FireAsync(new SweetAlertOptions {
|
||||||
Title = "Unauthorized!",
|
Title = "Unauthorized!",
|
||||||
Text = "You don't have the required Permissions to edit a user!",
|
Text = "You don't have the required permissions to edit a user!",
|
||||||
Icon = SweetAlertIcon.Error
|
Icon = SweetAlertIcon.Error
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
<Nullable>disable</Nullable>
|
<Nullable>disable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
|
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -24,5 +26,8 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.7" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="README.md" Pack="true" PackagePath="\"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
8
HopFrame.Web/Model/NavigationItem.cs
Normal file
8
HopFrame.Web/Model/NavigationItem.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace HopFrame.Web.Model;
|
||||||
|
|
||||||
|
public sealed class NavigationItem {
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Url { get; set; }
|
||||||
|
public string Permission { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
}
|
||||||
@@ -2,6 +2,6 @@ using HopFrame.Database.Models;
|
|||||||
|
|
||||||
namespace HopFrame.Web.Model;
|
namespace HopFrame.Web.Model;
|
||||||
|
|
||||||
public class PermissionGroupAdd : PermissionGroup {
|
internal sealed class PermissionGroupAdd : PermissionGroup {
|
||||||
public string GroupName { get; set; }
|
public string GroupName { get; set; }
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ using HopFrame.Security.Models;
|
|||||||
|
|
||||||
namespace HopFrame.Web.Model;
|
namespace HopFrame.Web.Model;
|
||||||
|
|
||||||
public class RegisterData : UserRegister {
|
internal class RegisterData : UserRegister {
|
||||||
public string RepeatedPassword { get; set; }
|
public string RepeatedPassword { get; set; }
|
||||||
|
|
||||||
public bool PasswordsMatch => Password == RepeatedPassword;
|
public bool PasswordsMatch => Password == RepeatedPassword;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
namespace HopFrame.Web.Model;
|
namespace HopFrame.Web.Model;
|
||||||
|
|
||||||
public class UserAdd : RegisterData {
|
internal sealed class UserAdd : RegisterData {
|
||||||
public string Group { get; set; }
|
public string Group { get; set; }
|
||||||
}
|
}
|
||||||
33
HopFrame.Web/Pages/Administration/AdminDashboard.razor
Normal file
33
HopFrame.Web/Pages/Administration/AdminDashboard.razor
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
@page "/administration"
|
||||||
|
@rendermode InteractiveServer
|
||||||
|
|
||||||
|
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||||
|
@using BlazorStrap
|
||||||
|
@using HopFrame.Web.Pages.Administration.Layout
|
||||||
|
@using BlazorStrap.V5
|
||||||
|
@using HopFrame.Web.Components
|
||||||
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
|
@layout AdminLayout
|
||||||
|
|
||||||
|
<PageTitle>Admin Dashboard</PageTitle>
|
||||||
|
|
||||||
|
<BSContainer>
|
||||||
|
<BSRow Justify="Justify.Center">
|
||||||
|
@foreach (var view in AdminMenu.Subpages) {
|
||||||
|
<AuthorizedView Permission="@view.Permission">
|
||||||
|
<BSCol Column="4" style="margin-bottom: 10px">
|
||||||
|
<BSCard CardType="CardType.Card" Color="BSColor.Dark" style="min-height: 200px">
|
||||||
|
<BSCard CardType="CardType.Body" style="display: flex; flex-direction: column">
|
||||||
|
<BSCard CardType="CardType.Title">@view.Name</BSCard>
|
||||||
|
<BSCard CardType="CardType.Subtitle"><span style="color: gray">@view.Permission</span></BSCard>
|
||||||
|
<BSCard CardType="CardType.Text">@view.Description</BSCard>
|
||||||
|
<BSButton IsOutlined="true" MarginTop="Margins.Auto" style="width: max-content; align-self: center" OnClick="() => Navigator.NavigateTo(view.Url, true)" Color="BSColor.Light">Open</BSButton>
|
||||||
|
</BSCard>
|
||||||
|
</BSCard>
|
||||||
|
</BSCol>
|
||||||
|
</AuthorizedView>
|
||||||
|
}
|
||||||
|
</BSRow>
|
||||||
|
</BSContainer>
|
||||||
|
|
||||||
|
@inject NavigationManager Navigator
|
||||||
67
HopFrame.Web/Pages/Administration/AdminLogin.razor
Normal file
67
HopFrame.Web/Pages/Administration/AdminLogin.razor
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
@page "/administration/login"
|
||||||
|
@layout EmptyLayout
|
||||||
|
|
||||||
|
@using BlazorStrap
|
||||||
|
@using BlazorStrap.V5
|
||||||
|
@using HopFrame.Security.Models
|
||||||
|
@using HopFrame.Web.Pages.Administration.Layout
|
||||||
|
@using HopFrame.Web.Services
|
||||||
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
|
@using Microsoft.AspNetCore.Components.Forms
|
||||||
|
|
||||||
|
<PageTitle>Login</PageTitle>
|
||||||
|
|
||||||
|
<div class="login-wrapper">
|
||||||
|
<EditForm Model="UserLogin" OnValidSubmit="Login" FormName="login-form">
|
||||||
|
<div class="field-wrapper">
|
||||||
|
<h3>Login</h3>
|
||||||
|
<div class="mb-3">
|
||||||
|
<BSLabel>E-Mail address</BSLabel>
|
||||||
|
<InputText type="email" class="form-control" required @bind-Value="UserLogin.Email"/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<BSLabel>Password</BSLabel>
|
||||||
|
<InputText type="password" class="form-control" required @bind-Value="UserLogin.Password"/>
|
||||||
|
</div>
|
||||||
|
<BSButton Color="BSColor.Primary" IsSubmit="true">Login</BSButton>
|
||||||
|
|
||||||
|
@if (_hasError) {
|
||||||
|
<BSAlert Color="BSColor.Danger" style="margin-top: 16px; margin-bottom: 0">Email or password does not match any account!</BSAlert>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</EditForm>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@inject IAuthService Auth
|
||||||
|
@inject NavigationManager Navigator
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[SupplyParameterFromForm]
|
||||||
|
private UserLogin UserLogin { get; set; }
|
||||||
|
|
||||||
|
[SupplyParameterFromQuery(Name = "redirect")]
|
||||||
|
private string RedirectAfter { get; set; }
|
||||||
|
|
||||||
|
private const string DefaultRedirect = "/administration";
|
||||||
|
|
||||||
|
private bool _hasError = false;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync() {
|
||||||
|
UserLogin ??= new();
|
||||||
|
|
||||||
|
if (await Auth.IsLoggedIn()) {
|
||||||
|
await Auth.Logout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Login() {
|
||||||
|
var result = await Auth.Login(UserLogin);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
_hasError = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Navigator.NavigateTo(string.IsNullOrEmpty(RedirectAfter) ? DefaultRedirect : RedirectAfter, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
@page "/administration"
|
|
||||||
@using HopFrame.Web.Pages.Administration.Layout
|
|
||||||
@inherits LayoutComponentBase
|
|
||||||
@layout AdminLayout
|
|
||||||
|
|
||||||
@inject NavigationManager Navigator
|
|
||||||
|
|
||||||
@code {
|
|
||||||
protected override void OnInitialized() {
|
|
||||||
Navigator.NavigateTo("administration/users");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,11 +2,12 @@
|
|||||||
@rendermode InteractiveServer
|
@rendermode InteractiveServer
|
||||||
@layout AdminLayout
|
@layout AdminLayout
|
||||||
|
|
||||||
|
@using System.Globalization
|
||||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||||
@using BlazorStrap
|
@using BlazorStrap
|
||||||
@using Microsoft.AspNetCore.Components.Web
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
@using HopFrame.Web.Components
|
@using HopFrame.Web.Components
|
||||||
@using HopFrame.Web.Pages.Administration.Components
|
@using HopFrame.Web.Components.Administration
|
||||||
@using BlazorStrap.V5
|
@using BlazorStrap.V5
|
||||||
@using CurrieTechnologies.Razor.SweetAlert2
|
@using CurrieTechnologies.Razor.SweetAlert2
|
||||||
@using HopFrame.Database.Models
|
@using HopFrame.Database.Models
|
||||||
@@ -15,7 +16,7 @@
|
|||||||
@using HopFrame.Web.Pages.Administration.Layout
|
@using HopFrame.Web.Pages.Administration.Layout
|
||||||
|
|
||||||
<PageTitle>Groups</PageTitle>
|
<PageTitle>Groups</PageTitle>
|
||||||
<AuthorizedView Permission="@AdminPermissions.ViewGroups" RedirectIfUnauthorized="login?redirect=/administration/groups"/>
|
<AuthorizedView Permission="@AdminPermissions.ViewGroups" RedirectIfUnauthorized="administration/login?redirect=/administration/groups"/>
|
||||||
|
|
||||||
<GroupAddModal ReloadPage="Reload" @ref="_groupAddModal"/>
|
<GroupAddModal ReloadPage="Reload" @ref="_groupAddModal"/>
|
||||||
|
|
||||||
@@ -27,20 +28,32 @@
|
|||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<form class="d-flex" role="search" id="search">
|
<form class="d-flex" role="search" id="search" @onsubmit="Search">
|
||||||
<input class="form-control me-2 input-dark" type="search" placeholder="Search" aria-label="Search">
|
<input class="form-control me-2 input-dark" type="search" placeholder="Search" aria-label="Search" @bind="_searchText">
|
||||||
<BSButton Color="BSColor.Success" IsOutlined="true" type="submit">Search</BSButton>
|
<BSButton Color="BSColor.Success" IsOutlined="true" type="submit">Search</BSButton>
|
||||||
</form>
|
</form>
|
||||||
|
<AuthorizedView Permission="@AdminPermissions.AddGroup">
|
||||||
<BSButton IsSubmit="false" Color="BSColor.Success" Target="add-user" OnClick="() => _groupAddModal.ShowAsync()">Add Group</BSButton>
|
<BSButton IsSubmit="false" Color="BSColor.Success" Target="add-user" OnClick="() => _groupAddModal.ShowAsync()">Add Group</BSButton>
|
||||||
|
</AuthorizedView>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BSTable IsStriped="true" IsHoverable="true" IsDark="true" Color="BSColor.Dark">
|
<BSTable IsStriped="true" IsHoverable="true" IsDark="true" Color="BSColor.Dark">
|
||||||
<BSTHead>
|
<BSTHead>
|
||||||
<BSTR>
|
<BSTR>
|
||||||
<BSTD>Name</BSTD>
|
<BSTD>
|
||||||
|
<span class="sorter" @onclick="() => OrderBy(OrderType.Name)">Name</span>
|
||||||
|
@if (_currentOrder == OrderType.Name) {
|
||||||
|
<HopIconDisplay Type="_currentOrderDirection == OrderDirection.Desc ? HopIconDisplay.HopIcon.ArrowDown : HopIconDisplay.HopIcon.ArrowUp"/>
|
||||||
|
}
|
||||||
|
</BSTD>
|
||||||
<BSTD>Description</BSTD>
|
<BSTD>Description</BSTD>
|
||||||
<BSTD>Default</BSTD>
|
<BSTD>Default</BSTD>
|
||||||
<BSTD>Created</BSTD>
|
<BSTD>
|
||||||
|
<span class="sorter" @onclick="() => OrderBy(OrderType.Created)">Created</span>
|
||||||
|
@if (_currentOrder == OrderType.Created) {
|
||||||
|
<HopIconDisplay Type="_currentOrderDirection == OrderDirection.Desc ? HopIconDisplay.HopIcon.ArrowDown : HopIconDisplay.HopIcon.ArrowUp"/>
|
||||||
|
}
|
||||||
|
</BSTD>
|
||||||
|
|
||||||
@if (_hasEditPrivileges || _hasDeletePrivileges) {
|
@if (_hasEditPrivileges || _hasDeletePrivileges) {
|
||||||
<BSTD>Actions</BSTD>
|
<BSTD>Actions</BSTD>
|
||||||
@@ -90,6 +103,9 @@
|
|||||||
|
|
||||||
private bool _hasEditPrivileges = false;
|
private bool _hasEditPrivileges = false;
|
||||||
private bool _hasDeletePrivileges = false;
|
private bool _hasDeletePrivileges = false;
|
||||||
|
private string _searchText;
|
||||||
|
private OrderType _currentOrder = OrderType.None;
|
||||||
|
private OrderDirection _currentOrderDirection = OrderDirection.Asc;
|
||||||
|
|
||||||
private GroupAddModal _groupAddModal;
|
private GroupAddModal _groupAddModal;
|
||||||
|
|
||||||
@@ -105,9 +121,40 @@
|
|||||||
|
|
||||||
_groups = await Permissions.GetPermissionGroups();
|
_groups = await Permissions.GetPermissionGroups();
|
||||||
|
|
||||||
|
OrderBy(_currentOrder, false);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task Search() {
|
||||||
|
var groups = await Permissions.GetPermissionGroups();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(_searchText)) {
|
||||||
|
groups = groups
|
||||||
|
.Where(group => group.Name.Contains(_searchText) ||
|
||||||
|
group.Description?.Contains(_searchText) == true ||
|
||||||
|
group.CreatedAt.ToString(CultureInfo.InvariantCulture).Contains(_searchText) ||
|
||||||
|
group.Permissions.Any(perm => perm.PermissionName.Contains(_searchText)))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
_groups = groups;
|
||||||
|
OrderBy(_currentOrder, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OrderBy(OrderType type, bool changeDir = true) {
|
||||||
|
if (_currentOrder == type && changeDir) _currentOrderDirection = (OrderDirection)(((byte)_currentOrderDirection + 1) % 2);
|
||||||
|
if (_currentOrder != type) _currentOrderDirection = OrderDirection.Asc;
|
||||||
|
|
||||||
|
if (type == OrderType.Name) {
|
||||||
|
_groups = _currentOrderDirection == OrderDirection.Asc ? _groups.OrderBy(group => group.Name).ToList() : _groups.OrderByDescending(group => group.Name).ToList();
|
||||||
|
}
|
||||||
|
else if (type == OrderType.Created) {
|
||||||
|
_groups = _currentOrderDirection == OrderDirection.Asc ? _groups.OrderBy(group => group.CreatedAt).ToList() : _groups.OrderByDescending(group => group.CreatedAt).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentOrder = type;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task Delete(PermissionGroup group) {
|
private async Task Delete(PermissionGroup group) {
|
||||||
var result = await Alerts.FireAsync(new SweetAlertOptions {
|
var result = await Alerts.FireAsync(new SweetAlertOptions {
|
||||||
Title = "Are you sure?",
|
Title = "Are you sure?",
|
||||||
@@ -130,4 +177,15 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum OrderType {
|
||||||
|
None,
|
||||||
|
Name,
|
||||||
|
Created
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum OrderDirection : byte {
|
||||||
|
Asc = 0,
|
||||||
|
Desc = 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
@using BlazorStrap.V5
|
@using BlazorStrap.V5
|
||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
<AuthorizedView Permission="@AdminPermissions.IsAdmin" RedirectIfUnauthorized="login?redirect=/administration" />
|
<AuthorizedView Permission="@AdminPermissions.IsAdmin" RedirectIfUnauthorized="administration/login" />
|
||||||
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,16 @@
|
|||||||
@using BlazorStrap
|
@using BlazorStrap
|
||||||
@using BlazorStrap.V5
|
@using BlazorStrap.V5
|
||||||
@using HopFrame.Security.Claims
|
@using HopFrame.Security.Claims
|
||||||
@using HopFrame.Web.Pages.Administration.Components
|
|
||||||
@using HopFrame.Web.Services
|
@using HopFrame.Web.Services
|
||||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||||
|
@using HopFrame.Web.Components.Administration
|
||||||
|
@using HopFrame.Web.Model
|
||||||
|
@using HopFrame.Web.Components
|
||||||
|
|
||||||
|
|
||||||
<BSNavbar Color="BSColor.Dark" IsDark="true" IsFixedTop="true">
|
<BSNavbar Color="BSColor.Dark" IsDark="true" IsFixedTop="true">
|
||||||
<BSContainer Container="Container.Fluid">
|
<BSContainer Container="Container.Fluid">
|
||||||
<BSNavbarBrand>
|
<BSNavbarBrand>
|
||||||
<img src="/favicon.png" alt="logo" width="30" class="d-inline-block align-text-top"/>
|
|
||||||
HopFrame
|
HopFrame
|
||||||
</BSNavbarBrand>
|
</BSNavbarBrand>
|
||||||
<BSCollapse IsInNavbar="true">
|
<BSCollapse IsInNavbar="true">
|
||||||
@@ -20,8 +21,12 @@
|
|||||||
</Toggler>
|
</Toggler>
|
||||||
<Content>
|
<Content>
|
||||||
<BSNav MarginEnd="Margins.Auto" MarginBottom="Margins.Small" Class="mb-lg-0">
|
<BSNav MarginEnd="Margins.Auto" MarginBottom="Margins.Small" Class="mb-lg-0">
|
||||||
|
<BSNavItem IsActive="IsDashboardActive()" OnClick="NavigateToDashboard">Dashboard</BSNavItem>
|
||||||
|
|
||||||
@foreach (var nav in Subpages) {
|
@foreach (var nav in Subpages) {
|
||||||
<BSNavItem IsActive="IsNavItemActive(nav.Key)" OnClick="() => Navigate(nav.Key)">@nav.Value</BSNavItem>
|
<AuthorizedView Permission="@nav.Permission">
|
||||||
|
<BSNavItem IsActive="IsNavItemActive(nav.Url)" OnClick="() => Navigate(nav.Url)">@nav.Name</BSNavItem>
|
||||||
|
</AuthorizedView>
|
||||||
}
|
}
|
||||||
</BSNav>
|
</BSNav>
|
||||||
|
|
||||||
@@ -43,20 +48,38 @@
|
|||||||
@inject IAuthService Auth
|
@inject IAuthService Auth
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
public static IDictionary<string, string> Subpages = new Dictionary<string, string> {
|
public static IList<NavigationItem> Subpages = new List<NavigationItem> {
|
||||||
{ "administration/users", "Users" },
|
new () {
|
||||||
{ "administration/groups", "Groups" }
|
Name = "Users",
|
||||||
|
Url = "administration/users",
|
||||||
|
Description = "On this page you can manage all user accounts.",
|
||||||
|
Permission = AdminPermissions.ViewUsers
|
||||||
|
},
|
||||||
|
new () {
|
||||||
|
Name = "Groups",
|
||||||
|
Url = "administration/groups",
|
||||||
|
Description = "On this page you can view, create, edit and delete permission groups.",
|
||||||
|
Permission = AdminPermissions.ViewGroups
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public bool IsNavItemActive(string element) {
|
private bool IsNavItemActive(string element) {
|
||||||
return Navigator.Uri.Contains(element);
|
return Navigator.Uri.Contains(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsDashboardActive() {
|
||||||
|
return Navigator.Uri.TrimEnd('/').EndsWith("administration");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NavigateToDashboard() {
|
||||||
|
Navigate("administration");
|
||||||
|
}
|
||||||
|
|
||||||
private void Navigate(string url) {
|
private void Navigate(string url) {
|
||||||
Navigator.NavigateTo(url, true);
|
Navigator.NavigateTo(url, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Logout() {
|
private void Logout() {
|
||||||
Navigator.NavigateTo("login?redirect=/administration", true);
|
Navigator.NavigateTo("administration/login", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
@using BlazorStrap.V5
|
||||||
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||||
|
|
||||||
|
@Body
|
||||||
|
<BSCore/>
|
||||||
|
|
||||||
|
<script src="_content/BlazorStrap/popper.min.js"></script>
|
||||||
@@ -13,10 +13,10 @@
|
|||||||
@using Microsoft.AspNetCore.Components.Web
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
@using HopFrame.Web.Components
|
@using HopFrame.Web.Components
|
||||||
@using BlazorStrap.V5
|
@using BlazorStrap.V5
|
||||||
@using HopFrame.Web.Pages.Administration.Components
|
@using HopFrame.Web.Components.Administration
|
||||||
|
|
||||||
<PageTitle>Users</PageTitle>
|
<PageTitle>Users</PageTitle>
|
||||||
<AuthorizedView Permission="@AdminPermissions.ViewUsers" RedirectIfUnauthorized="login?redirect=/administration/users"/>
|
<AuthorizedView Permission="@AdminPermissions.ViewUsers" RedirectIfUnauthorized="administration/login?redirect=/administration/users"/>
|
||||||
|
|
||||||
<UserAddModal @ref="_userAddModal" ReloadPage="Reload"/>
|
<UserAddModal @ref="_userAddModal" ReloadPage="Reload"/>
|
||||||
<UserEditModal @ref="_userEditModal" ReloadPage="Reload"/>
|
<UserEditModal @ref="_userEditModal" ReloadPage="Reload"/>
|
||||||
@@ -33,7 +33,9 @@
|
|||||||
<input class="form-control me-2 input-dark" type="search" placeholder="Search" aria-label="Search" @bind="_searchText">
|
<input class="form-control me-2 input-dark" type="search" placeholder="Search" aria-label="Search" @bind="_searchText">
|
||||||
<BSButton Color="BSColor.Success" IsOutlined="true" type="submit">Search</BSButton>
|
<BSButton Color="BSColor.Success" IsOutlined="true" type="submit">Search</BSButton>
|
||||||
</form>
|
</form>
|
||||||
|
<AuthorizedView Permission="@AdminPermissions.AddUser">
|
||||||
<BSButton IsSubmit="false" Color="BSColor.Success" Target="add-user" OnClick="() => _userAddModal.ShowAsync()">Add User</BSButton>
|
<BSButton IsSubmit="false" Color="BSColor.Success" Target="add-user" OnClick="() => _userAddModal.ShowAsync()">Add User</BSButton>
|
||||||
|
</AuthorizedView>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BSTable IsStriped="true" IsHoverable="true" IsDark="true" Color="BSColor.Dark">
|
<BSTable IsStriped="true" IsHoverable="true" IsDark="true" Color="BSColor.Dark">
|
||||||
@@ -118,7 +120,7 @@
|
|||||||
|
|
||||||
foreach (var user in _users) {
|
foreach (var user in _users) {
|
||||||
var groups = await PermissionsService.GetUserPermissionGroups(user);
|
var groups = await PermissionsService.GetUserPermissionGroups(user);
|
||||||
_userGroups.Add(user.Id, groups.FirstOrDefault());
|
_userGroups.Add(user.Id, groups.LastOrDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
_hasEditPrivileges = await PermissionsService.HasPermission(AdminPermissions.EditUser, Auth.User.Id);
|
_hasEditPrivileges = await PermissionsService.HasPermission(AdminPermissions.EditUser, Auth.User.Id);
|
||||||
@@ -133,10 +135,10 @@
|
|||||||
|
|
||||||
foreach (var user in _users) {
|
foreach (var user in _users) {
|
||||||
var groups = await PermissionsService.GetUserPermissionGroups(user);
|
var groups = await PermissionsService.GetUserPermissionGroups(user);
|
||||||
_userGroups.Add(user.Id, groups.FirstOrDefault());
|
_userGroups.Add(user.Id, groups.LastOrDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OrderBy(_currentOrder, false);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +169,7 @@
|
|||||||
|
|
||||||
private void OrderBy(OrderType type, bool changeDir = true) {
|
private void OrderBy(OrderType type, bool changeDir = true) {
|
||||||
if (_currentOrder == type && changeDir) _currentOrderDirection = (OrderDirection)(((byte)_currentOrderDirection + 1) % 2);
|
if (_currentOrder == type && changeDir) _currentOrderDirection = (OrderDirection)(((byte)_currentOrderDirection + 1) % 2);
|
||||||
|
if (_currentOrder != type) _currentOrderDirection = OrderDirection.Asc;
|
||||||
|
|
||||||
if (type == OrderType.Email) {
|
if (type == OrderType.Email) {
|
||||||
_users = _currentOrderDirection == OrderDirection.Asc ? _users.OrderBy(user => user.Email).ToList() : _users.OrderByDescending(user => user.Email).ToList();
|
_users = _currentOrderDirection == OrderDirection.Asc ? _users.OrderBy(user => user.Email).ToList() : _users.OrderByDescending(user => user.Email).ToList();
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
@page "/login"
|
|
||||||
@using HopFrame.Security.Models
|
|
||||||
@using HopFrame.Web.Services
|
|
||||||
@using Microsoft.AspNetCore.Components.Forms
|
|
||||||
@using Microsoft.AspNetCore.Components.Routing
|
|
||||||
@using Microsoft.AspNetCore.Components.Web
|
|
||||||
|
|
||||||
<PageTitle>Login</PageTitle>
|
|
||||||
|
|
||||||
<div class="login-wrapper">
|
|
||||||
<EditForm Model="LoginData" FormName="login-form" OnSubmit="OnLogin">
|
|
||||||
@*<AntiforgeryToken />*@
|
|
||||||
<div class="field-wrapper">
|
|
||||||
<h2>Login</h2>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="email" class="form-label">Email address</label>
|
|
||||||
<InputText type="email" class="form-control" id="email" required @bind-Value="LoginData.Email"/>
|
|
||||||
@*<ValidationMessage For="() => RegisterData.Email"/>*@
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="password" class="form-label">Password</label>
|
|
||||||
<InputText type="password" class="form-control" id="password" aria-describedby="passwordHelp" required @bind-Value="LoginData.Password"/>
|
|
||||||
@*<ValidationMessage For="() => RegisterData.Password"/>*@
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<span>Don't have an account? <NavLink href="register">Register</NavLink></span>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary">Login</button>
|
|
||||||
|
|
||||||
@if (_loginError) {
|
|
||||||
<div class="alert alert-danger" role="alert" style="margin-top: 16px; margin-bottom: 0px">
|
|
||||||
Email or password does not match any account!
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</EditForm>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@inject IAuthService Auth
|
|
||||||
@inject NavigationManager Navigator
|
|
||||||
|
|
||||||
@code {
|
|
||||||
[SupplyParameterFromForm]
|
|
||||||
private UserLogin LoginData { get; set; }
|
|
||||||
|
|
||||||
[SupplyParameterFromQuery(Name = "redirect")]
|
|
||||||
private string RedirectAfter { get; set; }
|
|
||||||
|
|
||||||
private bool _loginError;
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync() {
|
|
||||||
LoginData ??= new();
|
|
||||||
|
|
||||||
if (await Auth.IsLoggedIn()) {
|
|
||||||
await Auth.Logout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task OnLogin() {
|
|
||||||
var result = await Auth.Login(LoginData);
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
_loginError = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Navigator.NavigateTo(string.IsNullOrEmpty(RedirectAfter) ? Register.RedirectAfterRegister : RedirectAfter, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
@page "/register"
|
|
||||||
@using HopFrame.Security.Services
|
|
||||||
@using HopFrame.Web.Model
|
|
||||||
@using HopFrame.Web.Services
|
|
||||||
@using Microsoft.AspNetCore.Components.Forms
|
|
||||||
@using Microsoft.AspNetCore.Components.Routing
|
|
||||||
@using Microsoft.AspNetCore.Components.Web
|
|
||||||
|
|
||||||
@implements IDisposable
|
|
||||||
|
|
||||||
<PageTitle>Register</PageTitle>
|
|
||||||
|
|
||||||
<div class="register-wrapper">
|
|
||||||
<EditForm EditContext="_context" OnValidSubmit="OnRegister" FormName="register-form">
|
|
||||||
@*<AntiforgeryToken />*@
|
|
||||||
<div class="field-wrapper">
|
|
||||||
<h2>Register</h2>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="email" class="form-label">Email address</label>
|
|
||||||
<InputText type="email" class="form-control" id="email" required @bind-Value="RegisterData.Email"/>
|
|
||||||
<ValidationMessage For="() => RegisterData.Email"/>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="username" class="form-label">Username</label>
|
|
||||||
<InputText type="text" class="form-control" id="username" required @bind-Value="RegisterData.Username"/>
|
|
||||||
<ValidationMessage For="() => RegisterData.Username"/>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="password" class="form-label">Password</label>
|
|
||||||
<InputText type="password" class="form-control" id="password" aria-describedby="passwordHelp" required @bind-Value="RegisterData.Password"/>
|
|
||||||
<div id="passwordHelp" class="form-text">The password needs to be at least 8 characters long</div>
|
|
||||||
<ValidationMessage For="() => RegisterData.Password"/>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="passwordRepeat" class="form-label">Repeat password</label>
|
|
||||||
<InputText type="password" class="form-control" id="passwordRepeat" aria-describedby="passwordHelp" required @bind-Value="RegisterData.RepeatedPassword"/>
|
|
||||||
<ValidationMessage For="() => RegisterData.RepeatedPassword"/>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<span>Already have an account? <NavLink href="login">Login</NavLink></span>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary">Register</button>
|
|
||||||
</div>
|
|
||||||
</EditForm>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@inject NavigationManager Navigator
|
|
||||||
@inject IUserService Users
|
|
||||||
@inject IAuthService Auth
|
|
||||||
|
|
||||||
@code {
|
|
||||||
public static string RedirectAfterRegister { get; set; } = "/";
|
|
||||||
|
|
||||||
[SupplyParameterFromForm]
|
|
||||||
private RegisterData RegisterData { get; set; }
|
|
||||||
|
|
||||||
private EditContext _context;
|
|
||||||
private ValidationMessageStore _messages;
|
|
||||||
|
|
||||||
protected override void OnInitialized() {
|
|
||||||
RegisterData ??= new();
|
|
||||||
|
|
||||||
_context = new EditContext(RegisterData);
|
|
||||||
_context.OnValidationRequested += ValidateForm;
|
|
||||||
_messages = new ValidationMessageStore(_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task OnRegister() {
|
|
||||||
var hasConflict = false;
|
|
||||||
|
|
||||||
if (await Users.GetUserByEmail(RegisterData.Email) is not null) {
|
|
||||||
_messages.Add(() => RegisterData.Email, "Email is already in use");
|
|
||||||
hasConflict = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await Users.GetUserByUsername(RegisterData.Username) is not null) {
|
|
||||||
_messages.Add(() => RegisterData.Username, "Username is already in use");
|
|
||||||
hasConflict = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasConflict) return;
|
|
||||||
|
|
||||||
await Auth.Register(RegisterData);
|
|
||||||
Navigator.NavigateTo(RedirectAfterRegister, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ValidateForm(object sender, ValidationRequestedEventArgs e) {
|
|
||||||
_messages.Clear();
|
|
||||||
|
|
||||||
if (!RegisterData.PasswordsMatch) {
|
|
||||||
_messages.Add(() => RegisterData.RepeatedPassword, "Passwords doesn't mach");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!RegisterData.PasswordIsValid) {
|
|
||||||
_messages.Add(() => RegisterData.Password, "Password needs to be at least 8 characters long");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!RegisterData.EmailIsValid) {
|
|
||||||
_messages.Add(() => RegisterData.Email, "Please enter a valid email address");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() {
|
|
||||||
_context.OnValidationRequested -= ValidateForm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
.register-wrapper {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-wrapper {
|
|
||||||
margin-top: 25vh;
|
|
||||||
min-width: 30vw;
|
|
||||||
|
|
||||||
padding: 30px;
|
|
||||||
border: 2px solid #ced4da;
|
|
||||||
border-radius: 10px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
2
HopFrame.Web/README.md
Normal file
2
HopFrame.Web/README.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# HopFrame Web module
|
||||||
|
This module contains useful helpers for Blazor Apps and an Admin Dashboard.
|
||||||
@@ -26,10 +26,10 @@ public static class ServiceCollectionExtensions {
|
|||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RazorComponentsEndpointConventionBuilder AddHopFramePages(this RazorComponentsEndpointConventionBuilder builder) {
|
public static RazorComponentsEndpointConventionBuilder AddHopFrameAdminPages(this RazorComponentsEndpointConventionBuilder builder) {
|
||||||
return builder
|
return builder
|
||||||
|
.DisableAntiforgery()
|
||||||
.AddAdditionalAssemblies(typeof(ServiceCollectionExtensions).Assembly)
|
.AddAdditionalAssemblies(typeof(ServiceCollectionExtensions).Assembly)
|
||||||
.AddInteractiveServerRenderMode()
|
.AddInteractiveServerRenderMode();
|
||||||
.DisableAntiforgery(); //TODO: Make Antiforgery work
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
|
|
||||||
namespace HopFrame.Web.Services.Implementation;
|
namespace HopFrame.Web.Services.Implementation;
|
||||||
|
|
||||||
public class AuthService<TDbContext>(
|
internal class AuthService<TDbContext>(
|
||||||
IUserService userService,
|
IUserService userService,
|
||||||
IHttpContextAccessor httpAccessor,
|
IHttpContextAccessor httpAccessor,
|
||||||
TDbContext context)
|
TDbContext context)
|
||||||
|
|||||||
Reference in New Issue
Block a user