mirror of
https://github.com/xtr-dev/payload-automation.git
synced 2025-12-11 01:03:23 +00:00
Initial commit
This commit is contained in:
42
src/steps/create-document-handler.ts
Normal file
42
src/steps/create-document-handler.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import type { TaskHandler } from "payload"
|
||||
|
||||
export const createDocumentHandler: TaskHandler<'create-document'> = async ({ input, req }) => {
|
||||
if (!input) {
|
||||
throw new Error('No input provided')
|
||||
}
|
||||
|
||||
const { collection, data, draft, locale } = input
|
||||
|
||||
if (!collection || typeof collection !== 'string') {
|
||||
throw new Error('Collection slug is required')
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
throw new Error('Document data is required')
|
||||
}
|
||||
|
||||
try {
|
||||
const parsedData = typeof data === 'string' ? JSON.parse(data) : data
|
||||
|
||||
const result = await req.payload.create({
|
||||
collection,
|
||||
data: parsedData,
|
||||
draft: draft || false,
|
||||
locale: locale || undefined,
|
||||
req
|
||||
})
|
||||
|
||||
return {
|
||||
output: {
|
||||
id: result.id,
|
||||
doc: result
|
||||
},
|
||||
state: 'succeeded'
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
errorMessage: error instanceof Error ? error.message : 'Failed to create document',
|
||||
state: 'failed'
|
||||
}
|
||||
}
|
||||
}
|
||||
56
src/steps/create-document.ts
Normal file
56
src/steps/create-document.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import type { TaskConfig } from "payload"
|
||||
|
||||
import { createDocumentHandler } from "./create-document-handler.js"
|
||||
|
||||
export const CreateDocumentStepTask = {
|
||||
slug: 'create-document',
|
||||
handler: createDocumentHandler,
|
||||
inputSchema: [
|
||||
{
|
||||
name: 'collection',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'The collection slug to create a document in'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'data',
|
||||
type: 'json',
|
||||
admin: {
|
||||
description: 'The document data to create'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'draft',
|
||||
type: 'checkbox',
|
||||
admin: {
|
||||
description: 'Create as draft (if collection has drafts enabled)'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'locale',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Locale for the document (if localization is enabled)'
|
||||
}
|
||||
}
|
||||
],
|
||||
outputSchema: [
|
||||
{
|
||||
name: 'doc',
|
||||
type: 'json',
|
||||
admin: {
|
||||
description: 'The created document'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'id',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'The ID of the created document'
|
||||
}
|
||||
}
|
||||
]
|
||||
} satisfies TaskConfig<'create-document'>
|
||||
71
src/steps/delete-document-handler.ts
Normal file
71
src/steps/delete-document-handler.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import type { TaskHandler } from "payload"
|
||||
|
||||
export const deleteDocumentHandler: TaskHandler<'delete-document'> = async ({ input, req }) => {
|
||||
if (!input) {
|
||||
throw new Error('No input provided')
|
||||
}
|
||||
|
||||
const { id, collection, where } = input
|
||||
|
||||
if (!collection || typeof collection !== 'string') {
|
||||
throw new Error('Collection slug is required')
|
||||
}
|
||||
|
||||
try {
|
||||
// If ID is provided, delete by ID
|
||||
if (id) {
|
||||
const result = await req.payload.delete({
|
||||
id: id.toString(),
|
||||
collection,
|
||||
req
|
||||
})
|
||||
|
||||
return {
|
||||
output: {
|
||||
deletedCount: 1,
|
||||
doc: result
|
||||
},
|
||||
state: 'succeeded'
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, delete multiple documents
|
||||
if (!where) {
|
||||
throw new Error('Either ID or where conditions must be provided')
|
||||
}
|
||||
|
||||
const parsedWhere = typeof where === 'string' ? JSON.parse(where) : where
|
||||
|
||||
// First find the documents to delete
|
||||
const toDelete = await req.payload.find({
|
||||
collection,
|
||||
limit: 1000, // Set a reasonable limit
|
||||
req,
|
||||
where: parsedWhere
|
||||
})
|
||||
|
||||
// Delete each document
|
||||
const deleted = []
|
||||
for (const doc of toDelete.docs) {
|
||||
const result = await req.payload.delete({
|
||||
id: doc.id,
|
||||
collection,
|
||||
req
|
||||
})
|
||||
deleted.push(result)
|
||||
}
|
||||
|
||||
return {
|
||||
output: {
|
||||
deletedCount: deleted.length,
|
||||
doc: deleted
|
||||
},
|
||||
state: 'succeeded'
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
errorMessage: error instanceof Error ? error.message : 'Failed to delete document(s)',
|
||||
state: 'failed'
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/steps/delete-document.ts
Normal file
48
src/steps/delete-document.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import type { TaskConfig } from "payload"
|
||||
|
||||
import { deleteDocumentHandler } from "./delete-document-handler.js"
|
||||
|
||||
export const DeleteDocumentStepTask = {
|
||||
slug: 'delete-document',
|
||||
handler: deleteDocumentHandler,
|
||||
inputSchema: [
|
||||
{
|
||||
name: 'collection',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'The collection slug to delete from'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'id',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'The ID of a specific document to delete (leave empty to delete multiple)'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'where',
|
||||
type: 'json',
|
||||
admin: {
|
||||
description: 'Query conditions to find documents to delete (used when ID is not provided)'
|
||||
}
|
||||
}
|
||||
],
|
||||
outputSchema: [
|
||||
{
|
||||
name: 'doc',
|
||||
type: 'json',
|
||||
admin: {
|
||||
description: 'The deleted document(s)'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'deletedCount',
|
||||
type: 'number',
|
||||
admin: {
|
||||
description: 'Number of documents deleted'
|
||||
}
|
||||
}
|
||||
]
|
||||
} satisfies TaskConfig<'delete-document'>
|
||||
14
src/steps/http-request-handler.ts
Normal file
14
src/steps/http-request-handler.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import type {TaskHandler} from "payload"
|
||||
|
||||
export const httpStepHandler: TaskHandler<'http-request-step'> = async ({input}) => {
|
||||
if (!input) {
|
||||
throw new Error('No input provided')
|
||||
}
|
||||
const response = await fetch(input.url)
|
||||
return {
|
||||
output: {
|
||||
response: await response.text()
|
||||
},
|
||||
state: response.ok ? 'succeeded' : undefined
|
||||
}
|
||||
}
|
||||
20
src/steps/http-request.ts
Normal file
20
src/steps/http-request.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import type {TaskConfig} from "payload"
|
||||
|
||||
import {httpStepHandler} from "./http-request-handler.js"
|
||||
|
||||
export const HttpRequestStepTask = {
|
||||
slug: 'http-request-step',
|
||||
handler: httpStepHandler,
|
||||
inputSchema: [
|
||||
{
|
||||
name: 'url',
|
||||
type: 'text',
|
||||
}
|
||||
],
|
||||
outputSchema: [
|
||||
{
|
||||
name: 'response',
|
||||
type: 'textarea',
|
||||
}
|
||||
]
|
||||
} satisfies TaskConfig<'http-request-step'>
|
||||
13
src/steps/index.ts
Normal file
13
src/steps/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export { CreateDocumentStepTask } from './create-document.js'
|
||||
export { createDocumentHandler } from './create-document-handler.js'
|
||||
export { DeleteDocumentStepTask } from './delete-document.js'
|
||||
export { deleteDocumentHandler } from './delete-document-handler.js'
|
||||
export { HttpRequestStepTask } from './http-request.js'
|
||||
export { httpStepHandler } from './http-request-handler.js'
|
||||
|
||||
export { ReadDocumentStepTask } from './read-document.js'
|
||||
export { readDocumentHandler } from './read-document-handler.js'
|
||||
export { SendEmailStepTask } from './send-email.js'
|
||||
export { sendEmailHandler } from './send-email-handler.js'
|
||||
export { UpdateDocumentStepTask } from './update-document.js'
|
||||
export { updateDocumentHandler } from './update-document-handler.js'
|
||||
60
src/steps/read-document-handler.ts
Normal file
60
src/steps/read-document-handler.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import type { TaskHandler } from "payload"
|
||||
|
||||
export const readDocumentHandler: TaskHandler<'read-document'> = async ({ input, req }) => {
|
||||
if (!input) {
|
||||
throw new Error('No input provided')
|
||||
}
|
||||
|
||||
const { id, collection, depth, limit, locale, sort, where } = input
|
||||
|
||||
if (!collection || typeof collection !== 'string') {
|
||||
throw new Error('Collection slug is required')
|
||||
}
|
||||
|
||||
try {
|
||||
// If ID is provided, find by ID
|
||||
if (id) {
|
||||
const result = await req.payload.findByID({
|
||||
id: id.toString(),
|
||||
collection,
|
||||
depth: typeof depth === 'number' ? depth : undefined,
|
||||
locale: locale || undefined,
|
||||
req
|
||||
})
|
||||
|
||||
return {
|
||||
output: {
|
||||
doc: result,
|
||||
totalDocs: 1
|
||||
},
|
||||
state: 'succeeded'
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, find multiple documents
|
||||
const parsedWhere = where ? (typeof where === 'string' ? JSON.parse(where) : where) : {}
|
||||
|
||||
const result = await req.payload.find({
|
||||
collection,
|
||||
depth: typeof depth === 'number' ? depth : undefined,
|
||||
limit: typeof limit === 'number' ? limit : 10,
|
||||
locale: locale || undefined,
|
||||
req,
|
||||
sort: sort || undefined,
|
||||
where: parsedWhere
|
||||
})
|
||||
|
||||
return {
|
||||
output: {
|
||||
doc: result.docs,
|
||||
totalDocs: result.totalDocs
|
||||
},
|
||||
state: 'succeeded'
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
errorName: error instanceof Error ? error.message : 'Failed to read document(s)',
|
||||
state: 'failed'
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/steps/read-document.ts
Normal file
76
src/steps/read-document.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import type { TaskConfig } from "payload"
|
||||
|
||||
import { readDocumentHandler } from "./read-document-handler.js"
|
||||
|
||||
export const ReadDocumentStepTask = {
|
||||
slug: 'read-document',
|
||||
handler: readDocumentHandler,
|
||||
inputSchema: [
|
||||
{
|
||||
name: 'collection',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'The collection slug to read from'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'id',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'The ID of a specific document to read (leave empty to find multiple)'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'where',
|
||||
type: 'json',
|
||||
admin: {
|
||||
description: 'Query conditions to find documents (used when ID is not provided)'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
admin: {
|
||||
description: 'Maximum number of documents to return (default: 10)'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'sort',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Field to sort by (prefix with - for descending order)'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'locale',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Locale for the document (if localization is enabled)'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'depth',
|
||||
type: 'number',
|
||||
admin: {
|
||||
description: 'Depth of relationships to populate (0-10)'
|
||||
}
|
||||
}
|
||||
],
|
||||
outputSchema: [
|
||||
{
|
||||
name: 'doc',
|
||||
type: 'json',
|
||||
admin: {
|
||||
description: 'The document(s) found'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'totalDocs',
|
||||
type: 'number',
|
||||
admin: {
|
||||
description: 'Total number of documents matching the query'
|
||||
}
|
||||
}
|
||||
]
|
||||
} satisfies TaskConfig<'read-document'>
|
||||
56
src/steps/send-email-handler.ts
Normal file
56
src/steps/send-email-handler.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import type { TaskHandler } from "payload"
|
||||
|
||||
export const sendEmailHandler: TaskHandler<'send-email'> = async ({ input, req }) => {
|
||||
if (!input) {
|
||||
throw new Error('No input provided')
|
||||
}
|
||||
|
||||
const { bcc, cc, from, html, subject, text, to } = input
|
||||
|
||||
if (!to || typeof to !== 'string') {
|
||||
throw new Error('Recipient email address (to) is required')
|
||||
}
|
||||
|
||||
if (!subject || typeof subject !== 'string') {
|
||||
throw new Error('Subject is required')
|
||||
}
|
||||
|
||||
if (!text && !html) {
|
||||
throw new Error('Either text or html content is required')
|
||||
}
|
||||
|
||||
try {
|
||||
// Use Payload's email functionality
|
||||
const emailData = {
|
||||
bcc: Array.isArray(bcc) ? bcc.filter(email => typeof email === 'string') : undefined,
|
||||
cc: Array.isArray(cc) ? cc.filter(email => typeof email === 'string') : undefined,
|
||||
from: typeof from === 'string' ? from : undefined,
|
||||
html: typeof html === 'string' ? html : undefined,
|
||||
subject,
|
||||
text: typeof text === 'string' ? text : undefined,
|
||||
to
|
||||
}
|
||||
|
||||
// Clean up undefined values
|
||||
Object.keys(emailData).forEach(key => {
|
||||
if (emailData[key as keyof typeof emailData] === undefined) {
|
||||
delete emailData[key as keyof typeof emailData]
|
||||
}
|
||||
})
|
||||
|
||||
const result = await req.payload.sendEmail(emailData)
|
||||
|
||||
return {
|
||||
output: {
|
||||
messageId: (result && typeof result === 'object' && 'messageId' in result) ? result.messageId : 'unknown',
|
||||
response: typeof result === 'object' ? JSON.stringify(result) : String(result)
|
||||
},
|
||||
state: 'succeeded'
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
errorMessage: error instanceof Error ? error.message : 'Failed to send email',
|
||||
state: 'failed'
|
||||
}
|
||||
}
|
||||
}
|
||||
79
src/steps/send-email.ts
Normal file
79
src/steps/send-email.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import type { TaskConfig } from "payload"
|
||||
|
||||
import { sendEmailHandler } from "./send-email-handler.js"
|
||||
|
||||
export const SendEmailStepTask = {
|
||||
slug: 'send-email',
|
||||
handler: sendEmailHandler,
|
||||
inputSchema: [
|
||||
{
|
||||
name: 'to',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Recipient email address'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'from',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Sender email address (optional, uses default if not provided)'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'subject',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Email subject line'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'text',
|
||||
type: 'textarea',
|
||||
admin: {
|
||||
description: 'Plain text email content'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'html',
|
||||
type: 'textarea',
|
||||
admin: {
|
||||
description: 'HTML email content (optional)'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'cc',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'CC recipients'
|
||||
},
|
||||
hasMany: true
|
||||
},
|
||||
{
|
||||
name: 'bcc',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'BCC recipients'
|
||||
},
|
||||
hasMany: true
|
||||
}
|
||||
],
|
||||
outputSchema: [
|
||||
{
|
||||
name: 'messageId',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Email message ID from the mail server'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'response',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Response from the mail server'
|
||||
}
|
||||
}
|
||||
]
|
||||
} satisfies TaskConfig<'send-email'>
|
||||
47
src/steps/update-document-handler.ts
Normal file
47
src/steps/update-document-handler.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { TaskHandler } from "payload"
|
||||
|
||||
export const updateDocumentHandler: TaskHandler<'update-document'> = async ({ input, req }) => {
|
||||
if (!input) {
|
||||
throw new Error('No input provided')
|
||||
}
|
||||
|
||||
const { id, collection, data, draft, locale } = input
|
||||
|
||||
if (!collection || typeof collection !== 'string') {
|
||||
throw new Error('Collection slug is required')
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
throw new Error('Document ID is required')
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
throw new Error('Update data is required')
|
||||
}
|
||||
|
||||
try {
|
||||
const parsedData = typeof data === 'string' ? JSON.parse(data) : data
|
||||
|
||||
const result = await req.payload.update({
|
||||
id: id.toString(),
|
||||
collection,
|
||||
data: parsedData,
|
||||
draft: draft || false,
|
||||
locale: locale || undefined,
|
||||
req
|
||||
})
|
||||
|
||||
return {
|
||||
output: {
|
||||
id: result.id,
|
||||
doc: result
|
||||
},
|
||||
state: 'succeeded'
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
errorName: error instanceof Error ? error.message : 'Failed to update document',
|
||||
state: 'failed'
|
||||
}
|
||||
}
|
||||
}
|
||||
64
src/steps/update-document.ts
Normal file
64
src/steps/update-document.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import type { TaskConfig } from "payload"
|
||||
|
||||
import { updateDocumentHandler } from "./update-document-handler.js"
|
||||
|
||||
export const UpdateDocumentStepTask = {
|
||||
slug: 'update-document',
|
||||
handler: updateDocumentHandler,
|
||||
inputSchema: [
|
||||
{
|
||||
name: 'collection',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'The collection slug to update a document in'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'id',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'The ID of the document to update'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'data',
|
||||
type: 'json',
|
||||
admin: {
|
||||
description: 'The data to update the document with'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'draft',
|
||||
type: 'checkbox',
|
||||
admin: {
|
||||
description: 'Update as draft (if collection has drafts enabled)'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'locale',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Locale for the document (if localization is enabled)'
|
||||
}
|
||||
}
|
||||
],
|
||||
outputSchema: [
|
||||
{
|
||||
name: 'doc',
|
||||
type: 'json',
|
||||
admin: {
|
||||
description: 'The updated document'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'id',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'The ID of the updated document'
|
||||
}
|
||||
}
|
||||
]
|
||||
} satisfies TaskConfig<'update-document'>
|
||||
Reference in New Issue
Block a user