Skip to content

Commit

Permalink
Merge pull request #8277 from ever-co/fix/#8216-role-permissions-pres…
Browse files Browse the repository at this point in the history
…elect-toggle-button

[Bug] Roles / Permissions: Pre-Selected Toggle Buttons
  • Loading branch information
rahul-rocket authored Sep 28, 2024
2 parents e63d589 + 4171330 commit 1edb7ca
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 174 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@ <h4>
></nb-icon>
</button>
</nb-form-field>
<nb-autocomplete
#autocomplete
(selectedChange)="onSelectionChange($event)"
>
<nb-autocomplete #autocomplete (selectedChange)="onSelectionChange($event)">
<nb-option
*ngFor="let role of roles$ | async"
[value]="role.name"
Expand All @@ -41,10 +38,7 @@ <h4>
</nb-autocomplete>
</div>
</div>
<div
class="col-6"
*ngxPermissionsOnly="['CHANGE_ROLES_PERMISSIONS']"
>
<div class="col-6" *ngxPermissionsOnly="['CHANGE_ROLES_PERMISSIONS']">
<ng-container *ngIf="isWantToCreate">
<div class="actions create">
<button
Expand All @@ -59,9 +53,7 @@ <h4>
{{ 'BUTTONS.CREATE_NEW_ROLE' | translate : { name: input.value } }}
</div>
</ng-container>
<ng-container
*ngIf="role && role.isSystem === false && !isWantToCreate"
>
<ng-container *ngIf="role && role.isSystem === false && !isWantToCreate">
<div class="actions delete">
<button
nbButton
Expand All @@ -71,10 +63,7 @@ <h4>
size="small"
[nbTooltip]="'BUTTONS.DELETE' | translate"
>
<nb-icon
status="danger"
icon="trash-2-outline"
></nb-icon>
<nb-icon status="danger" icon="trash-2-outline"></nb-icon>
</button>
{{ 'BUTTONS.DELETE_EXISTING_ROLE' | translate : { name: role.name } }}
</div>
Expand All @@ -85,35 +74,20 @@ <h4>
<div class="col-12 col-xl-6">
<nb-card>
<nb-card-header>
{{
'ORGANIZATIONS_PAGE.PERMISSIONS.GROUPS.GENERAL'
| translate
}}
{{ 'ORGANIZATIONS_PAGE.PERMISSIONS.GROUPS.GENERAL' | translate }}
</nb-card-header>
<nb-card-body class="permission-items-col">
<nb-toggle
*ngFor="let permission of permissionGroups.GENERAL"
[(checked)]="enabledPermissions[permission]"
(checkedChange)="
permissionChanged(
permission,
$event,
!isDisabledGeneralPermissions()
)
"
(checkedChange)="permissionChanged(permission, $event, !isDisabledGeneralPermissions())"
labelPosition="start"
status="basic"
[disabled]="isDisabledGeneralPermissions()"
>
<div class="custom-permission-view">
<strong>{{
'ORGANIZATIONS_PAGE.PERMISSIONS.' +
permission | translate
}}</strong>
<small>{{
'ORGANIZATIONS_PAGE.PERMISSIONS.' +
permission | translate
}}</small>
<strong>{{ 'ORGANIZATIONS_PAGE.PERMISSIONS.' + permission | translate }}</strong>
<small>{{ 'ORGANIZATIONS_PAGE.PERMISSIONS.' + permission | translate }}</small>
</div>
</nb-toggle>
</nb-card-body>
Expand All @@ -122,46 +96,28 @@ <h4>
<div class="col-12 col-xl-6">
<nb-card>
<nb-card-header
>{{
'ORGANIZATIONS_PAGE.PERMISSIONS.GROUPS.ADMINISTRATION'
| translate
}}
>{{ 'ORGANIZATIONS_PAGE.PERMISSIONS.GROUPS.ADMINISTRATION' | translate }}
<nb-icon
[nbTooltip]="
'ORGANIZATIONS_PAGE.PERMISSIONS.ONLY_ADMIN'
| translate
"
[nbTooltip]="'ORGANIZATIONS_PAGE.PERMISSIONS.ONLY_ADMIN' | translate"
icon="question-mark-circle-outline"
size="tiny"
>
</nb-icon>
</nb-card-header>
<nb-card-body class="permission-items-col">
<nb-toggle
*ngFor="
let permission of getAdministrationPermissions()
"
*ngFor="let permission of getAdministrationPermissions()"
[(checked)]="enabledPermissions[permission]"
(checkedChange)="
permissionChanged(
permission,
$event,
!isDisabledAdministrationPermissions()
)
permissionChanged(permission, $event, !isDisabledAdministrationPermissions())
"
labelPosition="start"
status="basic"
[disabled]="isDisabledAdministrationPermissions()"
>
<div class="custom-permission-view">
<strong>{{
'ORGANIZATIONS_PAGE.PERMISSIONS.' +
permission | translate
}}</strong>
<small>{{
'ORGANIZATIONS_PAGE.PERMISSIONS.' +
permission | translate
}}</small>
<strong>{{ 'ORGANIZATIONS_PAGE.PERMISSIONS.' + permission | translate }}</strong>
<small>{{ 'ORGANIZATIONS_PAGE.PERMISSIONS.' + permission | translate }}</small>
</div>
</nb-toggle>
</nb-card-body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { FormControl } from '@angular/forms';
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
import { PermissionGroups, IRolePermission, RolesEnum, IUser, IRole, PermissionsEnum } from '@gauzy/contracts';
import { TranslateService } from '@ngx-translate/core';
import { debounceTime, filter, tap, map } from 'rxjs/operators';
import { Observable, Subject, of as observableOf, startWith, catchError } from 'rxjs';
import { debounceTime, filter, tap, map } from 'rxjs/operators';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { TranslationBaseComponent } from '@gauzy/ui-core/i18n';
import { environment } from '@gauzy/ui-config';
import { PermissionGroups, IRolePermission, RolesEnum, IUser, IRole, PermissionsEnum } from '@gauzy/contracts';
import { RolePermissionsService, RoleService, Store, ToastrService } from '@gauzy/ui-core/core';
import { TranslationBaseComponent } from '@gauzy/ui-core/i18n';

