Skip to content
This repository was archived by the owner on Feb 24, 2026. It is now read-only.

Commit 792b528

Browse files
authored
GZY-437: Restrict task visibility to employees own projects in erp (#113)
* feat: service role manager in tasks view * feat: provide new permission for managers and hr roles
1 parent cdd6a9b commit 792b528

21 files changed

Lines changed: 165 additions & 39 deletions

File tree

apps/gauzy/src/app/pages/settings/roles-permissions/roles-permissions.component.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ import { TranslationBaseComponent } from '@gauzy/ui-core/i18n';
1212

1313
@UntilDestroy({ checkProperties: true })
1414
@Component({
15-
selector: 'ga-org-roles-permissions',
16-
templateUrl: './roles-permissions.component.html',
17-
styleUrls: ['./roles-permissions.component.scss'],
18-
standalone: false
15+
selector: 'ga-org-roles-permissions',
16+
templateUrl: './roles-permissions.component.html',
17+
styleUrls: ['./roles-permissions.component.scss'],
18+
standalone: false
1919
})
2020
export class RolesPermissionsComponent extends TranslationBaseComponent implements OnInit, OnDestroy {
2121
rolesEnum = RolesEnum;
2222
permissionGroups = PermissionGroups;
23-
isWantToCreate: boolean = false;
23+
isWantToCreate = false;
2424
loading: boolean;
2525
enabledPermissions: any = {};
2626
user: IUser;
@@ -354,9 +354,7 @@ export class RolesPermissionsComponent extends TranslationBaseComponent implemen
354354
* Disabled all administration permissions except "SUPER_ADMIN"
355355
*/
356356
if (this.user.role.name === RolesEnum.SUPER_ADMIN) {
357-
if (this.role.name === RolesEnum.ADMIN) {
358-
return false;
359-
}
357+
return false;
360358
}
361359
return true;
362360
}

apps/gauzy/src/app/pages/tasks/components/task/task.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ export class TaskComponent extends PaginationFilterBaseComponent implements OnIn
509509
...(this._store.hasPermission(PermissionsEnum.CHANGE_SELECTED_EMPLOYEE) && this.selectedEmployeeId
510510
? {
511511
members: {
512-
id: this.selectedEmployeeId
512+
id: this.selectedEmployeeId ?? this._store.user.employeeId
513513
}
514514
}
515515
: {}),

apps/gauzy/src/app/pages/tasks/tasks-routing.module.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ const routes: Routes = [
2424
},
2525
{
2626
path: 'me',
27-
component: TaskComponent
27+
component: TaskComponent,
28+
data: {
29+
selectors: {
30+
team: false
31+
}
32+
}
2833
},
2934
{
3035
path: 'settings/:id',

packages/contracts/src/lib/role-permission.model.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ export enum PermissionsEnum {
136136
ORG_PROJECT_VIEW = 'ORG_PROJECT_VIEW',
137137
ORG_PROJECT_EDIT = 'ORG_PROJECT_EDIT',
138138
ORG_PROJECT_DELETE = 'ORG_PROJECT_DELETE',
139+
VIEW_ASSIGNED_PROJECTS_ONLY = 'VIEW_ASSIGNED_PROJECTS_ONLY',
139140
/* Invoices */
140141
INVOICES_VIEW = 'INVOICES_VIEW',
141142
ORG_INVOICES_VIEW = 'ORG_INVOICES_VIEW',
@@ -444,6 +445,13 @@ export const PermissionGroups = {
444445
/** Tenant API Key */
445446
PermissionsEnum.TENANT_API_KEY_CREATE,
446447
PermissionsEnum.TENANT_API_KEY_VIEW,
447-
PermissionsEnum.TENANT_API_KEY_DELETE
448+
PermissionsEnum.TENANT_API_KEY_DELETE,
449+
450+
/** Used for managerial roles to restrict project visibility
451+
* so that managers and other roles can only see projects they are assigned to.
452+
*/
453+
PermissionsEnum.VIEW_ASSIGNED_PROJECTS_ONLY,
454+
455+
PermissionsEnum.PROFILE_EDIT
448456
]
449457
};

packages/core/src/lib/role-permission/default-role-permissions.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@ export const DEFAULT_ROLE_PERMISSIONS = [
242242
/** Member View Permissions Start */
243243
PermissionsEnum.ORG_MEMBERS_VIEW,
244244
/** Member View Permissions End */
245-
PermissionsEnum.ORG_EMPLOYEES_EDIT,
246245
PermissionsEnum.ORG_CANDIDATES_VIEW,
247246
PermissionsEnum.ORG_CANDIDATES_EDIT,
248247
PermissionsEnum.ORG_CANDIDATES_TASK_EDIT,
@@ -448,7 +447,7 @@ export const DEFAULT_ROLE_PERMISSIONS = [
448447
PermissionsEnum.ORG_INVENTORY_PRODUCT_EDIT,
449448
PermissionsEnum.ORG_HELP_CENTER_EDIT,
450449
PermissionsEnum.PROFILE_EDIT,
451-
PermissionsEnum.SELECT_EMPLOYEE,
450+
PermissionsEnum.SELECT_EMPLOYEE
452451
]
453452
},
454453
{
@@ -570,7 +569,7 @@ export const DEFAULT_ROLE_PERMISSIONS = [
570569
},
571570
{
572571
role: RolesEnum.MANAGER,
573-
defaultEnabledPermissions: []
572+
defaultEnabledPermissions: [PermissionsEnum.VIEW_ASSIGNED_PROJECTS_ONLY]
574573
},
575574
{
576575
role: RolesEnum.VIEWER,

packages/core/src/lib/tasks/task.service.ts

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -472,14 +472,19 @@ export class TaskService extends TenantAwareCrudService<Task> {
472472
const { where } = options;
473473
const { members } = where;
474474

475-
const hasPermission = RequestContext.hasPermission(PermissionsEnum.CHANGE_SELECTED_EMPLOYEE);
475+
const hasPermission =
476+
RequestContext.hasPermission(PermissionsEnum.ORG_EMPLOYEES_EDIT) &&
477+
!RequestContext.hasPermission(PermissionsEnum.VIEW_ASSIGNED_PROJECTS_ONLY);
478+
const isManager =
479+
RequestContext.hasPermission(PermissionsEnum.ORG_EMPLOYEES_EDIT) &&
480+
RequestContext.hasPermission(PermissionsEnum.VIEW_ASSIGNED_PROJECTS_ONLY);
476481

477482
const query = this.typeOrmRepository.createQueryBuilder(this.tableName);
478483
query.innerJoin(`${query.alias}.members`, 'members');
479484

480-
if (!hasPermission) {
485+
if (!hasPermission || isManager) {
481486
// Employee without permission: get their projects first
482-
const employeeId = RequestContext.currentEmployeeId();
487+
const employeeId = RequestContext.currentEmployeeId() ?? RequestContext.currentUser().employeeId;
483488
if (isNotEmpty(employeeId)) {
484489
const tenantId = RequestContext.currentTenantId();
485490
const organizationId = where?.organizationId as string;
@@ -512,6 +517,30 @@ export class TaskService extends TenantAwareCrudService<Task> {
512517
const employeeId = members['id'];
513518
subQuery.andWhere(p('"task_employee"."employeeId" = :employeeId'), { employeeId });
514519
}
520+
} else if (isManager) {
521+
const selectedEmployeeId = members?.['id'];
522+
const managerId = RequestContext.currentUser().employeeId;
523+
524+
if (isNotEmpty(selectedEmployeeId) && selectedEmployeeId !== managerId) {
525+
subQuery
526+
.andWhere(p('"task_employee"."employeeId" = :employeeId'), {
527+
employeeId: selectedEmployeeId
528+
})
529+
.andWhere(
530+
`EXISTS (
531+
SELECT 1 FROM "task_employee" te2
532+
WHERE te2."taskId" = "task_employee"."taskId"
533+
AND te2."employeeId" = :managerId
534+
)`
535+
)
536+
.setParameters({ managerId });
537+
} else {
538+
if (isNotEmpty(managerId)) {
539+
subQuery.andWhere(p('"task_employee"."employeeId" = :employeeId'), {
540+
employeeId: managerId
541+
});
542+
}
543+
}
515544
} else {
516545
// If employee has login and don't have permission to change employee
517546
const employeeId = RequestContext.currentEmployeeId();
@@ -623,14 +652,19 @@ export class TaskService extends TenantAwareCrudService<Task> {
623652
const { teams = [] } = where;
624653
const { members } = where;
625654

626-
const hasPermission = RequestContext.hasPermission(PermissionsEnum.CHANGE_SELECTED_EMPLOYEE);
655+
const hasPermission =
656+
RequestContext.hasPermission(PermissionsEnum.ORG_EMPLOYEES_EDIT) &&
657+
!RequestContext.hasPermission(PermissionsEnum.VIEW_ASSIGNED_PROJECTS_ONLY);
658+
const isManager =
659+
RequestContext.hasPermission(PermissionsEnum.ORG_EMPLOYEES_EDIT) &&
660+
RequestContext.hasPermission(PermissionsEnum.VIEW_ASSIGNED_PROJECTS_ONLY);
627661
const query = this.typeOrmRepository.createQueryBuilder(this.tableName);
628662
query.leftJoin(`${query.alias}.teams`, 'teams');
629663

630664
let projectIds: string[] = [];
631665

632-
if (!hasPermission) {
633-
const employeeId = RequestContext.currentEmployeeId();
666+
if (!hasPermission || isManager) {
667+
const employeeId = RequestContext.currentEmployeeId() ?? RequestContext.currentUser().employeeId;
634668
if (isNotEmpty(employeeId)) {
635669
const tenantId = RequestContext.currentTenantId();
636670
const organizationId = where?.organizationId as string;
@@ -668,6 +702,31 @@ export class TaskService extends TenantAwareCrudService<Task> {
668702
const employeeId = members['id'];
669703
subQuery.andWhere(p('"organization_team_employee"."employeeId" = :employeeId'), { employeeId });
670704
}
705+
} else if (isManager) {
706+
const selectedEmployeeId = members?.['id'];
707+
const managerId = RequestContext.currentUser().employeeId;
708+
709+
if (isNotEmpty(selectedEmployeeId) && selectedEmployeeId !== managerId) {
710+
subQuery
711+
.andWhere(p('"organization_team_employee"."employeeId" = :employeeId'), {
712+
employeeId: selectedEmployeeId
713+
})
714+
.andWhere(
715+
`EXISTS (
716+
SELECT 1
717+
FROM "organization_team_employee" te
718+
WHERE te."organizationTeamId" = "organization_team_employee"."organizationTeamId"
719+
AND te."employeeId" = :managerId
720+
)`
721+
)
722+
.setParameters({ managerId });
723+
} else {
724+
if (isNotEmpty(managerId)) {
725+
subQuery.andWhere(p('"organization_team_employee"."employeeId" = :employeeId'), {
726+
employeeId: managerId
727+
});
728+
}
729+
}
671730
} else {
672731
// If employee has login and don't have permission to change employee
673732
const employeeId = RequestContext.currentEmployeeId();
@@ -769,11 +828,17 @@ export class TaskService extends TenantAwareCrudService<Task> {
769828
const employeeId = RequestContext.currentEmployeeId();
770829
const tenantId = RequestContext.currentTenantId();
771830
const organizationId = where.organizationId as string;
772-
const hasPermission = RequestContext.hasPermission(PermissionsEnum.CHANGE_SELECTED_EMPLOYEE);
831+
const hasPermission =
832+
RequestContext.hasPermission(PermissionsEnum.ORG_EMPLOYEES_EDIT) &&
833+
!RequestContext.hasPermission(PermissionsEnum.VIEW_ASSIGNED_PROJECTS_ONLY);
834+
const isManager =
835+
RequestContext.hasPermission(PermissionsEnum.ORG_EMPLOYEES_EDIT) &&
836+
RequestContext.hasPermission(PermissionsEnum.VIEW_ASSIGNED_PROJECTS_ONLY);
773837
const userProvidedProjectId = !!options.where?.projectId;
774838

775-
if (!userProvidedProjectId && !hasPermission) {
776-
const projects = await this._organizationProjectService.findByEmployee(employeeId, {
839+
if (!userProvidedProjectId && (isManager || !hasPermission)) {
840+
const emplId = employeeId ?? RequestContext.currentUser().employeeId;
841+
const projects = await this._organizationProjectService.findByEmployee(emplId, {
777842
tenantId,
778843
organizationId,
779844
relations: ['members']

packages/ui-core/i18n/assets/i18n/ach.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,6 +1922,8 @@
19221922
}
19231923
},
19241924
"PERMISSIONS": {
1925+
"VIEW_ASSIGNED_PROJECTS_ONLY": "crwdns100002:0crwdne100002:0",
1926+
"PROFILE_EDIT": "crwdns100003:0crwdne100003:0",
19251927
"ADMIN_DASHBOARD_VIEW": "crwdns2651:0crwdne2651:0",
19261928
"ORG_PAYMENT_VIEW": "crwdns8296:0crwdne8296:0",
19271929
"ORG_PAYMENT_ADD_EDIT": "crwdns8298:0crwdne8298:0",

packages/ui-core/i18n/assets/i18n/ar.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,6 +2165,8 @@
21652165
}
21662166
},
21672167
"PERMISSIONS": {
2168+
"VIEW_ASSIGNED_PROJECTS_ONLY": "عرض المشاريع المعينة فقط (للأدوار الإدارية)",
2169+
"PROFILE_EDIT": "تعديل الملف الشخصي",
21682170
"ADMIN_DASHBOARD_VIEW": "عرض لوحة تحكم المسؤول",
21692171
"TEAM_DASHBOARD": "عرض لوحة تحكم الفريق",
21702172
"PROJECT_MANAGEMENT_DASHBOARD": "عرض لوحة تحكم إدارة المشاريع",

packages/ui-core/i18n/assets/i18n/bg.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,6 +2165,8 @@
21652165
}
21662166
},
21672167
"PERMISSIONS": {
2168+
"VIEW_ASSIGNED_PROJECTS_ONLY": "Показвай само назначените проекти (за управленски роли)",
2169+
"PROFILE_EDIT": "Редактиране на профила",
21682170
"ADMIN_DASHBOARD_VIEW": "Виж админ табло",
21692171
"TEAM_DASHBOARD": "Виж табло на екипа",
21702172
"PROJECT_MANAGEMENT_DASHBOARD": "Виж табло за управление на проекти",

packages/ui-core/i18n/assets/i18n/de.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,6 +2165,8 @@
21652165
}
21662166
},
21672167
"PERMISSIONS": {
2168+
"VIEW_ASSIGNED_PROJECTS_ONLY": "Nur zugewiesene Projekte anzeigen (für Management-Rollen)",
2169+
"PROFILE_EDIT": "Profil bearbeiten",
21682170
"ADMIN_DASHBOARD_VIEW": "Admin-Dashboard anzeigen",
21692171
"TEAM_DASHBOARD": "Team-Dashboard anzeigen",
21702172
"PROJECT_MANAGEMENT_DASHBOARD": "Projektmanagement-Dashboard anzeigen",

0 commit comments

Comments
 (0)