feat: add core modules - dienstService, whatsappApi, messageHandler, webhook server
This commit is contained in:
parent
f8a708c9d0
commit
3e6b33f103
4 changed files with 163 additions and 0 deletions
24
src/dienstService.js
Normal file
24
src/dienstService.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
let dienstenCache = null
|
||||||
|
|
||||||
|
function loadDiensten() {
|
||||||
|
if (dienstenCache) return dienstenCache
|
||||||
|
const jsonPath = process.env.DIENSTEN_JSON
|
||||||
|
const raw = fs.readFileSync(jsonPath, 'utf-8')
|
||||||
|
dienstenCache = JSON.parse(raw)
|
||||||
|
return dienstenCache
|
||||||
|
}
|
||||||
|
|
||||||
|
function findDienst(dienstnummer) {
|
||||||
|
const diensten = loadDiensten()
|
||||||
|
return diensten.find(d => d.dienstnummer === dienstnummer) || null
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPngFilePaths(dienst) {
|
||||||
|
const pngDir = process.env.DIENSTEN_PNG
|
||||||
|
return dienst.paginas.map(p => path.join(pngDir, p.bestandsnaam))
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { loadDiensten, findDienst, getPngFilePaths }
|
||||||
31
src/index.js
Normal file
31
src/index.js
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
require('dotenv').config()
|
||||||
|
const express = require('express')
|
||||||
|
const { handleWebhook } = require('./messageHandler')
|
||||||
|
const { loadDiensten } = require('./dienstService')
|
||||||
|
|
||||||
|
const app = express()
|
||||||
|
app.use(express.json({ limit: '10mb' }))
|
||||||
|
|
||||||
|
app.post('/webhook', async (req, res) => {
|
||||||
|
try {
|
||||||
|
await handleWebhook(req.body)
|
||||||
|
res.json({ success: true })
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Webhook processing error:', err.message)
|
||||||
|
res.status(500).json({ success: false, error: err.message })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/health', (req, res) => {
|
||||||
|
res.json({ status: 'ok' })
|
||||||
|
})
|
||||||
|
|
||||||
|
const PORT = process.env.WEBHOOK_PORT || 3002
|
||||||
|
|
||||||
|
loadDiensten()
|
||||||
|
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log(`dienst-bot listening on port ${PORT}`)
|
||||||
|
console.log(`Allowed group: ${process.env.ALLOWED_GROUP}`)
|
||||||
|
console.log(`Bot name: ${process.env.BOT_NAME}`)
|
||||||
|
})
|
||||||
62
src/messageHandler.js
Normal file
62
src/messageHandler.js
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
const { findDienst, getPngFilePaths } = require('./dienstService')
|
||||||
|
const { sendTextMessage, sendImageMessage, notifyAdmin } = require('./whatsappApi')
|
||||||
|
|
||||||
|
const BOT_NAME = (process.env.BOT_NAME || 'EdGpt').toLowerCase()
|
||||||
|
const ALLOWED_GROUP = process.env.ALLOWED_GROUP
|
||||||
|
|
||||||
|
function extractDienstnummer(body) {
|
||||||
|
const match = body.match(/\b(\d{4})\b/)
|
||||||
|
return match ? match[1] : null
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBotMentioned(message) {
|
||||||
|
if (message._data?.mentionedJidList?.length > 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (message.body && message.body.toLowerCase().includes(`@${BOT_NAME}`)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleWebhook(payload) {
|
||||||
|
if (payload.dataType !== 'message') return
|
||||||
|
if (payload.sessionId !== process.env.WHATSAPP_SESSION) return
|
||||||
|
|
||||||
|
const message = payload.data?.message
|
||||||
|
if (!message) return
|
||||||
|
if (message.fromMe) return
|
||||||
|
if (message.from !== ALLOWED_GROUP) return
|
||||||
|
if (!isBotMentioned(message)) return
|
||||||
|
|
||||||
|
const dienstnummer = extractDienstnummer(message.body || '')
|
||||||
|
if (!dienstnummer) return
|
||||||
|
|
||||||
|
const author = message.author
|
||||||
|
if (!author) return
|
||||||
|
|
||||||
|
const dienst = findDienst(dienstnummer)
|
||||||
|
if (!dienst) {
|
||||||
|
await sendTextMessage(author, `Dienstnummer ${dienstnummer} niet gevonden.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const pngPaths = getPngFilePaths(dienst)
|
||||||
|
if (!pngPaths || pngPaths.length === 0) {
|
||||||
|
await sendTextMessage(author, `Geen pagina's gevonden voor dienst ${dienstnummer}.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const pngPath of pngPaths) {
|
||||||
|
const filename = pngPath.split('/').pop()
|
||||||
|
try {
|
||||||
|
await sendImageMessage(author, pngPath, filename)
|
||||||
|
} catch (err) {
|
||||||
|
const errorMsg = `Fout bij verzenden ${filename} naar ${author}: ${err.message}`
|
||||||
|
console.error(errorMsg)
|
||||||
|
await notifyAdmin(errorMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { handleWebhook }
|
||||||
46
src/whatsappApi.js
Normal file
46
src/whatsappApi.js
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
const axios = require('axios')
|
||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
const API_BASE = process.env.WHATSAPP_API_ENDPOINT
|
||||||
|
const SESSION = process.env.WHATSAPP_SESSION
|
||||||
|
|
||||||
|
async function sendTextMessage(chatId, text) {
|
||||||
|
const url = `${API_BASE}/client/sendMessage/${SESSION}`
|
||||||
|
const response = await axios.post(url, {
|
||||||
|
chatId,
|
||||||
|
contentType: 'string',
|
||||||
|
content: text
|
||||||
|
})
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendImageMessage(chatId, filePath, filename) {
|
||||||
|
const fileBuffer = fs.readFileSync(filePath)
|
||||||
|
const base64Data = fileBuffer.toString('base64')
|
||||||
|
const url = `${API_BASE}/client/sendMessage/${SESSION}`
|
||||||
|
const response = await axios.post(url, {
|
||||||
|
chatId,
|
||||||
|
contentType: 'MessageMedia',
|
||||||
|
content: {
|
||||||
|
mimetype: 'image/png',
|
||||||
|
data: base64Data,
|
||||||
|
filename: filename
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
|
||||||
|
async function notifyAdmin(errorText) {
|
||||||
|
const adminNumber = process.env.ADMIN_NUMBER
|
||||||
|
if (!adminNumber) {
|
||||||
|
console.error('ADMIN_NUMBER not configured, skipping admin notification')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await sendTextMessage(adminNumber, `[dienst-bot fout] ${errorText}`)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to notify admin:', err.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { sendTextMessage, sendImageMessage, notifyAdmin }
|
||||||
Loading…
Reference in a new issue