Decouple Send Email node from workflows (#13322)
- Renamed `WorkflowActionAdapter` to `ToolExecutorWorkflowAction` - Renamed `settingPermission` table to `permissionFlag` and `setting` column to `flag` - Decoupled the send email logic from workflows to tools - Add new `Tools Permission` section in FE --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@ -7,7 +7,7 @@ import { createOneObjectMetadataQueryFactory } from 'test/integration/metadata/s
|
||||
import { deleteOneObjectMetadataQueryFactory } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata-query-factory.util';
|
||||
|
||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||
import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants';
|
||||
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
|
||||
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||
import { WORKSPACE_MEMBER_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/workspace-member-data-seeds.constant';
|
||||
|
||||
@ -70,13 +70,13 @@ describe('Granular settings permissions', () => {
|
||||
// Assign specific setting permissions to the custom role
|
||||
const upsertSettingPermissionsQuery = {
|
||||
query: `
|
||||
mutation UpsertSettingPermissions {
|
||||
upsertSettingPermissions(upsertSettingPermissionsInput: {
|
||||
mutation UpsertPermissionFlags {
|
||||
upsertPermissionFlags(upsertPermissionFlagsInput: {
|
||||
roleId: "${customRoleId}"
|
||||
settingPermissionKeys: [${SettingPermissionType.DATA_MODEL}, ${SettingPermissionType.WORKSPACE}, ${SettingPermissionType.WORKFLOWS}]
|
||||
permissionFlagKeys: [${PermissionFlagType.DATA_MODEL}, ${PermissionFlagType.WORKSPACE}, ${PermissionFlagType.WORKFLOWS}]
|
||||
}) {
|
||||
id
|
||||
setting
|
||||
flag
|
||||
roleId
|
||||
}
|
||||
}
|
||||
@ -357,8 +357,8 @@ describe('Granular settings permissions', () => {
|
||||
id
|
||||
label
|
||||
canUpdateAllSettings
|
||||
settingPermissions {
|
||||
setting
|
||||
permissionFlags {
|
||||
flag
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -376,13 +376,13 @@ describe('Granular settings permissions', () => {
|
||||
|
||||
expect(customRole).toBeDefined();
|
||||
expect(customRole.canUpdateAllSettings).toBe(false);
|
||||
expect(customRole.settingPermissions).toHaveLength(3);
|
||||
expect(
|
||||
customRole.settingPermissions.map((p: any) => p.setting),
|
||||
).toContain(SettingPermissionType.DATA_MODEL);
|
||||
expect(
|
||||
customRole.settingPermissions.map((p: any) => p.setting),
|
||||
).toContain(SettingPermissionType.WORKSPACE);
|
||||
expect(customRole.permissionFlags).toHaveLength(3);
|
||||
expect(customRole.permissionFlags.map((p: any) => p.flag)).toContain(
|
||||
PermissionFlagType.DATA_MODEL,
|
||||
);
|
||||
expect(customRole.permissionFlags.map((p: any) => p.flag)).toContain(
|
||||
PermissionFlagType.WORKSPACE,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -391,13 +391,13 @@ describe('Granular settings permissions', () => {
|
||||
// Add SECURITY permission to the custom role
|
||||
const upsertSecurityPermissionQuery = {
|
||||
query: `
|
||||
mutation UpsertSettingPermissions {
|
||||
upsertSettingPermissions(upsertSettingPermissionsInput: {
|
||||
mutation UpsertPermissionFlags {
|
||||
upsertPermissionFlags(upsertPermissionFlagsInput: {
|
||||
roleId: "${customRoleId}"
|
||||
settingPermissionKeys: [${SettingPermissionType.DATA_MODEL}, ${SettingPermissionType.WORKSPACE}, ${SettingPermissionType.SECURITY}]
|
||||
permissionFlagKeys: [${PermissionFlagType.DATA_MODEL}, ${PermissionFlagType.WORKSPACE}, ${PermissionFlagType.SECURITY}]
|
||||
}) {
|
||||
id
|
||||
setting
|
||||
flag
|
||||
roleId
|
||||
}
|
||||
}
|
||||
@ -411,7 +411,7 @@ describe('Granular settings permissions', () => {
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.errors).toBeUndefined();
|
||||
expect(response.body.data.upsertSettingPermissions).toHaveLength(3);
|
||||
expect(response.body.data.upsertPermissionFlags).toHaveLength(3);
|
||||
|
||||
// Verify the user now has access to security operations
|
||||
// Note: This would require a specific security operation to test
|
||||
@ -421,8 +421,8 @@ describe('Granular settings permissions', () => {
|
||||
query GetRole {
|
||||
getRoles {
|
||||
id
|
||||
settingPermissions {
|
||||
setting
|
||||
permissionFlags {
|
||||
flag
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -438,23 +438,23 @@ describe('Granular settings permissions', () => {
|
||||
(role: any) => role.id === customRoleId,
|
||||
);
|
||||
|
||||
expect(updatedRole.settingPermissions).toHaveLength(3);
|
||||
expect(
|
||||
updatedRole.settingPermissions.map((p: any) => p.setting),
|
||||
).toContain(SettingPermissionType.SECURITY);
|
||||
expect(updatedRole.permissionFlags).toHaveLength(3);
|
||||
expect(updatedRole.permissionFlags.map((p: any) => p.flag)).toContain(
|
||||
PermissionFlagType.SECURITY,
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow removing setting permissions from existing role', async () => {
|
||||
// Remove SECURITY permission, keep only DATA_MODEL and WORKSPACE
|
||||
const upsertReducedPermissionsQuery = {
|
||||
query: `
|
||||
mutation UpsertSettingPermissions {
|
||||
upsertSettingPermissions(upsertSettingPermissionsInput: {
|
||||
mutation UpsertPermissionFlags {
|
||||
upsertPermissionFlags(upsertPermissionFlagsInput: {
|
||||
roleId: "${customRoleId}"
|
||||
settingPermissionKeys: [${SettingPermissionType.DATA_MODEL}, ${SettingPermissionType.WORKSPACE}]
|
||||
permissionFlagKeys: [${PermissionFlagType.DATA_MODEL}, ${PermissionFlagType.WORKSPACE}]
|
||||
}) {
|
||||
id
|
||||
setting
|
||||
flag
|
||||
roleId
|
||||
}
|
||||
}
|
||||
@ -468,7 +468,7 @@ describe('Granular settings permissions', () => {
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.errors).toBeUndefined();
|
||||
expect(response.body.data.upsertSettingPermissions).toHaveLength(2);
|
||||
expect(response.body.data.upsertPermissionFlags).toHaveLength(2);
|
||||
|
||||
// Verify SECURITY permission was removed
|
||||
const getRoleQuery = {
|
||||
@ -476,8 +476,8 @@ describe('Granular settings permissions', () => {
|
||||
query GetRole {
|
||||
getRoles {
|
||||
id
|
||||
settingPermissions {
|
||||
setting
|
||||
permissionFlags {
|
||||
flag
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -493,10 +493,10 @@ describe('Granular settings permissions', () => {
|
||||
(role: any) => role.id === customRoleId,
|
||||
);
|
||||
|
||||
expect(updatedRole.settingPermissions).toHaveLength(2);
|
||||
expect(
|
||||
updatedRole.settingPermissions.map((p: any) => p.setting),
|
||||
).not.toContain(SettingPermissionType.SECURITY);
|
||||
expect(updatedRole.permissionFlags).toHaveLength(2);
|
||||
expect(updatedRole.permissionFlags.map((p: any) => p.flag)).not.toContain(
|
||||
PermissionFlagType.SECURITY,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,7 +5,7 @@ import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object
|
||||
|
||||
import { fieldTextMock } from 'src/engine/api/__mocks__/object-metadata-item.mock';
|
||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||
import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants';
|
||||
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
|
||||
import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception';
|
||||
import { WORKSPACE_MEMBER_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/workspace-member-data-seeds.constant';
|
||||
|
||||
@ -561,17 +561,17 @@ describe('roles permissions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('upsertSettingPermissions', () => {
|
||||
describe('upsertPermissionFlags', () => {
|
||||
const upsertSettingPermissionsMutation = ({
|
||||
roleId,
|
||||
}: {
|
||||
roleId: string;
|
||||
}) => `
|
||||
mutation UpsertSettingPermissions {
|
||||
upsertSettingPermissions(upsertSettingPermissionsInput: {roleId: "${roleId}", settingPermissionKeys: [${SettingPermissionType.DATA_MODEL}]}) {
|
||||
mutation UpsertPermissionFlags {
|
||||
upsertPermissionFlags(upsertPermissionFlagsInput: {roleId: "${roleId}", permissionFlagKeys: [${PermissionFlagType.DATA_MODEL}]}) {
|
||||
id
|
||||
roleId
|
||||
setting
|
||||
flag
|
||||
}
|
||||
}
|
||||
`;
|
||||
@ -625,11 +625,11 @@ describe('roles permissions', () => {
|
||||
.expect((res) => {
|
||||
expect(res.body.data).toBeDefined();
|
||||
expect(res.body.errors).toBeUndefined();
|
||||
expect(res.body.data.upsertSettingPermissions).toEqual(
|
||||
expect(res.body.data.upsertPermissionFlags).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
roleId: createdEditableRoleId,
|
||||
setting: SettingPermissionType.DATA_MODEL,
|
||||
flag: PermissionFlagType.DATA_MODEL,
|
||||
}),
|
||||
]),
|
||||
);
|
||||
|
||||
@ -5,14 +5,19 @@ import { Repository } from 'typeorm';
|
||||
|
||||
import { ToolAdapterService } from 'src/engine/core-modules/ai/services/tool-adapter.service';
|
||||
import { ToolService } from 'src/engine/core-modules/ai/services/tool.service';
|
||||
import { ToolRegistryService } from 'src/engine/core-modules/tool/services/tool-registry.service';
|
||||
import { SendEmailTool } from 'src/engine/core-modules/tool/tools/send-email-tool/send-email-tool';
|
||||
import { AgentToolService } from 'src/engine/metadata-modules/agent/agent-tool.service';
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/agent/agent.entity';
|
||||
import { AgentService } from 'src/engine/metadata-modules/agent/agent.service';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
|
||||
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
|
||||
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { MessagingSendMessageService } from 'src/modules/messaging/message-import-manager/services/messaging-send-message.service';
|
||||
import { getMockObjectMetadataEntity } from 'src/utils/__test__/get-object-metadata-entity.mock';
|
||||
|
||||
export interface AgentToolTestContext {
|
||||
@ -79,6 +84,34 @@ export const createAgentToolTestModule =
|
||||
provide: ToolAdapterService,
|
||||
useClass: ToolAdapterService,
|
||||
},
|
||||
{
|
||||
provide: ToolRegistryService,
|
||||
useClass: ToolRegistryService,
|
||||
},
|
||||
{
|
||||
provide: SendEmailTool,
|
||||
useValue: {
|
||||
description: 'mock',
|
||||
parameters: {},
|
||||
execute: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: ScopedWorkspaceContextFactory,
|
||||
useValue: {
|
||||
create: jest.fn(() => ({ workspaceId: 'test-workspace-id' })),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: MessagingSendMessageService,
|
||||
useValue: { sendMessage: jest.fn() },
|
||||
},
|
||||
{
|
||||
provide: PermissionsService,
|
||||
useValue: {
|
||||
hasToolPermission: jest.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user