documenso/packages/lib/server-only/document/update-document.ts

249 lines
7.5 KiB
TypeScript
Raw Normal View History

2025-01-02 04:33:37 +00:00
import { DocumentVisibility } from '@prisma/client';
import { DocumentStatus, TeamMemberRole } from '@prisma/client';
import { isDeepEqual } from 'remeda';
import { match } from 'ts-pattern';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
import type { CreateDocumentAuditLogDataResponse } from '@documenso/lib/utils/document-audit-logs';
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
import { prisma } from '@documenso/prisma';
import { AppError, AppErrorCode } from '../../errors/app-error';
import type { TDocumentAccessAuthTypes, TDocumentActionAuthTypes } from '../../types/document-auth';
import { createDocumentAuthOptions, extractDocumentAuthMethods } from '../../utils/document-auth';
2025-06-10 01:49:52 +00:00
import { getDocumentWhereInput } from './get-document-by-id';
export type UpdateDocumentOptions = {
userId: number;
2025-06-10 01:49:52 +00:00
teamId: number;
documentId: number;
data?: {
title?: string;
externalId?: string | null;
visibility?: DocumentVisibility | null;
globalAccessAuth?: TDocumentAccessAuthTypes[];
globalActionAuth?: TDocumentActionAuthTypes[];
fix: rework fields (#1697) Rework: - Field styling to improve visibility - Field insertions, better alignment, centering and overflows ## Changes General changes: - Set default text alignment to left if no meta found - Reduce borders and rings around fields to allow smaller fields - Removed lots of redundant duplicated code surrounding field rendering - Make fields more consistent across viewing, editing and signing - Add more transparency to fields to allow users to see under fields - No more optional/required/etc colors when signing, required fields will be highlighted as orange when form is "validating" Highlighted internal changes: - Utilize native PDF fields to insert text, instead of drawing text - Change font auto scaling to only apply to when the height overflows AND no custom font is set ⚠️ Multiline changes: Multi line is enabled for a field under these conditions 1. Field content exceeds field width 2. Field includes a new line 3. Field type is TEXT ## [BEFORE] Field UI Signing ![image](https://github.com/user-attachments/assets/ea002743-faeb-477c-a239-3ed240b54f55) ## [AFTER] Field UI Signing ![image](https://github.com/user-attachments/assets/0f8eb252-4cf3-4d96-8d4f-cd085881b78c) ## [BEFORE] Signing a checkbox ![image](https://github.com/user-attachments/assets/4567d745-e1da-4202-a758-5d3c178c930e) ![image](https://github.com/user-attachments/assets/c25068e7-fe80-40f5-b63a-e8a0d4b38b6c) ## [AFTER] Signing a checkbox ![image](https://github.com/user-attachments/assets/effa5e3d-385a-4c35-bc8a-405386dd27d6) ![image](https://github.com/user-attachments/assets/64be34a9-0b32-424d-9264-15361c03eca5) ## [BEFORE] What a 2nd recipient sees once someone else signed a document ![image](https://github.com/user-attachments/assets/21c21ae2-fc62-4ccc-880a-46aab012aa70) ## [AFTER] What a 2nd recipient sees once someone else signed a document ![image](https://github.com/user-attachments/assets/ae51677b-f1d5-4008-a7fd-756533166542) ## **[BEFORE]** Inserting fields ![image](https://github.com/user-attachments/assets/1a8bb8da-9a15-4deb-bc28-eb349414465c) ## **[AFTER]** Inserting fields ![image](https://github.com/user-attachments/assets/c52c5238-9836-45aa-b8a4-bc24a3462f40) ## Overflows, multilines and field alignments testing Debugging borders: - Red border = The original field placement without any modifications - Blue border = The available space to overflow ### Single line overflows and field alignments This is left aligned fields, overflow will always go to the end of the page and will not wrap ![image](https://github.com/user-attachments/assets/47003658-783e-4f9c-adbf-c4686804d98f) This is center aligned fields, the max width is the closest edge to the page * 2 ![image](https://github.com/user-attachments/assets/05a38093-75d6-4600-bae2-21ecff63e115) This is right aligned text, the width will extend all the way to the left hand side of the page ![image](https://github.com/user-attachments/assets/6a9d84a8-4166-4626-9fb3-1577fac2571e) ### Multiline line overflows and field alignments These are text fields that can be overflowed ![image](https://github.com/user-attachments/assets/f7b5456e-2c49-48b2-8d4c-ab1dc3401644) Another example of left aligned text overflows with more text ![image](https://github.com/user-attachments/assets/3db6b35e-4c8d-4ffe-8036-0da760d9c167)
2025-04-23 11:40:42 +00:00
useLegacyFieldInsertion?: boolean;
};
requestMetadata: ApiRequestMetadata;
};
2024-02-22 02:39:34 +00:00
export const updateDocument = async ({
userId,
teamId,
documentId,
2024-02-22 02:39:34 +00:00
data,
requestMetadata,
}: UpdateDocumentOptions) => {
2025-06-10 01:49:52 +00:00
const { documentWhereInput, team } = await getDocumentWhereInput({
documentId,
userId,
teamId,
});
const document = await prisma.document.findFirst({
2025-06-10 01:49:52 +00:00
where: documentWhereInput,
include: {
team: {
select: {
2025-06-10 01:49:52 +00:00
organisation: {
select: {
2025-06-10 01:49:52 +00:00
organisationClaim: true,
},
},
},
},
},
});
if (!document) {
throw new AppError(AppErrorCode.NOT_FOUND, {
message: 'Document not found',
});
}
2025-06-10 01:49:52 +00:00
const isDocumentOwner = document.userId === userId;
const requestedVisibility = data?.visibility;
2025-06-10 01:49:52 +00:00
if (!isDocumentOwner) {
match(team.currentTeamRole)
.with(TeamMemberRole.ADMIN, () => true)
.with(TeamMemberRole.MANAGER, () => {
const allowedVisibilities: DocumentVisibility[] = [
DocumentVisibility.EVERYONE,
DocumentVisibility.MANAGER_AND_ABOVE,
];
2025-06-10 01:49:52 +00:00
if (
!allowedVisibilities.includes(document.visibility) ||
(requestedVisibility && !allowedVisibilities.includes(requestedVisibility))
) {
throw new AppError(AppErrorCode.UNAUTHORIZED, {
2025-06-10 01:49:52 +00:00
message: 'You do not have permission to update the document visibility',
});
2025-06-10 01:49:52 +00:00
}
})
.with(TeamMemberRole.MEMBER, () => {
if (
document.visibility !== DocumentVisibility.EVERYONE ||
(requestedVisibility && requestedVisibility !== DocumentVisibility.EVERYONE)
) {
throw new AppError(AppErrorCode.UNAUTHORIZED, {
message: 'You do not have permission to update the document visibility',
});
}
})
.otherwise(() => {
throw new AppError(AppErrorCode.UNAUTHORIZED, {
message: 'You do not have permission to update the document',
});
2025-06-10 01:49:52 +00:00
});
}
// If no data just return the document since this function is normally chained after a meta update.
if (!data || Object.values(data).length === 0) {
return document;
}
const { documentAuthOption } = extractDocumentAuthMethods({
documentAuth: document.authOptions,
});
const documentGlobalAccessAuth = documentAuthOption?.globalAccessAuth ?? null;
const documentGlobalActionAuth = documentAuthOption?.globalActionAuth ?? null;
// If the new global auth values aren't passed in, fallback to the current document values.
const newGlobalAccessAuth =
data?.globalAccessAuth === undefined ? documentGlobalAccessAuth : data.globalAccessAuth;
const newGlobalActionAuth =
data?.globalActionAuth === undefined ? documentGlobalActionAuth : data.globalActionAuth;
// Check if user has permission to set the global action auth.
2025-06-10 01:49:52 +00:00
if (newGlobalActionAuth.length > 0 && !document.team.organisation.organisationClaim.flags.cfr21) {
throw new AppError(AppErrorCode.UNAUTHORIZED, {
message: 'You do not have permission to set the action auth',
});
}
const isTitleSame = data.title === undefined || data.title === document.title;
const isExternalIdSame = data.externalId === undefined || data.externalId === document.externalId;
const isGlobalAccessSame =
documentGlobalAccessAuth === undefined ||
isDeepEqual(documentGlobalAccessAuth, newGlobalAccessAuth);
const isGlobalActionSame =
documentGlobalActionAuth === undefined ||
isDeepEqual(documentGlobalActionAuth, newGlobalActionAuth);
const isDocumentVisibilitySame =
data.visibility === undefined || data.visibility === document.visibility;
const auditLogs: CreateDocumentAuditLogDataResponse[] = [];
if (!isTitleSame && document.status !== DocumentStatus.DRAFT) {
throw new AppError(AppErrorCode.INVALID_BODY, {
message: 'You cannot update the title if the document has been sent',
});
}
if (!isTitleSame) {
auditLogs.push(
createDocumentAuditLogData({
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_TITLE_UPDATED,
documentId,
metadata: requestMetadata,
data: {
from: document.title,
to: data.title || '',
},
}),
);
}
if (!isExternalIdSame) {
auditLogs.push(
createDocumentAuditLogData({
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_EXTERNAL_ID_UPDATED,
documentId,
metadata: requestMetadata,
data: {
from: document.externalId,
to: data.externalId || '',
},
}),
);
}
if (!isGlobalAccessSame) {
auditLogs.push(
createDocumentAuditLogData({
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_GLOBAL_AUTH_ACCESS_UPDATED,
documentId,
metadata: requestMetadata,
data: {
from: documentGlobalAccessAuth,
to: newGlobalAccessAuth,
},
}),
);
}
if (!isGlobalActionSame) {
auditLogs.push(
createDocumentAuditLogData({
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_GLOBAL_AUTH_ACTION_UPDATED,
documentId,
metadata: requestMetadata,
data: {
from: documentGlobalActionAuth,
to: newGlobalActionAuth,
},
}),
);
}
if (!isDocumentVisibilitySame) {
auditLogs.push(
createDocumentAuditLogData({
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_VISIBILITY_UPDATED,
documentId,
metadata: requestMetadata,
data: {
from: document.visibility,
to: data.visibility || '',
},
}),
);
}
// Early return if nothing is required.
fix: rework fields (#1697) Rework: - Field styling to improve visibility - Field insertions, better alignment, centering and overflows ## Changes General changes: - Set default text alignment to left if no meta found - Reduce borders and rings around fields to allow smaller fields - Removed lots of redundant duplicated code surrounding field rendering - Make fields more consistent across viewing, editing and signing - Add more transparency to fields to allow users to see under fields - No more optional/required/etc colors when signing, required fields will be highlighted as orange when form is "validating" Highlighted internal changes: - Utilize native PDF fields to insert text, instead of drawing text - Change font auto scaling to only apply to when the height overflows AND no custom font is set ⚠️ Multiline changes: Multi line is enabled for a field under these conditions 1. Field content exceeds field width 2. Field includes a new line 3. Field type is TEXT ## [BEFORE] Field UI Signing ![image](https://github.com/user-attachments/assets/ea002743-faeb-477c-a239-3ed240b54f55) ## [AFTER] Field UI Signing ![image](https://github.com/user-attachments/assets/0f8eb252-4cf3-4d96-8d4f-cd085881b78c) ## [BEFORE] Signing a checkbox ![image](https://github.com/user-attachments/assets/4567d745-e1da-4202-a758-5d3c178c930e) ![image](https://github.com/user-attachments/assets/c25068e7-fe80-40f5-b63a-e8a0d4b38b6c) ## [AFTER] Signing a checkbox ![image](https://github.com/user-attachments/assets/effa5e3d-385a-4c35-bc8a-405386dd27d6) ![image](https://github.com/user-attachments/assets/64be34a9-0b32-424d-9264-15361c03eca5) ## [BEFORE] What a 2nd recipient sees once someone else signed a document ![image](https://github.com/user-attachments/assets/21c21ae2-fc62-4ccc-880a-46aab012aa70) ## [AFTER] What a 2nd recipient sees once someone else signed a document ![image](https://github.com/user-attachments/assets/ae51677b-f1d5-4008-a7fd-756533166542) ## **[BEFORE]** Inserting fields ![image](https://github.com/user-attachments/assets/1a8bb8da-9a15-4deb-bc28-eb349414465c) ## **[AFTER]** Inserting fields ![image](https://github.com/user-attachments/assets/c52c5238-9836-45aa-b8a4-bc24a3462f40) ## Overflows, multilines and field alignments testing Debugging borders: - Red border = The original field placement without any modifications - Blue border = The available space to overflow ### Single line overflows and field alignments This is left aligned fields, overflow will always go to the end of the page and will not wrap ![image](https://github.com/user-attachments/assets/47003658-783e-4f9c-adbf-c4686804d98f) This is center aligned fields, the max width is the closest edge to the page * 2 ![image](https://github.com/user-attachments/assets/05a38093-75d6-4600-bae2-21ecff63e115) This is right aligned text, the width will extend all the way to the left hand side of the page ![image](https://github.com/user-attachments/assets/6a9d84a8-4166-4626-9fb3-1577fac2571e) ### Multiline line overflows and field alignments These are text fields that can be overflowed ![image](https://github.com/user-attachments/assets/f7b5456e-2c49-48b2-8d4c-ab1dc3401644) Another example of left aligned text overflows with more text ![image](https://github.com/user-attachments/assets/3db6b35e-4c8d-4ffe-8036-0da760d9c167)
2025-04-23 11:40:42 +00:00
if (auditLogs.length === 0 && data.useLegacyFieldInsertion === undefined) {
return document;
}
return await prisma.$transaction(async (tx) => {
const authOptions = createDocumentAuthOptions({
globalAccessAuth: newGlobalAccessAuth,
globalActionAuth: newGlobalActionAuth,
});
const updatedDocument = await tx.document.update({
where: {
id: documentId,
},
data: {
title: data.title,
externalId: data.externalId,
visibility: data.visibility as DocumentVisibility,
fix: rework fields (#1697) Rework: - Field styling to improve visibility - Field insertions, better alignment, centering and overflows ## Changes General changes: - Set default text alignment to left if no meta found - Reduce borders and rings around fields to allow smaller fields - Removed lots of redundant duplicated code surrounding field rendering - Make fields more consistent across viewing, editing and signing - Add more transparency to fields to allow users to see under fields - No more optional/required/etc colors when signing, required fields will be highlighted as orange when form is "validating" Highlighted internal changes: - Utilize native PDF fields to insert text, instead of drawing text - Change font auto scaling to only apply to when the height overflows AND no custom font is set ⚠️ Multiline changes: Multi line is enabled for a field under these conditions 1. Field content exceeds field width 2. Field includes a new line 3. Field type is TEXT ## [BEFORE] Field UI Signing ![image](https://github.com/user-attachments/assets/ea002743-faeb-477c-a239-3ed240b54f55) ## [AFTER] Field UI Signing ![image](https://github.com/user-attachments/assets/0f8eb252-4cf3-4d96-8d4f-cd085881b78c) ## [BEFORE] Signing a checkbox ![image](https://github.com/user-attachments/assets/4567d745-e1da-4202-a758-5d3c178c930e) ![image](https://github.com/user-attachments/assets/c25068e7-fe80-40f5-b63a-e8a0d4b38b6c) ## [AFTER] Signing a checkbox ![image](https://github.com/user-attachments/assets/effa5e3d-385a-4c35-bc8a-405386dd27d6) ![image](https://github.com/user-attachments/assets/64be34a9-0b32-424d-9264-15361c03eca5) ## [BEFORE] What a 2nd recipient sees once someone else signed a document ![image](https://github.com/user-attachments/assets/21c21ae2-fc62-4ccc-880a-46aab012aa70) ## [AFTER] What a 2nd recipient sees once someone else signed a document ![image](https://github.com/user-attachments/assets/ae51677b-f1d5-4008-a7fd-756533166542) ## **[BEFORE]** Inserting fields ![image](https://github.com/user-attachments/assets/1a8bb8da-9a15-4deb-bc28-eb349414465c) ## **[AFTER]** Inserting fields ![image](https://github.com/user-attachments/assets/c52c5238-9836-45aa-b8a4-bc24a3462f40) ## Overflows, multilines and field alignments testing Debugging borders: - Red border = The original field placement without any modifications - Blue border = The available space to overflow ### Single line overflows and field alignments This is left aligned fields, overflow will always go to the end of the page and will not wrap ![image](https://github.com/user-attachments/assets/47003658-783e-4f9c-adbf-c4686804d98f) This is center aligned fields, the max width is the closest edge to the page * 2 ![image](https://github.com/user-attachments/assets/05a38093-75d6-4600-bae2-21ecff63e115) This is right aligned text, the width will extend all the way to the left hand side of the page ![image](https://github.com/user-attachments/assets/6a9d84a8-4166-4626-9fb3-1577fac2571e) ### Multiline line overflows and field alignments These are text fields that can be overflowed ![image](https://github.com/user-attachments/assets/f7b5456e-2c49-48b2-8d4c-ab1dc3401644) Another example of left aligned text overflows with more text ![image](https://github.com/user-attachments/assets/3db6b35e-4c8d-4ffe-8036-0da760d9c167)
2025-04-23 11:40:42 +00:00
useLegacyFieldInsertion: data.useLegacyFieldInsertion,
authOptions,
},
});
await tx.documentAuditLog.createMany({
data: auditLogs,
});
return updatedDocument;
});
};