Temporary Webhook for Recruitment when new Application Posted. #77

Open
opened 2025-12-13 01:48:37 -06:00 by EagleTrooper · 0 comments
Owner

Request

When a new application is created

Send an Recruiter Channel Post to a discord webhook.

This is until the Milsim Integration Bot is built out and can handle cron jobs or event handler to post to Discord.

Rough Code example

Discord Notification Function

// utils/discordApplicationNotifier.js
import fetch from 'node-fetch';
import { DISCORD_WEBHOOK_URL } from '../config/discord.js';

export async function sendOrUpdateApplicationNotification(type, application) {
    let embed;
    if (type === 'submitted') {
        embed = {
            title: '📨 New Application Submitted',
            color: 0x3498db,
            fields: [
                { name: 'Applicant ID', value: `${application.member_id}`, inline: true },
                { name: 'Application ID', value: `${application.id}`, inline: true },
                { name: 'Version', value: `${application.app_version}`, inline: true },
                {
                    name: 'Submitted At',
                    value: `<t:${Math.floor(new Date(application.submitted_at).getTime() / 1000)}:F>`
                }
            ],
            footer: { text: 'Recruitment System' }
        };
    } else if (type === 'approved') {
        embed = {
            title: '✅ Application Approved',
            color: 0x2ecc71,
            fields: [
                { name: 'Applicant ID', value: `${application.member_id}`, inline: true },
                { name: 'Application ID', value: `${application.id}`, inline: true },
                {
                    name: 'Approved At',
                    value: `<t:${Math.floor(new Date(application.approved_at).getTime() / 1000)}:F>`
                }
            ],
            footer: { text: 'Recruitment System' }
        };
    } else if (type === 'denied') {
        embed = {
            title: '❌ Application Denied',
            color: 0xe74c3c,
            fields: [
                { name: 'Applicant ID', value: `${application.member_id}`, inline: true },
                { name: 'Application ID', value: `${application.id}`, inline: true },
                {
                    name: 'Denied At',
                    value: `<t:${Math.floor(new Date(application.denied_at).getTime() / 1000)}:F>`
                }
            ],
            footer: { text: 'Recruitment System' }
        };
    }

    const url = application.discord_message_id
        ? `${DISCORD_WEBHOOK_URL}/messages/${application.discord_message_id}`
        : DISCORD_WEBHOOK_URL;

    const method = application.discord_message_id ? 'PATCH' : 'POST';

    const response = await fetch(url, {
        method,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            username: 'Application Bot',
            embeds: [embed]
        })
    });

    const data = await response.json();

    // If this was a new post, store the message ID for future updates
    if (!application.discord_message_id && data.id) {
        return data.id;
    }

    return application.discord_message_id;
}

New Application

router.post('/applications', async (req, res) => {
    const { member_id, app_version, app_data } = req.body;

    const [result] = await db.query(
        `INSERT INTO applications (member_id, app_version, app_data)
         VALUES (?, ?, ?)`,
        [member_id, app_version, JSON.stringify(app_data)]
    );

    const [[application]] = await db.query(
        `SELECT * FROM applications WHERE id = ?`,
        [result.insertId]
    );

    // Post to Discord
    const messageId = await sendOrUpdateApplicationNotification('submitted', application);

    // Save Discord message ID
    await db.query(
        `UPDATE applications SET discord_message_id = ? WHERE id = ?`,
        [messageId, application.id]
    );

    res.json({ success: true, application_id: application.id });
});

Accepted Event

router.patch('/applications/:id/approve', async (req, res) => {
    const { id } = req.params;

    await db.query(
        `UPDATE applications SET approved_at = NOW() WHERE id = ? AND denied_at IS NULL`,
        [id]
    );

    const [[application]] = await db.query(
        `SELECT * FROM applications WHERE id = ?`,
        [id]
    );

    await sendOrUpdateApplicationNotification('approved', application);

    res.json({ success: true });
});

Denied Event

router.patch('/applications/:id/deny', async (req, res) => {
    const { id } = req.params;

    await db.query(
        `UPDATE applications SET denied_at = NOW() WHERE id = ? AND approved_at IS NULL`,
        [id]
    );

    const [[application]] = await db.query(
        `SELECT * FROM applications WHERE id = ?`,
        [id]
    );

    await sendOrUpdateApplicationNotification('denied', application);

    res.json({ success: true });
});

