Skip to content

Commit e899182

Browse files
authored
fix: restoreVersion validation for localized required fields (#15821)
## Summary - fix collection `restoreVersion` to read version/current docs with all locales before restore processing - validate restore data in the default locale context while preserving full locale data for persistence - add an integration regression test for restoring versions when required localized fields are empty in a non-default locale Closes #15698 ## Related #15698 ## Changes - update `packages/payload/src/collections/operations/restoreVersion.ts` - add coverage in `test/versions/int.spec.ts` ## Testing - [x] `PAYLOAD_DATABASE=sqlite NODE_OPTIONS="--no-deprecation --no-experimental-strip-types" NODE_NO_WARNINGS=1 DISABLE_LOGGING=true pnpm exec vitest --project int test/versions/int.spec.ts -t "should restore published version with correct data|should restore a published version when required localized fields are empty in a non-default locale"` --------- Co-authored-by: German Jablonski <GermanJablo@users.noreply.github.com>
1 parent cb6f426 commit e899182

File tree

2 files changed

+62
-11
lines changed

2 files changed

+62
-11
lines changed

packages/payload/src/collections/operations/restoreVersion.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export const restoreVersionOperation = async <
8080
const { docs: versionDocs } = await req.payload.db.findVersions({
8181
collection: collectionConfig.slug,
8282
limit: 1,
83-
locale: locale!,
83+
locale: 'all',
8484
pagination: false,
8585
req,
8686
where: { id: { equals: id } },
@@ -109,7 +109,7 @@ export const restoreVersionOperation = async <
109109

110110
const findOneArgs: FindOneArgs = {
111111
collection: collectionConfig.slug,
112-
locale: locale!,
112+
locale: 'all',
113113
req,
114114
where: combineQueries({ id: { equals: parentDocID } }, accessResults),
115115
}
@@ -143,6 +143,10 @@ export const restoreVersionOperation = async <
143143
})
144144

145145
// originalDoc with hoisted localized data
146+
const validationLocale = payload.config.localization
147+
? payload.config.localization.defaultLocale
148+
: locale!
149+
146150
const originalDoc = await afterRead({
147151
collection: collectionConfig,
148152
context: req.context,
@@ -151,13 +155,13 @@ export const restoreVersionOperation = async <
151155
draft: draftArg,
152156
fallbackLocale: null,
153157
global: null,
154-
locale: locale!,
158+
locale: validationLocale,
155159
overrideAccess: true,
156160
req,
157161
showHiddenFields: true,
158162
})
159163

160-
// version data with hoisted localized data
164+
// Use locale-hoisted version data for validation while preserving all locales in docWithLocales.
161165
const prevVersionDoc = await afterRead({
162166
collection: collectionConfig,
163167
context: req.context,
@@ -166,7 +170,7 @@ export const restoreVersionOperation = async <
166170
draft: draftArg,
167171
fallbackLocale: null,
168172
global: null,
169-
locale: locale!,
173+
locale: validationLocale,
170174
overrideAccess: true,
171175
req,
172176
showHiddenFields: true,
@@ -176,6 +180,11 @@ export const restoreVersionOperation = async <
176180
// beforeValidate - Fields
177181
// /////////////////////////////////////
178182

183+
const reqWithValidationLocale = Object.assign(Object.create(req), req, {
184+
fallbackLocale: null,
185+
locale: validationLocale,
186+
})
187+
179188
let data = await beforeValidate({
180189
id: parentDocID,
181190
collection: collectionConfig,
@@ -185,7 +194,7 @@ export const restoreVersionOperation = async <
185194
global: null,
186195
operation: 'update',
187196
overrideAccess,
188-
req,
197+
req: reqWithValidationLocale,
189198
})
190199

191200
// /////////////////////////////////////
@@ -201,7 +210,7 @@ export const restoreVersionOperation = async <
201210
data,
202211
operation: 'update',
203212
originalDoc,
204-
req,
213+
req: reqWithValidationLocale,
205214
})) || data
206215
}
207216
}
@@ -219,7 +228,7 @@ export const restoreVersionOperation = async <
219228
data,
220229
operation: 'update',
221230
originalDoc,
222-
req,
231+
req: reqWithValidationLocale,
223232
})) || data
224233
}
225234
}
@@ -238,7 +247,7 @@ export const restoreVersionOperation = async <
238247
global: null,
239248
operation: 'update',
240249
overrideAccess,
241-
req,
250+
req: reqWithValidationLocale,
242251
skipValidation: draftArg && !hasDraftValidationEnabled(collectionConfig),
243252
})
244253

@@ -261,7 +270,7 @@ export const restoreVersionOperation = async <
261270
id: parentDocID,
262271
collection: collectionConfig.slug,
263272
data: result,
264-
req,
273+
req: reqWithValidationLocale,
265274
select,
266275
})
267276
}
@@ -278,7 +287,7 @@ export const restoreVersionOperation = async <
278287
draft: draftArg,
279288
operation: 'restoreVersion',
280289
payload,
281-
req,
290+
req: reqWithValidationLocale,
282291
select,
283292
})
284293

test/versions/int.spec.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,48 @@ describe('Versions', () => {
837837
expect(restoredVersion.title).toStrictEqual('v1')
838838
})
839839

840+
it('should restore a published version when required localized fields are empty in a non-default locale', async () => {
841+
const originalPost = await payload.create({
842+
collection: draftCollectionSlug,
843+
data: {
844+
_status: 'published',
845+
description: 'description v1',
846+
title: 'title v1 en',
847+
},
848+
})
849+
850+
await payload.update({
851+
id: originalPost.id,
852+
collection: draftCollectionSlug,
853+
data: {
854+
_status: 'published',
855+
description: 'description v2',
856+
title: 'title v2 en',
857+
},
858+
draft: true,
859+
})
860+
861+
const versions = await payload.findVersions({
862+
collection: draftCollectionSlug,
863+
where: {
864+
parent: {
865+
equals: originalPost.id,
866+
},
867+
},
868+
})
869+
870+
const oldestVersion = versions.docs[versions.docs.length - 1]
871+
872+
const restoredVersion = await payload.restoreVersion({
873+
id: oldestVersion!.id,
874+
collection: draftCollectionSlug,
875+
fallbackLocale: false,
876+
locale: 'de',
877+
})
878+
879+
expect(restoredVersion.id).toStrictEqual(originalPost.id)
880+
})
881+
840882
it('findVersions - pagination should work correctly', async () => {
841883
const post = await payload.create({
842884
collection: draftCollectionSlug,

0 commit comments

Comments
 (0)