Release v2.20.1: migrate authentication to Better Auth

This commit is contained in:
lzstealth committed 2026-10-25 18:19:55 +00:00
1 parent e9a53f577c
commit fba4f99ff7
92 files changed
+5085 -1943

No files matched your search

+62
View File
@@ -197,4 +197,66 @@ test('playlist create and update redirect to the canonical edit path', async ()
}, invalidRes, () => {});
assert.equal(invalidRes.statusCode, 400);
}
});
test('playlist audit compares persisted items and schedules without recreated row IDs', async () => {
let items = [{ id: 101, slide_id: 11, duration_seconds: 10 }];
let rules = [{ playlist_slide_id: 101, start_time: '08:00:00', end_time: '17:00:00', schedule_days_json: '[1,2]' }];
const events = [];
const connection = {
async commit() {}, async rollback() {}, release() {},
async query(sql, params) {
if (sql.includes('FROM c_playlist_slides WHERE playlist_id') && sql.startsWith('SELECT id, slide_id')) return [structuredClone(items)];
if (sql.includes('FROM c_playlist_slide_schedule_rules r')) return [structuredClone(rules)];
if (sql.startsWith('SELECT sl.id, st.canvas_size_id')) return [[{ id: 11, canvas_size_id: 7 }]];
if (sql.startsWith('DELETE FROM c_playlist_slides')) { items = []; rules = []; }
if (sql.startsWith('INSERT INTO c_playlist_slides')) {
items = [{ id: 202, slide_id: params[1], duration_seconds: params[3] }];
return [{ insertId: 202 }];
}
if (sql.startsWith('INSERT INTO c_playlist_slide_schedule_rules')) {
rules.push({ playlist_slide_id: params[0], start_time: params[4] + ':00', end_time: params[5] + ':00', schedule_days_json: params[6] });
}
return [[]];
}
};
const { app, handlers } = createAppAndHandlers();
registerPlaylistRoutes(app, {
pool: { async getConnection() { return connection; } },
common: {
async fetchDuplicateName() { return null; },
async fetchPlaylistById() { return { id: 4, name: 'Loop', canvas_id: 7, fade_between_slides: 0, skip_unavailable_rtmp: 0 }; }
},
readArrayField(body, keys) {
for (const key of keys) {
if (Object.hasOwn(body, key)) return Array.isArray(body[key]) ? body[key] : [body[key]];
}
return [];
},
fetchScreensByPlaylistId: async () => [], getAuditUserId: () => 12,
recordRequestAuditEvent: async (_pool, _req, event) => { events.push(event); },
redirectAfterSave() {}, notifyPlayerScreens: async () => {}, broadcastDashboardState: async () => {},
requirePermission: () => () => {}
});
const body = {
name: 'Loop', slide_id: ['11'], row_key: ['row-11'], duration_seconds: ['10'],
schedule_rule_row_key: ['row-11'], schedule_rule_start_time: ['08:00'], schedule_rule_end_time: ['17:00'], schedule_rule_days_csv: ['1,2']
};
const save = async () => {
const response = createResponse();
await handlers['/playlists/:id'].at(-1)({ params: { id: '4' }, body }, response, error => { throw error; });
assert.equal(response.statusCode, 200);
return events.at(-1).details.changes;
};
assert.deepEqual(await save(), {});
body.duration_seconds = ['20'];
assert.deepEqual(await save(), { 'items[0].duration_seconds': { from: 10, to: 20 } });
body.schedule_rule_start_time = ['09:00'];
assert.deepEqual(await save(), { 'items[0].scheduleRules[0].start_time': { from: '08:00:00', to: '09:00:00' } });
body.slide_id = [];
body.row_key = [];
body.duration_seconds = [];
const removed = await save();
assert.deepEqual(removed['items[0].slide_id'], { from: 11, to: null });
assert.deepEqual(removed['items[0].scheduleRules[0].start_time'], { from: '09:00:00', to: null });
});