Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Role based access on admin panel #930

Merged
merged 3 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
namespace Alvtime.Adminpanel.Client.Authorization;

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
using System.Security.Claims;
using System.Text.Json;

//https://auth0.com/blog/role-based-access-control-in-blazor-apps/
public class CustomAccountFactory(IAccessTokenProviderAccessor accessor) : AccountClaimsPrincipalFactory<RemoteUserAccount>(accessor)
{
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account,
RemoteAuthenticationUserOptions options)
{
var userAccount = await base.CreateUserAsync(account, options);
var userIdentity = userAccount.Identity as ClaimsIdentity;

if (userIdentity?.IsAuthenticated is not true) return userAccount;

if (account.AdditionalProperties.TryGetValue(userIdentity.RoleClaimType, out var rolesObj) && rolesObj is JsonElement roles && roles.ValueKind == JsonValueKind.Array)
{
var roleClaim = userIdentity.Claims.FirstOrDefault(c => c.Type == userIdentity.RoleClaimType);
if (roleClaim != null)
{
userIdentity.TryRemoveClaim(roleClaim);
}

foreach (var element in roles.EnumerateArray())
{
var role = element.GetString();
if (!string.IsNullOrEmpty(role))
{
userIdentity.AddClaim(new Claim(userIdentity.RoleClaimType, role));
}
}
}

return userAccount;
}
}
469 changes: 237 additions & 232 deletions packages/adminpanel/Client/Pages/Customers/Customer.razor

Large diffs are not rendered by default.

68 changes: 38 additions & 30 deletions packages/adminpanel/Client/Pages/Customers/Customers.razor
Original file line number Diff line number Diff line change
Expand Up @@ -12,43 +12,51 @@

<PageTitle>@Localizer["CustomersPage.Title"]</PageTitle>

<MudText Typo="Typo.h2">@Localizer["CustomersPage.Title"]</MudText>
<MudButton
Class="my-4"
Color="Color.Secondary"
Variant="Variant.Filled"
OnClick="@AddEmptyCustomer">
<TextAdjuster>
@Localizer["CustomersPage.AddCustomer"]
</TextAdjuster>
</MudButton>
<MudTextField
Value="@_customerSearchString"
Immediate="true"
ValueChanged="@(new Func<string, Task>(OnFilterChanged))"
Placeholder="@Localizer["Common.Search"]"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search"
IconSize="Size.Medium"
Class="my-4">
</MudTextField>
<MudPaper
Elevation="0"
Class="d-flex flex-wrap justify-start gap-8">
@if (FilteredCustomers is not null)
{
@foreach (var customer in FilteredCustomers)
{
<AuthorizeView Roles="Admin">
<Authorized>
<MudText Typo="Typo.h2">@Localizer["CustomersPage.Title"]</MudText>
<MudButton
Class="my-4"
Color="Color.Secondary"
Variant="Variant.Filled"
OnClick="@AddEmptyCustomer">
<TextAdjuster>
@Localizer["CustomersPage.AddCustomer"]
</TextAdjuster>
</MudButton>
<MudTextField
Value="@_customerSearchString"
Immediate="true"
ValueChanged="@(new Func<string, Task>(OnFilterChanged))"
Placeholder="@Localizer["Common.Search"]"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search"
IconSize="Size.Medium"
Class="my-4">
</MudTextField>
<MudPaper
Elevation="0"
Class="d-flex flex-wrap justify-start gap-8">
@if (FilteredCustomers is not null)
{
@foreach (var customer in FilteredCustomers)
{
<CustomerCard
ActionLabel="@Localizer["Common.NavigateTo"]"
OnActionPress="@(() => Navigation.NavigateTo($"/kunder/{customer.Id}"))"
CustomerName="@customer.Name"
ProjectCount="@customer.ProjectCount"
ContactPerson="@customer.ContactPerson">
</CustomerCard>
}
}
</MudPaper>
}
}
</MudPaper>
</Authorized>

