This commit is contained in:
2025-12-17 14:42:45 +01:00
parent d443ece2ca
commit 875396e6ee
32 changed files with 1669 additions and 286 deletions

View File

@ -156,7 +156,7 @@
<virtualDirectoryDefaults allowSubDirConfig="true" />
<site name="StandManager" id="1">
<application path="/" applicationPool="StandManager AppPool">
<virtualDirectory path="/" physicalPath="C:\Users\g.vitari\Documents\Git\StandManager\StandManager" />
<virtualDirectory path="/" physicalPath="C:\Users\g.vitari\Documents\Git\StandManager_Locale\StandManager" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:21401:localhost" />

View File

@ -19,6 +19,10 @@ public class Cliente : EntitaBase
public Guid? AgenteId { get; set; }
public Utente Agente { get; set; }
[ForeignKey(nameof(Capoarea))]
public Guid? CapoareaId { get; set; }
public Utente Capoarea { get; set; }
[InverseProperty(nameof(Destinazione.Cliente))]
public List<Destinazione> Destinazioni { get; set; }

View File

@ -17,5 +17,6 @@ public enum FeatureType
Insert = 0,
Edit,
Delete,
Capoarea = 50,
AdminGlobal = 100
}

View File

@ -21,6 +21,10 @@ public class Utente : EntitaBase
public Guid? RuoloId { get; set; }
public Ruolo Ruolo { get; set; }
[ForeignKey(nameof(Capoarea))]
public Guid? CapoareaId { get; set; }
public Utente Capoarea { get; set; }
public override string ToString()
{
return $"{Nome} {Cognome}";

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace StandManager.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class Capoarea : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "CapoareaId",
table: "Utente",
type: "uniqueidentifier",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "CapoareaId",
table: "Cliente",
type: "uniqueidentifier",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Utente_CapoareaId",
table: "Utente",
column: "CapoareaId");
migrationBuilder.CreateIndex(
name: "IX_Cliente_CapoareaId",
table: "Cliente",
column: "CapoareaId");
migrationBuilder.AddForeignKey(
name: "FK_Cliente_Utente_CapoareaId",
table: "Cliente",
column: "CapoareaId",
principalTable: "Utente",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Utente_Utente_CapoareaId",
table: "Utente",
column: "CapoareaId",
principalTable: "Utente",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Cliente_Utente_CapoareaId",
table: "Cliente");
migrationBuilder.DropForeignKey(
name: "FK_Utente_Utente_CapoareaId",
table: "Utente");
migrationBuilder.DropIndex(
name: "IX_Utente_CapoareaId",
table: "Utente");
migrationBuilder.DropIndex(
name: "IX_Cliente_CapoareaId",
table: "Cliente");
migrationBuilder.DropColumn(
name: "CapoareaId",
table: "Utente");
migrationBuilder.DropColumn(
name: "CapoareaId",
table: "Cliente");
}
}
}

View File

