fix: ensure scheduled publish restriction (#10317)

This commit is contained in:
Sasha
2025-01-03 15:26:21 +02:00
committed by GitHub
parent d6d9edc304
commit 4e57054bb7
7 changed files with 113 additions and 1 deletions

View File

@@ -222,6 +222,7 @@ export const sanitizeConfig = async (incomingConfig: Config): Promise<SanitizedC
configWithDefaults.jobs.tasks.push(
getSchedulePublishTask({
adminUserSlug: config.admin.user,
collections: schedulePublishCollections,
globals: schedulePublishGlobals,
}),

View File

@@ -1,12 +1,15 @@
import type { User } from '../../auth/types.js'
import type { TaskConfig } from '../../queues/config/types/taskTypes.js'
import type { SchedulePublishTaskInput } from './types.js'
type Args = {
adminUserSlug: string
collections: string[]
globals: string[]
}
export const getSchedulePublishTask = ({
adminUserSlug,
collections,
globals,
}: Args): TaskConfig<{ input: SchedulePublishTaskInput; output: object }> => {
@@ -15,6 +18,20 @@ export const getSchedulePublishTask = ({
handler: async ({ input, req }) => {
const _status = input?.type === 'publish' || !input?.type ? 'published' : 'draft'
const userID = input.user
let user: null | User = null
if (userID) {
user = (await req.payload.findByID({
id: userID,
collection: adminUserSlug,
depth: 0,
})) as User
user.collection = adminUserSlug
}
let publishSpecificLocale: string
if (input?.type === 'publish' && input.locale && req.payload.config.localization) {
@@ -35,7 +52,9 @@ export const getSchedulePublishTask = ({
_status,
},
depth: 0,
overrideAccess: user === null,
publishSpecificLocale,
user,
})
}
@@ -46,7 +65,9 @@ export const getSchedulePublishTask = ({
_status,
},
depth: 0,
overrideAccess: user === null,
publishSpecificLocale,
user,
})
}
@@ -75,6 +96,11 @@ export const getSchedulePublishTask = ({
type: 'select',
options: globals,
},
{
name: 'user',
type: 'relationship',
relationTo: adminUserSlug,
},
],
}
}

View File

@@ -8,4 +8,5 @@ export type SchedulePublishTaskInput = {
global?: GlobalSlug
locale?: string
type: string
user?: number | string
}

View File

@@ -11,8 +11,32 @@ export const schedulePublishHandler = async ({
doc,
global,
locale,
req: { i18n, payload },
req,
}: SchedulePublishHandlerArgs) => {
const { i18n, payload, user } = req
const incomingUserSlug = user?.collection
const adminUserSlug = payload.config.admin.user
if (!incomingUserSlug) {
throw new Error('Unauthorized')
}
const adminAccessFunction = payload.collections[incomingUserSlug].config.access?.admin
// Run the admin access function from the config if it exists
if (adminAccessFunction) {
const canAccessAdmin = await adminAccessFunction({ req })
if (!canAccessAdmin) {
throw new Error('Unauthorized')
}
// Match the user collection to the global admin config
} else if (adminUserSlug !== incomingUserSlug) {
throw new Error('Unauthorized')
}
try {
await payload.jobs.queue({
input: {
@@ -20,6 +44,7 @@ export const schedulePublishHandler = async ({
doc,
global,
locale,
user: user.id,
},
task: 'schedulePublish',
waitUntil: date,

View File

@@ -5,6 +5,13 @@ import { draftCollectionSlug } from '../slugs.js'
const DraftPosts: CollectionConfig = {
slug: draftCollectionSlug,
access: {
update: () => {
return {
restrictedToUpdate: {
not_equals: true,
},
}
},
read: ({ req: { user } }) => {
if (user) {
return true
@@ -111,6 +118,10 @@ const DraftPosts: CollectionConfig = {
type: 'relationship',
relationTo: draftCollectionSlug,
},
{
name: 'restrictedToUpdate',
type: 'checkbox',
},
],
versions: {
drafts: {

View File

@@ -1792,6 +1792,51 @@ describe('Versions', () => {
expect(retrieved._status).toStrictEqual('published')
})
it('should restrict scheduled publish based on user', async () => {
const draft = await payload.create({
collection: draftCollectionSlug,
data: {
title: 'my doc to publish in the future',
description: 'hello',
restrictedToUpdate: true,
},
draft: true,
})
expect(draft._status).toStrictEqual('draft')
const currentDate = new Date()
const user = (
await payload.find({ collection: 'users', where: { email: { equals: devUser.email } } })
).docs[0]
await payload.jobs.queue({
task: 'schedulePublish',
waitUntil: new Date(currentDate.getTime() + 3000),
input: {
doc: {
relationTo: draftCollectionSlug,
value: draft.id,
},
user: user.id,
},
})
await wait(4000)
const res = await payload.jobs.run()
expect(res.jobStatus[Object.keys(res.jobStatus)[0]].status).toBe('error-reached-max-retries')
const retrieved = await payload.findByID({
collection: draftCollectionSlug,
id: draft.id,
})
expect(retrieved._status).toStrictEqual('draft')
})
it('should allow collection scheduled unpublish', async () => {
const published = await payload.create({
collection: draftCollectionSlug,

View File

@@ -157,6 +157,7 @@ export interface DraftPost {
}[]
| null;
relation?: (string | null) | DraftPost;
restrictedToUpdate?: boolean | null;
updatedAt: string;
createdAt: string;
_status?: ('draft' | 'published') | null;
@@ -459,6 +460,7 @@ export interface DraftPostsSelect<T extends boolean = true> {
};
};
relation?: T;
restrictedToUpdate?: T;
updatedAt?: T;
createdAt?: T;
_status?: T;
@@ -723,6 +725,7 @@ export interface TaskSchedulePublish {
value: string | DraftPost;
} | null;
global?: 'draft-global' | null;
user?: (string | null) | User;
};
output?: unknown;
}