@UntilDestroy({ checkProperties: true })
@Component({
Expand All @@ -22,17 +22,13 @@ export class RolesPermissionsComponent extends TranslationBaseComponent implemen
isWantToCreate: boolean = false;
loading: boolean;
enabledPermissions: any = {};

user: IUser;
role: IRole;
roles: IRole[] = [];
permissions: IRolePermission[] = [];

roles$: Observable<IRole[]> = observableOf([]);
permissions$: Subject<any> = new Subject();

roleSubject$: Subject<any> = new Subject();

formControl: FormControl = new FormControl();
@ViewChild('input') input: ElementRef;

Expand Down Expand Up @@ -127,60 +123,65 @@ export class RolesPermissionsComponent extends TranslationBaseComponent implemen
}
}

async loadPermissions() {
/**
* Loads and sets the enabled permissions for the current role.
*/
async loadPermissions(): Promise<void> {
this.enabledPermissions = {};

if (!this.role) {
return;
}
if (!this.role) return;

const { tenantId } = this.user;
const { id: roleId } = this.role;
try {
const { id: roleId, tenantId } = this.role;

this.permissions = (
await this.rolePermissionsService
.getRolePermissions({
roleId,
tenantId
})
.finally(() => (this.loading = false))
).items;
// Fetch role permissions and update the enabledPermissions map
const { items: permissions } = await this.rolePermissionsService.getRolePermissions({
roleId,
tenantId
});

this.permissions.forEach((p) => {
this.enabledPermissions[p.permission] = p.enabled;
});
this.permissions = permissions;
this.permissions.forEach(({ permission, enabled }) => {
this.enabledPermissions[permission] = enabled;
});
} finally {
this.loading = false;
}
}

async permissionChanged(permission: string, enabled: boolean, allowChange: boolean) {
/**
* If anyone trying to update another users permissions without enough permission
*/
/**
* Handles the change in permission status and updates it accordingly.
*
* @param {string} permission - The name of the permission to be changed.
* @param {boolean} enabled - Indicates whether the permission should be enabled or disabled.
* @param {boolean} allowChange - Flag indicating whether the current user has the right to change the permission.
* @returns {Promise<void>}
*/
async permissionChanged(permission: string, enabled: boolean, allowChange: boolean): Promise<void> {
// Check if the user has permission to make changes
if (!allowChange) {
this.toastrService.danger(
this.getTranslation('TOASTR.MESSAGE.PERMISSION_UPDATE_ERROR'),
this.getTranslation('TOASTR.TITLE.ERROR')
);
return;
}

try {
const { id: roleId } = this.role;
const { tenantId } = this.user;

const permissionToEdit = this.permissions.find((p) => p.permission === permission);
const payload = { enabled, roleId, tenantId, permission };

const payload = {
enabled,
roleId,
tenantId,
permission
};
permissionToEdit && permissionToEdit.id
? await this.rolePermissionsService.update(permissionToEdit.id, {
...payload
})
: await this.rolePermissionsService.create({
...payload
});
// Update or create the permission based on its existence
if (permissionToEdit?.id) {
await this.rolePermissionsService.update(permissionToEdit.id, payload);
} else {
await this.rolePermissionsService.create(payload);
}

// Display success message
this.toastrService.success(
this.getTranslation('TOASTR.MESSAGE.PERMISSION_UPDATED', {
permissionName: this.getTranslation('ORGANIZATIONS_PAGE.PERMISSIONS.' + permission),
Expand All @@ -189,43 +190,49 @@ export class RolesPermissionsComponent extends TranslationBaseComponent implemen
this.getTranslation('TOASTR.TITLE.SUCCESS')
);
} catch (error) {
// Display error message
this.toastrService.danger(
this.getTranslation('TOASTR.MESSAGE.PERMISSION_UPDATE_ERROR'),
this.getTranslation('TOASTR.TITLE.ERROR')
);
} finally {
// Notify about permission update
this.permissions$.next(true);
}
}

/**
* CHANGE current selected role
* Handles the change of the currently selected role.
*/
onSelectedRole() {
onSelectedRole(): void {
this.role = this.getRoleByName(this.formControl.value);
this.isWantToCreate = !this.role;
this.permissions$.next(true);
}

/**
* GET role by name
* Retrieves a role by its name.
*
* @param name
* @returns
* @param {string} name - The name of the role to retrieve.
* @returns {IRole | undefined} - The found role, or undefined if not found.
*/
getRoleByName(name: IRole['name']) {
return this.roles.find((role: IRole) => name === role.name);
getRoleByName(name: IRole['name']): IRole | undefined {
return this.roles.find((role) => role.name === name);
}

/***
* GET Administration permissions & removed some permission in DEMO
/**
* Retrieves administration permissions, removing certain permissions in DEMO mode.
*
* @returns {PermissionsEnum[]} - The filtered list of administration permissions.
*/
getAdministrationPermissions(): PermissionsEnum[] {
// removed permissions for all users in DEMO mode
const deniedPermissions = [PermissionsEnum.ACCESS_DELETE_ACCOUNT, PermissionsEnum.ACCESS_DELETE_ALL_DATA];
const deniedPermissions = new Set([
PermissionsEnum.ACCESS_DELETE_ACCOUNT,
PermissionsEnum.ACCESS_DELETE_ALL_DATA
]);

return this.permissionGroups.ADMINISTRATION.filter((permission) =>
environment.DEMO ? !deniedPermissions.includes(permission) : true
return this.permissionGroups.ADMINISTRATION.filter(
(permission) => !environment.DEMO || !deniedPermissions.has(permission)
);
}

Expand Down Expand Up @@ -311,30 +318,21 @@ export class RolesPermissionsComponent extends TranslationBaseComponent implemen
}

/**
* Disabled General Group Permissions
* Checks whether the General Group Permissions should be disabled.
*
* @returns
* @returns {boolean} - Returns true if the general permissions are disabled; otherwise, false.
*/
isDisabledGeneralPermissions(): boolean {
if (!this.role) {
return true;
}
if (!this.role) return true;

/**
* Disabled all permissions for "SUPER_ADMIN"
*/
const excludes = [RolesEnum.SUPER_ADMIN, RolesEnum.ADMIN];
if (excludes.includes(this.user.role.name as RolesEnum)) {
if (this.role.name === RolesEnum.SUPER_ADMIN) {
return true;
}
}
if (this.user.role.name === RolesEnum.ADMIN) {
if (this.role.name === RolesEnum.ADMIN) {
return true;
}
}
return false;
// Disable permissions for "SUPER_ADMIN" role and when the current user's role is "ADMIN"
const userRole = this.user.role.name as RolesEnum;
const roleName = this.role.name;

return (
(userRole === RolesEnum.SUPER_ADMIN && roleName === RolesEnum.SUPER_ADMIN) ||
(userRole === RolesEnum.ADMIN && roleName === RolesEnum.ADMIN)
);
}

/**
Expand Down
6 changes: 6 additions & 0 deletions packages/contracts/src/role-permission.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ export interface IRolePermissionCreateInput extends IBasePerTenantEntityModel {
enabled: boolean;
}

export interface IRolePermissionFindInput extends IBasePerTenantEntityModel {
roleId?: ID;
permission?: string;
enabled?: boolean;
}

export interface IRolePermissionUpdateInput extends IRolePermissionCreateInput {
enabled: boolean;
}
Expand Down
Loading

0 comments on commit 1edb7ca

Please sign in to comment.