- Full-stack: React 18 + Express + SQLite - Drag-and-drop kanban boards with @hello-pangea/dnd - Google App Password email integration (SMTP + IMAP) - Inbound email: create cards by sending emails - Reply-to-card: email replies become comments - Admin/user management with role-based access - Setup wizard: email config → admin creation - Checklists, time tracking, priorities, labels, due dates - Real-time notifications with activity feed - Beautiful HTML email templates
38 lines
1.3 KiB
JavaScript
38 lines
1.3 KiB
JavaScript
import { Router } from 'express';
|
|
import db from '../db.js';
|
|
import { authMiddleware, adminOnly } from '../middleware/auth.js';
|
|
import { getEmailConfig } from '../email/transporter.js';
|
|
import { pollInbox } from '../email/imap.js';
|
|
|
|
const router = Router();
|
|
router.use(authMiddleware);
|
|
|
|
router.get('/config', adminOnly, (req, res) => {
|
|
const config = getEmailConfig();
|
|
if (!config) return res.status(404).json({ error: 'Not configured' });
|
|
res.json({ ...config, app_password: '••••••••' });
|
|
});
|
|
|
|
router.get('/log', adminOnly, (req, res) => {
|
|
const logs = db.prepare('SELECT * FROM email_log ORDER BY created_at DESC LIMIT 100').all();
|
|
res.json(logs);
|
|
});
|
|
|
|
router.post('/poll', adminOnly, async (req, res) => {
|
|
try {
|
|
await pollInbox();
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
router.get('/stats', adminOnly, (req, res) => {
|
|
const sent = db.prepare("SELECT COUNT(*) as c FROM email_log WHERE direction = 'sent'").get().c;
|
|
const received = db.prepare("SELECT COUNT(*) as c FROM email_log WHERE direction = 'received'").get().c;
|
|
const failed = db.prepare("SELECT COUNT(*) as c FROM email_log WHERE status = 'failed'").get().c;
|
|
res.json({ sent, received, failed });
|
|
});
|
|
|
|
export default router;
|