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" /> <virtualDirectoryDefaults allowSubDirConfig="true" />
<site name="StandManager" id="1"> <site name="StandManager" id="1">
<application path="/" applicationPool="StandManager AppPool"> <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> </application>
<bindings> <bindings>
<binding protocol="http" bindingInformation="*:21401:localhost" /> <binding protocol="http" bindingInformation="*:21401:localhost" />

View File

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

View File

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

View File

@ -21,6 +21,10 @@ public class Utente : EntitaBase
public Guid? RuoloId { get; set; } public Guid? RuoloId { get; set; }
public Ruolo Ruolo { get; set; } public Ruolo Ruolo { get; set; }
[ForeignKey(nameof(Capoarea))]
public Guid? CapoareaId { get; set; }
public Utente Capoarea { get; set; }
public override string ToString() public override string ToString()
{ {
return $"{Nome} {Cognome}"; 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") b.Property<string>("Cap")
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
b.Property<Guid?>("CapoareaId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Citta") b.Property<string>("Citta")
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
@ -85,6 +88,8 @@ namespace StandManager.Infrastructure.Migrations
b.HasIndex("AgenteId"); b.HasIndex("AgenteId");
b.HasIndex("CapoareaId");
b.HasIndex("IdUtenteCreazione"); b.HasIndex("IdUtenteCreazione");
b.HasIndex("IdUtenteModifica"); b.HasIndex("IdUtenteModifica");
@ -633,6 +638,9 @@ namespace StandManager.Infrastructure.Migrations
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<Guid?>("CapoareaId")
.HasColumnType("uniqueidentifier");
b.Property<string>("CodiceAgente") b.Property<string>("CodiceAgente")
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
@ -676,6 +684,8 @@ namespace StandManager.Infrastructure.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("CapoareaId");
b.HasIndex("IdUtenteCreazione"); b.HasIndex("IdUtenteCreazione");
b.HasIndex("IdUtenteModifica"); b.HasIndex("IdUtenteModifica");
@ -691,6 +701,10 @@ namespace StandManager.Infrastructure.Migrations
.WithMany() .WithMany()
.HasForeignKey("AgenteId"); .HasForeignKey("AgenteId");
b.HasOne("StandManager.Domain.Entita.Utente", "Capoarea")
.WithMany()
.HasForeignKey("CapoareaId");
b.HasOne("StandManager.Domain.Entita.Utente", "UtenteCreazione") b.HasOne("StandManager.Domain.Entita.Utente", "UtenteCreazione")
.WithMany() .WithMany()
.HasForeignKey("IdUtenteCreazione"); .HasForeignKey("IdUtenteCreazione");
@ -705,6 +719,8 @@ namespace StandManager.Infrastructure.Migrations
b.Navigation("Agente"); b.Navigation("Agente");
b.Navigation("Capoarea");
b.Navigation("TipologiaCliente"); b.Navigation("TipologiaCliente");
b.Navigation("UtenteCreazione"); b.Navigation("UtenteCreazione");
@ -946,6 +962,10 @@ namespace StandManager.Infrastructure.Migrations
modelBuilder.Entity("StandManager.Domain.Entita.Utente", b => modelBuilder.Entity("StandManager.Domain.Entita.Utente", b =>
{ {
b.HasOne("StandManager.Domain.Entita.Utente", "Capoarea")
.WithMany()
.HasForeignKey("CapoareaId");
b.HasOne("StandManager.Domain.Entita.Utente", "UtenteCreazione") b.HasOne("StandManager.Domain.Entita.Utente", "UtenteCreazione")
.WithMany() .WithMany()
.HasForeignKey("IdUtenteCreazione"); .HasForeignKey("IdUtenteCreazione");
@ -958,6 +978,8 @@ namespace StandManager.Infrastructure.Migrations
.WithMany("Utenti") .WithMany("Utenti")
.HasForeignKey("RuoloId"); .HasForeignKey("RuoloId");
b.Navigation("Capoarea");
b.Navigation("Ruolo"); b.Navigation("Ruolo");
b.Navigation("UtenteCreazione"); 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 IClienteService ClienteService{ get; set; }
public IDestinazioneService DestinazioneService{ get; set; } public IDestinazioneService DestinazioneService{ get; set; }
public IEventoService EventoService{ get; set; } public IEventoService EventoService{ get; set; }
public IFeatureService FeatureService{ get; set; }
public IInvitoEventoService InvitoEventoService{ get; set; } public IInvitoEventoService InvitoEventoService{ get; set; }
public IIscrizioneEventoService IscrizioneEventoService{ get; set; } public IIscrizioneEventoService IscrizioneEventoService{ get; set; }
public IPermissionService PermissionService{ get; set; }
public IReferenteService ReferenteService{ get; set; } public IReferenteService ReferenteService{ get; set; }
public IRuoloService RuoloService{ get; set; }
public ISezioneService SezioneService{ get; set; }
public ITipologiaClienteService TipologiaClienteService { get; set; } public ITipologiaClienteService TipologiaClienteService { get; set; }
public IUtenteService UtenteService { 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, public ManagerService(IUtenteService utenteService, IClienteService clienteService, IDestinazioneService destinazioneService, IEventoService eventoService,
IInvitoEventoService invitoEventoService, IIscrizioneEventoService iscrizioneEventoService, IReferenteService referenteService, IInvitoEventoService invitoEventoService, IIscrizioneEventoService iscrizioneEventoService, IReferenteService referenteService,
ITipologiaClienteService tipologiaClienteService) ITipologiaClienteService tipologiaClienteService, IFeatureService featureService, IPermissionService permissionService, IRuoloService ruoloService, ISezioneService sezioneService)
{ {
UtenteService = utenteService; UtenteService = utenteService;
ClienteService = clienteService; ClienteService = clienteService;
@ -16,14 +16,22 @@ public class ManagerService : IManagerService
IscrizioneEventoService = iscrizioneEventoService; IscrizioneEventoService = iscrizioneEventoService;
ReferenteService = referenteService; ReferenteService = referenteService;
TipologiaClienteService = tipologiaClienteService; TipologiaClienteService = tipologiaClienteService;
FeatureService = featureService;
PermissionService = permissionService;
RuoloService = ruoloService;
SezioneService = sezioneService;
} }
public IUtenteService UtenteService { get; set; } public IUtenteService UtenteService { get; set; }
public IClienteService ClienteService { get; set; } public IClienteService ClienteService { get; set; }
public IDestinazioneService DestinazioneService { get; set; } public IDestinazioneService DestinazioneService { get; set; }
public IEventoService EventoService { get; set; } public IEventoService EventoService { get; set; }
public IFeatureService FeatureService { get; set; }
public IInvitoEventoService InvitoEventoService{ get; set; } public IInvitoEventoService InvitoEventoService{ get; set; }
public IIscrizioneEventoService IscrizioneEventoService { get; set; } public IIscrizioneEventoService IscrizioneEventoService { get; set; }
public IPermissionService PermissionService { get; set; }
public IReferenteService ReferenteService { get; set; } public IReferenteService ReferenteService { get; set; }
public IRuoloService RuoloService { get; set; }
public ISezioneService SezioneService { get; set; }
public ITipologiaClienteService TipologiaClienteService { 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="container-xl">
<div class="row flex-column flex-md-row flex-fill align-items-center"> <div class="row flex-column flex-md-row flex-fill align-items-center">
<div class="col"> <div class="col">
<!-- BEGIN NAVBAR MENU --> <!-- BEGIN NAVBAR MENU -->
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item @GetActiveClass("/management")"> <NavigationItem currentUrl="@currentUrl" requiredUrl="/management" destination="/management" iconName="fa-home" title="Home"/>
<a class="nav-link" href="/management"> <NavigationItem currentUrl="@currentUrl" requiredUrl="/management/Utenti" destination="/management/Utenti" iconName="fa-user" title="Utenti"/>
<span class="nav-link-icon d-md-none d-lg-inline-block"> <NavigationItem currentUrl="@currentUrl" requiredUrl="/management/Clienti" destination="/management/Clienti" iconName="fa-address-card" title="Clienti"/>
<i class="fa-solid fa-house"></i> <NavigationItem currentUrl="@currentUrl" requiredUrl="/management/Eventi" destination="/management/Eventi" iconName="fa-calendar" title="Eventi"/>
</span> <NavigationItem currentUrl="@currentUrl" requiredUrl="/management/Ruoli" destination="/management/Ruoli" iconName="fa-lock" title="Ruoli"/>
<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>
</ul> </ul>
</div> </div>
</div> </div>
@ -99,20 +73,4 @@
base.OnInitializedAsync(); base.OnInitializedAsync();
currentUrl = NavManager.ToBaseRelativePath(NavManager.Uri); 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.Infrastructure.DAL.Context
@using StandManager.Model @using StandManager.Model
@using System.Security.Claims @using System.Security.Claims
@using Microsoft.EntityFrameworkCore
@using StandManager.Service.Interfaces @using StandManager.Service.Interfaces
@inject IHttpContextAccessor HttpContextAccessor @inject IHttpContextAccessor HttpContextAccessor
@ -66,7 +67,8 @@
/// </summary> /// </summary>
private async Task HandleValidSubmit(EditContext args) 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>(); var hasher = new PasswordHasher<Utente>();
if (user == null || if (user == null ||
@ -81,7 +83,8 @@
{ {
new Claim(ClaimTypes.Name, user.Email), new Claim(ClaimTypes.Name, user.Email),
new Claim(ClaimTypes.Role, "Admin"), 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); var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

View File

@ -169,18 +169,19 @@
@code { @code {
[Parameter] [Parameter]
public Guid? ClienteId { get; set; } public Guid? ClienteId { get; set; }
public Guid idClaim { get; set; }
[SupplyParameterFromForm] [SupplyParameterFromForm]
private ClienteViewModel cliente { get; set; } = new(); private ClienteViewModel cliente { get; set; } = new();
private IEnumerable<UtenteViewModel> agenti { get; set; } = new List<UtenteViewModel>(); private IEnumerable<UtenteViewModel> agenti { get; set; } = new List<UtenteViewModel>();
private List<TipologiaClienteViewModel> tipologiaCliente { get; set; } = new(); 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; RadzenDataGrid<DestinazioneViewModel> destinazioniGrid;
private string pageTitle => cliente?.Id == Guid.Empty ? "Nuovo cliente" : "Modifica cliente"; 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, Resizable = false,
Draggable = false, Draggable = false,
@ -194,7 +195,19 @@
/// </summary> /// </summary>
protected override async Task OnInitializedAsync() 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(); .Select(x => (UtenteViewModel)x).ToList();
var eUtils = new EnumUtils(); var eUtils = new EnumUtils();
tipologiaCliente = (await _managerService.TipologiaClienteService.RicercaQueryable(ordinamento: x => x.OrderBy(y => y.Nome))).Select(x => (TipologiaClienteViewModel)x).ToList(); tipologiaCliente = (await _managerService.TipologiaClienteService.RicercaQueryable(ordinamento: x => x.OrderBy(y => y.Nome))).Select(x => (TipologiaClienteViewModel)x).ToList();
@ -225,8 +238,6 @@
/// </summary> /// </summary>
private async Task onClienteSave() private async Task onClienteSave()
{ {
var idClaim = await MembershipUtils.GetUserId(auth);
var model = await _managerService.ClienteService.RicercaPer(x => x.Id == cliente.Id, solaLettura: false) var model = await _managerService.ClienteService.RicercaPer(x => x.Id == cliente.Id, solaLettura: false)
?? new Cliente() { Destinazioni = new List<Destinazione>() }; ?? 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] @attribute [Authorize]
@page "/management/Utenti" @page "/management/Utenti"
@using Microsoft.EntityFrameworkCore
@rendermode InteractiveServer @rendermode InteractiveServer
@ -35,8 +36,10 @@
<RadzenDataGridColumn Property="@nameof(Utente.Nome)" Title="Nome" Width="160px" /> <RadzenDataGridColumn Property="@nameof(Utente.Nome)" Title="Nome" Width="160px" />
<RadzenDataGridColumn Property="@nameof(Utente.Cognome)" Title="Cognome" Width="160px" /> <RadzenDataGridColumn Property="@nameof(Utente.Cognome)" Title="Cognome" Width="160px" />
<RadzenDataGridColumn Property="@nameof(Utente.Email)" Title="Mail" Width="200px" /> <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"> <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="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" /> <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(); 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> /// <summary>
@ -80,12 +86,15 @@
/// </summary> /// </summary>
private async Task DeleteRow(Utente user) 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) if (ok == true)
{ {
await _managerService.UtenteService.Elimina(user.Id, await MembershipUtils.GetUserId(auth)); 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}" @page "/management/Utenti/Modifica/{UserId:guid}"
@using Microsoft.AspNetCore.Identity @using Microsoft.AspNetCore.Identity
@using Microsoft.EntityFrameworkCore
@using StandManager.Model @using StandManager.Model
@inject AuthenticationStateProvider auth @inject AuthenticationStateProvider auth
@ -52,19 +53,29 @@
</div> </div>
<div class="row"> <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"> <div class="col-4 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Password</RadzenText> <RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Password</RadzenText>
<RadzenPassword Style="width: 100%" aria-label="Password" @bind-Value="@utente.Password" /> <RadzenPassword Style="width: 100%" aria-label="Password" @bind-Value="@utente.Password"/>
</div> </div>
</div> </div>
<div class="row"> <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"> <button type="button" class="btn btn-default w-100" @onclick="backToHome">
Annulla Annulla
</button> </button>
</div> </div>
<div class="col-3 mb-3"> <div class="col-4 mb-3">
<button type="submit" class="btn btn-primary w-100"> <button type="submit" class="btn btn-primary w-100">
Salva Salva
</button> </button>
@ -87,6 +98,8 @@
[SupplyParameterFromForm] [SupplyParameterFromForm]
private UtenteViewModel? utente { get; set; } = new(); 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"; private string pageTitle => utente?.Id == Guid.Empty ? "Nuovo utente" : "Modifica utente";
@ -97,9 +110,21 @@
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
if (UserId.GetValueOrDefault() != Guid.Empty) 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 else
utente = new UtenteViewModel(); 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> /// <summary>
@ -128,6 +153,9 @@
model.Password = hasher.HashPassword(model, utente.Password); model.Password = hasher.HashPassword(model, utente.Password);
} }
model.RuoloId = utente.RuoloId;
model.CapoareaId = utente.CapoareaId;
await _managerService.UtenteService.Salva(model, Guid.Parse(idClaim)); await _managerService.UtenteService.Salva(model, Guid.Parse(idClaim));
_navManager.NavigateTo("/management/Utenti"); _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; } public string Nome { get; set; }
[Required(ErrorMessage = "Il cognome è obbligatorio")] [Required(ErrorMessage = "Il cognome è obbligatorio")]
public string Cognome { get; set; } public string Cognome { get; set; }
public Guid RuoloId { get; set; }
public Guid CapoareaId { get; set; }
public string Info => $"{Nome} {Cognome}"; public string Info => $"{Nome} {Cognome}";
public static implicit operator UtenteViewModel(Utente? model) public static implicit operator UtenteViewModel(Utente? model)
@ -26,7 +28,9 @@ namespace StandManager.Model
Username = model.Username, Username = model.Username,
Email = model.Email, Email = model.Email,
Nome = model.Nome, 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()); 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());
}
} }