fix(ui): updatedAt field in locked-docs collection able to be updated by non-owner (#9026)
### What? If you have a custom field that sets the value of the field using the `useField` hook on entry into a document - the `updatedAt` field would be updated even when a non-owner tries to enter a locked document. ### Why? When a field is updated in the edit view - we perform an update in `form-state` to keep the doc in `payload-locked-documents` up to date with the current editing status. The above scenario would hit this update operation even on non-owner users because it was previously only checking for `updateLastEdited` (which would get hit by the `setValue` in the `useField` hook) so we also need to check to make sure the current user entering a locked doc is also the owner of the document. ### How? When performing an update to `payload-locked-documents` in `buildFormState` - only perform the update if the current user is also the owner of the locked document otherwise skip the `update` operation. Fixes #8781
This commit is contained in:
@@ -278,7 +278,13 @@ export const buildFormState = async ({
|
|||||||
user: lockedDocument.docs[0]?.user?.value,
|
user: lockedDocument.docs[0]?.user?.value,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateLastEdited) {
|
const lockOwnerId =
|
||||||
|
typeof lockedDocument.docs[0]?.user?.value === 'object'
|
||||||
|
? lockedDocument.docs[0]?.user?.value?.id
|
||||||
|
: lockedDocument.docs[0]?.user?.value
|
||||||
|
|
||||||
|
// Should only update doc if the incoming / current user is also the owner of the locked doc
|
||||||
|
if (updateLastEdited && req.user && lockOwnerId === req.user.id) {
|
||||||
await req.payload.db.updateOne({
|
await req.payload.db.updateOne({
|
||||||
id: lockedDocument.docs[0].id,
|
id: lockedDocument.docs[0].id,
|
||||||
collection: 'payload-locked-documents',
|
collection: 'payload-locked-documents',
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
'use client'
|
||||||
|
import type { TextFieldClientProps } from 'payload'
|
||||||
|
|
||||||
|
import { DatePicker, FieldLabel, useField } from '@payloadcms/ui'
|
||||||
|
import { type FunctionComponent, useEffect, useRef } from 'react'
|
||||||
|
|
||||||
|
export const DocumentLoaded: FunctionComponent<TextFieldClientProps> = ({ field: label }) => {
|
||||||
|
const field = useField<Date>({
|
||||||
|
path: 'documentLoaded',
|
||||||
|
})
|
||||||
|
const hasRun = useRef(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasRun.current || field.formInitializing) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hasRun.current = true
|
||||||
|
|
||||||
|
field.setValue(new Date().toISOString())
|
||||||
|
}, [field])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginBottom: '20px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FieldLabel field={label} />
|
||||||
|
<DatePicker displayFormat="yyyy-MM-dd hh:mm:ss" readOnly={true} value={field.value} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ export const PostsCollection: CollectionConfig = {
|
|||||||
slug: postsSlug,
|
slug: postsSlug,
|
||||||
admin: {
|
admin: {
|
||||||
useAsTitle: 'text',
|
useAsTitle: 'text',
|
||||||
|
defaultColumns: ['text', 'createdAt', 'updatedAt', '_status'],
|
||||||
},
|
},
|
||||||
lockDocuments: {
|
lockDocuments: {
|
||||||
duration: 180,
|
duration: 180,
|
||||||
@@ -15,6 +16,20 @@ export const PostsCollection: CollectionConfig = {
|
|||||||
name: 'text',
|
name: 'text',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'documentLoaded',
|
||||||
|
label: 'Document loaded',
|
||||||
|
type: 'date',
|
||||||
|
admin: {
|
||||||
|
date: {
|
||||||
|
displayFormat: 'yyyy-MM-dd HH:mm:ss',
|
||||||
|
},
|
||||||
|
readOnly: true,
|
||||||
|
components: {
|
||||||
|
Field: '/collections/Posts/fields/DocumentLoaded.tsx#DocumentLoaded',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
versions: {
|
versions: {
|
||||||
drafts: true,
|
drafts: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user