@ -34,6 +34,9 @@ namespace StandManager.Infrastructure.Migrations
b.Property<string>("Cap")
.HasColumnType("nvarchar(max)");
b.Property<Guid?>("CapoareaId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Citta")
.HasColumnType("nvarchar(max)");
@ -85,6 +88,8 @@ namespace StandManager.Infrastructure.Migrations
b.HasIndex("AgenteId");
b.HasIndex("CapoareaId");
b.HasIndex("IdUtenteCreazione");
b.HasIndex("IdUtenteModifica");
@ -633,6 +638,9 @@ namespace StandManager.Infrastructure.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("CapoareaId")
.HasColumnType("uniqueidentifier");
b.Property<string>("CodiceAgente")
.HasColumnType("nvarchar(max)");
@ -676,6 +684,8 @@ namespace StandManager.Infrastructure.Migrations
b.HasKey("Id");
b.HasIndex("CapoareaId");
b.HasIndex("IdUtenteCreazione");
b.HasIndex("IdUtenteModifica");
@ -691,6 +701,10 @@ namespace StandManager.Infrastructure.Migrations
.WithMany()
.HasForeignKey("AgenteId");
b.HasOne("StandManager.Domain.Entita.Utente", "Capoarea")
.WithMany()
.HasForeignKey("CapoareaId");
b.HasOne("StandManager.Domain.Entita.Utente", "UtenteCreazione")
.WithMany()
.HasForeignKey("IdUtenteCreazione");
@ -705,6 +719,8 @@ namespace StandManager.Infrastructure.Migrations
b.Navigation("Agente");
b.Navigation("Capoarea");
b.Navigation("TipologiaCliente");
b.Navigation("UtenteCreazione");
@ -946,6 +962,10 @@ namespace StandManager.Infrastructure.Migrations
modelBuilder.Entity("StandManager.Domain.Entita.Utente", b =>
{
b.HasOne("StandManager.Domain.Entita.Utente", "Capoarea")
.WithMany()
.HasForeignKey("CapoareaId");
b.HasOne("StandManager.Domain.Entita.Utente", "UtenteCreazione")
.WithMany()
.HasForeignKey("IdUtenteCreazione");
@ -958,6 +978,8 @@ namespace StandManager.Infrastructure.Migrations
.WithMany("Utenti")
.HasForeignKey("RuoloId");
b.Navigation("Capoarea");
b.Navigation("Ruolo");
b.Navigation("UtenteCreazione");

View File

@ -0,0 +1,13 @@
using OAService.Service.Servizi.Implementazioni;
using StandManager.Domain.Entita;
using StandManager.Service.Interfaces;
using StandManager.Service.Repository;
namespace StandManager.Service;
public class FeatureService : TService<Feature>, IFeatureService
{
public FeatureService(IStandManagerUnitOfWork unitOfWork) : base(unitOfWork)
{
}
}

View File

@ -0,0 +1,9 @@
using OAService.Service.Repository;
using OAService.Service.Servizi.Interfacce;
using StandManager.Domain.Entita;
namespace StandManager.Service.Interfaces;
public interface IFeatureService : ITService<Feature>
{
}

View File

@ -5,9 +5,13 @@
public IClienteService ClienteService{ get; set; }
public IDestinazioneService DestinazioneService{ get; set; }
public IEventoService EventoService{ get; set; }
public IFeatureService FeatureService{ get; set; }
public IInvitoEventoService InvitoEventoService{ get; set; }
public IIscrizioneEventoService IscrizioneEventoService{ get; set; }
public IPermissionService PermissionService{ get; set; }
public IReferenteService ReferenteService{ get; set; }
public IRuoloService RuoloService{ get; set; }
public ISezioneService SezioneService{ get; set; }
public ITipologiaClienteService TipologiaClienteService { get; set; }
public IUtenteService UtenteService { get; set; }
}

View File

@ -0,0 +1,9 @@
using OAService.Service.Repository;
using OAService.Service.Servizi.Interfacce;
using StandManager.Domain.Entita;
namespace StandManager.Service.Interfaces;
public interface IPermissionService : ITService<Permission>
{
}

View File

@ -0,0 +1,9 @@
using OAService.Service.Repository;
using OAService.Service.Servizi.Interfacce;
using StandManager.Domain.Entita;
namespace StandManager.Service.Interfaces;
public interface IRuoloService : ITService<Ruolo>
{
}

View File

@ -0,0 +1,9 @@
using OAService.Service.Repository;
using OAService.Service.Servizi.Interfacce;
using StandManager.Domain.Entita;
namespace StandManager.Service.Interfaces;
public interface ISezioneService : ITService<Sezione>
{
}

View File

@ -6,7 +6,7 @@ public class ManagerService : IManagerService
{
public ManagerService(IUtenteService utenteService, IClienteService clienteService, IDestinazioneService destinazioneService, IEventoService eventoService,
IInvitoEventoService invitoEventoService, IIscrizioneEventoService iscrizioneEventoService, IReferenteService referenteService,
ITipologiaClienteService tipologiaClienteService)
ITipologiaClienteService tipologiaClienteService, IFeatureService featureService, IPermissionService permissionService, IRuoloService ruoloService, ISezioneService sezioneService)
{
UtenteService = utenteService;
ClienteService = clienteService;
@ -16,14 +16,22 @@ public class ManagerService : IManagerService
IscrizioneEventoService = iscrizioneEventoService;
ReferenteService = referenteService;
TipologiaClienteService = tipologiaClienteService;
FeatureService = featureService;
PermissionService = permissionService;
RuoloService = ruoloService;
SezioneService = sezioneService;
}
public IUtenteService UtenteService { get; set; }
public IClienteService ClienteService { get; set; }
public IDestinazioneService DestinazioneService { get; set; }
public IEventoService EventoService { get; set; }
public IFeatureService FeatureService { get; set; }
public IInvitoEventoService InvitoEventoService{ get; set; }
public IIscrizioneEventoService IscrizioneEventoService { get; set; }
public IPermissionService PermissionService { get; set; }
public IReferenteService ReferenteService { get; set; }
public IRuoloService RuoloService { get; set; }
public ISezioneService SezioneService { get; set; }
public ITipologiaClienteService TipologiaClienteService { get; set; }
}

View File

@ -0,0 +1,13 @@
using OAService.Service.Servizi.Implementazioni;
using StandManager.Domain.Entita;
using StandManager.Service.Interfaces;
using StandManager.Service.Repository;
namespace StandManager.Service;
public class PermissionService : TService<Permission>, IPermissionService
{
public PermissionService(IStandManagerUnitOfWork unitOfWork) : base(unitOfWork)
{
}
}

View File

@ -0,0 +1,13 @@
using OAService.Service.Servizi.Implementazioni;
using StandManager.Domain.Entita;
using StandManager.Service.Interfaces;
using StandManager.Service.Repository;
namespace StandManager.Service;
public class RuoloService : TService<Ruolo>, IRuoloService
{
public RuoloService(IStandManagerUnitOfWork unitOfWork) : base(unitOfWork)
{
}
}

View File

@ -0,0 +1,13 @@
using OAService.Service.Servizi.Implementazioni;
using StandManager.Domain.Entita;
using StandManager.Service.Interfaces;
using StandManager.Service.Repository;
namespace StandManager.Service;
public class SezioneService : TService<Sezione>, ISezioneService
{
public SezioneService(IStandManagerUnitOfWork unitOfWork) : base(unitOfWork)
{
}
}

View File

