feat: Add no-cache headers to API requests
Co-authored-by: mathieumoran1 <[email protected]>
This commit is contained in:
co-authored by
mathieumoran1
parent
d8bc03fecc
commit
bacd25f1ac
@@ -159,7 +159,7 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
|
|
||||||
async function fetchCompletionModalContent() {
|
async function fetchCompletionModalContent() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/settings/completion-modal', { method: 'GET' });
|
const res = await fetch('/api/settings/completion-modal', { method: 'GET', cache: 'no-cache' });
|
||||||
if (!res.ok) throw new Error('Failed to fetch completion modal');
|
if (!res.ok) throw new Error('Failed to fetch completion modal');
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
return {
|
return {
|
||||||
@@ -217,7 +217,7 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
|
|
||||||
async function fetchActiveYear() {
|
async function fetchActiveYear() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/settings/year', { method: 'GET' });
|
const res = await fetch('/api/settings/year', { method: 'GET', cache: 'no-cache' });
|
||||||
if (!res.ok) throw new Error('Failed to fetch active year');
|
if (!res.ok) throw new Error('Failed to fetch active year');
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const year = Number(data?.year);
|
const year = Number(data?.year);
|
||||||
@@ -229,7 +229,7 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
|
|
||||||
async function fetchOscarEffectiveDate(year) {
|
async function fetchOscarEffectiveDate(year) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/settings/oscar-date?year=${encodeURIComponent(String(year))}`, { method: 'GET' });
|
const res = await fetch(`/api/settings/oscar-date?year=${encodeURIComponent(String(year))}`, { method: 'GET', cache: 'no-cache' });
|
||||||
if (!res.ok) throw new Error('Failed to fetch oscar date');
|
if (!res.ok) throw new Error('Failed to fetch oscar date');
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const effectiveDate = typeof data?.effectiveDate === 'string' ? data.effectiveDate : null;
|
const effectiveDate = typeof data?.effectiveDate === 'string' ? data.effectiveDate : null;
|
||||||
@@ -247,7 +247,8 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
async function fetchMoviesSummary(year) {
|
async function fetchMoviesSummary(year) {
|
||||||
const res = await fetch(`/api/movies/summary?year=${encodeURIComponent(String(year))}`, {
|
const res = await fetch(`/api/movies/summary?year=${encodeURIComponent(String(year))}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { 'Authorization': `Bearer ${token}` }
|
headers: { 'Authorization': `Bearer ${token}` },
|
||||||
|
cache: 'no-cache',
|
||||||
});
|
});
|
||||||
if (!res.ok) throw new Error('Failed to fetch movies summary');
|
if (!res.ok) throw new Error('Failed to fetch movies summary');
|
||||||
return await res.json();
|
return await res.json();
|
||||||
@@ -346,7 +347,8 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
fetchCompletionModalContent(),
|
fetchCompletionModalContent(),
|
||||||
fetch(`/api/movies?year=${encodeURIComponent(String(activeYear))}&view=checklist`, {
|
fetch(`/api/movies?year=${encodeURIComponent(String(activeYear))}&view=checklist`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { 'Authorization': `Bearer ${token}` }
|
headers: { 'Authorization': `Bearer ${token}` },
|
||||||
|
cache: 'no-cache',
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -498,7 +500,8 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
|
|
||||||
const updatedWatchedMoviesRes = await fetch('/api/movies/watchedMovies', {
|
const updatedWatchedMoviesRes = await fetch('/api/movies/watchedMovies', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { 'Authorization': `Bearer ${token}` }
|
headers: { 'Authorization': `Bearer ${token}` },
|
||||||
|
cache: 'no-cache',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (updatedWatchedMoviesRes.ok) {
|
if (updatedWatchedMoviesRes.ok) {
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
|
|
||||||
async function fetchActiveYear() {
|
async function fetchActiveYear() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/settings/year', { method: 'GET' });
|
const res = await fetch('/api/settings/year', { method: 'GET', cache: 'no-cache' });
|
||||||
if (!res.ok) throw new Error('Failed to fetch active year');
|
if (!res.ok) throw new Error('Failed to fetch active year');
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const year = Number(data?.year);
|
const year = Number(data?.year);
|
||||||
@@ -174,7 +174,7 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
|
|
||||||
async function fetchOscarEffectiveDate(year) {
|
async function fetchOscarEffectiveDate(year) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/settings/oscar-date?year=${encodeURIComponent(String(year))}`, { method: 'GET' });
|
const res = await fetch(`/api/settings/oscar-date?year=${encodeURIComponent(String(year))}`, { method: 'GET', cache: 'no-cache' });
|
||||||
if (!res.ok) throw new Error('Failed to fetch oscar date');
|
if (!res.ok) throw new Error('Failed to fetch oscar date');
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const effectiveDate = typeof data?.effectiveDate === 'string' ? data.effectiveDate : null;
|
const effectiveDate = typeof data?.effectiveDate === 'string' ? data.effectiveDate : null;
|
||||||
@@ -194,6 +194,7 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
const res = await fetch(`/api/movies/summary?year=${encodeURIComponent(String(year))}`, {
|
const res = await fetch(`/api/movies/summary?year=${encodeURIComponent(String(year))}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { 'Authorization': `Bearer ${token}` },
|
headers: { 'Authorization': `Bearer ${token}` },
|
||||||
|
cache: 'no-cache',
|
||||||
});
|
});
|
||||||
if (!res.ok) throw new Error('Failed to fetch movies summary');
|
if (!res.ok) throw new Error('Failed to fetch movies summary');
|
||||||
return await res.json();
|
return await res.json();
|
||||||
@@ -319,6 +320,7 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
const res = await fetch(`/api/movies?year=${encodeURIComponent(String(activeYear))}`, {
|
const res = await fetch(`/api/movies?year=${encodeURIComponent(String(activeYear))}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { 'Authorization': `Bearer ${token}` },
|
headers: { 'Authorization': `Bearer ${token}` },
|
||||||
|
cache: 'no-cache',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
|
|
||||||
async function fetchActiveYear() {
|
async function fetchActiveYear() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/settings/year', { method: 'GET' });
|
const res = await fetch('/api/settings/year', { method: 'GET', cache: 'no-cache' });
|
||||||
if (!res.ok) throw new Error('Failed to fetch active year');
|
if (!res.ok) throw new Error('Failed to fetch active year');
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const year = Number(data?.year);
|
const year = Number(data?.year);
|
||||||
@@ -142,7 +142,7 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
|
|
||||||
async function fetchWinners() {
|
async function fetchWinners() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/settings/winners', { method: 'GET' });
|
const res = await fetch('/api/settings/winners', { method: 'GET', cache: 'no-cache' });
|
||||||
if (!res.ok) throw new Error('Failed to fetch winners');
|
if (!res.ok) throw new Error('Failed to fetch winners');
|
||||||
const data = await res.json().catch(() => ({}));
|
const data = await res.json().catch(() => ({}));
|
||||||
return Array.isArray(data?.winners) ? data.winners : [];
|
return Array.isArray(data?.winners) ? data.winners : [];
|
||||||
@@ -155,7 +155,8 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
try {
|
try {
|
||||||
const res = await fetch('/api/users/completions', {
|
const res = await fetch('/api/users/completions', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { 'Authorization': `Bearer ${token}` }
|
headers: { 'Authorization': `Bearer ${token}` },
|
||||||
|
cache: 'no-cache',
|
||||||
});
|
});
|
||||||
if (!res.ok) throw new Error('Failed to fetch completions');
|
if (!res.ok) throw new Error('Failed to fetch completions');
|
||||||
const data = await res.json().catch(() => ({}));
|
const data = await res.json().catch(() => ({}));
|
||||||
@@ -650,7 +651,8 @@ window.addEventListener('DOMContentLoaded', async function () {
|
|||||||
const [statsRes, winners, completions] = await Promise.all([
|
const [statsRes, winners, completions] = await Promise.all([
|
||||||
fetch(statsUrl, {
|
fetch(statsUrl, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { 'Authorization': `Bearer ${token}` }
|
headers: { 'Authorization': `Bearer ${token}` },
|
||||||
|
cache: 'no-cache',
|
||||||
}),
|
}),
|
||||||
fetchWinners(),
|
fetchWinners(),
|
||||||
fetchCompletions(),
|
fetchCompletions(),
|
||||||
|
|||||||
@@ -291,6 +291,9 @@ router.get("/watchedMovies", async (req, res) => {
|
|||||||
const user = await User.findById(decoded.id).select("watchedMovies").lean(); // Get user by ID
|
const user = await User.findById(decoded.id).select("watchedMovies").lean(); // Get user by ID
|
||||||
if (!user) return res.status(404).json({ message: "User not found" });
|
if (!user) return res.status(404).json({ message: "User not found" });
|
||||||
|
|
||||||
|
// User-specific: never allow shared/proxy caching.
|
||||||
|
res.set("Cache-Control", "private, no-store, must-revalidate");
|
||||||
|
res.set("Vary", "Authorization");
|
||||||
res.status(200).json(user.watchedMovies); // Return the list of watched movies
|
res.status(200).json(user.watchedMovies); // Return the list of watched movies
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({ error: error.message });
|
res.status(500).json({ error: error.message });
|
||||||
|
|||||||
@@ -122,6 +122,10 @@ async function getOrInitActiveYear() {
|
|||||||
// Get user stats with watched movie titles and details from the movies collection
|
// Get user stats with watched movie titles and details from the movies collection
|
||||||
router.get("/stats", verifyToken, async (req, res) => {
|
router.get("/stats", verifyToken, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
// Auth-scoped response: never allow caching.
|
||||||
|
res.set("Cache-Control", "private, no-store, must-revalidate");
|
||||||
|
res.set("Vary", "Authorization");
|
||||||
|
|
||||||
// Fetch all users (only needed fields)
|
// Fetch all users (only needed fields)
|
||||||
const users = await User.find().select("name watchedMovies").lean();
|
const users = await User.find().select("name watchedMovies").lean();
|
||||||
|
|
||||||
@@ -192,6 +196,10 @@ router.get("/stats", verifyToken, async (req, res) => {
|
|||||||
// Returns: { years: number[], totals: { [year]: number }, completersByYear: { [year]: {name, watchedCount, totalMoviesCount}[] } }
|
// Returns: { years: number[], totals: { [year]: number }, completersByYear: { [year]: {name, watchedCount, totalMoviesCount}[] } }
|
||||||
router.get("/completions", verifyToken, async (req, res) => {
|
router.get("/completions", verifyToken, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
// Auth-scoped response: never allow caching.
|
||||||
|
res.set("Cache-Control", "private, no-store, must-revalidate");
|
||||||
|
res.set("Vary", "Authorization");
|
||||||
|
|
||||||
const yearsRaw = await Movie.distinct("year");
|
const yearsRaw = await Movie.distinct("year");
|
||||||
const years = (Array.isArray(yearsRaw) ? yearsRaw : [])
|
const years = (Array.isArray(yearsRaw) ? yearsRaw : [])
|
||||||
.map((y) => Number(y))
|
.map((y) => Number(y))
|
||||||
|
|||||||
Reference in New Issue
Block a user