Skip to content

Commit

Permalink
fix: #8703 so admin can't change own role
Browse files Browse the repository at this point in the history
  • Loading branch information
rahul-rocket committed Jan 6, 2025
1 parent d159f87 commit b31d76e
Show file tree
Hide file tree
Showing 10 changed files with 455 additions and 234 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { Location } from '@angular/common';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { FormGroup } from '@angular/forms';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { IUser, ITag, RolesEnum } from '@gauzy/contracts';
import { firstValueFrom } from 'rxjs';
import { filter, tap } from 'rxjs/operators';
import { filter, firstValueFrom, tap } from 'rxjs';
import { NbRouteTab } from '@nebular/theme';
import { TranslateService } from '@ngx-translate/core';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { IUser, ITag, RolesEnum } from '@gauzy/contracts';
import { AuthService, UsersService } from '@gauzy/ui-core/core';
import { TranslationBaseComponent } from '@gauzy/ui-core/i18n';
import { UsersService } from '@gauzy/ui-core/core';
import { AuthService } from '@gauzy/ui-core/core';

@UntilDestroy({ checkProperties: true })
@Component({
Expand All @@ -18,17 +16,15 @@ import { AuthService } from '@gauzy/ui-core/core';
styleUrls: ['./edit-user-profile.component.scss']
})
export class EditUserProfileComponent extends TranslationBaseComponent implements OnInit, OnDestroy {
form: UntypedFormGroup;
form: FormGroup;
params: Params;
user: IUser;

tabs: any[];
tabs: NbRouteTab[];
tags: ITag[];

constructor(
private readonly route: ActivatedRoute,
private readonly router: Router,
private readonly location: Location,
public readonly translateService: TranslateService,
private readonly usersService: UsersService,
private readonly authService: AuthService
Expand All @@ -41,7 +37,7 @@ export class EditUserProfileComponent extends TranslationBaseComponent implement
.pipe(
filter((params) => !!params),
tap((params) => (this.params = params)),
tap(() => this.loadTabs()),
tap(() => this.registerPageTabs()),
tap(() => this.getUserProfile()),
untilDestroyed(this)
)
Expand All @@ -52,15 +48,27 @@ export class EditUserProfileComponent extends TranslationBaseComponent implement
this._applyTranslationOnTabs();
}

goBack() {
this.location.back();
}
/**
* Generates the route for a given tab based on the current user ID.
*
* @param tab - The tab name to append to the route.
* @returns The full route string.
*/
getRoute(tab: string = ''): string {
if (!this.params?.id) {
return `/pages/users`;
}

getRoute(tab: string): string {
return `/pages/users/edit/${this.params.id}/${tab}`;
return `/pages/users/edit/${this.params?.id}/${tab}`;
}

loadTabs() {
/**
* Registers page tabs for the dashboard module.
* Ensures that tabs are registered only once.
*
* @returns {void}
*/
registerPageTabs(): void {
this.tabs = [
{
title: this.getTranslation('USERS_PAGE.EDIT_USER.MAIN'),
Expand All @@ -81,26 +89,40 @@ export class EditUserProfileComponent extends TranslationBaseComponent implement
* GET user profile
*/
private async getUserProfile() {
const { id } = this.params;
const user = await this.usersService.getUserById(id, ['role', 'tags']);
if (!this.params.id) {
this.router.navigate(['/pages/users']);
return;
}

if (user.role.name === RolesEnum.SUPER_ADMIN) {
this.user = await this.usersService.getUserById(this.params.id, ['role', 'tags']);

if (this.user?.role?.name === RolesEnum.SUPER_ADMIN) {
/**
* Redirect If Edit Super Admin Without Permission
*/
const hasSuperAdminRole = await firstValueFrom(this.authService.hasRole([RolesEnum.SUPER_ADMIN]));
const hasSuperAdminRole = await firstValueFrom(
this.authService.hasRole([RolesEnum.SUPER_ADMIN])
);

if (!hasSuperAdminRole) {
this.router.navigate(['/pages/users']);
return;
}
}
this.user = user;
}

private _applyTranslationOnTabs() {
/**
* Subscribes to language change events and applies translations to page tabs.
* Ensures the tabs are updated dynamically when the language changes.
* Uses `untilDestroyed` to clean up subscriptions when the component is destroyed.
*/
private _applyTranslationOnTabs(): void {
this.translateService.onLangChange
.pipe(
tap(() => this.loadTabs()),
// Re-register page tabs on language change
tap(() => this.registerPageTabs()),

// Automatically unsubscribe when the component is destroyed
untilDestroyed(this)
)
.subscribe();
Expand Down
131 changes: 84 additions & 47 deletions apps/gauzy/src/app/pages/users/users.component.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
<nb-card [nbSpinner]="loading" nbSpinnerStatus="primary" nbSpinnerSize="large">
<nb-card
[nbSpinner]="loading"
nbSpinnerStatus="primary"
nbSpinnerSize="large"
>
<nb-card-header class="d-flex flex-column pb-0">
<div class="card-header-title">
<h4>
Expand All @@ -9,10 +13,10 @@ <h4>
<ng-template ngxPermissionsOnly="ORG_USERS_EDIT">
<ng-template [ngxPermissionsOnly]="['ORG_INVITE_VIEW', 'ORG_INVITE_EDIT']">
<button
*ngIf="organizationInvitesAllowed"
nbButton
class="action"
size="small"
*ngIf="organizationInvitesAllowed"
status="primary"
(click)="manageInvites()"
>
Expand All @@ -34,81 +38,99 @@ <h4>
</nb-card-header>
<nb-card-body>
<ng-template ngxPermissionsOnly="ORG_USERS_EDIT">
<div class="edit-user-mutation" *ngIf="showAddCard">
<ng-template ngxPermissionsOnly="TENANT_ADD_EXISTING_USER">
<ga-edit-user-mutation
[organization]="organization"
(addOrEditUser)="addOrEditUser($event)"
(canceled)="cancel()"
></ga-edit-user-mutation>
</ng-template>
</div>
</ng-template>
<ng-template [ngIf]="dataLayoutStyle === componentLayoutStyleEnum.TABLE" [ngIfElse]="gridLayout">
<div class="table-scroll-container">
<angular2-smart-table
style="cursor: pointer"
[settings]="settingsSmartTable"
[source]="sourceSmartTable"
(userRowSelect)="selectUser($event)"
></angular2-smart-table>
</div>
<div class="pagination-container align-self-end">
<ng-container *ngIf="sourceSmartTable">
<ngx-pagination [source]="sourceSmartTable"></ngx-pagination>
</ng-container>
</div>
<ng-template [ngIf]="showAddCard">
<div class="edit-user-mutation">
<ng-template ngxPermissionsOnly="TENANT_ADD_EXISTING_USER">
<ga-edit-user-mutation
[organization]="organization"
(addOrEditUser)="addOrEditUser($event)"
(canceled)="cancel()"
></ga-edit-user-mutation>
</ng-template>
</div>
</ng-template>
</ng-template>
<ng-template #gridLayout>
<div class="grid">
<ga-card-grid
[totalItems]="pagination?.totalItems"
[settings]="settingsSmartTable"
[source]="users"
(scroll)="onScroll()"
(onSelectedItem)="selectUser($event)"
></ga-card-grid>
</div>

<!-- Check if the user has the 'ORG_INVITE_VIEW' permission -->
<ng-template [ngxPermissionsOnly]="[PermissionsEnum.ORG_USERS_VIEW]">
<ng-container [ngSwitch]="dataLayoutStyle">
<!-- Table View -->
<ng-template [ngSwitchCase]="componentLayoutStyleEnum.TABLE">
<div class="table-scroll-container">
<angular2-smart-table
style="cursor: pointer"
[settings]="settingsSmartTable"
[source]="sourceSmartTable"
(userRowSelect)="selectUser($event)"
></angular2-smart-table>
</div>
<div class="pagination-container">
<ng-container *ngIf="smartTableSource">
<ngx-pagination [source]="smartTableSource"></ngx-pagination>
</ng-container>
</div>
</ng-template>

<!-- Card Grid View -->
<ng-template [ngSwitchCase]="componentLayoutStyleEnum.CARDS_GRID">
<ga-card-grid
[totalItems]="pagination?.totalItems"
[settings]="settingsSmartTable"
[source]="users"
(scroll)="onScroll()"
(onSelectedItem)="selectUser($event)"
></ga-card-grid>
</ng-template>

<!-- Optional: Default case if no specific layout matches -->
<ng-template *ngSwitchDefault>
<p>{{ 'SETTINGS_MENU.NO_LAYOUT' | translate }}</p>
</ng-template>
</ng-container>
</ng-template>
</nb-card-body>
</nb-card>

<ng-template #actionButtons let-selectedItem="selectedItem">
<!-- Actions -->
<ng-template #actionButtons>
<ng-template ngxPermissionsOnly="ORG_USERS_EDIT">
<div class="actions">
<button
nbButton
[disabled]="!selectedItem && disableButton"
[disabled]="disableButton"
status="basic"
class="action secondary"
size="small"
underConstruction
>
<nb-icon class="mr-1" icon="eye-outline"></nb-icon>{{ 'BUTTONS.VIEW' | translate }}
<nb-icon class="mr-1" icon="eye-outline"></nb-icon>
{{ 'BUTTONS.VIEW' | translate }}
</button>
<button
nbButton
[disabled]="!selectedItem && disableButton"
[disabled]="disableButton"
(click)="edit(selectedItem)"
status="basic"
class="action primary"
size="small"
>
<nb-icon class="mr-1" icon="edit-outline"></nb-icon>{{ 'BUTTONS.EDIT' | translate }}
<nb-icon class="mr-1" icon="edit-outline"></nb-icon>
{{ 'BUTTONS.EDIT' | translate }}
</button>
<button
nbButton
[disabled]="(!selectedItem && disableButton) || isEmployee()"
[disabled]="disableButton || isEmployee()"
(click)="convertUserToEmployee()"
status="basic"
class="action primary"
size="small"
>
<nb-icon class="mr-1" icon="person"></nb-icon> {{ 'BUTTONS.CONVERT_TO_EMPLOYEE' | translate }}
<nb-icon class="mr-1" icon="person"></nb-icon>
{{ 'BUTTONS.CONVERT_TO_EMPLOYEE' | translate }}
</button>
<button
nbButton
[disabled]="!selectedItem && disableButton"
[disabled]="disableButton"
(click)="removeUserFromOrganization(selectedUser, selectedItem)"
status="basic"
class="action"
Expand All @@ -120,6 +142,8 @@ <h4>
</div>
</ng-template>
</ng-template>

<!-- Invite -->
<ng-template #visible>
<ng-template ngxPermissionsOnly="ORG_INVITE_EDIT">
<button
Expand All @@ -130,15 +154,28 @@ <h4>
class="action info"
size="small"
>
<nb-icon icon="email-outline"></nb-icon>{{ 'BUTTONS.INVITE' | translate }}
<nb-icon icon="email-outline"></nb-icon>
{{ 'BUTTONS.INVITE' | translate }}
</button>
</ng-template>
<button nbButton status="success" size="small" (click)="add()" class="action">
<button
nbButton
status="success"
size="small"
class="action"
(click)="add()"
>
<nb-icon icon="plus-outline"></nb-icon>
{{ 'BUTTONS.ADD_NEW' | translate }}
</button>
<ng-template ngxPermissionsOnly="TENANT_ADD_EXISTING_USER">
<button (click)="showAddCard = !showAddCard" nbButton status="warning" class="action" size="small">
<button
(click)="toggleAddCard()"
nbButton
status="warning"
class="action"
size="small"
>
<nb-icon icon="plus-outline"></nb-icon>
{{ 'BUTTONS.ADD_EXISTING' | translate }}
</button>
Expand Down
Loading

0 comments on commit b31d76e

Please sign in to comment.