🚀 Patch auto
This commit is contained in:
8
.env
8
.env
@@ -1,20 +1,20 @@
|
|||||||
# === Super Sunday PROD Environment ===
|
# === Super Sunday PROD Environment ===
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
PORT=8080
|
PORT=4000
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
POSTGRES_DB=supersunday
|
POSTGRES_DB=supersunday
|
||||||
POSTGRES_USER=supersunday
|
POSTGRES_USER=supersunday
|
||||||
POSTGRES_PASSWORD=Sup3rSund@y2025!
|
POSTGRES_PASSWORD=postgres
|
||||||
DATABASE_URL=postgres://supersunday:Sup3rSund@y2025!@db:5432/supersunday
|
DATABASE_URL=postgres://supersunday:Sup3rSund@y2025!@db:5432/supersunday
|
||||||
|
|
||||||
# API / Auth
|
# API / Auth
|
||||||
JWT_SECRET=Sup3rSundayUltraSecretKey_2025
|
JWT_SECRET=Sup3rSundayUltraSecretKey_2025
|
||||||
CORS_ORIGIN=http://localhost:8080
|
CORS_ORIGIN=http://localhost
|
||||||
|
|
||||||
# Admin credentials
|
# Admin credentials
|
||||||
ADMIN_EMAIL=admin@supersunday.app
|
ADMIN_EMAIL=admin@supersunday.app
|
||||||
ADMIN_PASSWORD=ChangeMeNow!42
|
ADMIN_PASSWORD=4575SataUMGF2026+-PROD
|
||||||
|
|
||||||
# Branding
|
# Branding
|
||||||
APP_NAME="Super Sunday Padel Championship"
|
APP_NAME="Super Sunday Padel Championship"
|
||||||
|
|||||||
21
.env.
21
.env.
@@ -1,21 +0,0 @@
|
|||||||
# === Super Sunday PROD Environment ===
|
|
||||||
NODE_ENV=production
|
|
||||||
PORT=8080
|
|
||||||
|
|
||||||
# Database
|
|
||||||
POSTGRES_DB=supersunday
|
|
||||||
POSTGRES_USER=supersunday
|
|
||||||
POSTGRES_PASSWORD=Sup3rSund@y2025!
|
|
||||||
DATABASE_URL=postgres://supersunday:Sup3rSund@y2025!@db:5432/supersunday
|
|
||||||
|
|
||||||
# API / Auth
|
|
||||||
JWT_SECRET=Sup3rSundayUltraSecretKey_2025
|
|
||||||
CORS_ORIGIN=http://localhost
|
|
||||||
|
|
||||||
# Admin credentials
|
|
||||||
ADMIN_EMAIL=admin@padel24play.com
|
|
||||||
ADMIN_PASSWORD=4575SataMGF+-
|
|
||||||
|
|
||||||
# Branding
|
|
||||||
APP_NAME="Super Sunday Padel Championship"
|
|
||||||
CLUB_NAME="Les Églantiers, Woluwe-Saint-Pierre"
|
|
||||||
14
.env.example
Normal file
14
.env.example
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Backend
|
||||||
|
PORT=4000
|
||||||
|
JWT_SECRET=change_me_supersecret
|
||||||
|
|
||||||
|
# Admin (simple login)
|
||||||
|
ADMIN_EMAIL=admin@supersunday.local
|
||||||
|
ADMIN_PASSWORD=admin1234
|
||||||
|
|
||||||
|
# Postgres
|
||||||
|
PGHOST=db
|
||||||
|
PGPORT=5432
|
||||||
|
PGDATABASE=supersunday
|
||||||
|
PGUSER=supersunday
|
||||||
|
PGPASSWORD=supersunday
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# === Super Sunday PROD Environment ===
|
# === Super Sunday PROD Environment ===
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
PORT=8080
|
PORT=4000
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
POSTGRES_DB=supersunday
|
POSTGRES_DB=supersunday
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
Patch HTML (header/menu unifié + onglet actif + liens CSS v=4)
|
|
||||||
- frontend/public/index.html
|
|
||||||
- frontend/public/tournament/index.html
|
|
||||||
- frontend/public/admin/index.html
|
|
||||||
|
|
||||||
Installation:
|
|
||||||
unzip -o supersunday_frontend_html_header_patch.zip -d .
|
|
||||||
docker compose build web && docker compose up -d
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
Patch: Typography + titles facelift (hero titles, section titles, kicker labels).
|
|
||||||
Files:
|
|
||||||
- frontend/public/assets/style.titles.patch.css
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
1. Copy style.titles.patch.css into frontend/public/assets/
|
|
||||||
2. In your HTML <head>, include:
|
|
||||||
<link rel="stylesheet" href="/assets/style.titles.patch.css" />
|
|
||||||
3. Apply classes .hero-title, .section-title, .kicker, .btn-outline in your HTML.
|
|
||||||
|
|
||||||
Rebuild web:
|
|
||||||
docker compose build web && docker compose up -d
|
|
||||||
14
backend/.env
Normal file
14
backend/.env
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# --- Backend API ---
|
||||||
|
PORT=4000
|
||||||
|
|
||||||
|
# --- Postgres ---
|
||||||
|
PGHOST=db
|
||||||
|
PGUSER=postgres
|
||||||
|
PGPASSWORD=postgres
|
||||||
|
PGDATABASE=supersunday
|
||||||
|
PGPORT=5432
|
||||||
|
|
||||||
|
# --- Admin auth ---
|
||||||
|
ADMIN_EMAIL=admin@supersunday.local
|
||||||
|
ADMIN_PASSWORD=changeme
|
||||||
|
JWT_SECRET=supersecret
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
FROM node:20-alpine AS deps
|
|
||||||
WORKDIR /app
|
|
||||||
COPY package.json package-lock.json* .npmrc* ./
|
|
||||||
RUN npm ci --omit=dev
|
|
||||||
|
|
||||||
FROM node:20-alpine
|
FROM node:20-alpine
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV NODE_ENV=production
|
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
COPY package*.json ./
|
||||||
|
RUN npm ci --omit=dev || npm install --production
|
||||||
COPY . .
|
COPY . .
|
||||||
EXPOSE 8080
|
|
||||||
CMD ["node", "server.js"]
|
RUN apk add --no-cache curl
|
||||||
|
|
||||||
|
EXPOSE 4000
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=10s --timeout=3s --retries=12 --start-period=30s CMD curl -fsS http://localhost:4000/api/health || exit 1
|
||||||
|
|
||||||
|
CMD ["node","src/index.js"]
|
||||||
|
|||||||
45
backend/README_BACKEND_CRUD_PATCH.txt
Normal file
45
backend/README_BACKEND_CRUD_PATCH.txt
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
Supersunday — Backend CRUD patch (final)
|
||||||
|
|
||||||
|
Adds:
|
||||||
|
- src/middleware/auth.js (JWT guard)
|
||||||
|
- src/routes/auth.js (POST /api/auth/login)
|
||||||
|
- src/routes/tournaments.js (GET list/one/related, POST create, POST add participant)
|
||||||
|
- src/routes/matches.js (POST /api/matches/:id/score)
|
||||||
|
- src/db.js (pg connection)
|
||||||
|
- src/index.js (mount routes + /api/health)
|
||||||
|
- sql/schema.sql (tables + indexes)
|
||||||
|
|
||||||
|
Install:
|
||||||
|
1) Unzip into ./backend
|
||||||
|
unzip -o supersunday_backend_crud_patch.zip -d backend
|
||||||
|
|
||||||
|
2) Ensure backend/.env has:
|
||||||
|
PORT=4000
|
||||||
|
PGHOST=db
|
||||||
|
PGUSER=postgres
|
||||||
|
PGPASSWORD=postgres
|
||||||
|
PGDATABASE=supersunday
|
||||||
|
PGPORT=5432
|
||||||
|
ADMIN_EMAIL=admin@supersunday.local
|
||||||
|
ADMIN_PASSWORD=changeme
|
||||||
|
JWT_SECRET=supersecret
|
||||||
|
|
||||||
|
3) Apply schema:
|
||||||
|
docker compose cp backend/sql/schema.sql db:/tmp/schema.sql
|
||||||
|
docker compose exec db psql -U postgres -d supersunday -f /tmp/schema.sql
|
||||||
|
|
||||||
|
4) Rebuild API:
|
||||||
|
docker compose up -d --build api
|
||||||
|
|
||||||
|
Quick test:
|
||||||
|
- Login:
|
||||||
|
curl -s http://localhost:4000/api/auth/login -H 'Content-Type: application/json' -d '{"email":"admin@supersunday.local","password":"changeme"}'
|
||||||
|
|
||||||
|
- Create tournament:
|
||||||
|
TOKEN=...; curl -s http://localhost:4000/api/tournaments -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"name":"Super Sunday #2","location":"PC","start_date":"2025-10-05"}'
|
||||||
|
|
||||||
|
- Add participant:
|
||||||
|
curl -s http://localhost:4000/api/tournaments/1/participants -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"full_name":"Nouvel Joueur"}'
|
||||||
|
|
||||||
|
- Score match:
|
||||||
|
curl -s http://localhost:4000/api/matches/1/score -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"score_a":6,"score_b":4,"done":true}'
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "supersunday-api",
|
"name": "supersunday-backend",
|
||||||
"version": "1.1.0",
|
"version": "1.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node server.js"
|
"start": "node src/index.js",
|
||||||
|
"dev": "node --watch src/index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.6.1",
|
||||||
"express": "^4.19.2",
|
"express": "^4.21.2",
|
||||||
"helmet": "^7.1.0",
|
"helmet": "^7.2.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"morgan": "^1.10.0",
|
|
||||||
"pg": "^8.11.5"
|
"pg": "^8.11.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
backend/sql/schema.sql
Normal file
28
backend/sql/schema.sql
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
create table if not exists tournaments(
|
||||||
|
id serial primary key,
|
||||||
|
name text not null,
|
||||||
|
location text,
|
||||||
|
start_date date,
|
||||||
|
end_date date,
|
||||||
|
created_at timestamp default now()
|
||||||
|
);
|
||||||
|
create table if not exists participants(
|
||||||
|
id serial primary key,
|
||||||
|
tournament_id int not null references tournaments(id) on delete cascade,
|
||||||
|
full_name text not null,
|
||||||
|
created_at timestamp default now()
|
||||||
|
);
|
||||||
|
create index if not exists idx_participants_t on participants(tournament_id);
|
||||||
|
create table if not exists matches(
|
||||||
|
id serial primary key,
|
||||||
|
tournament_id int not null references tournaments(id) on delete cascade,
|
||||||
|
court text,
|
||||||
|
starts_at timestamp,
|
||||||
|
team_a text,
|
||||||
|
team_b text,
|
||||||
|
score_a int default 0,
|
||||||
|
score_b int default 0,
|
||||||
|
done boolean default false,
|
||||||
|
created_at timestamp default now()
|
||||||
|
);
|
||||||
|
create index if not exists idx_matches_t on matches(tournament_id);
|
||||||
11
backend/src/db.js
Normal file
11
backend/src/db.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import pg from 'pg';
|
||||||
|
const { Pool } = pg;
|
||||||
|
|
||||||
|
const pool = new Pool({
|
||||||
|
host: process.env.PGHOST || 'db',
|
||||||
|
port: Number(process.env.PGPORT || 5432),
|
||||||
|
user: process.env.PGUSER || 'postgres',
|
||||||
|
password: process.env.PGPASSWORD || 'postgres',
|
||||||
|
database: process.env.PGDATABASE || 'supersunday',
|
||||||
|
});
|
||||||
|
export default pool;
|
||||||
24
backend/src/index.js
Normal file
24
backend/src/index.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import 'dotenv/config';
|
||||||
|
import express from 'express';
|
||||||
|
import helmet from 'helmet';
|
||||||
|
import cors from 'cors';
|
||||||
|
|
||||||
|
import authRoutes from './routes/auth.js';
|
||||||
|
import tournamentsRoutes from './routes/tournaments.js';
|
||||||
|
import matchesRoutes from './routes/matches.js';
|
||||||
|
import standingsRoutes from './routes/standings.js';
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
app.use(helmet());
|
||||||
|
app.use(cors());
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
app.get('/api/health', (req,res)=>res.json({ ok:true, ts: Date.now() }));
|
||||||
|
|
||||||
|
app.use('/api/auth', authRoutes);
|
||||||
|
app.use('/api/tournaments', tournamentsRoutes);
|
||||||
|
app.use('/api/matches', matchesRoutes);
|
||||||
|
app.use('/api/tournaments', standingsRoutes);
|
||||||
|
|
||||||
|
const PORT = process.env.PORT || 4000;
|
||||||
|
app.listen(PORT, () => console.log(`API listening on :${PORT}`));
|
||||||
14
backend/src/middleware/auth.js
Normal file
14
backend/src/middleware/auth.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import jwt from 'jsonwebtoken';
|
||||||
|
|
||||||
|
export function requireAuth(req, res, next) {
|
||||||
|
try {
|
||||||
|
const h = req.headers.authorization || '';
|
||||||
|
const token = h.startsWith('Bearer ') ? h.slice(7) : '';
|
||||||
|
if (!token) return res.status(401).json({ error: 'missing_token' });
|
||||||
|
const decoded = jwt.verify(token, process.env.JWT_SECRET || 'supersecret');
|
||||||
|
req.user = decoded;
|
||||||
|
next();
|
||||||
|
} catch (e) {
|
||||||
|
res.status(401).json({ error: 'invalid_token' });
|
||||||
|
}
|
||||||
|
}
|
||||||
17
backend/src/routes/auth.js
Normal file
17
backend/src/routes/auth.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import jwt from 'jsonwebtoken';
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
router.post('/login', async (req, res) => {
|
||||||
|
const { email, password } = req.body || {};
|
||||||
|
const ADMIN_EMAIL = process.env.ADMIN_EMAIL || 'admin@supersunday.local';
|
||||||
|
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'changeme';
|
||||||
|
if (email === ADMIN_EMAIL && password === ADMIN_PASSWORD) {
|
||||||
|
const token = jwt.sign({ sub: email, role: 'admin' }, process.env.JWT_SECRET || 'supersecret', { expiresIn: '12h' });
|
||||||
|
return res.json({ token });
|
||||||
|
}
|
||||||
|
return res.status(401).json({ error: 'bad_credentials' });
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
20
backend/src/routes/matches.js
Normal file
20
backend/src/routes/matches.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import pool from '../db.js';
|
||||||
|
import { requireAuth } from '../middleware/auth.js';
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
// Score a match (admin)
|
||||||
|
router.post('/:id/score', requireAuth, async (req,res)=>{
|
||||||
|
const mid = Number(req.params.id);
|
||||||
|
const { score_a, score_b, done } = req.body || {};
|
||||||
|
if (!mid) return res.status(400).json({ error:'bad_match_id' });
|
||||||
|
const { rows } = await pool.query(
|
||||||
|
'update matches set score_a=$2, score_b=$3, done=coalesce($4, done) where id=$1 returning *',
|
||||||
|
[mid, score_a ?? 0, score_b ?? 0, done]
|
||||||
|
);
|
||||||
|
if (!rows[0]) return res.status(404).json({ error:'match_not_found' });
|
||||||
|
res.json(rows[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
78
backend/src/routes/standings.js
Normal file
78
backend/src/routes/standings.js
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import pool from '../db.js';
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
// GET /api/tournaments/:id/standings
|
||||||
|
router.get('/:id/standings', async (req, res) => {
|
||||||
|
const tid = Number(req.params.id);
|
||||||
|
if (!tid) return res.status(400).json({ error: 'bad_tournament_id' });
|
||||||
|
|
||||||
|
const { rows: players } = await pool.query('select id, full_name from participants where tournament_id=$1', [tid]);
|
||||||
|
const { rows: matches } = await pool.query('select * from matches where tournament_id=$1 order by id', [tid]);
|
||||||
|
|
||||||
|
const nameToId = new Map(players.map(p => [p.full_name, p.id]));
|
||||||
|
const stats = new Map(players.map(p => [p.id, {
|
||||||
|
player_id: p.id, name: p.full_name,
|
||||||
|
played: 0, wins: 0, draws: 0, losses: 0,
|
||||||
|
games_for: 0, games_against: 0, points: 0
|
||||||
|
}]));
|
||||||
|
|
||||||
|
const addStats = (pid, gf, ga, wdl) => {
|
||||||
|
const s = stats.get(pid);
|
||||||
|
s.played += 1;
|
||||||
|
s.games_for += gf;
|
||||||
|
s.games_against += ga;
|
||||||
|
if (wdl === 'W') s.wins += 1;
|
||||||
|
else if (wdl === 'D') s.draws += 1;
|
||||||
|
else if (wdl === 'L') s.losses += 1;
|
||||||
|
s.points += gf; // Americano style: points = games won
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const m of matches) {
|
||||||
|
if (!m.team_a || !m.team_b) continue;
|
||||||
|
const aNames = m.team_a.split('&').map(s => s.trim());
|
||||||
|
const bNames = m.team_b.split('&').map(s => s.trim());
|
||||||
|
const aIds = aNames.map(n => nameToId.get(n)).filter(Boolean);
|
||||||
|
const bIds = bNames.map(n => nameToId.get(n)).filter(Boolean);
|
||||||
|
|
||||||
|
const sa = Number(m.score_a || 0);
|
||||||
|
const sb = Number(m.score_b || 0);
|
||||||
|
const considered = m.done === true || sa > 0 || sb > 0;
|
||||||
|
if (!considered) continue;
|
||||||
|
|
||||||
|
let outcomeA = 'D', outcomeB = 'D';
|
||||||
|
if (sa > sb) { outcomeA = 'W'; outcomeB = 'L'; }
|
||||||
|
else if (sb > sa) { outcomeA = 'L'; outcomeB = 'W'; }
|
||||||
|
|
||||||
|
for (const pid of aIds) addStats(pid, sa, sb, outcomeA);
|
||||||
|
for (const pid of bIds) addStats(pid, sb, sa, outcomeB);
|
||||||
|
}
|
||||||
|
|
||||||
|
const table = Array.from(stats.values()).map(s => ({
|
||||||
|
...s,
|
||||||
|
diff: s.games_for - s.games_against,
|
||||||
|
rank_key: [-(s.points), -(s.diff), -(s.wins), s.name.toLowerCase()]
|
||||||
|
}));
|
||||||
|
|
||||||
|
table.sort((x, y) => {
|
||||||
|
for (let i = 0; i < x.rank_key.length; i++) {
|
||||||
|
if (x.rank_key[i] < y.rank_key[i]) return -1;
|
||||||
|
if (x.rank_key[i] > y.rank_key[i]) return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
let rank = 0, prevKey = null;
|
||||||
|
for (const row of table) {
|
||||||
|
const key = JSON.stringify(row.rank_key);
|
||||||
|
if (key !== prevKey) rank += 1;
|
||||||
|
row.rank = rank;
|
||||||
|
prevKey = key;
|
||||||
|
delete row.rank_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({ tournament_id: tid, standings: table });
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
59
backend/src/routes/tournaments.js
Normal file
59
backend/src/routes/tournaments.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import pool from '../db.js';
|
||||||
|
import { requireAuth } from '../middleware/auth.js';
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
// List
|
||||||
|
router.get('/', async (req,res)=>{
|
||||||
|
const { rows } = await pool.query('select * from tournaments order by start_date nulls last, id desc limit 200');
|
||||||
|
res.json(rows);
|
||||||
|
});
|
||||||
|
|
||||||
|
// One
|
||||||
|
router.get('/:id', async (req,res)=>{
|
||||||
|
const { rows } = await pool.query('select * from tournaments where id=$1', [req.params.id]);
|
||||||
|
if (!rows[0]) return res.status(404).json({ error:'not_found' });
|
||||||
|
res.json(rows[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Participants
|
||||||
|
router.get('/:id/participants', async (req,res)=>{
|
||||||
|
const { rows } = await pool.query('select * from participants where tournament_id=$1 order by id', [req.params.id]);
|
||||||
|
res.json(rows);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Matches
|
||||||
|
router.get('/:id/matches', async (req,res)=>{
|
||||||
|
const { rows } = await pool.query('select * from matches where tournament_id=$1 order by starts_at nulls last, id', [req.params.id]);
|
||||||
|
res.json(rows);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create tournament (admin)
|
||||||
|
router.post('/', requireAuth, async (req,res)=>{
|
||||||
|
const { name, location, start_date, end_date } = req.body || {};
|
||||||
|
if (!name) return res.status(400).json({ error:'name_required' });
|
||||||
|
const { rows } = await pool.query(
|
||||||
|
'insert into tournaments(name,location,start_date,end_date) values ($1,$2,$3,$4) returning *',
|
||||||
|
[name, location||null, start_date||null, end_date||null]
|
||||||
|
);
|
||||||
|
res.status(201).json(rows[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add participant (admin)
|
||||||
|
router.post('/:id/participants', requireAuth, async (req,res)=>{
|
||||||
|
const { full_name } = req.body || {};
|
||||||
|
const tid = Number(req.params.id);
|
||||||
|
if (!tid) return res.status(400).json({ error:'bad_tournament_id' });
|
||||||
|
if (!full_name) return res.status(400).json({ error:'full_name_required' });
|
||||||
|
// ensure tournament exists
|
||||||
|
const t = await pool.query('select id from tournaments where id=$1', [tid]);
|
||||||
|
if (!t.rows[0]) return res.status(404).json({ error:'tournament_not_found' });
|
||||||
|
const { rows } = await pool.query(
|
||||||
|
'insert into participants(tournament_id, full_name) values ($1,$2) returning *',
|
||||||
|
[tid, full_name]
|
||||||
|
);
|
||||||
|
res.status(201).json(rows[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
1
data/db/PG_VERSION
Normal file
1
data/db/PG_VERSION
Normal file
@@ -0,0 +1 @@
|
|||||||
|
16
|
||||||
BIN
data/db/base/1/112
Normal file
BIN
data/db/base/1/112
Normal file
Binary file not shown.
BIN
data/db/base/1/113
Normal file
BIN
data/db/base/1/113
Normal file
Binary file not shown.
BIN
data/db/base/1/1247
Normal file
BIN
data/db/base/1/1247
Normal file
Binary file not shown.
BIN
data/db/base/1/1247_fsm
Normal file
BIN
data/db/base/1/1247_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/1247_vm
Normal file
BIN
data/db/base/1/1247_vm
Normal file
Binary file not shown.
BIN
data/db/base/1/1249
Normal file
BIN
data/db/base/1/1249
Normal file
Binary file not shown.
BIN
data/db/base/1/1249_fsm
Normal file
BIN
data/db/base/1/1249_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/1249_vm
Normal file
BIN
data/db/base/1/1249_vm
Normal file
Binary file not shown.
BIN
data/db/base/1/1255
Normal file
BIN
data/db/base/1/1255
Normal file
Binary file not shown.
BIN
data/db/base/1/1255_fsm
Normal file
BIN
data/db/base/1/1255_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/1255_vm
Normal file
BIN
data/db/base/1/1255_vm
Normal file
Binary file not shown.
BIN
data/db/base/1/1259
Normal file
BIN
data/db/base/1/1259
Normal file
Binary file not shown.
BIN
data/db/base/1/1259_fsm
Normal file
BIN
data/db/base/1/1259_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/1259_vm
Normal file
BIN
data/db/base/1/1259_vm
Normal file
Binary file not shown.
BIN
data/db/base/1/13460
Normal file
BIN
data/db/base/1/13460
Normal file
Binary file not shown.
BIN
data/db/base/1/13460_fsm
Normal file
BIN
data/db/base/1/13460_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/13460_vm
Normal file
BIN
data/db/base/1/13460_vm
Normal file
Binary file not shown.
0
data/db/base/1/13463
Normal file
0
data/db/base/1/13463
Normal file
BIN
data/db/base/1/13464
Normal file
BIN
data/db/base/1/13464
Normal file
Binary file not shown.
BIN
data/db/base/1/13465
Normal file
BIN
data/db/base/1/13465
Normal file
Binary file not shown.
BIN
data/db/base/1/13465_fsm
Normal file
BIN
data/db/base/1/13465_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/13465_vm
Normal file
BIN
data/db/base/1/13465_vm
Normal file
Binary file not shown.
0
data/db/base/1/13468
Normal file
0
data/db/base/1/13468
Normal file
BIN
data/db/base/1/13469
Normal file
BIN
data/db/base/1/13469
Normal file
Binary file not shown.
BIN
data/db/base/1/13470
Normal file
BIN
data/db/base/1/13470
Normal file
Binary file not shown.
BIN
data/db/base/1/13470_fsm
Normal file
BIN
data/db/base/1/13470_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/13470_vm
Normal file
BIN
data/db/base/1/13470_vm
Normal file
Binary file not shown.
0
data/db/base/1/13473
Normal file
0
data/db/base/1/13473
Normal file
BIN
data/db/base/1/13474
Normal file
BIN
data/db/base/1/13474
Normal file
Binary file not shown.
BIN
data/db/base/1/13475
Normal file
BIN
data/db/base/1/13475
Normal file
Binary file not shown.
BIN
data/db/base/1/13475_fsm
Normal file
BIN
data/db/base/1/13475_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/13475_vm
Normal file
BIN
data/db/base/1/13475_vm
Normal file
Binary file not shown.
0
data/db/base/1/13478
Normal file
0
data/db/base/1/13478
Normal file
BIN
data/db/base/1/13479
Normal file
BIN
data/db/base/1/13479
Normal file
Binary file not shown.
0
data/db/base/1/1417
Normal file
0
data/db/base/1/1417
Normal file
0
data/db/base/1/1418
Normal file
0
data/db/base/1/1418
Normal file
BIN
data/db/base/1/174
Normal file
BIN
data/db/base/1/174
Normal file
Binary file not shown.
BIN
data/db/base/1/175
Normal file
BIN
data/db/base/1/175
Normal file
Binary file not shown.
BIN
data/db/base/1/2187
Normal file
BIN
data/db/base/1/2187
Normal file
Binary file not shown.
0
data/db/base/1/2224
Normal file
0
data/db/base/1/2224
Normal file
BIN
data/db/base/1/2228
Normal file
BIN
data/db/base/1/2228
Normal file
Binary file not shown.
0
data/db/base/1/2328
Normal file
0
data/db/base/1/2328
Normal file
0
data/db/base/1/2336
Normal file
0
data/db/base/1/2336
Normal file
BIN
data/db/base/1/2337
Normal file
BIN
data/db/base/1/2337
Normal file
Binary file not shown.
BIN
data/db/base/1/2579
Normal file
BIN
data/db/base/1/2579
Normal file
Binary file not shown.
BIN
data/db/base/1/2600
Normal file
BIN
data/db/base/1/2600
Normal file
Binary file not shown.
BIN
data/db/base/1/2600_fsm
Normal file
BIN
data/db/base/1/2600_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/2600_vm
Normal file
BIN
data/db/base/1/2600_vm
Normal file
Binary file not shown.
BIN
data/db/base/1/2601
Normal file
BIN
data/db/base/1/2601
Normal file
Binary file not shown.
BIN
data/db/base/1/2601_fsm
Normal file
BIN
data/db/base/1/2601_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/2601_vm
Normal file
BIN
data/db/base/1/2601_vm
Normal file
Binary file not shown.
BIN
data/db/base/1/2602
Normal file
BIN
data/db/base/1/2602
Normal file
Binary file not shown.
BIN
data/db/base/1/2602_fsm
Normal file
BIN
data/db/base/1/2602_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/2602_vm
Normal file
BIN
data/db/base/1/2602_vm
Normal file
Binary file not shown.
BIN
data/db/base/1/2603
Normal file
BIN
data/db/base/1/2603
Normal file
Binary file not shown.
BIN
data/db/base/1/2603_fsm
Normal file
BIN
data/db/base/1/2603_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/2603_vm
Normal file
BIN
data/db/base/1/2603_vm
Normal file
Binary file not shown.
0
data/db/base/1/2604
Normal file
0
data/db/base/1/2604
Normal file
BIN
data/db/base/1/2605
Normal file
BIN
data/db/base/1/2605
Normal file
Binary file not shown.
BIN
data/db/base/1/2605_fsm
Normal file
BIN
data/db/base/1/2605_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/2605_vm
Normal file
BIN
data/db/base/1/2605_vm
Normal file
Binary file not shown.
BIN
data/db/base/1/2606
Normal file
BIN
data/db/base/1/2606
Normal file
Binary file not shown.
BIN
data/db/base/1/2606_fsm
Normal file
BIN
data/db/base/1/2606_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/2606_vm
Normal file
BIN
data/db/base/1/2606_vm
Normal file
Binary file not shown.
BIN
data/db/base/1/2607
Normal file
BIN
data/db/base/1/2607
Normal file
Binary file not shown.
BIN
data/db/base/1/2607_fsm
Normal file
BIN
data/db/base/1/2607_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/2607_vm
Normal file
BIN
data/db/base/1/2607_vm
Normal file
Binary file not shown.
BIN
data/db/base/1/2608
Normal file
BIN
data/db/base/1/2608
Normal file
Binary file not shown.
BIN
data/db/base/1/2608_fsm
Normal file
BIN
data/db/base/1/2608_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/2608_vm
Normal file
BIN
data/db/base/1/2608_vm
Normal file
Binary file not shown.
BIN
data/db/base/1/2609
Normal file
BIN
data/db/base/1/2609
Normal file
Binary file not shown.
BIN
data/db/base/1/2609_fsm
Normal file
BIN
data/db/base/1/2609_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/2609_vm
Normal file
BIN
data/db/base/1/2609_vm
Normal file
Binary file not shown.
BIN
data/db/base/1/2610
Normal file
BIN
data/db/base/1/2610
Normal file
Binary file not shown.
BIN
data/db/base/1/2610_fsm
Normal file
BIN
data/db/base/1/2610_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/2610_vm
Normal file
BIN
data/db/base/1/2610_vm
Normal file
Binary file not shown.
0
data/db/base/1/2611
Normal file
0
data/db/base/1/2611
Normal file
BIN
data/db/base/1/2612
Normal file
BIN
data/db/base/1/2612
Normal file
Binary file not shown.
BIN
data/db/base/1/2612_fsm
Normal file
BIN
data/db/base/1/2612_fsm
Normal file
Binary file not shown.
BIN
data/db/base/1/2612_vm
Normal file
BIN
data/db/base/1/2612_vm
Normal file
Binary file not shown.
0
data/db/base/1/2613
Normal file
0
data/db/base/1/2613
Normal file
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user