mirror of
https://github.com/xtr-dev/payload-mailing.git
synced 2025-12-10 16:23:23 +00:00
Add validation for beforeSend hook to ensure required properties remain intact
- Validate that 'from' field is not removed - Validate that 'to' field is not removed or emptied - Validate that 'subject' field is not removed - Validate that at least 'html' or 'text' content exists - Throw clear error messages if validation fails - Bump version to 0.1.21
This commit is contained in:
@@ -248,6 +248,10 @@ export interface Email {
|
||||
* Sender email address (optional, uses default if not provided)
|
||||
*/
|
||||
from?: string | null;
|
||||
/**
|
||||
* Sender display name (optional, e.g., "John Doe" for "John Doe <john@example.com>")
|
||||
*/
|
||||
fromName?: string | null;
|
||||
/**
|
||||
* Reply-to email address
|
||||
*/
|
||||
@@ -543,6 +547,7 @@ export interface EmailsSelect<T extends boolean = true> {
|
||||
cc?: T;
|
||||
bcc?: T;
|
||||
from?: T;
|
||||
fromName?: T;
|
||||
replyTo?: T;
|
||||
subject?: T;
|
||||
html?: T;
|
||||
@@ -675,6 +680,18 @@ export interface TaskSendEmail {
|
||||
* Optional comma-separated list of BCC email addresses
|
||||
*/
|
||||
bcc?: string | null;
|
||||
/**
|
||||
* Optional sender email address (uses default if not provided)
|
||||
*/
|
||||
from?: string | null;
|
||||
/**
|
||||
* Optional sender display name (e.g., "John Doe")
|
||||
*/
|
||||
fromName?: string | null;
|
||||
/**
|
||||
* Optional reply-to email address
|
||||
*/
|
||||
replyTo?: string | null;
|
||||
/**
|
||||
* Optional date/time to schedule email for future delivery
|
||||
*/
|
||||
@@ -684,7 +701,9 @@ export interface TaskSendEmail {
|
||||
*/
|
||||
priority?: number | null;
|
||||
};
|
||||
output?: unknown;
|
||||
output: {
|
||||
id?: string | null;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
|
||||
113
dev/test-hook-validation.ts
Normal file
113
dev/test-hook-validation.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
// Test hook validation in the dev environment
|
||||
import { getPayload } from 'payload'
|
||||
import config from './payload.config.js'
|
||||
|
||||
async function testHookValidation() {
|
||||
const payload = await getPayload({ config: await config })
|
||||
|
||||
console.log('\n🧪 Testing beforeSend hook validation...\n')
|
||||
|
||||
// Test 1: Create an email to process
|
||||
const email = await payload.create({
|
||||
collection: 'emails',
|
||||
data: {
|
||||
to: ['test@example.com'],
|
||||
subject: 'Test Email for Validation',
|
||||
html: '<p>Testing hook validation</p>',
|
||||
text: 'Testing hook validation',
|
||||
status: 'pending'
|
||||
}
|
||||
})
|
||||
|
||||
console.log('✅ Test email created:', email.id)
|
||||
|
||||
// Get the mailing service
|
||||
const mailingService = (payload as any).mailing.service
|
||||
|
||||
// Test 2: Temporarily replace the config with a bad hook
|
||||
const originalBeforeSend = mailingService.config.beforeSend
|
||||
|
||||
console.log('\n📝 Test: Hook that removes "from" field...')
|
||||
mailingService.config.beforeSend = async (options: any, email: any) => {
|
||||
delete options.from
|
||||
return options
|
||||
}
|
||||
|
||||
try {
|
||||
await mailingService.processEmails()
|
||||
console.log('❌ Should have thrown error for missing "from"')
|
||||
} catch (error: any) {
|
||||
if (error.message.includes('must not remove the "from" property')) {
|
||||
console.log('✅ Correctly caught missing "from" field')
|
||||
} else {
|
||||
console.log('❌ Unexpected error:', error.message)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n📝 Test: Hook that empties "to" array...')
|
||||
mailingService.config.beforeSend = async (options: any, email: any) => {
|
||||
options.to = []
|
||||
return options
|
||||
}
|
||||
|
||||
try {
|
||||
await mailingService.processEmails()
|
||||
console.log('❌ Should have thrown error for empty "to"')
|
||||
} catch (error: any) {
|
||||
if (error.message.includes('must not remove or empty the "to" property')) {
|
||||
console.log('✅ Correctly caught empty "to" array')
|
||||
} else {
|
||||
console.log('❌ Unexpected error:', error.message)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n📝 Test: Hook that removes "subject"...')
|
||||
mailingService.config.beforeSend = async (options: any, email: any) => {
|
||||
delete options.subject
|
||||
return options
|
||||
}
|
||||
|
||||
try {
|
||||
await mailingService.processEmails()
|
||||
console.log('❌ Should have thrown error for missing "subject"')
|
||||
} catch (error: any) {
|
||||
if (error.message.includes('must not remove the "subject" property')) {
|
||||
console.log('✅ Correctly caught missing "subject" field')
|
||||
} else {
|
||||
console.log('❌ Unexpected error:', error.message)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n📝 Test: Hook that removes both "html" and "text"...')
|
||||
mailingService.config.beforeSend = async (options: any, email: any) => {
|
||||
delete options.html
|
||||
delete options.text
|
||||
return options
|
||||
}
|
||||
|
||||
try {
|
||||
await mailingService.processEmails()
|
||||
console.log('❌ Should have thrown error for missing content')
|
||||
} catch (error: any) {
|
||||
if (error.message.includes('must not remove both "html" and "text" properties')) {
|
||||
console.log('✅ Correctly caught missing content fields')
|
||||
} else {
|
||||
console.log('❌ Unexpected error:', error.message)
|
||||
}
|
||||
}
|
||||
|
||||
// Restore original hook
|
||||
mailingService.config.beforeSend = originalBeforeSend
|
||||
|
||||
console.log('\n✅ All validation tests completed!\n')
|
||||
|
||||
// Clean up
|
||||
await payload.delete({
|
||||
collection: 'emails',
|
||||
id: email.id
|
||||
})
|
||||
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
testHookValidation().catch(console.error)
|
||||
Reference in New Issue
Block a user