UNPKG

@lucidcms/core

Version:

The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.

1 lines 28.1 kB
{"version":3,"file":"create-single.mjs","names":["collectionServices.getSingleInstance","documentWorkflowServices.canPublishTarget","documentVersionServices.cloneVersion"],"sources":["../../../src/services/document-publish-operations/create-single.ts"],"sourcesContent":["import type { RichTextJSON } from \"@lucidcms/rich-text\";\nimport { getTableNames } from \"../../libs/collection/schema/runtime/runtime-schema-selectors.js\";\nimport { copy } from \"../../libs/i18n/index.js\";\nimport {\n\tDocumentPublishOperationAssigneesRepository,\n\tDocumentPublishOperationsRepository,\n\tDocumentsRepository,\n\tDocumentVersionsRepository,\n\tQueueJobsRepository,\n} from \"../../libs/repositories/index.js\";\nimport type { LucidAuth } from \"../../types/hono.js\";\nimport type { ServiceFn } from \"../../utils/services/types.js\";\nimport {\n\tcollectionServices,\n\tdocumentVersionServices,\n\tdocumentWorkflowServices,\n} from \"../index.js\";\nimport approve from \"./approve.js\";\nimport getReviewers from \"./get-reviewers.js\";\nimport createEvent from \"./helpers/create-event.js\";\nimport {\n\tactivePublishOperationStatuses,\n\tcanUsePublishOperationsForTarget,\n\tcollectionTargetSupportsScheduling,\n\tgetReleaseRequirementTargets,\n\tgetUnmetReleaseRequirementTargets,\n\thasCollectionPermission,\n\tparseScheduleInput,\n\tsnapshotVersionType,\n\tunresolvedPublishOperationExecutionStatuses,\n} from \"./helpers/index.js\";\nimport normalizeComment from \"./helpers/normalize-comment.js\";\nimport notifyPublishOperationUsers from \"./notifications.js\";\n\nconst createSingle: ServiceFn<\n\t[\n\t\t{\n\t\t\tcollectionKey: string;\n\t\t\tdocumentId: number;\n\t\t\ttarget: string;\n\t\t\tcomment?: RichTextJSON;\n\t\t\tassigneeIds?: number[];\n\t\t\tautoAccept?: boolean;\n\t\t\tscheduledAt?: string | null;\n\t\t\tscheduledTimezone?: string | null;\n\t\t\tuser: LucidAuth;\n\t\t},\n\t],\n\tundefined\n> = async (context, data) => {\n\t// Resolve collection and publish operation mode.\n\tconst collectionRes = collectionServices.getSingleInstance(context, {\n\t\tkey: data.collectionKey,\n\t});\n\tif (collectionRes.error) return collectionRes;\n\n\tconst collection = collectionRes.data;\n\tconst publishReview = collection.getData.review;\n\tconst targetIsEnvironment = collection.getData.environments.some(\n\t\t(environment) => environment.key === data.target,\n\t);\n\tconst requiresApproval = canUsePublishOperationsForTarget({\n\t\tcollection,\n\t\ttarget: data.target,\n\t});\n\tconst operationType = requiresApproval ? \"request\" : \"direct\";\n\tconst comment = normalizeComment(data.comment);\n\tconst autoAccept = data.autoAccept === true;\n\tconst approveImmediately = !requiresApproval || autoAccept;\n\tconst scheduleInput = parseScheduleInput({\n\t\tscheduledAt: data.scheduledAt,\n\t\tscheduledTimezone: data.scheduledTimezone,\n\t});\n\tif (scheduleInput.error) {\n\t\treturn {\n\t\t\terror: scheduleInput.error,\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\tconst schedule = scheduleInput.data;\n\n\t// Validate target, permissions, and comments before touching document data.\n\tif (!targetIsEnvironment) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.publish.requests.target.not.enabled\"),\n\t\t\t\tstatus: 400,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tif (\n\t\t!hasCollectionPermission({\n\t\t\tuser: data.user,\n\t\t\tcollection,\n\t\t\taction: \"publish\",\n\t\t})\n\t) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tname: copy(\"server:core.collections.permission.error.name\"),\n\t\t\t\tmessage: copy(\"server:core.collections.permission.error.message\", {\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tcollection: data.collectionKey,\n\t\t\t\t\t\taction: \"publish\",\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tstatus: 403,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tif (\n\t\tschedule?.scheduledAt &&\n\t\t!collectionTargetSupportsScheduling({\n\t\t\tcollection,\n\t\t\ttarget: data.target,\n\t\t\tqueueSupportsScheduling: context.queue.support.scheduling,\n\t\t})\n\t) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.publish.operations.schedule.not.supported\"),\n\t\t\t\tstatus: 400,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tif (\n\t\trequiresApproval &&\n\t\tpublishReview?.comments.request === \"required\" &&\n\t\t!comment.text\n\t) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.publish.requests.request.comment.required\"),\n\t\t\t\tstatus: 400,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tif (\n\t\trequiresApproval &&\n\t\tautoAccept &&\n\t\tpublishReview?.allowSelfApproval !== true\n\t) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.publish.requests.auto.accept.not.allowed\"),\n\t\t\t\tstatus: 403,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tif (\n\t\trequiresApproval &&\n\t\tautoAccept &&\n\t\t!hasCollectionPermission({\n\t\t\tuser: data.user,\n\t\t\tcollection,\n\t\t\taction: \"review\",\n\t\t})\n\t) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tname: copy(\"server:core.collections.permission.error.name\"),\n\t\t\t\tmessage: copy(\"server:core.collections.permission.error.message\", {\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tcollection: data.collectionKey,\n\t\t\t\t\t\taction: \"review\",\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tstatus: 403,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tif (\n\t\trequiresApproval &&\n\t\tautoAccept &&\n\t\tpublishReview?.comments.decision === \"required\" &&\n\t\t!comment.text\n\t) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.publish.requests.decision.comment.required\"),\n\t\t\t\tstatus: 400,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tconst workflowPublishRes = await documentWorkflowServices.canPublishTarget(\n\t\tcontext,\n\t\t{\n\t\t\tcollectionKey: data.collectionKey,\n\t\t\tdocumentId: data.documentId,\n\t\t\ttarget: data.target,\n\t\t},\n\t);\n\tif (workflowPublishRes.error) return workflowPublishRes;\n\n\t// Validate reviewer assignments only when this target requires approval.\n\tconst reviewersRes = requiresApproval\n\t\t? await getReviewers(context, {\n\t\t\t\tcollectionKey: data.collectionKey,\n\t\t\t\ttarget: data.target,\n\t\t\t})\n\t\t: undefined;\n\tif (reviewersRes?.error) return reviewersRes;\n\n\tconst reviewerMap = new Map(\n\t\t(reviewersRes?.data ?? []).map((reviewer) => [reviewer.id, reviewer]),\n\t);\n\tconst assigneeIds = Array.from(new Set(data.assigneeIds ?? []));\n\tconst invalidAssignee = requiresApproval\n\t\t? assigneeIds.find((id) => !reviewerMap.has(id))\n\t\t: undefined;\n\tif (invalidAssignee !== undefined) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.publish.requests.invalid.assignees\"),\n\t\t\t\tstatus: 400,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\t// Load repositories and current document state.\n\tconst Versions = new DocumentVersionsRepository(\n\t\tcontext.db.client,\n\t\tcontext.config.db,\n\t);\n\tconst Documents = new DocumentsRepository(\n\t\tcontext.db.client,\n\t\tcontext.config.db,\n\t);\n\tconst Operations = new DocumentPublishOperationsRepository(\n\t\tcontext.db.client,\n\t\tcontext.config.db,\n\t);\n\tconst Assignees = new DocumentPublishOperationAssigneesRepository(\n\t\tcontext.db.client,\n\t\tcontext.config.db,\n\t);\n\tconst QueueJobs = new QueueJobsRepository(\n\t\tcontext.db.client,\n\t\tcontext.config.db,\n\t);\n\n\tconst tableNamesRes = await getTableNames(context, data.collectionKey);\n\tif (tableNamesRes.error) return tableNamesRes;\n\n\tconst [documentRes, latestVersionRes, activeRes] = await Promise.all([\n\t\tDocuments.selectSingle(\n\t\t\t{\n\t\t\t\tselect: [\"id\", \"tenant_key\"],\n\t\t\t\twhere: [\n\t\t\t\t\t{ key: \"id\", operator: \"=\", value: data.documentId },\n\t\t\t\t\t{ key: \"collection_key\", operator: \"=\", value: data.collectionKey },\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: \"is_deleted\",\n\t\t\t\t\t\toperator: \"=\",\n\t\t\t\t\t\tvalue: context.config.db.getDefault(\"boolean\", \"false\"),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tvalidation: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tdefaultError: {\n\t\t\t\t\t\tmessage: copy(\"server:core.documents.not.found.message\"),\n\t\t\t\t\t\tstatus: 404,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttableName: tableNamesRes.data.document,\n\t\t\t},\n\t\t),\n\t\tVersions.selectSingle(\n\t\t\t{\n\t\t\t\tselect: [\"id\", \"content_id\"],\n\t\t\t\twhere: [\n\t\t\t\t\t{ key: \"collection_key\", operator: \"=\", value: data.collectionKey },\n\t\t\t\t\t{ key: \"document_id\", operator: \"=\", value: data.documentId },\n\t\t\t\t\t{ key: \"type\", operator: \"=\", value: \"latest\" },\n\t\t\t\t],\n\t\t\t\tvalidation: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tdefaultError: {\n\t\t\t\t\t\tmessage: copy(\"server:core.documents.version.not.found.message\"),\n\t\t\t\t\t\tstatus: 404,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttableName: tableNamesRes.data.version,\n\t\t\t},\n\t\t),\n\t\tOperations.selectSingle({\n\t\t\tselect: [\n\t\t\t\t\"id\",\n\t\t\t\t\"collection_key\",\n\t\t\t\t\"document_id\",\n\t\t\t\t\"target\",\n\t\t\t\t\"source_content_id\",\n\t\t\t\t\"scheduled_job_id\",\n\t\t\t],\n\t\t\twhere: [\n\t\t\t\t{ key: \"collection_key\", operator: \"=\", value: data.collectionKey },\n\t\t\t\t{ key: \"document_id\", operator: \"=\", value: data.documentId },\n\t\t\t\t{ key: \"target\", operator: \"=\", value: data.target },\n\t\t\t\t{\n\t\t\t\t\tkey: \"status\",\n\t\t\t\t\toperator: \"in\",\n\t\t\t\t\tvalue: activePublishOperationStatuses,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkey: \"execution_status\",\n\t\t\t\t\toperator: \"in\",\n\t\t\t\t\tvalue: unresolvedPublishOperationExecutionStatuses,\n\t\t\t\t},\n\t\t\t],\n\t\t}),\n\t]);\n\tif (documentRes.error) return documentRes;\n\tif (latestVersionRes.error) return latestVersionRes;\n\tif (activeRes.error) return activeRes;\n\n\tif (\n\t\tdocumentRes.data.tenant_key &&\n\t\tcontext.request.tenantKey &&\n\t\tdocumentRes.data.tenant_key !== context.request.tenantKey\n\t) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.documents.not.found.message\"),\n\t\t\t\tstatus: 404,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\t// Checks the target environment's required environment list and that they are in sync with latest before allowing the publish\n\tconst releaseRequirementTargets = getReleaseRequirementTargets({\n\t\tcollection,\n\t\ttarget: data.target,\n\t});\n\tif (releaseRequirementTargets.length > 0) {\n\t\tconst requirementVersionsRes = await Versions.selectMultiple(\n\t\t\t{\n\t\t\t\tselect: [\"type\", \"content_id\"],\n\t\t\t\twhere: [\n\t\t\t\t\t{ key: \"collection_key\", operator: \"=\", value: data.collectionKey },\n\t\t\t\t\t{ key: \"document_id\", operator: \"=\", value: data.documentId },\n\t\t\t\t\t{ key: \"type\", operator: \"in\", value: releaseRequirementTargets },\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\ttableName: tableNamesRes.data.version,\n\t\t\t},\n\t\t);\n\t\tif (requirementVersionsRes.error) return requirementVersionsRes;\n\n\t\tconst unmetRequirements = getUnmetReleaseRequirementTargets({\n\t\t\tcollection,\n\t\t\ttarget: data.target,\n\t\t\tsourceContentId: latestVersionRes.data.content_id,\n\t\t\tcontentIdsByTarget: new Map(\n\t\t\t\t(requirementVersionsRes.data ?? []).map((version) => [\n\t\t\t\t\tversion.type,\n\t\t\t\t\tversion.content_id,\n\t\t\t\t]),\n\t\t\t),\n\t\t});\n\n\t\tif (unmetRequirements.length > 0) {\n\t\t\treturn {\n\t\t\t\terror: {\n\t\t\t\t\ttype: \"basic\",\n\t\t\t\t\tmessage: copy(\"server:core.publish.requests.requires.not.current\", {\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\ttarget: data.target,\n\t\t\t\t\t\t\trequired: unmetRequirements.join(\", \"),\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\tstatus: 403,\n\t\t\t\t},\n\t\t\t\tdata: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Retire any unresolved operation for this document and target before creating the new release\n\tif (activeRes.data) {\n\t\tconst now = new Date().toISOString();\n\n\t\tif (activeRes.data.scheduled_job_id) {\n\t\t\tconst cancelJobRes = await QueueJobs.updateSingle({\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: \"job_id\",\n\t\t\t\t\t\toperator: \"=\",\n\t\t\t\t\t\tvalue: activeRes.data.scheduled_job_id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdata: {\n\t\t\t\t\tstatus: \"cancelled\",\n\t\t\t\t\tupdated_at: now,\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (cancelJobRes.error) return cancelJobRes;\n\t\t}\n\n\t\tconst [activeDetailedRes, supersedeRes] = await Promise.all([\n\t\t\tOperations.selectSingleDetailed({\n\t\t\t\ttenantKey: context.request.tenantKey,\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: \"lucid_document_publish_operations.id\",\n\t\t\t\t\t\toperator: \"=\",\n\t\t\t\t\t\tvalue: activeRes.data.id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t}),\n\t\t\tOperations.updateSingle({\n\t\t\t\twhere: [{ key: \"id\", operator: \"=\", value: activeRes.data.id }],\n\t\t\t\tdata: {\n\t\t\t\t\tstatus: \"superseded\",\n\t\t\t\t\texecution_status: \"cancelled\",\n\t\t\t\t\tscheduled_job_id: null,\n\t\t\t\t\tupdated_at: now,\n\t\t\t\t},\n\t\t\t}),\n\t\t]);\n\t\tif (activeDetailedRes.error) return activeDetailedRes;\n\t\tif (supersedeRes.error) return supersedeRes;\n\n\t\tconst eventRes = await createEvent(context, {\n\t\t\toperation: activeDetailedRes.data ?? activeRes.data,\n\t\t\tcollectionInstance: collection,\n\t\t\tevent: {\n\t\t\t\ttype: \"superseded\",\n\t\t\t\tuserId: data.user.id,\n\t\t\t\tcomment: comment.text,\n\t\t\t\tmetadata: {\n\t\t\t\t\tsourceContentId: latestVersionRes.data.content_id,\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\t\tif (eventRes.error) return eventRes;\n\n\t\tif (activeDetailedRes.data) {\n\t\t\tconst requestedBy = activeDetailedRes.data.requested_by;\n\t\t\tconst requesterEmail = activeDetailedRes.data.requested_by_email;\n\t\t\tconst requesterRecipients =\n\t\t\t\trequestedBy !== null &&\n\t\t\t\trequesterEmail !== undefined &&\n\t\t\t\trequesterEmail !== null &&\n\t\t\t\trequestedBy !== data.user.id\n\t\t\t\t\t? [{ id: requestedBy, email: requesterEmail }]\n\t\t\t\t\t: [];\n\t\t\tconst supersedeRecipients = [\n\t\t\t\t...activeDetailedRes.data.assignees.map((assignee) => ({\n\t\t\t\t\tid: assignee.user_id,\n\t\t\t\t\temail: assignee.email ?? null,\n\t\t\t\t})),\n\t\t\t\t...requesterRecipients,\n\t\t\t];\n\n\t\t\tconst notifySupersededRes = await notifyPublishOperationUsers(context, {\n\t\t\t\toperationId: activeDetailedRes.data.id,\n\t\t\t\tcollectionKey: activeDetailedRes.data.collection_key,\n\t\t\t\tdocumentId: activeDetailedRes.data.document_id,\n\t\t\t\trecipients: supersedeRecipients,\n\t\t\t\ttitle: copy(\"server:core.publish.requests.replaced.title\"),\n\t\t\t\tmessage: copy(\"server:core.publish.requests.replaced.message\", {\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tcollection: data.collectionKey,\n\t\t\t\t\t\tdocumentId: data.documentId,\n\t\t\t\t\t\ttarget: data.target,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tdedupeAction: \"superseded\",\n\t\t\t});\n\t\t\tif (notifySupersededRes.error) return notifySupersededRes;\n\t\t}\n\t}\n\n\t// Snapshot the submitted latest version, then create the operation record.\n\tconst snapshotRes = await documentVersionServices.cloneVersion(context, {\n\t\tfromVersionId: latestVersionRes.data.id,\n\t\ttoVersionType: snapshotVersionType,\n\t\tcollectionKey: data.collectionKey,\n\t\tdocumentId: data.documentId,\n\t\tuserId: data.user.id,\n\t});\n\tif (snapshotRes.error) return snapshotRes;\n\n\tif (snapshotRes.data.sourceVersionType !== \"latest\") {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.publish.requests.snapshot.latest.only\"),\n\t\t\t\tstatus: 400,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tconst operationRes = await Operations.createSingle({\n\t\tdata: {\n\t\t\tcollection_key: data.collectionKey,\n\t\t\ttenant_key: documentRes.data.tenant_key,\n\t\t\tdocument_id: data.documentId,\n\t\t\ttarget: data.target,\n\t\t\toperation_type: operationType,\n\t\t\tstatus: \"pending\",\n\t\t\tsource_version_id: latestVersionRes.data.id,\n\t\t\tsource_content_id: latestVersionRes.data.content_id,\n\t\t\tsnapshot_version_id: snapshotRes.data.versionId,\n\t\t\trequested_by: data.user.id,\n\t\t\trequest_comment: comment.value,\n\t\t\tscheduled_at: schedule?.scheduledAt ?? undefined,\n\t\t\tscheduled_timezone: schedule?.scheduledTimezone ?? null,\n\t\t\texecution_status: \"awaiting_approval\",\n\t\t},\n\t\treturning: [\"id\"],\n\t\tvalidation: {\n\t\t\tenabled: true,\n\t\t},\n\t});\n\tif (operationRes.error) return operationRes;\n\n\tif (requiresApproval && !autoAccept && assigneeIds.length > 0) {\n\t\tconst assigneeRes = await Assignees.createMultiple({\n\t\t\tdata: assigneeIds.map((userId) => ({\n\t\t\t\toperation_id: operationRes.data.id,\n\t\t\t\tuser_id: userId,\n\t\t\t\tassigned_by: data.user.id,\n\t\t\t})),\n\t\t});\n\t\tif (assigneeRes.error) return assigneeRes;\n\t}\n\n\tconst eventRes = await createEvent(context, {\n\t\toperation: {\n\t\t\tid: operationRes.data.id,\n\t\t\tcollection_key: data.collectionKey,\n\t\t\tdocument_id: data.documentId,\n\t\t\ttarget: data.target,\n\t\t},\n\t\tcollectionInstance: collection,\n\t\tevent: {\n\t\t\ttype: \"created\",\n\t\t\tuserId: data.user.id,\n\t\t\tcomment: comment.text,\n\t\t\tmetadata: {},\n\t\t},\n\t});\n\tif (eventRes.error) return eventRes;\n\n\t// Direct publishes and auto-accepted requests share the same approval path.\n\tif (approveImmediately) {\n\t\tconst approveRes = await approve(context, {\n\t\t\tid: operationRes.data.id,\n\t\t\tcomment: comment.value ?? undefined,\n\t\t\tuser: data.user,\n\t\t\tbypassReviewChecks: !requiresApproval,\n\t\t\tsuppressRequesterNotification: !requiresApproval,\n\t\t});\n\t\treturn approveRes;\n\t}\n\n\t// Pending requests notify assigned reviewers, then refetch in the UI.\n\tconst recipients = assigneeIds\n\t\t.map((id) => reviewerMap.get(id))\n\t\t.filter((reviewer) => reviewer !== undefined)\n\t\t.map((reviewer) => ({\n\t\t\tid: reviewer.id,\n\t\t\temail: reviewer.email,\n\t\t}));\n\n\tconst notifyRes = await notifyPublishOperationUsers(context, {\n\t\toperationId: operationRes.data.id,\n\t\tcollectionKey: data.collectionKey,\n\t\tdocumentId: data.documentId,\n\t\trecipients,\n\t\ttitle: copy(\"server:core.publish.requests.created.title\"),\n\t\tmessage: copy(\"server:core.publish.requests.created.message\", {\n\t\t\tdata: {\n\t\t\t\tuser: data.user.email,\n\t\t\t\tcollection: data.collectionKey,\n\t\t\t\tdocumentId: data.documentId,\n\t\t\t\ttarget: data.target,\n\t\t\t},\n\t\t}),\n\t\tdedupeAction: \"created\",\n\t\tcomment: {\n\t\t\tlabel: copy(\"server:core.publish.requests.email.request.comment\"),\n\t\t\tvalue: comment.text,\n\t\t\thtml: comment.html,\n\t\t},\n\t\tdetails: [\n\t\t\t{\n\t\t\t\tlabel: copy(\"server:core.publish.requests.email.detail.release\"),\n\t\t\t\tvalue: `#${operationRes.data.id}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: copy(\"server:core.publish.requests.email.detail.collection\"),\n\t\t\t\tvalue: data.collectionKey,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: copy(\"server:core.publish.requests.email.detail.document\"),\n\t\t\t\tvalue: `#${data.documentId}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: copy(\"server:core.publish.requests.email.detail.target\"),\n\t\t\t\tvalue: data.target,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: copy(\"server:core.publish.requests.email.detail.requested.by\"),\n\t\t\t\tvalue: data.user.email,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: copy(\"server:core.publish.requests.email.detail.scheduled.for\"),\n\t\t\t\tvalue: schedule?.scheduledAt,\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: copy(\n\t\t\t\t\t\"server:core.publish.requests.email.detail.scheduled.timezone\",\n\t\t\t\t),\n\t\t\t\tvalue: schedule?.scheduledTimezone,\n\t\t\t},\n\t\t],\n\t});\n\tif (notifyRes.error) return notifyRes;\n\n\treturn {\n\t\terror: undefined,\n\t\tdata: undefined,\n\t};\n};\n\nexport default createSingle;\n"],"mappings":"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"}