mirror of
https://github.com/nfonteyne/octane-website.git
synced 2026-09-03 23:24:48 +02:00
first commit
This commit is contained in:
commit
244cdbedd7
44 changed files with 3386 additions and 0 deletions
8
src/repositories/instrumentsRepo.js
Normal file
8
src/repositories/instrumentsRepo.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
const pool = require('../db/pool');
|
||||
|
||||
async function findAll() {
|
||||
const { rows } = await pool.query('SELECT id, name FROM instruments ORDER BY name');
|
||||
return rows;
|
||||
}
|
||||
|
||||
module.exports = { findAll };
|
||||
118
src/repositories/setlistsRepo.js
Normal file
118
src/repositories/setlistsRepo.js
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
const pool = require('../db/pool');
|
||||
|
||||
async function findNext() {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT id, name, venue, concert_date, created_by, created_at, updated_at
|
||||
FROM setlists
|
||||
WHERE concert_date >= CURRENT_DATE
|
||||
ORDER BY concert_date ASC
|
||||
LIMIT 1`
|
||||
);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
async function findHistory() {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT id, name, venue, concert_date, created_by, created_at, updated_at
|
||||
FROM setlists
|
||||
WHERE concert_date < CURRENT_DATE
|
||||
ORDER BY concert_date DESC`
|
||||
);
|
||||
return rows;
|
||||
}
|
||||
|
||||
async function findById(id) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT id, name, venue, concert_date, created_by, created_at, updated_at
|
||||
FROM setlists WHERE id = $1`,
|
||||
[id]
|
||||
);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
async function findSongs(setlistId) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT ss.id, ss.setlist_id, ss.song_id, s.title, s.artist, ss.position, ss.note, ss.is_encore
|
||||
FROM setlist_songs ss
|
||||
JOIN songs s ON s.id = ss.song_id
|
||||
WHERE ss.setlist_id = $1
|
||||
ORDER BY ss.is_encore, ss.position`,
|
||||
[setlistId]
|
||||
);
|
||||
return rows;
|
||||
}
|
||||
|
||||
async function create({ name, venue, concertDate, createdBy }) {
|
||||
const { rows } = await pool.query(
|
||||
`INSERT INTO setlists (name, venue, concert_date, created_by)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id, name, venue, concert_date, created_by, created_at, updated_at`,
|
||||
[name || null, venue || null, concertDate, createdBy]
|
||||
);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
async function update(id, { name, venue, concertDate }) {
|
||||
const { rows } = await pool.query(
|
||||
`UPDATE setlists SET name = $2, venue = $3, concert_date = $4, updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING id, name, venue, concert_date, created_by, created_at, updated_at`,
|
||||
[id, name || null, venue || null, concertDate]
|
||||
);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
async function remove(id) {
|
||||
await pool.query('DELETE FROM setlists WHERE id = $1', [id]);
|
||||
}
|
||||
|
||||
async function replaceSongs(setlistId, songEntries) {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
await client.query('DELETE FROM setlist_songs WHERE setlist_id = $1', [setlistId]);
|
||||
for (const entry of songEntries) {
|
||||
await client.query(
|
||||
`INSERT INTO setlist_songs (setlist_id, song_id, position, note, is_encore)
|
||||
VALUES ($1, $2, $3, $4, $5)`,
|
||||
[setlistId, entry.songId, entry.position, entry.note || null, !!entry.isEncore]
|
||||
);
|
||||
}
|
||||
await client.query('COMMIT');
|
||||
} catch (err) {
|
||||
await client.query('ROLLBACK');
|
||||
throw err;
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
async function addSong(setlistId, { songId, position, note, isEncore }) {
|
||||
const { rows } = await pool.query(
|
||||
`INSERT INTO setlist_songs (setlist_id, song_id, position, note, is_encore)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id, setlist_id, song_id, position, note, is_encore`,
|
||||
[setlistId, songId, position, note || null, !!isEncore]
|
||||
);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
async function removeSong(setlistId, setlistSongId) {
|
||||
await pool.query('DELETE FROM setlist_songs WHERE id = $1 AND setlist_id = $2', [
|
||||
setlistSongId,
|
||||
setlistId,
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
findNext,
|
||||
findHistory,
|
||||
findById,
|
||||
findSongs,
|
||||
create,
|
||||
update,
|
||||
remove,
|
||||
replaceSongs,
|
||||
addSong,
|
||||
removeSong,
|
||||
};
|
||||
86
src/repositories/songsRepo.js
Normal file
86
src/repositories/songsRepo.js
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
const pool = require('../db/pool');
|
||||
|
||||
async function findAll() {
|
||||
const { rows } = await pool.query(`
|
||||
SELECT s.id, s.title, s.artist, s.notes, s.created_at,
|
||||
COUNT(st.id)::int AS tutorial_count
|
||||
FROM songs s
|
||||
LEFT JOIN song_tutorials st ON st.song_id = s.id
|
||||
GROUP BY s.id
|
||||
ORDER BY s.title
|
||||
`);
|
||||
return rows;
|
||||
}
|
||||
|
||||
async function findById(id) {
|
||||
const { rows } = await pool.query(
|
||||
'SELECT id, title, artist, notes, added_by, created_at, updated_at FROM songs WHERE id = $1',
|
||||
[id]
|
||||
);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
async function create({ title, artist, notes, addedBy }) {
|
||||
const { rows } = await pool.query(
|
||||
`INSERT INTO songs (title, artist, notes, added_by)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id, title, artist, notes, added_by, created_at, updated_at`,
|
||||
[title, artist, notes || null, addedBy]
|
||||
);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
async function update(id, { title, artist, notes }) {
|
||||
const { rows } = await pool.query(
|
||||
`UPDATE songs SET title = $2, artist = $3, notes = $4, updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING id, title, artist, notes, added_by, created_at, updated_at`,
|
||||
[id, title, artist, notes || null]
|
||||
);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
async function remove(id) {
|
||||
await pool.query('DELETE FROM songs WHERE id = $1', [id]);
|
||||
}
|
||||
|
||||
async function findTutorials(songId) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT st.id, st.song_id, st.instrument_id, i.name AS instrument_name,
|
||||
st.url, st.label, st.added_by, st.created_at
|
||||
FROM song_tutorials st
|
||||
JOIN instruments i ON i.id = st.instrument_id
|
||||
WHERE st.song_id = $1
|
||||
ORDER BY i.name`,
|
||||
[songId]
|
||||
);
|
||||
return rows;
|
||||
}
|
||||
|
||||
async function addTutorial(songId, { instrumentId, url, label, addedBy }) {
|
||||
const { rows } = await pool.query(
|
||||
`INSERT INTO song_tutorials (song_id, instrument_id, url, label, added_by)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id, song_id, instrument_id, url, label, added_by, created_at`,
|
||||
[songId, instrumentId, url, label || null, addedBy]
|
||||
);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
async function removeTutorial(songId, tutorialId) {
|
||||
await pool.query('DELETE FROM song_tutorials WHERE id = $1 AND song_id = $2', [
|
||||
tutorialId,
|
||||
songId,
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
findAll,
|
||||
findById,
|
||||
create,
|
||||
update,
|
||||
remove,
|
||||
findTutorials,
|
||||
addTutorial,
|
||||
removeTutorial,
|
||||
};
|
||||
127
src/repositories/suggestionsRepo.js
Normal file
127
src/repositories/suggestionsRepo.js
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
const pool = require('../db/pool');
|
||||
|
||||
async function findAll() {
|
||||
const { rows } = await pool.query(`
|
||||
SELECT sg.id, sg.title, sg.artist, sg.youtube_url, sg.status, sg.promoted_song_id,
|
||||
sg.created_at, sg.suggested_by, u.name AS suggested_by_name,
|
||||
COUNT(*) FILTER (WHERE v.vote = 'approve')::int AS approve_count,
|
||||
COUNT(*) FILTER (WHERE v.vote = 'reject')::int AS reject_count
|
||||
FROM suggestions sg
|
||||
JOIN users u ON u.id = sg.suggested_by
|
||||
LEFT JOIN suggestion_votes v ON v.suggestion_id = sg.id
|
||||
GROUP BY sg.id, u.name
|
||||
ORDER BY sg.created_at DESC
|
||||
`);
|
||||
return rows;
|
||||
}
|
||||
|
||||
async function findById(id) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT sg.id, sg.title, sg.artist, sg.youtube_url, sg.status, sg.promoted_song_id,
|
||||
sg.created_at, sg.suggested_by, u.name AS suggested_by_name
|
||||
FROM suggestions sg
|
||||
JOIN users u ON u.id = sg.suggested_by
|
||||
WHERE sg.id = $1`,
|
||||
[id]
|
||||
);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
async function findVotes(suggestionId) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT v.id, v.user_id, u.name AS voter_name, v.vote, v.comment, v.created_at, v.updated_at
|
||||
FROM suggestion_votes v
|
||||
JOIN users u ON u.id = v.user_id
|
||||
WHERE v.suggestion_id = $1
|
||||
ORDER BY v.created_at`,
|
||||
[suggestionId]
|
||||
);
|
||||
return rows;
|
||||
}
|
||||
|
||||
async function create({ title, artist, youtubeUrl, suggestedBy }) {
|
||||
const { rows } = await pool.query(
|
||||
`INSERT INTO suggestions (title, artist, youtube_url, suggested_by)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id, title, artist, youtube_url, status, promoted_song_id, created_at, suggested_by`,
|
||||
[title, artist || null, youtubeUrl, suggestedBy]
|
||||
);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
async function updateStatus(id, status) {
|
||||
const { rows } = await pool.query(
|
||||
`UPDATE suggestions SET status = $2, updated_at = now() WHERE id = $1
|
||||
RETURNING id, title, artist, youtube_url, status, promoted_song_id, created_at, suggested_by`,
|
||||
[id, status]
|
||||
);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
async function remove(id) {
|
||||
await pool.query('DELETE FROM suggestions WHERE id = $1', [id]);
|
||||
}
|
||||
|
||||
async function upsertVote(suggestionId, userId, { vote, comment }) {
|
||||
const { rows } = await pool.query(
|
||||
`INSERT INTO suggestion_votes (suggestion_id, user_id, vote, comment)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT (suggestion_id, user_id)
|
||||
DO UPDATE SET vote = $3, comment = $4, updated_at = now()
|
||||
RETURNING id, suggestion_id, user_id, vote, comment, created_at, updated_at`,
|
||||
[suggestionId, userId, vote, comment || null]
|
||||
);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
async function removeVote(suggestionId, userId) {
|
||||
await pool.query('DELETE FROM suggestion_votes WHERE suggestion_id = $1 AND user_id = $2', [
|
||||
suggestionId,
|
||||
userId,
|
||||
]);
|
||||
}
|
||||
|
||||
async function promoteToSong(suggestionId, addedBy) {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
const { rows: sugRows } = await client.query('SELECT * FROM suggestions WHERE id = $1 FOR UPDATE', [
|
||||
suggestionId,
|
||||
]);
|
||||
const suggestion = sugRows[0];
|
||||
if (!suggestion) {
|
||||
await client.query('ROLLBACK');
|
||||
return null;
|
||||
}
|
||||
const { rows: songRows } = await client.query(
|
||||
`INSERT INTO songs (title, artist, added_by)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING id, title, artist, notes, added_by, created_at, updated_at`,
|
||||
[suggestion.title, suggestion.artist || suggestion.title, addedBy]
|
||||
);
|
||||
const song = songRows[0];
|
||||
await client.query(
|
||||
`UPDATE suggestions SET status = 'approved', promoted_song_id = $2, updated_at = now() WHERE id = $1`,
|
||||
[suggestionId, song.id]
|
||||
);
|
||||
await client.query('COMMIT');
|
||||
return song;
|
||||
} catch (err) {
|
||||
await client.query('ROLLBACK');
|
||||
throw err;
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
findAll,
|
||||
findById,
|
||||
findVotes,
|
||||
create,
|
||||
updateStatus,
|
||||
remove,
|
||||
upsertVote,
|
||||
removeVote,
|
||||
promoteToSong,
|
||||
};
|
||||
23
src/repositories/usersRepo.js
Normal file
23
src/repositories/usersRepo.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
const pool = require('../db/pool');
|
||||
|
||||
async function findById(id) {
|
||||
const { rows } = await pool.query(
|
||||
'SELECT id, authentik_sub, name, email, is_admin, created_at FROM users WHERE id = $1',
|
||||
[id]
|
||||
);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
async function upsertFromClaims({ sub, name, email, isAdmin }) {
|
||||
const { rows } = await pool.query(
|
||||
`INSERT INTO users (authentik_sub, name, email, is_admin)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT (authentik_sub)
|
||||
DO UPDATE SET name = $2, email = $3, is_admin = $4, updated_at = now()
|
||||
RETURNING id, authentik_sub, name, email, is_admin, created_at`,
|
||||
[sub, name, email, isAdmin]
|
||||
);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
module.exports = { findById, upsertFromClaims };
|
||||
Loading…
Add table
Add a link
Reference in a new issue