diff --git a/src/app/app.interceptor.ts b/src/app/app.interceptor.ts index 639c5488fa00d59a741d863cc7b932f9b1d3c5b0..fce9c80aa618271ae5a4d0f4fcb084a7823705f5 100644 --- a/src/app/app.interceptor.ts +++ b/src/app/app.interceptor.ts @@ -15,6 +15,7 @@ export class AuthInterceptor implements HttpInterceptor { } const loginData = this.mds.loginData$.getValue(); + let authData; if (loginData === null) { authData = { diff --git a/src/app/superadmin/backend.service.ts b/src/app/superadmin/backend.service.ts index fc1c5329d6a4f661a8b5cadd3771921ffd1e4f21..f87375989e54a1656109e1cca439f0103606ac0d 100644 --- a/src/app/superadmin/backend.service.ts +++ b/src/app/superadmin/backend.service.ts @@ -2,6 +2,7 @@ import { Injectable, Inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, of } from 'rxjs'; import { catchError } from 'rxjs/operators'; +import {IdAndName, IdLabelSelectedData, IdRoleData, UserData} from "./superadmin.interfaces"; @Injectable({ @@ -15,10 +16,10 @@ export class BackendService { private http: HttpClient) { } - getUsers(): Observable<IdAndName[]> { + getUsers(): Observable<UserData[]> { return this.http - .get<NameOnly[]>(this.serverUrl + 'users') + .get<UserData[]>(this.serverUrl + 'users') .pipe(catchError(() => [])); } @@ -36,6 +37,13 @@ export class BackendService { .pipe(catchError(() => of(false))); } + setSuperUserStatus(userId: number, changeToSuperUser: boolean, password: string): Observable<Boolean> { + + return this.http + .patch<Boolean>(this.serverUrl + `user/${userId}/super-admin/` + (changeToSuperUser ? 'on' : 'off'), {p: password}) + .pipe(catchError(() => of(false))); + } + deleteUsers(users: string[]): Observable<Boolean> { return this.http @@ -99,25 +107,3 @@ export class BackendService { .pipe(catchError(() => [])); } } - - -export interface NameOnly { - name: string; -} - -export interface IdAndName { - id: number; - name: string; -} - -export interface IdLabelSelectedData { - id: number; - label: string; - selected: boolean; -} - -export interface IdRoleData { - id: number; - label: string; - role: string; -} diff --git a/src/app/superadmin/superadmin-password-request/superadmin-password-request.component.css b/src/app/superadmin/superadmin-password-request/superadmin-password-request.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/app/superadmin/superadmin-password-request/superadmin-password-request.component.html b/src/app/superadmin/superadmin-password-request/superadmin-password-request.component.html new file mode 100644 index 0000000000000000000000000000000000000000..d461c4face79b70857aab085ffdc3327eda83598 --- /dev/null +++ b/src/app/superadmin/superadmin-password-request/superadmin-password-request.component.html @@ -0,0 +1,20 @@ +<form [formGroup]="passwordform"> + <h1 mat-dialog-title>Sicherheitsabfrage Kennwort</h1> + + <mat-dialog-content> + <div class="infobox"> + <p>Für die Funktion "{{data}}" ist es zur Sicherheit notwendig, dass Sie Ihr Kennwort nocheinmal eingeben.</p> + </div> + <p> + <mat-form-field class="full-width"> + <input matInput type="password" formControlName="pw" placeholder="Kennwort"> + </mat-form-field> + </p> + </mat-dialog-content> + + <mat-dialog-actions> + <button mat-raised-button color="primary" type="submit" [mat-dialog-close]="passwordform" [disabled]="passwordform.invalid">Bestätigen</button> + <button mat-raised-button [mat-dialog-close]="false">Abbrechen</button> + </mat-dialog-actions> + +</form> diff --git a/src/app/superadmin/superadmin-password-request/superadmin-password-request.component.spec.ts b/src/app/superadmin/superadmin-password-request/superadmin-password-request.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..adb6f10e0aa2e2c661a37636415f556141f5bd65 --- /dev/null +++ b/src/app/superadmin/superadmin-password-request/superadmin-password-request.component.spec.ts @@ -0,0 +1,41 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SuperadminPasswordRequestComponent } from './superadmin-password-request.component'; +import {MAT_DIALOG_DATA, MatDialog, MatDialogModule} from "@angular/material/dialog"; +import {ReactiveFormsModule} from "@angular/forms"; +import {MatInputModule} from "@angular/material/input"; +import {MatFormFieldModule} from "@angular/material/form-field"; +import {NoopAnimationsModule} from "@angular/platform-browser/animations"; + +describe('SuperadminPasswordRequestComponent', () => { + let component: SuperadminPasswordRequestComponent; + let fixture: ComponentFixture<SuperadminPasswordRequestComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SuperadminPasswordRequestComponent ], + imports: [ + MatDialogModule, + ReactiveFormsModule, + MatInputModule, + MatFormFieldModule, + NoopAnimationsModule + ], + providers: [ + MatDialog, + { provide: MAT_DIALOG_DATA, useValue: 'fonk' } + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SuperadminPasswordRequestComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/superadmin/superadmin-password-request/superadmin-password-request.component.ts b/src/app/superadmin/superadmin-password-request/superadmin-password-request.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..f7bcfb33d132519b7102ab82fa333c2a4290b8ea --- /dev/null +++ b/src/app/superadmin/superadmin-password-request/superadmin-password-request.component.ts @@ -0,0 +1,17 @@ +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { Component, Inject } from '@angular/core'; +import {FormGroup, Validators, FormControl} from '@angular/forms'; + +@Component({ + templateUrl: './superadmin-password-request.component.html', + styleUrls: ['./superadmin-password-request.component.css'] +}) + +export class SuperadminPasswordRequestComponent { + passwordform = new FormGroup({ + pw: new FormControl('', [Validators.required, Validators.minLength(3)]) + }); + + constructor( + @Inject(MAT_DIALOG_DATA) public data: string) { } +} diff --git a/src/app/superadmin/superadmin.interfaces.ts b/src/app/superadmin/superadmin.interfaces.ts new file mode 100644 index 0000000000000000000000000000000000000000..91e12796f765db07a9d29739af4dd3612fa21944 --- /dev/null +++ b/src/app/superadmin/superadmin.interfaces.ts @@ -0,0 +1,28 @@ +export interface NameOnly { + name: string; +} + +export interface IdAndName { + id: number; + name: string; +} + +export interface IdLabelSelectedData { + id: number; + label: string; + selected: boolean; +} + +export interface IdRoleData { + id: number; + label: string; + role: string; +} + +export interface UserData { + id: number; + name: string; + email: string; + is_superadmin: string; + selected: boolean; +} diff --git a/src/app/superadmin/superadmin.module.ts b/src/app/superadmin/superadmin.module.ts index 4a8da1172ee1d2b2fbdab35c59f81c103dfcebe3..20807dca732e1e44f60196ac4c475d7fd985b368 100644 --- a/src/app/superadmin/superadmin.module.ts +++ b/src/app/superadmin/superadmin.module.ts @@ -29,7 +29,7 @@ import {NewpasswordComponent} from "./users/newpassword/newpassword.component"; import {NewuserComponent} from "./users/newuser/newuser.component"; import {NewworkspaceComponent} from "./workspaces/newworkspace/newworkspace.component"; import {EditworkspaceComponent} from "./workspaces/editworkspace/editworkspace.component"; -import {HttpClientModule} from "@angular/common/http"; +import { SuperadminPasswordRequestComponent } from './superadmin-password-request/superadmin-password-request.component'; @NgModule({ @@ -40,7 +40,8 @@ import {HttpClientModule} from "@angular/common/http"; NewuserComponent, NewworkspaceComponent, EditworkspaceComponent, - WorkspacesComponent + WorkspacesComponent, + SuperadminPasswordRequestComponent ], imports: [ CommonModule, @@ -65,8 +66,7 @@ import {HttpClientModule} from "@angular/common/http"; MatSnackBarModule, MatGridListModule, MatCardModule, - FlexLayoutModule, - HttpClientModule + FlexLayoutModule ], exports: [ SuperadminComponent diff --git a/src/app/superadmin/users/users.component.html b/src/app/superadmin/users/users.component.html index 5e1b3d152aef627dc85bed86728eb7ae6920aaaa..be28462b34f95d621023564a591b106ee961bc23 100644 --- a/src/app/superadmin/users/users.component.html +++ b/src/app/superadmin/users/users.component.html @@ -6,17 +6,21 @@ <!-- ============================================= --> <div class="objectlist" fxLayout="column" fxFlex="50"> <div fxLayout="row"> - <button mat-raised-button (click)="addObject()" matTooltip="Nutzer hinzufügen" matTooltipPosition="above"> - <mat-icon>add</mat-icon> - </button> - <button mat-raised-button (click)="deleteObject()" - matTooltip="Markierte Nutzer löschen" matTooltipPosition="above"> - <mat-icon>delete</mat-icon> - </button> - <button mat-raised-button (click)="changePassword()" - matTooltip="Kennwort ändern" matTooltipPosition="above"> - <mat-icon>edit</mat-icon> + <button mat-raised-button (click)="addObject()" matTooltip="Nutzer hinzufügen" matTooltipPosition="above"> + <mat-icon>add</mat-icon> </button> + <button mat-raised-button (click)="deleteObject()" + matTooltip="Markierte Nutzer löschen" matTooltipPosition="above"> + <mat-icon>delete</mat-icon> + </button> + <button mat-raised-button (click)="changePassword()" + matTooltip="Kennwort ändern" matTooltipPosition="above"> + <mat-icon>edit</mat-icon> + </button> + <button mat-raised-button (click)="changeSuperadminStatus()" + matTooltip="Superadmin-Status ändern" matTooltipPosition="above"> + <mat-icon>edit</mat-icon> + </button> </div> <mat-table *ngIf="isSuperadmin" [dataSource]="objectsDatasource" matSort> @@ -37,7 +41,7 @@ <ng-container matColumnDef="name"> <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell> - <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell> + <mat-cell *matCellDef="let element"> {{element.name}} {{element.is_superadmin === '1' ? '*' : ''}}</mat-cell> </ng-container> <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row> diff --git a/src/app/superadmin/users/users.component.ts b/src/app/superadmin/users/users.component.ts index c12db9a6877a8621a6097e861195600e5e9ede6f..196cb9057e8a55031576805cbbaaf2cb5d418a3d 100644 --- a/src/app/superadmin/users/users.component.ts +++ b/src/app/superadmin/users/users.component.ts @@ -1,6 +1,6 @@ import { NewpasswordComponent } from './newpassword/newpassword.component'; import { NewuserComponent } from './newuser/newuser.component'; -import { BackendService, IdRoleData, IdAndName } from '../backend.service'; +import { BackendService } from '../backend.service'; import { MatTableDataSource } from '@angular/material/table'; import { ViewChild, OnDestroy } from '@angular/core'; @@ -16,6 +16,8 @@ import { } from 'iqb-components'; import { Subscription } from 'rxjs'; import { MainDataService } from 'src/app/maindata.service'; +import {IdRoleData, UserData} from "../superadmin.interfaces"; +import {SuperadminPasswordRequestComponent} from "../superadmin-password-request/superadmin-password-request.component"; @Component({ @@ -25,10 +27,10 @@ import { MainDataService } from 'src/app/maindata.service'; export class UsersComponent implements OnInit, OnDestroy { public isSuperadmin = false; public dataLoading = false; - public objectsDatasource: MatTableDataSource<IdAndName>; + public objectsDatasource: MatTableDataSource<UserData>; public displayedColumns = ['selectCheckbox', 'name']; - private tableselectionCheckbox = new SelectionModel<IdAndName>(true, []); - private tableselectionRow = new SelectionModel<IdAndName>(false, []); + private tableselectionCheckbox = new SelectionModel<UserData>(true, []); + private tableselectionRow = new SelectionModel<UserData>(false, []); private selectedUser = -1; private selectedUserName = ''; @@ -44,7 +46,8 @@ export class UsersComponent implements OnInit, OnDestroy { private mds: MainDataService, private newuserDialog: MatDialog, private newpasswordDialog: MatDialog, - private deleteConfirmDialog: MatDialog, + private confirmDialog: MatDialog, + private superadminPasswordDialog: MatDialog, private messsageDialog: MatDialog, private snackBar: MatSnackBar ) { @@ -92,6 +95,63 @@ export class UsersComponent implements OnInit, OnDestroy { }); } + changeSuperadminStatus() { + let selectedRows = this.tableselectionRow.selected; + if (selectedRows.length === 0) { + selectedRows = this.tableselectionCheckbox.selected; + } + if (selectedRows.length === 0) { + this.messsageDialog.open(MessageDialogComponent, { + width: '400px', + data: <MessageDialogData>{ + title: 'Superadmin-Status ändern', + content: 'Bitte markieren Sie erst einen Nutzer!', + type: MessageType.error + } + }); + } else { + const userObject = <UserData>selectedRows[0]; + const confirmDialogRef = this.confirmDialog.open(ConfirmDialogComponent, { + width: '400px', + data: <ConfirmDialogData>{ + title: 'Ändern des Superadmin-Status', + content: 'Für "' + userObject.name + '" den Status auf "' + (userObject.is_superadmin === '0' ? '' : 'NICHT ') + 'Superadmin" setzen?', + confirmbuttonlabel: 'Status ändern', + showcancel: true + } + }); + + confirmDialogRef.afterClosed().subscribe(result => { + if ((typeof result !== 'undefined') && (result !== false)) { + const passwdDialogRef = this.superadminPasswordDialog.open(SuperadminPasswordRequestComponent, { + width: '600px', + data: 'Superadmin-Status ' + (userObject.is_superadmin === '0' ? 'setzen' : 'entziehen') + }); + + passwdDialogRef.afterClosed().subscribe(result => { + if (typeof result !== 'undefined') { + if (result !== false) { + this.dataLoading = true; + this.bs.setSuperUserStatus( + selectedRows[0]['id'], + userObject.is_superadmin === '0', + (<FormGroup>result).get('pw').value).subscribe( + respOk => { + if (respOk !== false) { + this.snackBar.open('Status geändert', '', {duration: 1000}); + } else { + this.snackBar.open('Konnte Status nicht ändern', 'Fehler', {duration: 1000}); + } + this.dataLoading = false; + }); + } + } + }); + } + }); + } + } + changePassword() { let selectedRows = this.tableselectionRow.selected; if (selectedRows.length === 0) { @@ -153,7 +213,7 @@ export class UsersComponent implements OnInit, OnDestroy { } else { prompt = prompt + ' Nutzer "' + selectedRows[0].name + '" '; } - const dialogRef = this.deleteConfirmDialog.open(ConfirmDialogComponent, { + const dialogRef = this.confirmDialog.open(ConfirmDialogComponent, { width: '400px', data: <ConfirmDialogData>{ title: 'Löschen von Nutzern', @@ -168,7 +228,7 @@ export class UsersComponent implements OnInit, OnDestroy { // ========================================================= this.dataLoading = true; const usersToDelete = []; - selectedRows.forEach((r: IdAndName) => usersToDelete.push(r.id)); + selectedRows.forEach((r: UserData) => usersToDelete.push(r.id)); this.bs.deleteUsers(usersToDelete).subscribe( respOk => { if (respOk !== false) { @@ -233,6 +293,7 @@ export class UsersComponent implements OnInit, OnDestroy { this.tableselectionCheckbox.clear(); this.tableselectionRow.clear(); this.bs.getUsers().subscribe(dataresponse => { + console.log(dataresponse); this.objectsDatasource = new MatTableDataSource(dataresponse); this.objectsDatasource.sort = this.sort; this.dataLoading = false; diff --git a/src/app/superadmin/workspaces/workspaces.component.ts b/src/app/superadmin/workspaces/workspaces.component.ts index 72ffe0ab78750b0de8a052e83ab5886947b45e02..885f1168f9a362a5bbf8e21066f1a2a66f56da5a 100644 --- a/src/app/superadmin/workspaces/workspaces.component.ts +++ b/src/app/superadmin/workspaces/workspaces.component.ts @@ -1,6 +1,6 @@ import { EditworkspaceComponent } from './editworkspace/editworkspace.component'; import { NewworkspaceComponent } from './newworkspace/newworkspace.component'; -import { BackendService, IdAndName, IdRoleData } from '../backend.service'; +import { BackendService } from '../backend.service'; import { MatTableDataSource } from '@angular/material/table'; import { ViewChild, OnDestroy } from '@angular/core'; @@ -16,6 +16,7 @@ import { } from 'iqb-components'; import { Subscription } from 'rxjs'; import { MainDataService } from 'src/app/maindata.service'; +import {IdAndName, IdRoleData} from "../superadmin.interfaces"; @Component({ templateUrl: './workspaces.component.html', diff --git a/src/app/sys-check/sys-check.module.ts b/src/app/sys-check/sys-check.module.ts index 8f6a2e7858113786149b08dfe7d9355a07787f1d..5e0d18ef72220b9202d7d6b080de56711346f91e 100644 --- a/src/app/sys-check/sys-check.module.ts +++ b/src/app/sys-check/sys-check.module.ts @@ -35,7 +35,6 @@ import {MatRadioModule} from "@angular/material/radio"; import {MatSelectModule} from "@angular/material/select"; import {MatSnackBarModule} from "@angular/material/snack-bar"; import {MatStepperModule} from "@angular/material/stepper"; -import {HttpClientModule} from "@angular/common/http"; @NgModule({ imports: [ @@ -58,7 +57,6 @@ import {HttpClientModule} from "@angular/common/http"; MatTooltipModule, ReactiveFormsModule, SysCheckRoutingModule, - HttpClientModule, IqbComponentsModule.forChild() ], declarations: [ diff --git a/src/app/test-controller/test-controller.module.ts b/src/app/test-controller/test-controller.module.ts index 87004537524d4ae281ed05b9385f06ccab0b4115..deffd4bebb3dd9e9b1fadc829af6af7d3dbeb694 100644 --- a/src/app/test-controller/test-controller.module.ts +++ b/src/app/test-controller/test-controller.module.ts @@ -27,7 +27,6 @@ import {MatMenuModule} from "@angular/material/menu"; import {MatButtonModule} from "@angular/material/button"; import {MatToolbarModule} from "@angular/material/toolbar"; import {MatIconModule} from "@angular/material/icon"; -import {HttpClientModule} from "@angular/common/http"; @NgModule({ @@ -50,7 +49,6 @@ import {HttpClientModule} from "@angular/common/http"; MatButtonModule, MatToolbarModule, MatIconModule, - HttpClientModule, IqbComponentsModule.forChild() ], declarations: [ diff --git a/src/app/workspace-admin/workspace.module.ts b/src/app/workspace-admin/workspace.module.ts index 89d8b5b28d8d6cc8556c6eefe2c8f7c70b3d4628..3fbecf6ed4c8dfd92c2a2fe869e4adb45aef9cdb 100644 --- a/src/app/workspace-admin/workspace.module.ts +++ b/src/app/workspace-admin/workspace.module.ts @@ -30,7 +30,6 @@ import { MatGridListModule } from '@angular/material/grid-list'; import { SyscheckComponent } from './syscheck/syscheck.component'; import { IqbComponentsModule } from 'iqb-components'; import {IqbFilesModule} from './files/iqb-files'; -import {HttpClientModule} from "@angular/common/http"; @NgModule({ imports: [ @@ -54,7 +53,6 @@ import {HttpClientModule} from "@angular/common/http"; MatToolbarModule, MatSnackBarModule, MatGridListModule, - HttpClientModule, IqbComponentsModule, MatCardModule, FlexLayoutModule, diff --git a/src/app/workspace-monitor/workspace-monitor.module.ts b/src/app/workspace-monitor/workspace-monitor.module.ts index 564e136bcdf96f9ff04138b3d49a222447905faa..0ae150d067ac01b1635ea78d7b68e58b1c8cdc3f 100644 --- a/src/app/workspace-monitor/workspace-monitor.module.ts +++ b/src/app/workspace-monitor/workspace-monitor.module.ts @@ -14,7 +14,6 @@ import {MatTooltipModule} from "@angular/material/tooltip"; import {MatCheckboxModule} from "@angular/material/checkbox"; import {ReactiveFormsModule} from "@angular/forms"; import {MatButtonModule} from "@angular/material/button"; -import {HttpClientModule} from "@angular/common/http"; import {BackendService} from "./backend.service"; @@ -33,8 +32,7 @@ import {BackendService} from "./backend.service"; ReactiveFormsModule, MatTooltipModule, MatCheckboxModule, - MatButtonModule, - HttpClientModule + MatButtonModule ], providers: [ BackendService