mirror of
https://github.com/documenso/documenso.git
synced 2026-07-26 01:45:08 +10:00
Merge branch 'main' into feat/public-completed-document-access
This commit is contained in:
@@ -13,6 +13,10 @@ const prisma = remember(
|
||||
() =>
|
||||
new PrismaClient({
|
||||
datasourceUrl: getDatabaseUrl(),
|
||||
transactionOptions: {
|
||||
maxWait: 5000,
|
||||
timeout: 10000,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
-- AlterEnum
|
||||
-- This migration adds more than one value to an enum.
|
||||
-- With PostgreSQL versions 11 and earlier, this is not possible
|
||||
-- in a single migration. This can be worked around by creating
|
||||
-- multiple migrations, each migration adding only one value to
|
||||
-- the enum.
|
||||
|
||||
|
||||
ALTER TYPE "WebhookTriggerEvents" ADD VALUE 'DOCUMENT_RECIPIENT_COMPLETED';
|
||||
ALTER TYPE "WebhookTriggerEvents" ADD VALUE 'DOCUMENT_REMINDER_SENT';
|
||||
ALTER TYPE "WebhookTriggerEvents" ADD VALUE 'TEMPLATE_CREATED';
|
||||
ALTER TYPE "WebhookTriggerEvents" ADD VALUE 'TEMPLATE_UPDATED';
|
||||
ALTER TYPE "WebhookTriggerEvents" ADD VALUE 'TEMPLATE_DELETED';
|
||||
ALTER TYPE "WebhookTriggerEvents" ADD VALUE 'TEMPLATE_USED';
|
||||
@@ -0,0 +1,17 @@
|
||||
-- CreateExtension
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX IF NOT EXISTS "Recipient_email_documentDeletedAt_envelopeId_idx" ON "Recipient"("email", "documentDeletedAt", "envelopeId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX IF NOT EXISTS "Recipient_email_envelopeId_idx" ON "Recipient"("email", "envelopeId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX IF NOT EXISTS "Recipient_email_signingStatus_envelopeId_role_idx" ON "Recipient"("email", "signingStatus", "envelopeId", "role");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX IF NOT EXISTS "Recipient_email_trgm_idx" ON "Recipient" USING GIN ("email" gin_trgm_ops);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX IF NOT EXISTS "Recipient_name_trgm_idx" ON "Recipient" USING GIN ("name" gin_trgm_ops);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TYPE "TemplateType" ADD VALUE 'ORGANISATION';
|
||||
@@ -0,0 +1,16 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "DocumentMeta" ADD COLUMN "reminderSettings" JSONB;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "OrganisationGlobalSettings" ADD COLUMN "reminderSettings" JSONB;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "TeamGlobalSettings" ADD COLUMN "reminderSettings" JSONB;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Recipient" ADD COLUMN "sentAt" TIMESTAMP(3),
|
||||
ADD COLUMN "lastReminderSentAt" TIMESTAMP(3),
|
||||
ADD COLUMN "nextReminderAt" TIMESTAMP(3);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Recipient_nextReminderAt_idx" ON "Recipient"("nextReminderAt");
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "DocumentAuditLog" DROP CONSTRAINT "DocumentAuditLog_envelopeId_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "DocumentAuditLog" ALTER COLUMN "envelopeId" DROP NOT NULL;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "DocumentAuditLog" ADD CONSTRAINT "DocumentAuditLog_envelopeId_fkey" FOREIGN KEY ("envelopeId") REFERENCES "Envelope"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.19.0",
|
||||
"kysely": "0.28.8",
|
||||
"kysely": "0.28.16",
|
||||
"nanoid": "^5.1.6",
|
||||
"prisma": "^6.19.0",
|
||||
"prisma-extension-kysely": "^3.0.0",
|
||||
|
||||
@@ -173,6 +173,12 @@ enum WebhookTriggerEvents {
|
||||
DOCUMENT_REJECTED
|
||||
DOCUMENT_CANCELLED
|
||||
RECIPIENT_EXPIRED
|
||||
DOCUMENT_RECIPIENT_COMPLETED
|
||||
DOCUMENT_REMINDER_SENT
|
||||
TEMPLATE_CREATED
|
||||
TEMPLATE_UPDATED
|
||||
TEMPLATE_DELETED
|
||||
TEMPLATE_USED
|
||||
}
|
||||
|
||||
model Webhook {
|
||||
@@ -461,7 +467,7 @@ model EnvelopeItem {
|
||||
|
||||
model DocumentAuditLog {
|
||||
id String @id @default(cuid())
|
||||
envelopeId String
|
||||
envelopeId String?
|
||||
createdAt DateTime @default(now())
|
||||
type String
|
||||
data Json
|
||||
@@ -473,7 +479,7 @@ model DocumentAuditLog {
|
||||
userAgent String?
|
||||
ipAddress String?
|
||||
|
||||
envelope Envelope @relation(fields: [envelopeId], references: [id], onDelete: Cascade)
|
||||
envelope Envelope? @relation(fields: [envelopeId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@index([envelopeId])
|
||||
}
|
||||
@@ -502,7 +508,7 @@ enum DocumentDistributionMethod {
|
||||
NONE
|
||||
}
|
||||
|
||||
/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';", "import { ZEnvelopeExpirationPeriod as ZEnvelopeExpirationPeriodSchema } from '@documenso/lib/constants/envelope-expiration';"])
|
||||
/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';", "import { ZEnvelopeExpirationPeriod as ZEnvelopeExpirationPeriodSchema } from '@documenso/lib/constants/envelope-expiration';", "import { ZEnvelopeReminderSettings as ZEnvelopeReminderSettingsSchema } from '@documenso/lib/constants/envelope-reminder';"])
|
||||
model DocumentMeta {
|
||||
id String @id @default(cuid())
|
||||
subject String?
|
||||
@@ -526,6 +532,8 @@ model DocumentMeta {
|
||||
|
||||
envelopeExpirationPeriod Json? /// [EnvelopeExpirationPeriod] @zod.custom.use(ZEnvelopeExpirationPeriodSchema)
|
||||
|
||||
reminderSettings Json? /// [EnvelopeReminderSettings] @zod.custom.use(ZEnvelopeReminderSettingsSchema)
|
||||
|
||||
envelope Envelope?
|
||||
}
|
||||
|
||||
@@ -582,7 +590,10 @@ model Recipient {
|
||||
expired DateTime? // deprecated Not in use. To be removed in a future migration.
|
||||
expiresAt DateTime?
|
||||
expirationNotifiedAt DateTime?
|
||||
sentAt DateTime?
|
||||
signedAt DateTime?
|
||||
lastReminderSentAt DateTime?
|
||||
nextReminderAt DateTime?
|
||||
authOptions Json? /// [RecipientAuthOptions] @zod.custom.use(ZRecipientAuthOptionsSchema)
|
||||
signingOrder Int? /// @zod.number.describe("The order in which the recipient should sign the document. Only works if the document is set to sequential signing.")
|
||||
rejectionReason String?
|
||||
@@ -599,6 +610,12 @@ model Recipient {
|
||||
@@index([envelopeId])
|
||||
@@index([signedAt])
|
||||
@@index([expiresAt])
|
||||
@@index([email, documentDeletedAt, envelopeId], map: "Recipient_email_documentDeletedAt_envelopeId_idx")
|
||||
@@index([email, envelopeId], map: "Recipient_email_envelopeId_idx")
|
||||
@@index([email, signingStatus, envelopeId, role], map: "Recipient_email_signingStatus_envelopeId_role_idx")
|
||||
@@index([nextReminderAt])
|
||||
@@index([email(ops: raw("gin_trgm_ops"))], map: "Recipient_email_trgm_idx", type: Gin)
|
||||
@@index([name(ops: raw("gin_trgm_ops"))], map: "Recipient_name_trgm_idx", type: Gin)
|
||||
}
|
||||
|
||||
enum FieldType {
|
||||
@@ -815,7 +832,7 @@ enum OrganisationMemberInviteStatus {
|
||||
DECLINED
|
||||
}
|
||||
|
||||
/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';", "import { ZDefaultRecipientsSchema } from '@documenso/lib/types/default-recipients';", "import { ZEnvelopeExpirationPeriod as ZEnvelopeExpirationPeriodSchema } from '@documenso/lib/constants/envelope-expiration';"])
|
||||
/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';", "import { ZDefaultRecipientsSchema } from '@documenso/lib/types/default-recipients';", "import { ZEnvelopeExpirationPeriod as ZEnvelopeExpirationPeriodSchema } from '@documenso/lib/constants/envelope-expiration';", "import { ZEnvelopeReminderSettings as ZEnvelopeReminderSettingsSchema } from '@documenso/lib/constants/envelope-reminder';"])
|
||||
model OrganisationGlobalSettings {
|
||||
id String @id
|
||||
organisation Organisation?
|
||||
@@ -850,11 +867,13 @@ model OrganisationGlobalSettings {
|
||||
|
||||
envelopeExpirationPeriod Json? /// [EnvelopeExpirationPeriod] @zod.custom.use(ZEnvelopeExpirationPeriodSchema)
|
||||
|
||||
reminderSettings Json? /// [EnvelopeReminderSettings] @zod.custom.use(ZEnvelopeReminderSettingsSchema)
|
||||
|
||||
// AI features settings.
|
||||
aiFeaturesEnabled Boolean @default(false)
|
||||
}
|
||||
|
||||
/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';", "import { ZDefaultRecipientsSchema } from '@documenso/lib/types/default-recipients';", "import { ZEnvelopeExpirationPeriod as ZEnvelopeExpirationPeriodSchema } from '@documenso/lib/constants/envelope-expiration';"])
|
||||
/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';", "import { ZDefaultRecipientsSchema } from '@documenso/lib/types/default-recipients';", "import { ZEnvelopeExpirationPeriod as ZEnvelopeExpirationPeriodSchema } from '@documenso/lib/constants/envelope-expiration';", "import { ZEnvelopeReminderSettings as ZEnvelopeReminderSettingsSchema } from '@documenso/lib/constants/envelope-reminder';"])
|
||||
model TeamGlobalSettings {
|
||||
id String @id
|
||||
team Team?
|
||||
@@ -890,6 +909,8 @@ model TeamGlobalSettings {
|
||||
|
||||
envelopeExpirationPeriod Json? /// [EnvelopeExpirationPeriod] @zod.custom.use(ZEnvelopeExpirationPeriodSchema)
|
||||
|
||||
reminderSettings Json? /// [EnvelopeReminderSettings] @zod.custom.use(ZEnvelopeReminderSettingsSchema)
|
||||
|
||||
// AI features settings.
|
||||
aiFeaturesEnabled Boolean?
|
||||
}
|
||||
@@ -946,6 +967,7 @@ model TeamEmailVerification {
|
||||
enum TemplateType {
|
||||
PUBLIC
|
||||
PRIVATE
|
||||
ORGANISATION
|
||||
}
|
||||
|
||||
model TemplateDirectLink {
|
||||
|
||||
@@ -6,6 +6,18 @@ import { match } from 'ts-pattern';
|
||||
|
||||
import { createEnvelope } from '@documenso/lib/server-only/envelope/create-envelope';
|
||||
import { incrementDocumentId } from '@documenso/lib/server-only/envelope/increment-id';
|
||||
import {
|
||||
FIELD_CHECKBOX_META_DEFAULT_VALUES,
|
||||
FIELD_DATE_META_DEFAULT_VALUES,
|
||||
FIELD_DROPDOWN_META_DEFAULT_VALUES,
|
||||
FIELD_EMAIL_META_DEFAULT_VALUES,
|
||||
FIELD_INITIALS_META_DEFAULT_VALUES,
|
||||
FIELD_NAME_META_DEFAULT_VALUES,
|
||||
FIELD_NUMBER_META_DEFAULT_VALUES,
|
||||
FIELD_RADIO_META_DEFAULT_VALUES,
|
||||
FIELD_SIGNATURE_META_DEFAULT_VALUES,
|
||||
FIELD_TEXT_META_DEFAULT_VALUES,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import { prefixedId } from '@documenso/lib/universal/id';
|
||||
|
||||
import { prisma } from '..';
|
||||
@@ -576,6 +588,19 @@ export const seedPendingDocumentWithFullFields = async ({
|
||||
height: new Prisma.Decimal(5),
|
||||
envelopeId: document.id,
|
||||
envelopeItemId: firstItem.id,
|
||||
fieldMeta: match(fieldType)
|
||||
.with(FieldType.DATE, () => FIELD_DATE_META_DEFAULT_VALUES)
|
||||
.with(FieldType.EMAIL, () => FIELD_EMAIL_META_DEFAULT_VALUES)
|
||||
.with(FieldType.NAME, () => FIELD_NAME_META_DEFAULT_VALUES)
|
||||
.with(FieldType.SIGNATURE, () => FIELD_SIGNATURE_META_DEFAULT_VALUES)
|
||||
.with(FieldType.TEXT, () => FIELD_TEXT_META_DEFAULT_VALUES)
|
||||
.with(FieldType.NUMBER, () => FIELD_NUMBER_META_DEFAULT_VALUES)
|
||||
.with(FieldType.CHECKBOX, () => FIELD_CHECKBOX_META_DEFAULT_VALUES)
|
||||
.with(FieldType.RADIO, () => FIELD_RADIO_META_DEFAULT_VALUES)
|
||||
.with(FieldType.DROPDOWN, () => FIELD_DROPDOWN_META_DEFAULT_VALUES)
|
||||
.with(FieldType.INITIALS, () => FIELD_INITIALS_META_DEFAULT_VALUES)
|
||||
.with(FieldType.FREE_SIGNATURE, () => undefined)
|
||||
.exhaustive(),
|
||||
})),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
import { prisma } from '..';
|
||||
import { DocumentStatus } from '../client';
|
||||
import { seedBlankDocument } from './documents';
|
||||
import { seedUser } from './users';
|
||||
|
||||
const MEDIUM_ACCOUNT_EMAIL = 'medium-account@documenso.com';
|
||||
const DOCUMENT_COUNT = 1000;
|
||||
|
||||
const STATUSES = [DocumentStatus.DRAFT, DocumentStatus.PENDING, DocumentStatus.COMPLETED];
|
||||
|
||||
export const seedDatabase = async () => {
|
||||
const existingUser = await prisma.user.findFirst({
|
||||
where: {
|
||||
email: MEDIUM_ACCOUNT_EMAIL,
|
||||
},
|
||||
});
|
||||
|
||||
if (existingUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[SEEDING]: Creating medium account with ${DOCUMENT_COUNT} documents...`);
|
||||
|
||||
const { user, team } = await seedUser({
|
||||
name: 'Medium Account',
|
||||
email: MEDIUM_ACCOUNT_EMAIL,
|
||||
});
|
||||
|
||||
const recipientEmails = Array.from({ length: 20 }, (_, i) => `recipient-${i}@test.documenso.com`);
|
||||
|
||||
for (let i = 0; i < DOCUMENT_COUNT; i++) {
|
||||
const status = STATUSES[i % STATUSES.length];
|
||||
|
||||
const document = await seedBlankDocument(user, team.id, {
|
||||
key: `medium-${i}`,
|
||||
createDocumentOptions: {
|
||||
title: `[MEDIUM] Document ${i} - ${status}`,
|
||||
status,
|
||||
},
|
||||
});
|
||||
|
||||
// Add 1-3 recipients per document.
|
||||
const recipientCount = (i % 3) + 1;
|
||||
|
||||
for (let r = 0; r < recipientCount; r++) {
|
||||
await prisma.recipient.create({
|
||||
data: {
|
||||
email: recipientEmails[(i + r) % recipientEmails.length],
|
||||
name: `Recipient ${r}`,
|
||||
token: nanoid(),
|
||||
envelopeId: document.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Also create some documents where the medium user is a recipient (not owner).
|
||||
// Every 5th document, create an extra doc owned by a "ghost" sender with medium user as recipient.
|
||||
if (i % 5 === 0) {
|
||||
await prisma.recipient.create({
|
||||
data: {
|
||||
email: MEDIUM_ACCOUNT_EMAIL,
|
||||
name: 'Medium Account',
|
||||
token: nanoid(),
|
||||
envelopeId: document.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (i % 100 === 0) {
|
||||
console.log(`[SEEDING]: Created ${i}/${DOCUMENT_COUNT} documents...`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[SEEDING]: Medium account seeded with ${DOCUMENT_COUNT} documents.`);
|
||||
};
|
||||
Reference in New Issue
Block a user