self.assertStatus(400)
self.assertError(code='cannot_update_system_role',
component='role')
+
+ def test_clone_role(self):
+ self._post('/api/role/read-only/clone', {'new_name': 'foo'})
+ self.assertStatus(201)
+ self._delete('/api/role/foo')
import cherrypy
-from . import ApiController, RESTController, UiApiController
+from . import ApiController, RESTController, UiApiController,\
+ CreatePermission
from .. import mgr
from ..exceptions import RoleDoesNotExist, DashboardException,\
RoleIsAssociatedWithUser, RoleAlreadyExists
role.set_scope_permissions(scope, permissions)
def list(self):
+ # type: () -> list
roles = dict(mgr.ACCESS_CTRL_DB.roles)
roles.update(SYSTEM_ROLES)
roles = sorted(roles.values(), key=lambda role: role.name)
return [Role._role_to_dict(r) for r in roles]
- def get(self, name):
+ @staticmethod
+ def _get(name):
role = SYSTEM_ROLES.get(name)
if not role:
try:
raise cherrypy.HTTPError(404)
return Role._role_to_dict(role)
- def create(self, name=None, description=None, scopes_permissions=None):
+ def get(self, name):
+ # type: (str) -> dict
+ return Role._get(name)
+
+ @staticmethod
+ def _create(name=None, description=None, scopes_permissions=None):
if not name:
raise DashboardException(msg='Name is required',
code='name_required',
mgr.ACCESS_CTRL_DB.save()
return Role._role_to_dict(role)
+ def create(self, name=None, description=None, scopes_permissions=None):
+ # type: (str, str, dict) -> dict
+ return Role._create(name, description, scopes_permissions)
+
def set(self, name, description=None, scopes_permissions=None):
+ # type: (str, str, dict) -> dict
try:
role = mgr.ACCESS_CTRL_DB.get_role(name)
except RoleDoesNotExist:
return Role._role_to_dict(role)
def delete(self, name):
+ # type: (str) -> None
try:
mgr.ACCESS_CTRL_DB.delete_role(name)
except RoleDoesNotExist:
component='role')
mgr.ACCESS_CTRL_DB.save()
+ @RESTController.Resource('POST', status=201)
+ @CreatePermission
+ def clone(self, name, new_name):
+ # type: (str, str) -> dict
+ role = Role._get(name)
+ return Role._create(new_name, role.get('description'),
+ role.get('scopes_permissions'))
+
@UiApiController('/scope', SecurityScope.USER)
class Scope(RESTController):
expect(tableActions).toEqual({
'create,update,delete': {
- actions: ['Create', 'Edit', 'Delete'],
+ actions: ['Create', 'Clone', 'Edit', 'Delete'],
primary: { multiple: 'Create', executing: 'Edit', single: 'Edit', no: 'Create' }
},
'create,update': {
- actions: ['Create', 'Edit'],
+ actions: ['Create', 'Clone', 'Edit'],
primary: { multiple: 'Create', executing: 'Edit', single: 'Edit', no: 'Create' }
},
'create,delete': {
- actions: ['Create', 'Delete'],
+ actions: ['Create', 'Clone', 'Delete'],
primary: { multiple: 'Create', executing: 'Delete', single: 'Delete', no: 'Create' }
},
create: {
- actions: ['Create'],
+ actions: ['Create', 'Clone'],
primary: { multiple: 'Create', executing: 'Create', single: 'Create', no: 'Create' }
},
'update,delete': {
import { RoleService } from '../../../shared/api/role.service';
import { ScopeService } from '../../../shared/api/scope.service';
import { CriticalConfirmationModalComponent } from '../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
+import { FormModalComponent } from '../../../shared/components/form-modal/form-modal.component';
import { ActionLabelsI18n } from '../../../shared/constants/app.constants';
import { CellTemplate } from '../../../shared/enum/cell-template.enum';
import { Icons } from '../../../shared/enum/icons.enum';
routerLink: () => this.urlBuilder.getCreate(),
name: this.actionLabels.CREATE
};
+ const cloneAction: CdTableAction = {
+ permission: 'create',
+ icon: Icons.clone,
+ name: this.actionLabels.CLONE,
+ disable: () => !this.selection.hasSingleSelection,
+ click: () => this.cloneRole()
+ };
const editAction: CdTableAction = {
permission: 'update',
icon: Icons.edit,
click: () => this.deleteRoleModal(),
name: this.actionLabels.DELETE
};
- this.tableActions = [addAction, editAction, deleteAction];
+ this.tableActions = [addAction, cloneAction, editAction, deleteAction];
}
ngOnInit() {
}
});
}
+
+ cloneRole() {
+ const name = this.selection.first().name;
+ this.modalRef = this.modalService.show(FormModalComponent, {
+ initialState: {
+ fields: [
+ {
+ type: 'text',
+ name: 'newName',
+ value: `${name}_clone`,
+ label: this.i18n('New name'),
+ required: true
+ }
+ ],
+ titleText: this.i18n('Clone Role'),
+ submitButtonText: this.i18n('Clone Role'),
+ onSubmit: (values) => {
+ this.roleService.clone(name, values['newName']).subscribe(() => {
+ this.getRoles();
+ this.notificationService.show(
+ NotificationType.success,
+ this.i18n(`Cloned role '{{dst_name}}' from '{{src_name}}'`, {
+ src_name: name,
+ dst_name: values['newName']
+ })
+ );
+ });
+ }
+ }
+ });
+ }
}
expect(req.request.method).toBe('GET');
});
+ it('should call clone', () => {
+ service.clone('foo', 'bar').subscribe();
+ const req = httpTesting.expectOne('api/role/foo/clone?new_name=bar');
+ expect(req.request.method).toBe('POST');
+ });
+
it('should check if role name exists', () => {
let exists: boolean;
service.exists('role1').subscribe((res: boolean) => {
-import { HttpClient } from '@angular/common/http';
+import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, of as observableOf } from 'rxjs';
return this.http.get('api/role');
}
- delete(role: string) {
- return this.http.delete(`api/role/${role}`);
+ delete(name: string) {
+ return this.http.delete(`api/role/${name}`);
}
- get(name) {
+ get(name: string) {
return this.http.get(`api/role/${name}`);
}
return this.http.post(`api/role`, role);
}
+ clone(name: string, newName: string) {
+ let params = new HttpParams();
+ params = params.append('new_name', newName);
+ return this.http.post(`api/role/${name}/clone`, null, { params });
+ }
+
update(role: RoleFormModel) {
return this.http.put(`api/role/${role.name}`, role);
}