@ -43,40 +43,14 @@
<div class="container-xl">
<div class="row flex-column flex-md-row flex-fill align-items-center">
<div class="col">
<!-- BEGIN NAVBAR MENU -->
<ul class="navbar-nav">
<li class="nav-item @GetActiveClass("/management")">
<a class="nav-link" href="/management">
<span class="nav-link-icon d-md-none d-lg-inline-block">
<i class="fa-solid fa-house"></i>
</span>
<span class="nav-link-title"> Home </span>
</a>
</li>
<li class="nav-item @GetActiveClass("/management/Utenti")">
<a class="nav-link" href="/management/Utenti">
<span class="nav-link-icon d-md-none d-lg-inline-block">
<i class="fa-solid fa-user"></i>
</span>
<span class="nav-link-title"> Utenti </span>
</a>
</li>
<li class="nav-item @GetActiveClass("/management/Clienti")">
<a class="nav-link" href="/management/Clienti">
<span class="nav-link-icon d-md-none d-lg-inline-block">
<i class="fa-solid fa-address-card"></i>
</span>
<span class="nav-link-title"> Clienti </span>
</a>
</li>
<li class="nav-item @GetActiveClass("/management/Eventi")">
<a class="nav-link" href="/management/Eventi">
<span class="nav-link-icon d-md-none d-lg-inline-block">
<i class="fa-solid fa-calendar"></i>
</span>
<span class="nav-link-title"> Eventi </span>
</a>
</li>
<NavigationItem currentUrl="@currentUrl" requiredUrl="/management" destination="/management" iconName="fa-home" title="Home"/>
<NavigationItem currentUrl="@currentUrl" requiredUrl="/management/Utenti" destination="/management/Utenti" iconName="fa-user" title="Utenti"/>
<NavigationItem currentUrl="@currentUrl" requiredUrl="/management/Clienti" destination="/management/Clienti" iconName="fa-address-card" title="Clienti"/>
<NavigationItem currentUrl="@currentUrl" requiredUrl="/management/Eventi" destination="/management/Eventi" iconName="fa-calendar" title="Eventi"/>
<NavigationItem currentUrl="@currentUrl" requiredUrl="/management/Ruoli" destination="/management/Ruoli" iconName="fa-lock" title="Ruoli"/>
</ul>
</div>
</div>
@ -99,20 +73,4 @@
base.OnInitializedAsync();
currentUrl = NavManager.ToBaseRelativePath(NavManager.Uri);
}
private string GetActiveClass(string href)
{
string currentClean = currentUrl.Split("management").Last();
string hrefClean = href.Split("management").Last();
if (currentClean.Contains("?"))
currentClean = currentClean.Substring(0, currentClean.IndexOf("?"));
var isActive = (currentClean.Contains(hrefClean, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(hrefClean)
|| (string.IsNullOrEmpty(hrefClean) && string.IsNullOrEmpty(currentClean)));
return isActive ? "active" : "";
}
}

View File

@ -1,94 +0,0 @@
@implements IDisposable
@inject NavigationManager NavigationManager
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">StandManager</a>
</div>
</div>
<input type="checkbox" title="Navigation menu" class="navbar-toggler" />
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="weather">
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="auth">
<span class="bi bi-lock-nav-menu" aria-hidden="true"></span> Auth Required
</NavLink>
</div>
<AuthorizeView>
<Authorized>
<div class="nav-item px-3">
<NavLink class="nav-link" href="/Management">
<span class="bi bi-person-fill-nav-menu" aria-hidden="true"></span> @context.User.Identity?.Name
</NavLink>
</div>
<div class="nav-item px-3">
<input type="hidden" name="ReturnUrl" value="@currentUrl" />
<button @onclick="onLogoutPressed" class="nav-link">
<span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true"></span> Logout
</button>
</div>
</Authorized>
<NotAuthorized>
<div class="nav-item px-3">
<NavLink class="nav-link" href="Account/Register">
<span class="bi bi-person-nav-menu" aria-hidden="true"></span> Register
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="/management/login">
<span class="bi bi-person-badge-nav-menu" aria-hidden="true"></span> Login
</NavLink>
</div>
</NotAuthorized>
</AuthorizeView>
</nav>
</div>
@code {
private string? currentUrl;
protected override void OnInitialized()
{
currentUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
NavigationManager.LocationChanged += OnLocationChanged;
}
private void OnLocationChanged(object? sender, LocationChangedEventArgs e)
{
currentUrl = NavigationManager.ToBaseRelativePath(e.Location);
StateHasChanged();
}
public void Dispose()
{
NavigationManager.LocationChanged -= OnLocationChanged;
}
public void onLogoutPressed()
{
var a = "";
}
}

View File

