graph + mail dispatcher, test-email endpoint, notifications global
This commit is contained in:
+15
@@ -0,0 +1,15 @@
|
||||
import type { Endpoint } from 'payload';
|
||||
/**
|
||||
* Custom endpoint: send a test email to a given address through whatever
|
||||
* transport is currently active (SMTP or Graph — mailAdapter reads the panel
|
||||
* setting per send, so the test exercises the REAL path a form email would
|
||||
* take). Mounted at POST /api/ipal/test-email.
|
||||
*
|
||||
* Admin-only: uses payload.sendEmail (server-side), and requires an
|
||||
* authenticated admin user — a test-send button must never be open to the
|
||||
* public (it would be an open relay / spam vector).
|
||||
*
|
||||
* Returns the adapter's own result so the panel can show exactly what happened,
|
||||
* including the transport-specific error (SMTP auth failure, Graph 401, etc.).
|
||||
*/
|
||||
export declare const testEmailEndpoint: Endpoint;
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
import { addDataAndFileToRequest } from 'payload';
|
||||
/**
|
||||
* Custom endpoint: send a test email to a given address through whatever
|
||||
* transport is currently active (SMTP or Graph — mailAdapter reads the panel
|
||||
* setting per send, so the test exercises the REAL path a form email would
|
||||
* take). Mounted at POST /api/ipal/test-email.
|
||||
*
|
||||
* Admin-only: uses payload.sendEmail (server-side), and requires an
|
||||
* authenticated admin user — a test-send button must never be open to the
|
||||
* public (it would be an open relay / spam vector).
|
||||
*
|
||||
* Returns the adapter's own result so the panel can show exactly what happened,
|
||||
* including the transport-specific error (SMTP auth failure, Graph 401, etc.).
|
||||
*/ export const testEmailEndpoint = {
|
||||
handler: async (req)=>{
|
||||
// Auth: only signed-in admins may trigger a send.
|
||||
if (!req.user) {
|
||||
return Response.json({
|
||||
error: 'Unauthorized',
|
||||
ok: false
|
||||
}, {
|
||||
status: 401
|
||||
});
|
||||
}
|
||||
await addDataAndFileToRequest(req);
|
||||
const to = req.data?.to?.trim();
|
||||
if (!to || !/^[^@\s]+@[^\s@][^\s.@]*\.[^\s@]+$/.test(to)) {
|
||||
return Response.json({
|
||||
error: 'Provide a valid recipient address.',
|
||||
ok: false
|
||||
}, {
|
||||
status: 400
|
||||
});
|
||||
}
|
||||
try {
|
||||
const info = await req.payload.sendEmail({
|
||||
html: '<p>This is a test message from <strong>ipal-kit</strong>. If you received it, outbound email is configured correctly.</p>',
|
||||
subject: 'ipal-kit — test email',
|
||||
text: 'This is a test message from ipal-kit. If you received it, outbound email is configured correctly.',
|
||||
to
|
||||
});
|
||||
// Payload's sendEmail resolves with the adapter's result. Our adapters
|
||||
// return { sent: boolean, error?: string }; nodemailer returns info with
|
||||
// messageId. Normalize to a simple ok/message for the panel.
|
||||
const sent = info && typeof info === 'object' && 'sent' in info ? info.sent !== false : true;
|
||||
if (!sent) {
|
||||
const error = info?.error ?? 'Send failed (see server logs).';
|
||||
return Response.json({
|
||||
error,
|
||||
ok: false
|
||||
}, {
|
||||
status: 502
|
||||
});
|
||||
}
|
||||
return Response.json({
|
||||
message: `Test email sent to ${to}.`,
|
||||
ok: true
|
||||
});
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
req.payload.logger.error(`[ipal] Test email failed: ${message}`);
|
||||
return Response.json({
|
||||
error: 'Send failed. Check transport settings and server logs.',
|
||||
ok: false
|
||||
}, {
|
||||
status: 502
|
||||
});
|
||||
}
|
||||
},
|
||||
method: 'post',
|
||||
path: '/ipal/test-email'
|
||||
};
|
||||
|
||||
//# sourceMappingURL=testEmailEndpoint.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../../../../src/modules/email/test/testEmailEndpoint.ts"],"sourcesContent":["import type { Endpoint, PayloadRequest } from 'payload'\n\nimport { addDataAndFileToRequest } from 'payload'\n\n/**\n * Custom endpoint: send a test email to a given address through whatever\n * transport is currently active (SMTP or Graph — mailAdapter reads the panel\n * setting per send, so the test exercises the REAL path a form email would\n * take). Mounted at POST /api/ipal/test-email.\n *\n * Admin-only: uses payload.sendEmail (server-side), and requires an\n * authenticated admin user — a test-send button must never be open to the\n * public (it would be an open relay / spam vector).\n *\n * Returns the adapter's own result so the panel can show exactly what happened,\n * including the transport-specific error (SMTP auth failure, Graph 401, etc.).\n */\nexport const testEmailEndpoint: Endpoint = {\n handler: async (req: PayloadRequest) => {\n // Auth: only signed-in admins may trigger a send.\n if (!req.user) {\n return Response.json({ error: 'Unauthorized', ok: false }, { status: 401 })\n }\n\n await addDataAndFileToRequest(req)\n const to = (req.data?.to as string | undefined)?.trim()\n\n if (!to || !/^[^@\\s]+@[^\\s@][^\\s.@]*\\.[^\\s@]+$/.test(to)) {\n return Response.json(\n { error: 'Provide a valid recipient address.', ok: false },\n { status: 400 },\n )\n }\n\n try {\n const info = await req.payload.sendEmail({\n html: '<p>This is a test message from <strong>ipal-kit</strong>. If you received it, outbound email is configured correctly.</p>',\n subject: 'ipal-kit — test email',\n text: 'This is a test message from ipal-kit. If you received it, outbound email is configured correctly.',\n to,\n })\n\n // Payload's sendEmail resolves with the adapter's result. Our adapters\n // return { sent: boolean, error?: string }; nodemailer returns info with\n // messageId. Normalize to a simple ok/message for the panel.\n const sent =\n info && typeof info === 'object' && 'sent' in info\n ? (info as { sent?: boolean }).sent !== false\n : true\n\n if (!sent) {\n const error = (info as { error?: string })?.error ?? 'Send failed (see server logs).'\n return Response.json({ error, ok: false }, { status: 502 })\n }\n\n return Response.json({ message: `Test email sent to ${to}.`, ok: true })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n req.payload.logger.error(`[ipal] Test email failed: ${message}`)\n return Response.json(\n { error: 'Send failed. Check transport settings and server logs.', ok: false },\n { status: 502 },\n )\n }\n },\n method: 'post',\n path: '/ipal/test-email',\n}\n"],"names":["addDataAndFileToRequest","testEmailEndpoint","handler","req","user","Response","json","error","ok","status","to","data","trim","test","info","payload","sendEmail","html","subject","text","sent","message","err","Error","String","logger","method","path"],"mappings":"AAEA,SAASA,uBAAuB,QAAQ,UAAS;AAEjD;;;;;;;;;;;;CAYC,GACD,OAAO,MAAMC,oBAA8B;IACzCC,SAAS,OAAOC;QACd,kDAAkD;QAClD,IAAI,CAACA,IAAIC,IAAI,EAAE;YACb,OAAOC,SAASC,IAAI,CAAC;gBAAEC,OAAO;gBAAgBC,IAAI;YAAM,GAAG;gBAAEC,QAAQ;YAAI;QAC3E;QAEA,MAAMT,wBAAwBG;QAC9B,MAAMO,KAAMP,IAAIQ,IAAI,EAAED,IAA2BE;QAEjD,IAAI,CAACF,MAAM,CAAC,oCAAoCG,IAAI,CAACH,KAAK;YACxD,OAAOL,SAASC,IAAI,CAClB;gBAAEC,OAAO;gBAAsCC,IAAI;YAAM,GACzD;gBAAEC,QAAQ;YAAI;QAElB;QAEA,IAAI;YACF,MAAMK,OAAO,MAAMX,IAAIY,OAAO,CAACC,SAAS,CAAC;gBACvCC,MAAM;gBACNC,SAAS;gBACTC,MAAM;gBACNT;YACF;YAEA,uEAAuE;YACvE,yEAAyE;YACzE,6DAA6D;YAC7D,MAAMU,OACJN,QAAQ,OAAOA,SAAS,YAAY,UAAUA,OAC1C,AAACA,KAA4BM,IAAI,KAAK,QACtC;YAEN,IAAI,CAACA,MAAM;gBACT,MAAMb,QAAQ,AAACO,MAA6BP,SAAS;gBACrD,OAAOF,SAASC,IAAI,CAAC;oBAAEC;oBAAOC,IAAI;gBAAM,GAAG;oBAAEC,QAAQ;gBAAI;YAC3D;YAEA,OAAOJ,SAASC,IAAI,CAAC;gBAAEe,SAAS,CAAC,mBAAmB,EAAEX,GAAG,CAAC,CAAC;gBAAEF,IAAI;YAAK;QACxE,EAAE,OAAOc,KAAK;YACZ,MAAMD,UAAUC,eAAeC,QAAQD,IAAID,OAAO,GAAGG,OAAOF;YAC5DnB,IAAIY,OAAO,CAACU,MAAM,CAAClB,KAAK,CAAC,CAAC,0BAA0B,EAAEc,SAAS;YAC/D,OAAOhB,SAASC,IAAI,CAClB;gBAAEC,OAAO;gBAA0DC,IAAI;YAAM,GAC7E;gBAAEC,QAAQ;YAAI;QAElB;IACF;IACAiB,QAAQ;IACRC,MAAM;AACR,EAAC"}
|
||||
Reference in New Issue
Block a user