Merged woht merge branch

This commit is contained in:
kriks7iitk 2024-07-11 11:23:30 +05:30
commit 4b39935233
13 changed files with 647 additions and 133 deletions

View file

@ -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
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"
1 First Name Last Name Email Group User Role
2 test user test@gmail.com For multiple groups separate using pipe (|) operator e.g. All Users|Admin 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

View file

@ -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 }));
}}
/>
<div>
@ -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 }));
}}
/>
<div>

View file

@ -35,7 +35,7 @@ function AppResourcePermissions({
>
<div className="resource-name d-flex">
<SolidIcon name="app" width="20px" className="resource-icon" />
<div className="resource-text">{permissions.name}</div>
<div className="resource-text">{` ${permissions.name}`}</div>
</div>
<div className="text-muted">
<div className="d-flex apps-permission-wrap flex-column">

View file

@ -555,7 +555,10 @@ class ManageGroupPermissionResourcesComponent extends React.Component {
<nav className="nav nav-tabs groups-sub-header-wrap">
<a
onClick={() => this.setState({ currentTab: 'users', showUserSearchBox: false })}
onClick={() => {
this.setState({ currentTab: 'granularAccess', showUserSearchBox: false });
this.setSelectedUsers([]);
}}
className={cx('nav-item nav-link', { active: currentTab === 'users' })}
data-cy="users-link"
>
@ -570,7 +573,10 @@ class ManageGroupPermissionResourcesComponent extends React.Component {
</a>
<a
onClick={() => this.setState({ currentTab: 'permissions', showUserSearchBox: false })}
onClick={() => {
this.setState({ currentTab: 'granularAccess', showUserSearchBox: false });
this.setSelectedUsers([]);
}}
className={cx('nav-item nav-link', { active: currentTab === 'permissions' })}
data-cy="permissions-link"
>
@ -587,7 +593,10 @@ class ManageGroupPermissionResourcesComponent extends React.Component {
)}
</a>
<a
onClick={() => this.setState({ currentTab: 'granularAccess', showUserSearchBox: false })}
onClick={() => {
this.setState({ currentTab: 'granularAccess', showUserSearchBox: false });
this.setSelectedUsers([]);
}}
className={cx('nav-item nav-link', { active: currentTab === 'granularAccess' })}
data-cy="granular-access-link"
>

View file

@ -507,7 +507,6 @@ class ManageGroupPermissionsComponent extends React.Component {
</ButtonSolid>
)}
</div>
<Modal
show={showNewGroupForm || showGroupNameUpdateForm}
closeModal={() =>
@ -589,16 +588,90 @@ class ManageGroupPermissionsComponent extends React.Component {
</div>
</form>
</Modal>
{!showNewGroupForm && !showGroupNameUpdateForm && (
<div className="org-users-page-card-wrap">
<div className="org-users-page-sidebar">
<div className="default-group-list-container">
<div className="org-users-page-card-wrap">
<div className="org-users-page-sidebar">
<div className="default-group-list-container">
<div className="mb-2 d-flex align-items-center">
<SolidIcon name="usergear" />
<span className="ml-1 group-title">USER ROLE</span>
</div>
{defaultGroups.map((permissionGroup) => {
return (
<FolderList
key={permissionGroup.id}
listId={permissionGroup.id}
overlayFunctionParam={{
id: permissionGroup.id,
groupName: permissionGroup.name,
}}
selectedItem={this.state.selectedGroup == this.humanizeifDefaultGroupName(permissionGroup.name)}
onClick={() => {
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, '-')}
>
<span>
<OverflowTooltip>{this.humanizeifDefaultGroupName(permissionGroup.name)}</OverflowTooltip>
</span>
</FolderList>
);
})}
</div>
<div>
{!showGroupSearchBar ? (
<div className="mb-2 d-flex align-items-center">
<SolidIcon name="usergear" />
<span className="ml-1 group-title">USER ROLE</span>
<SolidIcon name="usergroup" width="18px" fill="#889096" />
<span className="ml-1 group-title">CUSTOM GROUPS</span>
<div className="create-group-cont">
<ButtonSolid
onClick={(e) => {
e.preventDefault();
this.setState({ showGroupSearchBar: true });
}}
size="xsm"
rightIcon="search"
iconWidth="15"
fill="#889096"
className="create-group-custom"
/>
<ButtonSolid
onClick={(e) => {
e.preventDefault();
this.setState({ newGroupName: null, showNewGroupForm: true, isSaveBtnDisabled: true });
}}
size="sm"
fill="#889096"
rightIcon="plus"
iconWidth="20"
className="create-group-custom"
/>
</div>
</div>
{defaultGroups.map((permissionGroup) => {
) : (
<div className="searchbox-custom">
<SearchBox
dataCy={`query-manager`}
width="70px !important"
callBack={this.handleGroupSearch}
placeholder={'Search'}
customClass="tj-common-search-input-group"
onClearCallback={this.handleGroupSearchClose}
autoFocus={true}
/>
</div>
)}
{groups.length ? (
filteredGroup.map((permissionGroup) => {
return (
<FolderList
key={permissionGroup.id}
@ -629,116 +702,37 @@ class ManageGroupPermissionsComponent extends React.Component {
</span>
</FolderList>
);
})}
</div>
<div>
{!showGroupSearchBar ? (
<div className="mb-2 d-flex align-items-center">
<SolidIcon name="usergroup" width="18px" fill="#889096" />
<span className="ml-1 group-title">CUSTOM GROUPS</span>
<div className="create-group-cont">
<ButtonSolid
onClick={(e) => {
e.preventDefault();
this.setState({ showGroupSearchBar: true });
}}
size="xsm"
rightIcon="search"
iconWidth="15"
fill="#889096"
className="create-group-custom"
/>
<ButtonSolid
onClick={(e) => {
e.preventDefault();
this.setState({ newGroupName: null, showNewGroupForm: true, isSaveBtnDisabled: true });
}}
size="sm"
fill="#889096"
rightIcon="plus"
iconWidth="20"
className="create-group-custom"
/>
</div>
</div>
) : (
<div className="searchbox-custom">
<SearchBox
dataCy={`query-manager`}
width="70px !important"
callBack={this.handleGroupSearch}
placeholder={'Search'}
customClass="tj-common-search-input-group"
onClearCallback={this.handleGroupSearchClose}
autoFocus={true}
/>
</div>
)}
{groups.length ? (
filteredGroup.map((permissionGroup) => {
return (
<FolderList
key={permissionGroup.id}
listId={permissionGroup.id}
overlayFunctionParam={{
id: permissionGroup.id,
groupName: permissionGroup.name,
}}
selectedItem={
this.state.selectedGroup == this.humanizeifDefaultGroupName(permissionGroup.name)
}
onClick={() => {
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, '-')}
>
<span>
<OverflowTooltip>{this.humanizeifDefaultGroupName(permissionGroup.name)}</OverflowTooltip>
</span>
</FolderList>
);
})
) : (
<div className="empty-custom-group-info">
<SolidIcon className="info-icon" name="information" width="18px" />
<span className="tj-text-xsm text-center info-label">No custom groups added</span>
</div>
)}
</div>
</div>
<div className="org-users-page-card-body">
{isLoading ? (
<Loader />
})
) : (
<ManageGroupPermissionResourcesV2
groupPermissionId={this.state.selectedGroupPermissionId}
darkMode={this.props.darkMode}
selectedGroup={this.state.selectedGroup}
selectedGroupObject={this.state.selectedGroupObject}
updateGroupName={this.updateGroupName}
deleteGroup={this.deleteGroup}
roleOptions={defaultGroups.map((group) => {
return {
name: this.humanizeifDefaultGroupName(group.name),
value: group.name,
};
})}
/>
<div className="empty-custom-group-info">
<SolidIcon className="info-icon" name="information" width="18px" />
<span className="tj-text-xsm text-center info-label">No custom groups added</span>
</div>
)}
</div>
</div>
)}
<div className="org-users-page-card-body">
{isLoading ? (
<Loader />
) : (
<ManageGroupPermissionResourcesV2
groupPermissionId={this.state.selectedGroupPermissionId}
darkMode={this.props.darkMode}
selectedGroup={this.state.selectedGroup}
selectedGroupObject={this.state.selectedGroupObject}
updateGroupName={this.updateGroupName}
deleteGroup={this.deleteGroup}
roleOptions={defaultGroups.map((group) => {
return {
name: this.humanizeifDefaultGroupName(group.name),
value: group.name,
};
})}
/>
)}
</div>
</div>
</div>
</div>
</ErrorBoundary>

View file

@ -430,6 +430,7 @@
}
.resource-text {
margin-left: 10px;
padding-left: 20px;
}
}
}

View file

@ -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<void> {
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<ResourceType, CreateResourcePermissionObject> =
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<GranularPermissions> {
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<AppsGroupPermissions> {
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<void> {}
}

View file

@ -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<void> {
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<void> {}
}

View file

@ -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<void> {
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<GranularPermissions> {
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<AppsGroupPermissions> {
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<void> {}
}

View file

@ -0,0 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class DropGroupPermissionsOlderRelatedTables1720513124281 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
queryRunner.query('DROP TABLE group_permissions, user_group_permissions, app_group_permissions CASCADE;');
}
public async down(queryRunner: QueryRunner): Promise<void> {}
}

View file

@ -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;
}

View file

@ -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 = {

View file

@ -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;
}