Skip to content

Instantly share code, notes, and snippets.

@losh11
Created August 6, 2025 11:49
Show Gist options
  • Select an option

  • Save losh11/fdba5b6610f6d943e4e5ca129b68ff84 to your computer and use it in GitHub Desktop.

Select an option

Save losh11/fdba5b6610f6d943e4e5ca129b68ff84 to your computer and use it in GitHub Desktop.
import express from 'express';
import * as argon2 from 'argon2';
import {
sendNotificationToUsers,
sendNotificationToOldUsers,
sendNotificationToEmptyUsers,
sendNotificationToUsersTest,
} from '../utils/notifications';
interface ISendNotificationRequest {
password: string;
title: string;
body: string;
country?: string;
currency?: string;
lng?: string;
osVersion?: string;
isIOS?: boolean;
}
interface ISendNotificationRequestTest extends ISendNotificationRequest {
deviceToken: string;
}
const router = express.Router();
// Middleware: authenticate admin via password
async function authenticateAdmin(
req: express.Request,
res: express.Response,
next: express.NextFunction
) {
const { password } = req.body as { password?: string };
const hashedPassword = process.env.ADMIN_PASSWORD_HASH;
if (!hashedPassword || !password) {
return res.status(401).json({ success: false, error: 'Invalid password' });
}
try {
const valid = await argon2.verify(hashedPassword, password);
if (!valid) {
return res.status(401).json({ success: false, error: 'Invalid password' });
}
next();
} catch (err) {
return res.status(500).json({ success: false, error: String(err) });
}
}
// Middleware: validate title and body, optionally deviceToken
function validateNotificationPayload(requireDeviceToken = false) {
return (
req: express.Request,
res: express.Response,
next: express.NextFunction
) => {
const { title, body } = req.body as { title?: string; body?: string };
if (!title || !body) {
return res.status(400).json({ success: false, error: 'Title and body are required' });
}
if (requireDeviceToken) {
const { deviceToken } = req.body as { deviceToken?: string };
if (!deviceToken) {
return res.status(400).json({ success: false, error: 'deviceToken is required' });
}
}
next();
};
}
// Common builder for params object
function buildParams(body: any) {
const { country, currency, lng, osVersion } = body;
return {
...(country && { country }),
...(currency && { currency }),
...(lng && { lng }),
...(osVersion && { osVersion }),
};
}
// Route: send to all users
router.post(
'/send-notif-to-users',
authenticateAdmin,
validateNotificationPayload(),
async (req, res) => {
try {
const {
title,
body,
isIOS,
} = req.body as ISendNotificationRequest;
const params = buildParams(req.body);
const result = await sendNotificationToUsers(title, body, params, isIOS);
res.json(result);
} catch (error) {
res.status(500).json({ success: false, error: String(error) });
}
}
);
// Route: send to old users
router.post(
'/send-notif-to-old-users',
authenticateAdmin,
validateNotificationPayload(),
async (req, res) => {
try {
const { title, body, isIOS } = req.body as ISendNotificationRequest;
const result = await sendNotificationToOldUsers(title, body, isIOS);
res.json(result);
} catch (error) {
res.status(500).json({ success: false, error: String(error) });
}
}
);
// Route: send to users with empty profiles
router.post(
'/send-notif-to-empty-users',
authenticateAdmin,
validateNotificationPayload(),
async (req, res) => {
try {
const { title, body, isIOS } = req.body as ISendNotificationRequest;
const result = await sendNotificationToEmptyUsers(title, body, isIOS);
res.json(result);
} catch (error) {
res.status(500).json({ success: false, error: String(error) });
}
}
);
// Route: generate password hash
router.post('/generate-hash', async (req, res) => {
try {
const { password } = req.body as { password?: string };
if (!password) {
return res.status(400).json({ success: false, error: 'Password is required' });
}
const hash = await argon2.hash(password);
res.json({ success: true, hash });
} catch (error) {
res.status(500).json({ success: false, error: String(error) });
}
});
// Route: send to a single test device
router.post(
'/send-notif-to-users-test',
authenticateAdmin,
validateNotificationPayload(true),
async (req, res) => {
try {
const {
title,
body,
isIOS,
deviceToken,
} = req.body as ISendNotificationRequestTest;
const params = buildParams(req.body);
const result = await sendNotificationToUsersTest(
deviceToken,
title,
body,
params,
isIOS
);
res.json(result);
} catch (error) {
res.status(500).json({ success: false, error: String(error) });
}
}
);
export default router;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment