web: a photo can sit in every landing section at once
The picker was one dropdown, so a photo lived in exactly one place. The three destinations are now independent checkboxes on the card, and the column holds the set as a comma list — the landing page draws a photo in every section it was ticked into, each still picking one of its own at random per visit. Ticking nothing is what `off` used to be: the row is kept and the landing page stops drawing it, which is what the old "not on the landing page" option did.
This commit is contained in:
@@ -284,7 +284,10 @@ try {
|
||||
const rows = adminList.body?.photos ?? [];
|
||||
check('an admin lists contributions', adminList.status === 200 && rows.length > 0);
|
||||
check('the admin listing carries the owner', rows.some((r) => /@test\.local$/.test(r.email ?? '')));
|
||||
check('a fresh upload lands in the strip slot', rows.find((r) => r.id === id)?.slot === 'strip');
|
||||
check(
|
||||
'a fresh upload lands in the strip section',
|
||||
JSON.stringify(rows.find((r) => r.id === id)?.slots) === JSON.stringify(['strip']),
|
||||
);
|
||||
check('a plain member cannot delete', (await user.req(`/admin/photos/${id}`, { method: 'DELETE' })).status === 403);
|
||||
|
||||
// ---- placement ----------------------------------------------------------
|
||||
@@ -295,27 +298,38 @@ try {
|
||||
(await user.req(`/admin/photos/${id}`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({ slot: 'qr' }),
|
||||
body: JSON.stringify({ slots: ['qr'] }),
|
||||
})).status === 403,
|
||||
);
|
||||
const placed = await patch(`/admin/photos/${id}`, { slot: 'qr' });
|
||||
check('an admin moves a photo to a live slot', placed.status === 200 && placed.body?.slot === 'qr', JSON.stringify(placed.body));
|
||||
const placed = await patch(`/admin/photos/${id}`, { slots: ['tester', 'creator'] });
|
||||
check(
|
||||
'the slot is public, the owner is not',
|
||||
((await actor().req('/photos')).body?.photos ?? []).find((r) => r.id === id)?.slot === 'qr',
|
||||
'an admin puts a photo in several sections at once',
|
||||
placed.status === 200 && JSON.stringify(placed.body?.slots) === JSON.stringify(['tester', 'creator']),
|
||||
JSON.stringify(placed.body),
|
||||
);
|
||||
// `off` is the curator's removal: the reel draws slot === 'strip' and the
|
||||
// live slots draw their own, so the row shows up nowhere — but the uploader
|
||||
// keeps it in their folder.
|
||||
const off = await patch(`/admin/photos/${id}`, { slot: 'off' });
|
||||
check('an admin takes a photo off the landing', off.status === 200 && off.body?.slot === 'off', JSON.stringify(off.body));
|
||||
check(
|
||||
'an off photo is on no landing slot',
|
||||
((await actor().req('/photos')).body?.photos ?? []).find((r) => r.id === id)?.slot === 'off',
|
||||
'the sections are public, the owner is not',
|
||||
JSON.stringify(((await actor().req('/photos')).body?.photos ?? []).find((r) => r.id === id)?.slots) ===
|
||||
JSON.stringify(['tester', 'creator']),
|
||||
);
|
||||
const one = await patch(`/admin/photos/${id}`, { slots: ['strip', 'strip', 'qr'] });
|
||||
check(
|
||||
'a repeated section is stored once',
|
||||
JSON.stringify(one.body?.slots) === JSON.stringify(['strip', 'qr']),
|
||||
JSON.stringify(one.body),
|
||||
);
|
||||
// An empty set is the curator's removal: no landing section draws the row,
|
||||
// but the uploader keeps it in their folder.
|
||||
const off = await patch(`/admin/photos/${id}`, { slots: [] });
|
||||
check('an admin takes a photo off the landing', off.status === 200 && off.body?.slots?.length === 0, JSON.stringify(off.body));
|
||||
check(
|
||||
'an off photo is on no landing section',
|
||||
((await actor().req('/photos')).body?.photos ?? []).find((r) => r.id === id)?.slots?.length === 0,
|
||||
);
|
||||
check('its owner still has it in the folder', ((await user.req('/photos/mine')).body?.photos ?? []).some((p) => p.id === id));
|
||||
check('an unknown slot is refused', (await patch(`/admin/photos/${id}`, { slot: 'nope' })).status === 400);
|
||||
check('placing an unknown photo is a 404', (await patch('/admin/photos/999999', { slot: 'qr' })).status === 404);
|
||||
check('an unknown slot is refused', (await patch(`/admin/photos/${id}`, { slots: ['nope'] })).status === 400);
|
||||
check('a bare slot string is refused', (await patch(`/admin/photos/${id}`, { slots: 'strip' })).status === 400);
|
||||
check('placing an unknown photo is a 404', (await patch('/admin/photos/999999', { slots: ['qr'] })).status === 404);
|
||||
|
||||
const deleted = await admin.req(`/admin/photos/${id}`, { method: 'DELETE' });
|
||||
check('an admin deletes a contribution', deleted.status === 204, `got ${deleted.status}`);
|
||||
|
||||
Reference in New Issue
Block a user