chuvsu-js 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,13 @@
1
1
  import type { PersonalData } from "./types.js";
2
2
  export declare class LkClient {
3
3
  private http;
4
+ private credentials;
4
5
  login(opts: {
5
6
  email: string;
6
7
  password: string;
7
8
  }): Promise<void>;
9
+ private isSessionExpired;
10
+ private authGet;
8
11
  getPersonalData(): Promise<PersonalData>;
9
12
  getGroupId(): Promise<number | null>;
10
13
  }
package/dist/lk/client.js CHANGED
@@ -6,14 +6,27 @@ const LOGIN_URL = `${BASE}/info/login.php`;
6
6
  const STUDENT_BASE = `${BASE}/student`;
7
7
  export class LkClient {
8
8
  http = new HttpClient();
9
+ credentials = null;
9
10
  async login(opts) {
10
11
  const res = await this.http.post(LOGIN_URL, { email: opts.email, password: opts.password, role: "1", enter: "" }, false);
11
12
  if (!(res.status === 302 && res.location?.includes("student"))) {
12
13
  throw new AuthError("LK login failed");
13
14
  }
15
+ this.credentials = opts;
16
+ }
17
+ isSessionExpired(body) {
18
+ return body.includes("login.php");
19
+ }
20
+ async authGet(url) {
21
+ const res = await this.http.get(url);
22
+ if (this.credentials && this.isSessionExpired(res.body)) {
23
+ await this.login(this.credentials);
24
+ return this.http.get(url);
25
+ }
26
+ return res;
14
27
  }
15
28
  async getPersonalData() {
16
- const { body } = await this.http.get(`${STUDENT_BASE}/personal_data.php`);
29
+ const { body } = await this.authGet(`${STUDENT_BASE}/personal_data.php`);
17
30
  const vals = extractScriptValues(body, "form_personal_data");
18
31
  return {
19
32
  lastName: vals.fam ?? "",
@@ -32,7 +45,7 @@ export class LkClient {
32
45
  };
33
46
  }
34
47
  async getGroupId() {
35
- const { body } = await this.http.get(`${STUDENT_BASE}/tt.php`);
48
+ const { body } = await this.authGet(`${STUDENT_BASE}/tt.php`);
36
49
  const match = body.match(/tt\.chuvsu\.ru\/index\/grouptt\/gr\/(\d+)/);
37
50
  return match ? parseInt(match[1]) : null;
38
51
  }
@@ -5,6 +5,7 @@ export declare class TtClient {
5
5
  private http;
6
6
  private educationType;
7
7
  private cache;
8
+ private loginMode;
8
9
  constructor(opts?: TtClientOptions);
9
10
  private get pertt();
10
11
  clearCache(category?: keyof CacheConfig): void;
@@ -15,6 +16,10 @@ export declare class TtClient {
15
16
  password: string;
16
17
  }): Promise<void>;
17
18
  loginAsGuest(): Promise<void>;
19
+ private isSessionExpired;
20
+ private relogin;
21
+ private authGet;
22
+ private authPost;
18
23
  getGroupSchedule(opts: {
19
24
  groupId: number;
20
25
  period?: Period;
package/dist/tt/client.js CHANGED
@@ -9,6 +9,7 @@ export class TtClient {
9
9
  http = new HttpClient();
10
10
  educationType;
11
11
  cache;
12
+ loginMode = null;
12
13
  constructor(opts) {
13
14
  this.educationType = opts?.educationType ?? 1 /* EducationType.HigherEducation */;
14
15
  if (opts?.cache == null) {
@@ -51,12 +52,43 @@ export class TtClient {
51
52
  if (res.status !== 302) {
52
53
  throw new AuthError("TT login failed");
53
54
  }
55
+ this.loginMode = { type: "credentials", ...opts };
54
56
  }
55
57
  async loginAsGuest() {
56
58
  const res = await this.http.post(AUTH_URL, { guest: "Войти гостем", hfac: "0", pertt: this.pertt }, false);
57
59
  if (res.status !== 302) {
58
60
  throw new AuthError("TT guest login failed");
59
61
  }
62
+ this.loginMode = { type: "guest" };
63
+ }
64
+ isSessionExpired(body) {
65
+ return body.includes('name="wname"');
66
+ }
67
+ async relogin() {
68
+ if (!this.loginMode)
69
+ return;
70
+ if (this.loginMode.type === "credentials") {
71
+ await this.login(this.loginMode);
72
+ }
73
+ else {
74
+ await this.loginAsGuest();
75
+ }
76
+ }
77
+ async authGet(url) {
78
+ const res = await this.http.get(url);
79
+ if (this.loginMode && this.isSessionExpired(res.body)) {
80
+ await this.relogin();
81
+ return this.http.get(url);
82
+ }
83
+ return res;
84
+ }
85
+ async authPost(url, data) {
86
+ const res = await this.http.post(url, data);
87
+ if (this.loginMode && this.isSessionExpired(res.body)) {
88
+ await this.relogin();
89
+ return this.http.post(url, data);
90
+ }
91
+ return res;
60
92
  }
61
93
  // --- Schedule ---
62
94
  async getGroupSchedule(opts) {
@@ -67,10 +99,10 @@ export class TtClient {
67
99
  const url = `${BASE}/index/grouptt/gr/${opts.groupId}`;
68
100
  let body;
69
101
  if (opts.period !== undefined) {
70
- ({ body } = await this.http.post(url, { htype: String(opts.period) }));
102
+ ({ body } = await this.authPost(url, { htype: String(opts.period) }));
71
103
  }
72
104
  else {
73
- ({ body } = await this.http.get(url));
105
+ ({ body } = await this.authGet(url));
74
106
  }
75
107
  const data = parseFullSchedule(body);
76
108
  this.cache?.set("schedule", cacheKey, data);
@@ -193,7 +225,7 @@ export class TtClient {
193
225
  const cached = this.cache?.get("faculties", "all");
194
226
  if (cached)
195
227
  return cached;
196
- const { body } = await this.http.get(`${BASE}/`);
228
+ const { body } = await this.authGet(`${BASE}/`);
197
229
  const data = parseFacultyButtons(body);
198
230
  this.cache?.set("faculties", "all", data);
199
231
  return data;
@@ -203,7 +235,7 @@ export class TtClient {
203
235
  const cached = this.cache?.get("groups", cacheKey);
204
236
  if (cached)
205
237
  return cached;
206
- const { body } = await this.http.post(`${BASE}/`, {
238
+ const { body } = await this.authPost(`${BASE}/`, {
207
239
  hfac: String(opts.facultyId),
208
240
  pertt: this.pertt,
209
241
  });
@@ -212,7 +244,7 @@ export class TtClient {
212
244
  return data;
213
245
  }
214
246
  async searchGroup(opts) {
215
- const { body } = await this.http.post(`${BASE}/`, {
247
+ const { body } = await this.authPost(`${BASE}/`, {
216
248
  grname: opts.name,
217
249
  findgr: "найти",
218
250
  hfac: "0",
@@ -221,7 +253,7 @@ export class TtClient {
221
253
  return parseGroupButtons(body);
222
254
  }
223
255
  async searchTeacher(opts) {
224
- const { body } = await this.http.post(`${BASE}/`, {
256
+ const { body } = await this.authPost(`${BASE}/`, {
225
257
  techname: opts.name,
226
258
  findtech: "найти",
227
259
  hfac: "0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chuvsu-js",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Node.js library for ChuvSU student portal (lk.chuvsu.ru) and schedule (tt.chuvsu.ru)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",