warmbox/apps/api/src/routes/campaigns.routes.ts

183 lines
4.9 KiB
TypeScript

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<ReturnType<typeof getCampaignById>>) {
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;