mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
feat(core): Email recipients on resource shared (#8408)
This commit is contained in:
@@ -16,6 +16,8 @@ import { getCredentialOwnerRole, getGlobalMemberRole, getGlobalOwnerRole } from
|
||||
import { createManyUsers, createUser, createUserShell } from './shared/db/users';
|
||||
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
|
||||
import Container from 'typedi';
|
||||
import { mockInstance } from '../shared/mocking';
|
||||
import { UserManagementMailer } from '@/UserManagement/email';
|
||||
|
||||
const sharingSpy = jest.spyOn(UserManagementHelpers, 'isSharingEnabled').mockReturnValue(true);
|
||||
const testServer = utils.setupTestServer({ endpointGroups: ['credentials'] });
|
||||
@@ -27,6 +29,7 @@ let anotherMember: User;
|
||||
let authOwnerAgent: SuperAgentTest;
|
||||
let authAnotherMemberAgent: SuperAgentTest;
|
||||
let saveCredential: SaveCredentialFunction;
|
||||
const mailer = mockInstance(UserManagementMailer);
|
||||
|
||||
beforeAll(async () => {
|
||||
const globalOwnerRole = await getGlobalOwnerRole();
|
||||
@@ -47,6 +50,10 @@ beforeEach(async () => {
|
||||
await testDb.truncate(['SharedCredentials', 'Credentials']);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
// ----------------------------------------
|
||||
// dynamic router switching
|
||||
// ----------------------------------------
|
||||
@@ -363,6 +370,8 @@ describe('PUT /credentials/:id/share', () => {
|
||||
expect(sharedCredential.role.name).toBe('user');
|
||||
expect(sharedCredential.role.scope).toBe('credential');
|
||||
});
|
||||
|
||||
expect(mailer.notifyCredentialsShared).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should share the credential with the provided userIds', async () => {
|
||||
@@ -400,6 +409,7 @@ describe('PUT /credentials/:id/share', () => {
|
||||
|
||||
expect(ownerSharedCredential.role.name).toBe('owner');
|
||||
expect(ownerSharedCredential.role.scope).toBe('credential');
|
||||
expect(mailer.notifyCredentialsShared).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should respond 403 for non-existing credentials', async () => {
|
||||
@@ -408,6 +418,7 @@ describe('PUT /credentials/:id/share', () => {
|
||||
.send({ shareWithIds: [member.id] });
|
||||
|
||||
expect(response.statusCode).toBe(403);
|
||||
expect(mailer.notifyCredentialsShared).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('should respond 403 for non-owned credentials for shared members', async () => {
|
||||
@@ -424,6 +435,7 @@ describe('PUT /credentials/:id/share', () => {
|
||||
where: { credentialsId: savedCredential.id },
|
||||
});
|
||||
expect(sharedCredentials).toHaveLength(2);
|
||||
expect(mailer.notifyCredentialsShared).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('should respond 403 for non-owned credentials for non-shared members sharing with self', async () => {
|
||||
@@ -439,6 +451,7 @@ describe('PUT /credentials/:id/share', () => {
|
||||
where: { credentialsId: savedCredential.id },
|
||||
});
|
||||
expect(sharedCredentials).toHaveLength(1);
|
||||
expect(mailer.notifyCredentialsShared).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('should respond 403 for non-owned credentials for non-shared members sharing', async () => {
|
||||
@@ -455,6 +468,7 @@ describe('PUT /credentials/:id/share', () => {
|
||||
where: { credentialsId: savedCredential.id },
|
||||
});
|
||||
expect(sharedCredentials).toHaveLength(1);
|
||||
expect(mailer.notifyCredentialsShared).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('should respond 200 for non-owned credentials for owners', async () => {
|
||||
@@ -469,6 +483,7 @@ describe('PUT /credentials/:id/share', () => {
|
||||
where: { credentialsId: savedCredential.id },
|
||||
});
|
||||
expect(sharedCredentials).toHaveLength(2);
|
||||
expect(mailer.notifyCredentialsShared).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should ignore pending sharee', async () => {
|
||||
@@ -487,6 +502,7 @@ describe('PUT /credentials/:id/share', () => {
|
||||
|
||||
expect(sharedCredentials).toHaveLength(1);
|
||||
expect(sharedCredentials[0].userId).toBe(owner.id);
|
||||
expect(mailer.notifyCredentialsShared).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('should ignore non-existing sharee', async () => {
|
||||
@@ -504,6 +520,7 @@ describe('PUT /credentials/:id/share', () => {
|
||||
|
||||
expect(sharedCredentials).toHaveLength(1);
|
||||
expect(sharedCredentials[0].userId).toBe(owner.id);
|
||||
expect(mailer.notifyCredentialsShared).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('should respond 400 if invalid payload is provided', async () => {
|
||||
@@ -515,6 +532,7 @@ describe('PUT /credentials/:id/share', () => {
|
||||
]);
|
||||
|
||||
responses.forEach((response) => expect(response.statusCode).toBe(400));
|
||||
expect(mailer.notifyCredentialsShared).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
test('should unshare the credential', async () => {
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: owner });
|
||||
@@ -537,6 +555,7 @@ describe('PUT /credentials/:id/share', () => {
|
||||
|
||||
expect(sharedCredentials).toHaveLength(1);
|
||||
expect(sharedCredentials[0].userId).toBe(owner.id);
|
||||
expect(mailer.notifyCredentialsShared).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
} from '../shared/db/roles';
|
||||
import { createUser } from '../shared/db/users';
|
||||
import { createWorkflow, getWorkflowSharing, shareWorkflowWithUsers } from '../shared/db/workflows';
|
||||
import { UserManagementMailer } from '@/UserManagement/email';
|
||||
|
||||
let globalMemberRole: Role;
|
||||
let owner: User;
|
||||
@@ -44,6 +45,7 @@ const testServer = utils.setupTestServer({
|
||||
enabledFeatures: ['feat:sharing'],
|
||||
});
|
||||
const license = testServer.license;
|
||||
const mailer = mockInstance(UserManagementMailer);
|
||||
|
||||
beforeAll(async () => {
|
||||
const globalOwnerRole = await getGlobalOwnerRole();
|
||||
@@ -70,6 +72,10 @@ beforeEach(async () => {
|
||||
await testDb.truncate(['Workflow', 'SharedWorkflow', 'WorkflowHistory']);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('router should switch based on flag', () => {
|
||||
let savedWorkflowId: string;
|
||||
|
||||
@@ -107,6 +113,7 @@ describe('PUT /workflows/:id', () => {
|
||||
|
||||
const sharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(sharedWorkflows).toHaveLength(2);
|
||||
expect(mailer.notifyWorkflowShared).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('PUT /workflows/:id/share should succeed when sharing with invalid user-id', async () => {
|
||||
@@ -133,6 +140,7 @@ describe('PUT /workflows/:id', () => {
|
||||
|
||||
const sharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(sharedWorkflows).toHaveLength(3);
|
||||
expect(mailer.notifyWorkflowShared).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('PUT /workflows/:id/share should override sharing', async () => {
|
||||
@@ -154,6 +162,7 @@ describe('PUT /workflows/:id', () => {
|
||||
|
||||
const secondSharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(secondSharedWorkflows).toHaveLength(2);
|
||||
expect(mailer.notifyWorkflowShared).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('PUT /workflows/:id/share should allow sharing by the owner of the workflow', async () => {
|
||||
@@ -167,6 +176,7 @@ describe('PUT /workflows/:id', () => {
|
||||
|
||||
const sharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(sharedWorkflows).toHaveLength(2);
|
||||
expect(mailer.notifyWorkflowShared).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('PUT /workflows/:id/share should allow sharing by the instance owner', async () => {
|
||||
@@ -180,6 +190,7 @@ describe('PUT /workflows/:id', () => {
|
||||
|
||||
const sharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(sharedWorkflows).toHaveLength(2);
|
||||
expect(mailer.notifyWorkflowShared).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('PUT /workflows/:id/share should not allow sharing by another shared member', async () => {
|
||||
@@ -195,6 +206,7 @@ describe('PUT /workflows/:id', () => {
|
||||
|
||||
const sharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(sharedWorkflows).toHaveLength(2);
|
||||
expect(mailer.notifyWorkflowShared).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('PUT /workflows/:id/share should not allow sharing with self by another non-shared member', async () => {
|
||||
@@ -208,6 +220,7 @@ describe('PUT /workflows/:id', () => {
|
||||
|
||||
const sharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(sharedWorkflows).toHaveLength(1);
|
||||
expect(mailer.notifyWorkflowShared).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('PUT /workflows/:id/share should not allow sharing by another non-shared member', async () => {
|
||||
@@ -223,6 +236,7 @@ describe('PUT /workflows/:id', () => {
|
||||
|
||||
const sharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(sharedWorkflows).toHaveLength(1);
|
||||
expect(mailer.notifyWorkflowShared).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user