snp-batch-validation/frontend/src/api/bypassAccountApi.ts
HYOJIN 911f755d46 feat(bypass-account): Bypass API 사용자 계정 발급 신청 프로세스 개발 (#126)
- Spring Security Basic Auth 인증 도입 (Bypass 데이터 API만)
- 계정 신청/승인/거절 백엔드 API 및 프론트엔드 구현
- 계정 관리 (CRUD, 비밀번호 재설정, 상태/기간 수정)
- 401 응답에 계정 상태 상세 메시지 포함
- Swagger UI Basic Auth 스킴/환경별 그룹 노출 연동
- 신청 폼 정규식 검증 및 접근기간 프리셋 선택
2026-04-02 17:12:51 +09:00

139 lines
4.4 KiB
TypeScript

export interface BypassAccountResponse {
id: number;
username: string;
displayName: string;
organization: string | null;
email: string | null;
phone: string | null;
status: string;
accessStartDate: string | null;
accessEndDate: string | null;
createdAt: string;
updatedAt: string;
plainPassword: string | null;
}
export interface BypassAccountUpdateRequest {
displayName?: string;
organization?: string;
email?: string;
phone?: string;
status?: string;
accessStartDate?: string;
accessEndDate?: string;
}
export interface BypassRequestResponse {
id: number;
applicantName: string;
organization: string | null;
purpose: string | null;
email: string | null;
phone: string | null;
requestedAccessPeriod: string | null;
status: string;
reviewedBy: string | null;
reviewedAt: string | null;
rejectReason: string | null;
accountId: number | null;
accountUsername: string | null;
createdAt: string;
updatedAt: string;
}
export interface BypassRequestSubmitRequest {
applicantName: string;
organization: string;
purpose: string;
email: string;
phone: string;
requestedAccessPeriod: string;
}
export interface BypassRequestReviewRequest {
reviewedBy: string;
rejectReason?: string;
accessStartDate?: string;
accessEndDate?: string;
}
export interface PageResponse<T> {
content: T[];
totalElements: number;
totalPages: number;
number: number;
size: number;
}
interface ApiResponse<T> {
success: boolean;
message: string;
data: T;
}
// BASE URL
const BASE = '/snp-api/api/bypass-account';
// 헬퍼 함수 (bypassApi.ts 패턴과 동일)
async function fetchJson<T>(url: string): Promise<T> {
const res = await fetch(url);
if (!res.ok) throw new Error(`API Error: ${res.status} ${res.statusText}`);
return res.json();
}
async function postJson<T>(url: string, body?: unknown): Promise<T> {
const res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: body != null ? JSON.stringify(body) : undefined,
});
if (!res.ok) throw new Error(`API Error: ${res.status} ${res.statusText}`);
return res.json();
}
async function putJson<T>(url: string, body?: unknown): Promise<T> {
const res = await fetch(url, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: body != null ? JSON.stringify(body) : undefined,
});
if (!res.ok) throw new Error(`API Error: ${res.status} ${res.statusText}`);
return res.json();
}
async function deleteJson<T>(url: string): Promise<T> {
const res = await fetch(url, { method: 'DELETE' });
if (!res.ok) throw new Error(`API Error: ${res.status} ${res.statusText}`);
return res.json();
}
export const bypassAccountApi = {
// Accounts
getAccounts: (status?: string, page = 0, size = 20) => {
const params = new URLSearchParams({ page: String(page), size: String(size) });
if (status) params.set('status', status);
return fetchJson<ApiResponse<PageResponse<BypassAccountResponse>>>(`${BASE}/accounts?${params}`);
},
getAccount: (id: number) =>
fetchJson<ApiResponse<BypassAccountResponse>>(`${BASE}/accounts/${id}`),
updateAccount: (id: number, data: BypassAccountUpdateRequest) =>
putJson<ApiResponse<BypassAccountResponse>>(`${BASE}/accounts/${id}`, data),
deleteAccount: (id: number) =>
deleteJson<ApiResponse<void>>(`${BASE}/accounts/${id}`),
resetPassword: (id: number) =>
postJson<ApiResponse<BypassAccountResponse>>(`${BASE}/accounts/${id}/reset-password`, {}),
// Requests
submitRequest: (data: BypassRequestSubmitRequest) =>
postJson<ApiResponse<BypassRequestResponse>>(`${BASE}/requests`, data),
getRequests: (status?: string, page = 0, size = 20) => {
const params = new URLSearchParams({ page: String(page), size: String(size) });
if (status) params.set('status', status);
return fetchJson<ApiResponse<PageResponse<BypassRequestResponse>>>(`${BASE}/requests?${params}`);
},
approveRequest: (id: number, data: BypassRequestReviewRequest) =>
postJson<ApiResponse<BypassAccountResponse>>(`${BASE}/requests/${id}/approve`, data),
rejectRequest: (id: number, data: BypassRequestReviewRequest) =>
postJson<ApiResponse<BypassRequestResponse>>(`${BASE}/requests/${id}/reject`, data),
};