add feed in / out button page and also button to redirect to button page

This commit is contained in:
Alberto-Audrix committed 2026-09-02 13:33:41 +07:00
1 parent 07b8e2dc25
commit b86bd7a2f4
17 files changed
+719 -28

No files matched your search

+17 -5
View File
@@ -55,7 +55,12 @@ function getCookie(name: string): string | null {
function parseDetail(body: unknown): string {
if (!body || typeof body !== 'object') return 'Request failed';
const detail = (body as { detail?: unknown }).detail;
if (typeof detail === 'string') return detail;
if (typeof detail === 'string') {
if (detail.toLowerCase().includes('csrf')) {
return 'Permintaan ditolak (CSRF). Muat ulang halaman lalu coba lagi.';
}
return detail;
}
if (Array.isArray(detail)) return detail.map(String).join(', ');
const entries = Object.entries(body as Record<string, unknown>)
.filter(([key]) => key !== 'detail')
@@ -64,8 +69,6 @@ function parseDetail(body: unknown): string {
}
async function ensureCsrf(): Promise<string> {
const existing = getCookie('csrftoken');
if (existing) return existing;
const res = await fetch(`${API_BASE}/auth/csrf/`, { credentials: 'include' });
if (!res.ok) {
throw new ApiError('Gagal mengambil CSRF token', res.status, null);
@@ -74,6 +77,12 @@ async function ensureCsrf(): Promise<string> {
return data.csrfToken || getCookie('csrftoken') || '';
}
function isCsrfFailure(status: number, body: unknown): boolean {
if (status !== 403) return false;
const detail = parseDetail(body).toLowerCase();
return detail.includes('csrf');
}
type Query = Record<string, string | number | boolean | null | undefined>;
function withQuery(path: string, query?: Query): string {
@@ -87,7 +96,7 @@ function withQuery(path: string, query?: Query): string {
return qs ? `${path}?${qs}` : path;
}
async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
async function request<T>(path: string, init: RequestInit = {}, csrfRetried = false): Promise<T> {
const method = (init.method || 'GET').toUpperCase();
const headers = new Headers(init.headers);
headers.set('Accept', 'application/json');
@@ -121,7 +130,10 @@ async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
}
if (!res.ok) {
if (res.status === 401 || res.status === 403) {
if (isCsrfFailure(res.status, body) && !csrfRetried && method !== 'GET' && method !== 'HEAD') {
return request<T>(path, init, true);
}
if (res.status === 401) {
window.dispatchEvent(new CustomEvent(AUTH_UNAUTHORIZED_EVENT));
}
throw new ApiError(parseDetail(body), res.status, body);