@robertying/thu-learn-lib 4.1.0 → 5.0.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 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAc,kBAAkB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1G,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,YAAY,CAUzD;AAWD,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAEvD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAU/C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAMjF;AAED,eAAO,MAAM,eAAe,iCA0B1B,CAAC;AAEH,eAAO,MAAM,oBAAoB,kCAAkC,CAAC;AAEpE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAQrD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMnD;AAED,eAAO,MAAM,gBAAgB,0BAQ3B,CAAC;AACH,eAAO,MAAM,wBAAwB,0BAOnC,CAAC;AAEH,eAAO,MAAM,YAAY,gCAIvB,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,WAAW,EAAc,kBAAkB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1G,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,YAAY,CAUzD;AAWD,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAEvD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAU/C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAMjF;AAED,eAAO,MAAM,eAAe,iCA0B1B,CAAC;AAEH,eAAO,MAAM,oBAAoB,kCAAkC,CAAC;AAEpE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAQrD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMnD;AAED,eAAO,MAAM,gBAAgB,0BAQ3B,CAAC;AACH,eAAO,MAAM,wBAAwB,0BAOnC,CAAC;AAEH,eAAO,MAAM,YAAY,gCAIvB,CAAC;AAEH,oFAAoF;AACpF,eAAO,MAAM,UAAU,GAAI,CAAC,YAAY,cAAc,CAAC,CAAC,CAAC,GAAG,SAAS,QAAQ,CAAC,KAAG,OACP,CAAC"}
package/lib/utils.js CHANGED
@@ -112,4 +112,6 @@ export const QNR_TYPE_MAP = new Map([
112
112
  ['填表', QuestionnaireType.FORM],
113
113
  ['问卷', QuestionnaireType.SURVEY],
114
114
  ]);
115
+ /** whether `item` is selected by a `DetailSelector` (`undefined` means `'none'`) */
116
+ export const isSelected = (selector, item) => selector === 'all' || (typeof selector === 'function' && selector(item));
115
117
  //# sourceMappingURL=utils.js.map
package/lib/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,MAAM,UAAU,CAAC;AAErD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1G,MAAM,UAAU,iBAAiB,CAAC,CAAS;IACzC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACZ,OAAO,YAAY,CAAC,IAAI,CAAC;IAC3B,CAAC;SAAM,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,YAAY,CAAC,MAAM,CAAC;IAC7B,CAAC;SAAM,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,YAAY,CAAC,MAAM,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,OAAO,YAAY,CAAC,OAAO,CAAC;IAC9B,CAAC;AACH,CAAC;AAED,MAAM,mBAAmB,GAAG;IAC1B,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,MAAM;IAClC,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM;IAC1B,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM;IAC9B,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,EAAE;IAC5B,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,EAAE;IAC1B,CAAC,WAAW,CAAC,aAAa,CAAC,EAAE,EAAE;CAChC,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,IAAiB;IAC7C,OAAO,KAAK,GAAG,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IACrC,mDAAmD;IACnD,OAAO,IAAI,CAAC,UAAU,CAAC,sBAAsB,CAAC;QAC5C,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACf,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC;YAC/B,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YACf,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;gBAC3B,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;gBACf,CAAC,CAAC,IAAI,CAAC;AACf,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAA+B;IAC3D,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QACxC,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,OAAO,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IACrC,CAAC,CAAC,GAAG,EAAE,kBAAkB,CAAC,OAAO,CAAC;IAClC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,MAAM,CAAC;IAChC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC3B,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,OAAO,CAAC;IACjC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,MAAM,CAAC;IAChC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,WAAW,CAAC;IACrC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC3B,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,OAAO,CAAC;IACjC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,MAAM,CAAC;IAChC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC3B,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,OAAO,CAAC;IACjC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC3B,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,MAAM,CAAC;IAChC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC3B,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,eAAe,CAAC;IACzC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,IAAI,CAAC;IAC9B,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,EAAE,CAAC;IAC5B,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,SAAS,CAAC;IACnC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,IAAI,CAAC;IAC9B,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,OAAO,CAAC;IACjC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC3B,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC3B,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,UAAU,CAAC;IACpC,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,EAAE,CAAC;IAC5B,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;CAC5B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG,+BAA+B,CAAC;AAEpE,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,qBAAqB;IACrB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAC5C,MAAM,UAAU,CAAC,gBAAgB,CAAC;IACpC,CAAC;IACD,sBAAsB;IACtB,+GAA+G;IAC/G,OAAO,QAAQ,CAAC,sBAAsB,oBAAoB,kBAAkB,KAAK,GAAG,CAAC,EAAE,CAAC;AAC1F,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,sEAAsE;IACtE,IAAI,IAAI,GAAG,IAAI;QAAE,OAAO,IAAI,GAAG,GAAG,CAAC;IACnC,IAAI,IAAI,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IAC9D,IAAI,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IAC5E,OAAO,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IACtC,CAAC,WAAW,CAAC,YAAY,EAAE,MAAM,CAAC;IAClC,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC;IAC1B,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC9B,CAAC,WAAW,CAAC,UAAU,EAAE,MAAM,CAAC;IAChC,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC9B,CAAC,WAAW,CAAC,aAAa,EAAE,MAAM,CAAC;IACnC,oBAAoB;CACrB,CAAC,CAAC;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC;IAC9C,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,YAAY,CAAE,EAAE,WAAW,CAAC,YAAY,CAAC;IAC3E,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAE,EAAE,WAAW,CAAC,IAAI,CAAC;IAC3D,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAE,EAAE,WAAW,CAAC,QAAQ,CAAC;IACnE,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,UAAU,CAAE,EAAE,WAAW,CAAC,UAAU,CAAC;IACvE,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAE,EAAE,WAAW,CAAC,QAAQ,CAAC;IACnE,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,aAAa,CAAE,EAAE,WAAW,CAAC,aAAa,CAAC;CAC9E,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IAClC,CAAC,IAAI,EAAE,iBAAiB,CAAC,IAAI,CAAC;IAC9B,CAAC,IAAI,EAAE,iBAAiB,CAAC,IAAI,CAAC;IAC9B,CAAC,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC;CACjC,CAAC,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robertying/thu-learn-lib",
3
- "version": "4.1.0",
3
+ "version": "5.0.0",
4
4
  "description": "a JavaScript library to provide a program-friendly interface to Web Learning (2018) of Tsinghua University",
5
5
  "keywords": [
6
6
  "learn2018",
package/src/contents.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // One kind of content for many courses at once.
2
2
 
3
3
  import type { Session } from './request.ts';
4
- import type { ContentTypeMap, CourseContent } from './types.ts';
4
+ import type { AllContentsOptions, AllContentsResult, ContentTypeMap, CourseContent } from './types.ts';
5
5
  import { ContentType, CourseType, FailReason } from './types.ts';
6
6
  import { getAnsweredQuestionList, getDiscussionList } from './discussions.ts';
7
7
  import { getFileList } from './files.ts';
@@ -11,23 +11,27 @@ import { getQuestionnaireList } from './questionnaires.ts';
11
11
 
12
12
  /**
13
13
  * Get certain type of content of all specified courses.
14
- * It actually wraps around other `getXXX` functions. You can ignore the failure caused by certain courses.
14
+ * It wraps around the `getXXX` list functions; one course failing doesn't fail the others: its error is in `errors`.
15
15
  */
16
16
  export async function getAllContents<T extends ContentType>(
17
17
  s: Session,
18
18
  courseIDs: string[],
19
19
  type: T,
20
- courseType: CourseType = CourseType.STUDENT,
21
- allowFailure = false,
22
- ) {
23
- const fetchContentForCourse = (id: string) => {
20
+ options: AllContentsOptions<T> = {},
21
+ ): Promise<AllContentsResult<T>> {
22
+ const courseType = options.courseType ?? CourseType.STUDENT;
23
+ const fetchContentForCourse = (id: string): Promise<ContentTypeMap[T][]> => {
24
24
  switch (type) {
25
25
  case ContentType.NOTIFICATION:
26
- return getNotificationList(s, id, courseType) as Promise<ContentTypeMap[T][]>;
26
+ return getNotificationList(s, id, courseType, {
27
+ attachments: (options as AllContentsOptions<ContentType.NOTIFICATION>).details,
28
+ }) as Promise<ContentTypeMap[T][]>;
27
29
  case ContentType.FILE:
28
30
  return getFileList(s, id, courseType) as Promise<ContentTypeMap[T][]>;
29
31
  case ContentType.HOMEWORK:
30
- return getHomeworkList(s, id) as Promise<ContentTypeMap[T][]>;
32
+ return getHomeworkList(s, id, CourseType.STUDENT, {
33
+ details: (options as AllContentsOptions<ContentType.HOMEWORK>).details,
34
+ }) as Promise<ContentTypeMap[T][]>;
31
35
  case ContentType.DISCUSSION:
32
36
  return getDiscussionList(s, id, courseType) as Promise<ContentTypeMap[T][]>;
33
37
  case ContentType.QUESTION:
@@ -43,25 +47,17 @@ export async function getAllContents<T extends ContentType>(
43
47
  };
44
48
 
45
49
  const contents: CourseContent<T> = {};
50
+ const errors: AllContentsResult<T>['errors'] = {};
46
51
 
47
- const results = await Promise.allSettled(
52
+ await Promise.all(
48
53
  courseIDs.map(async (id) => {
49
- contents[id] = await fetchContentForCourse(id);
54
+ try {
55
+ contents[id] = await fetchContentForCourse(id);
56
+ } catch (err) {
57
+ errors[id] = err;
58
+ }
50
59
  }),
51
60
  );
52
61
 
53
- if (!allowFailure) {
54
- for (const r of results) {
55
- if (r.status === 'rejected') {
56
- return Promise.reject({
57
- reason: FailReason.INVALID_RESPONSE,
58
- extra: {
59
- reason: r.reason,
60
- },
61
- });
62
- }
63
- }
64
- }
65
-
66
- return contents;
62
+ return { contents, errors };
67
63
  }
package/src/courses.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // Semesters and courses.
2
2
 
3
3
  import type { Session } from './request.ts';
4
- import type { CourseInfo, SemesterInfo } from './types.ts';
4
+ import type { ApiError, CourseInfo, CourseListOptions, SemesterInfo } from './types.ts';
5
5
  import { CourseType, FailReason } from './types.ts';
6
6
  import * as URLS from './urls.ts';
7
7
  import { decodeHTML, parseSemesterType } from './utils.ts';
@@ -38,12 +38,13 @@ export async function getCurrentSemester(s: Session): Promise<SemesterInfo> {
38
38
  };
39
39
  }
40
40
 
41
- /** get all courses in the specified semester */
41
+ /** get all courses in the specified semester; time and location only with `options.timeAndLocation` */
42
42
  export async function getCourseList(
43
43
  s: Session,
44
44
  semesterID: string,
45
45
  courseType: CourseType = CourseType.STUDENT,
46
46
  lang = s.lang,
47
+ options: CourseListOptions = {},
47
48
  ): Promise<CourseInfo[]> {
48
49
  const json = await (await s.fetchWithToken(URLS.LEARN_COURSE_LIST(semesterID, courseType, lang))).json();
49
50
  if (json.message !== 'success' || !Array.isArray(json.resultList)) {
@@ -56,11 +57,14 @@ export async function getCourseList(
56
57
 
57
58
  return Promise.all(
58
59
  result.map(async (c) => {
59
- let timeAndLocation: string[] = [];
60
- try {
61
- // see https://github.com/Harry-Chen/Learn-Helper/issues/145
62
- timeAndLocation = await (await s.fetchWithToken(URLS.LEARN_COURSE_TIME_LOCATION(c.wlkcid))).json();
63
- } catch (e) {}
60
+ let timeAndLocation: string[] | undefined;
61
+ if (options.timeAndLocation) {
62
+ try {
63
+ timeAndLocation = await getCourseTimeAndLocation(s, c.wlkcid);
64
+ } catch {
65
+ timeAndLocation = [];
66
+ }
67
+ }
64
68
  return {
65
69
  id: c.wlkcid,
66
70
  name: decodeHTML(c.zywkcm),
@@ -78,6 +82,16 @@ export async function getCourseList(
78
82
  );
79
83
  }
80
84
 
85
+ /** get the time and location of one course (1 request) */
86
+ export async function getCourseTimeAndLocation(s: Session, courseID: string): Promise<string[]> {
87
+ // see https://github.com/Harry-Chen/Learn-Helper/issues/145
88
+ const json = await (await s.fetchWithToken(URLS.LEARN_COURSE_TIME_LOCATION(courseID))).json();
89
+ if (!Array.isArray(json)) {
90
+ throw { reason: FailReason.INVALID_RESPONSE, extra: json } as ApiError;
91
+ }
92
+ return json as string[];
93
+ }
94
+
81
95
  export async function sortCourses(s: Session, courseIDs: string[]): Promise<void> {
82
96
  const json = await (
83
97
  await s.fetchWithToken(URLS.LEARN_SORT_COURSES, {
package/src/homework.ts CHANGED
@@ -9,6 +9,7 @@ import type {
9
9
  ApiError,
10
10
  ExcellentHomework,
11
11
  Homework,
12
+ HomeworkListOptions,
12
13
  HomeworkTA,
13
14
  IExcellentHomework,
14
15
  IHomework,
@@ -19,12 +20,20 @@ import type {
19
20
  } from './types.ts';
20
21
  import { ContentType, CourseType, FailReason } from './types.ts';
21
22
  import * as URLS from './urls.ts';
22
- import { GRADE_LEVEL_MAP, decodeHTML, trimAndDefine } from './utils.ts';
23
+ import { GRADE_LEVEL_MAP, decodeHTML, isSelected, trimAndDefine } from './utils.ts';
23
24
 
24
- /** Get all homeworks (课程作业) of the specified course. */
25
+ /**
26
+ * Get all homeworks (课程作业) of the specified course: 3 status lists and the excellent homework list.
27
+ * Details (page + description) only for the homework `options.details` selects.
28
+ */
25
29
  export function getHomeworkList(s: Session, courseID: string): Promise<Homework[]>;
26
30
 
27
- export function getHomeworkList(s: Session, courseID: string, courseType: CourseType.STUDENT): Promise<Homework[]>;
31
+ export function getHomeworkList(
32
+ s: Session,
33
+ courseID: string,
34
+ courseType: CourseType.STUDENT,
35
+ options?: HomeworkListOptions,
36
+ ): Promise<Homework[]>;
28
37
 
29
38
  export function getHomeworkList(s: Session, courseID: string, courseType: CourseType.TEACHER): Promise<HomeworkTA[]>;
30
39
 
@@ -32,6 +41,7 @@ export async function getHomeworkList(
32
41
  s: Session,
33
42
  courseID: string,
34
43
  courseType: CourseType = CourseType.STUDENT,
44
+ options: HomeworkListOptions = {},
35
45
  ): Promise<Homework[] | HomeworkTA[]> {
36
46
  if (courseType === CourseType.TEACHER) {
37
47
  const json = await (
@@ -70,9 +80,19 @@ export async function getHomeworkList(
70
80
  }) satisfies HomeworkTA,
71
81
  );
72
82
  } else {
83
+ const [lists, excellentHomeworkListByHomework] = await Promise.all([
84
+ Promise.all(
85
+ URLS.LEARN_HOMEWORK_LIST_SOURCE.map((source) => getHomeworkListAtUrl(s, courseID, source.url, source.status)),
86
+ ),
87
+ // Don't block the whole process if excellent homework list cannot be fetched
88
+ getExcellentHomeworkListByHomework(s, courseID).catch((): { [id: string]: ExcellentHomework[] } => ({})),
89
+ ]);
73
90
  return Promise.all(
74
- URLS.LEARN_HOMEWORK_LIST_SOURCE.map((source) => getHomeworkListAtUrl(s, courseID, source.url, source.status)),
75
- ).then((r) => r.flat());
91
+ lists.flat().map(async (h) => {
92
+ const homework: Homework = { ...h, excellentHomeworkList: excellentHomeworkListByHomework[h.baseId] };
93
+ return isSelected(options.details, homework) ? { ...homework, ...(await getHomeworkDetail(s, h)) } : homework;
94
+ }),
95
+ );
76
96
  }
77
97
  }
78
98
 
@@ -81,7 +101,7 @@ async function getHomeworkListAtUrl(
81
101
  courseID: string,
82
102
  url: string,
83
103
  status: IHomeworkStatus,
84
- ): Promise<Homework[]> {
104
+ ): Promise<IHomework[]> {
85
105
  const json = await (
86
106
  await s.fetchWithToken(url, {
87
107
  method: 'POST',
@@ -97,50 +117,31 @@ async function getHomeworkListAtUrl(
97
117
 
98
118
  const result = (json.object?.aaData ?? []) as any[];
99
119
 
100
- let excellentHomeworkListByHomework: { [id: string]: ExcellentHomework[] } = {};
101
- try {
102
- excellentHomeworkListByHomework = await getExcellentHomeworkListByHomework(s, courseID);
103
- } catch (e) {
104
- // Don't block the whole process if excellent homework list cannot be fetched
105
- }
106
-
107
- return Promise.all(
108
- result
109
- .map(
110
- (h) =>
111
- ({
112
- id: h.xszyid,
113
- studentHomeworkId: h.xszyid,
114
- baseId: h.zyid,
115
- title: decodeHTML(h.bt),
116
- url: URLS.LEARN_HOMEWORK_PAGE(h.wlkcid, h.xszyid),
117
- deadline: h.jzsj,
118
- lateSubmissionDeadline: h.bjjzsj ? h.bjjzsj : undefined,
119
- isLateSubmission: h.sfbj === YES,
120
- completionType: h.zywcfs,
121
- submissionType: h.zytjfs,
122
- submitUrl: URLS.LEARN_HOMEWORK_SUBMIT_PAGE(h.wlkcid, h.xszyid),
123
- submitTime: h.scsj === null ? undefined : h.scsj,
124
- grade: h.cj === null ? undefined : h.cj,
125
- gradeLevel: GRADE_LEVEL_MAP.get(h.cj),
126
- graderName: trimAndDefine(h.jsm),
127
- gradeContent: trimAndDefine(h.pynr),
128
- gradeTime: h.pysj === null ? undefined : h.pysj,
129
- isFavorite: h.sfsc === YES,
130
- favoriteTime: h.scsj === null || h.sfsc !== YES ? undefined : h.scsj,
131
- comment: h.bznr ?? undefined,
132
- excellentHomeworkList: excellentHomeworkListByHomework[h.zyid],
133
- ...status,
134
- }) satisfies IHomework,
135
- )
136
- .map(
137
- async (h) =>
138
- ({
139
- ...h,
140
- ...(await parseHomeworkAtUrl(s, h.url)),
141
- ...(await getHomeworkDetail(s, h.baseId)),
142
- }) satisfies Homework,
143
- ),
120
+ return result.map(
121
+ (h) =>
122
+ ({
123
+ id: h.xszyid,
124
+ studentHomeworkId: h.xszyid,
125
+ baseId: h.zyid,
126
+ title: decodeHTML(h.bt),
127
+ url: URLS.LEARN_HOMEWORK_PAGE(h.wlkcid, h.xszyid),
128
+ deadline: h.jzsj,
129
+ lateSubmissionDeadline: h.bjjzsj ? h.bjjzsj : undefined,
130
+ isLateSubmission: h.sfbj === YES,
131
+ completionType: h.zywcfs,
132
+ submissionType: h.zytjfs,
133
+ submitUrl: URLS.LEARN_HOMEWORK_SUBMIT_PAGE(h.wlkcid, h.xszyid),
134
+ submitTime: h.scsj === null ? undefined : h.scsj,
135
+ grade: h.cj === null ? undefined : h.cj,
136
+ gradeLevel: GRADE_LEVEL_MAP.get(h.cj),
137
+ graderName: trimAndDefine(h.jsm),
138
+ gradeContent: trimAndDefine(h.pynr),
139
+ gradeTime: h.pysj === null ? undefined : h.pysj,
140
+ isFavorite: h.sfsc === YES,
141
+ favoriteTime: h.scsj === null || h.sfsc !== YES ? undefined : h.scsj,
142
+ comment: h.bznr ?? undefined,
143
+ ...status,
144
+ }) satisfies IHomework,
144
145
  );
145
146
  }
146
147
 
@@ -163,40 +164,29 @@ async function getExcellentHomeworkListByHomework(
163
164
 
164
165
  const result = (json.object?.aaData ?? []) as any[];
165
166
 
166
- return (
167
- await Promise.all(
168
- result
169
- .map(
170
- (h) =>
171
- ({
172
- id: h.xszyid,
173
- baseId: h.zyid,
174
- title: decodeHTML(h.bt),
175
- url: URLS.LEARN_HOMEWORK_EXCELLENT_PAGE(h.wlkcid, h.xszyid),
176
- completionType: h.zywcfs,
177
- author: {
178
- id: h.cy?.split(' ')?.[0],
179
- name: h.cy?.split(' ')?.[1],
180
- anonymous: h.sfzm === YES,
181
- },
182
- }) satisfies IExcellentHomework,
183
- )
184
- .map(
185
- async (h) =>
186
- ({
187
- ...h,
188
- ...(await parseHomeworkAtUrl(s, h.url)),
189
- ...(await getHomeworkDetail(s, h.baseId)),
190
- }) satisfies ExcellentHomework,
191
- ),
167
+ return result
168
+ .map(
169
+ (h) =>
170
+ ({
171
+ id: h.xszyid,
172
+ baseId: h.zyid,
173
+ title: decodeHTML(h.bt),
174
+ url: URLS.LEARN_HOMEWORK_EXCELLENT_PAGE(h.wlkcid, h.xszyid),
175
+ completionType: h.zywcfs,
176
+ author: {
177
+ id: h.cy?.split(' ')?.[0],
178
+ name: h.cy?.split(' ')?.[1],
179
+ anonymous: h.sfzm === YES,
180
+ },
181
+ }) satisfies IExcellentHomework,
192
182
  )
193
- ).reduce<{ [id: string]: ExcellentHomework[] }>((acc, cur) => {
194
- if (!acc[cur.baseId]) {
195
- acc[cur.baseId] = [];
196
- }
197
- acc[cur.baseId].push(cur);
198
- return acc;
199
- }, {});
183
+ .reduce<{ [id: string]: ExcellentHomework[] }>((acc, cur) => {
184
+ if (!acc[cur.baseId]) {
185
+ acc[cur.baseId] = [];
186
+ }
187
+ acc[cur.baseId].push(cur);
188
+ return acc;
189
+ }, {});
200
190
  }
201
191
 
202
192
  async function parseHomeworkAtUrl(s: Session, url: string): Promise<IHomeworkDetail> {
@@ -216,7 +206,22 @@ async function parseHomeworkAtUrl(s: Session, url: string): Promise<IHomeworkDet
216
206
  };
217
207
  }
218
208
 
219
- async function getHomeworkDetail(s: Session, baseId: string): Promise<IHomeworkDetail> {
209
+ /**
210
+ * Get the detail of one homework or excellent homework: its page (answer, submitted content, attachments) and the
211
+ * description JSON (which wins for `description`). 2 requests.
212
+ */
213
+ export async function getHomeworkDetail(
214
+ s: Session,
215
+ homework: Pick<IHomework | IExcellentHomework, 'url' | 'baseId'>,
216
+ ): Promise<IHomeworkDetail> {
217
+ const [page, description] = await Promise.all([
218
+ parseHomeworkAtUrl(s, homework.url),
219
+ getHomeworkDescription(s, homework.baseId),
220
+ ]);
221
+ return { ...page, ...description };
222
+ }
223
+
224
+ async function getHomeworkDescription(s: Session, baseId: string): Promise<IHomeworkDetail> {
220
225
  const json = await (
221
226
  await s.fetchWithToken(URLS.LEARN_HOMEWORK_DETAIL, {
222
227
  method: 'POST',
package/src/index.ts CHANGED
@@ -10,8 +10,16 @@ import * as notices from './notices.ts';
10
10
  import * as questionnaires from './questionnaires.ts';
11
11
  import { Session } from './request.ts';
12
12
  import type {
13
+ AllContentsOptions,
14
+ AllContentsResult,
13
15
  CalendarOptions,
14
16
  CalendarResult,
17
+ CourseListOptions,
18
+ ExcellentHomework,
19
+ HomeworkListOptions,
20
+ IHomeworkDetail,
21
+ NotificationListOptions,
22
+ RemoteFile,
15
23
  CommentItem,
16
24
  CourseInfo,
17
25
  Discussion,
@@ -31,6 +39,7 @@ import type {
31
39
  ContentType,
32
40
  } from './types.ts';
33
41
  import { CourseType } from './types.ts';
42
+ import * as URLS from './urls.ts';
34
43
  import * as user from './user.ts';
35
44
 
36
45
  export { addCSRFTokenToUrl } from './request.ts';
@@ -42,7 +51,7 @@ export class Learn2018Helper {
42
51
 
43
52
  /** you can provide a CookieJar and / or CredentialProvider in the configuration */
44
53
  constructor(config?: HelperConfig) {
45
- this.#session = new Session(config, () => this.login());
54
+ this.#session = new Session(config, () => auth.login(this.#session));
46
55
  }
47
56
 
48
57
  /** whether preview URLs open the first page only (`HelperConfig.generatePreviewUrlForFirstPage`) */
@@ -78,7 +87,10 @@ export class Learn2018Helper {
78
87
  return auth.getRoamingTicket(this.#session, username, password, fingerPrint, fingerGenPrint, fingerGenPrint3);
79
88
  }
80
89
 
81
- /** login is necessary if you do not provide a `CredentialProvider` */
90
+ /**
91
+ * Login is necessary if you do not provide a `CredentialProvider`.
92
+ * Without credentials it uses the provider, and concurrent calls share one SSO login.
93
+ */
82
94
  public async login(
83
95
  username?: string,
84
96
  password?: string,
@@ -86,9 +98,19 @@ export class Learn2018Helper {
86
98
  fingerGenPrint?: string,
87
99
  fingerGenPrint3?: string,
88
100
  ): Promise<void> {
101
+ if (!username || !password || !fingerPrint) return this.#session.relogin();
89
102
  return auth.login(this.#session, username, password, fingerPrint, fingerGenPrint, fingerGenPrint3);
90
103
  }
91
104
 
105
+ /**
106
+ * Make sure the session is usable without a full SSO login when possible: with a CSRF token (from an earlier login
107
+ * or `setCSRFToken`), make one cheap request and log in again only if the session has expired; without one, log in.
108
+ * Use it when resuming an app instead of `login()`.
109
+ */
110
+ public async ensureSession(): Promise<void> {
111
+ return this.#session.ensureSession(URLS.LEARN_CURRENT_SEMESTER());
112
+ }
113
+
92
114
  /** logout (to make everyone happy) */
93
115
  public async logout(): Promise<void> {
94
116
  return auth.logout(this.#session);
@@ -116,34 +138,56 @@ export class Learn2018Helper {
116
138
  return courses.getCurrentSemester(this.#session);
117
139
  }
118
140
 
119
- /** get all courses in the specified semester */
141
+ /**
142
+ * Get all courses in the specified semester.
143
+ * `timeAndLocation` is only fetched (one request per course) with `options.timeAndLocation`.
144
+ */
120
145
  public async getCourseList(
121
146
  semesterID: string,
122
147
  courseType: CourseType = CourseType.STUDENT,
123
148
  lang: Language = this.#session.lang,
149
+ options?: CourseListOptions,
124
150
  ): Promise<CourseInfo[]> {
125
- return courses.getCourseList(this.#session, semesterID, courseType, lang);
151
+ return courses.getCourseList(this.#session, semesterID, courseType, lang, options);
152
+ }
153
+
154
+ /** Get the time and location of one course. */
155
+ public async getCourseTimeAndLocation(courseID: string): Promise<string[]> {
156
+ return courses.getCourseTimeAndLocation(this.#session, courseID);
126
157
  }
127
158
 
128
159
  /**
129
160
  * Get certain type of content of all specified courses.
130
- * It actually wraps around other `getXXX` functions. You can ignore the failure caused by certain courses.
161
+ * It wraps around the `getXXX` list functions; a course that fails is reported in `errors` instead of failing
162
+ * the rest. `options.details` is passed on as homework `details` or notification `attachments`.
131
163
  */
132
164
  public async getAllContents<T extends ContentType>(
133
165
  courseIDs: string[],
134
166
  type: T,
135
- courseType: CourseType = CourseType.STUDENT,
136
- allowFailure = false,
137
- ) {
138
- return contents.getAllContents(this.#session, courseIDs, type, courseType, allowFailure);
167
+ options?: AllContentsOptions<T>,
168
+ ): Promise<AllContentsResult<T>> {
169
+ return contents.getAllContents(this.#session, courseIDs, type, options);
139
170
  }
140
171
 
141
- /** Get all notifications (课程公告) of the specified course. */
172
+ /**
173
+ * Get all notifications (课程公告) of the specified course.
174
+ * Attachments are only fetched (one request per notice) for the notices `options.attachments` selects;
175
+ * use `getNotificationAttachment` for the others.
176
+ */
142
177
  public async getNotificationList(
143
178
  courseID: string,
144
179
  courseType: CourseType = CourseType.STUDENT,
180
+ options?: NotificationListOptions,
145
181
  ): Promise<Notification[]> {
146
- return notices.getNotificationList(this.#session, courseID, courseType);
182
+ return notices.getNotificationList(this.#session, courseID, courseType, options);
183
+ }
184
+
185
+ /** Get the attachment of a notice (one request), `undefined` if it has none. */
186
+ public async getNotificationAttachment(
187
+ notification: Pick<Notification, 'url' | 'attachmentName'>,
188
+ courseType: CourseType = CourseType.STUDENT,
189
+ ): Promise<RemoteFile | undefined> {
190
+ return notices.getNotificationAttachment(this.#session, notification, courseType);
147
191
  }
148
192
 
149
193
  /** Get all files (课程文件) of the specified course. */
@@ -171,17 +215,36 @@ export class Learn2018Helper {
171
215
  return files.getFileListByCategory(this.#session, courseID, categoryId, courseType);
172
216
  }
173
217
 
174
- /** Get all homeworks (课程作业) of the specified course. */
218
+ /**
219
+ * Get all homeworks (课程作业) of the specified course, with the excellent homework list (without details).
220
+ * Details (page + description, two requests per homework) are only fetched for the homework `options.details`
221
+ * selects; use `getHomeworkDetail` for the others.
222
+ */
175
223
  public async getHomeworkList(courseID: string): Promise<Homework[]>;
176
- public async getHomeworkList(courseID: string, courseType: CourseType.STUDENT): Promise<Homework[]>;
224
+ public async getHomeworkList(
225
+ courseID: string,
226
+ courseType: CourseType.STUDENT,
227
+ options?: HomeworkListOptions,
228
+ ): Promise<Homework[]>;
177
229
  public async getHomeworkList(courseID: string, courseType: CourseType.TEACHER): Promise<HomeworkTA[]>;
178
230
  public async getHomeworkList(
179
231
  courseID: string,
180
232
  courseType: CourseType = CourseType.STUDENT,
233
+ options?: HomeworkListOptions,
181
234
  ): Promise<Homework[] | HomeworkTA[]> {
182
235
  return courseType === CourseType.TEACHER
183
236
  ? homework.getHomeworkList(this.#session, courseID, CourseType.TEACHER)
184
- : homework.getHomeworkList(this.#session, courseID, CourseType.STUDENT);
237
+ : homework.getHomeworkList(this.#session, courseID, CourseType.STUDENT, options);
238
+ }
239
+
240
+ /** Get the detail (page content, attachments and description) of one homework. */
241
+ public async getHomeworkDetail(item: Pick<Homework, 'url' | 'baseId'>): Promise<IHomeworkDetail> {
242
+ return homework.getHomeworkDetail(this.#session, item);
243
+ }
244
+
245
+ /** Get the detail (page content, attachments and description) of one excellent homework. */
246
+ public async getExcellentHomeworkDetail(item: Pick<ExcellentHomework, 'url' | 'baseId'>): Promise<IHomeworkDetail> {
247
+ return homework.getHomeworkDetail(this.#session, item);
185
248
  }
186
249
 
187
250
  /** Get all discussions (课程讨论) of the specified course. */