feat: add registration and authentication
This commit is contained in:
@@ -2,8 +2,10 @@ import { Router, Request, Response } from "express";
|
||||
import { pool } from "../db";
|
||||
import { rowToDto, bodyToColumns, RaceRow } from "../mappers/race";
|
||||
import { extractRaceCoverImage } from "../raceCoverImage";
|
||||
import { requireAuth } from "../authMiddleware";
|
||||
|
||||
const router = Router();
|
||||
router.use(requireAuth);
|
||||
|
||||
type ValidationErrorBody = {
|
||||
error: "validation_error";
|
||||
@@ -69,6 +71,9 @@ router.get("/races", async (req: Request, res: Response) => {
|
||||
const params: unknown[] = [];
|
||||
let idx = 1;
|
||||
|
||||
conditions.push(`owner_user_id = $${idx++}`);
|
||||
params.push(req.auth!.user.id);
|
||||
|
||||
if (yearResult.value != null) {
|
||||
conditions.push(`EXTRACT(YEAR FROM race_date) = $${idx++}`);
|
||||
params.push(yearResult.value);
|
||||
@@ -94,8 +99,8 @@ router.get("/races", async (req: Request, res: Response) => {
|
||||
router.get("/races/:id", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { rows } = await pool.query<RaceRow>(
|
||||
"SELECT * FROM races WHERE id = $1",
|
||||
[req.params.id],
|
||||
"SELECT * FROM races WHERE id = $1 AND owner_user_id = $2",
|
||||
[req.params.id, req.auth!.user.id],
|
||||
);
|
||||
if (rows.length === 0) {
|
||||
res.status(404).json({ error: "not_found", details: ["Race not found"] });
|
||||
@@ -113,12 +118,14 @@ router.get("/races/:id", async (req: Request, res: Response) => {
|
||||
router.post("/races", async (req: Request, res: Response) => {
|
||||
const body = req.body;
|
||||
|
||||
if (!body.id || !body.date || !body.title || body.distanceKm == null) {
|
||||
validationError(res, ["Fields id, date, title, distanceKm are required"]);
|
||||
const slug = typeof body.slug === "string" && body.slug.trim() ? body.slug.trim() : body.id;
|
||||
|
||||
if (!slug || !body.date || !body.title || body.distanceKm == null) {
|
||||
validationError(res, ["Fields slug, date, title, distanceKm are required"]);
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = { ...body };
|
||||
const payload = { ...body, slug };
|
||||
const hasManualCover = typeof payload.coverImageUrl === "string" && payload.coverImageUrl.trim() !== "";
|
||||
const hasOfficialUrl = typeof payload.officialUrl === "string" && payload.officialUrl.trim() !== "";
|
||||
|
||||
@@ -127,8 +134,12 @@ router.post("/races", async (req: Request, res: Response) => {
|
||||
}
|
||||
|
||||
const { columns, values } = bodyToColumns(payload);
|
||||
columns.unshift("id");
|
||||
values.unshift(body.id);
|
||||
columns.unshift("owner_user_id");
|
||||
values.unshift(req.auth!.user.id);
|
||||
if (!columns.includes("slug")) {
|
||||
columns.push("slug");
|
||||
values.push(slug);
|
||||
}
|
||||
|
||||
const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
|
||||
const sql = `INSERT INTO races (${columns.join(", ")}) VALUES (${placeholders}) RETURNING *`;
|
||||
@@ -140,7 +151,7 @@ router.post("/races", async (req: Request, res: Response) => {
|
||||
if (err.code === "23505") {
|
||||
res.status(409).json({
|
||||
error: "conflict",
|
||||
details: ["Race with this id already exists"],
|
||||
details: ["Race with this slug already exists"],
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -162,7 +173,8 @@ router.patch("/races/:id", async (req: Request, res: Response) => {
|
||||
const sets = columns.map((col, i) => `${col} = $${i + 1}`);
|
||||
sets.push(`updated_at = NOW()`);
|
||||
values.push(req.params.id);
|
||||
const sql = `UPDATE races SET ${sets.join(", ")} WHERE id = $${values.length} RETURNING *`;
|
||||
values.push(req.auth!.user.id);
|
||||
const sql = `UPDATE races SET ${sets.join(", ")} WHERE id = $${values.length - 1} AND owner_user_id = $${values.length} RETURNING *`;
|
||||
|
||||
try {
|
||||
const { rows } = await pool.query<RaceRow>(sql, values);
|
||||
@@ -182,8 +194,8 @@ router.patch("/races/:id", async (req: Request, res: Response) => {
|
||||
router.delete("/races/:id", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { rowCount } = await pool.query(
|
||||
"DELETE FROM races WHERE id = $1",
|
||||
[req.params.id],
|
||||
"DELETE FROM races WHERE id = $1 AND owner_user_id = $2",
|
||||
[req.params.id, req.auth!.user.id],
|
||||
);
|
||||
if (rowCount === 0) {
|
||||
res.status(404).json({ error: "not_found", details: ["Race not found"] });
|
||||
|
||||
Reference in New Issue
Block a user