feat: add hooks to restoreVersion collection operation (#13333)
Adds missing hooks to the restoreVersion operation. - beforeOperation - beforeValidate - Fields - beforeValidate - Collection - beforeChange - Collection - beforeChange - Fields - afterOperation
This commit is contained in:
@@ -85,6 +85,7 @@ export type HookOperationType =
|
||||
| 'readDistinct'
|
||||
| 'refresh'
|
||||
| 'resetPassword'
|
||||
| 'restoreVersion'
|
||||
| 'update'
|
||||
|
||||
type CreateOrUpdateOperation = Extract<HookOperationType, 'create' | 'update'>
|
||||
|
||||
@@ -291,6 +291,7 @@ export const createOperation = async <
|
||||
autosave,
|
||||
collection: collectionConfig,
|
||||
docWithLocales: result,
|
||||
operation: 'create',
|
||||
payload,
|
||||
publishSpecificLocale,
|
||||
req,
|
||||
|
||||
@@ -10,15 +10,23 @@ import { combineQueries } from '../../database/combineQueries.js'
|
||||
import { APIError, Forbidden, NotFound } from '../../errors/index.js'
|
||||
import { afterChange } from '../../fields/hooks/afterChange/index.js'
|
||||
import { afterRead } from '../../fields/hooks/afterRead/index.js'
|
||||
import { beforeChange } from '../../fields/hooks/beforeChange/index.js'
|
||||
import { beforeValidate } from '../../fields/hooks/beforeValidate/index.js'
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { deepCopyObjectSimple } from '../../utilities/deepCopyObject.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
import { sanitizeSelect } from '../../utilities/sanitizeSelect.js'
|
||||
import { getLatestCollectionVersion } from '../../versions/getLatestCollectionVersion.js'
|
||||
import { saveVersion } from '../../versions/saveVersion.js'
|
||||
import { buildAfterOperation } from './utils.js'
|
||||
|
||||
export type Arguments = {
|
||||
collection: Collection
|
||||
currentDepth?: number
|
||||
depth?: number
|
||||
disableErrors?: boolean
|
||||
disableTransaction?: boolean
|
||||
draft?: boolean
|
||||
id: number | string
|
||||
overrideAccess?: boolean
|
||||
@@ -35,7 +43,7 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
|
||||
id,
|
||||
collection: { config: collectionConfig },
|
||||
depth,
|
||||
draft,
|
||||
draft: draftArg = false,
|
||||
overrideAccess = false,
|
||||
populate,
|
||||
req,
|
||||
@@ -45,6 +53,25 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
|
||||
} = args
|
||||
|
||||
try {
|
||||
const shouldCommit = !args.disableTransaction && (await initTransaction(args.req))
|
||||
|
||||
// /////////////////////////////////////
|
||||
// beforeOperation - Collection
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (args.collection.config.hooks?.beforeOperation?.length) {
|
||||
for (const hook of args.collection.config.hooks.beforeOperation) {
|
||||
args =
|
||||
(await hook({
|
||||
args,
|
||||
collection: args.collection.config,
|
||||
context: args.req.context,
|
||||
operation: 'restoreVersion',
|
||||
req: args.req,
|
||||
})) || args
|
||||
}
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
throw new APIError('Missing ID of version to restore.', httpStatus.BAD_REQUEST)
|
||||
}
|
||||
@@ -68,7 +95,7 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
|
||||
throw new NotFound(req.t)
|
||||
}
|
||||
|
||||
const parentDocID = rawVersion.parent
|
||||
const { parent: parentDocID, version: versionToRestoreWithLocales } = rawVersion
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Access
|
||||
@@ -90,6 +117,7 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
|
||||
where: combineQueries({ id: { equals: parentDocID } }, accessResults),
|
||||
}
|
||||
|
||||
// Get the document from the non versioned collection
|
||||
const doc = await req.payload.db.findOne(findOneArgs)
|
||||
|
||||
if (!doc && !hasWherePolicy) {
|
||||
@@ -109,7 +137,6 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
|
||||
// /////////////////////////////////////
|
||||
// fetch previousDoc
|
||||
// /////////////////////////////////////
|
||||
|
||||
const prevDocWithLocales = await getLatestCollectionVersion({
|
||||
id: parentDocID,
|
||||
config: collectionConfig,
|
||||
@@ -118,6 +145,109 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
|
||||
req,
|
||||
})
|
||||
|
||||
// originalDoc with hoisted localized data
|
||||
const originalDoc = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
depth: 0,
|
||||
doc: deepCopyObjectSimple(prevDocWithLocales),
|
||||
draft: draftArg,
|
||||
fallbackLocale: null,
|
||||
global: null,
|
||||
locale: locale!,
|
||||
overrideAccess: true,
|
||||
req,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
|
||||
// version data with hoisted localized data
|
||||
const prevVersionDoc = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
depth: 0,
|
||||
doc: deepCopyObjectSimple(versionToRestoreWithLocales),
|
||||
draft: draftArg,
|
||||
fallbackLocale: null,
|
||||
global: null,
|
||||
locale: locale!,
|
||||
overrideAccess: true,
|
||||
req,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
|
||||
let data = deepCopyObjectSimple(prevVersionDoc)
|
||||
|
||||
// /////////////////////////////////////
|
||||
// beforeValidate - Fields
|
||||
// /////////////////////////////////////
|
||||
|
||||
data = await beforeValidate({
|
||||
id: parentDocID,
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: originalDoc,
|
||||
global: null,
|
||||
operation: 'update',
|
||||
overrideAccess,
|
||||
req,
|
||||
})
|
||||
|
||||
// /////////////////////////////////////
|
||||
// beforeValidate - Collection
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (collectionConfig.hooks?.beforeValidate?.length) {
|
||||
for (const hook of collectionConfig.hooks.beforeValidate) {
|
||||
data =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
operation: 'update',
|
||||
originalDoc,
|
||||
req,
|
||||
})) || data
|
||||
}
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// beforeChange - Collection
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (collectionConfig.hooks?.beforeChange?.length) {
|
||||
for (const hook of collectionConfig.hooks.beforeChange) {
|
||||
data =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
operation: 'update',
|
||||
originalDoc,
|
||||
req,
|
||||
})) || data
|
||||
}
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// beforeChange - Fields
|
||||
// /////////////////////////////////////
|
||||
|
||||
let result = await beforeChange({
|
||||
id: parentDocID,
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data: { ...data, id: parentDocID },
|
||||
doc: originalDoc,
|
||||
docWithLocales: versionToRestoreWithLocales,
|
||||
global: null,
|
||||
operation: 'update',
|
||||
overrideAccess,
|
||||
req,
|
||||
skipValidation:
|
||||
draftArg && collectionConfig.versions.drafts && !collectionConfig.versions.drafts.validate,
|
||||
})
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Update
|
||||
// /////////////////////////////////////
|
||||
@@ -128,10 +258,10 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
|
||||
select: incomingSelect,
|
||||
})
|
||||
|
||||
let result = await req.payload.db.updateOne({
|
||||
result = await req.payload.db.updateOne({
|
||||
id: parentDocID,
|
||||
collection: collectionConfig.slug,
|
||||
data: rawVersion.version,
|
||||
data: result,
|
||||
req,
|
||||
select,
|
||||
})
|
||||
@@ -140,18 +270,16 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
|
||||
// Save `previousDoc` as a version after restoring
|
||||
// /////////////////////////////////////
|
||||
|
||||
const prevVersion = { ...prevDocWithLocales }
|
||||
|
||||
delete prevVersion.id
|
||||
|
||||
await payload.db.createVersion({
|
||||
result = await saveVersion({
|
||||
id: parentDocID,
|
||||
autosave: false,
|
||||
collectionSlug: collectionConfig.slug,
|
||||
createdAt: prevVersion.createdAt,
|
||||
parent: parentDocID,
|
||||
collection: collectionConfig,
|
||||
docWithLocales: result,
|
||||
draft: draftArg,
|
||||
operation: 'restoreVersion',
|
||||
payload,
|
||||
req,
|
||||
updatedAt: new Date().toISOString(),
|
||||
versionData: draft ? { ...rawVersion.version, _status: 'draft' } : rawVersion.version,
|
||||
select,
|
||||
})
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -225,6 +353,21 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
|
||||
}
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// afterOperation - Collection
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await buildAfterOperation({
|
||||
args,
|
||||
collection: collectionConfig,
|
||||
operation: 'restoreVersion',
|
||||
result,
|
||||
})
|
||||
|
||||
if (shouldCommit) {
|
||||
await commitTransaction(req)
|
||||
}
|
||||
|
||||
return result
|
||||
} catch (error: unknown) {
|
||||
await killTransaction(req)
|
||||
|
||||
@@ -314,6 +314,7 @@ export const updateDocument = async <
|
||||
collection: collectionConfig,
|
||||
docWithLocales: result,
|
||||
draft: shouldSaveDraft,
|
||||
operation: 'update',
|
||||
payload,
|
||||
publishSpecificLocale,
|
||||
req,
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { forgotPasswordOperation } from '../../auth/operations/forgotPasswo
|
||||
import type { loginOperation } from '../../auth/operations/login.js'
|
||||
import type { refreshOperation } from '../../auth/operations/refresh.js'
|
||||
import type { resetPasswordOperation } from '../../auth/operations/resetPassword.js'
|
||||
import type { CollectionSlug } from '../../index.js'
|
||||
import type { CollectionSlug, restoreVersionOperation } from '../../index.js'
|
||||
import type { PayloadRequest } from '../../types/index.js'
|
||||
import type { SanitizedCollectionConfig, SelectFromCollectionSlug } from '../config/types.js'
|
||||
import type { countOperation } from './count.js'
|
||||
@@ -36,6 +36,7 @@ export type AfterOperationMap<TOperationGeneric extends CollectionSlug> = {
|
||||
login: typeof loginOperation<TOperationGeneric>
|
||||
refresh: typeof refreshOperation
|
||||
resetPassword: typeof resetPasswordOperation<TOperationGeneric>
|
||||
restoreVersion: typeof restoreVersionOperation
|
||||
update: typeof updateOperation<TOperationGeneric, SelectFromCollectionSlug<TOperationGeneric>>
|
||||
updateByID: typeof updateByIDOperation<
|
||||
TOperationGeneric,
|
||||
@@ -108,6 +109,11 @@ export type AfterOperationArg<TOperationGeneric extends CollectionSlug> = {
|
||||
operation: 'resetPassword'
|
||||
result: Awaited<ReturnType<AfterOperationMap<TOperationGeneric>['resetPassword']>>
|
||||
}
|
||||
| {
|
||||
args: Parameters<AfterOperationMap<TOperationGeneric>['restoreVersion']>[0]
|
||||
operation: 'restoreVersion'
|
||||
result: Awaited<ReturnType<AfterOperationMap<TOperationGeneric>['restoreVersion']>>
|
||||
}
|
||||
| {
|
||||
args: Parameters<AfterOperationMap<TOperationGeneric>['update']>[0]
|
||||
operation: 'update'
|
||||
|
||||
@@ -282,6 +282,7 @@ export const updateOperation = async <
|
||||
docWithLocales: result,
|
||||
draft: shouldSaveDraft,
|
||||
global: globalConfig,
|
||||
operation: 'update',
|
||||
payload,
|
||||
publishSpecificLocale,
|
||||
req,
|
||||
|
||||
@@ -16,6 +16,7 @@ type Args = {
|
||||
draft?: boolean
|
||||
global?: SanitizedGlobalConfig
|
||||
id?: number | string
|
||||
operation?: 'create' | 'restoreVersion' | 'update'
|
||||
payload: Payload
|
||||
publishSpecificLocale?: string
|
||||
req?: PayloadRequest
|
||||
@@ -30,6 +31,7 @@ export const saveVersion = async ({
|
||||
docWithLocales: doc,
|
||||
draft,
|
||||
global,
|
||||
operation,
|
||||
payload,
|
||||
publishSpecificLocale,
|
||||
req,
|
||||
@@ -126,7 +128,7 @@ export const saveVersion = async ({
|
||||
const createVersionArgs = {
|
||||
autosave: Boolean(autosave),
|
||||
collectionSlug: undefined as string | undefined,
|
||||
createdAt: now,
|
||||
createdAt: operation === 'restoreVersion' ? versionData.createdAt : now,
|
||||
globalSlug: undefined as string | undefined,
|
||||
parent: collection ? id : undefined,
|
||||
publishedLocale: publishSpecificLocale || undefined,
|
||||
|
||||
Reference in New Issue
Block a user