Merge pull request 'Nico / 4-Feb-2026' (#60) from nico/4-feb-26 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/60
This commit is contained in:
@@ -19,19 +19,27 @@ function Content({ kategoriBuku }: { kategoriBuku: string }) {
|
||||
const searchQuery = searchParams.get('search') || '';
|
||||
const router = useTransitionRouter()
|
||||
|
||||
// Convert kebab-case back to original category name format
|
||||
// This reverses the transformation done in layoutTabs: item.name.toLowerCase().replace(/\s+/g, '-')
|
||||
const convertKebabCaseToOriginal = (kebabStr: string): string => {
|
||||
// Replace hyphens with spaces
|
||||
return kebabStr.replace(/-/g, ' ');
|
||||
};
|
||||
|
||||
const decodedKategoriBuku = decodeURIComponent(kategoriBuku);
|
||||
const originalKategoriName = convertKebabCaseToOriginal(decodedKategoriBuku);
|
||||
|
||||
const loadData = useCallback(async (searchQuery: string = '', page: number = 1) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const currentKategoriFilter = decodedKategoriBuku.toLowerCase() === 'semua' ? '' : decodedKategoriBuku;
|
||||
const currentKategoriFilter = decodedKategoriBuku.toLowerCase() === 'semua' ? '' : originalKategoriName;
|
||||
await state.dataPerpustakaan.findMany.load(page, 3, searchQuery, currentKategoriFilter);
|
||||
setCurrentPage(page);
|
||||
setTotalPages(state.dataPerpustakaan.findMany.totalPages);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [state.dataPerpustakaan.findMany, decodedKategoriBuku]);
|
||||
}, [state.dataPerpustakaan.findMany, originalKategoriName, decodedKategoriBuku]);
|
||||
|
||||
useShallowEffect(() => {
|
||||
loadData(searchQuery);
|
||||
|
||||
@@ -123,7 +123,7 @@ const getWorkStatus = (day: string, currentTime: string): { status: string; mess
|
||||
|
||||
let workHoursMessage = "";
|
||||
if (["Senin", "Selasa", "Rabu", "Kamis"].includes(day)) {
|
||||
workHoursMessage = "07:30 - 15:10";
|
||||
workHoursMessage = "07:30 - 15:30";
|
||||
} else if (day === "Jumat") {
|
||||
workHoursMessage = "07:30 - 12:00";
|
||||
}
|
||||
|
||||
109
src/lib/seafile-auth-service.ts
Normal file
109
src/lib/seafile-auth-service.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { Mutex } from 'async-mutex';
|
||||
|
||||
// Store the token and its expiration time
|
||||
let authToken: string | null = null;
|
||||
let tokenExpirationTime: number | null = null;
|
||||
|
||||
// Mutex to prevent multiple simultaneous token refresh attempts
|
||||
const mutex = new Mutex();
|
||||
|
||||
// Function to authenticate with Seafile and get a new token
|
||||
async function authenticateWithSeafile(): Promise<{token: string, expirationTime: number}> {
|
||||
// First, check if we have a static token as fallback
|
||||
const staticToken = process.env.SEAFILE_TOKEN;
|
||||
if (staticToken) {
|
||||
console.log("Using static SEAFILE_TOKEN from environment variables");
|
||||
// For static tokens, we'll set a conservative expiration (e.g., 6 days) to force periodic refresh attempts
|
||||
const conservativeExpiration = Date.now() + (6 * 24 * 60 * 60 * 1000); // 6 days from now
|
||||
return {
|
||||
token: staticToken,
|
||||
expirationTime: conservativeExpiration
|
||||
};
|
||||
}
|
||||
|
||||
// Otherwise, use username/password to get a new token
|
||||
const username = process.env.SEAFILE_USERNAME;
|
||||
const password = process.env.SEAFILE_PASSWORD;
|
||||
const baseUrl = process.env.SEAFILE_URL;
|
||||
|
||||
if (!username || !password || !baseUrl) {
|
||||
throw new Error('Missing required Seafile environment variables (either SEAFILE_TOKEN or SEAFILE_USERNAME/SEAFILE_PASSWORD/SEAFILE_URL)');
|
||||
}
|
||||
|
||||
const response = await fetch(`${baseUrl}/api2/auth-token/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
username,
|
||||
password,
|
||||
// Note: Seafile tokens typically last 7 days by default, but we'll refresh earlier
|
||||
}).toString(),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Authentication failed: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Calculate expiration time (set to refresh 1 hour before actual expiration)
|
||||
// Seafile tokens typically last 7 days (604800 seconds), so we refresh after 6 days and 23 hours (601200 seconds)
|
||||
const refreshTokenThreshold = 601200; // 6 days and 23 hours in seconds
|
||||
const expirationTime = Date.now() + (refreshTokenThreshold * 1000);
|
||||
|
||||
return {
|
||||
token: data.token,
|
||||
expirationTime
|
||||
};
|
||||
}
|
||||
|
||||
// Function to get a valid authentication token
|
||||
export async function getValidAuthToken(): Promise<string> {
|
||||
// Check if we have a valid token that hasn't expired
|
||||
if (authToken && tokenExpirationTime && Date.now() < tokenExpirationTime) {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
// Acquire lock to prevent multiple simultaneous refresh attempts
|
||||
return mutex.runExclusive(async () => {
|
||||
// Double-check after acquiring the lock
|
||||
if (authToken && tokenExpirationTime && Date.now() < tokenExpirationTime) {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
// Get a new token
|
||||
const { token, expirationTime } = await authenticateWithSeafile();
|
||||
|
||||
// Update the stored token and expiration time
|
||||
authToken = token;
|
||||
tokenExpirationTime = expirationTime;
|
||||
|
||||
console.log('New Seafile token acquired and cached');
|
||||
|
||||
return token;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to force refresh the token (useful for manual refresh or testing)
|
||||
export async function refreshAuthToken(): Promise<string> {
|
||||
return mutex.runExclusive(async () => {
|
||||
const { token, expirationTime } = await authenticateWithSeafile();
|
||||
|
||||
// Update the stored token and expiration time
|
||||
authToken = token;
|
||||
tokenExpirationTime = expirationTime;
|
||||
|
||||
console.log('Seafile token refreshed');
|
||||
|
||||
return token;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to check if the token is still valid
|
||||
export function isTokenValid(): boolean {
|
||||
return authToken !== null &&
|
||||
tokenExpirationTime !== null &&
|
||||
Date.now() < tokenExpirationTime;
|
||||
}
|
||||
Reference in New Issue
Block a user