Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 68 additions & 32 deletions src/api/admin/challengesAPI.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,86 @@
import UserService from "./usersAPI";
import axiosInstance from "../axiosInstance.js";
import { cacheRequest } from "@/utils/cacheUtils";

export default {
async fetchAllChallenges() {
return await axiosInstance.get(`/api/info/challenges`);
try {
const request = new Request(`${axiosInstance.defaults.baseURL}/api/info/challenges`);
const response = await cacheRequest(request);
const data = await response.json();
return { data };
} catch (error) {
console.error('Cache fetch failed, falling back to direct API call:', error);
// Fall back to axios which already handles auth
return await axiosInstance.get(`/api/info/challenges`);
}
},
async fetchChallengeByName(name) {
return await axiosInstance({
method: "get",
url: `/api/info/challenge/${name}`
// data: postData
});
try {
return await axiosInstance({
method: "get",
url: `/api/info/challenge/${name}`
// data: postData
});
} catch (error) {
console.error('Failed to fetch challenge by name:', error);
throw error;
}
},
async fetchAllTags() {
return await axiosInstance.get(`/api/info/tags`);
try {
return await axiosInstance.get(`/api/info/tags`);
} catch (error) {
console.error('Failed to fetch all tags:', error);
throw error;
}
},
async manageChalAction(name, action) {
let postData = new FormData();
postData.append("name", name);
postData.append("action", action);
return await axiosInstance({
method: "post",
url: `/api/manage/challenge/`,
data: postData
});
try {
let postData = new FormData();
postData.append("name", name);
postData.append("action", action);
return await axiosInstance({
method: "post",
url: `/api/manage/challenge/`,
data: postData
});
} catch (error) {
console.error('Failed to manage challenge action:', error);
throw error;
}
},

async manageMultipleChalAction(name, action) {
let postData = new FormData();
postData.append("names", name);
postData.append("action", action);
return await axiosInstance({
method: "post",
url: `/api/manage/challenge/multiple/`,
data: postData
});
try {
let postData = new FormData();
postData.append("names", name);
postData.append("action", action);
return await axiosInstance({
method: "post",
url: `/api/manage/challenge/multiple/`,
data: postData
});
} catch (error) {
console.error('Failed to manage multiple challenge action:', error);
throw error;
}
},

async createChallenge(file) {
let bodyFormData = new FormData();
bodyFormData.append("file", file);
const response = await axiosInstance({
method: "post",
url: `/api/manage/challenge/upload`,
data: bodyFormData,
headers: { "Content-Type": "multipart/form-data" }
});
return response.data;
try {
let bodyFormData = new FormData();
bodyFormData.append("file", file);
const response = await axiosInstance({
method: "post",
url: `/api/manage/challenge/upload`,
data: bodyFormData,
headers: { "Content-Type": "multipart/form-data" }
});
return response.data;
} catch (error) {
console.error('Failed to create challenge:', error);
throw error;
}
}
};
12 changes: 10 additions & 2 deletions src/api/admin/configureAPI.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import axiosInstance from "../axiosInstance.js";

import { cacheRequest } from "@/utils/cacheUtils";
export default {
async updateConfigs(configs) {
let bodyFormData = new FormData();
Expand All @@ -18,7 +18,15 @@ export default {
});
},
async getConfigs() {
return await axiosInstance.get(`/api/info/competition-info`);
try {
const request = new Request(`${axiosInstance.defaults.baseURL}/api/info/competition-info`);
const response = await cacheRequest(request);
const data = await response.json();
return { data };
} catch (error) {
console.error('Cache fetch failed, falling back to direct API call:', error);
return await axiosInstance.get(`/api/info/competition-info`);
}
},

async getLogo(imgUrl, imgName) {
Expand Down
82 changes: 82 additions & 0 deletions src/utils/cacheUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
const CACHE_NAME = 'api-cache';
const CACHE_DURATION = 5 * 60; // 5 minutes in seconds

const isCacheValid = (response) => {
if (!response) return false;

const cachedAt = response.headers.get('x-cached-at');
if (!cachedAt) return false;

const ageInSeconds = (Date.now() - new Date(cachedAt).getTime()) / 1000;
return ageInSeconds < CACHE_DURATION;
};

const addCacheHeaders = (response) => {
const headers = new Headers(response.headers);
headers.append('x-cached-at', new Date().toISOString());

return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers
});
};

// Get auth token from LoginUser
const getAuthToken = () => {
try {
const userInfo = JSON.parse(localStorage.getItem('userInfo'));
if (userInfo && userInfo.token) {
return `Bearer ${userInfo.token}`;
}
return null;
} catch (error) {
console.error('Error getting auth token:', error);
return null;
}
};

export const cacheRequest = async (request) => {
try {
const cache = await caches.open(CACHE_NAME);

const cachedResponse = await cache.match(request);
if (cachedResponse && isCacheValid(cachedResponse)) {
console.log('Returning cached response');
return cachedResponse;
}

// Add auth header to the request
const headers = new Headers(request.headers);
const authToken = getAuthToken();
if (authToken) {
headers.set('Authorization', authToken);
}

const authenticatedRequest = new Request(request, {
headers
});

const response = await fetch(authenticatedRequest);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const responseWithCacheHeaders = addCacheHeaders(response.clone());

await cache.put(request, responseWithCacheHeaders);

return response;
} catch (error) {
console.error('Cache operation failed:', error);
throw error; // Let the API caller handle the error
}
};

export const clearCache = async () => {
try {
const cache = await caches.open(CACHE_NAME);
await cache.delete();
} catch (error) {
console.error('Failed to clear cache:', error);
}
};