Initial commit
Next.js + Express event management app for Hope Family Church.
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
const DATA_DIR = path.join(__dirname, '..', '..', 'data');
|
||||
const QUEUE_PATH = path.join(DATA_DIR, 'scheduled-emails.json');
|
||||
|
||||
function ensureStore() {
|
||||
try {
|
||||
if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
if (!fs.existsSync(QUEUE_PATH)) fs.writeFileSync(QUEUE_PATH, JSON.stringify({ jobs: [] }, null, 2), 'utf-8');
|
||||
} catch (e) {
|
||||
// Best-effort; throws will surface to caller
|
||||
}
|
||||
}
|
||||
|
||||
function loadAll() {
|
||||
ensureStore();
|
||||
try {
|
||||
const raw = fs.readFileSync(QUEUE_PATH, 'utf-8');
|
||||
const data = JSON.parse(raw);
|
||||
const jobs = Array.isArray(data?.jobs) ? data.jobs : [];
|
||||
return jobs;
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function saveAll(jobs) {
|
||||
ensureStore();
|
||||
const payload = { jobs: Array.isArray(jobs) ? jobs : [] };
|
||||
// Simple atomic-ish write
|
||||
const tmp = QUEUE_PATH + '.tmp';
|
||||
fs.writeFileSync(tmp, JSON.stringify(payload, null, 2), 'utf-8');
|
||||
fs.renameSync(tmp, QUEUE_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a scheduled job
|
||||
* @param {object} job { id?, eventId, createdById, scheduledAt: ISO string, payload: body for emailEventAttendees }
|
||||
*/
|
||||
function addJob(job) {
|
||||
const now = new Date();
|
||||
const id = job.id || uuidv4();
|
||||
const rec = {
|
||||
id,
|
||||
eventId: job.eventId || null,
|
||||
broadcast: !!job.broadcast,
|
||||
createdById: job.createdById || null,
|
||||
scheduledAt: job.scheduledAt,
|
||||
createdAt: now.toISOString(),
|
||||
status: 'queued', // queued | sending | sent | error
|
||||
attempts: 0,
|
||||
lastError: null,
|
||||
payload: job.payload || {},
|
||||
};
|
||||
const jobs = loadAll();
|
||||
jobs.push(rec);
|
||||
saveAll(jobs);
|
||||
return rec;
|
||||
}
|
||||
|
||||
function listJobs(filter = {}) {
|
||||
const jobs = loadAll();
|
||||
// Basic filter support
|
||||
return jobs.filter(j => {
|
||||
if (filter.status && j.status !== filter.status) return false;
|
||||
if (filter.eventId && j.eventId !== filter.eventId) return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function getDueJobs(now = new Date()) {
|
||||
const jobs = loadAll();
|
||||
const t = now instanceof Date ? now : new Date(now);
|
||||
return jobs.filter(j => j.status === 'queued' && new Date(j.scheduledAt).getTime() <= t.getTime());
|
||||
}
|
||||
|
||||
function updateJob(id, patch) {
|
||||
const jobs = loadAll();
|
||||
const idx = jobs.findIndex(j => j.id === id);
|
||||
if (idx === -1) return null;
|
||||
jobs[idx] = { ...jobs[idx], ...patch };
|
||||
saveAll(jobs);
|
||||
return jobs[idx];
|
||||
}
|
||||
|
||||
function getJob(id) {
|
||||
const jobs = loadAll();
|
||||
return jobs.find(j => j.id === id) || null;
|
||||
}
|
||||
|
||||
function deleteJob(id) {
|
||||
const jobs = loadAll();
|
||||
const filtered = jobs.filter(j => j.id !== id);
|
||||
if (filtered.length === jobs.length) return false;
|
||||
saveAll(filtered);
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addJob,
|
||||
listJobs,
|
||||
getDueJobs,
|
||||
updateJob,
|
||||
getJob,
|
||||
deleteJob,
|
||||
};
|
||||
Reference in New Issue
Block a user