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