| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- // 서버 유틸리티 함수들
- 'use server';
- import axios, { AxiosRequestConfig } from 'axios';
- import https from 'https';
- import { cookies } from 'next/headers'
- import { ResultDto, TokenData } from '@/dtos/response/common';
- import BoardManager from '@/types/forum/boardManager';
- import { CLAIM_NAME_IDENTIFIER, CLAIM_EMAIL, CLAIM_NAME } from '@/constants/common';
- import { fetchMemberInfo } from '@/lib/api/account';
- const API_URL = process.env.API_URL;
- const agent = new https.Agent({
- rejectUnauthorized: false
- });
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- /*
- export async function fetchJson<T = any>(url: string, options: AxiosRequestConfig = {}): Promise<ResultDto<T>> {
- try {
- const actionURL = `${API_URL}${url.startsWith("/") ? url : `/${url}`}`;
- const httpsAgent = (process.env.NODE_ENV === 'production' ? undefined : agent);
- const cookieHeader = (await cookies()).getAll().map(c => `${c.name}=${c.value}`).join("; ");
- const res = await axios({
- url: actionURL,
- ...options,
- httpsAgent: httpsAgent,
- // timeout: 10000,
- headers: {
- ...(options.headers || {}),
- Cookie: cookieHeader,
- }
- });
- const setCookieHeader = res.headers['set-cookie'];
- if (setCookieHeader) {
- for (const cookieString of setCookieHeader) {
- const [cookieName, cookieValue] = cookieString.split("=");
- (await cookies()).set(cookieName, cookieValue.split(";")[0]);
- }
- }
- return res.data as ResultDto<T>;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- } catch (err: any) {
- let message = '알 수 없는 오류가 발생했습니다.';
- let status = 500;
- if (axios.isAxiosError(err)) {
- message = err.response?.data?.message || err.message;
- status = err.response?.status || 500;
- } else if (err instanceof Error) {
- message = err.message;
- }
- console.warn(`[${status}] ${message}`);
- return {
- ok: false,
- status: status,
- message: message,
- data: null,
- errors: null
- } satisfies ResultDto<T>;
- }
- }
- */
- export async function fetchJson<T>(url: string, options: RequestInit = {}): Promise<ResultDto<T>> {
- try {
- const actionURL = `${API_URL}${url.startsWith('/') ? url : `/${url}`}`;
- const cookie = (await cookies()).getAll().map(c => `${c.name}=${c.value}`).join("; ");
- const res = await fetch(actionURL, {
- ...options,
- headers: {
- ...(options.headers || {}),
- Cookie: cookie,
- 'Accept': 'application/json'
- },
- cache: 'no-store'
- });
- if (res.status === 204) {
- throw new Error('No Content');
- }
- return await res.json() as ResultDto<T>;
- } catch (err) {
- let message = '서버와 통신이 불가합니다.';
- const status = 500;
- if (err instanceof Error) {
- message = err.message;
- }
- console.warn(`[${status}] ${message}`);
- return {
- ok: false,
- status: status,
- message: message,
- data: null,
- errors: null
- } satisfies ResultDto<T>;
- }
- }
- export async function getAccessToken(): Promise<string|null> {
- return (await cookies()).get('accessToken')?.value ?? null;
- }
- export async function getRefreshToken(): Promise<string|null> {
- return (await cookies()).get('refreshToken')?.value ?? null;
- }
- // 로그인 전력 확인
- export async function isAuthenticated(): Promise<boolean> {
- return Boolean(getAccessToken());
- }
- // API 서버 URL 조회
- export async function getAPIUrl(): Promise<string> {
- return process.env.API_URL as string;
- }
- // SignalR 서버 URL 조회
- export async function getSignalRUrl(): Promise<string> {
- return process.env.SIGNALR_URL as string;
- }
- // JWT 토큰에서 사용자 정보 추출
- export async function getTokenData(): Promise<TokenData|null> {
- try {
- const token = await getAccessToken();
- if (!token) {
- throw new Error('Access token not found');
- }
- const base64URL = token.split('.')[1]; // JWT의 Payload 부분
- const base64 = base64URL.replace(/-/g, '+').replace(/_/g, '/'); // Base64 형식 변환
- const jsonPayload = decodeURIComponent(
- atob(base64).split('').map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join('')
- );
- const payload = JSON.parse(jsonPayload);
- return {
- id: payload[CLAIM_NAME_IDENTIFIER] || null,
- email: payload[CLAIM_EMAIL] || null,
- name: payload[CLAIM_NAME] || null
- };
- } catch {
- return null;
- }
- }
- // 첫번째 오류 조회
- export async function getFirstError(errors: Record<string, string[]> | null): Promise<string|null> {
- return (errors ? Object.values(errors).flat()[0] ?? null : null);
- }
- // 서버 응답 메시지 분석
- export async function throwError<T>(res: ResultDto<T>): Promise<void> {
- if (res.ok) {
- return;
- }
- let message:string|null = await getFirstError(res.errors);
- if (!message && res.message) {
- message = res.message;
- }
- switch (res.status) {
- case 400:
- throw Error(message || '잘못된 요청입니다.');
- case 401:
- throw Error('로그인 후 이용해 주세요.');
- case 403:
- throw Error('권한이 없습니다.');
- case 404:
- throw Error('요청하신 페이지를 찾을 수 없습니다.');
- }
- if (message) {
- throw Error(message);
- }
- }
- // 게시판, 게시글, 댓글 등 권한 확인
- export async function checkPermission(permission: number, boardManager: BoardManager[]): Promise<boolean> {
- if (permission > -1) {
- const member = await fetchMemberInfo();
- if (member.ok && member.data) {
- if (
- // 게시판 접근 권한이 회원 등급보다 높거나
- permission < member.data.memberGrade.order ||
- // 게시판 관리자에 포함되어 있으면 권한이 있음
- boardManager.some(manager => member.data!.id && manager.user.email == member.data!.email)
- ) {
- return true;
- }
- }
- return false;
- }
- return true;
- }
|