데이터불러오기기
This commit is contained in:
@@ -28,10 +28,16 @@ function toInt(v: any): number {
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
// 세션 사용자 확인 (핸들 매핑용)
|
||||
const session = await auth();
|
||||
if (!session?.user?.email) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
const urlObj = new URL(request.url)
|
||||
const hostHeader = (request.headers.get('host') || '').toLowerCase()
|
||||
const isLocal = hostHeader.includes('localhost') || hostHeader.includes('127.0.0.1') || urlObj.hostname === 'localhost' || urlObj.hostname === '127.0.0.1'
|
||||
|
||||
if (!isLocal) {
|
||||
// 세션 사용자 확인 (핸들 매핑용)
|
||||
const session = await auth();
|
||||
if (!session?.user?.email) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url)
|
||||
|
||||
134
datareq/datareq.js
Normal file
134
datareq/datareq.js
Normal file
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// 요청 예시: https://www.everfactory.kr/api/contents/update?date=YYYYMMDD
|
||||
// 사용법
|
||||
// 1) 오늘(가장 최신)부터 특정 일자까지 요청:
|
||||
// node datareq/datareq.js 20251014
|
||||
// 2) 특정 최신일자부터 특정 과거일자까지 요청:
|
||||
// node datareq/datareq.js 20251015 20251001
|
||||
// 환경변수로 호출 간 지연(ms) 조절: RATE_MS=500 node datareq/datareq.js 20251014
|
||||
|
||||
const BASE_URL = "http://localhost:9551/api/contents/update";
|
||||
const DEFAULT_RATE_MS = Number(process.env.RATE_MS || 400);
|
||||
|
||||
function isValidYyyyMmDd(value) {
|
||||
return typeof value === "string" && /^\d{8}$/.test(value);
|
||||
}
|
||||
|
||||
function truncateText(text, maxLen = 256) {
|
||||
if (typeof text !== "string") return "";
|
||||
return text.length > maxLen ? text.slice(0, maxLen) : text;
|
||||
}
|
||||
|
||||
function parseYyyyMmDdToDate(yyyyMmDd) {
|
||||
const year = Number(yyyyMmDd.slice(0, 4));
|
||||
const month = Number(yyyyMmDd.slice(4, 6)) - 1; // 0-based
|
||||
const day = Number(yyyyMmDd.slice(6, 8));
|
||||
// Date(YYYY, M, D)는 로컬 타임존 기준. 간단성을 위해 로컬 기준 사용.
|
||||
return new Date(year, month, day);
|
||||
}
|
||||
|
||||
function formatDateToYyyyMmDd(date) {
|
||||
const y = String(date.getFullYear());
|
||||
const m = String(date.getMonth() + 1).padStart(2, "0");
|
||||
const d = String(date.getDate()).padStart(2, "0");
|
||||
return `${y}${m}${d}`;
|
||||
}
|
||||
|
||||
function addDays(date, delta) {
|
||||
const next = new Date(date);
|
||||
next.setDate(next.getDate() + delta);
|
||||
return next;
|
||||
}
|
||||
|
||||
async function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function requestForDate(dateStr) {
|
||||
const url = `${BASE_URL}?date=${dateStr}`;
|
||||
try {
|
||||
const res = await fetch(url, { method: "GET" });
|
||||
const text = await res.text().catch(() => "");
|
||||
if (!res.ok) {
|
||||
const preview = truncateText(text, 256);
|
||||
console.error(`[FAIL] ${dateStr} | ${url} -> ${res.status} ${res.statusText} ${preview ? `| ${preview}` : ""}`);
|
||||
return { ok: false, status: res.status, body: text };
|
||||
}
|
||||
const preview = truncateText(text, 256);
|
||||
console.log(`[OK] ${dateStr} | ${url} -> ${preview || res.status}`);
|
||||
return { ok: true, status: res.status, body: text };
|
||||
} catch (err) {
|
||||
const errMsg = err instanceof Error ? err.message : String(err);
|
||||
console.error(`[ERROR] ${dateStr} | ${url} -> ${truncateText(errMsg, 256)}`);
|
||||
return { ok: false, error: err };
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.length === 0) {
|
||||
console.log("사용법: node datareq/datareq.js <끝일자YYYYMMDD> [시작(최신)일자YYYYMMDD]");
|
||||
console.log("예시1: node datareq/datareq.js 20251014");
|
||||
console.log("예시2: node datareq/datareq.js 20251015 20251001");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let newestStr; // 최신일자 (내림차순 시작점)
|
||||
let oldestStr; // 종료일자 (내림차순 끝점)
|
||||
|
||||
if (args.length === 1) {
|
||||
const today = new Date();
|
||||
newestStr = formatDateToYyyyMmDd(today);
|
||||
oldestStr = args[0];
|
||||
} else {
|
||||
// args.length >= 2 인 경우: [최신일자, 종료일자]
|
||||
newestStr = args[0];
|
||||
oldestStr = args[1];
|
||||
}
|
||||
|
||||
if (!isValidYyyyMmDd(newestStr) || !isValidYyyyMmDd(oldestStr)) {
|
||||
console.error("날짜 형식은 YYYYMMDD 여야 합니다.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let newestDate = parseYyyyMmDdToDate(newestStr);
|
||||
let oldestDate = parseYyyyMmDdToDate(oldestStr);
|
||||
|
||||
// 최신 >= 종료 가 아니면 자동 교환
|
||||
if (newestDate < oldestDate) {
|
||||
const tmp = newestDate;
|
||||
newestDate = oldestDate;
|
||||
oldestDate = tmp;
|
||||
newestStr = formatDateToYyyyMmDd(newestDate);
|
||||
oldestStr = formatDateToYyyyMmDd(oldestDate);
|
||||
}
|
||||
|
||||
console.log(`요청 범위: 최신 ${newestStr} → 종료 ${oldestStr} (내림차순)`);
|
||||
console.log(`요청 간 지연: ${DEFAULT_RATE_MS}ms`);
|
||||
|
||||
let current = newestDate;
|
||||
while (current >= oldestDate) {
|
||||
const dateStr = formatDateToYyyyMmDd(current);
|
||||
await requestForDate(dateStr);
|
||||
// 너무 빠른 연속 호출 방지
|
||||
await sleep(DEFAULT_RATE_MS);
|
||||
current = addDays(current, -1);
|
||||
}
|
||||
|
||||
console.log("모든 요청이 완료되었습니다.");
|
||||
}
|
||||
|
||||
// Node 18+ 환경 가정: fetch 전역 제공. 없으면 종료 안내.
|
||||
if (typeof fetch !== "function") {
|
||||
console.error("현재 Node 런타임에 fetch가 없습니다. Node 18+를 사용하거나 폴리필을 추가하세요.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error("예상치 못한 오류:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
|
||||
39
datareq/datareq_latest.js
Normal file
39
datareq/datareq_latest.js
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const BASE_URL = "http://localhost:9551/api/contents/update";
|
||||
|
||||
function truncateText(text, maxLen = 256) {
|
||||
if (typeof text !== "string") return "";
|
||||
return text.length > maxLen ? text.slice(0, maxLen) : text;
|
||||
}
|
||||
|
||||
async function requestLatest() {
|
||||
const url = `${BASE_URL}?date=latest`;
|
||||
try {
|
||||
const res = await fetch(url, { method: "GET" });
|
||||
const text = await res.text().catch(() => "");
|
||||
if (!res.ok) {
|
||||
const preview = truncateText(text, 256);
|
||||
console.error(`[FAIL] latest | ${url} -> ${res.status} ${res.statusText} ${preview ? `| ${preview}` : ""}`);
|
||||
return { ok: false, status: res.status, body: text };
|
||||
}
|
||||
const preview = truncateText(text, 256);
|
||||
console.log(`[OK] latest | ${url} -> ${preview || res.status}`);
|
||||
return { ok: true, status: res.status, body: text };
|
||||
} catch (err) {
|
||||
const errMsg = err instanceof Error ? err.message : String(err);
|
||||
console.error(`[ERROR] latest | ${url} -> ${truncateText(errMsg, 256)}`);
|
||||
return { ok: false, error: err };
|
||||
}
|
||||
}
|
||||
|
||||
// Node 18+ 환경 가정: fetch 전역 제공. 없으면 종료 안내.
|
||||
if (typeof fetch !== "function") {
|
||||
console.error("현재 Node 런타임에 fetch가 없습니다. Node 18+를 사용하거나 폴리필을 추가하세요.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
requestLatest().catch((err) => {
|
||||
console.error("예상치 못한 오류:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -10,10 +10,12 @@ export default auth(async (req) => {
|
||||
// 경로 추출
|
||||
const { pathname } = req.nextUrl;
|
||||
|
||||
console.log("request host:", req.headers.get('host'));
|
||||
// 로컬 접속 확인 (특정 경로만 우회)
|
||||
const isLocal = req.headers.get('host')?.includes('localhost') ||
|
||||
req.headers.get('host')?.includes('127.0.0.1');
|
||||
|
||||
|
||||
if (isLocal && pathname.startsWith("/api/contents")) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
@@ -148,6 +148,16 @@ function formatKoreanDateFromYMD(ymd) {
|
||||
return `${yyyy}. ${mm}. ${dd}.`;
|
||||
}
|
||||
|
||||
// '2025. 9. 1.' → '20250901' 로 변환
|
||||
function dotKoreanDateToYMD(dot) {
|
||||
const m = dot?.match(/^(\d{4})\.\s*(\d{1,2})\.\s*(\d{1,2})\.?$/);
|
||||
if (!m) return null;
|
||||
const yyyy = m[1];
|
||||
const mm = String(parseInt(m[2], 10)).padStart(2, '0');
|
||||
const dd = String(parseInt(m[3], 10)).padStart(2, '0');
|
||||
return `${yyyy}${mm}${dd}`;
|
||||
}
|
||||
|
||||
// 입력칸의 기존 값을 지우고 새 값 입력
|
||||
async function clearAndType(inputLocator, page, value) {
|
||||
await inputLocator.click();
|
||||
@@ -179,6 +189,13 @@ async function configureDateRangeSingleDay(page, ymdTarget) {
|
||||
await clearAndType(startInput, page, endVal);
|
||||
startVal = endVal;
|
||||
} else if (ymdTarget) {
|
||||
// 최신 종료일(=현재 UI가 가진 가장 최근 일자)과 비교하여 이후면 에러
|
||||
const latestEndVal = await endInput.inputValue();
|
||||
const latestYmd = dotKoreanDateToYMD(latestEndVal);
|
||||
if (!latestYmd) throw new Error('최신 종료일 파싱에 실패했습니다.');
|
||||
if (!/^\d{8}$/.test(ymdTarget)) throw new Error('잘못된 날짜 형식입니다. (예: 20250901)');
|
||||
if (ymdTarget > latestYmd) throw new Error(`요청한 날짜(${ymdTarget})가 최신 데이터(${latestYmd})보다 이후입니다.`);
|
||||
|
||||
const formatted = formatKoreanDateFromYMD(ymdTarget);
|
||||
if (!formatted) throw new Error(`잘못된 날짜 형식입니다. (예: 20250901)`);
|
||||
// 시작/종료 모두 동일 날짜로 설정
|
||||
|
||||
Reference in New Issue
Block a user