From 64cfdc3c6d18c5dc069ebbf4df65d6742ea19a44 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 20 Dec 2025 22:34:44 +0000 Subject: [PATCH] Add settings API for managing active Oscar year Co-authored-by: mathieumoran1 --- index.js | 2 ++ models/Setting.js | 14 ++++++++ routes/settings.js | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 models/Setting.js create mode 100644 routes/settings.js diff --git a/index.js b/index.js index f0a5f43..bdde37a 100644 --- a/index.js +++ b/index.js @@ -20,11 +20,13 @@ mongoose const userRoutes = require("./routes/users"); const movieRoutes = require("./routes/movies"); const versionRoutes = require("./routes/version"); +const settingsRoutes = require("./routes/settings"); app.use(express.static('public')); app.use("/api/users", userRoutes); app.use("/api/movies", movieRoutes); app.use("/api/version", versionRoutes); +app.use("/api/settings", settingsRoutes); // Start Server const PORT = process.env.PORT || 5000; diff --git a/models/Setting.js b/models/Setting.js new file mode 100644 index 0000000..f5eea63 --- /dev/null +++ b/models/Setting.js @@ -0,0 +1,14 @@ +const mongoose = require("mongoose"); + +// Simple key/value store for global site settings. +// We currently use it for the "active Oscar year" that drives filtering. +const settingSchema = new mongoose.Schema( + { + key: { type: String, required: true, unique: true, index: true }, + value: { type: mongoose.Schema.Types.Mixed, required: true }, + }, + { timestamps: true } +); + +module.exports = mongoose.model("Setting", settingSchema); + diff --git a/routes/settings.js b/routes/settings.js new file mode 100644 index 0000000..c7d68b3 --- /dev/null +++ b/routes/settings.js @@ -0,0 +1,82 @@ +const express = require("express"); +const jwt = require("jsonwebtoken"); + +const Setting = require("../models/Setting"); +const Movie = require("../models/Movie"); + +const router = express.Router(); + +const ACTIVE_YEAR_KEY = "active_oscar_year"; + +function parseOscarYear(raw) { + if (raw === undefined || raw === null || raw === "") return null; + const n = Number(raw); + if (!Number.isInteger(n)) return null; + if (n < 1900 || n > 3000) return null; + return n; +} + +async function getOrInitActiveYear() { + const existing = await Setting.findOne({ key: ACTIVE_YEAR_KEY }); + if (existing && typeof existing.value === "number") return existing.value; + + // Initialize from latest movie year if available, else from current year. + const latestMovie = await Movie.findOne({ year: { $type: "number" } }) + .sort({ year: -1 }) + .select("year"); + + const fallbackYear = latestMovie?.year || new Date().getFullYear(); + const year = parseOscarYear(fallbackYear) || new Date().getFullYear(); + + await Setting.findOneAndUpdate( + { key: ACTIVE_YEAR_KEY }, + { $set: { value: year } }, + { upsert: true, new: true } + ); + + return year; +} + +// Public: get current active Oscar year used by the site. +router.get("/year", async (req, res) => { + try { + const year = await getOrInitActiveYear(); + return res.status(200).json({ year }); + } catch (err) { + return res.status(500).json({ error: err.message }); + } +}); + +// Admin-only: set current active Oscar year. +router.put("/year", async (req, res) => { + const token = req.headers.authorization?.split(" ")[1]; + if (!token) return res.status(401).json({ message: "Authentication token is required" }); + + try { + const decoded = jwt.verify(token, process.env.JWT_SECRET); + if (!decoded.admin) { + return res.status(403).json({ message: "You do not have admin privileges" }); + } + + const year = parseOscarYear(req.body?.year); + if (!year) { + return res.status(400).json({ message: "Année invalide (ex: 2026)" }); + } + + const updated = await Setting.findOneAndUpdate( + { key: ACTIVE_YEAR_KEY }, + { $set: { value: year } }, + { upsert: true, new: true } + ); + + return res.status(200).json({ year: updated.value }); + } catch (err) { + if (err instanceof jwt.JsonWebTokenError) { + return res.status(401).json({ message: "Invalid or expired token" }); + } + return res.status(500).json({ error: err.message }); + } +}); + +module.exports = router; + -- 2.54.0