revoked access to website for coaches, added web-specific tokens
This commit is contained in:
@ -4,7 +4,7 @@ require_once __DIR__ . '/../db_init.php';
|
|||||||
|
|
||||||
header('Content-Type: application/json; charset=UTF-8');
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
$method = $_SERVER['REQUEST_METHOD'];
|
$method = $_SERVER['REQUEST_METHOD'];
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
|
|||||||
@ -4,8 +4,7 @@ require_once __DIR__ . '/../db_init.php';
|
|||||||
|
|
||||||
header('Content-Type: application/json; charset=UTF-8');
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
require_role(['admin', 'supervisor'], $tokenRec);
|
|
||||||
|
|
||||||
$callerRole = $tokenRec['role'];
|
$callerRole = $tokenRec['role'];
|
||||||
$callerEntityID = $tokenRec['entityID'] ?? '';
|
$callerEntityID = $tokenRec['entityID'] ?? '';
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
require_once __DIR__ . '/../common.php';
|
require_once __DIR__ . '/../common.php';
|
||||||
require_once __DIR__ . '/../db_init.php';
|
require_once __DIR__ . '/../db_init.php';
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||||
header('Content-Type: application/json; charset=UTF-8');
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|||||||
@ -11,7 +11,7 @@ require_once __DIR__ . '/../lib/validate.php';
|
|||||||
// CORS
|
// CORS
|
||||||
header('Access-Control-Allow-Origin: *');
|
header('Access-Control-Allow-Origin: *');
|
||||||
header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS');
|
header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS');
|
||||||
header('Access-Control-Allow-Headers: Content-Type, Authorization');
|
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-QDB-Client');
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||||
http_response_code(204);
|
http_response_code(204);
|
||||||
|
|||||||
@ -4,7 +4,7 @@ require_once __DIR__ . '/../db_init.php';
|
|||||||
|
|
||||||
header('Content-Type: application/json; charset=UTF-8');
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
$method = $_SERVER['REQUEST_METHOD'];
|
$method = $_SERVER['REQUEST_METHOD'];
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ require_once __DIR__ . '/../db_init.php';
|
|||||||
|
|
||||||
header('Content-Type: application/json; charset=UTF-8');
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
$method = $_SERVER['REQUEST_METHOD'];
|
$method = $_SERVER['REQUEST_METHOD'];
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ require_once __DIR__ . '/../db_init.php';
|
|||||||
|
|
||||||
header('Content-Type: application/json; charset=UTF-8');
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||||
http_response_code(405);
|
http_response_code(405);
|
||||||
|
|||||||
@ -4,7 +4,7 @@ require_once __DIR__ . '/../db_init.php';
|
|||||||
|
|
||||||
header('Content-Type: application/json; charset=UTF-8');
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
$method = $_SERVER['REQUEST_METHOD'];
|
$method = $_SERVER['REQUEST_METHOD'];
|
||||||
|
|
||||||
$validTypes = ['question', 'answer_option', 'string', 'language'];
|
$validTypes = ['question', 'answer_option', 'string', 'language'];
|
||||||
|
|||||||
@ -4,8 +4,7 @@ require_once __DIR__ . '/../db_init.php';
|
|||||||
|
|
||||||
header('Content-Type: application/json; charset=UTF-8');
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
require_role(['admin', 'supervisor'], $tokenRec);
|
|
||||||
|
|
||||||
$callerRole = $tokenRec['role'];
|
$callerRole = $tokenRec['role'];
|
||||||
$callerEntityID = $tokenRec['entityID'] ?? '';
|
$callerEntityID = $tokenRec['entityID'] ?? '';
|
||||||
|
|||||||
@ -5,8 +5,7 @@
|
|||||||
require_once __DIR__ . '/db_init.php';
|
require_once __DIR__ . '/db_init.php';
|
||||||
header('Content-Type: application/json; charset=UTF-8');
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
require_role(['admin', 'supervisor'], $tokenRec);
|
|
||||||
|
|
||||||
$role = $tokenRec['role'];
|
$role = $tokenRec['role'];
|
||||||
$entityID = $tokenRec['entityID'] ?? '';
|
$entityID = $tokenRec['entityID'] ?? '';
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
require_once __DIR__ . '/db_init.php';
|
require_once __DIR__ . '/db_init.php';
|
||||||
header('Content-Type: application/json; charset=UTF-8');
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
require_role(['admin'], $tokenRec);
|
require_role(['admin'], $tokenRec);
|
||||||
|
|
||||||
$dbPath = QDB_PATH;
|
$dbPath = QDB_PATH;
|
||||||
|
|||||||
@ -65,6 +65,16 @@ try {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (($user['role'] ?? '') === 'coach') {
|
||||||
|
qdb_discard($tmpDb, $lockFp);
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode([
|
||||||
|
"success" => false,
|
||||||
|
"message" => "Coach accounts can only sign in through the mobile app.",
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (!password_verify($oldPassword, $user['passwordHash'])) {
|
if (!password_verify($oldPassword, $user['passwordHash'])) {
|
||||||
qdb_discard($tmpDb, $lockFp);
|
qdb_discard($tmpDb, $lockFp);
|
||||||
http_response_code(401);
|
http_response_code(401);
|
||||||
|
|||||||
29
common.php
29
common.php
@ -178,6 +178,35 @@ function require_role(array $allowed, array $tokenRecord): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Roles that may use the management website (not the mobile app). */
|
||||||
|
function qdb_web_roles(): array {
|
||||||
|
return ['admin', 'supervisor'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** True when the request originates from the management website (see website/js/api.js). */
|
||||||
|
function qdb_is_web_client_request(): bool {
|
||||||
|
$h = $_SERVER['HTTP_X_QDB_CLIENT'] ?? '';
|
||||||
|
return strtolower(trim($h)) === 'web';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reject coach sign-in from the website; coaches use the mobile app only. */
|
||||||
|
function qdb_reject_coach_web_login(string $role): void {
|
||||||
|
if ($role === 'coach' && qdb_is_web_client_request()) {
|
||||||
|
json_error(
|
||||||
|
'FORBIDDEN',
|
||||||
|
'Coach accounts can only sign in through the mobile app.',
|
||||||
|
403
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Valid bearer token plus admin/supervisor role (website API). */
|
||||||
|
function require_valid_token_web(): array {
|
||||||
|
$rec = require_valid_token();
|
||||||
|
require_role(qdb_web_roles(), $rec);
|
||||||
|
return $rec;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a SQL WHERE clause fragment that restricts client visibility by role.
|
* Build a SQL WHERE clause fragment that restricts client visibility by role.
|
||||||
* Returns [string $clause, array $params].
|
* Returns [string $clause, array $params].
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// /var/www/html/db_download.php
|
// /var/www/html/db_download.php
|
||||||
require_once __DIR__ . '/db_init.php';
|
require_once __DIR__ . '/db_init.php';
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
|
|
||||||
$dbPath = QDB_PATH;
|
$dbPath = QDB_PATH;
|
||||||
if (!file_exists($dbPath)) { http_response_code(404); echo "Database not found"; exit; }
|
if (!file_exists($dbPath)) { http_response_code(404); echo "Database not found"; exit; }
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
require_once __DIR__ . '/db_init.php';
|
require_once __DIR__ . '/db_init.php';
|
||||||
header('Content-Type: text/html; charset=UTF-8');
|
header('Content-Type: text/html; charset=UTF-8');
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
|
|
||||||
$dbPath = QDB_PATH;
|
$dbPath = QDB_PATH;
|
||||||
if (!file_exists($dbPath)) { http_response_code(404); echo "Database not found"; exit; }
|
if (!file_exists($dbPath)) { http_response_code(404); echo "Database not found"; exit; }
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
require_once __DIR__ . '/db_init.php';
|
require_once __DIR__ . '/db_init.php';
|
||||||
header('Content-Type: text/html; charset=UTF-8');
|
header('Content-Type: text/html; charset=UTF-8');
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
|
|
||||||
$ORDER_JSON = __DIR__ . '/header_order.json';
|
$ORDER_JSON = __DIR__ . '/header_order.json';
|
||||||
$LABELS_JSON = __DIR__ . '/questions_en.json';
|
$LABELS_JSON = __DIR__ . '/questions_en.json';
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// /var/www/html/downloadFull.php
|
// /var/www/html/downloadFull.php
|
||||||
require_once __DIR__ . '/db_init.php';
|
require_once __DIR__ . '/db_init.php';
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
$token = $tokenRec['_token'];
|
$token = $tokenRec['_token'];
|
||||||
|
|
||||||
$dbPath = QDB_PATH;
|
$dbPath = QDB_PATH;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
$method = $_SERVER['REQUEST_METHOD'];
|
$method = $_SERVER['REQUEST_METHOD'];
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
require_role(['admin', 'supervisor'], $tokenRec);
|
|
||||||
|
|
||||||
$callerRole = $tokenRec['role'];
|
$callerRole = $tokenRec['role'];
|
||||||
$callerEntityID = $tokenRec['entityID'] ?? '';
|
$callerEntityID = $tokenRec['entityID'] ?? '';
|
||||||
|
|||||||
@ -43,6 +43,8 @@ case 'auth/login':
|
|||||||
|
|
||||||
qdb_discard($tmpDb, $lockFp);
|
qdb_discard($tmpDb, $lockFp);
|
||||||
|
|
||||||
|
qdb_reject_coach_web_login((string)($user['role'] ?? ''));
|
||||||
|
|
||||||
if ((int)$user['mustChangePassword'] === 1) {
|
if ((int)$user['mustChangePassword'] === 1) {
|
||||||
$tempToken = bin2hex(random_bytes(32));
|
$tempToken = bin2hex(random_bytes(32));
|
||||||
token_add($tempToken, 10 * 60, [
|
token_add($tempToken, 10 * 60, [
|
||||||
@ -127,6 +129,8 @@ case 'auth/change-password':
|
|||||||
json_error('FORBIDDEN', 'Token does not match user', 403);
|
json_error('FORBIDDEN', 'Token does not match user', 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qdb_reject_coach_web_login((string)($user['role'] ?? ''));
|
||||||
|
|
||||||
if (!password_verify($oldPassword, $user['passwordHash'])) {
|
if (!password_verify($oldPassword, $user['passwordHash'])) {
|
||||||
qdb_discard($tmpDb, $lockFp);
|
qdb_discard($tmpDb, $lockFp);
|
||||||
json_error('INVALID_CREDENTIALS', 'Old password incorrect', 401);
|
json_error('INVALID_CREDENTIALS', 'Old password incorrect', 401);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
require_role(['admin'], $tokenRec);
|
require_role(['admin'], $tokenRec);
|
||||||
|
|
||||||
$dbPath = QDB_PATH;
|
$dbPath = QDB_PATH;
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
require_role(['admin', 'supervisor'], $tokenRec);
|
|
||||||
|
|
||||||
$callerRole = $tokenRec['role'];
|
$callerRole = $tokenRec['role'];
|
||||||
$callerEntityID = $tokenRec['entityID'] ?? '';
|
$callerEntityID = $tokenRec['entityID'] ?? '';
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
$token = $tokenRec['_token'];
|
$token = $tokenRec['_token'];
|
||||||
|
|
||||||
if ($method !== 'GET') {
|
if ($method !== 'GET') {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
|
|
||||||
if ($method !== 'GET') {
|
if ($method !== 'GET') {
|
||||||
json_error('METHOD_NOT_ALLOWED', 'Method not allowed', 405);
|
json_error('METHOD_NOT_ALLOWED', 'Method not allowed', 405);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
|
|
||||||
if ($method !== 'GET') {
|
if ($method !== 'GET') {
|
||||||
json_error('METHOD_NOT_ALLOWED', 'Method not allowed', 405);
|
json_error('METHOD_NOT_ALLOWED', 'Method not allowed', 405);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
|
|
||||||
$validTypes = ['question', 'answer_option', 'string', 'app_string', 'language'];
|
$validTypes = ['question', 'answer_option', 'string', 'app_string', 'language'];
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
require_role(['admin', 'supervisor'], $tokenRec);
|
|
||||||
|
|
||||||
$callerRole = $tokenRec['role'];
|
$callerRole = $tokenRec['role'];
|
||||||
$callerEntityID = $tokenRec['entityID'] ?? '';
|
$callerEntityID = $tokenRec['entityID'] ?? '';
|
||||||
|
|||||||
@ -11,7 +11,7 @@ $isCli = (php_sapi_name() === 'cli');
|
|||||||
|
|
||||||
if (!$isCli) {
|
if (!$isCli) {
|
||||||
header('Content-Type: application/json; charset=UTF-8');
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
require_role(['admin'], $tokenRec);
|
require_role(['admin'], $tokenRec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -233,6 +233,11 @@ async function login(evt) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.role === 'coach') {
|
||||||
|
$('#loginMsg').textContent = 'Coach accounts can only sign in through the mobile app.';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.must_change_password) {
|
if (data.must_change_password) {
|
||||||
_pendingUser = data.user;
|
_pendingUser = data.user;
|
||||||
$('#loginCard').classList.add('hidden');
|
$('#loginCard').classList.add('hidden');
|
||||||
|
|||||||
@ -38,6 +38,15 @@ try {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (($user['role'] ?? '') === 'coach') {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode([
|
||||||
|
"success" => false,
|
||||||
|
"message" => "Coach accounts can only sign in through the mobile app.",
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
if ((int)$user['mustChangePassword'] === 1) {
|
if ((int)$user['mustChangePassword'] === 1) {
|
||||||
$tempToken = bin2hex(random_bytes(32));
|
$tempToken = bin2hex(random_bytes(32));
|
||||||
token_add($tempToken, 10 * 60, [
|
token_add($tempToken, 10 * 60, [
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
require_once __DIR__ . '/db_init.php';
|
require_once __DIR__ . '/db_init.php';
|
||||||
header('Content-Type: application/json; charset=UTF-8');
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|
||||||
$tokenRec = require_valid_token();
|
$tokenRec = require_valid_token_web();
|
||||||
require_role(['admin'], $tokenRec);
|
require_role(['admin'], $tokenRec);
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|||||||
@ -7,6 +7,7 @@ function getToken() {
|
|||||||
async function apiFetch(endpoint, options = {}) {
|
async function apiFetch(endpoint, options = {}) {
|
||||||
const token = getToken();
|
const token = getToken();
|
||||||
const headers = options.headers || {};
|
const headers = options.headers || {};
|
||||||
|
headers['X-QDB-Client'] = 'web';
|
||||||
if (token) headers['Authorization'] = `Bearer ${token}`;
|
if (token) headers['Authorization'] = `Bearer ${token}`;
|
||||||
if (!(options.body instanceof FormData)) {
|
if (!(options.body instanceof FormData)) {
|
||||||
headers['Content-Type'] = 'application/json; charset=UTF-8';
|
headers['Content-Type'] = 'application/json; charset=UTF-8';
|
||||||
|
|||||||
@ -19,9 +19,26 @@ export function getRole() {
|
|||||||
export function getUser() {
|
export function getUser() {
|
||||||
return localStorage.getItem('qdb_user') || '';
|
return localStorage.getItem('qdb_user') || '';
|
||||||
}
|
}
|
||||||
|
const WEBSITE_ROLES = ['admin', 'supervisor'];
|
||||||
|
|
||||||
|
export function canAccessWebsite() {
|
||||||
|
return WEBSITE_ROLES.includes(getRole());
|
||||||
|
}
|
||||||
|
|
||||||
export function canEdit() {
|
export function canEdit() {
|
||||||
const r = getRole();
|
return canAccessWebsite();
|
||||||
return r === 'admin' || r === 'supervisor';
|
}
|
||||||
|
|
||||||
|
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') {
|
export function showToast(message, type = 'info') {
|
||||||
@ -40,6 +57,7 @@ export function showToast(message, type = 'info') {
|
|||||||
function authGuard(handler) {
|
function authGuard(handler) {
|
||||||
return (params) => {
|
return (params) => {
|
||||||
if (!isLoggedIn()) { navigate('#/login'); return; }
|
if (!isLoggedIn()) { navigate('#/login'); return; }
|
||||||
|
if (!canAccessWebsite()) { rejectCoachSession(); return; }
|
||||||
return handler(params);
|
return handler(params);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -95,12 +113,14 @@ addRoute('/translations', roleGuard(['admin', 'supervisor'], translationsPage));
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
document.getElementById('logoutBtn').addEventListener('click', (e) => {
|
document.getElementById('logoutBtn').addEventListener('click', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
localStorage.removeItem('qdb_token');
|
clearSession();
|
||||||
localStorage.removeItem('qdb_user');
|
|
||||||
localStorage.removeItem('qdb_role');
|
|
||||||
navigate('#/login');
|
navigate('#/login');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (isLoggedIn() && !canAccessWebsite()) {
|
||||||
|
clearSession();
|
||||||
|
}
|
||||||
|
|
||||||
window.addEventListener('hashchange', updateNav);
|
window.addEventListener('hashchange', updateNav);
|
||||||
updateNav();
|
updateNav();
|
||||||
startRouter();
|
startRouter();
|
||||||
|
|||||||
@ -55,7 +55,10 @@ export function loginPage() {
|
|||||||
try {
|
try {
|
||||||
const res = await fetch('../api/auth/login', {
|
const res = await fetch('../api/auth/login', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-QDB-Client': 'web',
|
||||||
|
},
|
||||||
body: JSON.stringify({ username, password }),
|
body: JSON.stringify({ username, password }),
|
||||||
});
|
});
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
@ -65,6 +68,11 @@ export function loginPage() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const d = json.data;
|
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) {
|
if (d.mustChangePassword) {
|
||||||
pendingUsername = username;
|
pendingUsername = username;
|
||||||
pendingTempToken = d.token;
|
pendingTempToken = d.token;
|
||||||
@ -95,7 +103,10 @@ export function loginPage() {
|
|||||||
}
|
}
|
||||||
const oldPw = document.getElementById('password').value;
|
const oldPw = document.getElementById('password').value;
|
||||||
try {
|
try {
|
||||||
const headers = { 'Content-Type': 'application/json' };
|
const headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-QDB-Client': 'web',
|
||||||
|
};
|
||||||
if (pendingTempToken) {
|
if (pendingTempToken) {
|
||||||
headers['Authorization'] = `Bearer ${pendingTempToken}`;
|
headers['Authorization'] = `Bearer ${pendingTempToken}`;
|
||||||
}
|
}
|
||||||
@ -111,6 +122,11 @@ export function loginPage() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const d = json.data;
|
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_token', d.token);
|
||||||
localStorage.setItem('qdb_user', d.user);
|
localStorage.setItem('qdb_user', d.user);
|
||||||
localStorage.setItem('qdb_role', d.role);
|
localStorage.setItem('qdb_role', d.role);
|
||||||
|
|||||||
Reference in New Issue
Block a user