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:
@@ -35,7 +35,7 @@ import {
|
||||
photoFile,
|
||||
photoPath,
|
||||
sessionUser,
|
||||
setPhotoSlot,
|
||||
setPhotoSlots,
|
||||
setPhotoConsent,
|
||||
setUserAvatar,
|
||||
setUserBlocked,
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
type Recipe,
|
||||
type User,
|
||||
type EventKind,
|
||||
type PhotoSlot,
|
||||
} from './db';
|
||||
|
||||
const PORT = Number(process.env.PORT || 3000);
|
||||
@@ -804,18 +805,22 @@ app.delete('/api/admin/photos', async (req, reply) => {
|
||||
return reply.status(200).send({ removed: files.length });
|
||||
});
|
||||
|
||||
// Curating: which slot on the landing page this photo is allowed to appear in.
|
||||
// The landing page picks one at random per slot, so several photos in one slot
|
||||
// rotate between visits.
|
||||
// Curating: the landing sections this photo is allowed to appear in. A photo
|
||||
// may sit in several at once — each section picks one of its own at random per
|
||||
// visit, so several photos in one section rotate. An empty set takes it off
|
||||
// the landing without deleting the row.
|
||||
app.patch<{ Params: { id: string } }>('/api/admin/photos/:id', async (req, reply) => {
|
||||
const user = admin(req);
|
||||
if ('status' in user) return reply.status(user.status).send({ error: user.status === 401 ? 'unauthorized' : 'forbidden' });
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id) || id <= 0) return reply.status(404).send({ error: 'photo not found' });
|
||||
const b = bodyOf(req);
|
||||
if (!b || !isPhotoSlot(b.slot)) return reply.status(400).send({ error: 'invalid slot' });
|
||||
if (!setPhotoSlot(id, b.slot)) return reply.status(404).send({ error: 'photo not found' });
|
||||
return reply.status(200).send({ id, slot: b.slot });
|
||||
const slots = b?.slots;
|
||||
if (!Array.isArray(slots) || !slots.every((s) => isPhotoSlot(s)))
|
||||
return reply.status(400).send({ error: 'invalid slots' });
|
||||
const set: PhotoSlot[] = [...new Set(slots as PhotoSlot[])];
|
||||
if (!setPhotoSlots(id, set)) return reply.status(404).send({ error: 'photo not found' });
|
||||
return reply.status(200).send({ id, slots: set });
|
||||
});
|
||||
|
||||
app
|
||||
|
||||
Reference in New Issue
Block a user