import { RgwUserFormComponent } from './ceph/rgw/rgw-user-form/rgw-user-form.component';
import { RgwUserListComponent } from './ceph/rgw/rgw-user-list/rgw-user-list.component';
import { LoginComponent } from './core/auth/login/login.component';
+import { ForbiddenComponent } from './core/forbidden/forbidden.component';
import { NotFoundComponent } from './core/not-found/not-found.component';
import { AuthGuardService } from './shared/services/auth-guard.service';
import { ModuleStatusGuardService } from './shared/services/module-status-guard.service';
{ path: 'cephfs', component: CephfsListComponent, canActivate: [AuthGuardService] },
{ path: 'configuration', component: ConfigurationComponent, canActivate: [AuthGuardService] },
{ path: 'mirroring', component: MirroringComponent, canActivate: [AuthGuardService] },
+ { path: '403', component: ForbiddenComponent },
{ path: '404', component: NotFoundComponent },
{ path: 'osd', component: OsdListComponent, canActivate: [AuthGuardService] },
{ path: '**', redirectTo: '/404' }
<div class="col-sm-9">
<input class="form-control"
type="text"
+ placeholder="Pool name..."
id="pool"
name="pool"
formControlName="pool"
- *ngIf="mode === 'editing'">
+ *ngIf="mode === 'editing' || !poolPermission.read">
<select id="pool"
name="pool"
class="form-control"
formControlName="pool"
- *ngIf="mode !== 'editing'">
+ *ngIf="mode !== 'editing' && poolPermission.read">
<option *ngIf="pools === null"
[ngValue]="null">Loading...
</option>
<div class="col-sm-9">
<input class="form-control"
type="text"
+ placeholder="Data pool name..."
id="dataPool"
name="dataPool"
formControlName="dataPool"
- *ngIf="mode === 'editing'">
+ *ngIf="mode === 'editing' || !poolPermission.read">
<select id="dataPool"
name="dataPool"
class="form-control"
formControlName="dataPool"
(change)="onDataPoolChange($event.target.value)"
- *ngIf="mode !== 'editing'">
+ *ngIf="mode !== 'editing' && poolPermission.read">
<option *ngIf="dataPools === null"
[ngValue]="null">Loading...
</option>
import { PoolService } from '../../../shared/api/pool.service';
import { RbdService } from '../../../shared/api/rbd.service';
import { FinishedTask } from '../../../shared/models/finished-task';
+import { Permission } from '../../../shared/models/permissions';
import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
+import { AuthStorageService } from '../../../shared/services/auth-storage.service';
import { FormatterService } from '../../../shared/services/formatter.service';
import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
import { RbdFormCloneRequestModel } from './rbd-form-clone-request.model';
})
export class RbdFormComponent implements OnInit {
+ poolPermission: Permission;
rbdForm: FormGroup;
featuresFormGroups: FormGroup;
deepFlattenFormControl: FormControl;
];
constructor(
+ private authStorageService: AuthStorageService,
private route: ActivatedRoute,
private router: Router,
private poolService: PoolService,
private taskWrapper: TaskWrapperService,
private dimlessBinaryPipe: DimlessBinaryPipe
) {
+ this.poolPermission = this.authStorageService.getPermissions().pool;
this.features = {
'deep-flatten': {
desc: 'Deep flatten',
this.setFeatures(defaultFeatures);
});
}
- if (this.mode !== this.rbdFormMode.editing) {
+ if (this.mode !== this.rbdFormMode.editing && this.poolPermission.read) {
this.poolService.list(['pool_name', 'type', 'flags_names', 'application_metadata']).then(
resp => {
const pools = [];
dropdown>
<button type="button"
class="btn btn-sm btn-primary"
- *ngIf="!selection.hasSingleSelection"
+ *ngIf="permission.create && (!permission.update || !selection.hasSingleSelection)"
routerLink="/rbd/add">
- <i class="fa fa-fw fa-plus"></i>
- <span i18n>Add</span>
+ <i class="fa fa-fw fa-plus"></i><span i18n>Add</span>
</button>
<button type="button"
class="btn btn-sm btn-primary"
- *ngIf="selection.hasSingleSelection"
- [ngClass]="{'disabled': selection.first().executing}"
+ *ngIf="permission.update && (!permission.create || permission.create && selection.hasSingleSelection)"
+ [ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing}"
routerLink="/rbd/edit/{{ selection.first()?.pool_name }}/{{ selection.first()?.name }}">
- <i class="fa fa-fw fa-pencil"></i>
- <span i18n>Edit</span>
+ <i class="fa fa-fw fa-pencil"></i><span i18n>Edit</span>
+ </button>
+ <button type="button"
+ class="btn btn-sm btn-primary"
+ *ngIf="permission.delete && !permission.update && !permission.create"
+ [ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing}"
+ (click)="deleteRbdModal()">
+ <i class="fa fa-fw fa-trash-o"></i><span i18n>Delete</span>
</button>
<button type="button"
dropdownToggle
- class="btn btn-sm btn-primary dropdown-toggle dropdown-toggle-split">
+ class="btn btn-sm btn-primary dropdown-toggle dropdown-toggle-split"
+ *ngIf="permission.create || permission.update">
<span class="caret"></span>
<span class="sr-only"></span>
</button>
<ul *dropdownMenu
class="dropdown-menu"
role="menu">
- <li role="menuitem">
+ <li role="menuitem"
+ *ngIf="permission.create">
<a class="dropdown-item"
routerLink="/rbd/add">
<i class="fa fa-fw fa-plus"></i>
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.update"
[ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing}">
<a class="dropdown-item"
routerLink="/rbd/edit/{{ selection.first()?.pool_name }}/{{ selection.first()?.name }}">
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.create"
[ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing}">
<a class="dropdown-item"
routerLink="/rbd/copy/{{ selection.first()?.pool_name }}/{{ selection.first()?.name }}">
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.update"
[ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing || !selection.first().parent}">
<a class="dropdown-item"
(click)="flattenRbdModal()">
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.delete"
[ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing}">
<a class="dropdown-item"
(click)="deleteRbdModal()">
import { CdTableSelection } from '../../../shared/models/cd-table-selection';
import { ExecutingTask } from '../../../shared/models/executing-task';
import { FinishedTask } from '../../../shared/models/finished-task';
+import { Permission } from '../../../shared/models/permissions';
import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
import { DimlessPipe } from '../../../shared/pipes/dimless.pipe';
+import { AuthStorageService } from '../../../shared/services/auth-storage.service';
import { SummaryService } from '../../../shared/services/summary.service';
import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
import { RbdParentModel } from '../rbd-form/rbd-parent.model';
@ViewChild('usageTpl') usageTpl: TemplateRef<any>;
@ViewChild('parentTpl') parentTpl: TemplateRef<any>;
@ViewChild('nameTpl') nameTpl: TemplateRef<any>;
-
@ViewChild('flattenTpl') flattenTpl: TemplateRef<any>;
+ permission: Permission;
images: any;
executingTasks: ExecutingTask[] = [];
columns: CdTableColumn[];
modalRef: BsModalRef;
constructor(
+ private authStorageService: AuthStorageService,
private rbdService: RbdService,
private dimlessBinaryPipe: DimlessBinaryPipe,
private dimlessPipe: DimlessPipe,
private summaryService: SummaryService,
private modalService: BsModalService,
- private taskWrapper: TaskWrapperService
- ) {}
+ private taskWrapper: TaskWrapperService) {
+ this.permission = this.authStorageService.getPermissions().rbdImage;
+ }
ngOnInit() {
this.columns = [
dropdown>
<button type="button"
class="btn btn-sm btn-primary"
- *ngIf="!selection.hasSingleSelection"
+ *ngIf="permission.create && (!permission.update || !selection.hasSingleSelection)"
(click)="openCreateSnapshotModal()">
<i class="fa fa-fw fa-plus"></i>
<span i18n>Create</span>
</button>
<button type="button"
class="btn btn-sm btn-primary"
- *ngIf="selection.hasSingleSelection"
- [ngClass]="{'disabled': selection.first().executing}"
+ *ngIf="permission.update && (!permission.create || permission.create && selection.hasSingleSelection)"
+ [ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing}"
(click)="openEditSnapshotModal()">
<i class="fa fa-fw fa-pencil"></i>
<span i18n>Rename</span>
</button>
+ <button type="button"
+ class="btn btn-sm btn-primary"
+ *ngIf="permission.delete && !permission.update && !permission.create"
+ [ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing}"
+ (click)="deleteSnapshotModal()">
+ <i class="fa fa-fw fa-trash-o"></i>
+ <span i18n>Delete</span>
+ </button>
<button type="button"
dropdownToggle
- class="btn btn-sm btn-primary dropdown-toggle dropdown-toggle-split">
+ class="btn btn-sm btn-primary dropdown-toggle dropdown-toggle-split"
+ *ngIf="permission.create || permission.update">
<span class="caret"></span>
<span class="sr-only"></span>
</button>
<ul *dropdownMenu
class="dropdown-menu"
role="menu">
- <li role="menuitem">
+ <li role="menuitem"
+ *ngIf="permission.create">
<a class="dropdown-item"
(click)="openCreateSnapshotModal()">
<i class="fa fa-fw fa-plus"></i>
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.update"
[ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing}">
- <a class="dropdown-item"
- (click)="openEditSnapshotModal()">
+ <a class="dropdown-item" (click)="openEditSnapshotModal()">
<i class="fa fa-fw fa-pencil"></i>
<span i18n>Rename</span>
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.update"
[ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing}">
- <a class="dropdown-item"
- (click)="toggleProtection()">
+ <a class="dropdown-item" (click)="toggleProtection()">
<span *ngIf="!selection.first()?.is_protected">
<i class="fa fa-fw fa-lock"></i>
<span i18n>Protect</span>
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.create"
[ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing}">
<a class="dropdown-item"
routerLink="/rbd/clone/{{ poolName }}/{{ rbdName }}/{{ selection.first()?.name }}">
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.create"
[ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing}">
- <a class="dropdown-item"
- routerLink="/rbd/copy/{{ poolName }}/{{ rbdName }}/{{ selection.first()?.name }}">
- <i class="fa fa-fw fa-copy"></i>
- <span i18n>Copy</span>
+ <a class="dropdown-item" routerLink="/rbd/copy/{{ poolName }}/{{ rbdName }}/{{ selection.first()?.name }}">
+ <i class="fa fa-fw fa-copy"></i><span i18n>Copy</span>
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.update"
[ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing}">
<a class="dropdown-item"
(click)="rollbackModal()">
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.delete"
[ngClass]="{'disabled': !selection.hasSingleSelection || selection.first().executing || selection.first().is_protected}">
<a class="dropdown-item"
(click)="deleteSnapshotModal()">
import { RbdService } from '../../../shared/api/rbd.service';
import { ComponentsModule } from '../../../shared/components/components.module';
import { DataTableModule } from '../../../shared/datatable/datatable.module';
+import { Permissions } from '../../../shared/models/permissions';
import { AuthStorageService } from '../../../shared/services/auth-storage.service';
import { NotificationService } from '../../../shared/services/notification.service';
import { ServicesModule } from '../../../shared/services/services.module';
let component: RbdSnapshotListComponent;
let fixture: ComponentFixture<RbdSnapshotListComponent>;
+ const fakeAuthStorageService = {
+ isLoggedIn: () => {
+ return true;
+ },
+ getPermissions: () => {
+ return new Permissions({ 'rbd-image': ['read', 'update', 'create', 'delete'] });
+ }
+ };
+
configureTestBed({
declarations: [RbdSnapshotListComponent],
imports: [
HttpClientTestingModule,
RouterTestingModule
],
- providers: [AuthStorageService]
+ providers: [{ provide: AuthStorageService, useValue: fakeAuthStorageService }]
});
beforeEach(() => {
let called;
let rbdService: RbdService;
let notificationService: NotificationService;
+ let authStorageService: AuthStorageService;
beforeEach(() => {
called = false;
rbdService = new RbdService(null);
notificationService = new NotificationService(null, null);
+ authStorageService = new AuthStorageService();
+ authStorageService.set('user', { 'rbd-image': ['create', 'read', 'update', 'delete'] });
component = new RbdSnapshotListComponent(
+ authStorageService,
null,
null,
null,
import { CdTableSelection } from '../../../shared/models/cd-table-selection';
import { ExecutingTask } from '../../../shared/models/executing-task';
import { FinishedTask } from '../../../shared/models/finished-task';
+import { Permission } from '../../../shared/models/permissions';
import { CdDatePipe } from '../../../shared/pipes/cd-date.pipe';
import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
+import { AuthStorageService } from '../../../shared/services/auth-storage.service';
import { NotificationService } from '../../../shared/services/notification.service';
import { TaskManagerService } from '../../../shared/services/task-manager.service';
import { RbdSnapshotFormComponent } from '../rbd-snapshot-form/rbd-snapshot-form.component';
@ViewChild('protectTpl') protectTpl: TemplateRef<any>;
@ViewChild('rollbackTpl') rollbackTpl: TemplateRef<any>;
+ permission: Permission;
+
data: RbdSnapshotModel[];
columns: CdTableColumn[];
selection = new CdTableSelection();
constructor(
+ private authStorageService: AuthStorageService,
private modalService: BsModalService,
private dimlessBinaryPipe: DimlessBinaryPipe,
private cdDatePipe: CdDatePipe,
private rbdService: RbdService,
private taskManagerService: TaskManagerService,
private notificationService: NotificationService
- ) {}
+ ) {
+ this.permission = this.authStorageService.getPermissions().rbdImage;
+ }
ngOnInit() {
this.columns = [
(fetchData)="getHosts()">
<ng-template #servicesTpl let-value="value">
<span *ngFor="let service of value; last as isLast">
- <a [routerLink]="[service.cdLink]">{{ service.type }}.{{ service.id }}</a>{{ !isLast ? ", " : "" }}
+ <a [routerLink]="[service.cdLink]"
+ *ngIf="service.canRead">{{ service.type }}.{{ service.id }}</a>
+ <span *ngIf="!service.canRead">{{ service.type }}.{{ service.id }}</span>
+ {{ !isLast ? ", " : "" }}
</span>
</ng-template>
</cd-table>
import { BsDropdownModule } from 'ngx-bootstrap';
import { ComponentsModule } from '../../../shared/components/components.module';
+import { Permissions } from '../../../shared/models/permissions';
+import { AuthStorageService } from '../../../shared/services/auth-storage.service';
import { SharedModule } from '../../../shared/shared.module';
import { configureTestBed } from '../../../shared/unit-test-helper';
import { HostsComponent } from './hosts.component';
let component: HostsComponent;
let fixture: ComponentFixture<HostsComponent>;
+ const fakeAuthStorageService = {
+ getPermissions: () => {
+ return new Permissions({ hosts: ['read', 'update', 'create', 'delete'] });
+ }
+ };
+
configureTestBed({
imports: [
SharedModule,
BsDropdownModule.forRoot(),
RouterTestingModule
],
+ providers: [{ provide: AuthStorageService, useValue: fakeAuthStorageService }],
declarations: [HostsComponent]
});
import { HostService } from '../../../shared/api/host.service';
import { CdTableColumn } from '../../../shared/models/cd-table-column';
+import { Permissions } from '../../../shared/models/permissions';
import { CephShortVersionPipe } from '../../../shared/pipes/ceph-short-version.pipe';
+import { AuthStorageService } from '../../../shared/services/auth-storage.service';
@Component({
selector: 'cd-hosts',
styleUrls: ['./hosts.component.scss']
})
export class HostsComponent implements OnInit {
-
+ permissions: Permissions;
columns: Array<CdTableColumn> = [];
hosts: Array<object> = [];
isLoadingHosts = false;
@ViewChild('servicesTpl') public servicesTpl: TemplateRef<any>;
- constructor(private hostService: HostService,
- private cephShortVersionPipe: CephShortVersionPipe) { }
+ constructor(
+ private authStorageService: AuthStorageService,
+ private hostService: HostService,
+ private cephShortVersionPipe: CephShortVersionPipe
+ ) {
+ this.permissions = this.authStorageService.getPermissions();
+ }
ngOnInit() {
this.columns = [
if (this.isLoadingHosts) {
return;
}
+ const typeToPermissionKey = {
+ mds: 'cephfs',
+ mon: 'monitor',
+ osd: 'osd',
+ rgw: 'rgw',
+ 'rbd-mirror': 'rbdMirroring',
+ mgr: 'manager'
+ };
this.isLoadingHosts = true;
- this.hostService.list().then((resp) => {
- resp.map((host) => {
- host.services.map((service) => {
- service.cdLink = `/perf_counters/${service.type}/${service.id}`;
- return service;
+ this.hostService
+ .list()
+ .then((resp) => {
+ resp.map((host) => {
+ host.services.map((service) => {
+ service.cdLink = `/perf_counters/${service.type}/${service.id}`;
+ const permissionKey = typeToPermissionKey[service.type];
+ service.canRead = this.permissions[permissionKey].read;
+ return service;
+ });
+ return host;
});
- return host;
+ this.hosts = resp;
+ this.isLoadingHosts = false;
+ })
+ .catch(() => {
+ this.isLoadingHosts = false;
});
- this.hosts = resp;
- this.isLoadingHosts = false;
- }).catch(() => {
- this.isLoadingHosts = false;
- });
}
}
selectionType="single"
(updateSelection)="updateSelection($event)"
[updateSelectionOnRefresh]="false">
- <div class="table-actions">
+ <div class="table-actions"
+ *ngIf="permission.update">
<div class="btn-group"
dropdown>
<button dropdownToggle
import { ComponentsModule } from '../../../../shared/components/components.module';
import { DataTableModule } from '../../../../shared/datatable/datatable.module';
+import { Permissions } from '../../../../shared/models/permissions';
import { DimlessPipe } from '../../../../shared/pipes/dimless.pipe';
+import { AuthStorageService } from '../../../../shared/services/auth-storage.service';
import { FormatterService } from '../../../../shared/services/formatter.service';
import { SharedModule } from '../../../../shared/shared.module';
import { configureTestBed } from '../../../../shared/unit-test-helper';
let component: OsdListComponent;
let fixture: ComponentFixture<OsdListComponent>;
+ const fakeAuthStorageService = {
+ getPermissions: () => {
+ return new Permissions({ osd: ['read', 'update', 'create', 'delete'] });
+ }
+ };
+
configureTestBed({
imports: [
HttpClientModule,
SharedModule
],
declarations: [OsdListComponent, OsdDetailsComponent, OsdPerformanceHistogramComponent],
- providers: [DimlessPipe, FormatterService]
+ providers: [
+ DimlessPipe,
+ FormatterService,
+ { provide: AuthStorageService, useValue: fakeAuthStorageService }
+ ]
});
beforeEach(() => {
import { CellTemplate } from '../../../../shared/enum/cell-template.enum';
import { CdTableColumn } from '../../../../shared/models/cd-table-column';
import { CdTableSelection } from '../../../../shared/models/cd-table-selection';
+import { Permission } from '../../../../shared/models/permissions';
import { DimlessBinaryPipe } from '../../../../shared/pipes/dimless-binary.pipe';
+import { AuthStorageService } from '../../../../shared/services/auth-storage.service';
import { OsdScrubModalComponent } from '../osd-scrub-modal/osd-scrub-modal.component';
@Component({
@ViewChild('osdUsageTpl') osdUsageTpl: TemplateRef<any>;
@ViewChild(TableComponent) tableComponent: TableComponent;
+ permission: Permission;
bsModalRef: BsModalRef;
osds = [];
columns: CdTableColumn[];
selection = new CdTableSelection();
constructor(
+ private authStorageService: AuthStorageService,
private osdService: OsdService,
private dimlessBinaryPipe: DimlessBinaryPipe,
private modalService: BsModalService
- ) {}
+ ) {
+ this.permission = this.authStorageService.getPermissions().osd;
+ }
ngOnInit() {
this.columns = [
<!--STATS -->
<div class="row">
<div class="col-md-6">
- <div class="well">
+ <div class="well"
+ *ngIf="contentData.mon_status">
<div class="media">
<div class="media-left">
<i class="fa fa-database fa-fw"></i>
</div>
</div>
<div class="col-md-6">
- <div class="well">
+ <div class="well"
+ *ngIf="contentData.osd_map">
<div class="media">
<div class="media-left">
<i class="fa fa-hdd-o fa-fw"></i>
</div>
<div class="row">
<div class="col-md-6">
- <div class="well">
+ <div class="well"
+ *ngIf="contentData.fs_map">
<div class="media">
<div class="media-left">
<i class="fa fa-folder fa-fw"></i>
</div>
</div>
<div class="col-md-6">
- <div class="well">
+ <div class="well"
+ *ngIf="contentData.mgr_map">
<div class="media">
<div class="media-left">
<i class="fa fa-cog fa-fw"></i>
<div class="row">
<!-- USAGE -->
<div class="col-md-6">
- <div class="well">
+ <div class="well"
+ *ngIf="contentData.df?.stats?.total_objects">
<fieldset class="usage">
<legend i18n>Usage</legend>
</div>
<div class="col-md-6">
- <div class="well">
+ <div class="well"
+ *ngIf="contentData.pools">
<fieldset>
<legend i18n>Pools</legend>
<table class="table table-condensed">
<div class="row">
<div class="col-md-12">
<!-- LOGS -->
- <div class="well">
+ <div class="well"
+ *ngIf="contentData.clog || contentData.audit_log">
<fieldset>
<legend i18n>Logs</legend>
<tabset>
<tab heading="Cluster log"
class="text-monospace"
+ *ngIf="contentData.clog"
i18n-heading>
<span *ngFor="let line of contentData.clog">
{{ line.stamp }} {{ line.priority }}
</tab>
<tab heading="Audit log"
class="text-monospace"
+ *ngIf="contentData.audit_log"
i18n-heading>
<span *ngFor="let line of contentData.audit_log">
{{ line.stamp }} {{ line.priority }}
<div class="btn-group" dropdown>
<button type="button"
class="btn btn-sm btn-primary"
- *ngIf="!selection.hasSelection"
+ *ngIf="permission.create && (
+ permission.update && permission.delete && !selection.hasSelection ||
+ !permission.update && !permission.delete ||
+ !permission.update && permission.delete && !selection.hasMultiSelection ||
+ permission.update && !selection.hasSingleSelection && !permission.delete)"
routerLink="/rgw/bucket/add">
<i class="fa fa-fw fa-plus"></i>
<ng-container i18n>Add</ng-container>
</button>
<button type="button"
class="btn btn-sm btn-primary"
- *ngIf="selection.hasSingleSelection"
+ [ngClass]="{'disabled': !selection.hasSelection}"
+ *ngIf="permission.update && (!permission.create && !selection.hasMultiSelection || selection.hasSingleSelection)"
routerLink="/rgw/bucket/edit/{{ selection.first()?.bucket }}">
<i class="fa fa-fw fa-pencil"></i>
<ng-container i18n>Edit</ng-container>
</button>
<button type="button"
class="btn btn-sm btn-primary"
- *ngIf="selection.hasMultiSelection"
+ [ngClass]="{'disabled': !selection.hasSelection}"
+ *ngIf="permission.delete && (!permission.update && !permission.create || selection.hasMultiSelection)"
(click)="deleteAction()">
<i class="fa fa-fw fa-trash-o"></i>
<ng-container i18n>Delete</ng-container>
</button>
<button type="button"
class="btn btn-sm btn-primary dropdown-toggle dropdown-toggle-split"
+ *ngIf="((permission.create?1:0) + (permission.update?1:0) + (permission.delete?1:0)) > 1"
dropdownToggle>
<span class="caret"></span>
<span class="sr-only"></span>
<ul class="dropdown-menu"
*dropdownMenu
role="menu">
- <li role="menuitem">
+ <li role="menuitem"
+ *ngIf="permission.create">
<a class="dropdown-item"
routerLink="/rgw/bucket/add"
i18n>
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.update"
[ngClass]="{'disabled': !selection.hasSingleSelection}">
<a class="dropdown-item"
routerLink="/rgw/bucket/edit/{{ selection.first()?.bucket }}"
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.delete"
[ngClass]="{'disabled': !selection.hasSelection}">
<a class="dropdown-item"
(click)="deleteAction()"
import { TableComponent } from '../../../shared/datatable/table/table.component';
import { CdTableColumn } from '../../../shared/models/cd-table-column';
import { CdTableSelection } from '../../../shared/models/cd-table-selection';
+import { Permission } from '../../../shared/models/permissions';
+import { AuthStorageService } from '../../../shared/services/auth-storage.service';
@Component({
selector: 'cd-rgw-bucket-list',
export class RgwBucketListComponent {
@ViewChild(TableComponent) table: TableComponent;
+ permission: Permission;
columns: CdTableColumn[] = [];
buckets: object[] = [];
selection: CdTableSelection = new CdTableSelection();
- constructor(private rgwBucketService: RgwBucketService, private bsModalService: BsModalService) {
+ constructor(
+ private authStorageService: AuthStorageService,
+ private rgwBucketService: RgwBucketService,
+ private bsModalService: BsModalService
+ ) {
+ this.permission = this.authStorageService.getPermissions().rgw;
this.columns = [
{
name: 'Name',
<div class="btn-group" dropdown>
<button type="button"
class="btn btn-sm btn-primary"
- *ngIf="!selection.hasSelection"
+ *ngIf="permission.create && (
+ permission.update && permission.delete && !selection.hasSelection ||
+ !permission.update && !permission.delete ||
+ !permission.update && permission.delete && !selection.hasMultiSelection ||
+ permission.update && !selection.hasSingleSelection && !permission.delete)"
routerLink="/rgw/user/add">
<i class="fa fa-fw fa-plus"></i>
<ng-container i18n>Add</ng-container>
</button>
<button type="button"
class="btn btn-sm btn-primary"
- *ngIf="selection.hasSingleSelection"
+ [ngClass]="{'disabled': !selection.hasSelection}"
+ *ngIf="permission.update && (!permission.create && !selection.hasMultiSelection || selection.hasSingleSelection)"
routerLink="/rgw/user/edit/{{ selection.first()?.user_id }}">
<i class="fa fa-fw fa-pencil"></i>
<ng-container i18n>Edit</ng-container>
</button>
<button type="button"
class="btn btn-sm btn-primary"
- *ngIf="selection.hasMultiSelection"
+ [ngClass]="{'disabled': !selection.hasSelection}"
+ *ngIf="permission.delete && (!permission.update && !permission.create || selection.hasMultiSelection)"
(click)="deleteAction()">
<i class="fa fa-fw fa-trash-o"></i>
<ng-container i18n>Delete</ng-container>
</button>
<button type="button"
class="btn btn-sm btn-primary dropdown-toggle dropdown-toggle-split"
+ *ngIf="((permission.create?1:0) + (permission.update?1:0) + (permission.delete?1:0)) > 1"
dropdownToggle>
<span class="caret"></span>
<span class="sr-only"></span>
<ul class="dropdown-menu"
*dropdownMenu
role="menu">
- <li role="menuitem">
+ <li role="menuitem"
+ *ngIf="permission.create">
<a class="dropdown-item"
routerLink="/rgw/user/add"
i18n>
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.update"
[ngClass]="{'disabled': !selection.hasSingleSelection}">
<a class="dropdown-item"
routerLink="/rgw/user/edit/{{ selection.first()?.user_id }}"
</a>
</li>
<li role="menuitem"
+ *ngIf="permission.delete"
[ngClass]="{'disabled': !selection.hasSelection}">
<a class="dropdown-item"
(click)="deleteAction()"
import { ModalModule } from 'ngx-bootstrap';
import { RgwUserService } from '../../../shared/api/rgw-user.service';
+import { SharedModule } from '../../../shared/shared.module';
import { configureTestBed } from '../../../shared/unit-test-helper';
import { RgwUserListComponent } from './rgw-user-list.component';
configureTestBed({
declarations: [RgwUserListComponent],
- imports: [RouterTestingModule, HttpClientTestingModule, ModalModule.forRoot()],
+ imports: [RouterTestingModule, HttpClientTestingModule, ModalModule.forRoot(), SharedModule],
providers: [RgwUserService],
schemas: [NO_ERRORS_SCHEMA]
});
import { CellTemplate } from '../../../shared/enum/cell-template.enum';
import { CdTableColumn } from '../../../shared/models/cd-table-column';
import { CdTableSelection } from '../../../shared/models/cd-table-selection';
+import { Permission } from '../../../shared/models/permissions';
+import { AuthStorageService } from '../../../shared/services/auth-storage.service';
@Component({
selector: 'cd-rgw-user-list',
export class RgwUserListComponent {
@ViewChild(TableComponent) table: TableComponent;
+ permission: Permission;
columns: CdTableColumn[] = [];
users: object[] = [];
selection: CdTableSelection = new CdTableSelection();
- constructor(private rgwUserService: RgwUserService, private bsModalService: BsModalService) {
+ constructor(
+ private authStorageService: AuthStorageService,
+ private rgwUserService: RgwUserService,
+ private bsModalService: BsModalService
+ ) {
+ this.permission = this.authStorageService.getPermissions().rgw;
this.columns = [
{
name: 'Username',
import { NgModule } from '@angular/core';
import { AuthModule } from './auth/auth.module';
+import { ForbiddenComponent } from './forbidden/forbidden.component';
import { NavigationModule } from './navigation/navigation.module';
import { NotFoundComponent } from './not-found/not-found.component';
@NgModule({
- imports: [
- CommonModule,
- NavigationModule,
- AuthModule
- ],
+ imports: [CommonModule, NavigationModule, AuthModule],
exports: [NavigationModule],
- declarations: [NotFoundComponent]
+ declarations: [NotFoundComponent, ForbiddenComponent]
})
-export class CoreModule { }
+export class CoreModule {}
--- /dev/null
+<div class="row">
+ <div class="col-md-12 text-center">
+ <h1 i18n>Forbidden</h1>
+
+ <i class="fa fa-lock text-danger"></i>
+
+ <h2 i18n>Sorry, you are not allowed to see what you were looking for.</h2>
+
+ </div>
+</div>
--- /dev/null
+h1 {
+ font-size: -webkit-xxx-large;
+ font-family: monospace;
+}
+
+h2 {
+ font-size: xx-large;
+ font-family: monospace;
+}
+
+i {
+ font-size: 200px;
+}
--- /dev/null
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ForbiddenComponent } from './forbidden.component';
+
+describe('ForbiddenComponent', () => {
+ let component: ForbiddenComponent;
+ let fixture: ComponentFixture<ForbiddenComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ForbiddenComponent]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ForbiddenComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
--- /dev/null
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'cd-forbidden',
+ templateUrl: './forbidden.component.html',
+ styleUrls: ['./forbidden.component.scss']
+})
+export class ForbiddenComponent {
+ constructor() {}
+}
<!-- Cluster -->
<li dropdown
routerLinkActive="active"
- class="dropdown tc_menuitem tc_menuitem_cluster">
+ class="dropdown tc_menuitem tc_menuitem_cluster"
+ *ngIf="permissions.hosts.read || permissions.monitor.read || permissions.osd.read || permissions.configOpt.read">
<a dropdownToggle
class="dropdown-toggle"
data-toggle="dropdown">
<ul *dropdownMenu
class="dropdown-menu">
<li routerLinkActive="active"
- class="tc_submenuitem tc_submenuitem_hosts">
+ class="tc_submenuitem tc_submenuitem_hosts"
+ *ngIf="permissions.hosts.read">
<a i18n
class="dropdown-item"
routerLink="/hosts">Hosts
</a>
</li>
<li routerLinkActive="active"
- class="tc_submenuitem tc_submenuitem_cluster_monitor">
+ class="tc_submenuitem tc_submenuitem_cluster_monitor"
+ *ngIf="permissions.monitor.read">
<a i18n
class="dropdown-item"
routerLink="/monitor/"> Monitors
</a>
</li>
<li routerLinkActive="active"
- class="tc_submenuitem tc_submenuitem_hosts">
+ class="tc_submenuitem tc_submenuitem_hosts"
+ *ngIf="permissions.osd.read">
<a i18n
class="dropdown-item"
routerLink="/osd">OSDs
</a>
</li>
<li routerLinkActive="active"
- class="tc_submenuitem tc_submenuitem_configuration">
+ class="tc_submenuitem tc_submenuitem_configuration"
+ *ngIf="permissions.configOpt.read">
<a i18n
class="dropdown-item"
routerLink="/configuration">Configuration Doc.
<!-- Pools -->
<li routerLinkActive="active"
- class="tc_menuitem tc_menuitem_pool">
+ class="tc_menuitem tc_menuitem_pool"
+ *ngIf="permissions.pool.read">
<a i18n
routerLink="/pool">Pool
</a>
<!-- Block -->
<li dropdown
routerLinkActive="active"
- class="dropdown tc_menuitem tc_menuitem_block">
+ class="dropdown tc_menuitem tc_menuitem_block"
+ *ngIf="permissions.rbdImage.read || permissions.rbdMirroring.read || permissions.iscsi.read">
<a dropdownToggle
class="dropdown-toggle"
data-toggle="dropdown"
</a>
<ul class="dropdown-menu">
- <li routerLinkActive="active">
+ <li routerLinkActive="active"
+ *ngIf="permissions.rbdImage.read">
<a i18n
class="dropdown-item"
routerLink="/block/rbd">Images</a>
</li>
<li routerLinkActive="active"
- class="tc_submenuitem tc_submenuitem_block_mirroring">
+ class="tc_submenuitem tc_submenuitem_block_mirroring"
+ *ngIf="permissions.rbdMirroring.read">
<a i18n
class="dropdown-item"
routerLink="/mirroring/"> Mirroring
</a>
</li>
- <li routerLinkActive="active">
+ <li routerLinkActive="active"
+ *ngIf="permissions.iscsi.read">
<a i18n
class="dropdown-item"
routerLink="/block/iscsi">iSCSI</a>
<!-- Filesystem -->
<li routerLinkActive="active"
- class="tc_menuitem tc_menuitem_cephs">
+ class="tc_menuitem tc_menuitem_cephs"
+ *ngIf="permissions.cephfs.read">
<a i18n
routerLink="/cephfs">Filesystems
</a>
<!-- Object Gateway -->
<li dropdown
routerLinkActive="active"
- class="dropdown tc_menuitem tc_menuitem_rgw">
+ class="dropdown tc_menuitem tc_menuitem_rgw"
+ *ngIf="permissions.rgw.read">
<a dropdownToggle
class="dropdown-toggle"
data-toggle="dropdown">
import { Component, OnInit } from '@angular/core';
+
+import { Permissions } from '../../../shared/models/permissions';
+import { AuthStorageService } from '../../../shared/services/auth-storage.service';
import { SummaryService } from '../../../shared/services/summary.service';
@Component({
styleUrls: ['./navigation.component.scss']
})
export class NavigationComponent implements OnInit {
+ permissions: Permissions;
summaryData: any;
isCollapsed = true;
- constructor(private summaryService: SummaryService) {}
+ constructor(
+ private authStorageService: AuthStorageService,
+ private summaryService: SummaryService
+ ) {
+ this.permissions = this.authStorageService.getPermissions();
+ }
ngOnInit() {
this.summaryService.summaryData$.subscribe((data: any) => {
.post('api/auth', credentials)
.toPromise()
.then((resp: Credentials) => {
- this.authStorageService.set(resp.username);
+ this.authStorageService.set(resp.username, resp.permissions);
});
}
export class Credentials {
username: string;
password: string;
+ permissions: any;
stay_signed_in = false;
}
--- /dev/null
+export class Permission {
+ read: boolean;
+ create: boolean;
+ update: boolean;
+ delete: boolean;
+
+ constructor(serverPermission: Array<string> = []) {
+ this.read = serverPermission.indexOf('read') !== -1;
+ this.create = serverPermission.indexOf('create') !== -1;
+ this.update = serverPermission.indexOf('update') !== -1;
+ this.delete = serverPermission.indexOf('delete') !== -1;
+ }
+}
+
+export class Permissions {
+ hosts: Permission;
+ configOpt: Permission;
+ pool: Permission;
+ osd: Permission;
+ monitor: Permission;
+ rbdImage: Permission;
+ iscsi: Permission;
+ rbdMirroring: Permission;
+ rgw: Permission;
+ cephfs: Permission;
+ manager: Permission;
+ log: Permission;
+
+ constructor(serverPermissions: any) {
+ this.hosts = new Permission(serverPermissions['hosts']);
+ this.configOpt = new Permission(serverPermissions['config-opt']);
+ this.pool = new Permission(serverPermissions['pool']);
+ this.osd = new Permission(serverPermissions['osd']);
+ this.monitor = new Permission(serverPermissions['monitor']);
+ this.rbdImage = new Permission(serverPermissions['rbd-image']);
+ this.iscsi = new Permission(serverPermissions['iscsi']);
+ this.rbdMirroring = new Permission(serverPermissions['rbd-mirroring']);
+ this.rgw = new Permission(serverPermissions['rgw']);
+ this.cephfs = new Permission(serverPermissions['cephfs']);
+ this.manager = new Permission(serverPermissions['manager']);
+ this.log = new Permission(serverPermissions['log']);
+ }
+}
this.authStorageService.remove();
this.router.navigate(['/login']);
break;
+ case 403:
+ this.router.navigate(['/403']);
+ break;
case 404:
this.router.navigate(['/404']);
break;
import { Injectable } from '@angular/core';
+import { Permissions } from '../models/permissions';
import { ServicesModule } from './services.module';
@Injectable({
providedIn: ServicesModule
})
export class AuthStorageService {
+ constructor() {}
- constructor() {
- }
-
- set(username: string) {
+ set(username: string, permissions: any = {}) {
localStorage.setItem('dashboard_username', username);
+ localStorage.setItem('dashboard_permissions', JSON.stringify(new Permissions(permissions)));
}
remove() {
return localStorage.getItem('dashboard_username') !== null;
}
+ getPermissions(): Permissions {
+ return JSON.parse(
+ localStorage.getItem('dashboard_permissions') || JSON.stringify(new Permissions({}))
+ );
+ }
}