wip
This commit is contained in:
parent
f4e03be1fa
commit
d4eb8f94a8
25 changed files with 431 additions and 86 deletions
|
@ -20,12 +20,6 @@
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">
|
|
||||||
Land
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
Nr.
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
Navn
|
Navn
|
||||||
</th>
|
</th>
|
||||||
|
@ -35,6 +29,12 @@
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
Email
|
Email
|
||||||
</th>
|
</th>
|
||||||
|
<th scope="col">
|
||||||
|
Land
|
||||||
|
</th>
|
||||||
|
<th scope="col">
|
||||||
|
Nr.
|
||||||
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
|
|
||||||
</th>
|
</th>
|
||||||
|
@ -47,12 +47,13 @@
|
||||||
@foreach (var user in UserList)
|
@foreach (var user in UserList)
|
||||||
{
|
{
|
||||||
<tr class="align-middle">
|
<tr class="align-middle">
|
||||||
<td class="align-content-center">@user.CountryCode</td>
|
<td>@user.FullName</td>
|
||||||
<td>@user.SalesRep</td>
|
|
||||||
<td><a href="/admin/users/advisers/@user.CountryCode.ToLower()/@user.UserId/view">@user.FullName</a></td>
|
|
||||||
<td>@user.PhoneNumber</td>
|
<td>@user.PhoneNumber</td>
|
||||||
<td>@user.Email</td>
|
<td>@user.Email</td>
|
||||||
<td><a class="btn btn-info" href="/admin/users/advisers/@user.CountryCode.ToLower()/@user.UserId/reports">Salg</a></td>
|
<td class="align-content-center">@user.CountryCode</td>
|
||||||
|
<td>@user.SalesRep</td>
|
||||||
|
<td><a class="btn btn-primary" href="/admin/users/advisers/@user.CountryCode.ToLower()/@user.UserId/reports">Rapporter</a></td>
|
||||||
|
<td><a class="btn btn-info" href="/admin/users/advisers/@user.CountryCode.ToLower()/@user.UserId/view">Rediger</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -6,5 +6,5 @@ namespace Wonky.Client.Components;
|
||||||
|
|
||||||
public partial class AdminAdviserTableComponent
|
public partial class AdminAdviserTableComponent
|
||||||
{
|
{
|
||||||
[Parameter] public List<AdminAdviserListView> UserList { get; set; }
|
[Parameter] public List<UserListAdminView> UserList { get; set; }
|
||||||
}
|
}
|
53
Wonky.Client/Components/AdminUserTableComponent.razor
Normal file
53
Wonky.Client/Components/AdminUserTableComponent.razor
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
@*
|
||||||
|
// Copyright (C) 2022 FCS Frede's Computer Services.
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
|
||||||
|
//
|
||||||
|
*@
|
||||||
|
|
||||||
|
@if (UserList.Any())
|
||||||
|
{
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">
|
||||||
|
Land
|
||||||
|
</th>
|
||||||
|
<th scope="col">
|
||||||
|
Navn
|
||||||
|
</th>
|
||||||
|
<th scope="col">
|
||||||
|
Telefon
|
||||||
|
</th>
|
||||||
|
<th scope="col">
|
||||||
|
Email
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var user in UserList)
|
||||||
|
{
|
||||||
|
<tr class="align-middle">
|
||||||
|
<td class="align-content-center">@user.CountryCode</td>
|
||||||
|
<td><a href="/admin/users/office/@user.CountryCode.ToLower()/@user.UserId/view">@user.FullName</a></td>
|
||||||
|
<td>@user.PhoneNumber</td>
|
||||||
|
<td>@user.Email</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<AppSpinner/>
|
||||||
|
}
|
10
Wonky.Client/Components/AdminUserTableComponent.razor.cs
Normal file
10
Wonky.Client/Components/AdminUserTableComponent.razor.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Wonky.Entity.DTO;
|
||||||
|
using Wonky.Entity.Views;
|
||||||
|
|
||||||
|
namespace Wonky.Client.Components;
|
||||||
|
|
||||||
|
public partial class AdminUserTableComponent
|
||||||
|
{
|
||||||
|
[Parameter] public List<UserListAdminView> UserList { get; set; }
|
||||||
|
}
|
|
@ -18,15 +18,23 @@
|
||||||
@using Microsoft.AspNetCore.Authorization
|
@using Microsoft.AspNetCore.Authorization
|
||||||
<PageTitle>Inno Web CRM</PageTitle>
|
<PageTitle>Inno Web CRM</PageTitle>
|
||||||
|
|
||||||
<div class="card">
|
<AuthorizeView Roles="Adviser">
|
||||||
<div class="card-header">
|
<div class="card">
|
||||||
<div class="row">
|
<div class="card-header">
|
||||||
<div class="col">
|
<div class="row">
|
||||||
<h2 class="workDate">@(DateTime.Parse(_workDate).ToLongDateString())</h2>
|
<div class="col">
|
||||||
</div>
|
<h2 class="workDate">@(DateTime.Parse(_workDate).ToLongDateString())</h2>
|
||||||
<div class="col">
|
</div>
|
||||||
<WorkDateComponent OnChanged="GetCalender"></WorkDateComponent>
|
<div class="col">
|
||||||
|
<WorkDateComponent OnChanged="GetCalender"></WorkDateComponent>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</AuthorizeView>
|
||||||
|
<AuthorizeView Roles="Admin">
|
||||||
|
<h2>Administrator</h2>
|
||||||
|
</AuthorizeView>
|
||||||
|
<AuthorizeView Roles="Supervisor">
|
||||||
|
<h2>Supervisor</h2>
|
||||||
|
</AuthorizeView>
|
||||||
|
|
|
@ -4,8 +4,11 @@ namespace Wonky.Client.HttpRepository;
|
||||||
|
|
||||||
public interface IUserHttpRepository
|
public interface IUserHttpRepository
|
||||||
{
|
{
|
||||||
Task<List<AdminAdviserListView>> GetAdvisers();
|
Task<List<UserListAdminView>> GetAdvisers();
|
||||||
Task<AdviserInfoView> GetAdviserInfo(string userId);
|
Task<UserInfoAdminView> GetAdviserInfo(string userId);
|
||||||
Task UpdateAdviser(string userId, AdviserUpdateDto model);
|
Task UpdateAdviser(string userId, UserUpdateDto model);
|
||||||
|
Task<List<UserListAdminView>> GetAdminUsers();
|
||||||
|
Task<UserInfoAdminView> GetAdminUserInfo(string userId);
|
||||||
|
Task UpdateAdminUser(string userId, UserUpdateDto model);
|
||||||
Task ResetUserPassword(string userId, string newPasswd, string confirmPasswd);
|
Task ResetUserPassword(string userId, string newPasswd, string confirmPasswd);
|
||||||
}
|
}
|
|
@ -31,29 +31,36 @@ public class UserHttpRepository : IUserHttpRepository
|
||||||
_api = configuration.Value;
|
_api = configuration.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<AdminAdviserListView>> GetAdvisers()
|
public async Task<List<UserListAdminView>> GetAdvisers()
|
||||||
{
|
{
|
||||||
return await _client.GetFromJsonAsync<List<AdminAdviserListView>>(_api.AdminAdviserUri);
|
return await _client.GetFromJsonAsync<List<UserListAdminView>>(_api.AdminAdviserUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<AdviserInfoView> GetAdviserInfo(string userId)
|
public async Task<UserInfoAdminView> GetAdviserInfo(string userId)
|
||||||
{
|
{
|
||||||
return await _client.GetFromJsonAsync<AdviserInfoView>($"{_api.AdminAdviserUri}/{userId}");
|
return await _client.GetFromJsonAsync<UserInfoAdminView>($"{_api.AdminAdviserUri}/{userId}");
|
||||||
// var response = await _client.GetAsync($"{_api.AdminAdviserUri}/{userId}");
|
|
||||||
// var content = await response.Content.ReadAsStringAsync();
|
|
||||||
// _logger.LogInformation($"GetAdviserInfo => {content}", content);
|
|
||||||
// return new AdviserInfoView();
|
|
||||||
// if (!response.IsSuccessStatusCode)
|
|
||||||
// return new AdviserInfoView();
|
|
||||||
// var result = JsonSerializer.Deserialize<ApiResponse>(content);
|
|
||||||
// return JsonSerializer.Deserialize<AdviserInfoView>(result.Message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateAdviser(string userId, AdviserUpdateDto model)
|
public async Task UpdateAdviser(string userId, UserUpdateDto model)
|
||||||
{
|
{
|
||||||
await _client.PutAsJsonAsync($"{_api.AdminAdviserUri}/{userId}", model, _options);
|
await _client.PutAsJsonAsync($"{_api.AdminAdviserUri}/{userId}", model, _options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<UserListAdminView>> GetAdminUsers()
|
||||||
|
{
|
||||||
|
return await _client.GetFromJsonAsync<List<UserListAdminView>>(_api.AdminUserUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<UserInfoAdminView> GetAdminUserInfo(string userId)
|
||||||
|
{
|
||||||
|
return await _client.GetFromJsonAsync<UserInfoAdminView>($"{_api.AdminUserUri}/{userId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateAdminUser(string userId, UserUpdateDto model)
|
||||||
|
{
|
||||||
|
await _client.PutAsJsonAsync($"{_api.AdminUserUri}/{userId}", model, _options);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task ResetUserPassword(string userId, string newPasswd, string confirmPasswd)
|
public async Task ResetUserPassword(string userId, string newPasswd, string confirmPasswd)
|
||||||
{
|
{
|
||||||
var passwd = new Dictionary<string, string> {{"newPassword", newPasswd}, {"confirmPassword", confirmPasswd}};
|
var passwd = new Dictionary<string, string> {{"newPassword", newPasswd}, {"confirmPassword", confirmPasswd}};
|
||||||
|
|
11
Wonky.Client/Pages/AdminAdviserLandingPage.razor
Normal file
11
Wonky.Client/Pages/AdminAdviserLandingPage.razor
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
@page "/admin/users/advisers"
|
||||||
|
|
||||||
|
<div class="list-group">
|
||||||
|
<a class="list-group-item list-group-item-action" href="/admin/users/advisers/dk">Danmark</a>
|
||||||
|
<a class="list-group-item list-group-item-action" href="/admin/users/advisers/no">Norge</a>
|
||||||
|
<a class="list-group-item list-group-item-action" href="/admin/users/advisers/se">Sverige</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ public partial class AdminAdviserUserList : IDisposable
|
||||||
[Parameter] public string CountryCode { get; set; } = "";
|
[Parameter] public string CountryCode { get; set; } = "";
|
||||||
[Inject] private HttpInterceptorService _interceptor { get; set; }
|
[Inject] private HttpInterceptorService _interceptor { get; set; }
|
||||||
[Inject] private IUserHttpRepository _userRepo { get; set; }
|
[Inject] private IUserHttpRepository _userRepo { get; set; }
|
||||||
private List<AdminAdviserListView> _salesReps { get; set; } = new();
|
private List<UserListAdminView> _salesReps { get; set; } = new();
|
||||||
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<h3>Sælger info</h3>
|
<h3>Sælger info</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@if (_adviserInfo != null)
|
@if (UserInfoAdmin != null)
|
||||||
{
|
{
|
||||||
<EditForm EditContext="_editContext" OnValidSubmit="UpdateAdviser">
|
<EditForm EditContext="_editContext" OnValidSubmit="UpdateAdviser">
|
||||||
<DataAnnotationsValidator/>
|
<DataAnnotationsValidator/>
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
Sælgernr.
|
Sælgernr.
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
@_adviserInfo.Adviser
|
@UserInfoAdmin.Adviser
|
||||||
</td>
|
</td>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
Landekode
|
Landekode
|
||||||
|
|
|
@ -18,9 +18,9 @@ public partial class AdminAdviserView : IDisposable
|
||||||
[Inject] private ILogger<AdminAdviserView> _logger { get; set; }
|
[Inject] private ILogger<AdminAdviserView> _logger { get; set; }
|
||||||
[Inject] private NavigationManager _navigator { get; set; }
|
[Inject] private NavigationManager _navigator { get; set; }
|
||||||
[Inject] private IToastService _toast { get; set; }
|
[Inject] private IToastService _toast { get; set; }
|
||||||
private AdviserInfoView _adviserInfo { get; set; } = new();
|
private UserInfoAdminView UserInfoAdmin { get; set; } = new();
|
||||||
private EditContext _editContext { get; set; }
|
private EditContext _editContext { get; set; }
|
||||||
private AdviserUpdateDto _updateInfo { get; set; } = new();
|
private UserUpdateDto _updateInfo { get; set; } = new();
|
||||||
private AdminResetPasswordDto _passwords { get; set; } = new();
|
private AdminResetPasswordDto _passwords { get; set; } = new();
|
||||||
private EditContext _passwdContext { get; set; }
|
private EditContext _passwdContext { get; set; }
|
||||||
private bool _pwInvalid = true;
|
private bool _pwInvalid = true;
|
||||||
|
@ -38,14 +38,14 @@ public partial class AdminAdviserView : IDisposable
|
||||||
_interceptor.RegisterEvent();
|
_interceptor.RegisterEvent();
|
||||||
_interceptor.RegisterBeforeSendEvent();
|
_interceptor.RegisterBeforeSendEvent();
|
||||||
|
|
||||||
_adviserInfo = await _userRepo.GetAdviserInfo(UserId);
|
UserInfoAdmin = await _userRepo.GetAdviserInfo(UserId);
|
||||||
|
|
||||||
_updateInfo.Email = _adviserInfo.Email;
|
_updateInfo.Email = UserInfoAdmin.Email;
|
||||||
_updateInfo.CountryCode = _adviserInfo.CountryCode;
|
_updateInfo.CountryCode = UserInfoAdmin.CountryCode;
|
||||||
_updateInfo.FirstName = _adviserInfo.FirstName;
|
_updateInfo.FirstName = UserInfoAdmin.FirstName;
|
||||||
_updateInfo.LastName = _adviserInfo.LastName;
|
_updateInfo.LastName = UserInfoAdmin.LastName;
|
||||||
_updateInfo.PhoneNumber = _adviserInfo.PhoneNumber;
|
_updateInfo.PhoneNumber = UserInfoAdmin.PhoneNumber;
|
||||||
_updateInfo.LockoutEnabled = _adviserInfo.LockoutEnabled;
|
_updateInfo.LockoutEnabled = UserInfoAdmin.LockoutEnabled;
|
||||||
|
|
||||||
_passwdContext.OnFieldChanged += PwHandleFieldChanged;
|
_passwdContext.OnFieldChanged += PwHandleFieldChanged;
|
||||||
_passwdContext.OnValidationStateChanged += PwValidationChanged;
|
_passwdContext.OnValidationStateChanged += PwValidationChanged;
|
||||||
|
|
9
Wonky.Client/Pages/AdminOfficeLandingPage.razor
Normal file
9
Wonky.Client/Pages/AdminOfficeLandingPage.razor
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
@page "/admin/users/office"
|
||||||
|
|
||||||
|
<div class="list-group">
|
||||||
|
<a class="list-group-item list-group-item-action" href="/admin/users/office/dk">Danmark</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
}
|
13
Wonky.Client/Pages/AdminOfficeList.razor
Normal file
13
Wonky.Client/Pages/AdminOfficeList.razor
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
@using Wonky.Client.Components
|
||||||
|
@using Microsoft.AspNetCore.Authorization
|
||||||
|
@attribute [Authorize(Roles = "Admin")]
|
||||||
|
@page "/admin/users/office/{CountryCode}"
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3>Admins</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<AdminUserTableComponent UserList="_adminUsers"></AdminUserTableComponent>
|
||||||
|
</div>
|
||||||
|
</div>
|
30
Wonky.Client/Pages/AdminOfficeList.razor.cs
Normal file
30
Wonky.Client/Pages/AdminOfficeList.razor.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Wonky.Client.HttpInterceptors;
|
||||||
|
using Wonky.Client.HttpRepository;
|
||||||
|
using Wonky.Entity.DTO;
|
||||||
|
|
||||||
|
namespace Wonky.Client.Pages;
|
||||||
|
|
||||||
|
public partial class AdminOfficeList : IDisposable
|
||||||
|
{
|
||||||
|
[Parameter] public string CountryCode { get; set; } = "";
|
||||||
|
[Inject] private HttpInterceptorService _interceptor { get; set; }
|
||||||
|
[Inject] private IUserHttpRepository _userRepo { get; set; }
|
||||||
|
private List<UserListAdminView> _adminUsers { get; set; } = new();
|
||||||
|
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
_interceptor.RegisterEvent();
|
||||||
|
_interceptor.RegisterBeforeSendEvent();
|
||||||
|
var adviserList = await _userRepo.GetAdminUsers();
|
||||||
|
_adminUsers = adviserList
|
||||||
|
.Where(x => x.CountryCode.ToLower() == CountryCode)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_interceptor.DisposeEvent();
|
||||||
|
}
|
||||||
|
}
|
115
Wonky.Client/Pages/AdminOfficeView.razor
Normal file
115
Wonky.Client/Pages/AdminOfficeView.razor
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
@page "/admin/users/office/{CountryCode}/{UserId}/view"
|
||||||
|
@using Microsoft.AspNetCore.Authorization
|
||||||
|
@attribute [Authorize(Roles = "Admin")]
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3>Sælger info</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
@if (UserInfoAdmin != null)
|
||||||
|
{
|
||||||
|
<EditForm EditContext="_editContext" OnValidSubmit="UpdateUser">
|
||||||
|
<DataAnnotationsValidator/>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<table class="table">
|
||||||
|
<tbody>
|
||||||
|
<tr class="align-middle">
|
||||||
|
<th scope="col">
|
||||||
|
Fornavn
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<InputText id="firstName" class="form-control" @bind-Value="_updateInfo.FirstName"/>
|
||||||
|
<ValidationMessage For="@(() => _updateInfo.FirstName)"></ValidationMessage>
|
||||||
|
</td>
|
||||||
|
<th scope="col">
|
||||||
|
Efternavn
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<InputText id="lastName" class="form-control" @bind-Value="_updateInfo.LastName"/>
|
||||||
|
<ValidationMessage For="@(() => _updateInfo.LastName)"></ValidationMessage>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="align-middle">
|
||||||
|
<th scope="col">
|
||||||
|
Email
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<InputText id="email" class="form-control" @bind-Value="_updateInfo.Email"/>
|
||||||
|
<ValidationMessage For="@(() => _updateInfo.Email)"></ValidationMessage>
|
||||||
|
</td>
|
||||||
|
<th scope="col">
|
||||||
|
Mobilnummer
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<InputText id="phoneNumber" class="form-control" @bind-Value="_updateInfo.PhoneNumber"/>
|
||||||
|
<ValidationMessage For="@(() => _updateInfo.PhoneNumber)"></ValidationMessage>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="align-middle">
|
||||||
|
<th scope="col">
|
||||||
|
Sælgernr.
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
@UserInfoAdmin.Adviser
|
||||||
|
</td>
|
||||||
|
<th scope="col">
|
||||||
|
Landekode
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
@_updateInfo.CountryCode
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="align-middle">
|
||||||
|
<th scope="col">
|
||||||
|
Spærret
|
||||||
|
</th>
|
||||||
|
<td colspan="3">
|
||||||
|
<InputCheckbox id="lockoutEnabled" class="form-check" @bind-Value="_updateInfo.LockoutEnabled"/>
|
||||||
|
<ValidationMessage For="@(() => _updateInfo.LockoutEnabled)"></ValidationMessage>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<button type="submit" class="btn btn-primary">Gem</button>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<a class="btn btn-primary" href="/admin/users/office/@CountryCode">Tilbage</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</EditForm>
|
||||||
|
<EditForm EditContext="_passwdContext" class="mt-5" >
|
||||||
|
<DataAnnotationsValidator />
|
||||||
|
<h3>NULSTIL ADGANGSKODE</h3>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="newPasswd" class="col-md-2 col-form-label">Ny</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<InputText id="newPasswd" type="password" class="form-control" @bind-Value="@_passwords.NewPassword"/>
|
||||||
|
<ValidationMessage For="@(() => _passwords.NewPassword)"></ValidationMessage>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="verifyPasswd" class="col-md-2 col-form-label">Bekræft</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<InputText id="verifyPasswd" type="password" class="form-control" @bind-Value="@_passwords.ConfirmPassword"/>
|
||||||
|
<ValidationMessage For="@(() => _passwords.ConfirmPassword)"></ValidationMessage>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col align-content-end">
|
||||||
|
<button class="btn btn-warning" @onclick="SetPassword" disabled="@_pwInvalid">NULSTIL</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</EditForm>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<AppSpinner/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
93
Wonky.Client/Pages/AdminOfficeView.razor.cs
Normal file
93
Wonky.Client/Pages/AdminOfficeView.razor.cs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
using System.Security.Policy;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Blazored.Toast.Services;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
|
using Wonky.Client.HttpInterceptors;
|
||||||
|
using Wonky.Client.HttpRepository;
|
||||||
|
using Wonky.Entity.DTO;
|
||||||
|
|
||||||
|
namespace Wonky.Client.Pages;
|
||||||
|
|
||||||
|
public partial class AdminOfficeView : IDisposable
|
||||||
|
{
|
||||||
|
[Parameter] public string UserId { get; set; } = "";
|
||||||
|
[Parameter] public string CountryCode { get; set; } = "";
|
||||||
|
[Inject] private HttpInterceptorService _interceptor { get; set; }
|
||||||
|
[Inject] private IUserHttpRepository _userRepo { get; set; }
|
||||||
|
[Inject] private ILogger<AdminAdviserView> _logger { get; set; }
|
||||||
|
[Inject] private NavigationManager _navigator { get; set; }
|
||||||
|
[Inject] private IToastService _toast { get; set; }
|
||||||
|
private UserInfoAdminView UserInfoAdmin { get; set; } = new();
|
||||||
|
private EditContext _editContext { get; set; }
|
||||||
|
private UserUpdateDto _updateInfo { get; set; } = new();
|
||||||
|
private AdminResetPasswordDto _passwords { get; set; } = new();
|
||||||
|
private EditContext _passwdContext { get; set; }
|
||||||
|
private bool _pwInvalid = true;
|
||||||
|
|
||||||
|
private readonly JsonSerializerOptions? _options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync()
|
||||||
|
{
|
||||||
|
_editContext = new EditContext(_updateInfo);
|
||||||
|
_passwdContext = new EditContext(_passwords);
|
||||||
|
|
||||||
|
_interceptor.RegisterEvent();
|
||||||
|
_interceptor.RegisterBeforeSendEvent();
|
||||||
|
|
||||||
|
UserInfoAdmin = await _userRepo.GetAdminUserInfo(UserId);
|
||||||
|
|
||||||
|
_updateInfo.Email = UserInfoAdmin.Email;
|
||||||
|
_updateInfo.CountryCode = UserInfoAdmin.CountryCode;
|
||||||
|
_updateInfo.FirstName = UserInfoAdmin.FirstName;
|
||||||
|
_updateInfo.LastName = UserInfoAdmin.LastName;
|
||||||
|
_updateInfo.PhoneNumber = UserInfoAdmin.PhoneNumber;
|
||||||
|
_updateInfo.LockoutEnabled = UserInfoAdmin.LockoutEnabled;
|
||||||
|
|
||||||
|
_passwdContext.OnFieldChanged += PwHandleFieldChanged;
|
||||||
|
_passwdContext.OnValidationStateChanged += PwValidationChanged;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateUser()
|
||||||
|
{
|
||||||
|
_toast.ShowInfo("Sender data til server ...");
|
||||||
|
await _userRepo.UpdateAdminUser(UserId, _updateInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PwHandleFieldChanged(object sender, FieldChangedEventArgs e)
|
||||||
|
{
|
||||||
|
_pwInvalid = !_passwdContext.Validate();
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
private void PwValidationChanged(object sender, ValidationStateChangedEventArgs e)
|
||||||
|
{
|
||||||
|
_pwInvalid = true;
|
||||||
|
|
||||||
|
_passwdContext.OnFieldChanged -= PwHandleFieldChanged;
|
||||||
|
_passwdContext.OnValidationStateChanged -= PwValidationChanged;
|
||||||
|
|
||||||
|
_passwdContext = new EditContext(_passwords);
|
||||||
|
|
||||||
|
_passwdContext.OnFieldChanged += PwHandleFieldChanged;
|
||||||
|
_passwdContext.OnValidationStateChanged += PwValidationChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SetPassword()
|
||||||
|
{
|
||||||
|
await _userRepo.ResetUserPassword(UserId, _passwords.NewPassword, _passwords.ConfirmPassword);
|
||||||
|
_toast.ShowInfo("Password er nulstillet.");
|
||||||
|
_passwords.NewPassword = "";
|
||||||
|
_passwords.ConfirmPassword = "";
|
||||||
|
}
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_interceptor.DisposeEvent();
|
||||||
|
_passwdContext.OnFieldChanged -= PwHandleFieldChanged;
|
||||||
|
_passwdContext.OnValidationStateChanged -= PwValidationChanged;
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,18 +23,7 @@
|
||||||
|
|
||||||
@attribute [Authorize(Roles = "Adviser,Admin,Supervisor")]
|
@attribute [Authorize(Roles = "Adviser,Admin,Supervisor")]
|
||||||
|
|
||||||
<AuthorizeView Roles="Adviser">
|
<Home></Home>
|
||||||
<Home></Home>
|
|
||||||
</AuthorizeView>
|
|
||||||
<AuthorizeView Roles="Admin">
|
|
||||||
<div class="list-group">
|
|
||||||
<a class="list-group-item list-group-item-action" href="/admin/users/advisers/dk">Danmark</a>
|
|
||||||
<a class="list-group-item list-group-item-action" href="/admin/users/advisers/no">Norge</a>
|
|
||||||
<a class="list-group-item list-group-item-action" href="/admin/users/advisers/se">Sverige</a>
|
|
||||||
</div>
|
|
||||||
</AuthorizeView>
|
|
||||||
|
|
||||||
@code{
|
@code{
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,6 @@ namespace Wonky.Client.Services
|
||||||
|
|
||||||
var resContent = await response.Content.ReadAsStringAsync();
|
var resContent = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
// if not success - return error status
|
|
||||||
if (!response.IsSuccessStatusCode)
|
if (!response.IsSuccessStatusCode)
|
||||||
return new AuthResponseView
|
return new AuthResponseView
|
||||||
{
|
{
|
||||||
|
@ -71,10 +70,11 @@ namespace Wonky.Client.Services
|
||||||
await _localStorage.SetItemAsync("_xr", data.RefreshToken);
|
await _localStorage.SetItemAsync("_xr", data.RefreshToken);
|
||||||
await _localStorage.SetItemAsync("_xe", (int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds + data.ExpiresIn - 60);
|
await _localStorage.SetItemAsync("_xe", (int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds + data.ExpiresIn - 60);
|
||||||
|
|
||||||
// set default request headers using access_token
|
|
||||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", data.AccessToken);
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", data.AccessToken);
|
||||||
|
|
||||||
var userInfo = await UserInfo();
|
var userInfo = await UserInfo();
|
||||||
await _localStorage.SetItemAsync("_xu", userInfo);
|
await _localStorage.SetItemAsync("_xu", userInfo);
|
||||||
|
|
||||||
// notify system on state change
|
// notify system on state change
|
||||||
((AuthStateProvider)_authStateProvider).NotifyUserAuthenticationAsync(data.AccessToken);
|
((AuthStateProvider)_authStateProvider).NotifyUserAuthenticationAsync(data.AccessToken);
|
||||||
data.IsSuccess = true;
|
data.IsSuccess = true;
|
||||||
|
@ -90,9 +90,15 @@ namespace Wonky.Client.Services
|
||||||
["refresh_token"] = refreshToken
|
["refresh_token"] = refreshToken
|
||||||
};
|
};
|
||||||
var response = await _client.PostAsync(_apiConfig.Value.TokenUri, new FormUrlEncodedContent(credentials));
|
var response = await _client.PostAsync(_apiConfig.Value.TokenUri, new FormUrlEncodedContent(credentials));
|
||||||
if (!response.IsSuccessStatusCode) return string.Empty;
|
if (!response.IsSuccessStatusCode)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
var resContent = await response.Content.ReadAsStringAsync();
|
var resContent = await response.Content.ReadAsStringAsync();
|
||||||
var data = JsonSerializer.Deserialize<AuthResponseView>(resContent, _options);
|
var data = JsonSerializer.Deserialize<AuthResponseView>(resContent, _options);
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(data.AccessToken))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
// set default request headers using access_token
|
// set default request headers using access_token
|
||||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", data.AccessToken);
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", data.AccessToken);
|
||||||
await _localStorage.SetItemAsync("_xa", data.AccessToken);
|
await _localStorage.SetItemAsync("_xa", data.AccessToken);
|
||||||
|
|
|
@ -36,17 +36,14 @@ namespace Wonky.Client.Shared
|
||||||
|
|
||||||
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||||
{
|
{
|
||||||
// fetch token from localStorage
|
|
||||||
var token = await _storage.GetItemAsync<string>("_xa");
|
var token = await _storage.GetItemAsync<string>("_xa");
|
||||||
if (string.IsNullOrEmpty(token))
|
if (string.IsNullOrEmpty(token))
|
||||||
// return anonymous if empty
|
|
||||||
return _anonymous;
|
return _anonymous;
|
||||||
// create an authorized user
|
|
||||||
var userInfo = await _storage.GetItemAsync<UserInfoView>("_xu");
|
var userInfo = await _storage.GetItemAsync<UserInfoView>("_xu");
|
||||||
if (userInfo == null)
|
if (userInfo == null)
|
||||||
return _anonymous;
|
return _anonymous;
|
||||||
|
|
||||||
// set client authorization header
|
|
||||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
|
||||||
var exp = await _storage.GetItemAsync<string>("_xe");
|
var exp = await _storage.GetItemAsync<string>("_xe");
|
||||||
var roles = ExtractRoles(userInfo);
|
var roles = ExtractRoles(userInfo);
|
||||||
|
@ -69,18 +66,12 @@ namespace Wonky.Client.Shared
|
||||||
public async void NotifyUserAuthenticationAsync(string token)
|
public async void NotifyUserAuthenticationAsync(string token)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(token))
|
if (string.IsNullOrEmpty(token))
|
||||||
// do nothing
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// set client authorization header
|
|
||||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
|
||||||
|
|
||||||
// create an authorized user
|
var userInfo = await _storage.GetItemAsync<UserInfoView>("_xu");
|
||||||
var userInfo = await _storage.GetItemAsync<UserInfoView>("_xu")
|
var exp = await _storage.GetItemAsync<string>("_xe");
|
||||||
;
|
|
||||||
|
|
||||||
var exp = await _storage.GetItemAsync<string>("_xe")
|
|
||||||
;
|
|
||||||
|
|
||||||
var roles = ExtractRoles(userInfo);
|
var roles = ExtractRoles(userInfo);
|
||||||
var claims = new List<Claim>
|
var claims = new List<Claim>
|
||||||
|
@ -91,13 +82,12 @@ namespace Wonky.Client.Shared
|
||||||
new(ClaimTypes.Expiration, exp)
|
new(ClaimTypes.Expiration, exp)
|
||||||
};
|
};
|
||||||
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
|
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
|
||||||
// create authState
|
|
||||||
var authState = Task.FromResult(
|
var authState = Task.FromResult(
|
||||||
new AuthenticationState(
|
new AuthenticationState(
|
||||||
new ClaimsPrincipal(
|
new ClaimsPrincipal(
|
||||||
new ClaimsIdentity(claims, "token"))));
|
new ClaimsIdentity(claims, "token"))));
|
||||||
|
|
||||||
// send authState to notifier
|
|
||||||
NotifyAuthenticationStateChanged(authState);
|
NotifyAuthenticationStateChanged(authState);
|
||||||
}
|
}
|
||||||
public void NotifyUserLogout()
|
public void NotifyUserLogout()
|
||||||
|
|
|
@ -42,10 +42,15 @@
|
||||||
</AuthorizeView>
|
</AuthorizeView>
|
||||||
<AuthorizeView Roles="Admin">
|
<AuthorizeView Roles="Admin">
|
||||||
<div class="nav-item px-3">
|
<div class="nav-item px-3">
|
||||||
<NavLink class="nav-link ps-2" href="/">
|
<NavLink class="nav-link ps-2" href="/admin/users/advisers">
|
||||||
<span class="oi oi-people" aria-hidden="true"></span> Sælgere
|
<span class="oi oi-people" aria-hidden="true"></span> Sælgere
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="nav-item px-3">
|
||||||
|
<NavLink class="nav-link ps-2" href="/admin/users/office">
|
||||||
|
<span class="oi oi-people" aria-hidden="true"></span> Admins
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
</AuthorizeView>
|
</AuthorizeView>
|
||||||
<AuthorizeView Roles="Adviser">
|
<AuthorizeView Roles="Adviser">
|
||||||
<Authorized>
|
<Authorized>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"appInfo": {
|
"appInfo": {
|
||||||
"name": "Wonky Client",
|
"name": "Wonky Client",
|
||||||
"version": "0.8.44",
|
"version": "0.8.51",
|
||||||
"isBeta": true,
|
"isBeta": true,
|
||||||
"image": "grumpy-coder.png"
|
"image": "grumpy-coder.png"
|
||||||
},
|
},
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
"productUri": "history/products",
|
"productUri": "history/products",
|
||||||
"syncUri": "history/sync",
|
"syncUri": "history/sync",
|
||||||
"adminAdviserUri": "api/v2/admin/users/advisers",
|
"adminAdviserUri": "api/v2/admin/users/advisers",
|
||||||
|
"adminUserUri": "api/v2/admin/users/office",
|
||||||
"adminPasswdUri": "api/v2/admin/users/passwd",
|
"adminPasswdUri": "api/v2/admin/users/passwd",
|
||||||
"adminReportUri": "reports",
|
"adminReportUri": "reports",
|
||||||
"adminCompanyUri": "companies"
|
"adminCompanyUri": "companies"
|
||||||
|
|
|
@ -35,6 +35,7 @@ public class ApiConfig
|
||||||
public string ProductUri { get; set; } = "";
|
public string ProductUri { get; set; } = "";
|
||||||
public string SyncUri { get; set; } = "";
|
public string SyncUri { get; set; } = "";
|
||||||
public string AdminAdviserUri { get; set; } = "";
|
public string AdminAdviserUri { get; set; } = "";
|
||||||
|
public string AdminUserUri { get; set; } = "";
|
||||||
public string AdminPasswdUri { get; set; } = "";
|
public string AdminPasswdUri { get; set; } = "";
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Wonky.Entity.DTO;
|
namespace Wonky.Entity.DTO;
|
||||||
|
|
||||||
public class AdviserInfoView
|
public class UserInfoAdminView
|
||||||
{
|
{
|
||||||
[Required(ErrorMessage = "Fornavn skal angives.")]
|
[Required(ErrorMessage = "Fornavn skal angives.")]
|
||||||
[MaxLength(50,ErrorMessage = "Der kan højst bruges 50 tegn.")]
|
[MaxLength(50,ErrorMessage = "Der kan højst bruges 50 tegn.")]
|
|
@ -1,6 +1,6 @@
|
||||||
namespace Wonky.Entity.DTO;
|
namespace Wonky.Entity.DTO;
|
||||||
|
|
||||||
public class AdminAdviserListView
|
public class UserListAdminView
|
||||||
{
|
{
|
||||||
public string UserId { get; set; } = "";
|
public string UserId { get; set; } = "";
|
||||||
public string SalesRep { get; set; } = "";
|
public string SalesRep { get; set; } = "";
|
|
@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Wonky.Entity.DTO;
|
namespace Wonky.Entity.DTO;
|
||||||
|
|
||||||
public class AdviserUpdateDto
|
public class UserUpdateDto
|
||||||
{
|
{
|
||||||
[Required(ErrorMessage = "Fornavn skal angives.")]
|
[Required(ErrorMessage = "Fornavn skal angives.")]
|
||||||
[MaxLength(50,ErrorMessage = "Der kan højst bruges 50 tegn.")]
|
[MaxLength(50,ErrorMessage = "Der kan højst bruges 50 tegn.")]
|
Loading…
Reference in a new issue