mirror of
https://github.com/Spengreb/sync.git
synced 2026-06-09 23:02:05 +00:00
Fix shows/bot API auth gaps, handle missing channels as 404, make recurrence DST-safe, and clear lint regressions
This commit is contained in:
parent
e3dd961430
commit
12696452aa
5 changed files with 97 additions and 11 deletions
|
|
@ -39,7 +39,7 @@ class Database {
|
|||
database: Config.get('mysql.database'),
|
||||
multipleStatements: true, // Legacy thing
|
||||
charset: 'utf8mb4'
|
||||
}
|
||||
};
|
||||
} else {
|
||||
connection = {
|
||||
host: Config.get('mysql.server'),
|
||||
|
|
@ -49,7 +49,7 @@ class Database {
|
|||
database: Config.get('mysql.database'),
|
||||
multipleStatements: true, // Legacy thing
|
||||
charset: 'utf8mb4'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
knexConfig = {
|
||||
|
|
|
|||
92
src/shows.js
92
src/shows.js
|
|
@ -22,15 +22,93 @@ function makeSystemProxy(name) {
|
|||
|
||||
function computeNextRunAt(show) {
|
||||
const base = Number(show.next_run_at || show.scheduled_for || Date.now());
|
||||
if (show.recurrence === 'daily') {
|
||||
return base + 24 * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
if (show.recurrence === 'weekly') {
|
||||
return base + 7 * 24 * 60 * 60 * 1000;
|
||||
}
|
||||
const recurrence = show.recurrence;
|
||||
const timezone = show.timezone || 'UTC';
|
||||
|
||||
if (recurrence !== 'daily' && recurrence !== 'weekly') {
|
||||
return base;
|
||||
}
|
||||
|
||||
const daysToAdd = recurrence === 'weekly' ? 7 : 1;
|
||||
const source = new Date(base);
|
||||
const local = toZonedParts(source, timezone);
|
||||
if (!local) {
|
||||
return base + (daysToAdd * 24 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
const targetDate = addDaysUTC(local.year, local.month, local.day, daysToAdd);
|
||||
const zonedTarget = {
|
||||
year: targetDate.year,
|
||||
month: targetDate.month,
|
||||
day: targetDate.day,
|
||||
hour: local.hour,
|
||||
minute: local.minute,
|
||||
second: local.second
|
||||
};
|
||||
|
||||
const next = zonedDateTimeToUtc(zonedTarget, timezone);
|
||||
return next || (base + (daysToAdd * 24 * 60 * 60 * 1000));
|
||||
}
|
||||
|
||||
function toZonedParts(date, timezone) {
|
||||
try {
|
||||
const dtf = new Intl.DateTimeFormat('en-US', {
|
||||
timeZone: timezone,
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: false
|
||||
});
|
||||
const parts = dtf.formatToParts(date);
|
||||
const out = {};
|
||||
for (const part of parts) {
|
||||
if (part.type === 'literal') continue;
|
||||
out[part.type] = parseInt(part.value, 10);
|
||||
}
|
||||
|
||||
return {
|
||||
year: out.year,
|
||||
month: out.month,
|
||||
day: out.day,
|
||||
hour: out.hour,
|
||||
minute: out.minute,
|
||||
second: out.second
|
||||
};
|
||||
} catch (_err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function addDaysUTC(year, month, day, days) {
|
||||
const d = new Date(Date.UTC(year, month - 1, day + days));
|
||||
return {
|
||||
year: d.getUTCFullYear(),
|
||||
month: d.getUTCMonth() + 1,
|
||||
day: d.getUTCDate()
|
||||
};
|
||||
}
|
||||
|
||||
function zonedDateTimeToUtc(local, timezone) {
|
||||
let guess = Date.UTC(local.year, local.month - 1, local.day, local.hour, local.minute, local.second);
|
||||
|
||||
// Iterate to resolve timezone offset for the target wall-clock time (handles DST shifts).
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const zoned = toZonedParts(new Date(guess), timezone);
|
||||
if (!zoned) return null;
|
||||
|
||||
const desired = Date.UTC(local.year, local.month - 1, local.day, local.hour, local.minute, local.second);
|
||||
const current = Date.UTC(zoned.year, zoned.month - 1, zoned.day, zoned.hour, zoned.minute, zoned.second);
|
||||
const delta = desired - current;
|
||||
if (delta === 0) {
|
||||
return guess;
|
||||
}
|
||||
guess += delta;
|
||||
}
|
||||
|
||||
return guess;
|
||||
}
|
||||
|
||||
function normalizePlaylist(rawPlaylist) {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,11 @@ async function getChannelEmotes(channelId) {
|
|||
(err, rows) => {
|
||||
if (err) return reject(new Error(err));
|
||||
if (!rows || rows.length === 0) return resolve([]);
|
||||
try { resolve(JSON.parse(rows[0].value)); }
|
||||
catch (e) { resolve([]); }
|
||||
try {
|
||||
resolve(JSON.parse(rows[0].value));
|
||||
} catch (e) {
|
||||
resolve([]);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
@ -92,7 +95,6 @@ router.put('/:name', botAuth, requireRank(4), async (req, res) => {
|
|||
return res.status(409).json({ error: 'An emote with that name already exists' });
|
||||
}
|
||||
|
||||
const old = emotes[idx];
|
||||
emotes[idx] = validated;
|
||||
await saveChannelEmotes(req.bot.channel_id, emotes);
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ async function getChannelRow(channelName) {
|
|||
return new Promise((resolve, reject) => {
|
||||
db.channels.lookup(channelName, (err, row) => {
|
||||
if (err) reject(new Error(err));
|
||||
else if (!row) reject(new Error('Channel not found'));
|
||||
else resolve(row);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -138,6 +138,11 @@ async function authorizeChannel(req, res) {
|
|||
return null;
|
||||
}
|
||||
|
||||
if (bot.rank < 2) {
|
||||
res.status(403).json({ error: 'Insufficient rank' });
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
actorName: bot.name,
|
||||
rank: bot.rank,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue