Files
Toju/server/src/routes/device-tokens.ts
2026-06-05 18:34:01 +02:00

74 lines
1.9 KiB
TypeScript

import { Router } from 'express';
import {
dispatchPushToUser,
listDeviceTokensForUser,
upsertDeviceToken
} from '../services/push-dispatch.service';
import { requireAuth } from '../middleware/require-auth';
export interface DeviceTokenRecord {
userId: string;
platform: 'ios' | 'android';
token: string;
updatedAt: number;
}
const router = Router();
router.use(requireAuth);
router.post('/', async (req, res) => {
const { userId, platform, token } = req.body as Partial<DeviceTokenRecord>;
if (!userId || !token || (platform !== 'ios' && platform !== 'android')) {
return res.status(400).json({ error: 'Missing or invalid userId/platform/token' });
}
if (userId !== req.authUserId) {
return res.status(403).json({ error: 'Not authorized', errorCode: 'NOT_AUTHORIZED' });
}
await upsertDeviceToken({ userId, platform, token });
res.status(201).json({ ok: true });
});
router.get('/:userId', async (req, res) => {
if (req.params.userId !== req.authUserId) {
return res.status(403).json({ error: 'Not authorized', errorCode: 'NOT_AUTHORIZED' });
}
const records = await listDeviceTokensForUser(req.params.userId);
res.json({
tokens: records.map((record) => ({
userId: record.userId,
platform: record.platform,
token: record.token,
updatedAt: record.updatedAt
}))
});
});
router.post('/:userId/dispatch', async (req, res) => {
if (req.params.userId !== req.authUserId) {
return res.status(403).json({ error: 'Not authorized', errorCode: 'NOT_AUTHORIZED' });
}
const { title, body, data } = req.body as {
title?: string;
body?: string;
data?: Record<string, string>;
};
if (!title || !body) {
return res.status(400).json({ error: 'Missing title/body' });
}
await dispatchPushToUser(req.params.userId, { title, body, data });
res.json({ ok: true });
});
export default router;