fix(console): general fixes, project grants for owned and granted context (#425)

* update and delete project grants

* fix: user grant id (#421)

* fix: verboser logging on sql err (#412)

* fix(eventstore): improve insert statement

* fix: verbose logging on error

* fix: simplify insertEvents

* fix: project grant delete (#417)

* fix: add grant id to user grant if needed

* fix: add grant id to user grant if needed

Co-authored-by: Silvan <[email protected]>

* fix user grant context

* lint

* role validators

* fix: usergrantid (#424)

* fix: verboser logging on sql err (#412)

* fix(eventstore): improve insert statement

* fix: verbose logging on error

* fix: simplify insertEvents

* fix: project grant delete (#417)

* fix: add grant id to user grant if needed

* fix: add grant id to user grant if needed

* fix: add bulk remove

* fix: merge

Co-authored-by: Silvan <[email protected]>

Co-authored-by: Fabi <[email protected]>
Co-authored-by: Silvan <[email protected]>
This commit is contained in:
Max Peintner
2020-07-09 15:14:01 +02:00
committed by GitHub
co-authored by Silvan Fabi
parent cf51bbc36d
commit 0b012f2fa2
39 changed files with 18254 additions and 17184 deletions
@@ -242,8 +242,8 @@ export class AppDetailComponent implements OnInit, OnDestroy {
width: '400px',
});
}).catch(data => {
this.toast.showError(data.message);
}).catch(error => {
this.toast.showError(error);
});
}
@@ -91,6 +91,7 @@ export class GrantedProjectDetailComponent implements OnInit, OnDestroy {
if (this.projectId && this.grantId) {
this.projectService.GetGrantedProjectByID(this.projectId, this.grantId).then(proj => {
this.project = proj.toObject();
console.log('granted-project', this.project);
}).catch(error => {
this.toast.showError(error);
});
@@ -11,6 +11,7 @@ import { MatInputModule } from '@angular/material/input';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
import { MatTabsModule } from '@angular/material/tabs';
@@ -53,6 +54,7 @@ import { ProjectGrantsComponent } from './project-grants/project-grants.componen
UserGrantsModule,
ProjectContributorsModule,
FormsModule,
ReactiveFormsModule,
TranslateModule,
AvatarModule,
ReactiveFormsModule,
@@ -73,6 +75,7 @@ import { ProjectGrantsComponent } from './project-grants/project-grants.componen
MatTabsModule,
MatCheckboxModule,
CardModule,
MatSelectModule,
MatTooltipModule,
MatSortModule,
PipesModule,
@@ -29,6 +29,7 @@ export class ProjectGrantsDataSource extends DataSource<ProjectGrant.AsObject> {
catchError(() => of([])),
finalize(() => this.loadingSubject.next(false)),
).subscribe(grants => {
console.log(grants);
this.grantsSubject.next(grants);
});
}
@@ -11,8 +11,8 @@
</div>
<span class="fill-space"></span>
<ng-template appHasRole [appHasRole]="['project.grant.member.delete:'+projectId, 'project.grant.member.delete']">
<button [disabled]="disabled" matTooltip="{{'ORG_DETAIL.TABLE.DELETE' | translate}}" class="icon-button"
mat-icon-button *ngIf="selection.hasValue()" color="warn">
<button (click)="deleteSelectedGrants()" [disabled]="disabled" class="icon-button" mat-icon-button
*ngIf="selection.hasValue()" color="warn">
<i class="las la-trash"></i>
</button>
</ng-template>
@@ -46,19 +46,22 @@
<ng-container matColumnDef="grantedOrgName">
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.GRANTEDORG' | translate }} </th>
<td class="pointer" mat-cell *matCellDef="let grant">
<td [routerLink]="['/projects',grant.projectId,'grant', grant.id]" class="pointer" mat-cell
*matCellDef="let grant">
{{grant.grantedOrgName}} </td>
</ng-container>
<ng-container matColumnDef="creationDate">
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.CREATIONDATE' | translate }} </th>
<td class="pointer" mat-cell *matCellDef="let grant">
<td [routerLink]="['/projects',grant.projectId,'grant', grant.id]" class="pointer" mat-cell
*matCellDef="let grant">
{{grant.creationDate | timestampToDate | date: 'dd. MMM, HH:mm' }} </td>
</ng-container>
<ng-container matColumnDef="changeDate">
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.CHANGEDATE' | translate }} </th>
<td class="pointer" mat-cell *matCellDef="let grant">
<td [routerLink]="['/projects',grant.projectId,'grant', grant.id]" class="pointer" mat-cell
*matCellDef="let grant">
{{grant.changeDate | timestampToDate | date: 'dd. MMM, HH:mm' }} </td>
</ng-container>
@@ -66,12 +69,20 @@
<ng-container matColumnDef="roleNamesList">
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }} </th>
<td class="pointer" mat-cell *matCellDef="let grant">
<span class="role" *ngFor="let role of grant.roleNamesList">{{role}}</span> </td>
<mat-form-field class="form-field" appearance="outline" *ngIf="grant.roleKeysList">
<mat-label>{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}</mat-label>
<mat-select [(ngModel)]="grant.roleKeysList" multiple
(selectionChange)="updateRoles(grant, $event)">
<mat-option *ngFor="let role of memberRoleOptions" [value]="role.key">
{{role.key}}
</mat-option>
</mat-select>
</mat-form-field>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="data-row" [routerLink]="['/projects',grant.projectId,'grant', grant.id]" mat-row
*matRowDef="let grant; columns: displayedColumns;" class="element-row">
<tr class="data-row" mat-row *matRowDef="let grant; columns: displayedColumns;" class="element-row">
</tr>
</table>
@@ -2,10 +2,12 @@ import { animate, state, style, transition, trigger } from '@angular/animations'
import { SelectionModel } from '@angular/cdk/collections';
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatSelectChange } from '@angular/material/select';
import { MatTable } from '@angular/material/table';
import { tap } from 'rxjs/operators';
import { ProjectGrant, ProjectMemberView } from 'src/app/proto/generated/management_pb';
import { ProjectGrant, ProjectRoleView } from 'src/app/proto/generated/management_pb';
import { ProjectService } from 'src/app/services/project.service';
import { ToastService } from 'src/app/services/toast.service';
import { ProjectGrantsDataSource } from './project-grants-datasource';
@@ -28,17 +30,17 @@ export class ProjectGrantsComponent implements OnInit, AfterViewInit {
@ViewChild(MatTable) public table!: MatTable<ProjectGrant.AsObject>;
public dataSource!: ProjectGrantsDataSource;
public selection: SelectionModel<ProjectGrant.AsObject> = new SelectionModel<ProjectGrant.AsObject>(true, []);
public expandedElement: ProjectGrant.AsObject | null = null;
public selectedGrantMembers: ProjectMemberView.AsObject[] = [];
public memberRoleOptions: ProjectRoleView.AsObject[] = [];
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
public displayedColumns: string[] = ['select', 'grantedOrgName', 'creationDate', 'changeDate', 'roleNamesList'];
constructor(private projectService: ProjectService) { }
constructor(private projectService: ProjectService, private toast: ToastService) { }
public ngOnInit(): void {
this.dataSource = new ProjectGrantsDataSource(this.projectService);
this.dataSource.loadGrants(this.projectId, 0, 25, 'asc');
this.getRoleOptions(this.projectId);
}
public ngAfterViewInit(): void {
@@ -69,4 +71,41 @@ export class ProjectGrantsComponent implements OnInit, AfterViewInit {
this.selection.clear() :
this.dataSource.grantsSubject.value.forEach(row => this.selection.select(row));
}
public getRoleOptions(projectId: string): void {
this.projectService.SearchProjectRoles(projectId, 100, 0).then(resp => {
this.memberRoleOptions = resp.toObject().resultList;
console.log(resp.toObject());
});
}
updateRoles(grant: ProjectGrant.AsObject, selectionChange: MatSelectChange): void {
this.projectService.UpdateProjectGrant(grant.id, grant.projectId, selectionChange.value)
.then((newgrant: ProjectGrant) => {
this.toast.showInfo('Grant updated!');
}).catch(error => {
this.toast.showError(error);
});
}
deleteSelectedGrants(): void {
const promises = this.selection.selected.map(grant => {
return this.projectService.RemoveProjectGrant(grant.id, grant.projectId);
});
Promise.all(promises).then(() => {
this.toast.showInfo('GRANTS.TOAST.BULKREMOVED', true);
const data = this.dataSource.grantsSubject.getValue();
this.selection.selected.forEach((item) => {
const index = data.findIndex(i => i.id === item.id);
if (index > -1) {
data.splice(index, 1);
this.dataSource.grantsSubject.next(data);
}
});
this.selection.clear();
}).catch(error => {
this.toast.showError(error);
});
}
}
@@ -59,9 +59,9 @@ export class ProjectRoleCreateComponent implements OnInit, OnDestroy {
public addEntry(): void {
const newGroup = new FormGroup({
key: new FormControl(''),
key: new FormControl('', [Validators.required]),
displayName: new FormControl(''),
group: new FormControl('', [Validators.required]),
group: new FormControl(''),
});
this.formArray.push(newGroup);
@@ -94,8 +94,8 @@ export class ProjectRoleCreateComponent implements OnInit, OnDestroy {
this.projectService.BulkAddProjectRole(this.projectId, rolesToAdd).then(() => {
this.router.navigate(['projects', this.projectId]);
}).catch(data => {
this.toast.showError(data.message);
}).catch(error => {
this.toast.showError(error);
});
}
@@ -114,16 +114,16 @@ export class AuthUserDetailComponent implements OnDestroy {
public resendVerification(): void {
this.userService.ResendEmailVerification().then(() => {
this.toast.showInfo('USER.TOAST.EMAILSAVED', true);
}).catch(data => {
this.toast.showError(data.message);
}).catch(error => {
this.toast.showError(error);
});
}
public resendPhoneVerification(): void {
this.userService.ResendPhoneVerification().then(() => {
this.toast.showInfo('USER.TOAST.PHONEVERIFICATIONSENT', true);
}).catch(data => {
this.toast.showError(data.message);
}).catch(error => {
this.toast.showError(error);
});
}
@@ -132,8 +132,8 @@ export class AuthUserDetailComponent implements OnDestroy {
this.toast.showInfo('USER.TOAST.PHONEREMOVED', true);
this.user.phone = '';
this.phoneEditState = false;
}).catch(data => {
this.toast.showError(data.message);
}).catch(error => {
this.toast.showError(error);
});
}
@@ -66,12 +66,14 @@ export class UserDetailComponent implements OnInit, OnDestroy {
if (newState === UserState.USERSTATE_ACTIVE) {
this.mgmtUserService.ReactivateUser(this.user.id).then(() => {
this.toast.showInfo('USER.TOAST.REACTIVATED', true);
this.user.state = newState;
}).catch(error => {
this.toast.showError(error);
});
} else if (newState === UserState.USERSTATE_INACTIVE) {
this.mgmtUserService.DeactivateUser(this.user.id).then(() => {
this.toast.showInfo('USER.TOAST.DEACTIVATED', true);
this.user.state = newState;
}).catch(error => {
this.toast.showError(error);
});
@@ -105,16 +107,16 @@ export class UserDetailComponent implements OnInit, OnDestroy {
public resendVerification(): void {
this.mgmtUserService.ResendEmailVerification(this.user.id).then(() => {
this.toast.showInfo('USER.TOAST.EMAILVERIFICATIONSENT', true);
}).catch(data => {
this.toast.showError(data.message);
}).catch(error => {
this.toast.showError(error);
});
}
public resendPhoneVerification(): void {
this.mgmtUserService.ResendPhoneVerification(this.user.id).then(() => {
this.toast.showInfo('USER.TOAST.PHONEVERIFICATIONSENT', true);
}).catch(data => {
this.toast.showError(data.message);
}).catch(error => {
this.toast.showError(error);
});
}
@@ -123,8 +125,8 @@ export class UserDetailComponent implements OnInit, OnDestroy {
this.toast.showInfo('USER.TOAST.PHONEREMOVED', true);
this.user.phone = '';
this.phoneEditState = false;
}).catch(data => {
this.toast.showError(data.message);
}).catch(error => {
this.toast.showError(error);
});
}
@@ -35,10 +35,26 @@
<ng-container *ngIf="currentCreateStep === STEPS">
<h1>{{'PROJECT.GRANT.CREATE.SEL_ROLES' | translate}}</h1>
<ng-container *ngIf="context === UserGrantContext.OWNED_PROJECT && projectId">
<app-card>
<app-project-roles (changedSelection)="selectRoles($event)" [projectId]="projectId">
</app-project-roles>
</app-card>
</ng-container>
<app-card *ngIf="projectId">
<app-project-roles (changedSelection)="selectRoles($event)" [projectId]="projectId"></app-project-roles>
</app-card>
<ng-container *ngIf="context === UserGrantContext.GRANTED_PROJECT && grantRolesKeyList; else noGrantRolesFound">
<mat-form-field class="form-field" appearance="outline">
<mat-label>{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}</mat-label>
<mat-select multiple (selectionChange)="rolesList = $event.value">
<mat-option *ngFor="let role of grantRolesKeyList" [value]="role">
{{role}}
</mat-option>
</mat-select>
</mat-form-field>
</ng-container>
<ng-template #noGrantRolesFound>
<span>{{'PROJECT.GRANT.NOROLES'}}</span>
</ng-template>
</ng-container>
<div class="btn-container">
@@ -7,6 +7,7 @@ import { Org } from 'src/app/proto/generated/auth_pb';
import { ProjectGrantView, ProjectRole, ProjectView, User, UserGrant } from 'src/app/proto/generated/management_pb';
import { AuthService } from 'src/app/services/auth.service';
import { MgmtUserService } from 'src/app/services/mgmt-user.service';
import { ProjectService } from 'src/app/services/project.service';
import { ToastService } from 'src/app/services/toast.service';
@Component({
@@ -31,12 +32,15 @@ export class UserGrantCreateComponent implements OnDestroy {
private subscription: Subscription = new Subscription();
public UserGrantContext: any = UserGrantContext;
public grantRolesKeyList: string[] = [];
constructor(
private authService: AuthService,
private userService: MgmtUserService,
private toast: ToastService,
private _location: Location,
private route: ActivatedRoute,
private projectService: ProjectService,
) {
this.subscription = this.route.params.subscribe((params: Params) => {
const { context, projectid, grantid, userid } = params;
@@ -46,12 +50,23 @@ export class UserGrantCreateComponent implements OnDestroy {
this.grantId = grantid;
this.userId = userid;
if (this.userId) {
this.context = UserGrantContext.USER;
} else if (this.projectId && !this.grantId) {
console.log('usergrantcreate');
// if (this.userId) {
// this.context = UserGrantContext.USER;
// } else
if (this.projectId && !this.grantId) {
this.context = UserGrantContext.OWNED_PROJECT;
} else if (this.projectId && this.grantId) {
this.context = UserGrantContext.GRANTED_PROJECT;
console.log(this.grantId, this.projectId);
this.projectService.GetGrantedProjectByID(this.projectId, this.grantId).then(resp => {
console.log(resp.toObject());
this.grantRolesKeyList = resp.toObject().roleKeysList;
}).catch(error => {
this.toast.showError(error);
});
}
});
@@ -66,18 +81,18 @@ export class UserGrantCreateComponent implements OnDestroy {
public addGrant(): void {
switch (this.context) {
case UserGrantContext.USER:
this.userService.CreateUserGrant(
this.projectId,
this.userId,
this.rolesList,
).then((data: UserGrant) => {
this.toast.showInfo('User Grant added');
this.close();
}).catch(error => {
this.toast.showError(error);
});
break;
// case UserGrantContext.USER:
// this.userService.CreateUserGrant(
// this.projectId,
// this.userId,
// this.rolesList,
// ).then((data: UserGrant) => {
// this.toast.showInfo('User Grant added');
// this.close();
// }).catch(error => {
// this.toast.showError(error);
// });
// break;
case UserGrantContext.OWNED_PROJECT:
this.userService.CreateProjectUserGrant(
this.projectId,
@@ -1,7 +1,9 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatSelectModule } from '@angular/material/select';
import { TranslateModule } from '@ngx-translate/core';
import { CardModule } from 'src/app/modules/card/card.module';
import {
@@ -24,6 +26,8 @@ import { UserGrantCreateComponent } from './user-grant-create.component';
MatIconModule,
TranslateModule,
CardModule,
MatFormFieldModule,
MatSelectModule,
SearchProjectAutocompleteModule,
SearchUserAutocompleteModule,
ProjectRolesModule,