<NotAuthorized>
Du har ikke tilgang til å se dette innholdet.
</NotAuthorized>
</AuthorizeView>

@code {
[Inject] private HttpClient HttpClient { get; set; }
Expand Down
193 changes: 99 additions & 94 deletions packages/adminpanel/Client/Pages/Employees/Employee.razor
Original file line number Diff line number Diff line change
Expand Up @@ -9,105 +9,110 @@

@if (_employee is not null)
{
<MudIconButton
Icon="@Icons.Material.Filled.ArrowBack"
Color="Color.Secondary"
aria-label="back"
OnClick="@(()=> Navigation.NavigateTo("/ansatte"))"/>
<PageTitle>@_employee.Name ?? @Localizer["EmployeePage.Details"]</PageTitle>

<MudPaper Class="mb-4 d-flex flex-row align-center" Elevation="0">
<MudText Class="me-2" Typo="Typo.h2">@_employee.Name</MudText>
<MudIconButton
Icon="@Icons.Material.Filled.Edit"
Color="Color.Secondary"
OnClick="@EditEmployee">
</MudIconButton>
</MudPaper>

<div class="d-flex flex-column flex-sm-row gap-16 mb-8">
<MudPaper Class="pa-4" Elevation="0">
@if (_employee is null)
{
// insert avatar image
<MudAvatar Color="Color.Secondary" Style="width: 250px; height: 250px;">

</MudAvatar>
}
else
{
// insert placeholder avatar
<MudAvatar Elevation="2" Color="Color.Secondary" Style="width: 250px; height: 250px;">
<MudText Typo="Typo.button" Style="font-size: 2rem;">@TextUtilities.GetInitialsFromName(_employee.Name, null)</MudText>
</MudAvatar>
}
</MudPaper>
</div>
<MudPaper Elevation="0" Class="pa-4">
<MudText
>
@Localizer["Common.StartDate"]: @(_employee.StartDate.HasValue ? _employee.StartDate.Value.ToString("dd.MM.yyyy") : "")
</MudText>
<MudText
>
@Localizer["Common.EndDate"]: @(_employee.EndDate.HasValue ? _employee.EndDate.Value.ToString("dd.MM.yyyy") : "")
</MudText>
<MudText>
@Localizer["Common.Email"]: @_employee.Email
</MudText>
<MudText>
@Localizer["Common.EmployeeId"]: @_employee.EmployeeId
</MudText>
</MudPaper>

<MudPaper Elevation="0" Class="mb-4">
<MudDataGrid
T="EmployeeEmploymentRateModel"
Items="_employee.EmploymentRates"
MultiSelection="@_multiSelection"
@bind-selectedItem="_selectedEmploymentRate"
@bind-SelectedItems="_employmentRateSelectionList"
Filterable="false"
FooterClass="d-none">
<ToolBarContent>
<MudText Class="mb-2" Typo="Typo.h6">@Localizer["Common.EmploymentRate"]</MudText>
<MudSpacer/>
<MudIconButton
Icon="@Icons.Material.Filled.Add"
Color="Color.Secondary"
OnClick="@AddNewEmploymentRate"
aria-label="@Localizer["CustomerPage.AddProject"]">
</MudIconButton>
<AuthorizeView Roles="Admin">
<Authorized>
<MudIconButton
Icon="@Icons.Material.Filled.ArrowBack"
Color="Color.Secondary"
aria-label="back"
OnClick="@(()=> Navigation.NavigateTo("/ansatte"))"/>
<PageTitle>@_employee.Name ?? @Localizer["EmployeePage.Details"]</PageTitle>

<MudPaper Class="mb-4 d-flex flex-row align-center" Elevation="0">
<MudText Class="me-2" Typo="Typo.h2">@_employee.Name</MudText>
<MudIconButton
Icon="@Icons.Material.Filled.Edit"
Color="Color.Secondary"
OnClick="@EditEmploymentRate"
Disabled="@(_selectedEmploymentRate == null)"
aria-label="@Localizer["CustomerPage.EditProject"]">
OnClick="@EditEmployee">
</MudIconButton>
</ToolBarContent>
<Columns>
<SelectColumn
</MudPaper>

<div class="d-flex flex-column flex-sm-row gap-16 mb-8">
<MudPaper Class="pa-4" Elevation="0">
@if (_employee is null)
{
// insert avatar image
<MudAvatar Color="Color.Secondary" Style="width: 250px; height: 250px;">

</MudAvatar>
}
else
{
// insert placeholder avatar
<MudAvatar Elevation="2" Color="Color.Secondary" Style="width: 250px; height: 250px;">
<MudText Typo="Typo.button" Style="font-size: 2rem;">@TextUtilities.GetInitialsFromName(_employee.Name, null)</MudText>
</MudAvatar>
}
</MudPaper>
</div>
<MudPaper Elevation="0" Class="pa-4">
<MudText
>
@Localizer["Common.StartDate"]: @(_employee.StartDate.HasValue ? _employee.StartDate.Value.ToString("dd.MM.yyyy") : "")
</MudText>
<MudText
>
@Localizer["Common.EndDate"]: @(_employee.EndDate.HasValue ? _employee.EndDate.Value.ToString("dd.MM.yyyy") : "")
</MudText>
<MudText>
@Localizer["Common.Email"]: @_employee.Email
</MudText>
<MudText>
@Localizer["Common.EmployeeId"]: @_employee.EmployeeId
</MudText>
</MudPaper>

<MudPaper Elevation="0" Class="mb-4">
<MudDataGrid
T="EmployeeEmploymentRateModel"
ShowInHeader="false"
/>
<PropertyColumn
Title="@Localizer["Common.StartDate.Inclusive"]"
Property="r => r.FromDateInclusive"
Format="d"
/>
<PropertyColumn
Title="@Localizer["Common.EndDate.Inclusive"]"
Property="r=> r.ToDateInclusive"
Format="d"
/>
<PropertyColumn
Title="@Localizer["Common.EmploymentRate"]"
Property="r=>r.RatePercentage"
/>
</Columns>
</MudDataGrid>
</MudPaper>
Items="_employee.EmploymentRates"
MultiSelection="@_multiSelection"
@bind-selectedItem="_selectedEmploymentRate"
@bind-SelectedItems="_employmentRateSelectionList"
Filterable="false"
FooterClass="d-none">
<ToolBarContent>
<MudText Class="mb-2" Typo="Typo.h6">@Localizer["Common.EmploymentRate"]</MudText>
<MudSpacer/>
<MudIconButton
Icon="@Icons.Material.Filled.Add"
Color="Color.Secondary"
OnClick="@AddNewEmploymentRate"
aria-label="@Localizer["CustomerPage.AddProject"]">
</MudIconButton>
<MudIconButton
Icon="@Icons.Material.Filled.Edit"
Color="Color.Secondary"
OnClick="@EditEmploymentRate"
Disabled="@(_selectedEmploymentRate == null)"
aria-label="@Localizer["CustomerPage.EditProject"]">
</MudIconButton>
</ToolBarContent>
<Columns>
<SelectColumn
T="EmployeeEmploymentRateModel"
ShowInHeader="false"
/>
<PropertyColumn
Title="@Localizer["Common.StartDate.Inclusive"]"
Property="r => r.FromDateInclusive"
Format="d"
/>
<PropertyColumn
Title="@Localizer["Common.EndDate.Inclusive"]"
Property="r=> r.ToDateInclusive"
Format="d"
/>
<PropertyColumn
Title="@Localizer["Common.EmploymentRate"]"
Property="r=>r.RatePercentage"
/>
</Columns>
</MudDataGrid>
</MudPaper>
</Authorized>
<NotAuthorized>Du har ikke tilgang til å se dette innholdet.</NotAuthorized>
</AuthorizeView>
}
else
{
Expand Down
Loading
Loading