Add Import CSV and Export CSV Permissions (#13421)

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
Abdul Rahman
2025-07-25 11:37:38 +05:30
committed by GitHub
parent f411bd1b0e
commit 4b95de6775
28 changed files with 118 additions and 71 deletions

View File

@ -97,7 +97,7 @@ export class UserWorkspace {
twoFactorAuthenticationMethods: Relation<TwoFactorAuthenticationMethod[]>;
@Field(() => [PermissionFlagType], { nullable: true })
settingsPermissions?: PermissionFlagType[];
permissionFlags?: PermissionFlagType[];
@Field(() => [PermissionsOnAllObjectRecords], {
nullable: true,

View File

@ -11,4 +11,6 @@ export enum PermissionFlagType {
// Tool permissions
SEND_EMAIL_TOOL = 'SEND_EMAIL_TOOL',
IMPORT_CSV = 'IMPORT_CSV',
EXPORT_CSV = 'EXPORT_CSV',
}

View File

@ -0,0 +1,5 @@
export const TOOL_PERMISSION_FLAGS = [
'SEND_EMAIL_TOOL',
'IMPORT_CSV',
'EXPORT_CSV',
];

View File

@ -10,6 +10,7 @@ import {
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
import { TOOL_PERMISSION_FLAGS } from 'src/engine/metadata-modules/permissions/constants/tool-permission-flags';
import {
PermissionsException,
PermissionsExceptionCode,
@ -29,6 +30,10 @@ export class PermissionsService {
private readonly roleRepository: Repository<RoleEntity>,
) {}
private isToolPermission(feature: string) {
return TOOL_PERMISSION_FLAGS.includes(feature);
}
public async getUserWorkspacePermissions({
userWorkspaceId,
workspaceId,
@ -43,8 +48,6 @@ export class PermissionsService {
})
.then((roles) => roles?.get(userWorkspaceId) ?? []);
let hasPermissionOnSettingFeature = false;
if (!isDefined(roleOfUserWorkspace)) {
throw new PermissionsException(
PermissionsExceptionMessage.NO_ROLE_FOUND_FOR_USER_WORKSPACE,
@ -52,23 +55,23 @@ export class PermissionsService {
);
}
if (roleOfUserWorkspace.canUpdateAllSettings === true) {
hasPermissionOnSettingFeature = true;
}
const permissionFlags = roleOfUserWorkspace.permissionFlags ?? [];
const defaultSettingsPermissions =
this.getDefaultUserWorkspacePermissions().settingsPermissions;
const settingsPermissions = Object.keys(PermissionFlagType).reduce(
(acc, feature) => ({
...acc,
[feature]:
hasPermissionOnSettingFeature ||
permissionFlags.some(
(permissionFlag) => permissionFlag.flag === feature,
),
}),
this.getDefaultUserWorkspacePermissions().permissionFlags;
const permissionFlags = Object.keys(PermissionFlagType).reduce(
(acc, feature) => {
const hasBasePermission = this.isToolPermission(feature)
? roleOfUserWorkspace.canAccessAllTools
: roleOfUserWorkspace.canUpdateAllSettings;
return {
...acc,
[feature]:
hasBasePermission ||
roleOfUserWorkspace.permissionFlags.some(
(permissionFlag) => permissionFlag.flag === feature,
),
};
},
defaultSettingsPermissions,
);
@ -92,7 +95,7 @@ export class PermissionsService {
};
return {
settingsPermissions,
permissionFlags,
objectRecordsPermissions,
objectPermissions,
};
@ -106,7 +109,7 @@ export class PermissionsService {
[PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS]: false,
[PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS]: false,
},
settingsPermissions: {
permissionFlags: {
[PermissionFlagType.API_KEYS_AND_WEBHOOKS]: false,
[PermissionFlagType.WORKSPACE]: false,
[PermissionFlagType.WORKSPACE_MEMBERS]: false,
@ -116,6 +119,8 @@ export class PermissionsService {
[PermissionFlagType.SECURITY]: false,
[PermissionFlagType.WORKFLOWS]: false,
[PermissionFlagType.SEND_EMAIL_TOOL]: false,
[PermissionFlagType.IMPORT_CSV]: false,
[PermissionFlagType.EXPORT_CSV]: false,
},
objectPermissions: {},
}) as const satisfies UserWorkspacePermissions;

View File

@ -4,7 +4,7 @@ import { ObjectRecordsPermissions } from 'twenty-shared/types';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
export type UserWorkspacePermissions = {
settingsPermissions: Record<PermissionFlagType, boolean>;
permissionFlags: Record<PermissionFlagType, boolean>;
objectRecordsPermissions: Record<PermissionsOnAllObjectRecords, boolean>;
objectPermissions: ObjectRecordsPermissions;
};

View File

@ -2,5 +2,5 @@ import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-works
export type UserWorkspacePermissionsDto = Pick<
UserWorkspace,
'objectPermissions' | 'settingsPermissions' | 'objectRecordsPermissions'
'objectPermissions' | 'permissionFlags' | 'objectRecordsPermissions'
>;

View File

@ -7,7 +7,7 @@ import { UserWorkspacePermissionsDto } from 'src/engine/metadata-modules/role/dt
export const fromUserWorkspacePermissionsToUserWorkspacePermissionsDto = ({
objectPermissions: rawObjectPermissions,
objectRecordsPermissions: rawObjectRecordsPermissions,
settingsPermissions: rawSettingsPermissions,
permissionFlags: rawSettingsPermissions,
}: UserWorkspacePermissions): UserWorkspacePermissionsDto => {
const objectPermissions = Object.entries(rawObjectPermissions).map(
([objectMetadataId, permissions]) => ({
@ -19,7 +19,7 @@ export const fromUserWorkspacePermissionsToUserWorkspacePermissionsDto = ({
}),
);
const settingsPermissions = (
const permissionFlags = (
Object.keys(rawSettingsPermissions) as PermissionFlagType[]
).filter((feature) => rawSettingsPermissions[feature] === true);
@ -30,6 +30,6 @@ export const fromUserWorkspacePermissionsToUserWorkspacePermissionsDto = ({
return {
objectPermissions,
objectRecordsPermissions,
settingsPermissions,
permissionFlags,
};
};

View File

@ -110,6 +110,7 @@ export class DevSeederPermissionsService {
'All permissions except read on Rockets and update on Pets',
icon: 'custom',
canUpdateAllSettings: true,
canAccessAllTools: true,
canReadAllObjectRecords: true,
canUpdateAllObjectRecords: true,
canSoftDeleteAllObjectRecords: true,