fix: ensure scheduled publish restriction (#10317)
This commit is contained in:
@@ -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,
|
||||
}),
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,5 @@ export type SchedulePublishTaskInput = {
|
||||
global?: GlobalSlug
|
||||
locale?: string
|
||||
type: string
|
||||
user?: number | string
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user