Skip to content

Commit

Permalink
fix: ProjectRepository.getPersonalProjectForUser[OrFail] not taking t…
Browse files Browse the repository at this point in the history
…he type or the role of the user to the project into account (#8676)
  • Loading branch information
despairblue authored Feb 20, 2024
1 parent 674abd8 commit 655ada8
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 3 deletions.
8 changes: 6 additions & 2 deletions packages/cli/src/databases/repositories/project.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ export class ProjectRepository extends Repository<Project> {
}

async getPersonalProjectForUser(userId: string) {
return await this.findOne({ where: { projectRelations: { userId } } });
return await this.findOne({
where: { type: 'personal', projectRelations: { userId, role: 'project:personalOwner' } },
});
}

async getPersonalProjectForUserOrFail(userId: string) {
return await this.findOneOrFail({ where: { projectRelations: { userId } } });
return await this.findOneOrFail({
where: { type: 'personal', projectRelations: { userId, role: 'project:personalOwner' } },
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import Container from 'typedi';
import { createOwner } from '../../shared/db/users';
import * as testDb from '../../shared/testDb';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import { EntityNotFoundError } from '@n8n/typeorm';
import { createProject } from '../../shared/db/projects';

describe('ProjectRepository', () => {
beforeAll(async () => {
await testDb.init();
});

beforeEach(async () => {
await testDb.truncate(['User', 'Workflow', 'Project']);
});

afterAll(async () => {
await testDb.terminate();
});

describe('getPersonalProjectForUser', () => {
it('returns the personal project', async () => {
//
// ARRANGE
//
const owner = await createOwner();
const ownerPersonalProject = await Container.get(ProjectRepository).findOneByOrFail({
projectRelations: { userId: owner.id },
});

//
// ACT
//
const personalProject = await Container.get(ProjectRepository).getPersonalProjectForUser(
owner.id,
);

//
// ASSERT
//
if (!personalProject) {
fail('Expected personalProject to be defined.');
}
expect(personalProject).toBeDefined();
expect(personalProject.id).toBe(ownerPersonalProject.id);
});

it('does not return non personal projects', async () => {
//
// ARRANGE
//
const owner = await createOwner();
await Container.get(ProjectRepository).delete({});
await createProject(owner);

//
// ACT
//
const personalProject = await Container.get(ProjectRepository).getPersonalProjectForUser(
owner.id,
);

//
// ASSERT
//
expect(personalProject).toBeNull();
});
});

describe('getPersonalProjectForUserOrFail', () => {
it('returns the personal project', async () => {
//
// ARRANGE
//
const owner = await createOwner();
const ownerPersonalProject = await Container.get(ProjectRepository).findOneByOrFail({
projectRelations: { userId: owner.id },
});

//
// ACT
//
const personalProject = await Container.get(
ProjectRepository,
).getPersonalProjectForUserOrFail(owner.id);

//
// ASSERT
//
if (!personalProject) {
fail('Expected personalProject to be defined.');
}
expect(personalProject).toBeDefined();
expect(personalProject.id).toBe(ownerPersonalProject.id);
});

it('does not return non personal projects', async () => {
//
// ARRANGE
//
const owner = await createOwner();
await Container.get(ProjectRepository).delete({});
await createProject(owner);

//
// ACT
//
const promise = Container.get(ProjectRepository).getPersonalProjectForUserOrFail(owner.id);

//
// ASSERT
//
await expect(promise).rejects.toThrowError(EntityNotFoundError);
});
});
});
28 changes: 28 additions & 0 deletions packages/cli/test/integration/shared/db/projects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Container from 'typedi';
import { ProjectRepository } from '@/databases/repositories/project.repository';
import type { DeepPartial } from 'ts-essentials';
import type { Project } from '@/databases/entities/Project';
import { ProjectRelationRepository } from '@/databases/repositories/projectRelation.repository';
import type { User } from '@/databases/entities/User';

export async function createProject(user: User, project?: DeepPartial<Project>) {
const projectRepository = Container.get(ProjectRepository);
const projectRelationRepository = Container.get(ProjectRelationRepository);

const savedProject = await projectRepository.save(
projectRepository.create({
name: 'project name',
type: 'team',
...project,
}),
);
await projectRelationRepository.save(
projectRelationRepository.create({
userId: user.id,
projectId: savedProject.id,
role: 'project:personalOwner',
}),
);

return savedProject;
}
3 changes: 2 additions & 1 deletion packages/cli/test/integration/shared/testDb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,12 @@ const repositories = [
'AuthProviderSyncHistory',
'Credentials',
'EventDestinations',
'Execution',
'ExecutionData',
'ExecutionMetadata',
'Execution',
'InstalledNodes',
'InstalledPackages',
'Project',
'Role',
'Settings',
'SharedCredentials',
Expand Down

0 comments on commit 655ada8

Please sign in to comment.