import axios from "axios"; import { Controller, Post, Delete, Route, Security, Tags, Body, Path, Request, Response, Get, } from "tsoa"; import HttpError from "../interfaces/http-error"; import HttpStatusCode from "../interfaces/http-status"; import { addLogSequence } from "../interfaces/utils"; import HttpSuccess from "../interfaces/http-success"; interface CachedToken { token: string; expiry: Date; } const API_URL_BANGKOK = "https://exprofile.bangkok.go.th/API"; const clientId = "e5f6ad6ce374177eef023bf5d0c018b6"; const clientSecret = "5EhOvN5DwHOKakupqT9FmCk7MOwpT3zLqLPkPh4ZhJpxBN2nMG@2022"; class TokenCache { private static cache: Map = new Map(); static get(key: string): string | null { const cached = this.cache.get(key); if (!cached) return null; return cached.token; } static set(key: string, token: string): void { this.cache.set(key, { token, expiry: new Date(Date.now() + 50 * 60 * 1000) }); } static delete(key: string): void { this.cache.delete(key); } } @Route("api/v1/org/ex/retirement") @Tags("ExRetirement") @Security("bearerAuth") export class ExRetirementController extends Controller { @Post() async getExRetirement( @Body() requestBody: { type: string; //ประเภท retireYear: string; //ปีที่เกษียณ citizenID: string; //เลขบัตรประชาชน firstNameTH: string; //ชื่อ lastNameTH: string; //นามสกุล page: number; //หน้า }, ) { let retryCount = 0; const maxRetries = 2; while (retryCount < maxRetries) { try { const token = await getToken(clientId, clientSecret); if (!token) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่สามารถขอ Token ได้"); } // const scope = requestBody.type === "officer" ? "getOfficerRetireData" : ""; const scope = "getOfficerRetireData"; const startRecord = requestBody.page !== 1 ? (requestBody.page - 1) * 25 : 0; const formData = new FormData(); formData.append("scope", scope); formData.append("startRecord", startRecord.toString()); formData.append("retireYear", requestBody.retireYear); formData.append("citizenID", requestBody.citizenID); formData.append("firstNameTH", requestBody.firstNameTH); formData.append("lastNameTH", requestBody.lastNameTH); formData.append("officerTypeID", requestBody.type === "officer" ? "1" : "2"); const res = await axios.post(API_URL_BANGKOK + "/getData", formData, { headers: { Authorization: `Bearer ${token}`, }, }); // return res.data; return new HttpSuccess(res.data.data); } catch (error: any) { if (error.response?.status === 500 && retryCount < maxRetries - 1) { TokenCache.delete(`${clientId}:${clientSecret}`); retryCount++; continue; } throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "ไม่สามารถติดต่อ API ได้"); } } } @Get("/document/{documentId}") async getDocument(@Path("documentId") officerDocumentID: string, @Request() req: any) { let retryCount = 0; const maxRetries = 2; while (retryCount < maxRetries) { try { const token = await getToken(clientId, clientSecret); if (!token) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่สามารถขอ Token ได้"); } const formData = new FormData(); formData.append("scope", "getOfficerRetireFile"); formData.append("officerDocumentID", officerDocumentID); const res = await axios.post(API_URL_BANGKOK + "/getData", formData, { headers: { Authorization: `Bearer ${token}`, }, responseType: "arraybuffer", }); if (!req.res.headersSent && !req.res.destroyed) { // Set response headers req.res.setHeader("Content-Type", "application/pdf"); req.res.setHeader("Content-Disposition", `inline; filename="${officerDocumentID}.pdf"`); req.res.setHeader("Content-Length", res.data.byteLength.toString()); req.res.end(Buffer.from(res.data)); return; } } catch (error: any) { if (error.response?.status === 500 && retryCount < maxRetries - 1) { TokenCache.delete(`${clientId}:${clientSecret}`); retryCount++; continue; } throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "ไม่สามารถติดต่อ API ได้"); } } } } async function getToken(ClientID: string, ClientSecret: string): Promise { const cacheKey = `${ClientID}:${ClientSecret}`; // ลองหา token ใน cache ก่อน const cachedToken = TokenCache.get(cacheKey); if (cachedToken) { return cachedToken; } // ถ้าไม่มีใน cache ให้ขอใหม่ try { const formData = new FormData(); formData.append("ClientID", ClientID); formData.append("ClientSecret", ClientSecret); const res = await axios.post(API_URL_BANGKOK + "/authorize", formData, { headers: { "Content-Type": "application/json", }, }); const token = res.data.token; TokenCache.set(cacheKey, token); return token; } catch (error) { return Promise.reject({ message: "Error occurred", error }); } } // function post retire data to exprofile system export async function PostRetireToExprofile( request: any, citizenID: string, prefix: string, firstName: string, lastName: string, retireYear: string, positionName: string, positionTypeName: string, positionLevelName: string, retireDate: Date, organizeName: string, // child4Name child3Name child2Name child1Name rootName retireTypeName: string, // เช่น เกษียณ, ขอโอนออก, ลาออก, ปลดออก, ไล่ออก, ... ) { // check NODE_ENV ถ้าเป็น production ถึงจะทำการส่งข้อมูลไปยัง exprofile const NODE_ENV = process.env.NODE_ENV || "development"; if (NODE_ENV !== "production") { return; } let retryCount = 0; const maxRetries = 2; while (retryCount < maxRetries) { try { const token = await getToken(clientId, clientSecret); if (!token) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่สามารถขอ Token ได้"); } const scope = "importOfficerRetireData"; const body = { scope: scope, data: { citizenID: citizenID, prenameTH: prefix, firstNameTH: firstName, lastNameTH: lastName, retireYear, positionNameTH: positionName, positionTypeNameTH: positionTypeName, positionLevelNameTH: positionLevelName, retireDate, organizeNameTH: organizeName, retireTypeNameTH: retireTypeName, }, }; const res = await axios.post(API_URL_BANGKOK + "/importData", body, { headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, }); return res.data; } catch (error: any) { if (error.response?.status === 500 && retryCount < maxRetries - 1) { TokenCache.delete(`${clientId}:${clientSecret}`); retryCount++; continue; } addLogSequence(request, { action: "request", status: "error", description: "unconnected to exprofile api", request: { method: "POST", url: API_URL_BANGKOK + "/importData", response: JSON.stringify(error), }, }); throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "ไม่สามารถติดต่อ API ได้"); } } }