feat(zero): /config endpoints + dynamic scheduler hours
- GET/PATCH /api/admin/zero/config — read/write all Zero settings via app_settings
- scheduler reads GENERATE_HOUR / APPROVE_HOUR dynamically (no restart needed)
- generateDraft uses PUBLISH_HOUR for scheduled_at (was hardcoded 13)
- requireAdmin softened — works both with and without users.is_admin column
(prod has no is_admin; auth is provided by x-internal-secret + web cookie)
This commit is contained in:
@@ -19,15 +19,15 @@ const TICK_MS = 60_000;
|
||||
// Отметка последнего успешного тика по slot'у: { generate: '2026-06-19T13:00', approve: '2026-06-19T07:00' }
|
||||
const lastRun = {};
|
||||
|
||||
const GENERATE_HOUR_MSK = 13;
|
||||
const APPROVE_HOUR_MSK = 7;
|
||||
async function generateHourMsk() { return parseInt(await settings.get('ZERO_NOTES_GENERATE_HOUR', '13'), 10); }
|
||||
async function approveHourMsk() { return parseInt(await settings.get('ZERO_NOTES_APPROVE_HOUR', '7'), 10); }
|
||||
|
||||
function slotKey(ymd, hour) {
|
||||
return `${ymd}T${String(hour).padStart(2, '0')}:00`;
|
||||
}
|
||||
|
||||
async function runGeneration(ymd) {
|
||||
const key = slotKey(ymd, GENERATE_HOUR_MSK);
|
||||
const key = slotKey(ymd, await generateHourMsk());
|
||||
if (lastRun.generate === key) return;
|
||||
lastRun.generate = key;
|
||||
|
||||
@@ -50,7 +50,7 @@ async function runGeneration(ymd) {
|
||||
}
|
||||
|
||||
async function runAutoApprove(ymd) {
|
||||
const key = slotKey(ymd, APPROVE_HOUR_MSK);
|
||||
const key = slotKey(ymd, await approveHourMsk());
|
||||
if (lastRun.approve === key) return;
|
||||
lastRun.approve = key;
|
||||
|
||||
@@ -65,8 +65,9 @@ async function runAutoApprove(ymd) {
|
||||
async function tick() {
|
||||
const { hour, ymd } = zeroNotes.nowMsk();
|
||||
try {
|
||||
if (hour === GENERATE_HOUR_MSK) await runGeneration(ymd);
|
||||
if (hour === APPROVE_HOUR_MSK) await runAutoApprove(ymd);
|
||||
const [genHour, appHour] = [await generateHourMsk(), await approveHourMsk()];
|
||||
if (hour === genHour) await runGeneration(ymd);
|
||||
if (hour === appHour) await runAutoApprove(ymd);
|
||||
// публикация approved-заметок в TG (каждую минуту)
|
||||
const published = await zeroRunner.publishReady({ limit: 3 });
|
||||
if (published > 0) console.log(`[zeroNotes/scheduler] published ${published} note(s)`);
|
||||
@@ -85,8 +86,9 @@ function start() {
|
||||
intervalRef = setInterval(tick, TICK_MS);
|
||||
// первый тик через 30 сек после старта (даём engine стабильно подняться)
|
||||
setTimeout(tick, 30_000);
|
||||
console.log(`[zeroNotes/scheduler] started, tick every ${TICK_MS / 1000}s, ` +
|
||||
`generate=${GENERATE_HOUR_MSK}:00 MSK, auto-approve=${APPROVE_HOUR_MSK}:00 MSK`);
|
||||
Promise.all([generateHourMsk(), approveHourMsk()]).then(([gh, ah]) =>
|
||||
console.log(`[zeroNotes/scheduler] started, tick every ${TICK_MS/1000}s, generate=${gh}:00 MSK, auto-approve=${ah}:00 MSK (dynamic)`)
|
||||
).catch(() => {});
|
||||
}
|
||||
|
||||
function stop() {
|
||||
|
||||
Reference in New Issue
Block a user