@ -1,125 +0,0 @@
.navbar-toggler {
appearance: none;
cursor: pointer;
width: 3.5rem;
height: 2.5rem;
color: white;
position: absolute;
top: 0.5rem;
right: 1rem;
border: 1px solid rgba(255, 255, 255, 0.1);
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
}
.navbar-toggler:checked {
background-color: rgba(255, 255, 255, 0.5);
}
.top-row {
height: 3.5rem;
background-color: rgba(0,0,0,0.4);
}
.navbar-brand {
font-size: 1.1rem;
}
.bi {
display: inline-block;
position: relative;
width: 1.25rem;
height: 1.25rem;
margin-right: 0.75rem;
top: -1px;
background-size: cover;
}
.bi-house-door-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
}
.bi-plus-square-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
}
.bi-list-nested-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
}
.bi-lock-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2zM5 8h6a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1z'/%3E%3C/svg%3E");
}
.bi-person-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person' viewBox='0 0 16 16'%3E%3Cpath d='M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0Zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4Zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10Z'/%3E%3C/svg%3E");
}
.bi-person-badge-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person-badge' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3zM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z'/%3E%3Cpath d='M4.5 0A2.5 2.5 0 0 0 2 2.5V14a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2.5A2.5 2.5 0 0 0 11.5 0h-7zM3 2.5A1.5 1.5 0 0 1 4.5 1h7A1.5 1.5 0 0 1 13 2.5v10.795a4.2 4.2 0 0 0-.776-.492C11.392 12.387 10.063 12 8 12s-3.392.387-4.224.803a4.2 4.2 0 0 0-.776.492V2.5z'/%3E%3C/svg%3E");
}
.bi-person-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person-fill' viewBox='0 0 16 16'%3E%3Cpath d='M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3Zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z'/%3E%3C/svg%3E");
}
.bi-arrow-bar-left-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-arrow-bar-left' viewBox='0 0 16 16'%3E%3Cpath d='M12.5 15a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 1 0v13a.5.5 0 0 1-.5.5ZM10 8a.5.5 0 0 1-.5.5H3.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L3.707 7.5H9.5a.5.5 0 0 1 .5.5Z'/%3E%3C/svg%3E");
}
.nav-item {
font-size: 0.9rem;
padding-bottom: 0.5rem;
}
.nav-item:first-of-type {
padding-top: 1rem;
}
.nav-item:last-of-type {
padding-bottom: 1rem;
}
.nav-item ::deep .nav-link {
color: #d7d7d7;
background: none;
border: none;
border-radius: 4px;
height: 3rem;
display: flex;
align-items: center;
line-height: 3rem;
width: 100%;
}
.nav-item ::deep a.active {
background-color: rgba(255,255,255,0.37);
color: white;
}
.nav-item ::deep .nav-link:hover {
background-color: rgba(255,255,255,0.1);
color: white;
}
.nav-scrollable {
display: none;
}
.navbar-toggler:checked ~ .nav-scrollable {
display: block;
}
@media (min-width: 641px) {
.navbar-toggler {
display: none;
}
.nav-scrollable {
/* Never collapse the sidebar for wide screens */
display: block;
/* Allow sidebar to scroll for tall menus */
height: calc(100vh - 3.5rem);
overflow-y: auto;
}
}

View File

