mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 08:13:56 +10:00
feat: add email domains (#1895)
Implemented Email Domains which allows Platform/Enterprise customers to send emails to recipients using their custom emails.
This commit is contained in:
@ -205,12 +205,18 @@ export const diffDocumentMetaChanges = (
|
||||
const oldTimezone = oldData?.timezone ?? '';
|
||||
const oldPassword = oldData?.password ?? null;
|
||||
const oldRedirectUrl = oldData?.redirectUrl ?? '';
|
||||
const oldEmailId = oldData?.emailId || null;
|
||||
const oldEmailReplyTo = oldData?.emailReplyTo || null;
|
||||
const oldEmailSettings = oldData?.emailSettings || null;
|
||||
|
||||
const newDateFormat = newData?.dateFormat ?? '';
|
||||
const newMessage = newData?.message ?? '';
|
||||
const newSubject = newData?.subject ?? '';
|
||||
const newTimezone = newData?.timezone ?? '';
|
||||
const newRedirectUrl = newData?.redirectUrl ?? '';
|
||||
const newEmailId = newData?.emailId || null;
|
||||
const newEmailReplyTo = newData?.emailReplyTo || null;
|
||||
const newEmailSettings = newData?.emailSettings || null;
|
||||
|
||||
if (oldDateFormat !== newDateFormat) {
|
||||
diffs.push({
|
||||
@ -258,6 +264,30 @@ export const diffDocumentMetaChanges = (
|
||||
});
|
||||
}
|
||||
|
||||
if (oldEmailId !== newEmailId) {
|
||||
diffs.push({
|
||||
type: DOCUMENT_META_DIFF_TYPE.EMAIL_ID,
|
||||
from: oldEmailId,
|
||||
to: newEmailId,
|
||||
});
|
||||
}
|
||||
|
||||
if (oldEmailReplyTo !== newEmailReplyTo) {
|
||||
diffs.push({
|
||||
type: DOCUMENT_META_DIFF_TYPE.EMAIL_REPLY_TO,
|
||||
from: oldEmailReplyTo,
|
||||
to: newEmailReplyTo,
|
||||
});
|
||||
}
|
||||
|
||||
if (!isDeepEqual(oldEmailSettings, newEmailSettings)) {
|
||||
diffs.push({
|
||||
type: DOCUMENT_META_DIFF_TYPE.EMAIL_SETTINGS,
|
||||
from: JSON.stringify(oldEmailSettings),
|
||||
to: JSON.stringify(newEmailSettings),
|
||||
});
|
||||
}
|
||||
|
||||
return diffs;
|
||||
};
|
||||
|
||||
|
||||
@ -1,8 +1,62 @@
|
||||
import type { Document } from '@prisma/client';
|
||||
import { DocumentStatus } from '@prisma/client';
|
||||
import type {
|
||||
Document,
|
||||
DocumentMeta,
|
||||
OrganisationGlobalSettings,
|
||||
TemplateMeta,
|
||||
} from '@prisma/client';
|
||||
import { DocumentDistributionMethod, DocumentSigningOrder, DocumentStatus } from '@prisma/client';
|
||||
|
||||
import { DEFAULT_DOCUMENT_TIME_ZONE } from '../constants/time-zones';
|
||||
import { DEFAULT_DOCUMENT_EMAIL_SETTINGS } from '../types/document-email';
|
||||
|
||||
export const isDocumentCompleted = (document: Pick<Document, 'status'> | DocumentStatus) => {
|
||||
const status = typeof document === 'string' ? document : document.status;
|
||||
|
||||
return status === DocumentStatus.COMPLETED || status === DocumentStatus.REJECTED;
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts the derived document meta which should be used when creating a document
|
||||
* from scratch, or from a template.
|
||||
*
|
||||
* Uses the following, the lower number overrides the higher number:
|
||||
* 1. Merged organisation/team settings
|
||||
* 2. Meta overrides
|
||||
*
|
||||
* @param settings - The merged organisation/team settings.
|
||||
* @param overrideMeta - The meta to override the settings with.
|
||||
* @returns The derived document meta.
|
||||
*/
|
||||
export const extractDerivedDocumentMeta = (
|
||||
settings: Omit<OrganisationGlobalSettings, 'id'>,
|
||||
overrideMeta: Partial<DocumentMeta | TemplateMeta> | undefined | null,
|
||||
) => {
|
||||
const meta = overrideMeta ?? {};
|
||||
|
||||
// Note: If you update this you will also need to update `create-document-from-template.ts`
|
||||
// since there is custom work there which allows 3 overrides.
|
||||
return {
|
||||
language: meta.language || settings.documentLanguage,
|
||||
timezone: meta.timezone || settings.documentTimezone || DEFAULT_DOCUMENT_TIME_ZONE,
|
||||
dateFormat: meta.dateFormat || settings.documentDateFormat,
|
||||
message: meta.message || null,
|
||||
subject: meta.subject || null,
|
||||
password: meta.password || null,
|
||||
redirectUrl: meta.redirectUrl || null,
|
||||
|
||||
signingOrder: meta.signingOrder || DocumentSigningOrder.PARALLEL,
|
||||
allowDictateNextSigner: meta.allowDictateNextSigner ?? false,
|
||||
distributionMethod: meta.distributionMethod || DocumentDistributionMethod.EMAIL, // Todo: Make this a setting.
|
||||
|
||||
// Signature settings.
|
||||
typedSignatureEnabled: meta.typedSignatureEnabled ?? settings.typedSignatureEnabled,
|
||||
uploadSignatureEnabled: meta.uploadSignatureEnabled ?? settings.uploadSignatureEnabled,
|
||||
drawSignatureEnabled: meta.drawSignatureEnabled ?? settings.drawSignatureEnabled,
|
||||
|
||||
// Email settings.
|
||||
emailId: meta.emailId ?? settings.emailId,
|
||||
emailReplyTo: meta.emailReplyTo ?? settings.emailReplyTo,
|
||||
emailSettings:
|
||||
meta.emailSettings || settings.emailDocumentSettings || DEFAULT_DOCUMENT_EMAIL_SETTINGS,
|
||||
} satisfies Omit<DocumentMeta, 'id' | 'documentId'>;
|
||||
};
|
||||
|
||||
17
packages/lib/utils/email-domains.ts
Normal file
17
packages/lib/utils/email-domains.ts
Normal file
@ -0,0 +1,17 @@
|
||||
export const generateDkimRecord = (recordName: string, publicKeyFlattened: string) => {
|
||||
return {
|
||||
name: recordName,
|
||||
value: `v=DKIM1; k=rsa; p=${publicKeyFlattened}`,
|
||||
type: 'TXT',
|
||||
};
|
||||
};
|
||||
|
||||
export const AWS_SES_SPF_RECORD = {
|
||||
name: `@`,
|
||||
value: 'v=spf1 include:amazonses.com -all',
|
||||
type: 'TXT',
|
||||
};
|
||||
|
||||
export const generateEmailDomainRecords = (recordName: string, publicKeyFlattened: string) => {
|
||||
return [generateDkimRecord(recordName, publicKeyFlattened), AWS_SES_SPF_RECORD];
|
||||
};
|
||||
@ -7,11 +7,13 @@ import {
|
||||
|
||||
import type { ORGANISATION_MEMBER_ROLE_MAP } from '@documenso/lib/constants/organisations-translations';
|
||||
|
||||
import { DEFAULT_DOCUMENT_DATE_FORMAT } from '../constants/date-formats';
|
||||
import {
|
||||
LOWEST_ORGANISATION_ROLE,
|
||||
ORGANISATION_MEMBER_ROLE_HIERARCHY,
|
||||
ORGANISATION_MEMBER_ROLE_PERMISSIONS_MAP,
|
||||
} from '../constants/organisations';
|
||||
import { DEFAULT_DOCUMENT_EMAIL_SETTINGS } from '../types/document-email';
|
||||
|
||||
export const isPersonalLayout = (organisations: Pick<Organisation, 'type'>[]) => {
|
||||
return organisations.length === 1 && organisations[0].type === 'PERSONAL';
|
||||
@ -113,6 +115,9 @@ export const generateDefaultOrganisationSettings = (): Omit<
|
||||
return {
|
||||
documentVisibility: DocumentVisibility.EVERYONE,
|
||||
documentLanguage: 'en',
|
||||
documentTimezone: null, // Null means local timezone.
|
||||
documentDateFormat: DEFAULT_DOCUMENT_DATE_FORMAT,
|
||||
|
||||
includeSenderDetails: true,
|
||||
includeSigningCertificate: true,
|
||||
|
||||
@ -124,5 +129,10 @@ export const generateDefaultOrganisationSettings = (): Omit<
|
||||
brandingLogo: '',
|
||||
brandingUrl: '',
|
||||
brandingCompanyDetails: '',
|
||||
|
||||
emailId: null,
|
||||
emailReplyTo: null,
|
||||
// emailReplyToName: null,
|
||||
emailDocumentSettings: DEFAULT_DOCUMENT_EMAIL_SETTINGS,
|
||||
};
|
||||
};
|
||||
|
||||
@ -165,6 +165,9 @@ export const generateDefaultTeamSettings = (): Omit<TeamGlobalSettings, 'id' | '
|
||||
return {
|
||||
documentVisibility: null,
|
||||
documentLanguage: null,
|
||||
documentTimezone: null,
|
||||
documentDateFormat: null,
|
||||
|
||||
includeSenderDetails: null,
|
||||
includeSigningCertificate: null,
|
||||
|
||||
@ -176,6 +179,11 @@ export const generateDefaultTeamSettings = (): Omit<TeamGlobalSettings, 'id' | '
|
||||
brandingLogo: null,
|
||||
brandingUrl: null,
|
||||
brandingCompanyDetails: null,
|
||||
|
||||
emailDocumentSettings: null,
|
||||
emailId: null,
|
||||
emailReplyTo: null,
|
||||
// emailReplyToName: null,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user