BLUE
PHP 7.4.33
Path:
/var/www/receipt-app-backend-bitkit.dk/httpdocs/dist/controllers
Run
Logout
Edit File
Size: 10.86 KB
Close
/var/www/receipt-app-backend-bitkit.dk/httpdocs/dist/controllers/notificationController.js
Text
Base64
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.deleteAllNotifications = exports.sendPushNotificationToUser = exports.sendPushNotificationToAll = exports.uploadNotificationsCSV = exports.createNotification = exports.rejectNotification = exports.acceptNotification = exports.getPendingNotifications = void 0; const models_1 = require("../models"); const receiptAiService_1 = require("../services/receiptAiService"); const logger_1 = __importDefault(require("../utils/logger")); const models_2 = require("../models"); const firebaseCloudMessagingService_1 = require("../services/firebaseCloudMessagingService"); const notificationService_1 = require("../services/notificationService"); function parseDDMMYYYY(dateStr) { if (!dateStr) return new Date(); const [day, month, year] = dateStr.split("."); if (!day || !month || !year) return new Date(); return new Date(`${year}-${month}-${day}`); } const getPendingNotifications = async (req, res) => { // @ts-ignore const user = req.user; try { const entries = await models_1.Notification.findAll({ where: { userId: user.id, status: "pending" }, order: [["createdAt", "DESC"]], }); logger_1.default.info("Fetched pending notifications", { userId: user.id, count: entries.length, }); res.json({ entries }); } catch (err) { logger_1.default.error("Failed to fetch notifications", { error: err, userId: user.id, }); res.status(500).json({ error: "Failed to fetch notifications." }); } }; exports.getPendingNotifications = getPendingNotifications; const acceptNotification = async (req, res) => { // @ts-ignore const user = req.user; const { id } = req.params; try { const entry = await models_1.Notification.findOne({ where: { id, userId: user.id, status: "pending" }, }); if (!entry) { logger_1.default.warn("Accept notification: Entry not found or already processed", { userId: user.id, entryId: id, }); return res .status(404) .json({ error: "Entry not found or already processed." }); } // Create a bill from the entry const bill = await models_1.Bill.create({ userId: user.id, merchant: entry.merchant || entry.message, // Prefer parsed merchant date: entry.parsedDate, amount: entry.amount, categoryId: 1, // Default category, or map from entry.category if needed tags: [], description: entry.message, // Add notification message as description isPersonal: 0, }); entry.status = "accepted"; await entry.save(); logger_1.default.info("Notification accepted and bill created", { userId: user.id, entryId: id, billId: bill.id, }); res.json({ message: "Notification accepted and bill created.", bill }); } catch (err) { logger_1.default.error("Failed to accept notification", { error: err, userId: user.id, entryId: id, }); res.status(500).json({ error: "Failed to accept notification." }); } }; exports.acceptNotification = acceptNotification; const rejectNotification = async (req, res) => { // @ts-ignore const user = req.user; const { id } = req.params; try { const entry = await models_1.Notification.findOne({ where: { id, userId: user.id, status: "pending" }, }); if (!entry) { logger_1.default.warn("Reject notification: Entry not found or already processed", { userId: user.id, entryId: id, }); return res .status(404) .json({ error: "Entry not found or already processed." }); } entry.status = "rejected"; await entry.save(); logger_1.default.info("Notification rejected", { userId: user.id, entryId: id }); res.json({ message: "Notification rejected." }); } catch (err) { logger_1.default.error("Failed to reject notification", { error: err, userId: user.id, entryId: id, }); res.status(500).json({ error: "Failed to reject notification." }); } }; exports.rejectNotification = rejectNotification; const createNotification = async (req, res) => { // @ts-ignore const user = req.user; const { message } = req.body; if (!message) { logger_1.default.warn("Create notification: Message is required", { body: req.body }); return res.status(400).json({ error: "Message is required." }); } try { const aiParsed = await (0, receiptAiService_1.parseReceiptWithAi)(message); if (aiParsed && typeof aiParsed === "object" && "error" in aiParsed && typeof aiParsed.error === "string") { logger_1.default.warn("Create notification: AI parse failed", { aiParsed }); return res.status(500).json({ error: "Failed to parse message with AI." }); } const data = aiParsed; const parsedDate = data.date ? new Date(String(data.date)) : new Date(); const amount = typeof data.amount === "number" ? data.amount : typeof data.totalAmount === "number" ? data.totalAmount : 0; const entry = await models_1.Notification.create({ userId: user.id, message, parsedDate, amount, merchant: data.merchant != null ? String(data.merchant) : "", category: data.category != null ? String(data.category) : "", status: "pending", createdAt: new Date(), }); logger_1.default.info("Notification created", { userId: user.id, entryId: entry.id }); const currency = "currency" in data ? data.currency : null; res.status(201).json({ entry, aiParsed: data, currency }); } catch (err) { logger_1.default.error("Failed to create notification", { error: err, userId: user.id, body: req.body, }); if (err.message && /gemini|mistral|receipt ai|ai response|mistral_api_key/i.test(String(err.message))) { return res.status(500).json({ error: `AI error: ${err.message}` }); } res.status(500).json({ error: "Failed to create notification." }); } }; exports.createNotification = createNotification; const uploadNotificationsCSV = async (req, res) => { // No auth check, always use userId = 1 const userId = 1; logger_1.default.info("CSV upload started for notifications", { userId }); if (!req.file) { logger_1.default.warn("CSV upload failed: No file provided", { userId }); return res.status(400).json({ error: "CSV file is required." }); } try { const records = (0, notificationService_1.parseCSV)(req.file.buffer); const { successCount, insertedRows, errors } = await (0, notificationService_1.processCSVRecords)(records, userId); logger_1.default.info("CSV upload processed for notifications", { userId, inserted: successCount, errorsCount: errors.length, }); await (0, notificationService_1.sendUploadSummaryPush)(userId); res.json({ inserted: successCount, rows: insertedRows, errors }); } catch (err) { logger_1.default.error("Failed to process CSV file for notifications", { userId, error: err.message, }); res.status(500).json({ error: "Failed to process CSV file.", details: err.message, }); } }; exports.uploadNotificationsCSV = uploadNotificationsCSV; const sendPushNotificationToAll = async (req, res) => { // Set dummy data if not provided const title = "Test Notification"; const body = "This is a test push notification to all users."; try { const tokens = await models_2.UserToken.findAll({ attributes: ["firebase_token"] }); const results = await Promise.all(tokens.map((t) => (0, firebaseCloudMessagingService_1.sendFCMNotification)(t.firebase_token, title, body))); res.json({ message: "Push notifications triggered", count: tokens.length, results, }); } catch (err) { logger_1.default.error("Failed to send push notifications", { error: err }); res.status(500).json({ error: "Failed to send push notifications" }); } }; exports.sendPushNotificationToAll = sendPushNotificationToAll; const sendPushNotificationToUser = async (req, res) => { // Accept userId from URL param or body const userId = req.params.userId ? Number(req.params.userId) : Number(req.body.userId); if (!userId || isNaN(userId)) { return res .status(400) .json({ error: "userId is required and must be a number" }); } let { title, body } = req.body; if (!title) title = "Test Notification"; if (!body) body = "This is a test push notification to the user."; try { const tokens = await models_2.UserToken.findAll({ where: { userId }, attributes: ["firebase_token"], }); if (tokens.length === 0) { return res.status(404).json({ error: "No tokens found for this user" }); } const results = await Promise.all(tokens.map((t) => (0, firebaseCloudMessagingService_1.sendFCMNotification)(t.firebase_token, title, body))); res.json({ message: `Push notifications triggered for user ${userId}`, count: tokens.length, results, }); } catch (err) { logger_1.default.error("Failed to send push notifications to user", { error: err }); res .status(500) .json({ error: "Failed to send push notifications to user" }); } }; exports.sendPushNotificationToUser = sendPushNotificationToUser; const deleteAllNotifications = async (req, res) => { try { const deleted = await models_1.Notification.destroy({ where: {} }); logger_1.default.info("All notifications deleted", { deleted }); res.json({ message: "All notifications deleted", deleted }); } catch (err) { logger_1.default.error("Failed to delete all notifications", { error: err.message, }); res.status(500).json({ error: "Failed to delete all notifications.", details: err.message, }); } }; exports.deleteAllNotifications = deleteAllNotifications;
Save
Close
Exit & Reset
Text mode: syntax highlighting auto-detects file type.
Directory Contents
Dirs: 0 × Files: 9
Delete Selected
Select All
Select None
Sort:
Name
Size
Modified
Enable drag-to-move
Name
Size
Perms
Modified
Actions
authController.js
12.50 KB
lrw-r--r--
2026-05-06 08:23:54
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
billController.js
9.26 KB
lrw-r--r--
2026-05-06 08:23:54
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
categoryController.js
1.98 KB
lrw-r--r--
2026-05-06 08:23:54
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
creditorController.js
8.71 KB
lrw-r--r--
2026-05-06 08:23:54
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
notificationController.js
10.86 KB
lrw-r--r--
2026-05-06 08:23:54
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
podioController.js
3.43 KB
lrw-r--r--
2026-05-06 08:23:54
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
profileController.js
5.17 KB
lrw-r--r--
2026-05-06 08:23:54
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
reportController.js
1.96 KB
lrw-r--r--
2026-05-06 08:23:54
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
uploadController.js
3.54 KB
lrw-r--r--
2026-05-06 08:23:54
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
Zip Selected
If ZipArchive is unavailable, a
.tar
will be created (no compression).