160 lines
3.8 KiB
JavaScript
Executable File
160 lines
3.8 KiB
JavaScript
Executable File
import {
|
|
clearAuthState,
|
|
fetchWithAuth,
|
|
getAccessToken,
|
|
getAuthState,
|
|
logoutSession,
|
|
refreshAccessToken,
|
|
restoreSession,
|
|
storeAuthState
|
|
} from '../../auth-session.js';
|
|
|
|
export function getToken() {
|
|
return getAccessToken();
|
|
}
|
|
|
|
export function getSession() {
|
|
return getAuthState();
|
|
}
|
|
|
|
export async function initializeSession() {
|
|
return restoreSession();
|
|
}
|
|
|
|
export function isAuthenticatedAsAdmin() {
|
|
const role = getAuthState()?.role;
|
|
return getToken() && role === 'ADMIN';
|
|
}
|
|
|
|
export function isAuthenticatedAsRole(expectedRole) {
|
|
const role = getAuthState()?.role;
|
|
return getToken() && role === expectedRole;
|
|
}
|
|
|
|
export function isAuthenticatedAsAny(roles) {
|
|
const role = getAuthState()?.role;
|
|
return getToken() && roles.includes(role);
|
|
}
|
|
|
|
function getHeaders(contentType = 'application/json') {
|
|
const headers = {};
|
|
const token = getToken();
|
|
if (token) {
|
|
headers.Authorization = `Bearer ${token}`;
|
|
}
|
|
if (contentType) {
|
|
headers['Content-Type'] = contentType;
|
|
}
|
|
return headers;
|
|
}
|
|
|
|
export async function apiFetch(endpoint, method = 'GET', body = null, retryOnUnauthorized = true) {
|
|
const options = {
|
|
method,
|
|
headers: getHeaders(body ? 'application/json' : null),
|
|
credentials: 'same-origin'
|
|
};
|
|
|
|
if (body) {
|
|
options.body = JSON.stringify(body);
|
|
}
|
|
|
|
const response = await fetchWithAuth(endpoint, options);
|
|
|
|
let data;
|
|
try {
|
|
data = await response.json();
|
|
} catch (e) {
|
|
data = null;
|
|
}
|
|
|
|
if (response.status === 401 && retryOnUnauthorized) {
|
|
clearAuthState();
|
|
window.location.replace('/');
|
|
}
|
|
|
|
if (!response.ok) {
|
|
const error = new Error(data?.message || `Ошибка HTTP: ${response.status}`);
|
|
error.status = response.status;
|
|
error.data = data;
|
|
throw error;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
export { clearAuthState, refreshAccessToken, storeAuthState };
|
|
|
|
const cache = new Map();
|
|
|
|
const CACHABLE_PREFIXES = [
|
|
'/api/departments',
|
|
'/api/specialties',
|
|
'/api/education-forms',
|
|
'/api/users/teachers',
|
|
'/api/equipments',
|
|
'/api/classrooms'
|
|
];
|
|
|
|
function invalidateCache(url) {
|
|
const cacheKeysToClear = [
|
|
'/api/departments',
|
|
'/api/specialties',
|
|
'/api/education-forms',
|
|
'/api/users',
|
|
'/api/teacher-requests',
|
|
'/api/department/teacher-requests',
|
|
'/api/department/teachers',
|
|
'/api/equipments',
|
|
'/api/classrooms'
|
|
];
|
|
const affectedPrefixes = new Set(cacheKeysToClear.filter(prefix => url.includes(prefix)));
|
|
if (url.includes('/api/teacher-requests')) {
|
|
affectedPrefixes.add('/api/users');
|
|
}
|
|
if (url.includes('/api/department/teachers')) {
|
|
affectedPrefixes.add('/api/users/teachers');
|
|
}
|
|
for (const prefix of affectedPrefixes) {
|
|
for (const cacheKey of cache.keys()) {
|
|
if (cacheKey.includes(prefix)) {
|
|
cache.delete(cacheKey);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export function clearCache() {
|
|
cache.clear();
|
|
}
|
|
|
|
export async function logout() {
|
|
await logoutSession();
|
|
clearCache();
|
|
}
|
|
|
|
export const api = {
|
|
get: async (url) => {
|
|
const isCachable = CACHABLE_PREFIXES.some(prefix => url.startsWith(prefix));
|
|
if (isCachable) {
|
|
if (!cache.has(url)) {
|
|
cache.set(url, await apiFetch(url, 'GET'));
|
|
}
|
|
return cache.get(url);
|
|
}
|
|
return apiFetch(url, 'GET');
|
|
},
|
|
post: async (url, body) => {
|
|
invalidateCache(url);
|
|
return apiFetch(url, 'POST', body);
|
|
},
|
|
put: async (url, body) => {
|
|
invalidateCache(url);
|
|
return apiFetch(url, 'PUT', body);
|
|
},
|
|
delete: async (url, body = null) => {
|
|
invalidateCache(url);
|
|
return apiFetch(url, 'DELETE', body);
|
|
}
|
|
};
|