Quitar acceso admin a no permitidos

pull/3/head
Alvaro Puente Mella 2024-05-31 13:38:52 +02:00
parent 03accc5947
commit 4a86f36112
20 changed files with 210 additions and 15 deletions

View File

@ -18,6 +18,7 @@
"@angular/platform-browser": "^18.0.0",
"@angular/platform-browser-dynamic": "^18.0.0",
"@angular/router": "^18.0.0",
"jwt-decode": "^4.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "^0.14.6"
@ -8754,6 +8755,14 @@
"node >= 0.2.0"
]
},
"node_modules/jwt-decode": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
"integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
"engines": {
"node": ">=18"
}
},
"node_modules/karma": {
"version": "6.4.3",
"resolved": "https://registry.npmjs.org/karma/-/karma-6.4.3.tgz",

View File

@ -20,6 +20,7 @@
"@angular/platform-browser": "^18.0.0",
"@angular/platform-browser-dynamic": "^18.0.0",
"@angular/router": "^18.0.0",
"jwt-decode": "^4.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "^0.14.6"

View File

@ -17,7 +17,7 @@ const routes: Routes = [
{ path: 'dashboard', component: DashboardComponent },
{ path: 'admin', component: AdminComponent },
{ path: 'users', component: UsersComponent },
{ path: 'roles', component: RolesComponent },
{ path: 'user-groups', component: RolesComponent },
// otras rutas que usan el MainLayoutComponent
],
},

View File

@ -13,7 +13,7 @@
<button mat-flat-button color="primary">Buscar</button>
<button mat-flat-button color="primary">Calendario</button>
<button mat-flat-button color="primary">Ayuda</button>
<button mat-flat-button color="accent" routerLink="/admin">Admin</button>
<button mat-flat-button color="accent" routerLink="/admin" *ngIf="isSuperAdmin">Admin</button>
<button mat-flat-button color="warn" routerLink="/auth/login">Salir</button>
</div>

View File

@ -1,11 +1,26 @@
import { Component } from '@angular/core';
import {MatToolbarModule} from '@angular/material/toolbar';
import { Component, OnInit } from '@angular/core';
import {jwtDecode} from 'jwt-decode';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrl: './header.component.css',
styleUrls: ['./header.component.css'],
})
export class HeaderComponent {
export class HeaderComponent implements OnInit {
isSuperAdmin: boolean = false;
constructor() { }
ngOnInit(): void {
const token = localStorage.getItem('loginToken');
if (token) {
try {
const decodedToken: any = jwtDecode(token);
console.log('Decoded JWT:', decodedToken);
this.isSuperAdmin = decodedToken.roles.includes('ROLE_SUPER_ADMIN');
} catch (error) {
console.error('Error decoding JWT:', error);
}
}
}
}

View File

@ -1,10 +1,9 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-main-layout',
templateUrl: './main-layout.component.html',
styleUrl: './main-layout.component.css'
})
export class MainLayoutComponent {
}

View File

@ -3,7 +3,7 @@
<mat-icon>group</mat-icon>
<span>Usuarios</span>
</button>
<button mat-fab color="primary" class="fab-button" routerLink="/roles">
<button mat-fab color="primary" class="fab-button" routerLink="/user-groups">
<mat-icon>admin_panel_settings</mat-icon>
<span>Roles</span>
</button>

View File

@ -0,0 +1,10 @@
.role-form .form-field {
display: block;
margin-bottom: 10px; /* Puedes ajustar el valor para cambiar la separación */
}
.checkbox-group label {
display: block;
margin-bottom: 8px; /* Ajusta este valor según necesites */
}

View File

