add linked ACE to user and group detail page

This commit is contained in:
Elise Lebeau 2023-09-29 11:10:48 +02:00
parent ed4fd7c06a
commit db66a09e3b
11 changed files with 207 additions and 58 deletions

View File

@ -73,6 +73,8 @@ import {AceManagementComponent} from "@components/ace-management/ace-management.
import {ResourcePoolsManagementComponent} from "@components/resource-pools-management/resource-pools-management.component";
import {ResourcePoolDetailsComponent} from "@components/resource-pool-details/resource-pool-details.component";
import {ResourcePoolsResolver} from "@resolvers/resource-pools.resolver";
import {GroupAcesResolver} from "@resolvers/group-ace.resolver.ts.resolver";
import {UserAcesResolver} from "@resolvers/user-aces.resolver";
const routes: Routes = [
{
@ -101,6 +103,7 @@ const routes: Routes = [
resolve: {
user: UserDetailResolver,
groups: UserGroupsResolver,
aces: UserAcesResolver,
controller: ControllerResolve},
},
{
@ -262,7 +265,7 @@ const routes: Routes = [
members: GroupMembersResolver,
controller: ControllerResolve,
group: GroupResolver,
roles: GroupRoleResolver
aces: GroupAcesResolver
}
},
{

View File

@ -56,15 +56,34 @@
[pageSizeOptions]="[5, 20, 50, 100]"></mat-paginator>
</div>
</mat-tab>
<mat-tab label="Roles">
<div><button mat-button (click)="openAddRoleDialog()" ><mat-icon>group_add</mat-icon></button></div>
<div *ngFor="let role of roles" class="roles">
<div>{{role.name}}</div>
<div>
<button mat-button (click)="openRemoveRoleDialog(role)">
<mat-icon>delete</mat-icon>
</button>
</div>
<mat-tab label="Aces">
<div class="default-content">
<table mat-table [dataSource]="aceDatasource" class="mat-elevation-z8">
<ng-container matColumnDef="endpoint">
<th mat-header-cell *matHeaderCellDef> Endpoint </th>
<td mat-cell *matCellDef="let element">{{element.endpoint_name}}</td>
</ng-container>
<ng-container matColumnDef="role">
<th mat-header-cell *matHeaderCellDef > Role </th>
<td mat-cell *matCellDef="let element"> {{element.role_name}} </td>
</ng-container>
<ng-container matColumnDef="propagate">
<th mat-header-cell *matHeaderCellDef > Propagate </th>
<td mat-cell *matCellDef="let element"> {{element.propagate}} </td>
</ng-container>
<ng-container matColumnDef="allowed">
<th mat-header-cell *matHeaderCellDef> Allowed </th>
<td mat-cell *matCellDef="let element"> {{element.allowed}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="aceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: aceDisplayedColumns;"></tr>
</table>
</div>
</mat-tab>
</mat-tab-group>

View File

@ -1,3 +1,7 @@
table {
width: 100%;
}
.main {
display: flex;
justify-content: space-around;

View File

@ -22,8 +22,14 @@ import {RemoveToGroupDialogComponent} from "@components/group-details/remove-to-
import {GroupService} from "@services/group.service";
import {ToasterService} from "@services/toaster.service";
import {PageEvent} from "@angular/material/paginator";
import {ACE, ACEDetailed, AceType} from "@models/api/ACE";
import {UserService} from "@services/user.service";
import {RoleService} from "@services/role.service";
import {Role} from "@models/api/role";
import {AddRoleToGroupComponent} from "@components/group-details/add-role-to-group/add-role-to-group.component";
import {AclService} from "@services/acl.service";
import {Endpoint} from "@models/api/endpoint";
import {interval} from "rxjs";
import {MatTableDataSource} from "@angular/material/table";
@Component({
selector: 'app-group-details',
@ -37,28 +43,43 @@ export class GroupDetailsComponent implements OnInit {
editGroupForm: UntypedFormGroup;
pageEvent: PageEvent | undefined;
searchMembers: string;
roles: Role[];
aces: ACE[];
aceDatasource = new MatTableDataSource<ACEDetailed>();
public aceDisplayedColumns = ['endpoint', 'role', 'propagate', 'allowed'];
constructor(private route: ActivatedRoute,
private dialog: MatDialog,
private groupService: GroupService,
private toastService: ToasterService) {
private toastService: ToasterService,
private aclService: AclService,
private roleService: RoleService) {
this.editGroupForm = new UntypedFormGroup({
groupname: new UntypedFormControl(''),
});
this.route.data.subscribe((d: { controller: Controller; group: Group, members: User[], roles: Role[] }) => {
this.route.data.subscribe((d: { controller: Controller; group: Group, members: User[], aces: ACE[] }) => {
this.controller = d.controller;
this.group = d.group;
this.roles = d.roles;
this.aces = d.aces;
this.members = d.members.sort((a: User, b: User) => a.username.toLowerCase().localeCompare(b.username.toLowerCase()));
this.editGroupForm.setValue({groupname: this.group.name});
});
}
ngOnInit(): void {
this.roleService.get(this.controller).subscribe((roles: Role[]) => {
this.aclService.getEndpoints(this.controller).subscribe((endps: Endpoint[]) => {
this.aceDatasource.data = this.aces.map((ace: ACE) => {
const endpoint = endps.filter((endp: Endpoint) => endp.endpoint === ace.path)[0]
const role = roles.filter((r: Role) => r.role_id === ace.role_id)[0]
return {...ace, endpoint_name: endpoint.name, role_name: role.name}
})
})
})
}
@ -72,18 +93,6 @@ export class GroupDetailsComponent implements OnInit {
});
}
openAddRoleDialog() {
this.dialog
.open<AddRoleToGroupComponent>(AddRoleToGroupComponent,
{
width: '700px', height: '500px',
data: {controller: this.controller, group: this.group}
})
.afterClosed()
.subscribe(() => {
this.reloadRoles();
});
}
openAddUserDialog() {
this.dialog
.open<AddUserToGroupDialogComponent>(AddUserToGroupDialogComponent,
@ -117,24 +126,6 @@ export class GroupDetailsComponent implements OnInit {
}
openRemoveRoleDialog(role: Role) {
this.dialog.open<RemoveToGroupDialogComponent>(RemoveToGroupDialogComponent,
{width: '500px', height: '200px', data: {name: role.name}})
.afterClosed()
.subscribe((confirm: string) => {
if (confirm) {
this.groupService.removeRole(this.controller, this.group, role)
.subscribe(() => {
this.toastService.success(`Role ${role.name} was removed`);
this.reloadRoles();
},
(error) => {
this.toastService.error(`Error while removing role ${role.name} from ${this.group.name}`);
console.log(error);
});
}
});
}
reloadMembers() {
this.groupService.getGroupMember(this.controller, this.group.user_group_id)
@ -143,10 +134,4 @@ export class GroupDetailsComponent implements OnInit {
});
}
reloadRoles() {
this.groupService.getGroupRole(this.controller, this.group.user_group_id)
.subscribe((roles: Role[]) => {
this.roles = roles;
});
}
}

View File

@ -8,7 +8,7 @@
[routerLink]="['/controller', controller.id, 'management', 'resourcePools']">
<mat-icon aria-label="back to resource pools management">keyboard_arrow_left</mat-icon>
</a>
<h1 class="col">role {{pool.name}} details</h1>
<h1 class="col">Pool {{pool.name}} details</h1>
</div>
<div class="main">
<div class="details">
@ -23,7 +23,7 @@
<div>uuid: {{pool.resource_pool_id}}</div>
<div mat-dialog-actions class="button-div">
<button mat-button (click)="onUpdate()" tabindex="2" mat-raised-button color="primary">
update role
update pool
</button>
</div>
</div>

View File

@ -80,6 +80,37 @@
</ul>
</div>
</mat-tab>
<mat-tab label="Aces">
<div class="default-content">
<table mat-table [dataSource]="aceDatasource" class="mat-elevation-z8">
<ng-container matColumnDef="endpoint">
<th mat-header-cell *matHeaderCellDef> Endpoint </th>
<td mat-cell *matCellDef="let element">{{element.endpoint_name}}</td>
</ng-container>
<ng-container matColumnDef="role">
<th mat-header-cell *matHeaderCellDef > Role </th>
<td mat-cell *matCellDef="let element"> {{element.role_name}} </td>
</ng-container>
<ng-container matColumnDef="propagate">
<th mat-header-cell *matHeaderCellDef > Propagate </th>
<td mat-cell *matCellDef="let element"> {{element.propagate}} </td>
</ng-container>
<ng-container matColumnDef="allowed">
<th mat-header-cell *matHeaderCellDef> Allowed </th>
<td mat-cell *matCellDef="let element"> {{element.allowed}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="aceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: aceDisplayedColumns;"></tr>
</table>
</div>
</mat-tab>
</mat-tab-group>
</div>

View File

@ -5,3 +5,7 @@
.button-div {
float: right;
}
table {
width: 100%;
}

View File

@ -8,11 +8,15 @@ import {Controller} from "@models/controller";
import {userNameAsyncValidator} from "@components/user-management/add-user-dialog/userNameAsyncValidator";
import {userEmailAsyncValidator} from "@components/user-management/add-user-dialog/userEmailAsyncValidator";
import {ActivatedRoute, Router} from "@angular/router";
import {Role} from "@models/api/role";
import {AddUserDialogComponent} from "@components/user-management/add-user-dialog/add-user-dialog.component";
import {MatDialog} from "@angular/material/dialog";
import {ChangeUserPasswordComponent} from "@components/user-management/user-detail/change-user-password/change-user-password.component";
import {RemoveToGroupDialogComponent} from "@components/group-details/remove-to-group-dialog/remove-to-group-dialog.component";
import {ACE, ACEDetailed} from "@models/api/ACE";
import {MatTableDataSource} from "@angular/material/table";
import {AclService} from "@services/acl.service";
import {RoleService} from "@services/role.service";
import {Role} from "@models/api/role";
import {Endpoint} from "@models/api/endpoint";
@Component({
selector: 'app-user-detail',
@ -27,12 +31,17 @@ export class UserDetailComponent implements OnInit {
controller: Controller;
user_id: string;
changingPassword: boolean = false;
aces: ACE[];
aceDatasource = new MatTableDataSource<ACEDetailed>();
public aceDisplayedColumns = ['endpoint', 'role', 'propagate', 'allowed'];
constructor(public userService: UserService,
private toasterService: ToasterService,
private route: ActivatedRoute,
private router: Router,
public dialog: MatDialog) {
public dialog: MatDialog,
private aclService: AclService,
private roleService: RoleService) {
}
@ -40,11 +49,22 @@ export class UserDetailComponent implements OnInit {
this.controller = this.route.snapshot.data['controller'];
if (!this.controller) this.router.navigate(['/controllers']);
this.route.data.subscribe((d: { controller: Controller; user: User, groups: Group[]}) => {
this.route.data.subscribe((d: { controller: Controller; user: User, groups: Group[], aces: ACE[]}) => {
this.user = d.user;
this.user_id = this.user.user_id;
this.groups = d.groups;
this.aces = d.aces;
this.initForm();
this.roleService.get(this.controller).subscribe((roles: Role[]) => {
this.aclService.getEndpoints(this.controller).subscribe((endps: Endpoint[]) => {
this.aceDatasource.data = this.aces.map((ace: ACE) => {
const endpoint = endps.filter((endp: Endpoint) => endp.endpoint === ace.path)[0]
const role = roles.filter((r: Role) => r.role_id === ace.role_id)[0]
return {...ace, endpoint_name: endpoint.name, role_name: role.name}
})
})
})
});
}

View File

@ -3,6 +3,10 @@ export enum AceType {
user = "user"
}
export interface ACEDetailed extends ACE{
endpoint_name: string;
role_name: string;
}
export interface ACE {
ace_id: string;

View File

@ -0,0 +1,41 @@
import { Injectable } from '@angular/core';
import {
Router, Resolve,
RouterStateSnapshot,
ActivatedRouteSnapshot
} from '@angular/router';
import {Observable,Subscriber} from 'rxjs';
import {ACE} from "../models/api/ACE";
import {ControllerService} from "../services/controller.service";
import {AclService} from "../services/acl.service";
import {Controller} from "../models/controller";
import {UserService} from "@services/user.service";
import {GroupService} from "@services/group.service";
import {RoleService} from "@services/role.service";
@Injectable({
providedIn: 'root'
})
export class GroupAcesResolver implements Resolve<ACE[]> {
constructor(private controllerService: ControllerService,
private aceService: AclService) {
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<ACE[]> {
return new Observable<ACE[]>((subscriber: Subscriber<ACE[]>) => {
const controllerId = route.paramMap.get('controller_id');
const groupId = route.paramMap.get('user_group_id');
this.controllerService.get(+controllerId).then((controller: Controller) => {
this.aceService.list(controller).subscribe((aces: ACE[]) => {
const filter = aces.filter((ace: ACE) => ace.group_id === groupId)
subscriber.next(filter);
subscriber.complete()
})
});
});
}
}

View File

@ -0,0 +1,38 @@
import { Injectable } from '@angular/core';
import {
Router, Resolve,
RouterStateSnapshot,
ActivatedRouteSnapshot
} from '@angular/router';
import {Observable, of, Subscriber} from 'rxjs';
import {ACE} from "@models/api/ACE";
import {Controller} from "@models/controller";
import {ControllerService} from "@services/controller.service";
import {AclService} from "@services/acl.service";
@Injectable({
providedIn: 'root'
})
export class UserAcesResolver implements Resolve<ACE[]> {
constructor(private controllerService: ControllerService,
private aceService: AclService) {
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<ACE[]> {
return new Observable<ACE[]>((subscriber: Subscriber<ACE[]>) => {
const controllerId = route.paramMap.get('controller_id');
const userId = route.paramMap.get('user_id');
this.controllerService.get(+controllerId).then((controller: Controller) => {
this.aceService.list(controller).subscribe((aces: ACE[]) => {
const filter = aces.filter((ace: ACE) => ace.user_id === userId)
subscriber.next(filter);
subscriber.complete()
})
});
});
}
}