feat: auto-disable store after notification and improve ntfy payloads

This commit is contained in:
2025-11-09 21:25:50 +01:00
parent 7b1e4a1f03
commit e12bba63b9
2 changed files with 50 additions and 8 deletions

View File

@@ -33,7 +33,8 @@ async function sendNtfyNotification(adminNtfy, userNtfy, payload) {
const url = `${server}/${topic}`; const url = `${server}/${topic}`;
const headers = { const headers = {
Title: payload.title, Title: payload.title,
Priority: payload.priority || 'default' Priority: payload.priority || 'default',
'Content-Type': 'text/plain; charset=utf-8'
}; };
if (adminNtfy.username && adminNtfy.password) { if (adminNtfy.username && adminNtfy.password) {
const credentials = Buffer.from(`${adminNtfy.username}:${adminNtfy.password}`).toString('base64'); const credentials = Buffer.from(`${adminNtfy.username}:${adminNtfy.password}`).toString('base64');
@@ -51,8 +52,8 @@ async function sendTelegramNotification(adminTelegram, userTelegram, payload) {
endpoint, endpoint,
{ {
chat_id: userTelegram.chatId, chat_id: userTelegram.chatId,
text: `${payload.title}\n${payload.message}`, text: payload.message,
disable_web_page_preview: true disable_web_page_preview: false
}, },
{ timeout: 15000 } { timeout: 15000 }
); );
@@ -71,22 +72,25 @@ async function notifyChannels(profileId, template) {
} }
} }
async function sendSlotNotification({ profileId, storeName, pickupDate, onlyNotify, booked }) { async function sendSlotNotification({ profileId, storeName, pickupDate, onlyNotify, booked, storeId }) {
const dateLabel = formatDateLabel(pickupDate); const dateLabel = formatDateLabel(pickupDate);
const title = onlyNotify const title = onlyNotify
? `Slot verfügbar bei ${storeName}` ? `Slot verfügbar bei ${storeName}`
: booked : booked
? `Slot gebucht bei ${storeName}` ? `Slot gebucht bei ${storeName}`
: `Slot gefunden bei ${storeName}`; : `Slot gefunden bei ${storeName}`;
const message = onlyNotify const baseMessage = onlyNotify
? `Es wurde ein freier Slot am ${dateLabel} entdeckt.` ? `Es wurde ein freier Slot am ${dateLabel} entdeckt.`
: booked : booked
? `Der Slot am ${dateLabel} wurde erfolgreich gebucht.` ? `Der Slot am ${dateLabel} wurde erfolgreich gebucht.`
: `Es wurde ein Slot am ${dateLabel} gefunden.`; : `Es wurde ein Slot am ${dateLabel} gefunden.`;
const storeLink = storeId ? `https://foodsharing.de/store/${storeId}` : null;
const fullMessage = storeLink ? `${title}\n${baseMessage}\n${storeLink}` : `${title}\n${baseMessage}`;
await notifyChannels(profileId, { await notifyChannels(profileId, {
title, title,
message, message: fullMessage,
link: storeLink,
priority: booked ? 'high' : 'default' priority: booked ? 'high' : 'default'
}); });
} }

View File

@@ -3,6 +3,7 @@ const foodsharingClient = require('./foodsharingClient');
const sessionStore = require('./sessionStore'); const sessionStore = require('./sessionStore');
const { DEFAULT_SETTINGS } = require('./adminConfig'); const { DEFAULT_SETTINGS } = require('./adminConfig');
const notificationService = require('./notificationService'); const notificationService = require('./notificationService');
const { readConfig, writeConfig } = require('./configStore');
const weekdayMap = { const weekdayMap = {
Montag: 'Monday', Montag: 'Monday',
@@ -55,6 +56,34 @@ function resolveSettings(settings) {
}; };
} }
function deactivateEntryInMemory(entry) {
if (entry) {
entry.active = false;
}
}
function persistEntryDeactivation(profileId, entryId) {
if (!profileId || !entryId) {
return;
}
try {
const config = readConfig(profileId);
let changed = false;
const updated = config.map((item) => {
if (String(item?.id) === String(entryId) && item?.active !== false) {
changed = true;
return { ...item, active: false };
}
return item;
});
if (changed) {
writeConfig(profileId, updated);
}
} catch (error) {
console.error(`[CONFIG] Konnte Eintrag ${entryId} für Profil ${profileId} nicht deaktivieren:`, error.message);
}
}
async function ensureSession(session) { async function ensureSession(session) {
const profileId = session.profile?.id; const profileId = session.profile?.id;
if (!profileId) { if (!profileId) {
@@ -166,8 +195,11 @@ async function processBooking(session, entry, pickup) {
storeName, storeName,
pickupDate: pickup.date, pickupDate: pickup.date,
onlyNotify: true, onlyNotify: true,
booked: false booked: false,
storeId: entry.id
}); });
deactivateEntryInMemory(entry);
persistEntryDeactivation(session.profile.id, entry.id);
return; return;
} }
@@ -185,14 +217,20 @@ async function processBooking(session, entry, pickup) {
storeName, storeName,
pickupDate: pickup.date, pickupDate: pickup.date,
onlyNotify: false, onlyNotify: false,
booked: true booked: true,
storeId: entry.id
}); });
deactivateEntryInMemory(entry);
persistEntryDeactivation(session.profile.id, entry.id);
} catch (error) { } catch (error) {
console.error(`[ERROR] Buchung für ${storeName} am ${readableDate} fehlgeschlagen:`, error.message); console.error(`[ERROR] Buchung für ${storeName} am ${readableDate} fehlgeschlagen:`, error.message);
} }
} }
async function checkEntry(sessionId, entry, settings) { async function checkEntry(sessionId, entry, settings) {
if (entry?.active === false) {
return;
}
const session = sessionStore.get(sessionId); const session = sessionStore.get(sessionId);
if (!session) { if (!session) {
return; return;