@ -0,0 +1,31 @@
<li class="nav-item @GetActiveClass()">
<a class="nav-link" href="@destination">
<span class="nav-link-icon d-md-none d-lg-inline-block">
<i class="fa-solid @iconName"></i>
</span>
<span class="nav-link-title"> @title </span>
</a>
</li>
@code{
[Parameter] public string currentUrl { get; set; } = "";
[Parameter] public string requiredUrl { get; set; } = "/";
[Parameter] public string destination { get; set; } = "/";
[Parameter] public string iconName { get; set; } = "fa-user";
[Parameter] public string title { get; set; }
private string GetActiveClass()
{
var currentClean = currentUrl.Split("management").Last();
var hrefClean = requiredUrl.Split("management").Last();
if (currentClean.Contains("?"))
currentClean = currentClean.Substring(0, currentClean.IndexOf("?"));
var isActive = (currentClean.Contains(hrefClean, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(hrefClean)
|| (string.IsNullOrEmpty(hrefClean) && string.IsNullOrEmpty(currentClean)));
return isActive ? "active" : "";
}
}

View File

@ -9,6 +9,7 @@
@using StandManager.Infrastructure.DAL.Context
@using StandManager.Model
@using System.Security.Claims
@using Microsoft.EntityFrameworkCore
@using StandManager.Service.Interfaces
@inject IHttpContextAccessor HttpContextAccessor
@ -66,7 +67,8 @@
/// </summary>
private async Task HandleValidSubmit(EditContext args)
{
var user = await _managerService.UtenteService.RicercaPer(x => x.Email == model.Email);
var user = await _managerService.UtenteService.RicercaPer(x => x.Email == model.Email,
includi:x => x.Include(y => y.Ruolo));
var hasher = new PasswordHasher<Utente>();
if (user == null ||
@ -81,7 +83,8 @@
{
new Claim(ClaimTypes.Name, user.Email),
new Claim(ClaimTypes.Role, "Admin"),
new Claim("UserId", user.Id.ToString())
new Claim("UserId", user.Id.ToString()),
new Claim("RoleId", user.RuoloId?.ToString())
};
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

View File

@ -169,18 +169,19 @@
@code {
[Parameter]
public Guid? ClienteId { get; set; }
public Guid idClaim { get; set; }
[SupplyParameterFromForm]
private ClienteViewModel cliente { get; set; } = new();
private IEnumerable<UtenteViewModel> agenti { get; set; } = new List<UtenteViewModel>();
private List<TipologiaClienteViewModel> tipologiaCliente { get; set; } = new();
private List<LookupViewModel<int>> statoCliente { get; set; } = new List<LookupViewModel<int>>();
private List<LookupViewModel<int>> statoCliente { get; set; } = new();
RadzenDataGrid<DestinazioneViewModel> destinazioniGrid;
private string pageTitle => cliente?.Id == Guid.Empty ? "Nuovo cliente" : "Modifica cliente";
private DialogOptions editNewDialogOption { get; set; } = new DialogOptions()
private DialogOptions editNewDialogOption { get; set; } = new()
{
Resizable = false,
Draggable = false,
@ -194,7 +195,19 @@
/// </summary>
protected override async Task OnInitializedAsync()
{
agenti = (await _managerService.UtenteService.RicercaQueryable(x => x.Eliminato == false, ordinamento: x => x.OrderBy(y => y.Cognome).ThenBy(z => z.Nome)))
idClaim = await MembershipUtils.GetUserId(auth);
var idRuolo = await MembershipUtils.GetRoleId(auth);
var ruolo = await _managerService.RuoloService.RicercaPer(
x => x.Id == idRuolo && x.Permessi.Any(y => y.Feature.Type == FeatureType.Capoarea || y.Feature.Type == FeatureType.AdminGlobal),
includi:x => x.Include(y => y.Permessi).ThenInclude(z => z.Feature));
var isAdmin = ruolo?.Permessi.Where(x => x.Eliminato == false)?.Any(x => x.Feature.Type == FeatureType.AdminGlobal) ?? false;
agenti = ruolo == null
? [await _managerService.UtenteService.RicercaPer(x => x.Id == idClaim)]
: (await _managerService.UtenteService.RicercaQueryable(
x => x.Eliminato == false && (isAdmin || x.CapoareaId == idClaim),
includi: x => x.Include(y => y.Capoarea),
ordinamento: x => x.OrderBy(y => y.Cognome).ThenBy(z => z.Nome)))
.Select(x => (UtenteViewModel)x).ToList();
var eUtils = new EnumUtils();
tipologiaCliente = (await _managerService.TipologiaClienteService.RicercaQueryable(ordinamento: x => x.OrderBy(y => y.Nome))).Select(x => (TipologiaClienteViewModel)x).ToList();
@ -225,8 +238,6 @@
/// </summary>
private async Task onClienteSave()
{
var idClaim = await MembershipUtils.GetUserId(auth);
var model = await _managerService.ClienteService.RicercaPer(x => x.Id == cliente.Id, solaLettura: false)
?? new Cliente() { Destinazioni = new List<Destinazione>() };

View File

@ -0,0 +1,97 @@
@attribute [Authorize]
@page "/management/Ruoli"
@using ClosedXML.Excel
@using Microsoft.EntityFrameworkCore
@using StandManager.Model
@using System.Threading.Tasks
@rendermode InteractiveServer
@inject AuthenticationStateProvider auth
<PageTitle>Ruoli</PageTitle>
<div class="page-wrapper">
<!-- BEGIN PAGE BODY -->
<div class="page-body">
<div class="container-xl">
<div class="row row-cards">
<div class="col">
<!-- Page pre-title -->
<div class="page-pretitle">Overview</div>
<h2 class="page-title">Ruoli</h2>
</div>
<div class="col-auto ms-auto">
<div class="btn-list">
<a href="/management/Ruoli/Modifica" class="btn btn-primary btn-5 d-none d-sm-inline-block">
Nuovo ruolo
</a>
</div>
</div>
<div class="col-lg-12">
<div class="card">
<div class="table-responsive">
<RadzenDataGrid AllowFiltering="true" AllowColumnResize="true" AllowAlternatingRows="false" FilterMode="FilterMode.CheckBoxList" AllowSorting="true" PageSize="25"
AllowPaging="true" PagerHorizontalAlign="HorizontalAlign.Left" ShowPagingSummary="true"
Data="@ruoli" LogicalFilterOperator="LogicalFilterOperator.Or" SelectionMode="DataGridSelectionMode.Single">
<Columns>
<RadzenDataGridColumn Property="@nameof(RuoloViewModel.Id)" Filterable="false" Title="ID" Width="200px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn Property="@nameof(RuoloViewModel.Nome)" Title="Nome" Width="250px" />
<RadzenDataGridColumn Context="ruolo" Filterable="false" Sortable="false" TextAlign="TextAlign.Right" Width="250px">
<Template Context="ruolo">
<RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" class="rz-my-1 rz-ms-1" Click="@(args => EditRow(ruolo))" @onclick:stopPropagation="true" />
<RadzenButton Icon="delete" ButtonStyle="ButtonStyle.Danger" Variant="Variant.Flat" Size="ButtonSize.Medium" Shade="Shade.Lighter" class="rz-my-1 rz-ms-1" Click="@(args => DeleteRow(ruolo))" @onclick:stopPropagation="true" />
</Template>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@code {
List<RuoloViewModel> ruoli;
/// <summary>
/// Carica lelenco dei clienti non eliminati, includendo lagente,
/// e prepara i dati per la visualizzazione in pagina.
/// </summary>
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
ruoli = (await _managerService.RuoloService.RicercaQueryable(
x => x.Eliminato == false,
ordinamento: x => x.OrderBy(y => y.Nome)))
.Select(x => (RuoloViewModel)x).ToList();
}
/// <summary>
/// Apre la pagina di modifica per il cliente selezionato.
/// </summary>
private async Task EditRow(RuoloViewModel ruolo)
{
_navManager.NavigateTo($"/management/Ruoli/Modifica/{ruolo.Id}");
}
/// <summary>
/// Chiede conferma ed elimina il cliente scelto; se confermato,
/// aggiorna la lista ricaricandola dal database.
/// </summary>
private async Task DeleteRow(RuoloViewModel ruolo)
{
var ok = await _dialogService.Confirm($"Vuoi davvero eliminare il ruolo {ruolo.Nome}?", "Conferma eliminazione", new ConfirmOptions { OkButtonText = "Sì", CancelButtonText = "No", Width = "400px" });
if (ok == true)
{
await _managerService.RuoloService.Elimina(ruolo.Id, await MembershipUtils.GetUserId(auth));
ruoli = (await _managerService.RuoloService.RicercaQueryable(x => x.Eliminato == false))
.Select(x => (RuoloViewModel)x).ToList();
}
}
}

View File

@ -0,0 +1,175 @@
@attribute [Authorize]
@rendermode InteractiveServer
@page "/management/Ruoli/Modifica"
@page "/management/Ruoli/Modifica/{RuoloId:guid}"
@using Microsoft.AspNetCore.Identity
@using Microsoft.EntityFrameworkCore
@using StandManager.Model
@inject AuthenticationStateProvider auth
<PageTitle>@pageTitle</PageTitle>
<div class="page-wrapper">
<!-- BEGIN PAGE HEADER -->
<div class="page-header d-print-none" aria-label="Page header">
<div class="container-xl">
<div class="row g-2 align-items-center">
<div class="col">
<h2 class="page-title">@pageTitle</h2>
</div>
</div>
</div>
</div>
<!-- END PAGE HEADER -->
<!-- BEGIN PAGE BODY -->
<div class="page-body">
<div class="container-xl">
<div class="row row-cards">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<div class="row g-5">
<EditForm Model="ruolo" OnValidSubmit="onRuoloSave" FormName="editRuoloForm">
<DataAnnotationsValidator />
<div class="col-12">
<div class="row">
<div class="col-4 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Nome</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Nome" @bind-Value="@ruolo.Nome" />
</div>
</div>
<div class="row">
<div class="col-3 mb-3">
<button type="button" class="btn btn-default w-100" @onclick="backToHome">
Annulla
</button>
</div>
<div class="col-3 mb-3">
<button type="submit" class="btn btn-primary w-100">
Salva
</button>
</div>
</div>
</div>
</EditForm>
</div>
</div>
</div>
</div>
</div>
<div id="advanced-table">
<div class="table-responsive">
<RadzenDataGrid @ref="permessiGrid" AllowFiltering="true" AllowColumnResize="true" AllowAlternatingRows="false" FilterMode="FilterMode.CheckBoxList" AllowSorting="true" PageSize="25"
AllowPaging="true" PagerHorizontalAlign="HorizontalAlign.Left" ShowPagingSummary="true" AllowGrouping="true"
Data="@permessi" LogicalFilterOperator="LogicalFilterOperator.Or" SelectionMode="DataGridSelectionMode.Single" Render="@OnRender">
<Columns>
<RadzenDataGridColumn Property="@nameof(PermissionRowViewModel.Selected)" Filterable="true" Width="200px" TextAlign="TextAlign.Center">
<Template Context="permesso">
<RadzenCheckBox TValue="bool" Value="@permesso.Selected" Change=@(args => onSelected(args, permesso))></RadzenCheckBox>
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn Property="@nameof(PermissionRowViewModel.Ordinamento)" Visible="false" SortOrder="SortOrder.Ascending" />
<RadzenDataGridColumn Property="@nameof(PermissionRowViewModel.OrdinamentoFeature)" Visible="false" SortOrder="SortOrder.Ascending" />
<RadzenDataGridColumn Property="@nameof(PermissionRowViewModel.Nome)" Groupable="true" GroupProperty="Nome" Filterable="true" Width="200px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn Property="@nameof(PermissionRowViewModel.NomeFeature)" Title="Nome" Width="250px" />
<RadzenDataGridColumn Property="@nameof(PermissionRowViewModel.DescrizioneFeature)" Title="Descrizione" Width="250px" />
</Columns>
</RadzenDataGrid>
</div>
</div>
</div>
</div>
</div>
@code {
[Parameter]
public Guid? RuoloId { get; set; }
[SupplyParameterFromForm]
private RuoloViewModel? ruolo { get; set; } = new();
private List<PermissionRowViewModel> permessi { get; set; } = new();
private RadzenDataGrid<PermissionRowViewModel> permessiGrid { get; set; }
private string pageTitle => ruolo?.Id == Guid.Empty ? "Nuovo ruolo" : "Modifica ruolo";
/// <summary>
/// Recupera lutente da modificare se è stato passato un ID,
/// altrimenti inizializza un nuovo modello vuoto.
/// </summary>
protected override async Task OnInitializedAsync()
{
ruolo = RuoloId.GetValueOrDefault() != Guid.Empty
? await _managerService.RuoloService.RicercaPer(x => x.Id == RuoloId)
: new RuoloViewModel();
var sections = (await
_managerService.SezioneService.RicercaQueryable(x => x.Eliminato == false, includi: x => x.Include(y => y.Features))).ToList();
var permissions = await _managerService.PermissionService.RicercaQueryable(x => x.Ruolo.Id == ruolo.Id && x.Eliminato == false);
permessi = [];
foreach (var section in sections)
permessi.AddRange(section.Features.Where(x => !x.Eliminato).Select(x => new PermissionRowViewModel(section, x, permissions)).ToList());
}
void OnRender(DataGridRenderEventArgs<PermissionRowViewModel> args)
{
if (!args.FirstRender) return;
args.Grid.Groups.Add(new GroupDescriptor(){ Property = "Nome", SortOrder = SortOrder.Descending });
StateHasChanged();
}
/// <summary>
/// Salva lutente: recupera o crea il modello, applica le modifiche dalla UI,
/// gestisce lhash della password se inserita e registra tutto a database
/// usando lID dellutente autenticato.
/// </summary>
private async Task onRuoloSave()
{
var idClaim = await MembershipUtils.GetUserId(auth);
var model = await _managerService.RuoloService.RicercaPer(x => x.Id == ruolo.Id, solaLettura: false)
?? new Ruolo();
model.Nome = ruolo.Nome;
await _managerService.RuoloService.Salva(model, idClaim);
_navManager.NavigateTo("/management/Ruoli");
}
/// <summary>
/// Torna allelenco ruoli senza applicare altre azioni.
/// </summary>
private void backToHome()
{
_navManager.NavigateTo("/management/Ruoli");
}
private async Task onSelected(bool selected, PermissionRowViewModel permissionRow)
{
var idClaim = await MembershipUtils.GetUserId(auth);
var ruoloPermission = await _managerService.PermissionService.RicercaPer(
x => x.RuoloId == ruolo.Id && x.IdFeature == permissionRow.IdFeature && x.Eliminato == false,
includi: x => x.Include(y => y.Ruolo).Include(y => y.Feature),
solaLettura: false);
if (ruoloPermission == null && selected)
{
var permission = new Permission()
{
RuoloId = ruolo.Id,
IdFeature = permissionRow.IdFeature
};
await _managerService.PermissionService.Salva(permission, idClaim);
}
else
{
await _managerService.PermissionService.Elimina(ruoloPermission?.Id ?? Guid.Empty, idClaim);
}
permissionRow.Selected = selected;
}
}

View File

@ -1,5 +1,6 @@
@attribute [Authorize]
@page "/management/Utenti"
@using Microsoft.EntityFrameworkCore
@rendermode InteractiveServer
@ -35,8 +36,10 @@
<RadzenDataGridColumn Property="@nameof(Utente.Nome)" Title="Nome" Width="160px" />
<RadzenDataGridColumn Property="@nameof(Utente.Cognome)" Title="Cognome" Width="160px" />
<RadzenDataGridColumn Property="@nameof(Utente.Email)" Title="Mail" Width="200px" />
<RadzenDataGridColumn Property="Ruolo.Nome" Title="Ruolo" Width="200px" />
<RadzenDataGridColumn Property="Capoarea.Nome" Title="Capoarea" Width="200px" />
<RadzenDataGridColumn Context="order" Filterable="false" Sortable="false" TextAlign="TextAlign.Right">
<RadzenDataGridColumn Context="order" Filterable="false" Sortable="false" TextAlign="TextAlign.Right" Width="200px">
<Template Context="user">
<RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" class="rz-my-1 rz-ms-1" Click="@(args => EditRow(user))" @onclick:stopPropagation="true" />
<RadzenButton Icon="delete" ButtonStyle="ButtonStyle.Danger" Variant="Variant.Flat" Size="ButtonSize.Medium" Shade="Shade.Lighter" class="rz-my-1 rz-ms-1" Click="@(args => DeleteRow(user))" @onclick:stopPropagation="true" />
@ -63,7 +66,10 @@
{
await base.OnInitializedAsync();
utenti = await _managerService.UtenteService.RicercaQueryable(x => x.Eliminato == false, ordinamento: x => x.OrderBy(y => y.Cognome).ThenBy(z => z.Nome));
utenti = await _managerService.UtenteService.RicercaQueryable(
x => x.Eliminato == false,
includi: x => x.Include(y => y.Ruolo).Include(y => y.Capoarea),
ordinamento: x => x.OrderBy(y => y.Cognome).ThenBy(z => z.Nome));
}
/// <summary>
@ -80,12 +86,15 @@
/// </summary>
private async Task DeleteRow(Utente user)
{
var ok = await _dialogService.Confirm($"Vuoi davvero eliminare l'utente {user.ToString()}?", "Conferma eliminazione", new ConfirmOptions { OkButtonText = "Sì", CancelButtonText = "No", Width = "400px" });
var ok = await _dialogService.Confirm($"Vuoi davvero eliminare l'utente {user}?", "Conferma eliminazione", new ConfirmOptions { OkButtonText = "Sì", CancelButtonText = "No", Width = "400px" });
if (ok == true)
{
await _managerService.UtenteService.Elimina(user.Id, await MembershipUtils.GetUserId(auth));
utenti = await _managerService.UtenteService.RicercaQueryable(x => x.Eliminato == false);
utenti = await _managerService.UtenteService.RicercaQueryable(
x => x.Eliminato == false,
includi: x => x.Include(y => y.Ruolo).Include(y => y.Capoarea),
ordinamento: x => x.OrderBy(y => y.Cognome).ThenBy(z => z.Nome));
}
}
}

View File

@ -5,6 +5,7 @@
@page "/management/Utenti/Modifica/{UserId:guid}"
@using Microsoft.AspNetCore.Identity
@using Microsoft.EntityFrameworkCore
@using StandManager.Model
@inject AuthenticationStateProvider auth
@ -52,6 +53,16 @@
</div>
<div class="row">
<div class="col-4 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Ruolo</RadzenText>
<RadzenDropDown Style="width: 100%" TValue="Guid" @bind-Value=@utente.RuoloId Data=@ruoli TextProperty="Nome" ValueProperty="Id" Name="ruoliDrop" />
</div>
<div class="col-4 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Capoarea</RadzenText>
<RadzenDropDown Style="width: 100%" TValue="Guid" @bind-Value=@utente.CapoareaId Data=@capoareaList TextProperty="Nome" ValueProperty="Id" Name="capoareaDrop\" />
</div>
<div class="col-4 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Password</RadzenText>
<RadzenPassword Style="width: 100%" aria-label="Password" @bind-Value="@utente.Password"/>
@ -59,12 +70,12 @@
</div>
<div class="row">
<div class="col-3 mb-3">
<div class="col-4 mb-3">
<button type="button" class="btn btn-default w-100" @onclick="backToHome">
Annulla
</button>
</div>
<div class="col-3 mb-3">
<div class="col-4 mb-3">
<button type="submit" class="btn btn-primary w-100">
Salva
</button>
@ -87,6 +98,8 @@
[SupplyParameterFromForm]
private UtenteViewModel? utente { get; set; } = new();
private List<UtenteViewModel> capoareaList { get; set; } = new();
private List<RuoloViewModel> ruoli { get; set; } = new();
private string pageTitle => utente?.Id == Guid.Empty ? "Nuovo utente" : "Modifica utente";
@ -97,9 +110,21 @@
protected override async Task OnInitializedAsync()
{
if (UserId.GetValueOrDefault() != Guid.Empty)
utente = await _managerService.UtenteService.RicercaPer(x => x.Id == UserId);
utente = await _managerService.UtenteService.RicercaPer(
x => x.Id == UserId,
includi:x => x.Include(y => y.Ruolo).Include(y => y.Capoarea));
else
utente = new UtenteViewModel();
ruoli = (await _managerService.RuoloService.RicercaQueryable(x => x.Eliminato == false))
.Select(x => (RuoloViewModel)x).ToList();
var ruoliCapoarea = await _managerService.RuoloService.RicercaQueryable(
x => x.Permessi.Any(y => y.Feature.Type == FeatureType.AdminGlobal || y.Feature.Type == FeatureType.Capoarea),
includi:x => x.Include(y => y.Permessi).ThenInclude(z => z.Feature));
capoareaList = (await _managerService.UtenteService.RicercaQueryable(
u => ruoliCapoarea.Any(r => r.Id == u.RuoloId)
)).Select(x => (UtenteViewModel)x).ToList();
}
/// <summary>
@ -128,6 +153,9 @@
model.Password = hasher.HashPassword(model, utente.Password);
}
model.RuoloId = utente.RuoloId;
model.CapoareaId = utente.CapoareaId;
await _managerService.UtenteService.Salva(model, Guid.Parse(idClaim));
_navManager.NavigateTo("/management/Utenti");
}

View File

@ -0,0 +1,26 @@
using StandManager.Domain.Entita;
namespace StandManager.Model;
public class PermissionRowViewModel
{
public PermissionRowViewModel(Sezione section, Feature feature, IQueryable<Permission> permissions)
{
Nome = section.Nome;
IdSezione = section.Id;
NomeFeature = feature.Nome;
DescrizioneFeature = feature.Descrizione;
IdFeature = feature.Id;
Ordinamento = section.Ordinamento;
OrdinamentoFeature = feature.Ordinamento;
Selected = permissions.Any(y => y.Feature.Id == feature.Id);
}
public Guid IdSezione { get; set; }
public string Nome { get; set; }
public Guid IdFeature { get; set; }
public string NomeFeature { get; set; }
public string DescrizioneFeature { get; set; }
public int Ordinamento { get; set; }
public int OrdinamentoFeature { get; set; }
public bool Selected { get; set; }
}

View File

@ -0,0 +1,20 @@
using StandManager.Domain.Entita;
namespace StandManager.Model;
public class RuoloViewModel
{
public Guid Id { get; set; }
public string Nome { get; set; }
public static implicit operator RuoloViewModel(Ruolo model)
{
return model == null
? null
: new RuoloViewModel()
{
Nome = model.Nome,
Id = model.Id
};
}
}

View File

@ -16,6 +16,8 @@ namespace StandManager.Model
public string Nome { get; set; }
[Required(ErrorMessage = "Il cognome è obbligatorio")]
public string Cognome { get; set; }
public Guid RuoloId { get; set; }
public Guid CapoareaId { get; set; }
public string Info => $"{Nome} {Cognome}";
public static implicit operator UtenteViewModel(Utente? model)
@ -26,7 +28,9 @@ namespace StandManager.Model
Username = model.Username,
Email = model.Email,
Nome = model.Nome,
Cognome = model.Cognome
Cognome = model.Cognome,
RuoloId = model.Ruolo?.Id ?? Guid.Empty,
CapoareaId = model.Capoarea?.Id ?? Guid.Empty
};
}

View File

@ -11,4 +11,12 @@ public static class MembershipUtils
return Guid.Parse(idClaim ?? Guid.Empty.ToString());
}
public static async Task<Guid> GetRoleId(AuthenticationStateProvider auth)
{
var state = await auth.GetAuthenticationStateAsync();
var idClaim = state.User.FindFirst("RoleId")?.Value;
return Guid.Parse(idClaim ?? Guid.Empty.ToString());
}
}