All code above is an EXAMPLE and should not be used exactly.

Also should probably be placed in a place where it can easily be identified and removed if more appropriate system is in place.

## Request When a new application is created Send an Recruiter Channel Post to a discord webhook. This is until the Milsim Integration Bot is built out and can handle cron jobs or event handler to post to Discord. Rough Code example Discord Notification Function ```js // utils/discordApplicationNotifier.js import fetch from 'node-fetch'; import { DISCORD_WEBHOOK_URL } from '../config/discord.js'; export async function sendOrUpdateApplicationNotification(type, application) { let embed; if (type === 'submitted') { embed = { title: '📨 New Application Submitted', color: 0x3498db, fields: [ { name: 'Applicant ID', value: `${application.member_id}`, inline: true }, { name: 'Application ID', value: `${application.id}`, inline: true }, { name: 'Version', value: `${application.app_version}`, inline: true }, { name: 'Submitted At', value: `<t:${Math.floor(new Date(application.submitted_at).getTime() / 1000)}:F>` } ], footer: { text: 'Recruitment System' } }; } else if (type === 'approved') { embed = { title: '✅ Application Approved', color: 0x2ecc71, fields: [ { name: 'Applicant ID', value: `${application.member_id}`, inline: true }, { name: 'Application ID', value: `${application.id}`, inline: true }, { name: 'Approved At', value: `<t:${Math.floor(new Date(application.approved_at).getTime() / 1000)}:F>` } ], footer: { text: 'Recruitment System' } }; } else if (type === 'denied') { embed = { title: '❌ Application Denied', color: 0xe74c3c, fields: [ { name: 'Applicant ID', value: `${application.member_id}`, inline: true }, { name: 'Application ID', value: `${application.id}`, inline: true }, { name: 'Denied At', value: `<t:${Math.floor(new Date(application.denied_at).getTime() / 1000)}:F>` } ], footer: { text: 'Recruitment System' } }; } const url = application.discord_message_id ? `${DISCORD_WEBHOOK_URL}/messages/${application.discord_message_id}` : DISCORD_WEBHOOK_URL; const method = application.discord_message_id ? 'PATCH' : 'POST'; const response = await fetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: 'Application Bot', embeds: [embed] }) }); const data = await response.json(); // If this was a new post, store the message ID for future updates if (!application.discord_message_id && data.id) { return data.id; } return application.discord_message_id; } ``` New Application ```js router.post('/applications', async (req, res) => { const { member_id, app_version, app_data } = req.body; const [result] = await db.query( `INSERT INTO applications (member_id, app_version, app_data) VALUES (?, ?, ?)`, [member_id, app_version, JSON.stringify(app_data)] ); const [[application]] = await db.query( `SELECT * FROM applications WHERE id = ?`, [result.insertId] ); // Post to Discord const messageId = await sendOrUpdateApplicationNotification('submitted', application); // Save Discord message ID await db.query( `UPDATE applications SET discord_message_id = ? WHERE id = ?`, [messageId, application.id] ); res.json({ success: true, application_id: application.id }); }); ``` Accepted Event ```js router.patch('/applications/:id/approve', async (req, res) => { const { id } = req.params; await db.query( `UPDATE applications SET approved_at = NOW() WHERE id = ? AND denied_at IS NULL`, [id] ); const [[application]] = await db.query( `SELECT * FROM applications WHERE id = ?`, [id] ); await sendOrUpdateApplicationNotification('approved', application); res.json({ success: true }); }); ``` Denied Event ```js router.patch('/applications/:id/deny', async (req, res) => { const { id } = req.params; await db.query( `UPDATE applications SET denied_at = NOW() WHERE id = ? AND approved_at IS NULL`, [id] ); const [[application]] = await db.query( `SELECT * FROM applications WHERE id = ?`, [id] ); await sendOrUpdateApplicationNotification('denied', application); res.json({ success: true }); }); ``` All code above is an EXAMPLE and should not be used exactly. Also should probably be placed in a place where it can easily be identified and removed if more appropriate system is in place.
EagleTrooper added the Kind/Feature
Priority
Medium
labels 2025-12-13 01:48:37 -06:00
EagleTrooper added the Member Application label 2025-12-14 13:56:43 -06:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: 17th-Ranger-Battalion-ORG/milsim-site-v4#77