Skip to content
This repository has been archived by the owner on Jan 24, 2023. It is now read-only.

Fix several space developer permission bugs #4362

Merged
merged 8 commits into from
Jun 17, 2020
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<app-page-sub-nav>
<app-page-sub-nav *ngIf="canEditSpace$ | async">
<ng-container *ngIf="appAutoscalerPolicy$ | async as policy; else noPolicy">
<button mat-button name="edit" (click)="updatePolicyPage()" class="nav-button-with-text">
<span class="nav-button-with-text__span">
Expand Down Expand Up @@ -235,7 +235,7 @@
</app-tile>
</app-tile-group>
<app-no-content-message *ngIf="showNoPolicyMessage$ | async" [icon]="'meter'" [iconFont]="'stratos-icons'"
[firstLine]="noPolicyMessageFirstLine" [secondLine]="noPolicyMessageSecondLine">
[firstLine]="noPolicyMessageFirstLine" [secondLine]="(canEditSpace$ | async) ? noPolicyMessageSecondLine : ''">
richard-cox marked this conversation as resolved.
Show resolved Hide resolved
</app-no-content-message>
</app-tile-grid>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import {
import {
RunningInstancesComponent,
} from '../../../../cloud-foundry/src/shared/components/running-instances/running-instances.component';
import {
cfCurrentUserPermissionsService,
} from '../../../../cloud-foundry/src/user-permissions/cf-user-permissions-checkers';
import { ApplicationServiceMock } from '../../../../cloud-foundry/test-framework/application-service-helper';
import { CoreModule } from '../../../../core/src/core/core.module';
import { SharedModule } from '../../../../core/src/shared/shared.module';
Expand Down Expand Up @@ -48,7 +51,8 @@ describe('AutoscalerTabExtensionComponent', () => {
providers: [
DatePipe,
{ provide: ApplicationService, useClass: ApplicationServiceMock },
TabNavService
TabNavService,
...cfCurrentUserPermissionsService
]
})
.compileComponents();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import { MatSnackBar, MatSnackBarRef, SimpleSnackBar } from '@angular/material/s
import { ActivatedRoute } from '@angular/router';
import { Store } from '@ngrx/store';
import { combineLatest, Observable, Subscription } from 'rxjs';
import { distinctUntilChanged, filter, first, map, pairwise, publishReplay, refCount } from 'rxjs/operators';
import { distinctUntilChanged, filter, first, map, pairwise, publishReplay, refCount, switchMap } from 'rxjs/operators';

import { applicationEntityType } from '../../../../cloud-foundry/src/cf-entity-types';
import { createEntityRelationPaginationKey } from '../../../../cloud-foundry/src/entity-relations/entity-relations.types';
import { ApplicationMonitorService } from '../../../../cloud-foundry/src/features/applications/application-monitor.service';
import { ApplicationService } from '../../../../cloud-foundry/src/features/applications/application.service';
import { getGuids } from '../../../../cloud-foundry/src/features/applications/application/application-base.component';
import { CfCurrentUserPermissions } from '../../../../cloud-foundry/src/user-permissions/cf-user-permissions-checkers';
import { StratosTab, StratosTabType } from '../../../../core/src/core/extension/extension-service';
import { CurrentUserPermissionsService } from '../../../../core/src/core/permissions/current-user-permissions.service';
import { safeUnsubscribe } from '../../../../core/src/core/utils.service';
import { ConfirmationDialogConfig } from '../../../../core/src/shared/components/confirmation-dialog.config';
import { ConfirmationDialogService } from '../../../../core/src/shared/components/confirmation-dialog.service';
Expand Down Expand Up @@ -113,6 +115,8 @@ export class AutoscalerTabExtensionComponent implements OnInit, OnDestroy {
'order-direction': 'desc'
};

public canEditSpace$: Observable<boolean>;

ngOnDestroy(): void {
if (this.appAutoscalerPolicySnackBarRef) {
this.appAutoscalerPolicySnackBarRef.dismiss();
Expand All @@ -131,6 +135,7 @@ export class AutoscalerTabExtensionComponent implements OnInit, OnDestroy {
private appAutoscalerPolicySnackBar: MatSnackBar,
private appAutoscalerScalingHistorySnackBar: MatSnackBar,
private confirmDialog: ConfirmationDialogService,
private cups: CurrentUserPermissionsService
richard-cox marked this conversation as resolved.
Show resolved Hide resolved
) { }

ngOnInit() {
Expand Down Expand Up @@ -219,6 +224,18 @@ export class AutoscalerTabExtensionComponent implements OnInit, OnDestroy {
publishReplay(1),
refCount()
);

this.canEditSpace$ = combineLatest(
this.applicationService.appOrg$,
this.applicationService.appSpace$
).pipe(
switchMap(([org, space]) => this.cups.can(
CfCurrentUserPermissions.SPACE_EDIT,
this.applicationService.cfGuid,
org.metadata.guid,
space.metadata.guid
))
)
}

getAppMetric(metricName: string, trigger: AppScalingTrigger, params: AutoscalerPaginationParams) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@
</mat-card-content>
</mat-card>
</app-tile>
<app-tile id="app-build-tab-deployment-info">
<app-tile id="app-build-tab-deployment-info" *ngIf="(deploySource$ | async) as deploySource">
<mat-card>
<mat-card-header>
<mat-card-title>Deployment Info</mat-card-title>
</mat-card-header>
<mat-card-content *ngIf="(deploySource$ | async) as deploySource; else notDeployedFromStratos">
<mat-card-content>
<span [ngSwitch]="deploySource.type">
<app-metadata-item *ngSwitchCase="'giturl'" icon="code" label="Git Url">
<div matTooltip="{{ deploySource.branch + ' ' + (deploySource.commit | slice:0:8)}}"
Expand Down Expand Up @@ -183,9 +183,6 @@
</app-metadata-item>
</span>
</mat-card-content>
<ng-template #notDeployedFromStratos>
<mat-card-content>None</mat-card-content>
</ng-template>
</mat-card>
</app-tile>
</app-tile-group>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Component, Inject, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs';
import { combineLatest, delay, distinct, filter, first, map, mergeMap, startWith, tap } from 'rxjs/operators';
import { combineLatest as observableCombineLatest, Observable, of as observableOf, of } from 'rxjs';
import { combineLatest, delay, distinct, filter, first, map, mergeMap, startWith, switchMap, tap } from 'rxjs/operators';

import { AppMetadataTypes } from '../../../../../../../../cloud-foundry/src/actions/app-metadata.actions';
import { UpdateExistingApplication } from '../../../../../../../../cloud-foundry/src/actions/application.actions';
import { CFAppState } from '../../../../../../../../cloud-foundry/src/cf-app-state';
import {
CurrentUserPermissionsService,
} from '../../../../../../../../core/src/core/permissions/current-user-permissions.service';
import { getFullEndpointApiUrl } from '../../../../../../../../core/src/features/endpoints/endpoint-helpers';
import { ConfirmationDialogConfig } from '../../../../../../../../core/src/shared/components/confirmation-dialog.config';
import { ConfirmationDialogService } from '../../../../../../../../core/src/shared/components/confirmation-dialog.service';
Expand Down Expand Up @@ -58,6 +61,7 @@ const appRestageConfirmation = new ConfirmationDialogConfig(
export class BuildTabComponent implements OnInit {
public isBusyUpdating$: Observable<{ updating: boolean }>;
public manageAppPermission = CfCurrentUserPermissions.APPLICATION_MANAGE;

constructor(
public applicationService: ApplicationService,
private scmService: GitSCMService,
Expand All @@ -66,7 +70,7 @@ export class BuildTabComponent implements OnInit {
private route: ActivatedRoute,
private router: Router,
private confirmDialog: ConfirmationDialogService,

private cups: CurrentUserPermissionsService
) { }

cardTwoFetching$: Observable<boolean>;
Expand Down Expand Up @@ -108,8 +112,17 @@ export class BuildTabComponent implements OnInit {
})
);

this.deploySource$ = this.applicationService.applicationStratProject$.pipe(
combineLatest(this.applicationService.application$)
const canSeeEnvVars$ = this.applicationService.appSpace$.pipe(
switchMap(space => this.cups.can(
CfCurrentUserPermissions.APPLICATION_VIEW_ENV_VARS,
this.applicationService.cfGuid,
space.metadata.guid)
)
)

const deploySource$ = observableCombineLatest(
this.applicationService.applicationStratProject$,
this.applicationService.application$
).pipe(
map(([project, app]) => {
if (!!project) {
Expand Down Expand Up @@ -149,6 +162,10 @@ export class BuildTabComponent implements OnInit {
}
}),
startWith({ type: 'loading' })
)

this.deploySource$ = canSeeEnvVars$.pipe(
switchMap(canSeeEnvVars => canSeeEnvVars ? deploySource$ : of(null)),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
</mat-card-header>
<mat-card-content class="card-app-instances__compact">
<div *ngIf="!isEditing" class="card-app-instances__large">
<app-running-instances [instances]="(appService.application$ | async)?.app.entity?.instances" [cfGuid]="appService.cfGuid" [appGuid]="this.appService.appGuid">
<app-running-instances [instances]="(appService.application$ | async)?.app.entity?.instances"
[cfGuid]="appService.cfGuid" [appGuid]="this.appService.appGuid">
</app-running-instances>
</div>
<form [hidden]="!isEditing" class="card-app-instances__form">
Expand All @@ -14,23 +15,27 @@
</mat-form-field>
</form>
</mat-card-content>
<mat-card-actions *ngIf="showActions && (appService.applicationRunning$ | async) && !isEditing" class="card-app-instances__actions">
<button (click)="edit()" mat-icon-button [disabled]="appService.isUpdatingApp$ | async">
<mat-icon>edit</mat-icon>
<ng-container *ngIf="canEditSpace$ | async">
<mat-card-actions *ngIf="showActions && (appService.applicationRunning$ | async) && !isEditing"
class="card-app-instances__actions">
<button (click)="edit()" mat-icon-button [disabled]="appService.isUpdatingApp$ | async">
<mat-icon>edit</mat-icon>
</button>
<button (click)="scaleDown()" mat-icon-button [disabled]="appService.isUpdatingApp$ | async">
<mat-icon>remove_circle_outline</mat-icon>
<button (click)="scaleDown()" mat-icon-button [disabled]="appService.isUpdatingApp$ | async">
<mat-icon>remove_circle_outline</mat-icon>
</button>
<button (click)="scaleUp()" mat-icon-button [disabled]="appService.isUpdatingApp$ | async">
<mat-icon>add_circle_outline</mat-icon>
<button (click)="scaleUp()" mat-icon-button [disabled]="appService.isUpdatingApp$ | async">
<mat-icon>add_circle_outline</mat-icon>
</button>
</mat-card-actions>
<mat-card-actions *ngIf="showActions && isEditing" class="card-app-instances__actions">
<button (click)="finishEdit(false)" mat-icon-button [disabled]="appService.isUpdatingApp$ | async">
<mat-icon>clear</mat-icon>
</mat-card-actions>
<mat-card-actions *ngIf="showActions && isEditing" class="card-app-instances__actions">
<button (click)="finishEdit(false)" mat-icon-button [disabled]="appService.isUpdatingApp$ | async">
<mat-icon>clear</mat-icon>
</button>
<button (click)="finishEdit(true)" mat-icon-button [disabled]="appService.isUpdatingApp$ | async">
<mat-icon>done</mat-icon>
</button>
</mat-card-actions>
</mat-card>
<button (click)="finishEdit(true)" mat-icon-button [disabled]="appService.isUpdatingApp$ | async">
<mat-icon>done</mat-icon>
</button>
</mat-card-actions>
</ng-container>

</mat-card>
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild, Renderer2 } from '@angular/core';
import { Component, ElementRef, Input, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { MatSnackBar, MatSnackBarRef, SimpleSnackBar } from '@angular/material/snack-bar';
import { Observable, Subscription } from 'rxjs';
import { first, map } from 'rxjs/operators';
import { combineLatest, Observable, Subscription } from 'rxjs';
import { first, map, switchMap } from 'rxjs/operators';

import { AppMetadataTypes } from '../../../../../../cloud-foundry/src/actions/app-metadata.actions';
import { ApplicationService } from '../../../../../../cloud-foundry/src/features/applications/application.service';
import { CurrentUserPermissionsService } from '../../../../../../core/src/core/permissions/current-user-permissions.service';
import { ConfirmationDialogConfig } from '../../../../../../core/src/shared/components/confirmation-dialog.config';
import { ConfirmationDialogService } from '../../../../../../core/src/shared/components/confirmation-dialog.service';
import { StratosStatus } from '../../../../../../core/src/shared/shared.types';
import { CfCurrentUserPermissions } from '../../../../user-permissions/cf-user-permissions-checkers';

const appInstanceScaleToZeroConfirmation = new ConfirmationDialogConfig('Set Instance count to 0',
'Are you sure you want to set the instance count to 0?', 'Confirm', true);
Expand All @@ -28,14 +30,25 @@ export class CardAppInstancesComponent implements OnInit, OnDestroy {

status$: Observable<StratosStatus>;

public canEditSpace$: Observable<boolean>;

constructor(
public appService: ApplicationService,
private renderer: Renderer2,
private confirmDialog: ConfirmationDialogService,
private snackBar: MatSnackBar) {
private snackBar: MatSnackBar,
cups: CurrentUserPermissionsService
) {
this.status$ = this.appService.applicationState$.pipe(
map(state => state.indicator)
);
this.canEditSpace$ = combineLatest(
appService.appOrg$,
appService.appSpace$
).pipe(
switchMap(([org, space]) => cups.can(CfCurrentUserPermissions.SPACE_EDIT, appService.cfGuid, org.metadata.guid, space.metadata.guid))
)

}

private currentCount = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { combineLatest as combineLatestObs, Observable } from 'rxjs';
import { combineLatest, map, switchMap } from 'rxjs/operators';

import { DeleteApplicationInstance } from '../../../../../../../cloud-foundry/src/actions/application.actions';
import { FetchApplicationMetricsAction } from '../../../../../../../cloud-foundry/src/actions/cf-metrics.actions';
import { CFAppState } from '../../../../../../../cloud-foundry/src/cf-app-state';
import {
CurrentUserPermissionsService,
} from '../../../../../../../core/src/core/permissions/current-user-permissions.service';
import { UtilsService } from '../../../../../../../core/src/core/utils.service';
import { ConfirmationDialogConfig } from '../../../../../../../core/src/shared/components/confirmation-dialog.config';
import { ConfirmationDialogService } from '../../../../../../../core/src/shared/components/confirmation-dialog.service';
Expand All @@ -27,6 +30,7 @@ import { IMetricMatrixResult, IMetrics } from '../../../../../../../store/src/ty
import { IMetricApplication } from '../../../../../../../store/src/types/metric.types';
import { ApplicationService } from '../../../../../features/applications/application.service';
import { CfCellHelper } from '../../../../../features/cloud-foundry/cf-cell.helpers';
import { CfCurrentUserPermissions } from '../../../../../user-permissions/cf-user-permissions-checkers';
import { ListAppInstance } from './app-instance-types';
import { CfAppInstancesDataSource } from './cf-app-instances-data-source';
import { TableCellCfCellComponent } from './table-cell-cf-cell/table-cell-cf-cell.component';
Expand Down Expand Up @@ -158,7 +162,7 @@ export class CfAppInstancesConfigService implements IListConfig<ListAppInstance>
},
label: 'Terminate',
description: ``, // Description depends on console user permission

createVisible: () => this.canEditSpace$
richard-cox marked this conversation as resolved.
Show resolved Hide resolved
};

private listActionSsh: IListAction<any> = {
Expand All @@ -182,22 +186,26 @@ export class CfAppInstancesConfigService implements IListConfig<ListAppInstance>
space.entity.allow_ssh;
})
);
}))
})),
createVisible: () => this.canEditSpace$
};

private singleActions = [
this.listActionTerminate,
this.listActionSsh,
];

private canEditSpace$: Observable<boolean>;

constructor(
private store: Store<CFAppState>,
private appService: ApplicationService,
private utilsService: UtilsService,
private router: Router,
private confirmDialog: ConfirmationDialogService,
entityServiceFactory: EntityServiceFactory,
paginationMonitorFactory: PaginationMonitorFactory
paginationMonitorFactory: PaginationMonitorFactory,
cups: CurrentUserPermissionsService
) {
const cellHelper = new CfCellHelper(store, paginationMonitorFactory);

Expand All @@ -220,6 +228,13 @@ export class CfAppInstancesConfigService implements IListConfig<ListAppInstance>
this.appService.appGuid,
this,
);

this.canEditSpace$ = combineLatestObs(
appService.appOrg$,
appService.appSpace$
).pipe(
switchMap(([org, space]) => cups.can(CfCurrentUserPermissions.SPACE_EDIT, appService.cfGuid, org.metadata.guid, space.metadata.guid))
richard-cox marked this conversation as resolved.
Show resolved Hide resolved
)
}

getGlobalActions = () => null;
Expand Down
Loading