Group details, can add role to group

This commit is contained in:
Sylvain MATHIEU 2022-01-11 11:20:48 +01:00
parent 920154e7b9
commit 65172c18b5
21 changed files with 449 additions and 89 deletions

View File

@ -59,13 +59,15 @@ import {LoggedUserComponent} from './components/users/logged-user/logged-user.co
import {GroupManagementComponent} from "./components/group-management/group-management.component";
import {GroupDetailsComponent} from "@components/group-details/group-details.component";
import {UserDetailComponent} from "@components/user-management/user-detail/user-detail.component";
import {GroupDetailsResolver} from "@resolvers/group-details.resolver";
import {GroupMembersResolver} from "@resolvers/group-members.resolver";
import {ManagementComponent} from "@components/management/management.component";
import {RoleManagementComponent} from "@components/role-management/role-management.component";
import {RoleDetailComponent} from "@components/role-management/role-detail/role-detail.component";
import {RoleDetailResolver} from "@resolvers/role-detail.resolver";
import {PermissionEditorComponent} from "@components/role-management/role-detail/permission-editor/permission-editor.component";
import {PermissionResolver} from "@resolvers/permission.resolver";
import {GroupResolver} from "@resolvers/group.resolver";
import {GroupRoleResolver} from "@resolvers/group-role.resolver";
const routes: Routes = [
{
@ -244,7 +246,10 @@ const routes: Routes = [
path: 'server/:server_id/management/groups/:user_group_id',
component: GroupDetailsComponent,
resolve: {
group: GroupDetailsResolver
members: GroupMembersResolver,
server: ServerResolve,
group: GroupResolver,
roles: GroupRoleResolver
}
},
{

View File

@ -283,7 +283,7 @@ import { DeleteUserDialogComponent } from './components/user-management/delete-u
import { GroupDetailsComponent } from './components/group-details/group-details.component';
import { UserDetailComponent } from './components/user-management/user-detail/user-detail.component';
import { AddUserToGroupDialogComponent } from './components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component';
import { RemoveUserToGroupDialogComponent } from './components/group-details/remove-user-to-group-dialog/remove-user-to-group-dialog.component';
import { RemoveToGroupDialogComponent } from '@components/group-details/remove-to-group-dialog/remove-to-group-dialog.component';
import { PaginatorPipe } from './components/group-details/paginator.pipe';
import { MembersFilterPipe } from './components/group-details/members-filter.pipe';
import { ManagementComponent } from './components/management/management.component';
@ -295,6 +295,7 @@ import { RoleDetailComponent } from './components/role-management/role-detail/ro
import { PermissionEditorComponent } from './components/role-management/role-detail/permission-editor/permission-editor.component';
import { EditablePermissionComponent } from './components/role-management/role-detail/permission-editor/editable-permission/editable-permission.component';
import { PermissionEditorValidateDialogComponent } from './components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component';
import { AddRoleToGroupComponent } from './components/group-details/add-role-to-group/add-role-to-group.component';
@NgModule({
declarations: [
@ -493,7 +494,7 @@ import { PermissionEditorValidateDialogComponent } from './components/role-manag
GroupDetailsComponent,
UserDetailComponent,
AddUserToGroupDialogComponent,
RemoveUserToGroupDialogComponent,
RemoveToGroupDialogComponent,
PaginatorPipe,
MembersFilterPipe,
ManagementComponent,
@ -505,6 +506,7 @@ import { PermissionEditorValidateDialogComponent } from './components/role-manag
PermissionEditorComponent,
EditablePermissionComponent,
PermissionEditorValidateDialogComponent,
AddRoleToGroupComponent,
],
imports: [
BrowserModule,

View File

@ -0,0 +1,15 @@
<div class="title">
<h3>Add Role To group: {{data.group.name}}</h3>
</div>
<div class="filter">
<mat-form-field class="input-field">
<mat-label>Search user </mat-label>
<input matInput type="text" [(ngModel)]="searchText" (keydown)="onSearch()">
</mat-form-field>
</div>
<div class="userList" *ngFor="let role of displayedRoles | async">
<div>{{role.name}}</div>
<mat-icon (click)="addRole(role)" *ngIf="!loading">add</mat-icon>
<mat-spinner *ngIf="loading"></mat-spinner>
</div>

View File

@ -0,0 +1,35 @@
:host {
display: flex;
flex-direction: column;
width: 100%;
}
.title {
width: 100%;
text-align: center;
}
.filter {
display: flex;
width: 600px;
justify-content: center;
margin-bottom: 50px;
}
mat-form-field {
width: 600px;
}
input {
width: 100%;
}
.userList {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
mat-spinner {
width: 36px;
}

View File

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

View File

@ -0,0 +1,78 @@
import {Component, Inject, OnInit} from '@angular/core';
import {BehaviorSubject, forkJoin, timer} from "rxjs";
import {User} from "@models/users/user";
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {Server} from "@models/server";
import {Group} from "@models/groups/group";
import {UserService} from "@services/user.service";
import {GroupService} from "@services/group.service";
import {ToasterService} from "@services/toaster.service";
import {Role} from "@models/api/role";
import {RoleService} from "@services/role.service";
@Component({
selector: 'app-add-role-to-group',
templateUrl: './add-role-to-group.component.html',
styleUrls: ['./add-role-to-group.component.scss']
})
export class AddRoleToGroupComponent implements OnInit {
roles = new BehaviorSubject<Role[]>([]);
displayedRoles = new BehaviorSubject<Role[]>([]);
searchText: string;
loading = false;
constructor(private dialog: MatDialogRef<AddRoleToGroupComponent>,
@Inject(MAT_DIALOG_DATA) public data: { server: Server; group: Group },
private groupService: GroupService,
private roleService: RoleService,
private toastService: ToasterService) {
}
ngOnInit(): void {
this.getRoles();
}
onSearch() {
timer(500)
.subscribe(() => {
const displayedUsers = this.roles.value.filter((roles: Role) => {
return roles.name.includes(this.searchText);
});
this.displayedRoles.next(displayedUsers);
});
}
getRoles() {
forkJoin([
this.roleService.get(this.data.server),
this.groupService.getGroupRole(this.data.server, this.data.group.user_group_id)
]).subscribe((results) => {
const [globalRoles, groupRoles] = results;
const roles = globalRoles.filter((role: Role) => {
return !groupRoles.find((r: Role) => r.role_id === role.role_id);
});
this.roles.next(roles);
this.displayedRoles.next(roles);
});
}
addRole(role: Role) {
this.loading = true;
this.groupService
.addRoleToGroup(this.data.server, this.data.group, role)
.subscribe(() => {
this.toastService.success(`role ${role.name} was added`);
this.getRoles();
this.loading = false;
}, (err) => {
console.log(err);
this.toastService.error(`error while adding role ${role.name} to group ${this.data.group.name}`);
this.loading = false;
});
}
}

View File

@ -29,3 +29,7 @@ input {
justify-content: space-between;
margin-bottom: 10px;
}
mat-spinner {
width: 36px;
}

View File

@ -10,50 +10,63 @@
</a>
<h1 class="col">Groups {{group.name}} details</h1>
</div>
<div class="main">
<div class="details">
<mat-tab-group>
<mat-tab label="Details" class="details">
<div>
<mat-form-field>
<mat-label>Group name:</mat-label>
<input matInput type="text" [ngModel]="group.name">
</mat-form-field>
</div>
<div>Creation date: {{group.created_at}}</div>
<div>Last update Date: {{group.updated_at}}</div>
<div>UUID: {{group.user_group_id}}</div>
<div>
<mat-checkbox [checked]="group.is_builtin" disabled>Is build in</mat-checkbox>
</div>
<div mat-dialog-actions class="button-div">
<button mat-button (click)="onUpdate()" tabindex="2" mat-raised-button color="primary"
[disabled]="!editGroupForm.valid">
Update Group
</button>
</div>
</div>
<mat-divider [vertical]="true"></mat-divider>
<div class="members">
<div>
<div class="title">
<div>Members:</div>
<div>
<mat-form-field>
<mat-label>Group name:</mat-label>
<input matInput type="text" [ngModel]="group.name">
</mat-form-field>
</div>
<mat-icon (click)="openAddUserDialog()" class="clickable">person_add</mat-icon>
</div>
<div class="search">
<mat-form-field>
<input matInput placeholder="filter members" [(ngModel)]="searchMembers"/>
</mat-form-field>
</div>
<div *ngFor="let user of members | membersFilter: searchMembers | paginator: pageEvent">
<a href="/server/{{server.id}}/management/users/{{user.user_id}}">
<div>{{user.username}}</div>
</a>
<mat-icon class="clickable" (click)="openRemoveUserDialog(user)">delete</mat-icon>
</div>
<mat-paginator [length]="members.length" (page)="pageEvent = $event"
[pageSizeOptions]="[5, 20, 50, 100]"></mat-paginator>
</div>
</div>
<div>
<mat-checkbox [checked]="group.is_builtin" disabled>Is build in</mat-checkbox>
</div>
<div mat-dialog-actions class="button-div">
<button mat-button (click)="onUpdate()" tabindex="2" mat-raised-button color="primary"
[disabled]="!editGroupForm.valid">
Update Group
</button>
</div>
</div>
<div>
<div>Creation date: {{group.created_at}}</div>
<div>Last update Date: {{group.updated_at}}</div>
<div>UUID: {{group.user_group_id}}</div>
</div>
</mat-tab>
<mat-tab label="Members">
<div class="members">
<div>
<mat-icon (click)="openAddUserDialog()" class="clickable">person_add</mat-icon>
</div>
<div class="search">
<mat-form-field>
<input matInput placeholder="filter members" [(ngModel)]="searchMembers"/>
</mat-form-field>
</div>
<div *ngFor="let user of members | membersFilter: searchMembers | paginator: pageEvent">
<a href="/server/{{server.id}}/management/users/{{user.user_id}}">
<div>{{user.username}}</div>
</a>
<mat-icon class="clickable" (click)="openRemoveUserDialog(user)">delete</mat-icon>
</div>
<mat-paginator [length]="members.length" (page)="pageEvent = $event"
[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>
</div>
</mat-tab>
</mat-tab-group>
</div>
</div>

View File

@ -4,14 +4,12 @@
}
.details {
width: 30vw;
display: flex;
flex-direction: column;
justify-content: center;
}
.members {
width: 30vw;
display: flex;
flex-direction: column;
justify-content: stretch;
@ -28,11 +26,6 @@
cursor: pointer;
}
.members .title {
font-size: 2em;
text-decoration: underline;
}
.details > div {
margin-bottom: 20px;
}
@ -50,3 +43,9 @@
mat-form-field {
width: 100%;
}
.roles {
display: flex;
flex-direction: row;
justify-content: space-between;
}

View File

@ -10,18 +10,20 @@
*
* Author: Sylvain MATHIEU, Elise LEBEAU
*/
import {Component, Inject, OnInit} from '@angular/core';
import {ActivatedRoute, Router} from "@angular/router";
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from "@angular/router";
import {Server} from "@models/server";
import {Group} from "@models/groups/group";
import {User} from "@models/users/user";
import {FormControl, FormGroup} from "@angular/forms";
import {MatDialog} from "@angular/material/dialog";
import {AddUserToGroupDialogComponent} from "@components/group-details/add-user-to-group-dialog/add-user-to-group-dialog.component";
import {RemoveUserToGroupDialogComponent} from "@components/group-details/remove-user-to-group-dialog/remove-user-to-group-dialog.component";
import {RemoveToGroupDialogComponent} from "@components/group-details/remove-to-group-dialog/remove-to-group-dialog.component";
import {GroupService} from "@services/group.service";
import {ToasterService} from "@services/toaster.service";
import {PageEvent} from "@angular/material/paginator";
import {Role} from "@models/api/role";
import {AddRoleToGroupComponent} from "@components/group-details/add-role-to-group/add-role-to-group.component";
@Component({
selector: 'app-group-details',
@ -35,6 +37,7 @@ export class GroupDetailsComponent implements OnInit {
editGroupForm: FormGroup;
pageEvent: PageEvent | undefined;
searchMembers: string;
roles: Role[];
constructor(private route: ActivatedRoute,
private dialog: MatDialog,
@ -45,15 +48,14 @@ export class GroupDetailsComponent implements OnInit {
groupname: new FormControl(''),
});
this.route.data.subscribe((d: { group: { server: Server; group: Group, users: User[] } }) => {
this.route.data.subscribe((d: { server: Server; group: Group, members: User[], roles: Role[] }) => {
this.server = d.group.server;
this.group = d.group.group;
this.members = d.group.users.sort((a: User, b: User) => a.username.toLowerCase().localeCompare(b.username.toLowerCase()));
this.server = d.server;
this.group = d.group;
this.roles = d.roles;
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 {
@ -70,6 +72,18 @@ export class GroupDetailsComponent implements OnInit {
});
}
openAddRoleDialog() {
this.dialog
.open<AddRoleToGroupComponent>(AddRoleToGroupComponent,
{
width: '700px', height: '500px',
data: {server: this.server, group: this.group}
})
.afterClosed()
.subscribe(() => {
this.reloadRoles();
});
}
openAddUserDialog() {
this.dialog
.open<AddUserToGroupDialogComponent>(AddUserToGroupDialogComponent,
@ -84,14 +98,12 @@ export class GroupDetailsComponent implements OnInit {
}
openRemoveUserDialog(user: User) {
this.dialog
.open<RemoveUserToGroupDialogComponent>(RemoveUserToGroupDialogComponent,
{width: '500px', height: '200px', data: {user}})
this.dialog.open<RemoveToGroupDialogComponent>(RemoveToGroupDialogComponent,
{width: '500px', height: '200px', data: {name: user.username}})
.afterClosed()
.subscribe((userToRemove: User) => {
console.log(userToRemove);
if (userToRemove) {
this.groupService.removeUser(this.server, this.group, userToRemove)
.subscribe((confirm: boolean) => {
if (confirm) {
this.groupService.removeUser(this.server, this.group, user)
.subscribe(() => {
this.toastService.success(`User ${user.username} was removed`);
this.reloadMembers();
@ -104,10 +116,37 @@ 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.server, 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.server, this.group.user_group_id)
.subscribe((members: User[]) => {
this.members = members;
});
}
reloadRoles() {
this.groupService.getGroupRole(this.server, this.group.user_group_id)
.subscribe((roles: Role[]) => {
this.roles = roles;
});
}
}

View File

@ -1,6 +1,6 @@
<div class="header">
<div>Confirm ?</div>
<div>Removing user: {{data.user.username}}</div>
<div>Removing: {{data.name}}</div>
</div>
<div class="button">
<button mat-button mat-raised-button color="primary" (click)="onCancel()">No, cancel</button>

View File

@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RemoveUserToGroupDialogComponent } from './remove-user-to-group-dialog.component';
import { RemoveToGroupDialogComponent } from './remove-to-group-dialog.component';
describe('RemoveUserToGroupDialogComponent', () => {
let component: RemoveUserToGroupDialogComponent;
let fixture: ComponentFixture<RemoveUserToGroupDialogComponent>;
let component: RemoveToGroupDialogComponent;
let fixture: ComponentFixture<RemoveToGroupDialogComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ RemoveUserToGroupDialogComponent ]
declarations: [ RemoveToGroupDialogComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(RemoveUserToGroupDialogComponent);
fixture = TestBed.createComponent(RemoveToGroupDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

View File

@ -0,0 +1,25 @@
import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {User} from "@models/users/user";
@Component({
selector: 'app-remove-user-to-group-dialog',
templateUrl: './remove-to-group-dialog.component.html',
styleUrls: ['./remove-to-group-dialog.component.scss']
})
export class RemoveToGroupDialogComponent implements OnInit {
constructor(private dialogRef: MatDialogRef<RemoveToGroupDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: { name: string }) { }
ngOnInit(): void {
}
onCancel() {
this.dialogRef.close(false);
}
onConfirm() {
this.dialogRef.close(true);
}
}

View File

@ -1,13 +1,13 @@
import { TestBed } from '@angular/core/testing';
import { GroupDetailsResolver } from './group-details.resolver';
import { GroupMembersResolver } from './group-members.resolver';
describe('GroupDetailsResolver', () => {
let resolver: GroupDetailsResolver;
let resolver: GroupMembersResolver;
beforeEach(() => {
TestBed.configureTestingModule({});
resolver = TestBed.inject(GroupDetailsResolver);
resolver = TestBed.inject(GroupMembersResolver);
});
it('should be created', () => {

View File

@ -0,0 +1,38 @@
import {Injectable} from '@angular/core';
import {
Resolve,
RouterStateSnapshot,
ActivatedRouteSnapshot
} from '@angular/router';
import {Observable, Subscriber} from 'rxjs';
import {ServerService} from "../services/server.service";
import {GroupService} from "../services/group.service";
import {Server} from "../models/server";
import {Group} from "../models/groups/group";
import {User} from "../models/users/user";
@Injectable({
providedIn: 'root'
})
export class GroupMembersResolver implements Resolve<User[]> {
constructor(private serverService: ServerService,
private groupService: GroupService) {
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<User[]> {
return new Observable<User[]>((subscriber: Subscriber<User[]>) => {
const serverId = route.paramMap.get('server_id');
const groupId = route.paramMap.get('user_group_id');
this.serverService.get(+serverId).then((server: Server) => {
this.groupService.getGroupMember(server, groupId).subscribe((users: User[]) => {
subscriber.next(users);
subscriber.complete();
});
});
});
}
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { GroupRoleResolver } from './group-role.resolver';
describe('GroupRoleResolver', () => {
let resolver: GroupRoleResolver;
beforeEach(() => {
TestBed.configureTestingModule({});
resolver = TestBed.inject(GroupRoleResolver);
});
it('should be created', () => {
expect(resolver).toBeTruthy();
});
});

View File

@ -10,7 +10,7 @@
*
* Author: Sylvain MATHIEU, Elise LEBEAU
*/
import { Injectable } from '@angular/core';
import {Injectable} from '@angular/core';
import {
Router, Resolve,
RouterStateSnapshot,
@ -19,32 +19,30 @@ import {
import {Observable, of, Subscriber} from 'rxjs';
import {ServerService} from "../services/server.service";
import {GroupService} from "../services/group.service";
import {Server} from "../models/server";
import {Group} from "../models/groups/group";
import {User} from "../models/users/user";
import {Server} from "../models/server";
import {Role} from "../models/api/role";
@Injectable({
providedIn: 'root'
})
export class GroupDetailsResolver implements Resolve<{server: Server; group: Group; users: User[]}> {
export class GroupRoleResolver implements Resolve<Role[]> {
constructor(private serverService: ServerService,
private groupService: GroupService) {
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<{server: Server; group: Group; users: User[]}> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Role[]> {
return new Observable<{server: Server; group: Group; users: User[]}>((subscriber: Subscriber<any>) => {
return new Observable<Role[]>((subscriber: Subscriber<Role[]>) => {
const serverId = route.paramMap.get('server_id');
const groupId = route.paramMap.get('user_group_id');
this.serverService.get(+serverId).then((server: Server) => {
this.groupService.get(server, groupId).subscribe((group: Group) => {
this.groupService.getGroupMember(server, groupId).subscribe((users: User[]) => {
subscriber.next({server, group, users});
subscriber.complete();
});
this.groupService.getGroupRole(server, groupId).subscribe((role: Role[]) => {
subscriber.next(role);
subscriber.complete();
});
});
});

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { GroupResolver } from './group.resolver';
describe('GroupResolver', () => {
let resolver: GroupResolver;
beforeEach(() => {
TestBed.configureTestingModule({});
resolver = TestBed.inject(GroupResolver);
});
it('should be created', () => {
expect(resolver).toBeTruthy();
});
});

View File

@ -0,0 +1,39 @@
import {Injectable} from '@angular/core';
import {
Router, Resolve,
RouterStateSnapshot,
ActivatedRouteSnapshot
} from '@angular/router';
import {Observable, of, Subscriber} from 'rxjs';
import {ServerService} from "@services/server.service";
import {GroupService} from "@services/group.service";
import {User} from "@models/users/user";
import {Server} from "@models/server";
import {Group} from "@models/groups/group";
@Injectable({
providedIn: 'root'
})
export class GroupResolver implements Resolve<Group> {
constructor(private serverService: ServerService,
private groupService: GroupService) {
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Group> {
return new Observable<Group>((subscriber: Subscriber<Group>) => {
const serverId = route.paramMap.get('server_id');
const groupId = route.paramMap.get('user_group_id');
this.serverService.get(+serverId).then((server: Server) => {
this.groupService.get(server, groupId).subscribe((group: Group) => {
subscriber.next(group);
subscriber.complete();
});
});
});
}
}

View File

@ -16,6 +16,7 @@ import {Server} from "../models/server";
import {Group} from "../models/groups/group";
import {User} from "../models/users/user";
import {Observable} from "rxjs";
import {Role} from "@models/api/role";
@Injectable({
providedIn: 'root'
@ -58,4 +59,16 @@ export class GroupService {
update(server: Server, group: Group) {
return this.httpServer.put(server, `/groups/${group.user_group_id}`, {name: group.name});
}
getGroupRole(server: Server, groupId: string) {
return this.httpServer.get<Role[]>(server, `/groups/${groupId}/roles`);
}
removeRole(server: Server, group: Group, role: Role) {
return this.httpServer.delete(server, `/groups/${group.user_group_id}/roles/${role.role_id}`);
}
addRoleToGroup(server: Server, group: Group, role: Role) {
return this.httpServer.put(server, `/groups/${group.user_group_id}/roles/${role.role_id}`, {});
}
}