@ -0,0 +1,25 @@
<h1 mat-dialog-title>Añadir Rol (TBD)</h1>
<div mat-dialog-content>
<form class="role-form">
<mat-form-field class="form-field">
<mat-label>Nombre</mat-label>
<input matInput formControlName="rolename" required>
</mat-form-field>
<section class="example-section">
<h4>Permisos:</h4>
<p><mat-checkbox >Gestionar los usuarios</mat-checkbox></p>
<p><mat-checkbox >Configuración PXE</mat-checkbox></p>
<p><mat-checkbox >Imágenes de la consola web</mat-checkbox></p>
<p><mat-checkbox >Gestionar los distintos componentes</mat-checkbox></p>
<p><mat-checkbox >Crear imágenes</mat-checkbox></p>
<p><mat-checkbox >script de configuración del servidor</mat-checkbox></p>
<p><mat-checkbox >...</mat-checkbox></p>
</section>
</form>
</div>
<div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button>
<button mat-button>Añadir</button>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AddRoleModalComponent } from './add-role-modal.component';
describe('AddRoleModalComponent', () => {
let component: AddRoleModalComponent;
let fixture: ComponentFixture<AddRoleModalComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AddRoleModalComponent]
})
.compileComponents();
fixture = TestBed.createComponent(AddRoleModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,19 @@
import { HttpClient } from '@angular/common/http';
import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
@Component({
selector: 'app-add-role-modal',
templateUrl: './add-role-modal.component.html',
styleUrl: './add-role-modal.component.css'
})
export class AddRoleModalComponent {
constructor(
public dialogRef: MatDialogRef<AddRoleModalComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private http: HttpClient
) {}
onNoClick(): void {
this.dialogRef.close();
}
}

View File

@ -0,0 +1,8 @@
<h1 mat-dialog-title>Eliminar Rol</h1>
<div mat-dialog-content>
<p>¿Estás seguro que deseas eliminar el rol {{ data.name }}?</p>
</div>
<div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button>
<button mat-button (click)="onYesClick()">Eliminar</button>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DeleteRoleModalComponent } from './delete-role-modal.component';
describe('DeleteRoleModalComponent', () => {
let component: DeleteRoleModalComponent;
let fixture: ComponentFixture<DeleteRoleModalComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [DeleteRoleModalComponent]
})
.compileComponents();
fixture = TestBed.createComponent(DeleteRoleModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,40 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Component, EventEmitter, Inject, Output } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
@Component({
selector: 'app-delete-role-modal',
templateUrl: './delete-role-modal.component.html',
styleUrl: './delete-role-modal.component.css'
})
export class DeleteRoleModalComponent {
@Output() roleDeleted = new EventEmitter<void>();
constructor(
public dialogRef: MatDialogRef<DeleteRoleModalComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private http: HttpClient
) {}
onNoClick(): void {
this.dialogRef.close();
}
onYesClick(): void {
const apiUrl = `http://127.0.0.1:8080/user-groups/${this.data.uuid}`;
const headers = new HttpHeaders({
'Content-Type': 'application/ld+json'
});
this.http.delete(apiUrl, { headers: headers }).subscribe(
() => {
console.log('Role deleted successfully');
this.roleDeleted.emit();
this.dialogRef.close(true);
},
( error: any) => {
console.error('Error deleting role:', error);
// Agregar alguna lógica para manejar el error en la interfaz de usuario
}
);
}
}

View File

@ -7,9 +7,10 @@
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>Contraseña</mat-label>
<input matInput formControlName="password" required>
<input matInput formControlName="password" type="password" required>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-form-field class="form-field">
<mat-label>Rol</mat-label>
<mat-select formControlName="role">
<mat-option *ngFor="let group of userGroups" [value]="group['@id']">
@ -17,6 +18,16 @@
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>Organizational Units</mat-label>
<mat-select multiple formControlName="organizationalUnit">
<mat-option *ngFor="let unit of organizationalUnits" [value]="unit['@id']">
{{unit.name}}
</mat-option>
</mat-select>
</mat-form-field>
</form>
</div>

View File

@ -18,6 +18,7 @@ export class AddUserModalComponent implements OnInit {
@Output() userAdded = new EventEmitter<void>();
userForm: FormGroup;
userGroups: UserGroup[] = [];
organizationalUnits: any[] = [];
constructor(
public dialogRef: MatDialogRef<AddUserModalComponent>,
@ -28,7 +29,8 @@ export class AddUserModalComponent implements OnInit {
this.userForm = this.fb.group({
username: ['', Validators.required],
password: ['', Validators.required],
role: ['', Validators.required], // Control para el permiso seleccionado
role: ['', Validators.required],
organizationalUnit: [[], Validators.required]
});
}
@ -36,6 +38,10 @@ export class AddUserModalComponent implements OnInit {
this.userService.getUserGroups().subscribe((data) => {
this.userGroups = data['hydra:member'];
});
this.userService.getOrganizationalUnits().subscribe((data) => {
this.organizationalUnits = data['hydra:member'];
});
}
onNoClick(): void {
@ -46,7 +52,7 @@ export class AddUserModalComponent implements OnInit {
if (this.userForm.valid) {
const userPayload = {
username: this.userForm.value.username,
allowedOrganizationalUnits: [],
allowedOrganizationalUnits: this.userForm.value.organizationalUnit,
password: this.userForm.value.password,
enabled: true,
userGroups: [this.userForm.value.role ]

View File

@ -7,7 +7,7 @@
</mat-form-field>
<mat-form-field class="form-field">
<mat-label>Contraseña</mat-label>
<input matInput formControlName="password" >
<input matInput formControlName="password" type="password">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Rol</mat-label>

View File

@ -27,7 +27,7 @@ export class UsersComponent implements OnInit {
{
columnDef: 'allowedOrganizationalUnits',
header: 'Unidades Organizacionales Permitidas',
cell: (user: any) => `${user.allowedOrganizationalUnits.join(', ')}`
cell: (user: any) => `${user.allowedOrganizationalUnits.map((unit: { name: any; }) => unit.name).join(', ')}`
},
{
columnDef: 'roles',
@ -46,6 +46,7 @@ export class UsersComponent implements OnInit {
loadUsers() {
this.userService.getUsers().subscribe(response => {
this.dataSource.data = response['hydra:member'];
console.log(this.dataSource.data);
});
}

View File

@ -45,4 +45,9 @@ export class UserService {
getUsers(): Observable<any> {
return this.http.get<any>(`${this.apiUrl}/users?page=1&itemsPerPage=30`);
}
getOrganizationalUnits(): Observable<any> {
return this.http.get<any>(`${this.apiUrl}/organizational-units?page=1&itemsPerPage=30`);
}
}