mirror of
https://github.com/nfonteyne/octane-website.git
synced 2026-09-03 23:24:48 +02:00
update: accept/reject rehersal and get response information
This commit is contained in:
parent
247323654e
commit
5730a9fe3c
5 changed files with 142 additions and 2 deletions
9
src/db/migrations/015_rehearsal_votes.sql
Normal file
9
src/db/migrations/015_rehearsal_votes.sql
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
CREATE TABLE rehearsal_votes (
|
||||
id SERIAL PRIMARY KEY,
|
||||
rehearsal_id INTEGER NOT NULL REFERENCES rehearsals(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
vote TEXT NOT NULL CHECK (vote IN ('accept', 'reject')),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (rehearsal_id, user_id)
|
||||
);
|
||||
|
|
@ -2,10 +2,19 @@ const pool = require('../db/pool');
|
|||
|
||||
async function findUpcoming() {
|
||||
const { rows } = await pool.query(`
|
||||
SELECT r.id, r.starts_at, r.ends_at, r.location, r.proposed_by, u.name AS proposed_by_name, r.created_at
|
||||
SELECT r.id, r.starts_at, r.ends_at, r.location, r.proposed_by, u.name AS proposed_by_name, r.created_at,
|
||||
COALESCE(
|
||||
json_agg(
|
||||
json_build_object('userId', v.user_id, 'name', vu.name, 'avatarUrl', vu.avatar_url, 'vote', v.vote)
|
||||
) FILTER (WHERE v.id IS NOT NULL),
|
||||
'[]'
|
||||
) AS votes
|
||||
FROM rehearsals r
|
||||
JOIN users u ON u.id = r.proposed_by
|
||||
LEFT JOIN rehearsal_votes v ON v.rehearsal_id = r.id
|
||||
LEFT JOIN users vu ON vu.id = v.user_id
|
||||
WHERE r.ends_at >= now()
|
||||
GROUP BY r.id, u.name
|
||||
ORDER BY r.starts_at
|
||||
`);
|
||||
return rows;
|
||||
|
|
@ -30,4 +39,23 @@ async function remove(id) {
|
|||
await pool.query('DELETE FROM rehearsals WHERE id = $1', [id]);
|
||||
}
|
||||
|
||||
module.exports = { findUpcoming, findById, create, remove };
|
||||
async function upsertVote(rehearsalId, userId, vote) {
|
||||
const { rows } = await pool.query(
|
||||
`INSERT INTO rehearsal_votes (rehearsal_id, user_id, vote)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (rehearsal_id, user_id)
|
||||
DO UPDATE SET vote = $3, updated_at = now()
|
||||
RETURNING id, rehearsal_id, user_id, vote, created_at, updated_at`,
|
||||
[rehearsalId, userId, vote]
|
||||
);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
async function removeVote(rehearsalId, userId) {
|
||||
await pool.query('DELETE FROM rehearsal_votes WHERE rehearsal_id = $1 AND user_id = $2', [
|
||||
rehearsalId,
|
||||
userId,
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = { findUpcoming, findById, create, remove, upsertVote, removeVote };
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ router.get(
|
|||
location: r.location,
|
||||
proposedBy: r.proposed_by,
|
||||
proposedByName: r.proposed_by_name,
|
||||
votes: r.votes,
|
||||
}))
|
||||
);
|
||||
})
|
||||
|
|
@ -68,4 +69,31 @@ router.delete(
|
|||
})
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/:id/vote',
|
||||
asyncHandler(async (req, res) => {
|
||||
const { vote } = req.body || {};
|
||||
if (!['accept', 'reject'].includes(vote)) {
|
||||
return res.status(400).json({ error: 'invalid_vote' });
|
||||
}
|
||||
const rehearsal = await rehearsalsRepo.findById(req.params.id);
|
||||
if (!rehearsal) return res.status(404).json({ error: 'not_found' });
|
||||
const saved = await rehearsalsRepo.upsertVote(req.params.id, req.user.id, vote);
|
||||
res.json({
|
||||
id: saved.id,
|
||||
rehearsalId: saved.rehearsal_id,
|
||||
userId: saved.user_id,
|
||||
vote: saved.vote,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/:id/vote',
|
||||
asyncHandler(async (req, res) => {
|
||||
await rehearsalsRepo.removeVote(req.params.id, req.user.id);
|
||||
res.status(204).end();
|
||||
})
|
||||
);
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue