@robertying/thu-learn-lib 5.1.0 → 6.0.1

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.
Files changed (83) hide show
  1. package/README.md +81 -248
  2. package/lib/auth.d.ts +14 -3
  3. package/lib/auth.d.ts.map +1 -1
  4. package/lib/auth.js +56 -58
  5. package/lib/auth.js.map +1 -1
  6. package/lib/calendar.d.ts +7 -2
  7. package/lib/calendar.d.ts.map +1 -1
  8. package/lib/calendar.js +99 -14
  9. package/lib/calendar.js.map +1 -1
  10. package/lib/contents.d.ts.map +1 -1
  11. package/lib/contents.js +4 -9
  12. package/lib/contents.js.map +1 -1
  13. package/lib/courses.d.ts.map +1 -1
  14. package/lib/courses.js +11 -25
  15. package/lib/courses.js.map +1 -1
  16. package/lib/discussions.d.ts.map +1 -1
  17. package/lib/discussions.js +6 -17
  18. package/lib/discussions.js.map +1 -1
  19. package/lib/favorites.d.ts +1 -0
  20. package/lib/favorites.d.ts.map +1 -1
  21. package/lib/favorites.js +13 -48
  22. package/lib/favorites.js.map +1 -1
  23. package/lib/files.d.ts +3 -3
  24. package/lib/files.d.ts.map +1 -1
  25. package/lib/files.js +109 -133
  26. package/lib/files.js.map +1 -1
  27. package/lib/homework.d.ts +34 -3
  28. package/lib/homework.d.ts.map +1 -1
  29. package/lib/homework.js +135 -79
  30. package/lib/homework.js.map +1 -1
  31. package/lib/index.d.ts +39 -19
  32. package/lib/index.d.ts.map +1 -1
  33. package/lib/index.js +44 -17
  34. package/lib/index.js.map +1 -1
  35. package/lib/notices.d.ts +3 -3
  36. package/lib/notices.d.ts.map +1 -1
  37. package/lib/notices.js +4 -20
  38. package/lib/notices.js.map +1 -1
  39. package/lib/questionnaires.d.ts.map +1 -1
  40. package/lib/questionnaires.js +8 -14
  41. package/lib/questionnaires.js.map +1 -1
  42. package/lib/request.d.ts +27 -13
  43. package/lib/request.d.ts.map +1 -1
  44. package/lib/request.js +84 -51
  45. package/lib/request.js.map +1 -1
  46. package/lib/timetable.d.ts +26 -0
  47. package/lib/timetable.d.ts.map +1 -0
  48. package/lib/timetable.js +110 -0
  49. package/lib/timetable.js.map +1 -0
  50. package/lib/types.d.ts +108 -75
  51. package/lib/types.d.ts.map +1 -1
  52. package/lib/types.js +3 -0
  53. package/lib/types.js.map +1 -1
  54. package/lib/urls.d.ts +10 -20
  55. package/lib/urls.d.ts.map +1 -1
  56. package/lib/urls.js +11 -56
  57. package/lib/urls.js.map +1 -1
  58. package/lib/user.d.ts +7 -2
  59. package/lib/user.d.ts.map +1 -1
  60. package/lib/user.js +19 -5
  61. package/lib/user.js.map +1 -1
  62. package/lib/utils.d.ts +42 -4
  63. package/lib/utils.d.ts.map +1 -1
  64. package/lib/utils.js +78 -31
  65. package/lib/utils.js.map +1 -1
  66. package/package.json +8 -7
  67. package/src/auth.ts +62 -73
  68. package/src/calendar.ts +110 -16
  69. package/src/contents.ts +7 -9
  70. package/src/courses.ts +12 -26
  71. package/src/discussions.ts +8 -19
  72. package/src/favorites.ts +22 -48
  73. package/src/files.ts +121 -139
  74. package/src/homework.ts +184 -102
  75. package/src/index.ts +67 -48
  76. package/src/notices.ts +19 -26
  77. package/src/questionnaires.ts +18 -15
  78. package/src/request.ts +86 -62
  79. package/src/timetable.ts +121 -0
  80. package/src/types.ts +111 -86
  81. package/src/urls.ts +13 -64
  82. package/src/user.ts +21 -6
  83. package/src/utils.ts +96 -32
package/lib/homework.js CHANGED
@@ -1,63 +1,65 @@
1
1
  // Homework (课程作业), excellent homework and homework submission.
2
2
  import { Base64 } from 'js-base64';
3
- import { $, YES } from './request.js';
3
+ import { addCSRFTokenToUrl } from './request.js';
4
4
  import { ContentType, CourseType, FailReason } from './types.js';
5
5
  import * as URLS from './urls.js';
6
- import { GRADE_LEVEL_MAP, decodeHTML, isSelected, trimAndDefine } from './utils.js';
6
+ import { $, GRADE_LEVEL_MAP, YES, apiError, decodeHTML, expectSuccess, isSelected, looksLikeLoginPage, toRequiredServerTime, toServerTime, trimAndDefine, } from './utils.js';
7
+ /** the student homework lists, by submission status */
8
+ export const HOMEWORK_LIST_SOURCES = [
9
+ { url: URLS.LEARN_HOMEWORK_LIST_NEW, status: { submitted: false, graded: false } },
10
+ { url: URLS.LEARN_HOMEWORK_LIST_SUBMITTED, status: { submitted: true, graded: false } },
11
+ { url: URLS.LEARN_HOMEWORK_LIST_GRADED, status: { submitted: true, graded: true } },
12
+ ];
7
13
  export async function getHomeworkList(s, courseID, courseType = CourseType.STUDENT, options = {}) {
8
- if (courseType === CourseType.TEACHER) {
9
- const json = await s.fetchJsonWithToken(URLS.LEARN_HOMEWORK_LIST_TEACHER, {
10
- method: 'POST',
11
- body: URLS.LEARN_PAGE_LIST_FORM_DATA(courseID),
12
- });
13
- if (json.result !== 'success') {
14
- return Promise.reject({
15
- reason: FailReason.INVALID_RESPONSE,
16
- extra: json,
17
- });
18
- }
19
- const result = (json.object?.aaData ?? []);
20
- return result.map((d) => ({
21
- id: d.zyid,
22
- index: d.wz,
23
- title: decodeHTML(d.bt),
24
- description: decodeHTML(Base64.decode(d.nr)),
25
- publisherId: d.fbr,
26
- publishTime: d.fbsj,
27
- startTime: d.kssj,
28
- deadline: d.jzsj,
29
- lateSubmissionDeadline: d.bjjzsj ?? undefined,
30
- url: URLS.LEARN_HOMEWORK_DETAIL_TEACHER(courseID, d.zyid),
31
- completionType: d.zywcfs,
32
- submissionType: d.zytjfs,
33
- gradedCount: d.ypys,
34
- submittedCount: d.yjs,
35
- unsubmittedCount: d.wjs,
36
- }));
37
- }
38
- else {
39
- const [lists, excellentHomeworkListByHomework] = await Promise.all([
40
- Promise.all(URLS.LEARN_HOMEWORK_LIST_SOURCE.map((source) => getHomeworkListAtUrl(s, courseID, source.url, source.status))),
41
- // Don't block the whole process if excellent homework list cannot be fetched
42
- getExcellentHomeworkListByHomework(s, courseID).catch(() => ({})),
43
- ]);
44
- return Promise.all(lists.flat().map(async (h) => {
45
- const homework = { ...h, excellentHomeworkList: excellentHomeworkListByHomework[h.baseId] };
46
- return isSelected(options.details, homework) ? { ...homework, ...(await getHomeworkDetail(s, h)) } : homework;
47
- }));
48
- }
14
+ return courseType === CourseType.TEACHER
15
+ ? getTeacherHomeworkList(s, courseID)
16
+ : getStudentHomeworkList(s, courseID, options);
17
+ }
18
+ async function getTeacherHomeworkList(s, courseID) {
19
+ const json = await s.fetchJsonWithToken(URLS.LEARN_HOMEWORK_LIST_TEACHER, {
20
+ method: 'POST',
21
+ body: URLS.LEARN_PAGE_LIST_FORM_DATA(courseID),
22
+ });
23
+ expectSuccess(json, FailReason.INVALID_RESPONSE);
24
+ const result = (json.object?.aaData ?? []);
25
+ return result.map((d) => ({
26
+ id: d.zyid,
27
+ index: d.wz,
28
+ title: decodeHTML(d.bt),
29
+ description: decodeHTML(Base64.decode(d.nr ?? '')),
30
+ publisherId: d.fbr,
31
+ publishTime: toRequiredServerTime(d.fbsj),
32
+ startTime: toRequiredServerTime(d.kssj),
33
+ deadline: toRequiredServerTime(d.jzsj),
34
+ lateSubmissionDeadline: toServerTime(d.bjjzsj),
35
+ url: URLS.LEARN_HOMEWORK_DETAIL_TEACHER(courseID, d.zyid),
36
+ completionType: d.zywcfs,
37
+ submissionType: d.zytjfs,
38
+ gradedCount: d.ypys,
39
+ submittedCount: d.yjs,
40
+ unsubmittedCount: d.wjs,
41
+ }));
42
+ }
43
+ async function getStudentHomeworkList(s, courseID, options) {
44
+ const [lists, excellentHomeworkListByHomework] = await Promise.all([
45
+ Promise.all(HOMEWORK_LIST_SOURCES.map((source) => getHomeworkListAtUrl(s, courseID, source.url, source.status))),
46
+ // a failed excellent homework list doesn't fail the homework list: its items get `excellentHomeworkList: undefined`
47
+ getExcellentHomeworkListByHomework(s, courseID).catch(() => undefined),
48
+ ]);
49
+ return Promise.all(lists.flat().map(async (h) => {
50
+ const homework = {
51
+ ...h,
52
+ excellentHomeworkList: excellentHomeworkListByHomework && (excellentHomeworkListByHomework[h.baseId] ?? []),
53
+ };
54
+ return isSelected(options.details, homework) ? { ...homework, ...(await getHomeworkDetail(s, h)) } : homework;
55
+ }));
49
56
  }
50
57
  async function getHomeworkListAtUrl(s, courseID, url, status) {
51
58
  const json = await s.fetchJsonWithToken(url, {
52
59
  method: 'POST',
53
60
  body: URLS.LEARN_PAGE_LIST_FORM_DATA(courseID),
54
61
  });
55
- if (json.result !== 'success') {
56
- return Promise.reject({
57
- reason: FailReason.INVALID_RESPONSE,
58
- extra: json,
59
- });
60
- }
62
+ expectSuccess(json, FailReason.INVALID_RESPONSE);
61
63
  const result = (json.object?.aaData ?? []);
62
64
  return result.map((h) => ({
63
65
  id: h.xszyid,
@@ -65,20 +67,19 @@ async function getHomeworkListAtUrl(s, courseID, url, status) {
65
67
  baseId: h.zyid,
66
68
  title: decodeHTML(h.bt),
67
69
  url: URLS.LEARN_HOMEWORK_PAGE(h.wlkcid, h.xszyid),
68
- deadline: h.jzsj,
69
- lateSubmissionDeadline: h.bjjzsj ? h.bjjzsj : undefined,
70
+ deadline: toRequiredServerTime(h.jzsj),
71
+ lateSubmissionDeadline: toServerTime(h.bjjzsj),
70
72
  isLateSubmission: h.sfbj === YES,
71
73
  completionType: h.zywcfs,
72
74
  submissionType: h.zytjfs,
73
75
  submitUrl: URLS.LEARN_HOMEWORK_SUBMIT_PAGE(h.wlkcid, h.xszyid),
74
- submitTime: h.scsj === null ? undefined : h.scsj,
76
+ submitTime: toServerTime(h.scsj),
75
77
  grade: h.cj === null ? undefined : h.cj,
76
78
  gradeLevel: GRADE_LEVEL_MAP.get(h.cj),
77
79
  graderName: trimAndDefine(h.jsm),
78
80
  gradeContent: trimAndDefine(h.pynr),
79
- gradeTime: h.pysj === null ? undefined : h.pysj,
81
+ gradeTime: toServerTime(h.pysj),
80
82
  isFavorite: h.sfsc === YES,
81
- favoriteTime: h.scsj === null || h.sfsc !== YES ? undefined : h.scsj,
82
83
  comment: h.bznr ?? undefined,
83
84
  ...status,
84
85
  }));
@@ -88,12 +89,7 @@ async function getExcellentHomeworkListByHomework(s, courseID) {
88
89
  method: 'POST',
89
90
  body: URLS.LEARN_PAGE_LIST_FORM_DATA(courseID),
90
91
  });
91
- if (json.result !== 'success') {
92
- return Promise.reject({
93
- reason: FailReason.INVALID_RESPONSE,
94
- extra: json,
95
- });
96
- }
92
+ expectSuccess(json, FailReason.INVALID_RESPONSE);
97
93
  const result = (json.object?.aaData ?? []);
98
94
  return result
99
95
  .map((h) => ({
@@ -138,35 +134,31 @@ export async function getHomeworkDetail(s, homework) {
138
134
  parseHomeworkAtUrl(s, homework.url),
139
135
  getHomeworkDescription(s, homework.baseId),
140
136
  ]);
141
- return { ...page, ...description };
137
+ // the description JSON wins, but an empty one falls back to the page
138
+ return { ...page, description: description.description ?? page.description };
142
139
  }
143
140
  async function getHomeworkDescription(s, baseId) {
144
141
  const json = await s.fetchJsonWithToken(URLS.LEARN_HOMEWORK_DETAIL, {
145
142
  method: 'POST',
146
143
  body: URLS.LEARN_HOMEWORK_DETAIL_FORM_DATA(baseId),
147
144
  });
148
- if (json.result !== 'success') {
149
- throw {
150
- reason: FailReason.INVALID_RESPONSE,
151
- extra: json,
152
- };
153
- }
145
+ expectSuccess(json, FailReason.INVALID_RESPONSE);
154
146
  return {
155
147
  description: trimAndDefine(json.msg),
156
148
  };
157
149
  }
150
+ /** the attachment in one `div.list.fujian` block; `undefined` if the block is missing or has no link */
158
151
  function parseHomeworkFile(s, fileDiv) {
152
+ if (!fileDiv)
153
+ return undefined;
159
154
  const fileNode = $(fileDiv)('.ftitle').children('a')[0] ?? $(fileDiv)('.fl').children('a')[0];
160
155
  const href = fileNode?.attribs.href;
161
156
  if (fileNode !== undefined && href) {
162
157
  const size = trimAndDefine($(fileDiv)('.fl > span[class^="color"]').first().text()) ?? '';
163
158
  const params = new URLSearchParams(href.split('?').slice(-1)[0]);
164
159
  const attachmentId = params.get('fileId');
165
- // so dirty here...
166
- let downloadUrl = URLS.LEARN_PREFIX + href;
167
- if (params.has('downloadUrl')) {
168
- downloadUrl = URLS.LEARN_PREFIX + params.get('downloadUrl');
169
- }
160
+ // a link to the file viewer carries the download path in its `downloadUrl` parameter
161
+ const downloadUrl = URLS.LEARN_PREFIX + (params.get('downloadUrl') ?? href);
170
162
  return {
171
163
  id: attachmentId,
172
164
  name: fileNode.children[0]?.data ?? '',
@@ -180,17 +172,81 @@ function parseHomeworkFile(s, fileDiv) {
180
172
  }
181
173
  }
182
174
  export async function submitHomework(s, id, content = '', attachment, removeAttachment = false) {
183
- const json = await s.fetchJsonWithToken(URLS.LEARN_HOMEWORK_SUBMIT(), {
175
+ const json = await s.fetchJsonWithToken(URLS.LEARN_HOMEWORK_SUBMIT, {
184
176
  method: 'POST',
185
- body: URLS.LEARN_HOMEWORK_SUBMIT_FORM_DATA(id, content, attachment, removeAttachment),
177
+ body: homeworkSubmitForm(id, content, attachment, removeAttachment),
186
178
  // the response only starts after the whole upload, which can take longer than `requestTimeout`
187
179
  timeout: attachment ? 0 : undefined,
188
180
  });
189
- if (json.result !== 'success') {
190
- return Promise.reject({
191
- reason: FailReason.OPERATION_FAILED,
192
- extra: json,
193
- });
181
+ checkHomeworkSubmitResponse(json);
182
+ }
183
+ /**
184
+ * The request `submitHomework` would send, for sending it with another HTTP client (e.g. one that reports upload
185
+ * progress). Checks the session first (`ensureSession`: one request, and a login only if it has expired), as the
186
+ * request is sent without the helper's re-login and retry. Read the answer with `checkHomeworkSubmitResponse`.
187
+ */
188
+ export async function getHomeworkSubmitRequest(s, id, content = '', attachment, removeAttachment = false) {
189
+ await s.ensureSession(URLS.LEARN_CURRENT_SEMESTER);
190
+ return {
191
+ url: addCSRFTokenToUrl(URLS.LEARN_HOMEWORK_SUBMIT, s.csrfToken),
192
+ body: homeworkSubmitForm(id, content, attachment, removeAttachment),
193
+ };
194
+ }
195
+ /**
196
+ * Check the server's answer to a homework submission: its parsed JSON, or the body as text. Rejects with
197
+ * `NOT_LOGGED_IN` for the login page of an expired session (which the server sends with status 200),
198
+ * `INVALID_RESPONSE` for any other text that isn't JSON, and `OPERATION_FAILED` (with the answer in `extra`) unless
199
+ * `result` is `'success'`.
200
+ */
201
+ export function checkHomeworkSubmitResponse(body) {
202
+ let json = body;
203
+ if (typeof body === 'string') {
204
+ try {
205
+ json = JSON.parse(body);
206
+ }
207
+ catch {
208
+ throw apiError(looksLikeLoginPage(body) ? FailReason.NOT_LOGGED_IN : FailReason.INVALID_RESPONSE, body.slice(0, 200));
209
+ }
194
210
  }
211
+ expectSuccess(json, FailReason.OPERATION_FAILED);
212
+ }
213
+ /**
214
+ * The form the website's submit page sends (`fileUploadProgress` in `/res/js/common/myApp.js`): `fileupload` is the
215
+ * picked file, or the text "undefined" when none is picked (it appends `files[0]` as is); `zynr` is the whole current
216
+ * answer as HTML from its editor, sent every time (also when only the attachment changes); `isDeleted` is "1" when the
217
+ * existing attachment is deleted, and then the server ignores `zynr` (the submitted answer stays).
218
+ */
219
+ export const homeworkSubmitForm = (id, content = '', attachment, removeAttachment = false) => {
220
+ const form = new FormData();
221
+ form.append('xszyid', id);
222
+ form.append('zynr', content ?? '');
223
+ if (!attachment)
224
+ form.append('fileupload', 'undefined');
225
+ else if (attachment.content instanceof Blob)
226
+ form.append('fileupload', attachment.content, attachment.filename);
227
+ else {
228
+ // React Native's FormData reads a file from an object with its uri, name and type
229
+ const { uri, type } = attachment.content;
230
+ form.append('fileupload', { uri, name: attachment.filename, type: type || 'application/octet-stream' });
231
+ }
232
+ if (removeAttachment)
233
+ form.append('isDeleted', '1');
234
+ else
235
+ form.append('isDeleted', '0');
236
+ return form;
237
+ };
238
+ const HTML_ESCAPES = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' };
239
+ /**
240
+ * Plain text as the website's answer editor sends it: one `<p>` per line, with `&nbsp;` for an empty line, and `''`
241
+ * for text that is only whitespace. The server replaces the submitted answer with what is sent, so send its HTML
242
+ * as it is when the answer wasn't edited, to keep its formatting.
243
+ */
244
+ export function homeworkContentHtml(text) {
245
+ if (!text.trim())
246
+ return '';
247
+ return text
248
+ .split(/\r?\n/)
249
+ .map((line) => `<p>${line.trim() ? line.replace(/[&<>"']/g, (c) => HTML_ESCAPES[c]) : '&nbsp;'}</p>`)
250
+ .join('');
195
251
  }
196
252
  //# sourceMappingURL=homework.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"homework.js","sourceRoot":"","sources":["../src/homework.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"homework.js","sourceRoot":"","sources":["../src/homework.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
- import type { AllContentsOptions, AllContentsResult, CalendarOptions, CalendarResult, CourseListOptions, ExcellentHomework, HomeworkListOptions, IHomeworkDetail, NotificationListOptions, RemoteFile, CommentItem, CourseInfo, Discussion, FavoriteItem, File, FileCategory, HelperConfig, Homework, HomeworkTA, IHomeworkSubmitAttachment, Language, Notification, Question, Questionnaire, QuestionnaireDetail, QuestionnaireListOptions, SemesterInfo, UserInfo, ContentType } from './types.ts';
1
+ import type { AllContentsOptions, Credential, AllContentsResult, CalendarOptions, CalendarResult, CommentItem, ContentType, CourseFile, CourseInfo, CourseListOptions, CourseNotification, Discussion, ExcellentHomework, FavoriteItem, FileCategory, HelperConfig, Homework, HomeworkDetail, HomeworkListOptions, HomeworkSubmitAttachment, HomeworkSubmitRequest, HomeworkTA, Language, NotificationListOptions, Question, Questionnaire, QuestionnaireDetail, QuestionnaireListOptions, RemoteFile, SemesterInfo, UserInfo } from './types.ts';
2
2
  import { CourseType } from './types.ts';
3
- export { addCSRFTokenToUrl } from './request.ts';
3
+ export { addCSRFTokenToUrl, isConnectionError } from './request.ts';
4
+ export { checkHomeworkSubmitResponse, homeworkContentHtml } from './homework.ts';
5
+ export { CLASS_PERIOD_TIMES, parseCourseMeeting, parseWeeks, semesterWeek } from './timetable.ts';
4
6
  export * from './types.ts';
5
7
  /** the main helper class */
6
8
  export declare class Learn2018Helper {
@@ -15,16 +17,18 @@ export declare class Learn2018Helper {
15
17
  /** manually set CSRF token (useful when you want to reuse previous token) */
16
18
  setCSRFToken(csrfToken: string): void;
17
19
  /**
18
- * If using alternative cookie management systems,
19
- * be sure to clear id.tsinghua.edu.cn cookies before calling this function
20
+ * Sign in to id.tsinghua.edu.cn and return the Web Learning roaming ticket, without logging in to Web Learning.
21
+ * Rejects with `NO_CREDENTIAL` unless `credential` has a username, a password and a fingerprint. If using
22
+ * alternative cookie management systems, be sure to clear id.tsinghua.edu.cn cookies before calling this function.
20
23
  */
21
- getRoamingTicket(username: string, password: string, fingerPrint: string, fingerGenPrint?: string, fingerGenPrint3?: string): Promise<string>;
24
+ getRoamingTicket(credential: Credential): Promise<string>;
22
25
  /**
23
26
  * Login is necessary if you do not provide a `CredentialProvider`.
24
- * Without credentials it uses the provider, and concurrent calls share one SSO login. Logins never overlap: one with
25
- * credentials waits for a login in progress, and requests that find the session expired meanwhile wait for it.
27
+ * Without a credential it uses the provider, and concurrent calls share one SSO login; a credential without a
28
+ * username, a password and a fingerprint rejects with `NO_CREDENTIAL`. Logins never overlap: one with a credential
29
+ * waits for a login in progress, and requests that find the session expired meanwhile wait for it.
26
30
  */
27
- login(username?: string, password?: string, fingerPrint?: string, fingerGenPrint?: string, fingerGenPrint3?: string): Promise<void>;
31
+ login(credential?: Credential): Promise<void>;
28
32
  /**
29
33
  * Make sure the session is usable without a full SSO login when possible: with a CSRF token (from an earlier login
30
34
  * or `setCSRFToken`), make one cheap request and log in again only if the session has expired; without one, log in.
@@ -37,16 +41,19 @@ export declare class Learn2018Helper {
37
41
  getUserInfo(courseType?: CourseType): Promise<UserInfo>;
38
42
  /**
39
43
  * Get calendar items during the specified period (in yyyymmdd format, both inclusive).
40
- * Ranges longer than 28 days are fetched in windows and merged; windows that fail even after a retry are listed in
41
- * `failedRanges`. Rejects only when every window fails (usually with `FailReason.INVALID_RESPONSE`), or with a
42
- * `RangeError` for a date that is not a valid yyyymmdd.
44
+ * Ranges longer than 28 days are fetched in windows and merged; windows that still fail are listed in `failedRanges`
45
+ * (a timed-out window is not retried). Rejects when every window fails (usually with `FailReason.INVALID_RESPONSE`),
46
+ * with `FailReason.ERROR_REGISTRAR_AUTH` when signing in to the registrar fails, or with a `RangeError` for a date
47
+ * that is not a valid yyyymmdd. With a `CredentialProvider`, a sign-in that id.tsinghua.edu.cn turns down (its session
48
+ * from the last login expired) logs in again and is tried once more.
43
49
  */
44
50
  getCalendar(startDate: string, endDate: string, options?: CalendarOptions): Promise<CalendarResult>;
45
51
  getSemesterIdList(): Promise<string[]>;
46
52
  getCurrentSemester(): Promise<SemesterInfo>;
47
53
  /**
48
54
  * Get all courses in the specified semester.
49
- * `timeAndLocation` is only fetched (one request per course) with `options.timeAndLocation`.
55
+ * `timeAndLocation` is only fetched (one request per course) with `options.timeAndLocation`, and left out for a
56
+ * course whose request failed.
50
57
  */
51
58
  getCourseList(semesterID: string, courseType?: CourseType, lang?: Language, options?: CourseListOptions): Promise<CourseInfo[]>;
52
59
  /** Get the time and location of one course. */
@@ -62,18 +69,18 @@ export declare class Learn2018Helper {
62
69
  * Attachments are only fetched (one request per notice) for the notices `options.attachments` selects;
63
70
  * use `getNotificationAttachment` for the others.
64
71
  */
65
- getNotificationList(courseID: string, courseType?: CourseType, options?: NotificationListOptions): Promise<Notification[]>;
72
+ getNotificationList(courseID: string, courseType?: CourseType, options?: NotificationListOptions): Promise<CourseNotification[]>;
66
73
  /** Get the attachment of a notice (one request), `undefined` if it has none. */
67
- getNotificationAttachment(notification: Pick<Notification, 'url' | 'attachmentName'>, courseType?: CourseType): Promise<RemoteFile | undefined>;
74
+ getNotificationAttachment(notification: Pick<CourseNotification, 'url' | 'attachmentName'>, courseType?: CourseType): Promise<RemoteFile | undefined>;
68
75
  /** Get all files (课程文件) of the specified course. */
69
- getFileList(courseID: string, courseType?: CourseType): Promise<File[]>;
76
+ getFileList(courseID: string, courseType?: CourseType): Promise<CourseFile[]>;
70
77
  /** Get file categories of the specified course. */
71
78
  getFileCategoryList(courseID: string, courseType?: CourseType): Promise<FileCategory[]>;
72
79
  /**
73
80
  * Get all files of the specified category of the specified course.
74
81
  * Note: this cannot get correct `visitCount` and `downloadCount` for student
75
82
  */
76
- getFileListByCategory(courseID: string, categoryId: string, courseType?: CourseType): Promise<File[]>;
83
+ getFileListByCategory(courseID: string, categoryId: string, courseType?: CourseType): Promise<CourseFile[]>;
77
84
  /**
78
85
  * Get all homeworks (课程作业) of the specified course, with the excellent homework list (without details).
79
86
  * Details (page + description, two requests per homework) are only fetched for the homework `options.details`
@@ -82,9 +89,9 @@ export declare class Learn2018Helper {
82
89
  getHomeworkList(courseID: string, courseType?: CourseType.STUDENT, options?: HomeworkListOptions): Promise<Homework[]>;
83
90
  getHomeworkList(courseID: string, courseType: CourseType.TEACHER): Promise<HomeworkTA[]>;
84
91
  /** Get the detail (page content, attachments and description) of one homework. */
85
- getHomeworkDetail(item: Pick<Homework, 'url' | 'baseId'>): Promise<IHomeworkDetail>;
92
+ getHomeworkDetail(item: Pick<Homework, 'url' | 'baseId'>): Promise<HomeworkDetail>;
86
93
  /** Get the detail (page content, attachments and description) of one excellent homework. */
87
- getExcellentHomeworkDetail(item: Pick<ExcellentHomework, 'url' | 'baseId'>): Promise<IHomeworkDetail>;
94
+ getExcellentHomeworkDetail(item: Pick<ExcellentHomework, 'url' | 'baseId'>): Promise<HomeworkDetail>;
88
95
  /** Get all discussions (课程讨论) of the specified course. */
89
96
  getDiscussionList(courseID: string, courseType?: CourseType): Promise<Discussion[]>;
90
97
  /**
@@ -132,7 +139,20 @@ export declare class Learn2018Helper {
132
139
  */
133
140
  getComments(courseID?: string, type?: ContentType): Promise<CommentItem[]>;
134
141
  sortCourses(courseIDs: string[]): Promise<void>;
135
- submitHomework(id: string, content?: string, attachment?: IHomeworkSubmitAttachment, removeAttachment?: boolean): Promise<void>;
142
+ /**
143
+ * Submit homework `id` (the `studentHomeworkId`), the way the website's submit page does. `content` is the whole
144
+ * answer as HTML (the website sends its editor's HTML) and replaces the submitted one, so pass the current answer
145
+ * when only changing the attachment (`homeworkContentHtml` turns plain text into the editor's HTML). With no
146
+ * `attachment` the existing one is kept, unless `removeAttachment`: that only deletes the attachment, and `content` is
147
+ * ignored. In React Native, pass the attachment's `content` as `{ uri, type }`.
148
+ */
149
+ submitHomework(id: string, content?: string, attachment?: HomeworkSubmitAttachment, removeAttachment?: boolean): Promise<void>;
150
+ /**
151
+ * The request `submitHomework` would send, for sending with another HTTP client (e.g. to show upload progress, which
152
+ * `fetch` can't): POST `body` to `url`, then pass the answer (parsed JSON or text) to `checkHomeworkSubmitResponse`.
153
+ * It checks the session first (`ensureSession`), since that request doesn't log in again and retry.
154
+ */
155
+ getHomeworkSubmitRequest(id: string, content?: string, attachment?: HomeworkSubmitAttachment, removeAttachment?: boolean): Promise<HomeworkSubmitRequest>;
136
156
  setLanguage(lang: Language): Promise<void>;
137
157
  getCurrentLanguage(): Language;
138
158
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/lib/index.js CHANGED
@@ -9,17 +9,20 @@ import * as homework from './homework.js';
9
9
  import * as notices from './notices.js';
10
10
  import * as questionnaires from './questionnaires.js';
11
11
  import { Session } from './request.js';
12
- import { CourseType } from './types.js';
12
+ import { CourseType, FailReason } from './types.js';
13
+ import { apiError } from './utils.js';
13
14
  import * as URLS from './urls.js';
14
15
  import * as user from './user.js';
15
- export { addCSRFTokenToUrl } from './request.js';
16
+ export { addCSRFTokenToUrl, isConnectionError } from './request.js';
17
+ export { checkHomeworkSubmitResponse, homeworkContentHtml } from './homework.js';
18
+ export { CLASS_PERIOD_TIMES, parseCourseMeeting, parseWeeks, semesterWeek } from './timetable.js';
16
19
  export * from './types.js';
17
20
  /** the main helper class */
18
21
  export class Learn2018Helper {
19
22
  #session;
20
23
  /** you can provide a CookieJar and / or CredentialProvider in the configuration */
21
24
  constructor(config) {
22
- this.#session = new Session(config, () => auth.login(this.#session));
25
+ this.#session = new Session(config, () => auth.loginWithProvider(this.#session));
23
26
  }
24
27
  /** whether preview URLs open the first page only (`HelperConfig.generatePreviewUrlForFirstPage`) */
25
28
  get previewFirstPage() {
@@ -37,21 +40,27 @@ export class Learn2018Helper {
37
40
  this.#session.csrfToken = csrfToken;
38
41
  }
39
42
  /**
40
- * If using alternative cookie management systems,
41
- * be sure to clear id.tsinghua.edu.cn cookies before calling this function
43
+ * Sign in to id.tsinghua.edu.cn and return the Web Learning roaming ticket, without logging in to Web Learning.
44
+ * Rejects with `NO_CREDENTIAL` unless `credential` has a username, a password and a fingerprint. If using
45
+ * alternative cookie management systems, be sure to clear id.tsinghua.edu.cn cookies before calling this function.
42
46
  */
43
- async getRoamingTicket(username, password, fingerPrint, fingerGenPrint = '', fingerGenPrint3 = '') {
44
- return auth.getRoamingTicket(this.#session, username, password, fingerPrint, fingerGenPrint, fingerGenPrint3);
47
+ async getRoamingTicket(credential) {
48
+ if (!auth.isComplete(credential))
49
+ throw apiError(FailReason.NO_CREDENTIAL);
50
+ return auth.getRoamingTicket(this.#session, credential);
45
51
  }
46
52
  /**
47
53
  * Login is necessary if you do not provide a `CredentialProvider`.
48
- * Without credentials it uses the provider, and concurrent calls share one SSO login. Logins never overlap: one with
49
- * credentials waits for a login in progress, and requests that find the session expired meanwhile wait for it.
54
+ * Without a credential it uses the provider, and concurrent calls share one SSO login; a credential without a
55
+ * username, a password and a fingerprint rejects with `NO_CREDENTIAL`. Logins never overlap: one with a credential
56
+ * waits for a login in progress, and requests that find the session expired meanwhile wait for it.
50
57
  */
51
- async login(username, password, fingerPrint, fingerGenPrint, fingerGenPrint3) {
52
- if (!username || !password || !fingerPrint)
58
+ async login(credential) {
59
+ if (credential === undefined)
53
60
  return this.#session.relogin();
54
- return this.#session.runLogin(() => auth.login(this.#session, username, password, fingerPrint, fingerGenPrint, fingerGenPrint3));
61
+ if (!auth.isComplete(credential))
62
+ throw apiError(FailReason.NO_CREDENTIAL);
63
+ return this.#session.runLogin(() => auth.login(this.#session, credential));
55
64
  }
56
65
  /**
57
66
  * Make sure the session is usable without a full SSO login when possible: with a CSRF token (from an earlier login
@@ -59,7 +68,7 @@ export class Learn2018Helper {
59
68
  * Use it when resuming an app instead of `login()`.
60
69
  */
61
70
  async ensureSession() {
62
- return this.#session.ensureSession(URLS.LEARN_CURRENT_SEMESTER());
71
+ return this.#session.ensureSession(URLS.LEARN_CURRENT_SEMESTER);
63
72
  }
64
73
  /** logout (to make everyone happy) */
65
74
  async logout() {
@@ -71,9 +80,11 @@ export class Learn2018Helper {
71
80
  }
72
81
  /**
73
82
  * Get calendar items during the specified period (in yyyymmdd format, both inclusive).
74
- * Ranges longer than 28 days are fetched in windows and merged; windows that fail even after a retry are listed in
75
- * `failedRanges`. Rejects only when every window fails (usually with `FailReason.INVALID_RESPONSE`), or with a
76
- * `RangeError` for a date that is not a valid yyyymmdd.
83
+ * Ranges longer than 28 days are fetched in windows and merged; windows that still fail are listed in `failedRanges`
84
+ * (a timed-out window is not retried). Rejects when every window fails (usually with `FailReason.INVALID_RESPONSE`),
85
+ * with `FailReason.ERROR_REGISTRAR_AUTH` when signing in to the registrar fails, or with a `RangeError` for a date
86
+ * that is not a valid yyyymmdd. With a `CredentialProvider`, a sign-in that id.tsinghua.edu.cn turns down (its session
87
+ * from the last login expired) logs in again and is tried once more.
77
88
  */
78
89
  async getCalendar(startDate, endDate, options) {
79
90
  return calendar.getCalendar(this.#session, startDate, endDate, options);
@@ -86,7 +97,8 @@ export class Learn2018Helper {
86
97
  }
87
98
  /**
88
99
  * Get all courses in the specified semester.
89
- * `timeAndLocation` is only fetched (one request per course) with `options.timeAndLocation`.
100
+ * `timeAndLocation` is only fetched (one request per course) with `options.timeAndLocation`, and left out for a
101
+ * course whose request failed.
90
102
  */
91
103
  async getCourseList(semesterID, courseType = CourseType.STUDENT, lang = this.#session.lang, options) {
92
104
  return courses.getCourseList(this.#session, semesterID, courseType, lang, options);
@@ -214,9 +226,24 @@ export class Learn2018Helper {
214
226
  async sortCourses(courseIDs) {
215
227
  return courses.sortCourses(this.#session, courseIDs);
216
228
  }
229
+ /**
230
+ * Submit homework `id` (the `studentHomeworkId`), the way the website's submit page does. `content` is the whole
231
+ * answer as HTML (the website sends its editor's HTML) and replaces the submitted one, so pass the current answer
232
+ * when only changing the attachment (`homeworkContentHtml` turns plain text into the editor's HTML). With no
233
+ * `attachment` the existing one is kept, unless `removeAttachment`: that only deletes the attachment, and `content` is
234
+ * ignored. In React Native, pass the attachment's `content` as `{ uri, type }`.
235
+ */
217
236
  async submitHomework(id, content = '', attachment, removeAttachment = false) {
218
237
  return homework.submitHomework(this.#session, id, content, attachment, removeAttachment);
219
238
  }
239
+ /**
240
+ * The request `submitHomework` would send, for sending with another HTTP client (e.g. to show upload progress, which
241
+ * `fetch` can't): POST `body` to `url`, then pass the answer (parsed JSON or text) to `checkHomeworkSubmitResponse`.
242
+ * It checks the session first (`ensureSession`), since that request doesn't log in again and retry.
243
+ */
244
+ async getHomeworkSubmitRequest(id, content = '', attachment, removeAttachment = false) {
245
+ return homework.getHomeworkSubmitRequest(this.#session, id, content, attachment, removeAttachment);
246
+ }
220
247
  async setLanguage(lang) {
221
248
  return user.setLanguage(this.#session, lang);
222
249
  }