Add movie runtime, bulk OMDb refresh, and first-time setup
- Add runtime field to Movie model and display formatted duration (e.g., 2h 22min) on movie cards - Add bulk "Refresh OMDb" button in admin panel for selected movies - Add runtime field to movie edit modal in admin panel - Implement first-time setup flow: show admin creation form on login page when no admin exists - Block registration page until initial setup is complete Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
087f4f4023
commit
6186f3a051
+118
-35
@@ -22,49 +22,132 @@ async function applyActiveOscarYearToTitle() {
|
||||
// Fire and forget.
|
||||
applyActiveOscarYearToTitle();
|
||||
|
||||
// Check if the user is already logged in by looking for auth_token in localStorage
|
||||
const existingToken = localStorage.getItem('auth_token');
|
||||
if (existingToken) {
|
||||
// Check setup status first
|
||||
async function checkSetupStatus() {
|
||||
try {
|
||||
const decoded = decodeJwt(existingToken);
|
||||
const currentTime = Math.floor(Date.now() / 1000);
|
||||
if (decoded.exp && decoded.exp < currentTime) {
|
||||
localStorage.removeItem('auth_token');
|
||||
} else if (decoded.mustChangePassword) {
|
||||
window.location.href = '/change-password.html';
|
||||
} else {
|
||||
window.location.href = '/movies.html';
|
||||
}
|
||||
const res = await fetch('/api/users/setup/status', { method: 'GET', cache: 'no-store' });
|
||||
if (!res.ok) return { needsSetup: false };
|
||||
return await res.json();
|
||||
} catch (_) {
|
||||
localStorage.removeItem('auth_token');
|
||||
return { needsSetup: false };
|
||||
}
|
||||
}
|
||||
|
||||
// Handle login form submission
|
||||
document.getElementById('login-form').addEventListener('submit', async function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const email = document.getElementById('email').value;
|
||||
const password = document.getElementById('password').value;
|
||||
|
||||
const res = await fetch('/api/users/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email, password })
|
||||
});
|
||||
async function initPage() {
|
||||
const setupCard = document.getElementById('setup-card');
|
||||
const loginCard = document.getElementById('login-card');
|
||||
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
// Save the token to localStorage
|
||||
localStorage.setItem('auth_token', data.token);
|
||||
// Check if setup is needed
|
||||
const status = await checkSetupStatus();
|
||||
|
||||
if (data.mustChangePassword) {
|
||||
if (status.needsSetup) {
|
||||
// Show setup card, hide login card
|
||||
if (setupCard) setupCard.classList.remove('d-none');
|
||||
if (loginCard) loginCard.classList.add('d-none');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the user is already logged in
|
||||
const existingToken = localStorage.getItem('auth_token');
|
||||
if (existingToken) {
|
||||
try {
|
||||
const decoded = decodeJwt(existingToken);
|
||||
const currentTime = Math.floor(Date.now() / 1000);
|
||||
if (decoded.exp && decoded.exp < currentTime) {
|
||||
localStorage.removeItem('auth_token');
|
||||
} else if (decoded.mustChangePassword) {
|
||||
window.location.href = '/change-password.html';
|
||||
return;
|
||||
} else {
|
||||
window.location.href = '/movies.html'; // Redirect to movies page on success
|
||||
window.location.href = '/movies.html';
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const error = await res.json();
|
||||
alert(`${error.message}`);
|
||||
} catch (_) {
|
||||
localStorage.removeItem('auth_token');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the page
|
||||
initPage();
|
||||
|
||||
// Handle setup form submission
|
||||
const setupForm = document.getElementById('setup-form');
|
||||
if (setupForm) {
|
||||
setupForm.addEventListener('submit', async function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const setupError = document.getElementById('setup-error');
|
||||
const name = document.getElementById('setup-name').value.trim();
|
||||
const email = document.getElementById('setup-email').value.trim();
|
||||
const password = document.getElementById('setup-password').value;
|
||||
const passwordConfirm = document.getElementById('setup-password-confirm').value;
|
||||
|
||||
// Hide previous error
|
||||
if (setupError) setupError.classList.add('d-none');
|
||||
|
||||
// Validate passwords match
|
||||
if (password !== passwordConfirm) {
|
||||
if (setupError) {
|
||||
setupError.textContent = 'Les mots de passe ne correspondent pas';
|
||||
setupError.classList.remove('d-none');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/users/setup/admin', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name, email, password })
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (res.ok) {
|
||||
// Save the token and redirect
|
||||
localStorage.setItem('auth_token', data.token);
|
||||
window.location.href = '/movies.html';
|
||||
} else {
|
||||
if (setupError) {
|
||||
setupError.textContent = data.message || 'Erreur lors de la création du compte';
|
||||
setupError.classList.remove('d-none');
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (setupError) {
|
||||
setupError.textContent = 'Erreur réseau. Veuillez réessayer.';
|
||||
setupError.classList.remove('d-none');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Handle login form submission
|
||||
document.getElementById('login-form').addEventListener('submit', async function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const email = document.getElementById('email').value;
|
||||
const password = document.getElementById('password').value;
|
||||
|
||||
const res = await fetch('/api/users/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email, password })
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
// Save the token to localStorage
|
||||
localStorage.setItem('auth_token', data.token);
|
||||
|
||||
if (data.mustChangePassword) {
|
||||
window.location.href = '/change-password.html';
|
||||
} else {
|
||||
window.location.href = '/movies.html'; // Redirect to movies page on success
|
||||
}
|
||||
} else {
|
||||
const error = await res.json();
|
||||
alert(`${error.message}`);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user