Webhookのメッセージをカスタマイズできるように

This commit is contained in:
CyberRex
2026-05-27 10:59:58 +09:00
parent 2a4050d442
commit 38acbd35bb
14 changed files with 994 additions and 49 deletions

View File

@@ -5,6 +5,10 @@ import { query } from '../../db/pool.js';
import { requireAuth } from '../../middleware/auth.js';
import { badRequest, notFound } from '../../utils/httpErrors.js';
import { normalizeHttpsUrl } from '../../utils/urlPolicy.js';
import {
serializeWebhookMessageSettings,
validateWebhookMessageTemplate,
} from './webhookMessageSettings.js';
const router = new Hono();
@@ -25,6 +29,10 @@ const pushSubscriptionStatusSchema = z.object({
endpoint: z.string().trim().url().max(2048),
});
const webhookMessageSettingsSchema = z.object({
webhookMessageTemplate: z.string().max(2000),
});
function serializeWebhook(row) {
return {
notificationMethodId: row.notification_method_id,
@@ -39,22 +47,31 @@ router.use('*', requireAuth);
router.get('/', async (c) => {
const user = c.get('user');
const result = await query(
`SELECT notification_method_id,
alias,
url,
created_at,
updated_at
FROM notification_methods
WHERE user_id = $1
AND notification_type = 'webhook'
ORDER BY created_at DESC`,
[user.user_id],
);
const [webhookResult, settingsResult] = await Promise.all([
query(
`SELECT notification_method_id,
alias,
url,
created_at,
updated_at
FROM notification_methods
WHERE user_id = $1
AND notification_type = 'webhook'
ORDER BY created_at DESC`,
[user.user_id],
),
query(
`SELECT webhook_message_template, timezone
FROM user_notification_settings
WHERE user_id = $1`,
[user.user_id],
),
]);
return c.json({
webhooks: result.rows.map(serializeWebhook),
webhooks: webhookResult.rows.map(serializeWebhook),
vapidPublicKey: env.vapidPublicKey,
webhookMessageSettings: serializeWebhookMessageSettings(settingsResult.rows[0]),
});
});
@@ -139,6 +156,42 @@ router.delete('/webhooks/:methodId', async (c) => {
return c.json({ ok: true });
});
router.put('/webhook-message-settings', async (c) => {
const body = webhookMessageSettingsSchema.safeParse(await c.req.json().catch(() => null));
if (!body.success) {
throw badRequest('入力内容を確認してください', body.error.flatten());
}
let webhookMessageTemplate;
try {
webhookMessageTemplate = validateWebhookMessageTemplate(body.data.webhookMessageTemplate);
} catch (error) {
throw badRequest(error.message);
}
const result = await query(
`INSERT INTO user_notification_settings (user_id, webhook_message_template)
VALUES ($1, $2)
ON CONFLICT (user_id)
DO UPDATE SET webhook_message_template = EXCLUDED.webhook_message_template
RETURNING webhook_message_template, timezone`,
[c.get('user').user_id, webhookMessageTemplate],
);
return c.json({ webhookMessageSettings: serializeWebhookMessageSettings(result.rows[0]) });
});
router.delete('/webhook-message-settings', async (c) => {
const result = await query(
`UPDATE user_notification_settings
SET webhook_message_template = NULL
WHERE user_id = $1
RETURNING webhook_message_template, timezone`,
[c.get('user').user_id],
);
return c.json({ webhookMessageSettings: serializeWebhookMessageSettings(result.rows[0]) });
});
router.post('/push-subscription-status', async (c) => {
const body = pushSubscriptionStatusSchema.safeParse(await c.req.json().catch(() => null));
if (!body.success) {