Skip to content

Commit 7f428f3

Browse files
committed
menuNo 지원
1 parent 0eed6f5 commit 7f428f3

File tree

5 files changed

+40
-8
lines changed

5 files changed

+40
-8
lines changed

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,8 @@
77
npm install kaist-today-notice
88
```
99

10-
- 차세대 포탈을 지원하는 버전의 사용 방법은 아직 작성되지 않았습니다.
10+
- 차세대 포탈을 지원하는 버전의 자세한 사용 방법은 아직 작성되지 않았습니다.
11+
12+
- 간편 로그인은 사용자 이름만 있으면 통과할 수 있어서 승인 절차까지 자동화하는 경우 위험할 수 있으므로, 이메일 인증 번호를 사용하는 방식만 구현하고 있습니다.
13+
14+
- 로그인을 병렬로 동시 진행하면 마지막에 이메일로 전송된 OTP만 유효하며, 실패 시 Error가 발생(throw)합니다. `login`에서 발생할 수 있는 오류를 catch해야 하며, 가급적 외부에서 잠금을 구현하거나 적절한 백오프를 적용하십시오. `loginWithRetry`는 단순한 백오프 전략을 제공합니다.

auth.ts

+28-2
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,11 @@ async function loginToPortal(ssoCode: string) {
107107
}
108108
}
109109

110-
// eslint-disable-next-line import/prefer-default-export
111-
export async function login(username: string, password: string, getOtp: () => Promise<string>) {
110+
export async function login(
111+
username: string,
112+
password: string,
113+
getOtp: () => Promise<string>,
114+
): Promise<string> {
112115
await cookieJar.removeAllCookies();
113116

114117
await loginUsingPassword(username, password);
@@ -121,3 +124,26 @@ export async function login(username: string, password: string, getOtp: () => Pr
121124

122125
return cookieJar.getCookieStringSync('https://portal.kaist.ac.kr');
123126
}
127+
128+
export async function loginWithRetry(
129+
username: string,
130+
password: string,
131+
getOtp: () => Promise<string>,
132+
): ReturnType<typeof login> {
133+
const backoffSeconds = [15, 30, 30, 60, 60];
134+
const getJitter = () => Math.random() * 15;
135+
136+
for (; ;) {
137+
try {
138+
// eslint-disable-next-line no-await-in-loop
139+
return await login(username, password, getOtp);
140+
} catch (e) {
141+
if (backoffSeconds.length === 0) {
142+
throw e;
143+
}
144+
const delay = backoffSeconds.shift()! + getJitter();
145+
// eslint-disable-next-line no-await-in-loop
146+
await new Promise((resolve) => { setTimeout(resolve, delay * 1000); });
147+
}
148+
}
149+
}

fetch.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export interface KaistTodayNoticeFetchOptions {
22
cookie: string;
3+
menuNo?: number;
34
size?: number;
45
lang?: 'ko' | 'en';
56
}
@@ -39,13 +40,15 @@ export async function fetchPosts(
3940
): Promise<KaistTodayNotice[] | null> {
4041
const size = options.size ?? 10;
4142
const lang = options.lang ?? 'ko';
43+
const menuNo = options.menuNo ?? 0;
4244

4345
const boards = await getBoards(options.cookie);
4446
const getBoard = (boardId: number) => boards.find((board) => board.boardId === boardId);
4547

4648
const url = new URL('/wz/api/board/recents', 'https://portal.kaist.ac.kr/');
4749
url.searchParams.append('recordCountPerPage', size.toString());
4850
url.searchParams.append('lang', lang);
51+
url.searchParams.append('menuNo', menuNo.toString());
4952

5053
const response = await fetch(
5154
url,

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
{
22
"name": "kaist-today-notice",
3-
"version": "8.0.0",
3+
"version": "8.0.1",
44
"description": "KAIST 오늘의 공지사항",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",
77
"exports": {
8-
".": "./dist/index.js",
9-
"./auth": "./dist/auth.js"
8+
".": "./dist/index.js"
109
},
1110
"scripts": {
1211
"test": "echo \"Error: no test specified\" && exit 1",

0 commit comments

Comments
 (0)