import { Router, Request, Response, NextFunction } from 'express'; import { stripPassword } from '../lib/inboxGuard'; import { AppError } from '../middleware/errorHandler'; import { assignSatelliteSchema, campaignListQuerySchema, createCampaignSchema, updateCampaignSchema, } from '../models/campaign.schemas'; import { assignSatellite, CampaignError, createCampaign, deleteCampaign, getCampaignById, listCampaigns, listSatellites, pauseCampaign, resumeCampaign, startCampaign, unassignSatellite, updateCampaign, } from '../services/campaign.service'; const router = Router(); function handleCampaignError(err: unknown, next: NextFunction) { if (err instanceof CampaignError) { next(new AppError(err.statusCode, err.message)); return; } next(err); } function sanitizeCampaign(campaign: Awaited>) { return { ...campaign, primaryMailbox: stripPassword(campaign.primaryMailbox), satellites: campaign.satellites.map((s) => ({ ...s, satelliteMailbox: stripPassword(s.satelliteMailbox), })), }; } router.post('/', async (req: Request, res: Response, next: NextFunction) => { try { const data = createCampaignSchema.parse(req.body); const campaign = await createCampaign(data); res.status(201).json(sanitizeCampaign(campaign)); } catch (err) { handleCampaignError(err, next); } }); router.get('/', async (req: Request, res: Response, next: NextFunction) => { try { const filters = campaignListQuerySchema.parse(req.query); const campaigns = await listCampaigns(filters); res.json( campaigns.map((c) => ({ ...c, primaryMailbox: stripPassword(c.primaryMailbox), satellites: c.satellites.map((s) => ({ ...s, satelliteMailbox: stripPassword(s.satelliteMailbox), })), })), ); } catch (err) { next(err); } }); router.get('/:id', async (req: Request, res: Response, next: NextFunction) => { try { const campaign = await getCampaignById(req.params.id); res.json(sanitizeCampaign(campaign)); } catch (err) { handleCampaignError(err, next); } }); router.patch('/:id', async (req: Request, res: Response, next: NextFunction) => { try { const data = updateCampaignSchema.parse(req.body); const campaign = await updateCampaign(req.params.id, data); res.json({ ...campaign, primaryMailbox: stripPassword(campaign.primaryMailbox), satellites: campaign.satellites.map((s) => ({ ...s, satelliteMailbox: stripPassword(s.satelliteMailbox), })), }); } catch (err) { handleCampaignError(err, next); } }); router.delete('/:id', async (req: Request, res: Response, next: NextFunction) => { try { await deleteCampaign(req.params.id); res.status(204).send(); } catch (err) { handleCampaignError(err, next); } }); router.post('/:id/start', async (req: Request, res: Response, next: NextFunction) => { try { const campaign = await startCampaign(req.params.id); res.json({ ...campaign, primaryMailbox: stripPassword(campaign.primaryMailbox), satellites: campaign.satellites.map((s) => ({ ...s, satelliteMailbox: stripPassword(s.satelliteMailbox), })), }); } catch (err) { handleCampaignError(err, next); } }); router.post('/:id/pause', async (req: Request, res: Response, next: NextFunction) => { try { const campaign = await pauseCampaign(req.params.id); res.json(sanitizeCampaign(campaign)); } catch (err) { handleCampaignError(err, next); } }); router.post('/:id/resume', async (req: Request, res: Response, next: NextFunction) => { try { const campaign = await resumeCampaign(req.params.id); res.json(sanitizeCampaign(campaign)); } catch (err) { handleCampaignError(err, next); } }); router.get('/:id/satellites', async (req: Request, res: Response, next: NextFunction) => { try { const satellites = await listSatellites(req.params.id); res.json( satellites.map((s) => ({ ...s, satelliteMailbox: stripPassword(s.satelliteMailbox), })), ); } catch (err) { handleCampaignError(err, next); } }); router.post('/:id/satellites', async (req: Request, res: Response, next: NextFunction) => { try { const { mailboxId, weight } = assignSatelliteSchema.parse(req.body); const link = await assignSatellite(req.params.id, mailboxId, weight); res.status(201).json({ ...link, satelliteMailbox: stripPassword(link.satelliteMailbox), }); } catch (err) { handleCampaignError(err, next); } }); router.delete( '/:id/satellites/:mailboxId', async (req: Request, res: Response, next: NextFunction) => { try { await unassignSatellite(req.params.id, req.params.mailboxId); res.status(204).send(); } catch (err) { handleCampaignError(err, next); } }, ); export default router;