diff --git a/frontend/assets/csv/sample_upload.csv b/frontend/assets/csv/sample_upload.csv index b92715cca1..cd152f5452 100644 --- a/frontend/assets/csv/sample_upload.csv +++ b/frontend/assets/csv/sample_upload.csv @@ -1,2 +1,2 @@ -First Name,Last Name,Email,Group -test,user,test@gmail.com,For multiple groups separate using pipe (|) operator e.g. All Users|Admin \ No newline at end of file +First Name,Last Name,Email,Group,User Role +test,user,test@gmail.com,"For multiple groups separate using pipe (|) operator e.g. Groups1|Group2 or leave blank if no group assign","Assign each user a role: Admin, Builder or End User. User role value should be exact same" \ No newline at end of file diff --git a/frontend/src/ManageGranularAccess/AddEditResourceModal/AddEditResourcePermissionsModal.jsx b/frontend/src/ManageGranularAccess/AddEditResourceModal/AddEditResourcePermissionsModal.jsx index 3424779e03..3b7479032c 100644 --- a/frontend/src/ManageGranularAccess/AddEditResourceModal/AddEditResourcePermissionsModal.jsx +++ b/frontend/src/ManageGranularAccess/AddEditResourceModal/AddEditResourcePermissionsModal.jsx @@ -104,7 +104,7 @@ function AddEditResourcePermissionsModal({ type="radio" checked={isAll} onClick={() => { - updateParentState((prevState) => ({ isAll: !prevState.isAll, isCustom: !!prevState.isAll })); + !isAll && updateParentState((prevState) => ({ isAll: !prevState.isAll, isCustom: !!prevState.isAll })); }} />
@@ -121,7 +121,8 @@ function AddEditResourcePermissionsModal({ disabled={addableApps.length === 0 || disableBuilderLevelUpdate} checked={isCustom} onClick={() => { - updateParentState((prevState) => ({ isCustom: !prevState.isCustom, isAll: prevState.isCustom })); + !isCustom && + updateParentState((prevState) => ({ isCustom: !prevState.isCustom, isAll: prevState.isCustom })); }} />
diff --git a/frontend/src/ManageGranularAccess/AppResourcePermission.jsx b/frontend/src/ManageGranularAccess/AppResourcePermission.jsx index 0c93d0b70c..0b311e64a8 100644 --- a/frontend/src/ManageGranularAccess/AppResourcePermission.jsx +++ b/frontend/src/ManageGranularAccess/AppResourcePermission.jsx @@ -35,7 +35,7 @@ function AppResourcePermissions({ >
-
{permissions.name}
+
{` ${permissions.name}`}
diff --git a/frontend/src/ManageGroupPermissionResourcesV2/index.jsx b/frontend/src/ManageGroupPermissionResourcesV2/index.jsx index f996216af8..3305097887 100644 --- a/frontend/src/ManageGroupPermissionResourcesV2/index.jsx +++ b/frontend/src/ManageGroupPermissionResourcesV2/index.jsx @@ -555,7 +555,10 @@ class ManageGroupPermissionResourcesComponent extends React.Component {
- @@ -589,16 +588,90 @@ class ManageGroupPermissionsComponent extends React.Component {
- - {!showNewGroupForm && !showGroupNameUpdateForm && ( -
-
-
+
+
+
+
+ + USER ROLE +
+ {defaultGroups.map((permissionGroup) => { + return ( + { + this.setState({ + selectedGroupPermissionId: permissionGroup.id, + selectedGroup: this.humanizeifDefaultGroupName(permissionGroup.name), + selectedGroupObject: permissionGroup, + }); + }} + toolTipText={this.humanizeifDefaultGroupName(permissionGroup.name)} + overLayComponent={this.renderPopoverContent} + className="groups-folder-list" + dataCy={this.humanizeifDefaultGroupName(permissionGroup.name) + .toLowerCase() + .replace(/\s+/g, '-')} + > + + {this.humanizeifDefaultGroupName(permissionGroup.name)} + + + ); + })} +
+
+ {!showGroupSearchBar ? (
- - USER ROLE + + CUSTOM GROUPS +
+ { + e.preventDefault(); + this.setState({ showGroupSearchBar: true }); + }} + size="xsm" + rightIcon="search" + iconWidth="15" + fill="#889096" + className="create-group-custom" + /> + { + e.preventDefault(); + this.setState({ newGroupName: null, showNewGroupForm: true, isSaveBtnDisabled: true }); + }} + size="sm" + fill="#889096" + rightIcon="plus" + iconWidth="20" + className="create-group-custom" + /> +
- {defaultGroups.map((permissionGroup) => { + ) : ( +
+ +
+ )} + + {groups.length ? ( + filteredGroup.map((permissionGroup) => { return ( ); - })} -
-
- {!showGroupSearchBar ? ( -
- - CUSTOM GROUPS -
- { - e.preventDefault(); - this.setState({ showGroupSearchBar: true }); - }} - size="xsm" - rightIcon="search" - iconWidth="15" - fill="#889096" - className="create-group-custom" - /> - { - e.preventDefault(); - this.setState({ newGroupName: null, showNewGroupForm: true, isSaveBtnDisabled: true }); - }} - size="sm" - fill="#889096" - rightIcon="plus" - iconWidth="20" - className="create-group-custom" - /> -
-
- ) : ( -
- -
- )} - - {groups.length ? ( - filteredGroup.map((permissionGroup) => { - return ( - { - this.setState({ - selectedGroupPermissionId: permissionGroup.id, - selectedGroup: this.humanizeifDefaultGroupName(permissionGroup.name), - selectedGroupObject: permissionGroup, - }); - }} - toolTipText={this.humanizeifDefaultGroupName(permissionGroup.name)} - overLayComponent={this.renderPopoverContent} - className="groups-folder-list" - dataCy={this.humanizeifDefaultGroupName(permissionGroup.name) - .toLowerCase() - .replace(/\s+/g, '-')} - > - - {this.humanizeifDefaultGroupName(permissionGroup.name)} - - - ); - }) - ) : ( -
- - No custom groups added -
- )} -
-
- -
- {isLoading ? ( - + }) ) : ( - { - return { - name: this.humanizeifDefaultGroupName(group.name), - value: group.name, - }; - })} - /> +
+ + No custom groups added +
)}
- )} + +
+ {isLoading ? ( + + ) : ( + { + return { + name: this.humanizeifDefaultGroupName(group.name), + value: group.name, + }; + })} + /> + )} +
+
diff --git a/frontend/src/ManageGroupPermissionsV2/groupPermissions.theme.scss b/frontend/src/ManageGroupPermissionsV2/groupPermissions.theme.scss index 0ad36a1d01..1a6a4fd1cb 100644 --- a/frontend/src/ManageGroupPermissionsV2/groupPermissions.theme.scss +++ b/frontend/src/ManageGroupPermissionsV2/groupPermissions.theme.scss @@ -430,6 +430,7 @@ } .resource-text { margin-left: 10px; + padding-left: 20px; } } } diff --git a/server/data-migrations/1720352990850-CreateDefaultGroupInExistingWorkspace.ts b/server/data-migrations/1720352990850-CreateDefaultGroupInExistingWorkspace.ts new file mode 100644 index 0000000000..01624e6946 --- /dev/null +++ b/server/data-migrations/1720352990850-CreateDefaultGroupInExistingWorkspace.ts @@ -0,0 +1,149 @@ +import { CreateGranularPermissionDto } from '@dto/granular-permissions.dto'; +import { + DEFAULT_GRANULAR_PERMISSIONS_NAME, + DEFAULT_RESOURCE_PERMISSIONS, + ResourceType, +} from '@module/user_resource_permissions/constants/granular-permissions.constant'; +import { + USER_ROLE, + DEFAULT_GROUP_PERMISSIONS_MIGRATIONS, +} from '@module/user_resource_permissions/constants/group-permissions.constant'; +import { + CreateResourcePermissionObject, + ResourcePermissionMetaData, +} from '@module/user_resource_permissions/interface/granular-permissions.interface'; +import { AppsGroupPermissions } from 'src/entities/apps_group_permissions.entity'; +import { GranularPermissions } from 'src/entities/granular_permissions.entity'; +import { GroupPermissions } from 'src/entities/group_permissions.entity'; +import { Organization } from 'src/entities/organization.entity'; +import { UserGroupPermission } from 'src/entities/user_group_permission.entity'; +import { EntityManager, MigrationInterface, QueryRunner } from 'typeorm'; + +export class CreateDefaultGroupInExistingWorkspace1720352990850 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const manager = queryRunner.manager; + const organizationIds = ( + await manager.find(Organization, { + select: ['id'], + }) + ).map((organization) => organization.id); + + for (const organizationId of organizationIds) { + for (const defaultGroup of Object.keys(USER_ROLE)) { + const groupPermissions = DEFAULT_GROUP_PERMISSIONS_MIGRATIONS[defaultGroup]; + const query = ` + INSERT INTO permission_groups ( + organization_id, + name, + type, + app_create, + app_delete, + folder_crud, + org_constant_crud, + data_source_create, + data_source_delete + ) VALUES ( + '${organizationId}', + '${groupPermissions.name}', + '${groupPermissions.type}', + ${groupPermissions.appCreate}, + ${groupPermissions.appDelete}, + ${groupPermissions.folderCRUD}, + ${groupPermissions.orgConstantCRUD}, + ${groupPermissions.dataSourceCreate}, + ${groupPermissions.dataSourceDelete} + ) RETURNING *; + `; + const group: GroupPermissions = (await manager.query(query))[0]; + const groupGranularPermissions: Record = + DEFAULT_RESOURCE_PERMISSIONS[group.name]; + + for (const resource of Object.keys(groupGranularPermissions)) { + const createResourcePermissionObj: CreateResourcePermissionObject = groupGranularPermissions[resource]; + const dtoObject = { + name: DEFAULT_GRANULAR_PERMISSIONS_NAME[resource], + groupId: group.id, + type: resource as ResourceType, + isAll: true, + createAppsPermissionsObject: {}, + }; + if (group.name === USER_ROLE.ADMIN) { + const granularPermissions = await this.createGranularPermission(manager, dtoObject); + await this.createAppsResourcePermission( + manager, + { granularPermissions, organizationId }, + createResourcePermissionObj + ); + } + } + //Migrating Admins to new Admins + if (group.name === USER_ROLE.ADMIN) { + const adminsUsers = await manager + .createQueryBuilder(UserGroupPermission, 'usersGroup') + .innerJoin( + 'usersGroup.groupPermission', + 'groupPermission', + 'groupPermission.organizationId = :organizationId', + { + organizationId, + } + ) + .where('groupPermission.group = :admin', { + admin: 'admin', + }) + .getMany(); + const userIds = adminsUsers.map((userGroup) => userGroup.userId); + await this.migrateUserGroup(manager, userIds, group.id); + } + } + } + } + + async createGranularPermission( + manager: EntityManager, + createObject: CreateGranularPermissionDto + ): Promise { + const query = ` + INSERT INTO granular_permissions ( + group_id, + name, + type, + is_all + ) VALUES ( + '${createObject.groupId}', '${createObject.name}', '${createObject.type}', ${createObject.isAll} + ) RETURNING *; + `; + return (await manager.query(query))[0]; + } + + async createAppsResourcePermission( + manager: EntityManager, + createMeta: ResourcePermissionMetaData, + createObject: CreateResourcePermissionObject + ): Promise { + const { granularPermissions } = createMeta; + const query = ` + INSERT INTO apps_group_permissions ( + granular_permission_id, + can_edit, + can_view, + hide_from_dashboard + ) VALUES ( + '${granularPermissions.id}', ${createObject.canEdit}, ${createObject.canView}, ${createObject.hideFromDashboard} + ) RETURNING *; + `; + return (await manager.query(query))[0]; + } + + async migrateUserGroup(manager: EntityManager, userIds: string[], groupId: string) { + if (userIds.length == 0) return; + const valuesString = userIds.map((id) => `('${id}', '${groupId}')`).join(','); + const query = ` + INSERT INTO group_users (user_id, group_id) + VALUES ${valuesString}; + `; + return await manager.query(query); + } + + public async down(queryRunner: QueryRunner): Promise {} +} diff --git a/server/data-migrations/1720365772516-AddingUsersToRespectiveRolesBuilderAndEndUsers.ts b/server/data-migrations/1720365772516-AddingUsersToRespectiveRolesBuilderAndEndUsers.ts new file mode 100644 index 0000000000..25463d3ca7 --- /dev/null +++ b/server/data-migrations/1720365772516-AddingUsersToRespectiveRolesBuilderAndEndUsers.ts @@ -0,0 +1,124 @@ +import { + GROUP_PERMISSIONS_TYPE, + USER_ROLE, +} from '@module/user_resource_permissions/constants/group-permissions.constant'; +import { GroupPermissions } from 'src/entities/group_permissions.entity'; +import { Organization } from 'src/entities/organization.entity'; +import { OrganizationUser } from 'src/entities/organization_user.entity'; +import { User } from 'src/entities/user.entity'; +import { UserGroupPermission } from 'src/entities/user_group_permission.entity'; +import { Brackets, EntityManager, MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddingUsersToRespectiveRolesBuilderAndEndUsers1720365772516 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const manager = queryRunner.manager; + const organizationIds = ( + await manager.find(Organization, { + select: ['id'], + }) + ).map((organization) => organization.id); + await this.getAndConvertEditorBuilderUsers(manager, organizationIds); + } + + async getAndConvertEditorBuilderUsers(manager: EntityManager, organizationIds: string[]) { + for (const organizationId of organizationIds) { + const userIdsWithEditPermissions = ( + await manager + .createQueryBuilder(User, 'users') + .innerJoin( + 'users.organizationUsers', + 'organization_users', + 'organization_users.organizationId = :organizationId ', + { + organizationId, + } + ) + .innerJoin( + 'users.groupPermissions', + 'group_permissions', + 'organization_users.organizationId = group_permissions.organizationId' + ) + .leftJoin('group_permissions.appGroupPermission', 'app_group_permissions') + .andWhere( + new Brackets((qb) => { + qb.where('app_group_permissions.read = true AND app_group_permissions.update = true').orWhere( + 'group_permissions.appCreate = true' + ); + }) + ) + .select('users.id') + .distinct() + .getMany() + ).map((record) => record.id); + + const userIdsOfAppOwners = ( + await manager + .createQueryBuilder(User, 'users') + .innerJoin( + 'users.organizationUsers', + 'organization_users', + 'organization_users.organizationId = :organizationId', + { + organizationId, + } + ) + .innerJoin('users.apps', 'apps') + .select('users.id') + .distinct() + .getMany() + ).map((record) => record.id); + + const adminsUsers = ( + await manager + .createQueryBuilder(UserGroupPermission, 'usersGroup') + .innerJoin( + 'usersGroup.groupPermission', + 'groupPermission', + 'groupPermission.organizationId = :organizationId', + { + organizationId, + } + ) + .where('groupPermission.group = :admin', { + admin: 'admin', + }) + .getMany() + ).map((record) => record.userId); + const builderUsersWithAdmin = [...new Set([...userIdsWithEditPermissions, ...userIdsOfAppOwners])]; + const builderUsersWoAdmin = builderUsersWithAdmin.filter((id) => !adminsUsers.includes(id)); + const builderGroup = await manager.findOne(GroupPermissions, { + where: { name: USER_ROLE.BUILDER, type: GROUP_PERMISSIONS_TYPE.DEFAULT, organizationId: organizationId }, + }); + const endUserGroup = await manager.findOne(GroupPermissions, { + where: { name: USER_ROLE.END_USER, type: GROUP_PERMISSIONS_TYPE.DEFAULT, organizationId: organizationId }, + }); + + console.log('Builders users'); + console.log(builderUsersWoAdmin); + + await this.migrateUserGroup(manager, builderUsersWoAdmin, builderGroup.id); + const organizationUser = ( + await manager.find(OrganizationUser, { + where: { + organizationId, + }, + }) + ).map((record) => record.userId); + const builderAdminUsers = [...new Set([...builderUsersWoAdmin, ...adminsUsers])]; + const endUsers = organizationUser.filter((userId) => !builderAdminUsers.includes(userId)); + await this.migrateUserGroup(manager, endUsers, endUserGroup.id); + } + } + + async migrateUserGroup(manager: EntityManager, userIds: string[], groupId: string) { + if (userIds.length === 0) return; + const valuesString = userIds.map((id) => `('${id}', '${groupId}')`).join(','); + const query = ` + INSERT INTO group_users (user_id, group_id) + VALUES ${valuesString}; + `; + return await manager.query(query); + } + + public async down(queryRunner: QueryRunner): Promise {} +} diff --git a/server/data-migrations/1720434737529-MigrateCustomGroupToNewUserGroup.ts b/server/data-migrations/1720434737529-MigrateCustomGroupToNewUserGroup.ts new file mode 100644 index 0000000000..8cc12e70d9 --- /dev/null +++ b/server/data-migrations/1720434737529-MigrateCustomGroupToNewUserGroup.ts @@ -0,0 +1,213 @@ +import { CreateGranularPermissionDto } from '@dto/granular-permissions.dto'; +import { + DEFAULT_GRANULAR_PERMISSIONS_NAME, + ResourceType, +} from '@module/user_resource_permissions/constants/granular-permissions.constant'; +import { + GROUP_PERMISSIONS_TYPE, + USER_ROLE, +} from '@module/user_resource_permissions/constants/group-permissions.constant'; +import { + CreateResourcePermissionObject, + ResourcePermissionMetaData, +} from '@module/user_resource_permissions/interface/granular-permissions.interface'; +import { AppGroupPermission } from 'src/entities/app_group_permission.entity'; +import { AppsGroupPermissions } from 'src/entities/apps_group_permissions.entity'; +import { GranularPermissions } from 'src/entities/granular_permissions.entity'; +import { GroupPermission } from 'src/entities/group_permission.entity'; +import { GroupPermissions } from 'src/entities/group_permissions.entity'; +import { Organization } from 'src/entities/organization.entity'; +import { EntityManager, MigrationInterface, QueryRunner } from 'typeorm'; + +export class MigrateCustomGroupToNewUserGroup1720434737529 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const manager = queryRunner.manager; + const organizationIds = ( + await manager.find(Organization, { + select: ['id'], + }) + ).map((organization) => organization.id); + for (const organizationId of organizationIds) { + const groups = await manager + .createQueryBuilder(GroupPermission, 'groupPermission') + .where('groupPermission.organizationId = :organizationId', { + organizationId, + }) + .leftJoinAndSelect('groupPermission.appGroupPermission', 'appGroupPermission') + .leftJoinAndSelect('groupPermission.userGroupPermission', 'userGroupPermission') + .andWhere('groupPermission.group != :admin', { + admin: 'admin', + }) + .getMany(); + + for (const groupPermissions of groups) { + const query = ` + INSERT INTO permission_groups ( + organization_id, + name, + type, + app_create, + app_delete, + folder_crud, + org_constant_crud, + data_source_create, + data_source_delete + ) VALUES ( + '${organizationId}', + '${this.getGroupName(groupPermissions.group)}', + '${GROUP_PERMISSIONS_TYPE.CUSTOM_GROUP}', + ${groupPermissions.appCreate}, + ${groupPermissions.appDelete}, + ${groupPermissions.folderCreate}, + ${groupPermissions.orgEnvironmentConstantCreate}, + false, + false + ) RETURNING *; + `; + const group: GroupPermissions = (await manager.query(query))[0]; + const existingGroupUsers = groupPermissions.userGroupPermission; + await this.migrateUserGroup(manager, [...new Set(existingGroupUsers.map((record) => record.userId))], group.id); + const resources = [ResourceType.APP]; + for (const resource of resources) { + if (resource === ResourceType.APP) { + const viewLevelAppsPermissions = groupPermissions.appGroupPermission.filter( + (appPermissions) => appPermissions.read + ); + const updateLevelAppsPermissions = groupPermissions.appGroupPermission.filter( + (appPermissions) => appPermissions.update + ); + const createResourcePermissionObjView: CreateResourcePermissionObject = { + canView: true, + canEdit: false, + hideFromDashboard: false, + }; + await this.createAppLevelPermissions( + manager, + viewLevelAppsPermissions, + organizationId, + resource, + group, + createResourcePermissionObjView + ); + const createResourcePermissionObjEdit: CreateResourcePermissionObject = { + canView: false, + canEdit: true, + hideFromDashboard: false, + }; + await this.createAppLevelPermissions( + manager, + updateLevelAppsPermissions, + organizationId, + resource, + group, + createResourcePermissionObjEdit + ); + } + } + } + } + } + + getGroupName(name: string) { + switch (name) { + case USER_ROLE.BUILDER: + return `custom-${USER_ROLE.BUILDER}`; + case USER_ROLE.END_USER: + return `custom-${USER_ROLE.END_USER}`; + case 'all_users': + return `Custom All users`; + default: + return name; + } + } + + async createGranularPermission( + manager: EntityManager, + createObject: CreateGranularPermissionDto + ): Promise { + const query = ` + INSERT INTO granular_permissions ( + group_id, + name, + type, + is_all, + + ) VALUES ( + ${createObject.groupId} , ${createObject.name} , ${createObject.type},${createObject.isAll} + ) RETURNING *;`; + return (await manager.query(query))[0]; + } + + async createAppsResourcePermission( + manager: EntityManager, + createMeta: ResourcePermissionMetaData, + createObject: CreateResourcePermissionObject + ): Promise { + const { granularPermissions } = createMeta; + const query = ` + INSERT INTO apps_group_permissions ( + granular_permission_id, + can_edit, + can_view, + hide_from_dashboard + ) VALUES ( + ${granularPermissions.id}, + ${createObject.canEdit}, + ${createObject.canView}, + ${createObject.hideFromDashboard} + ) RETURNING *; + `; + return (await manager.query(query))[0]; + } + + async migrateUserGroup(manager: EntityManager, userIds: string[], groupId: string) { + if (userIds.length == 0) return; + const valuesString = userIds.map((id) => `('${id}', '${groupId}')`).join(','); + const query = ` + INSERT INTO group_users (user_id, group_id) + VALUES ${valuesString}; + `; + return await manager.query(query); + } + + async addAppsGroupToPermissions(manager: EntityManager, appIds: string[], appPermissionsId: string) { + const valuesString = appIds.map((id) => `('${id}', '${appPermissionsId}')`).join(','); + const query = ` + INSERT INTO group_apps (app_id, apps_group_permissions_id) + VALUES ${valuesString}; + `; + return await manager.query(query); + } + + async createAppLevelPermissions( + manager: EntityManager, + appsPermissions: AppGroupPermission[], + organizationId: string, + resource: ResourceType, + group: GroupPermissions, + createResourcePermissionObj: CreateResourcePermissionObject + ) { + const nameInit = createResourcePermissionObj.canView ? 'Viewable' : 'Updatable'; + if (appsPermissions.length === 0) return; + const dtoObject = { + name: `${nameInit} ${DEFAULT_GRANULAR_PERMISSIONS_NAME[resource]}`, + groupId: group.id, + type: resource as ResourceType, + isAll: false, + createAppsPermissionsObject: {}, + }; + const granularPermissions = await this.createGranularPermission(manager, dtoObject); + const appsGroupPermissions = await this.createAppsResourcePermission( + manager, + { granularPermissions, organizationId }, + createResourcePermissionObj + ); + await this.addAppsGroupToPermissions( + manager, + appsPermissions.map((record) => record.appId), + appsGroupPermissions.id + ); + } + + public async down(queryRunner: QueryRunner): Promise {} +} diff --git a/server/data-migrations/1720513124281-DropGroupPermissionsOlderRelatedTables.ts b/server/data-migrations/1720513124281-DropGroupPermissionsOlderRelatedTables.ts new file mode 100644 index 0000000000..8a47a54d64 --- /dev/null +++ b/server/data-migrations/1720513124281-DropGroupPermissionsOlderRelatedTables.ts @@ -0,0 +1,9 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class DropGroupPermissionsOlderRelatedTables1720513124281 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + queryRunner.query('DROP TABLE group_permissions, user_group_permissions, app_group_permissions CASCADE;'); + } + + public async down(queryRunner: QueryRunner): Promise {} +} diff --git a/server/src/helpers/queries.ts b/server/src/helpers/queries.ts index fd971c5fa1..359cdd2a84 100644 --- a/server/src/helpers/queries.ts +++ b/server/src/helpers/queries.ts @@ -53,10 +53,17 @@ export function viewableAppsQueryUsingPermissions( if (select) { viewableAppsQb.select(select.map((col) => `viewable_apps.${col}`)); } - if (userAppPermissions.hideAll || !(userAppPermissions.isAllEditable || userAppPermissions.isAllViewable)) { + const viewAll = userAppPermissions.isAllEditable || userAppPermissions.isAllViewable; + if (!viewAll || userAppPermissions.hideAll) { viewableAppsQb.where('viewable_apps.id IN (:...viewableApps)', { viewableApps, }); } + const hiddenApps = userAppPermissions.hiddenAppsId; + if (!userAppPermissions.hideAll && viewAll && hiddenApps.length > 0) { + viewableAppsQb.where('viewable_apps.id NOT IN (:...hiddenApps)', { + hiddenApps, + }); + } return viewableAppsQb; } diff --git a/server/src/services/granular_permissions.service.ts b/server/src/services/granular_permissions.service.ts index 386033fbb1..83e39ea582 100644 --- a/server/src/services/granular_permissions.service.ts +++ b/server/src/services/granular_permissions.service.ts @@ -40,7 +40,8 @@ export class GranularPermissionsService { ) { return await dbTransactionWrap(async (manager: EntityManager) => { const { createGranularPermissionDto, organizationId } = createGranularPermissionObject; - const { name, type, groupId, isAll } = createGranularPermissionDto; + const { name, type, groupId, isAll: isAllDto } = createGranularPermissionDto; + const isAll = isAllDto ? true : false; const granularPermissions: GranularPermissions = await catchDbException(async () => { const granularPermissions = manager.create(GranularPermissions, { name, type, groupId, isAll }); return await manager.save(granularPermissions); @@ -77,7 +78,7 @@ export class GranularPermissionsService { const { organizationId, updateGranularPermissionDto, group } = updateGranularPermissionsObj; const { isAll, name, resourcesToAdd, resourcesToDelete, actions, allowRoleChange } = updateGranularPermissionDto; const updateGranularPermission = { - isAll: isAll !== null || isAll !== undefined ? isAll : granularPermissions.isAll, + isAll: isAll ?? granularPermissions.isAll, ...(name && { name }), }; const updateResource: UpdateResourceGroupPermissionsObject = { diff --git a/server/src/services/organizations.service.ts b/server/src/services/organizations.service.ts index 5892bf3131..4b94f7e9c9 100644 --- a/server/src/services/organizations.service.ts +++ b/server/src/services/organizations.service.ts @@ -63,7 +63,7 @@ interface UserCsvRow { first_name: string; last_name: string; email: string; - role: string; + user_role: string; groups?: any; } @@ -711,7 +711,7 @@ export class OrganizationsService { const existingGroups = groupPermissions.map((groupPermission) => groupPermission.name); csv .parseString(fileStream.toString(), { - headers: ['first_name', 'last_name', 'email', 'groups', 'role'], + headers: ['first_name', 'last_name', 'email', 'groups', 'user_role'], renameHeaders: true, ignoreEmpty: true, }) @@ -719,13 +719,12 @@ export class OrganizationsService { return next(null, { ...row, groups: this.createGroupsList(row?.groups), - role: this.convertUserRolesCasing(row?.role), + user_role: this.convertUserRolesCasing(row?.user_role), }); }) .validate(async (data: UserCsvRow, next) => { await dbTransactionWrap(async (manager: EntityManager) => { //Check for existing users - let isInvalidRole = false; const user = await this.usersService.findByEmail(data?.email, undefined, undefined, manager); @@ -734,7 +733,14 @@ export class OrganizationsService { } else if (user?.organizationUsers?.some((ou) => ou.organizationId === currentUser.organizationId)) { existingUsers.push(data?.email); } else { - users.push(data); + const user = { + first_name: data.first_name, + last_name: data.last_name, + email: data.email, + role: data.user_role, + groups: data?.groups, + }; + users.push(user); } //Check for invalid groups @@ -748,8 +754,8 @@ export class OrganizationsService { } } - if (!Object.values(USER_ROLE).includes(data?.role as USER_ROLE)) { - invalidRoles.push(data?.role); + if (!Object.values(USER_ROLE).includes(data?.user_role as USER_ROLE)) { + invalidRoles.push(data?.user_role); isInvalidRole = true; }