revoked access to website for coaches, added web-specific tokens
This commit is contained in:
@ -7,6 +7,7 @@ function getToken() {
|
||||
async function apiFetch(endpoint, options = {}) {
|
||||
const token = getToken();
|
||||
const headers = options.headers || {};
|
||||
headers['X-QDB-Client'] = 'web';
|
||||
if (token) headers['Authorization'] = `Bearer ${token}`;
|
||||
if (!(options.body instanceof FormData)) {
|
||||
headers['Content-Type'] = 'application/json; charset=UTF-8';
|
||||
|
||||
@ -19,9 +19,26 @@ export function getRole() {
|
||||
export function getUser() {
|
||||
return localStorage.getItem('qdb_user') || '';
|
||||
}
|
||||
const WEBSITE_ROLES = ['admin', 'supervisor'];
|
||||
|
||||
export function canAccessWebsite() {
|
||||
return WEBSITE_ROLES.includes(getRole());
|
||||
}
|
||||
|
||||
export function canEdit() {
|
||||
const r = getRole();
|
||||
return r === 'admin' || r === 'supervisor';
|
||||
return canAccessWebsite();
|
||||
}
|
||||
|
||||
function clearSession() {
|
||||
localStorage.removeItem('qdb_token');
|
||||
localStorage.removeItem('qdb_user');
|
||||
localStorage.removeItem('qdb_role');
|
||||
}
|
||||
|
||||
function rejectCoachSession() {
|
||||
clearSession();
|
||||
showToast('Coach accounts must use the mobile app.', 'error');
|
||||
navigate('#/login');
|
||||
}
|
||||
|
||||
export function showToast(message, type = 'info') {
|
||||
@ -40,6 +57,7 @@ export function showToast(message, type = 'info') {
|
||||
function authGuard(handler) {
|
||||
return (params) => {
|
||||
if (!isLoggedIn()) { navigate('#/login'); return; }
|
||||
if (!canAccessWebsite()) { rejectCoachSession(); return; }
|
||||
return handler(params);
|
||||
};
|
||||
}
|
||||
@ -95,12 +113,14 @@ addRoute('/translations', roleGuard(['admin', 'supervisor'], translationsPage));
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.getElementById('logoutBtn').addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
localStorage.removeItem('qdb_token');
|
||||
localStorage.removeItem('qdb_user');
|
||||
localStorage.removeItem('qdb_role');
|
||||
clearSession();
|
||||
navigate('#/login');
|
||||
});
|
||||
|
||||
if (isLoggedIn() && !canAccessWebsite()) {
|
||||
clearSession();
|
||||
}
|
||||
|
||||
window.addEventListener('hashchange', updateNav);
|
||||
updateNav();
|
||||
startRouter();
|
||||
|
||||
@ -55,7 +55,10 @@ export function loginPage() {
|
||||
try {
|
||||
const res = await fetch('../api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-QDB-Client': 'web',
|
||||
},
|
||||
body: JSON.stringify({ username, password }),
|
||||
});
|
||||
const json = await res.json();
|
||||
@ -65,6 +68,11 @@ export function loginPage() {
|
||||
return;
|
||||
}
|
||||
const d = json.data;
|
||||
if (d.role === 'coach') {
|
||||
errEl.textContent = 'Coach accounts can only sign in through the mobile app.';
|
||||
errEl.style.display = '';
|
||||
return;
|
||||
}
|
||||
if (d.mustChangePassword) {
|
||||
pendingUsername = username;
|
||||
pendingTempToken = d.token;
|
||||
@ -95,7 +103,10 @@ export function loginPage() {
|
||||
}
|
||||
const oldPw = document.getElementById('password').value;
|
||||
try {
|
||||
const headers = { 'Content-Type': 'application/json' };
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-QDB-Client': 'web',
|
||||
};
|
||||
if (pendingTempToken) {
|
||||
headers['Authorization'] = `Bearer ${pendingTempToken}`;
|
||||
}
|
||||
@ -111,6 +122,11 @@ export function loginPage() {
|
||||
return;
|
||||
}
|
||||
const d = json.data;
|
||||
if (d.role === 'coach') {
|
||||
errEl.textContent = 'Coach accounts can only sign in through the mobile app.';
|
||||
errEl.style.display = '';
|
||||
return;
|
||||
}
|
||||
localStorage.setItem('qdb_token', d.token);
|
||||
localStorage.setItem('qdb_user', d.user);
|
||||
localStorage.setItem('qdb_role', d.role);
|
||||
|
||||
Reference in New Issue
Block a user