feat: add organisations (#1820)

This commit is contained in:
David Nguyen
2025-06-10 11:49:52 +10:00
committed by GitHub
parent 0b37f19641
commit e6dc237ad2
631 changed files with 37616 additions and 25695 deletions

View File

@ -8,12 +8,13 @@ import { seedUser } from '@documenso/prisma/seed/users';
import { apiSignin, apiSignout } from '../fixtures/authentication';
import { checkDocumentTabCount } from '../fixtures/documents';
import { expectTextToBeVisible } from '../fixtures/generic';
test('[TEAMS]: check team documents count', async ({ page }) => {
const { team, teamMember2 } = await seedTeamDocuments();
const { team, teamOwner, teamMember2 } = await seedTeamDocuments();
// Run the test twice, once with the team owner and once with a team member to ensure the counts are the same.
for (const user of [team.owner, teamMember2]) {
for (const user of [teamOwner, teamMember2]) {
await apiSignin({
page,
email: user.email,
@ -44,8 +45,12 @@ test('[TEAMS]: check team documents count', async ({ page }) => {
});
test('[TEAMS]: check team documents count with internal team email', async ({ page }) => {
const { team, teamMember2, teamMember4 } = await seedTeamDocuments();
const { team: team2, teamMember2: team2Member2 } = await seedTeamDocuments();
const { team, teamOwner, teamMember2, teamMember4 } = await seedTeamDocuments();
const {
team: team2,
teamOwner: team2Owner,
teamMember2: team2Member2,
} = await seedTeamDocuments();
const teamEmailMember = teamMember4;
@ -54,7 +59,7 @@ test('[TEAMS]: check team documents count with internal team email', async ({ pa
teamId: team.id,
});
const testUser1 = await seedUser();
const { user: testUser1, team: testUser1Team } = await seedUser();
await seedDocuments([
// Documents sent from the team email account.
@ -62,52 +67,53 @@ test('[TEAMS]: check team documents count with internal team email', async ({ pa
sender: teamEmailMember,
recipients: [testUser1],
type: DocumentStatus.COMPLETED,
documentOptions: {
teamId: team.id,
},
teamId: team.id,
documentOptions: {},
},
{
sender: teamEmailMember,
recipients: [testUser1],
type: DocumentStatus.PENDING,
documentOptions: {
teamId: team.id,
},
teamId: team.id,
documentOptions: {},
},
{
sender: teamMember4,
recipients: [testUser1],
type: DocumentStatus.DRAFT,
teamId: team.id,
},
// Documents sent to the team email account.
{
sender: testUser1,
recipients: [teamEmailMember],
type: DocumentStatus.COMPLETED,
teamId: testUser1Team.id,
},
{
sender: testUser1,
recipients: [teamEmailMember],
type: DocumentStatus.PENDING,
teamId: testUser1Team.id,
},
{
sender: testUser1,
recipients: [teamEmailMember],
type: DocumentStatus.DRAFT,
teamId: testUser1Team.id,
},
// Document sent to the team email account from another team.
{
sender: team2Member2,
recipients: [teamEmailMember],
type: DocumentStatus.PENDING,
documentOptions: {
teamId: team2.id,
},
teamId: team2.id,
documentOptions: {},
},
]);
// Run the test twice, one with the team owner and once with the team member email to ensure the counts are the same.
for (const user of [team.owner, teamEmailMember]) {
for (const user of [teamOwner, teamEmailMember]) {
await apiSignin({
page,
email: user.email,
@ -138,7 +144,8 @@ test('[TEAMS]: check team documents count with internal team email', async ({ pa
});
test('[TEAMS]: check team documents count with external team email', async ({ page }) => {
const { team, teamMember2 } = await seedTeamDocuments();
const { team, teamOwner, teamMember2 } = await seedTeamDocuments();
const { team: team2, teamMember2: team2Member2 } = await seedTeamDocuments();
const teamEmail = `external-team-email-${team.id}@test.documenso.com`;
@ -148,7 +155,9 @@ test('[TEAMS]: check team documents count with external team email', async ({ pa
teamId: team.id,
});
const testUser1 = await seedUser();
const { user: testUser1, team: testUser1Team } = await seedUser({
isPersonalOrganisation: true,
});
await seedDocuments([
// Documents sent to the team email account.
@ -156,42 +165,39 @@ test('[TEAMS]: check team documents count with external team email', async ({ pa
sender: testUser1,
recipients: [teamEmail],
type: DocumentStatus.COMPLETED,
teamId: testUser1Team.id,
},
{
sender: testUser1,
recipients: [teamEmail],
type: DocumentStatus.PENDING,
teamId: testUser1Team.id,
},
{
sender: testUser1,
recipients: [teamEmail],
type: DocumentStatus.DRAFT,
teamId: testUser1Team.id,
},
// Document sent to the team email account from another team.
{
sender: team2Member2,
recipients: [teamEmail],
type: DocumentStatus.PENDING,
documentOptions: {
teamId: team2.id,
},
teamId: team2.id,
},
// Document sent to the team email account from an individual user.
{
sender: testUser1,
recipients: [teamEmail],
type: DocumentStatus.PENDING,
documentOptions: {
teamId: team2.id,
},
teamId: testUser1Team.id,
},
{
sender: testUser1,
recipients: [teamEmail],
type: DocumentStatus.DRAFT,
documentOptions: {
teamId: team2.id,
},
teamId: testUser1Team.id,
},
]);
@ -222,7 +228,7 @@ test('[TEAMS]: check team documents count with external team email', async ({ pa
});
test('[TEAMS]: resend pending team document', async ({ page }) => {
const { team, teamMember2: currentUser } = await seedTeamDocuments();
const { team, teamOwner, teamMember2: currentUser } = await seedTeamDocuments();
await apiSignin({
page,
@ -248,7 +254,7 @@ test('[TEAMS]: resend pending team document', async ({ page }) => {
});
test('[TEAMS]: delete draft team document', async ({ page }) => {
const { team, teamMember2: teamEmailMember, teamMember3 } = await seedTeamDocuments();
const { team, teamOwner, teamMember2: teamEmailMember, teamMember3 } = await seedTeamDocuments();
await apiSignin({
page,
@ -273,7 +279,7 @@ test('[TEAMS]: delete draft team document', async ({ page }) => {
await apiSignout({ page });
// Run the test twice, one with the team owner and once with the team member email to ensure the counts are the same.
for (const user of [team.owner, teamEmailMember]) {
for (const user of [teamOwner, teamEmailMember]) {
await apiSignin({
page,
email: user.email,
@ -292,7 +298,7 @@ test('[TEAMS]: delete draft team document', async ({ page }) => {
});
test('[TEAMS]: delete pending team document', async ({ page }) => {
const { team, teamMember2: teamEmailMember, teamMember3 } = await seedTeamDocuments();
const { team, teamOwner, teamMember2: teamEmailMember, teamMember3 } = await seedTeamDocuments();
await apiSignin({
page,
@ -318,7 +324,7 @@ test('[TEAMS]: delete pending team document', async ({ page }) => {
await apiSignout({ page });
// Run the test twice, one with the team owner and once with the team member email to ensure the counts are the same.
for (const user of [team.owner, teamEmailMember]) {
for (const user of [teamOwner, teamEmailMember]) {
await apiSignin({
page,
email: user.email,
@ -337,7 +343,7 @@ test('[TEAMS]: delete pending team document', async ({ page }) => {
});
test('[TEAMS]: delete completed team document', async ({ page }) => {
const { team, teamMember2: teamEmailMember, teamMember3 } = await seedTeamDocuments();
const { team, teamOwner, teamMember2: teamEmailMember, teamMember3 } = await seedTeamDocuments();
await apiSignin({
page,
@ -363,7 +369,7 @@ test('[TEAMS]: delete completed team document', async ({ page }) => {
await apiSignout({ page });
// Run the test twice, one with the team owner and once with the team member email to ensure the counts are the same.
for (const user of [team.owner, teamEmailMember]) {
for (const user of [teamOwner, teamEmailMember]) {
await apiSignin({
page,
email: user.email,
@ -382,7 +388,7 @@ test('[TEAMS]: delete completed team document', async ({ page }) => {
});
test('[TEAMS]: check document visibility based on team member role', async ({ page }) => {
const team = await seedTeam();
const { team, owner } = await seedTeam();
// Seed users with different roles
const adminUser = await seedTeamMember({
@ -400,46 +406,48 @@ test('[TEAMS]: check document visibility based on team member role', async ({ pa
role: TeamMemberRole.MEMBER,
});
const outsideUser = await seedUser();
const { user: outsideUser, team: outsideUserTeam } = await seedUser({
isPersonalOrganisation: true,
});
// Seed documents with different visibility levels
await seedDocuments([
{
sender: team.owner,
sender: owner,
recipients: [],
type: DocumentStatus.COMPLETED,
teamId: team.id,
documentOptions: {
teamId: team.id,
visibility: 'EVERYONE',
title: 'Document Visible to Everyone',
},
},
{
sender: team.owner,
sender: owner,
recipients: [],
type: DocumentStatus.COMPLETED,
teamId: team.id,
documentOptions: {
teamId: team.id,
visibility: 'MANAGER_AND_ABOVE',
title: 'Document Visible to Manager and Above',
},
},
{
sender: team.owner,
sender: owner,
recipients: [],
type: DocumentStatus.COMPLETED,
teamId: team.id,
documentOptions: {
teamId: team.id,
visibility: 'ADMIN',
title: 'Document Visible to Admin',
},
},
{
sender: team.owner,
sender: owner,
recipients: [outsideUser],
type: DocumentStatus.COMPLETED,
teamId: team.id,
documentOptions: {
teamId: team.id,
visibility: 'ADMIN',
title: 'Document Visible to Admin with Recipient',
},
@ -470,11 +478,6 @@ test('[TEAMS]: check document visibility based on team member role', async ({ pa
path: teamUrlRedirect,
expectedDocuments: ['Document Visible to Everyone'],
},
{
user: outsideUser,
path: '/documents',
expectedDocuments: ['Document Visible to Admin with Recipient'],
},
];
for (const testCase of testCases) {
@ -491,12 +494,20 @@ test('[TEAMS]: check document visibility based on team member role', async ({ pa
await apiSignout({ page });
}
await apiSignin({
page,
email: outsideUser.email,
redirectPath: '/inbox',
});
await expectTextToBeVisible(page, 'Document Visible to Admin with Recipient');
});
test('[TEAMS]: ensure document owner can see document regardless of visibility', async ({
page,
}) => {
const team = await seedTeam();
const { team, owner } = await seedTeam();
// Seed a member user
const memberUser = await seedTeamMember({
@ -510,8 +521,8 @@ test('[TEAMS]: ensure document owner can see document regardless of visibility',
sender: memberUser,
recipients: [],
type: DocumentStatus.COMPLETED,
teamId: team.id,
documentOptions: {
teamId: team.id,
visibility: 'ADMIN',
title: 'Admin Document with Member Document Owner',
},
@ -533,7 +544,7 @@ test('[TEAMS]: ensure document owner can see document regardless of visibility',
});
test('[TEAMS]: ensure recipient can see document regardless of visibility', async ({ page }) => {
const team = await seedTeam();
const { team, owner } = await seedTeam();
// Seed a member user
const memberUser = await seedTeamMember({
@ -544,11 +555,11 @@ test('[TEAMS]: ensure recipient can see document regardless of visibility', asyn
// Seed a document with ADMIN visibility but make the member user a recipient
await seedDocuments([
{
sender: team.owner,
sender: owner,
recipients: [memberUser],
type: DocumentStatus.COMPLETED,
teamId: team.id,
documentOptions: {
teamId: team.id,
visibility: 'ADMIN',
title: 'Admin Document with Member Recipient',
},
@ -570,7 +581,7 @@ test('[TEAMS]: ensure recipient can see document regardless of visibility', asyn
});
test('[TEAMS]: check that MEMBER role cannot see ADMIN-only documents', async ({ page }) => {
const team = await seedTeam();
const { team, owner } = await seedTeam();
// Seed a member user
const memberUser = await seedTeamMember({
@ -581,11 +592,11 @@ test('[TEAMS]: check that MEMBER role cannot see ADMIN-only documents', async ({
// Seed an ADMIN-only document
await seedDocuments([
{
sender: team.owner,
sender: owner,
recipients: [],
type: DocumentStatus.COMPLETED,
teamId: team.id,
documentOptions: {
teamId: team.id,
visibility: 'ADMIN',
title: 'Admin Only Document',
},
@ -609,7 +620,7 @@ test('[TEAMS]: check that MEMBER role cannot see ADMIN-only documents', async ({
test('[TEAMS]: check that MEMBER role cannot see MANAGER_AND_ABOVE-only documents', async ({
page,
}) => {
const team = await seedTeam();
const { team, owner } = await seedTeam();
// Seed a member user
const memberUser = await seedTeamMember({
@ -620,11 +631,11 @@ test('[TEAMS]: check that MEMBER role cannot see MANAGER_AND_ABOVE-only document
// Seed an ADMIN-only document
await seedDocuments([
{
sender: team.owner,
sender: owner,
recipients: [],
type: DocumentStatus.COMPLETED,
teamId: team.id,
documentOptions: {
teamId: team.id,
visibility: 'MANAGER_AND_ABOVE',
title: 'Manager and Above Only Document',
},
@ -646,7 +657,7 @@ test('[TEAMS]: check that MEMBER role cannot see MANAGER_AND_ABOVE-only document
});
test('[TEAMS]: check that MANAGER role cannot see ADMIN-only documents', async ({ page }) => {
const team = await seedTeam();
const { team, owner } = await seedTeam();
// Seed a manager user
const managerUser = await seedTeamMember({
@ -657,11 +668,11 @@ test('[TEAMS]: check that MANAGER role cannot see ADMIN-only documents', async (
// Seed an ADMIN-only document
await seedDocuments([
{
sender: team.owner,
sender: owner,
recipients: [],
type: DocumentStatus.COMPLETED,
teamId: team.id,
documentOptions: {
teamId: team.id,
visibility: 'ADMIN',
title: 'Admin Only Document',
},
@ -683,7 +694,7 @@ test('[TEAMS]: check that MANAGER role cannot see ADMIN-only documents', async (
});
test('[TEAMS]: check that ADMIN role can see MANAGER_AND_ABOVE documents', async ({ page }) => {
const team = await seedTeam();
const { team, owner } = await seedTeam();
// Seed an admin user
const adminUser = await seedTeamMember({
@ -694,11 +705,11 @@ test('[TEAMS]: check that ADMIN role can see MANAGER_AND_ABOVE documents', async
// Seed a MANAGER_AND_ABOVE document
await seedDocuments([
{
sender: team.owner,
sender: owner,
recipients: [],
type: DocumentStatus.COMPLETED,
teamId: team.id,
documentOptions: {
teamId: team.id,
visibility: 'MANAGER_AND_ABOVE',
title: 'Manager and Above Document',
},
@ -720,25 +731,16 @@ test('[TEAMS]: check that ADMIN role can see MANAGER_AND_ABOVE documents', async
});
test('[TEAMS]: check that ADMIN role can change document visibility', async ({ page }) => {
const team = await seedTeam({
createTeamOptions: {
teamGlobalSettings: {
create: {
documentVisibility: DocumentVisibility.MANAGER_AND_ABOVE,
},
},
},
});
const { team, owner } = await seedTeam();
const adminUser = await seedTeamMember({
teamId: team.id,
role: TeamMemberRole.ADMIN,
});
const document = await seedBlankDocument(adminUser, {
const document = await seedBlankDocument(adminUser, team.id, {
createDocumentOptions: {
teamId: team.id,
visibility: team.teamGlobalSettings?.documentVisibility,
visibility: DocumentVisibility.MANAGER_AND_ABOVE,
},
});
@ -763,25 +765,16 @@ test('[TEAMS]: check that ADMIN role can change document visibility', async ({ p
test('[TEAMS]: check that MEMBER role cannot change visibility of EVERYONE documents', async ({
page,
}) => {
const team = await seedTeam({
createTeamOptions: {
teamGlobalSettings: {
create: {
documentVisibility: DocumentVisibility.EVERYONE,
},
},
},
});
const { team, owner } = await seedTeam();
const teamMember = await seedTeamMember({
teamId: team.id,
role: TeamMemberRole.MEMBER,
});
const document = await seedBlankDocument(teamMember, {
const document = await seedBlankDocument(teamMember, team.id, {
createDocumentOptions: {
teamId: team.id,
visibility: team.teamGlobalSettings?.documentVisibility,
visibility: DocumentVisibility.EVERYONE,
},
});
@ -798,25 +791,16 @@ test('[TEAMS]: check that MEMBER role cannot change visibility of EVERYONE docum
test('[TEAMS]: check that MEMBER role cannot change visibility of MANAGER_AND_ABOVE documents', async ({
page,
}) => {
const team = await seedTeam({
createTeamOptions: {
teamGlobalSettings: {
create: {
documentVisibility: DocumentVisibility.MANAGER_AND_ABOVE,
},
},
},
});
const { team, owner } = await seedTeam();
const teamMember = await seedTeamMember({
teamId: team.id,
role: TeamMemberRole.MEMBER,
});
const document = await seedBlankDocument(teamMember, {
const document = await seedBlankDocument(teamMember, team.id, {
createDocumentOptions: {
teamId: team.id,
visibility: team.teamGlobalSettings?.documentVisibility,
visibility: DocumentVisibility.MANAGER_AND_ABOVE,
},
});
@ -833,25 +817,16 @@ test('[TEAMS]: check that MEMBER role cannot change visibility of MANAGER_AND_AB
test('[TEAMS]: check that MEMBER role cannot change visibility of ADMIN documents', async ({
page,
}) => {
const team = await seedTeam({
createTeamOptions: {
teamGlobalSettings: {
create: {
documentVisibility: DocumentVisibility.ADMIN,
},
},
},
});
const { team, owner } = await seedTeam();
const teamMember = await seedTeamMember({
teamId: team.id,
role: TeamMemberRole.MEMBER,
});
const document = await seedBlankDocument(teamMember, {
const document = await seedBlankDocument(teamMember, team.id, {
createDocumentOptions: {
teamId: team.id,
visibility: team.teamGlobalSettings?.documentVisibility,
visibility: DocumentVisibility.ADMIN,
},
});
@ -868,25 +843,16 @@ test('[TEAMS]: check that MEMBER role cannot change visibility of ADMIN document
test('[TEAMS]: check that MANAGER role cannot change visibility of ADMIN documents', async ({
page,
}) => {
const team = await seedTeam({
createTeamOptions: {
teamGlobalSettings: {
create: {
documentVisibility: DocumentVisibility.ADMIN,
},
},
},
});
const { team, owner } = await seedTeam();
const teamManager = await seedTeamMember({
teamId: team.id,
role: TeamMemberRole.MANAGER,
});
const document = await seedBlankDocument(teamManager, {
const document = await seedBlankDocument(teamManager, team.id, {
createDocumentOptions: {
teamId: team.id,
visibility: team.teamGlobalSettings?.documentVisibility,
visibility: DocumentVisibility.ADMIN,
},
});
@ -902,17 +868,25 @@ test('[TEAMS]: check that MANAGER role cannot change visibility of ADMIN documen
test('[TEAMS]: users cannot see documents from other teams', async ({ page }) => {
// Seed two teams with documents
const { team: teamA, teamMember2: teamAMember } = await seedTeamDocuments();
const { team: teamB, teamMember2: teamBMember } = await seedTeamDocuments();
const {
team: teamA,
teamOwner: teamAOwner,
teamMember2: teamAMember,
} = await seedTeamDocuments();
const {
team: teamB,
teamOwner: teamBOwner,
teamMember2: teamBMember,
} = await seedTeamDocuments();
// Seed a document in team B
await seedDocuments([
{
sender: teamB.owner,
sender: teamBOwner,
recipients: [],
type: DocumentStatus.COMPLETED,
teamId: teamB.id,
documentOptions: {
teamId: teamB.id,
visibility: 'EVERYONE',
title: 'Team B Document',
},
@ -934,8 +908,8 @@ test('[TEAMS]: users cannot see documents from other teams', async ({ page }) =>
test('[TEAMS]: personal documents are not visible in team context', async ({ page }) => {
// Seed a team and a user with personal documents
const { team, teamMember2 } = await seedTeamDocuments();
const personalUser = await seedUser();
const { team, teamOwner, teamMember2 } = await seedTeamDocuments();
const { user: personalUser, team: personalUserTeam } = await seedUser();
// Seed a personal document for teamMember2
await seedDocuments([
@ -943,8 +917,8 @@ test('[TEAMS]: personal documents are not visible in team context', async ({ pag
sender: teamMember2,
recipients: [],
type: DocumentStatus.COMPLETED,
teamId: personalUserTeam.id,
documentOptions: {
teamId: null, // Indicates a personal document
visibility: 'EVERYONE',
title: 'Personal Document',
},
@ -965,34 +939,3 @@ test('[TEAMS]: personal documents are not visible in team context', async ({ pag
await apiSignout({ page });
});
test('[PERSONAL]: team documents are not visible in personal account', async ({ page }) => {
// Seed a team and a user with personal documents
const { team, teamMember2 } = await seedTeamDocuments();
// Seed a team document
await seedDocuments([
{
sender: teamMember2,
recipients: [],
type: DocumentStatus.COMPLETED,
documentOptions: {
teamId: team.id,
visibility: 'EVERYONE',
title: 'Team Document',
},
},
]);
// Sign in as teamMember2 in the personal context
await apiSignin({
page,
email: teamMember2.email,
redirectPath: `/documents?status=COMPLETED`,
});
// Verify that the team document is not visible in the personal context
await expect(page.getByRole('link', { name: 'Team Document', exact: true })).not.toBeVisible();
await apiSignout({ page });
});