chukyo-sdk 0.1.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.
- package/LICENSE +21 -0
- package/README.md +227 -0
- package/dist/cjs/albo/client.js +133 -0
- package/dist/cjs/albo/index.js +55 -0
- package/dist/cjs/albo/parser/albo.js +110 -0
- package/dist/cjs/albo/types/albo.js +351 -0
- package/dist/cjs/albo/types/alboCalendar.js +51 -0
- package/dist/cjs/albo/types/alboCommon.js +55 -0
- package/dist/cjs/albo/types/alboInformation.js +136 -0
- package/dist/cjs/albo/types/alboMenu.js +92 -0
- package/dist/cjs/albo/types/alboQuestionnaire.js +229 -0
- package/dist/cjs/albo/types/alboSharedItem.js +137 -0
- package/dist/cjs/albo/types/alboSystem.js +103 -0
- package/dist/cjs/albo/types/alboUniversalForm.js +51 -0
- package/dist/cjs/common/dom.js +137 -0
- package/dist/cjs/common/utils.js +29 -0
- package/dist/cjs/constants.js +127 -0
- package/dist/cjs/core/request.js +39 -0
- package/dist/cjs/cubics/client.js +49 -0
- package/dist/cjs/cubics/index.js +22 -0
- package/dist/cjs/cubics/parser/cubics.js +103 -0
- package/dist/cjs/cubics/types/cubics.js +90 -0
- package/dist/cjs/errors.js +55 -0
- package/dist/cjs/index.js +50 -0
- package/dist/cjs/manabo/client.js +135 -0
- package/dist/cjs/manabo/index.js +44 -0
- package/dist/cjs/manabo/parser/manaboClass.js +386 -0
- package/dist/cjs/manabo/parser/manaboEntry.js +38 -0
- package/dist/cjs/manabo/parser/manaboMail.js +153 -0
- package/dist/cjs/manabo/parser/manaboNews.js +26 -0
- package/dist/cjs/manabo/parser/manaboTimetable.js +93 -0
- package/dist/cjs/manabo/types/manaboClass.js +223 -0
- package/dist/cjs/manabo/types/manaboEntry.js +43 -0
- package/dist/cjs/manabo/types/manaboMail.js +117 -0
- package/dist/cjs/manabo/types/manaboNews.js +20 -0
- package/dist/cjs/manabo/types/manaboTimetable.js +79 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/shib/builder.js +239 -0
- package/dist/cjs/shib/index.js +32 -0
- package/dist/cjs/shib/parser/shibLogin.js +138 -0
- package/dist/cjs/shib/parser/shibUser.js +51 -0
- package/dist/cjs/shib/types/common.js +2 -0
- package/dist/cjs/shib/types/shibLogin.js +92 -0
- package/dist/cjs/shib/types/shibUser.js +44 -0
- package/dist/cjs/transports/fetch.js +84 -0
- package/dist/cjs/types.js +9 -0
- package/dist/esm/albo/client.d.ts +80 -0
- package/dist/esm/albo/client.d.ts.map +1 -0
- package/dist/esm/albo/client.js +129 -0
- package/dist/esm/albo/index.d.ts +12 -0
- package/dist/esm/albo/index.d.ts.map +1 -0
- package/dist/esm/albo/index.js +11 -0
- package/dist/esm/albo/parser/albo.d.ts +69 -0
- package/dist/esm/albo/parser/albo.d.ts.map +1 -0
- package/dist/esm/albo/parser/albo.js +84 -0
- package/dist/esm/albo/types/albo.d.ts +460 -0
- package/dist/esm/albo/types/albo.d.ts.map +1 -0
- package/dist/esm/albo/types/albo.js +348 -0
- package/dist/esm/albo/types/alboCalendar.d.ts +58 -0
- package/dist/esm/albo/types/alboCalendar.d.ts.map +1 -0
- package/dist/esm/albo/types/alboCalendar.js +48 -0
- package/dist/esm/albo/types/alboCommon.d.ts +52 -0
- package/dist/esm/albo/types/alboCommon.d.ts.map +1 -0
- package/dist/esm/albo/types/alboCommon.js +51 -0
- package/dist/esm/albo/types/alboInformation.d.ts +214 -0
- package/dist/esm/albo/types/alboInformation.d.ts.map +1 -0
- package/dist/esm/albo/types/alboInformation.js +133 -0
- package/dist/esm/albo/types/alboMenu.d.ts +114 -0
- package/dist/esm/albo/types/alboMenu.d.ts.map +1 -0
- package/dist/esm/albo/types/alboMenu.js +89 -0
- package/dist/esm/albo/types/alboQuestionnaire.d.ts +442 -0
- package/dist/esm/albo/types/alboQuestionnaire.d.ts.map +1 -0
- package/dist/esm/albo/types/alboQuestionnaire.js +226 -0
- package/dist/esm/albo/types/alboSharedItem.d.ts +205 -0
- package/dist/esm/albo/types/alboSharedItem.d.ts.map +1 -0
- package/dist/esm/albo/types/alboSharedItem.js +134 -0
- package/dist/esm/albo/types/alboSystem.d.ts +129 -0
- package/dist/esm/albo/types/alboSystem.d.ts.map +1 -0
- package/dist/esm/albo/types/alboSystem.js +100 -0
- package/dist/esm/albo/types/alboUniversalForm.d.ts +63 -0
- package/dist/esm/albo/types/alboUniversalForm.d.ts.map +1 -0
- package/dist/esm/albo/types/alboUniversalForm.js +48 -0
- package/dist/esm/common/dom.d.ts +35 -0
- package/dist/esm/common/dom.d.ts.map +1 -0
- package/dist/esm/common/dom.js +120 -0
- package/dist/esm/common/utils.d.ts +15 -0
- package/dist/esm/common/utils.d.ts.map +1 -0
- package/dist/esm/common/utils.js +22 -0
- package/dist/esm/constants.d.ts +113 -0
- package/dist/esm/constants.d.ts.map +1 -0
- package/dist/esm/constants.js +124 -0
- package/dist/esm/core/request.d.ts +29 -0
- package/dist/esm/core/request.d.ts.map +1 -0
- package/dist/esm/core/request.js +33 -0
- package/dist/esm/cubics/client.d.ts +13 -0
- package/dist/esm/cubics/client.d.ts.map +1 -0
- package/dist/esm/cubics/client.js +45 -0
- package/dist/esm/cubics/index.d.ts +4 -0
- package/dist/esm/cubics/index.d.ts.map +1 -0
- package/dist/esm/cubics/index.js +3 -0
- package/dist/esm/cubics/parser/cubics.d.ts +8 -0
- package/dist/esm/cubics/parser/cubics.d.ts.map +1 -0
- package/dist/esm/cubics/parser/cubics.js +99 -0
- package/dist/esm/cubics/types/cubics.d.ts +94 -0
- package/dist/esm/cubics/types/cubics.d.ts.map +1 -0
- package/dist/esm/cubics/types/cubics.js +87 -0
- package/dist/esm/errors.d.ts +46 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +46 -0
- package/dist/esm/index.d.ts +19 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +25 -0
- package/dist/esm/manabo/client.d.ts +75 -0
- package/dist/esm/manabo/client.d.ts.map +1 -0
- package/dist/esm/manabo/client.js +131 -0
- package/dist/esm/manabo/index.d.ts +12 -0
- package/dist/esm/manabo/index.d.ts.map +1 -0
- package/dist/esm/manabo/index.js +11 -0
- package/dist/esm/manabo/parser/manaboClass.d.ts +9 -0
- package/dist/esm/manabo/parser/manaboClass.d.ts.map +1 -0
- package/dist/esm/manabo/parser/manaboClass.js +377 -0
- package/dist/esm/manabo/parser/manaboEntry.d.ts +8 -0
- package/dist/esm/manabo/parser/manaboEntry.d.ts.map +1 -0
- package/dist/esm/manabo/parser/manaboEntry.js +33 -0
- package/dist/esm/manabo/parser/manaboMail.d.ts +8 -0
- package/dist/esm/manabo/parser/manaboMail.d.ts.map +1 -0
- package/dist/esm/manabo/parser/manaboMail.js +145 -0
- package/dist/esm/manabo/parser/manaboNews.d.ts +7 -0
- package/dist/esm/manabo/parser/manaboNews.d.ts.map +1 -0
- package/dist/esm/manabo/parser/manaboNews.js +22 -0
- package/dist/esm/manabo/parser/manaboTimetable.d.ts +4 -0
- package/dist/esm/manabo/parser/manaboTimetable.d.ts.map +1 -0
- package/dist/esm/manabo/parser/manaboTimetable.js +89 -0
- package/dist/esm/manabo/types/manaboClass.d.ts +294 -0
- package/dist/esm/manabo/types/manaboClass.d.ts.map +1 -0
- package/dist/esm/manabo/types/manaboClass.js +220 -0
- package/dist/esm/manabo/types/manaboEntry.d.ts +24 -0
- package/dist/esm/manabo/types/manaboEntry.d.ts.map +1 -0
- package/dist/esm/manabo/types/manaboEntry.js +40 -0
- package/dist/esm/manabo/types/manaboMail.d.ts +103 -0
- package/dist/esm/manabo/types/manaboMail.d.ts.map +1 -0
- package/dist/esm/manabo/types/manaboMail.js +114 -0
- package/dist/esm/manabo/types/manaboNews.d.ts +15 -0
- package/dist/esm/manabo/types/manaboNews.d.ts.map +1 -0
- package/dist/esm/manabo/types/manaboNews.js +17 -0
- package/dist/esm/manabo/types/manaboTimetable.d.ts +88 -0
- package/dist/esm/manabo/types/manaboTimetable.d.ts.map +1 -0
- package/dist/esm/manabo/types/manaboTimetable.js +76 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/shib/builder.d.ts +154 -0
- package/dist/esm/shib/builder.d.ts.map +1 -0
- package/dist/esm/shib/builder.js +212 -0
- package/dist/esm/shib/index.d.ts +15 -0
- package/dist/esm/shib/index.d.ts.map +1 -0
- package/dist/esm/shib/index.js +14 -0
- package/dist/esm/shib/parser/shibLogin.d.ts +47 -0
- package/dist/esm/shib/parser/shibLogin.d.ts.map +1 -0
- package/dist/esm/shib/parser/shibLogin.js +127 -0
- package/dist/esm/shib/parser/shibUser.d.ts +11 -0
- package/dist/esm/shib/parser/shibUser.d.ts.map +1 -0
- package/dist/esm/shib/parser/shibUser.js +46 -0
- package/dist/esm/shib/types/common.d.ts +20 -0
- package/dist/esm/shib/types/common.d.ts.map +1 -0
- package/dist/esm/shib/types/common.js +1 -0
- package/dist/esm/shib/types/shibLogin.d.ts +62 -0
- package/dist/esm/shib/types/shibLogin.d.ts.map +1 -0
- package/dist/esm/shib/types/shibLogin.js +89 -0
- package/dist/esm/shib/types/shibUser.d.ts +36 -0
- package/dist/esm/shib/types/shibUser.d.ts.map +1 -0
- package/dist/esm/shib/types/shibUser.js +41 -0
- package/dist/esm/transports/fetch.d.ts +36 -0
- package/dist/esm/transports/fetch.d.ts.map +1 -0
- package/dist/esm/transports/fetch.js +80 -0
- package/dist/esm/types.d.ts +71 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +8 -0
- package/package.json +72 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MaNaBo クライアント(Glexa ベース)。API は無く、トップページへの POST
|
|
3
|
+
* `action=glexa_ajax_*` で HTML 断片を取得してパースする。
|
|
4
|
+
*
|
|
5
|
+
* ※ レート制限(リクエスト間隔の間引き)は SDK では行わない。必要な場合は
|
|
6
|
+
* 利用側が Transport 内で適用すること(例: umebo は manabo ホスト宛のみ 500ms 間隔)。
|
|
7
|
+
*/
|
|
8
|
+
import { MANABO_URLS, SERVICES } from "../constants";
|
|
9
|
+
import { portalRequestText, unwrap } from "../core/request";
|
|
10
|
+
import { parseManaboClassContent, parseManaboClassDirectory, parseManaboClassEntry, parseManaboClassNews, parseManaboClassSyllabus, } from "./parser/manaboClass";
|
|
11
|
+
import { parseManaboEntryForm, parseManaboEntryResponse } from "./parser/manaboEntry";
|
|
12
|
+
import { parseManaboMailMember, parseManaboMailView, parseManaboReceivedMail, parseManaboSentMail } from "./parser/manaboMail";
|
|
13
|
+
import { parseManaboTimetable } from "./parser/manaboTimetable";
|
|
14
|
+
export class ManaboClient {
|
|
15
|
+
ctx;
|
|
16
|
+
constructor(ctx) {
|
|
17
|
+
this.ctx = ctx;
|
|
18
|
+
}
|
|
19
|
+
fetchText(path, init) {
|
|
20
|
+
return portalRequestText(this.ctx, SERVICES.manabo, {
|
|
21
|
+
method: init?.method ?? "GET",
|
|
22
|
+
url: `${MANABO_URLS.base}${path}`,
|
|
23
|
+
...(init?.body != null ? { body: init.body } : {}),
|
|
24
|
+
...(init?.headers ? { headers: init.headers } : {}),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/** トップページに `action=...` を POST して HTML 断片を得る */
|
|
28
|
+
postAction(params) {
|
|
29
|
+
return this.fetchText("/", {
|
|
30
|
+
method: "POST",
|
|
31
|
+
body: new URLSearchParams(params).toString(),
|
|
32
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/** 時間割を取得する */
|
|
36
|
+
async getTimetable() {
|
|
37
|
+
return unwrap(parseManaboTimetable(await this.postAction({ action: "glexa_ajax_timetable_view" })));
|
|
38
|
+
}
|
|
39
|
+
/** 授業のお知らせ一覧を取得する */
|
|
40
|
+
async getClassNews(classId) {
|
|
41
|
+
return unwrap(parseManaboClassNews(await this.postAction({ class_id: classId, directory_id: "0", action: "glexa_ajax_class_news_list" })));
|
|
42
|
+
}
|
|
43
|
+
/** 授業のシラバスを取得する */
|
|
44
|
+
async getClassSyllabus(classId) {
|
|
45
|
+
return unwrap(parseManaboClassSyllabus(await this.postAction({ class_id: classId, action: "glexa_ajax_class_syllabus_view" })));
|
|
46
|
+
}
|
|
47
|
+
/** 授業の出席表(各回の出欠一覧)を取得する */
|
|
48
|
+
async getClassEntry(classId) {
|
|
49
|
+
return unwrap(parseManaboClassEntry(await this.fetchText(`/?class_id=${classId}&action=glexa_modal_entry_view&_=${Date.now()}`)));
|
|
50
|
+
}
|
|
51
|
+
/** 授業のディレクトリ(週・回)一覧を取得する */
|
|
52
|
+
async getClassDirectory(classId) {
|
|
53
|
+
return unwrap(parseManaboClassDirectory(await this.postAction({ class_id: classId, directory_id: "0", action: "glexa_ajax_class_directory_list" })));
|
|
54
|
+
}
|
|
55
|
+
/** 授業のディレクトリ配下の教材一覧を取得する */
|
|
56
|
+
async getClassContent(classId, directoryId, viewType) {
|
|
57
|
+
return unwrap(parseManaboClassContent(await this.postAction({
|
|
58
|
+
class_id: classId,
|
|
59
|
+
directory_id: directoryId,
|
|
60
|
+
action: "glexa_ajax_class_content_list",
|
|
61
|
+
...(viewType ? { view_type: viewType } : {}),
|
|
62
|
+
})));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 出席受付モーダル(出欠カード)のフォームを取得する。
|
|
66
|
+
* 返り値の `requiresCode` が `true` なら出席コード(パスワード)が必要で、
|
|
67
|
+
* {@link submitEntry} の `code` に教員指示のコードを渡す。`false`(パスワードなし授業)
|
|
68
|
+
* なら `code` を省略してそのまま送信できる。
|
|
69
|
+
*/
|
|
70
|
+
async getEntryForm(classId) {
|
|
71
|
+
return unwrap(parseManaboEntryForm(await this.fetchText(`/?class_id=${classId}&action=glexa_modal_entry_form&_=${Date.now()}`)));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 出席登録を送信する({@link getEntryForm} で取得した entryId / uniqid を渡す)。
|
|
75
|
+
* 出席コード(パスワード)必須の授業では `code` に教員指示のコードを渡す。
|
|
76
|
+
* パスワードなし授業では `code` を省略する。
|
|
77
|
+
*/
|
|
78
|
+
async submitEntry(params) {
|
|
79
|
+
const query = new URLSearchParams({
|
|
80
|
+
action: "glexa_modal_entry_form_accept",
|
|
81
|
+
class_id: params.classId,
|
|
82
|
+
directory_id: params.directoryId,
|
|
83
|
+
entry_id: params.entryId,
|
|
84
|
+
uniqid: params.uniqid,
|
|
85
|
+
...(params.code != null ? { code: params.code } : {}),
|
|
86
|
+
_: String(Date.now()),
|
|
87
|
+
});
|
|
88
|
+
return unwrap(parseManaboEntryResponse(await this.fetchText(`/?${query.toString()}`)));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 受信メール一覧を取得する。
|
|
92
|
+
* リクエスト形は glexa JS の `glexa.loadMailReceives(p, q, o, unread, start, end)` で確認済み。
|
|
93
|
+
* @param options.page ページ番号(1 始まり) / q 検索語 / order 並び順 / unreadOnly 未読のみ / startDate・endDate 期間(YYYY-MM-DD)
|
|
94
|
+
*/
|
|
95
|
+
async getReceivedMail(options = {}) {
|
|
96
|
+
return unwrap(parseManaboReceivedMail(await this.postAction({
|
|
97
|
+
action: "glexa_ajax_mail_receive_list",
|
|
98
|
+
...(options.page != null ? { p: String(options.page) } : {}),
|
|
99
|
+
...(options.q ? { q: options.q } : {}),
|
|
100
|
+
...(options.order ? { o: options.order } : {}),
|
|
101
|
+
...(options.unreadOnly ? { unread: "1" } : {}),
|
|
102
|
+
...(options.startDate ? { start_date: options.startDate } : {}),
|
|
103
|
+
...(options.endDate ? { end_date: options.endDate } : {}),
|
|
104
|
+
})));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 送信メール一覧を取得する。
|
|
108
|
+
* リクエスト形は glexa JS の `glexa.loadMailSends(p, q, o, start, end)` で確認済み。
|
|
109
|
+
*/
|
|
110
|
+
async getSentMail(options = {}) {
|
|
111
|
+
return unwrap(parseManaboSentMail(await this.postAction({
|
|
112
|
+
action: "glexa_ajax_mail_send_list",
|
|
113
|
+
...(options.page != null ? { p: String(options.page) } : {}),
|
|
114
|
+
...(options.q ? { q: options.q } : {}),
|
|
115
|
+
...(options.order ? { o: options.order } : {}),
|
|
116
|
+
...(options.startDate ? { start_date: options.startDate } : {}),
|
|
117
|
+
...(options.endDate ? { end_date: options.endDate } : {}),
|
|
118
|
+
})));
|
|
119
|
+
}
|
|
120
|
+
/** メール本文(閲覧モーダル)を取得する */
|
|
121
|
+
async getMailView(mailId) {
|
|
122
|
+
return unwrap(parseManaboMailView(await this.fetchText(`/?mail_id=${mailId}&action=glexa_modal_mail_view&_=${Date.now()}`)));
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* メール作成モーダルで宛先候補メンバーを検索する(`q` は氏名/学籍番号などの検索語)。
|
|
126
|
+
* リクエスト形は HAR 内の inline JS(`glexa.ajax({ action: 'glexa_modal_mail_ajax_member_list', params: { q } })`)で確認済み。
|
|
127
|
+
*/
|
|
128
|
+
async searchMailMembers(q) {
|
|
129
|
+
return unwrap(parseManaboMailMember(await this.postAction({ action: "glexa_modal_mail_ajax_member_list", q })));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { parseManaboTimetable } from "./parser/manaboTimetable";
|
|
2
|
+
export { parseManaboNews } from "./parser/manaboNews";
|
|
3
|
+
export { parseManaboClassDirectory, parseManaboClassContent, parseManaboClassEntry, parseManaboClassNews, parseManaboClassSyllabus, parseManaboClassQuizResult, } from "./parser/manaboClass";
|
|
4
|
+
export { parseManaboEntryForm, parseManaboEntryResponse } from "./parser/manaboEntry";
|
|
5
|
+
export { parseManaboReceivedMail, parseManaboSentMail, parseManaboMailView, parseManaboMailSend, parseManaboMailMember, } from "./parser/manaboMail";
|
|
6
|
+
export * from "./types/manaboTimetable";
|
|
7
|
+
export * from "./types/manaboNews";
|
|
8
|
+
export * from "./types/manaboClass";
|
|
9
|
+
export * from "./types/manaboEntry";
|
|
10
|
+
export * from "./types/manaboMail";
|
|
11
|
+
export { ManaboClient } from "./client";
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/manabo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EACH,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,wBAAwB,EACxB,0BAA0B,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,EACH,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { parseManaboTimetable } from "./parser/manaboTimetable";
|
|
2
|
+
export { parseManaboNews } from "./parser/manaboNews";
|
|
3
|
+
export { parseManaboClassDirectory, parseManaboClassContent, parseManaboClassEntry, parseManaboClassNews, parseManaboClassSyllabus, parseManaboClassQuizResult, } from "./parser/manaboClass";
|
|
4
|
+
export { parseManaboEntryForm, parseManaboEntryResponse } from "./parser/manaboEntry";
|
|
5
|
+
export { parseManaboReceivedMail, parseManaboSentMail, parseManaboMailView, parseManaboMailSend, parseManaboMailMember, } from "./parser/manaboMail";
|
|
6
|
+
export * from "./types/manaboTimetable";
|
|
7
|
+
export * from "./types/manaboNews";
|
|
8
|
+
export * from "./types/manaboClass";
|
|
9
|
+
export * from "./types/manaboEntry";
|
|
10
|
+
export * from "./types/manaboMail";
|
|
11
|
+
export { ManaboClient } from "./client";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ZodSafeParseResult } from "zod";
|
|
2
|
+
import { type ManaboClassContentDTO, type ManaboClassDirectoryDTO, type ManaboClassEntryDTO, type ManaboClassNewsDTO, type ManaboClassQuizResultDTO, type ManaboClassSyllabusDTO } from "../types/manaboClass";
|
|
3
|
+
export declare const parseManaboClassDirectory: (html: string) => ZodSafeParseResult<ManaboClassDirectoryDTO>;
|
|
4
|
+
export declare const parseManaboClassContent: (html: string) => ZodSafeParseResult<ManaboClassContentDTO>;
|
|
5
|
+
export declare const parseManaboClassEntry: (html: string) => ZodSafeParseResult<ManaboClassEntryDTO>;
|
|
6
|
+
export declare const parseManaboClassNews: (html: string) => ZodSafeParseResult<ManaboClassNewsDTO>;
|
|
7
|
+
export declare const parseManaboClassSyllabus: (html: string) => ZodSafeParseResult<ManaboClassSyllabusDTO>;
|
|
8
|
+
export declare const parseManaboClassQuizResult: (html: string) => ZodSafeParseResult<ManaboClassQuizResultDTO>;
|
|
9
|
+
//# sourceMappingURL=manaboClass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manaboClass.d.ts","sourceRoot":"","sources":["../../../../src/manabo/parser/manaboClass.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,KAAK,CAAC;AAc9C,OAAO,EAOH,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC9B,MAAM,sBAAsB,CAAC;AAa9B,eAAO,MAAM,yBAAyB,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,uBAAuB,CAelG,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,qBAAqB,CAwH9F,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,mBAAmB,CAiB1F,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,kBAAkB,CAWxF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,sBAAsB,CA+JhG,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,wBAAwB,CAyEpG,CAAC"}
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import { closest, getAttribute, getInnerHtml, getTextContent, isElement, loadDocument, matches, nextSiblingElement, queryAll, queryOne, } from "../../common/dom";
|
|
2
|
+
import { normalizeWhitespace } from "../../common/utils";
|
|
3
|
+
import { ManaboClassContentSchema, ManaboClassDirectorySchema, ManaboClassEntrySchema, ManaboClassNewsSchema, ManaboClassQuizResultSchema, ManaboClassSyllabusSchema, } from "../types/manaboClass";
|
|
4
|
+
const findNextMatchingSibling = (element, selector) => {
|
|
5
|
+
let next = nextSiblingElement(element);
|
|
6
|
+
while (next) {
|
|
7
|
+
if (matches(next, selector)) {
|
|
8
|
+
return next;
|
|
9
|
+
}
|
|
10
|
+
next = nextSiblingElement(next);
|
|
11
|
+
}
|
|
12
|
+
return null;
|
|
13
|
+
};
|
|
14
|
+
export const parseManaboClassDirectory = (html) => {
|
|
15
|
+
const document = loadDocument(html);
|
|
16
|
+
const classNode = queryOne(".class-top-directory .x-content-drop", document);
|
|
17
|
+
const classId = getAttribute(classNode, "class_id") ?? "";
|
|
18
|
+
const className = normalizeWhitespace(getTextContent(queryOne(".class-top-directory .span-class-name", document)));
|
|
19
|
+
const directories = queryAll(".div-panel-directory li[directory_id]", document)
|
|
20
|
+
.map((node) => {
|
|
21
|
+
const directoryId = getAttribute(node, "directory_id") ?? "";
|
|
22
|
+
const title = normalizeWhitespace(getTextContent(queryOne(".x-directory-name", node)));
|
|
23
|
+
return { directoryId, title };
|
|
24
|
+
})
|
|
25
|
+
.filter((directory) => directory.directoryId.length > 0 && directory.title.length > 0);
|
|
26
|
+
return ManaboClassDirectorySchema.safeParse({ classId, className, directories });
|
|
27
|
+
};
|
|
28
|
+
export const parseManaboClassContent = (html) => {
|
|
29
|
+
const document = loadDocument(html);
|
|
30
|
+
const extractDurations = (context) => {
|
|
31
|
+
const containers = queryAll(".div-small", context);
|
|
32
|
+
const durations = [];
|
|
33
|
+
containers.forEach((container) => {
|
|
34
|
+
const boldElements = queryAll("b", container);
|
|
35
|
+
boldElements.forEach((bold) => {
|
|
36
|
+
const label = normalizeWhitespace(getTextContent(bold));
|
|
37
|
+
const valueFragments = [];
|
|
38
|
+
let current = bold.next;
|
|
39
|
+
while (current) {
|
|
40
|
+
if (isElement(current) && current.name.toLowerCase() === "b") {
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
if (isElement(current)) {
|
|
44
|
+
const tagName = current.name.toLowerCase();
|
|
45
|
+
if (tagName === "br") {
|
|
46
|
+
valueFragments.push(" ");
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
valueFragments.push(getTextContent(current));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
valueFragments.push(getTextContent(current));
|
|
54
|
+
}
|
|
55
|
+
current = current.next;
|
|
56
|
+
}
|
|
57
|
+
const value = normalizeWhitespace(valueFragments.join(" "));
|
|
58
|
+
if (label.length > 0 || value.length > 0) {
|
|
59
|
+
durations.push({ label, value });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
return durations;
|
|
64
|
+
};
|
|
65
|
+
const contents = [];
|
|
66
|
+
const rows = queryAll(".table-class-content tbody tr", document);
|
|
67
|
+
rows.forEach((row) => {
|
|
68
|
+
if (matches(row, ".toggle-area")) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const cells = queryAll("td", row);
|
|
72
|
+
if (!cells.length) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const detailCell = cells[1];
|
|
76
|
+
const pluginIconWrapper = queryOne(".plugin-icon-wrapper", row);
|
|
77
|
+
const pluginIconSrc = getAttribute(queryOne(".plugin-icon", row), "src") ?? "";
|
|
78
|
+
const isIconChecked = (pluginIconWrapper?.attribs?.class ?? "")
|
|
79
|
+
.split(/\s+/)
|
|
80
|
+
.filter((value) => value.length > 0)
|
|
81
|
+
.includes("img-checked");
|
|
82
|
+
const icon = { pluginIconSrc, isIconChecked };
|
|
83
|
+
const isFileRow = !!detailCell?.attribs?.colspan && detailCell.attribs.colspan === "2";
|
|
84
|
+
if (isFileRow) {
|
|
85
|
+
const commentNode = queryOne(".x-drag-title .cf", row);
|
|
86
|
+
const comment = commentNode ? getInnerHtml(commentNode).trim() : "";
|
|
87
|
+
const files = queryAll(".margin-top-md .display-block", row)
|
|
88
|
+
.map((block) => {
|
|
89
|
+
const link = queryOne("a", block);
|
|
90
|
+
const fileName = normalizeWhitespace(getTextContent(link));
|
|
91
|
+
const href = getAttribute(link, "href") ?? "";
|
|
92
|
+
const fileIcon = getAttribute(queryOne("img.icon", block), "src") ?? "";
|
|
93
|
+
return { fileName, href, icon: fileIcon };
|
|
94
|
+
})
|
|
95
|
+
.filter((file) => file.fileName.length > 0 || file.href.length > 0 || file.icon.length > 0);
|
|
96
|
+
contents.push({
|
|
97
|
+
type: "resource",
|
|
98
|
+
icon,
|
|
99
|
+
attachedFile: { comment, files, duration: extractDurations(row) },
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const titleAnchor = queryOne("a.a-content-open", row);
|
|
104
|
+
const titleElement = titleAnchor ?? queryOne("b", row);
|
|
105
|
+
const title = titleElement ? normalizeWhitespace(getTextContent(titleElement)) : "";
|
|
106
|
+
const contentId = titleAnchor ? (getAttribute(titleAnchor, "content_id") ?? "") : "";
|
|
107
|
+
const pluginKey = titleAnchor ? (getAttribute(titleAnchor, "plugin_key") ?? "") : "";
|
|
108
|
+
const duration = extractDurations(row);
|
|
109
|
+
const toggleRow = findNextMatchingSibling(row, ".toggle-area");
|
|
110
|
+
const toggleContainer = toggleRow ? (queryOne(".x-content-hide", toggleRow) ?? toggleRow) : null;
|
|
111
|
+
const descriptionNode = toggleContainer ? queryOne(".description", toggleContainer) : null;
|
|
112
|
+
const description = descriptionNode ? getInnerHtml(descriptionNode).trim() : "";
|
|
113
|
+
const errorNodes = toggleContainer ? queryAll(".confirm .error", toggleContainer) : [];
|
|
114
|
+
const errorMessages = errorNodes
|
|
115
|
+
.map((errorNode) => normalizeWhitespace(getTextContent(errorNode)))
|
|
116
|
+
.filter((message) => message.length > 0);
|
|
117
|
+
const hasNotAvailableYetError = errorMessages.some((message) => message.includes("まだ受講できません"));
|
|
118
|
+
const isNotAvailableYet = hasNotAvailableYetError;
|
|
119
|
+
// 「まだ受講できません」は将来の受講可能通知として扱い、期限切れとは区別する。
|
|
120
|
+
const isExpired = errorNodes.length > 0 ? !hasNotAvailableYetError : false;
|
|
121
|
+
const actions = toggleContainer
|
|
122
|
+
? queryAll(".confirm a.btn", toggleContainer).map((actionNode) => ({
|
|
123
|
+
title: normalizeWhitespace(getTextContent(actionNode)),
|
|
124
|
+
href: getAttribute(actionNode, "href") ?? "",
|
|
125
|
+
}))
|
|
126
|
+
: [];
|
|
127
|
+
contents.push({
|
|
128
|
+
type: "activity",
|
|
129
|
+
icon,
|
|
130
|
+
content: { title, contentId, pluginKey, duration },
|
|
131
|
+
toggleArea: { description, isExpired, isNotAvailableYet, actions },
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
return ManaboClassContentSchema.safeParse({ contents });
|
|
135
|
+
};
|
|
136
|
+
export const parseManaboClassEntry = (html) => {
|
|
137
|
+
const document = loadDocument(html);
|
|
138
|
+
const rows = queryAll("table.table-default tbody tr", document)
|
|
139
|
+
.filter((row) => {
|
|
140
|
+
const cells = queryAll("td", row);
|
|
141
|
+
const hasColspan = cells.some((cell) => getAttribute(cell, "colspan") !== null);
|
|
142
|
+
return !hasColspan;
|
|
143
|
+
})
|
|
144
|
+
.map((row) => {
|
|
145
|
+
const cells = queryAll("td", row);
|
|
146
|
+
const directory = normalizeWhitespace(getTextContent(cells[0] ?? null));
|
|
147
|
+
const lectureDateRaw = normalizeWhitespace(getTextContent(cells[1] ?? null));
|
|
148
|
+
const status = normalizeWhitespace(getTextContent(cells[2] ?? null));
|
|
149
|
+
return { directory, lectureDate: lectureDateRaw.length ? lectureDateRaw : null, status };
|
|
150
|
+
});
|
|
151
|
+
return ManaboClassEntrySchema.safeParse({ rows });
|
|
152
|
+
};
|
|
153
|
+
export const parseManaboClassNews = (html) => {
|
|
154
|
+
const document = loadDocument(html);
|
|
155
|
+
const items = queryAll("dl.x-openclose", document).map((dl) => {
|
|
156
|
+
const title = normalizeWhitespace(getTextContent(queryOne("dt b", dl)));
|
|
157
|
+
const bodyHtml = getInnerHtml(queryOne("dd", dl)).trim() || "";
|
|
158
|
+
const id = getAttribute(dl, "id");
|
|
159
|
+
const newsId = id ? id.replace(/^class-news-/, "") : null;
|
|
160
|
+
return { id, newsId, title, bodyHtml };
|
|
161
|
+
});
|
|
162
|
+
return ManaboClassNewsSchema.safeParse({ items });
|
|
163
|
+
};
|
|
164
|
+
export const parseManaboClassSyllabus = (html) => {
|
|
165
|
+
const document = loadDocument(html);
|
|
166
|
+
const mainTable = queryOne(".panel-body .table.table-default", document);
|
|
167
|
+
const rows = mainTable ? queryAll("tr", mainTable).filter((row) => closest(row, "table") === mainTable) : [];
|
|
168
|
+
let object = "";
|
|
169
|
+
let goal = [];
|
|
170
|
+
let method = "";
|
|
171
|
+
let usedMethods = [];
|
|
172
|
+
let evaluation = [];
|
|
173
|
+
const textbooks = [];
|
|
174
|
+
let references = [];
|
|
175
|
+
let officeHour = "";
|
|
176
|
+
let plan = [];
|
|
177
|
+
let comment = "";
|
|
178
|
+
let prePostStudy = "";
|
|
179
|
+
const isDataNode = (node) => !!node && typeof node.data === "string";
|
|
180
|
+
const collectSiblingText = (element) => {
|
|
181
|
+
if (!element) {
|
|
182
|
+
return "";
|
|
183
|
+
}
|
|
184
|
+
const fragments = [];
|
|
185
|
+
let current = element.next;
|
|
186
|
+
while (current) {
|
|
187
|
+
if (isElement(current)) {
|
|
188
|
+
if (current.name.toLowerCase() === "br") {
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
fragments.push(getTextContent(current));
|
|
192
|
+
}
|
|
193
|
+
else if (isDataNode(current)) {
|
|
194
|
+
fragments.push(current.data);
|
|
195
|
+
}
|
|
196
|
+
current = current.next;
|
|
197
|
+
}
|
|
198
|
+
return normalizeWhitespace(fragments.join(" "));
|
|
199
|
+
};
|
|
200
|
+
rows.forEach((row) => {
|
|
201
|
+
const heading = normalizeWhitespace(getTextContent(queryOne("th", row)));
|
|
202
|
+
const cell = queryOne("td", row);
|
|
203
|
+
switch (heading) {
|
|
204
|
+
case "授業概要・目的": {
|
|
205
|
+
object = normalizeWhitespace(getTextContent(cell));
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
case "学修到達目標": {
|
|
209
|
+
goal = queryAll("li", cell)
|
|
210
|
+
.map((item) => normalizeWhitespace(getTextContent(item)))
|
|
211
|
+
.filter((item) => item.length > 0);
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
case "授業方法": {
|
|
215
|
+
method = normalizeWhitespace(getTextContent(cell));
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
case "活用される授業方法": {
|
|
219
|
+
usedMethods = queryAll("input.usemethod[checked]", cell)
|
|
220
|
+
.map((input) => collectSiblingText(input))
|
|
221
|
+
.filter((value) => value.length > 0);
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
case "成績評価方法・基準": {
|
|
225
|
+
evaluation = queryAll("table tr", cell)
|
|
226
|
+
.map((evalRow) => {
|
|
227
|
+
const columns = queryAll("td", evalRow);
|
|
228
|
+
const type = normalizeWhitespace(getTextContent(columns[0] ?? null));
|
|
229
|
+
const weight = normalizeWhitespace(getTextContent(columns[1] ?? null));
|
|
230
|
+
if (!type || !weight) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
return { type, weight };
|
|
234
|
+
})
|
|
235
|
+
.filter((item) => item !== null);
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
case "教科書・教材・参考文献": {
|
|
239
|
+
queryAll("table tr", cell).forEach((bookRow) => {
|
|
240
|
+
const cells = queryAll("td", bookRow);
|
|
241
|
+
const label = normalizeWhitespace(getTextContent(cells[0] ?? null));
|
|
242
|
+
const valueCell = cells[1] ?? null;
|
|
243
|
+
if (!valueCell) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (label.includes("教科書・教材")) {
|
|
247
|
+
const title = normalizeWhitespace(getTextContent(valueCell));
|
|
248
|
+
if (title) {
|
|
249
|
+
textbooks.push({ type: label, title });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else if (label.includes("参考文献")) {
|
|
253
|
+
references = queryAll("li", valueCell)
|
|
254
|
+
.map((item) => {
|
|
255
|
+
const title = normalizeWhitespace(getTextContent(item));
|
|
256
|
+
const code = getAttribute(item, "data-code") ?? "";
|
|
257
|
+
if (!title || !code) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
return { title, code };
|
|
261
|
+
})
|
|
262
|
+
.filter((item) => item !== null);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
case "質問への対応(オフィスアワー等)": {
|
|
268
|
+
officeHour = normalizeWhitespace(getTextContent(cell));
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
case "授業計画": {
|
|
272
|
+
const planTable = queryOne("table", cell);
|
|
273
|
+
plan = queryAll("tbody tr", planTable)
|
|
274
|
+
.map((planRow) => {
|
|
275
|
+
const cols = queryAll("td", planRow);
|
|
276
|
+
const noText = normalizeWhitespace(getTextContent(cols[0] ?? null));
|
|
277
|
+
const item = normalizeWhitespace(getTextContent(cols[1] ?? null));
|
|
278
|
+
const content = normalizeWhitespace(getTextContent(cols[2] ?? null));
|
|
279
|
+
const no = Number.parseInt(noText, 10);
|
|
280
|
+
if (!Number.isFinite(no) || !item || !content) {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
return { no, item, content };
|
|
284
|
+
})
|
|
285
|
+
.filter((entry) => entry !== null);
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
case "履修者へのコメント": {
|
|
289
|
+
comment = normalizeWhitespace(getTextContent(cell));
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
case "事前事後学習": {
|
|
293
|
+
prePostStudy = normalizeWhitespace(getTextContent(cell)).replace(/\s+\(/g, "(");
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
default:
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
return ManaboClassSyllabusSchema.safeParse({
|
|
301
|
+
object,
|
|
302
|
+
goal,
|
|
303
|
+
method,
|
|
304
|
+
usedMethods,
|
|
305
|
+
evaluation,
|
|
306
|
+
textbooks,
|
|
307
|
+
references,
|
|
308
|
+
officeHour,
|
|
309
|
+
plan,
|
|
310
|
+
comment,
|
|
311
|
+
prePostStudy,
|
|
312
|
+
});
|
|
313
|
+
};
|
|
314
|
+
export const parseManaboClassQuizResult = (html) => {
|
|
315
|
+
const document = loadDocument(html);
|
|
316
|
+
const scoreText = normalizeWhitespace(getTextContent(queryOne(".text-center .Red b", document)));
|
|
317
|
+
const totalTextRaw = normalizeWhitespace(getTextContent(queryOne(".text-center", document)));
|
|
318
|
+
const totalText = totalTextRaw.split("/")[1] ?? "0";
|
|
319
|
+
const obtained = Number(scoreText.replace(/[^\d]/g, "")) || 0;
|
|
320
|
+
const total = Number(totalText.replace(/[^\d]/g, "")) || 0;
|
|
321
|
+
const paginationSummary = normalizeWhitespace(getTextContent(queryOne(".row.margin-top-md .col-sm-2", document)));
|
|
322
|
+
let currentPage = "";
|
|
323
|
+
const questions = queryAll("table.table-default-grade tbody tr", document).map((row) => {
|
|
324
|
+
const cells = queryAll("td", row);
|
|
325
|
+
let cellIndex = 0;
|
|
326
|
+
const firstCell = cells[cellIndex];
|
|
327
|
+
const firstCellRowspan = getAttribute(firstCell, "rowspan");
|
|
328
|
+
const hasPageCell = (firstCellRowspan !== null && firstCellRowspan !== "1") || cells.length === 7;
|
|
329
|
+
if (hasPageCell) {
|
|
330
|
+
currentPage = normalizeWhitespace(getTextContent(firstCell));
|
|
331
|
+
cellIndex += 1;
|
|
332
|
+
}
|
|
333
|
+
const questionNumber = normalizeWhitespace(getTextContent(cells[cellIndex] ?? null));
|
|
334
|
+
cellIndex += 1;
|
|
335
|
+
const questionCell = cells[cellIndex] ?? null;
|
|
336
|
+
const instruction = queryOne(".div-instructions", questionCell ?? undefined);
|
|
337
|
+
const questionText = normalizeWhitespace(instruction ? getTextContent(instruction) : getTextContent(questionCell));
|
|
338
|
+
cellIndex += 1;
|
|
339
|
+
const correctAnswer = normalizeWhitespace(getTextContent(cells[cellIndex] ?? null));
|
|
340
|
+
cellIndex += 1;
|
|
341
|
+
const studentAnswer = normalizeWhitespace(getTextContent(cells[cellIndex] ?? null));
|
|
342
|
+
cellIndex += 1;
|
|
343
|
+
const resultCell = cells[cellIndex] ?? null;
|
|
344
|
+
const resultIcon = queryOne("img", resultCell ?? undefined);
|
|
345
|
+
const resultIconSrc = getAttribute(resultIcon, "src");
|
|
346
|
+
const resultCellText = getTextContent(resultCell);
|
|
347
|
+
const pointsMatch = resultCellText.match(/\d+/);
|
|
348
|
+
const points = pointsMatch ? Number.parseInt(pointsMatch[0], 10) : null;
|
|
349
|
+
let isCorrect = null;
|
|
350
|
+
if (resultIconSrc) {
|
|
351
|
+
if (resultIconSrc.includes("point_good")) {
|
|
352
|
+
isCorrect = true;
|
|
353
|
+
}
|
|
354
|
+
else if (resultIconSrc.includes("point_worst") || resultIconSrc.includes("point_bad")) {
|
|
355
|
+
isCorrect = false;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
cellIndex += 1;
|
|
359
|
+
const teacherComment = normalizeWhitespace(getTextContent(cells[cellIndex] ?? null));
|
|
360
|
+
return {
|
|
361
|
+
page: currentPage,
|
|
362
|
+
questionNumber,
|
|
363
|
+
questionText,
|
|
364
|
+
correctAnswer,
|
|
365
|
+
studentAnswer,
|
|
366
|
+
isCorrect,
|
|
367
|
+
points,
|
|
368
|
+
resultIconSrc,
|
|
369
|
+
teacherComment: teacherComment.length ? teacherComment : null,
|
|
370
|
+
};
|
|
371
|
+
});
|
|
372
|
+
return ManaboClassQuizResultSchema.safeParse({
|
|
373
|
+
score: { obtained, total },
|
|
374
|
+
paginationSummary: paginationSummary.length ? paginationSummary : null,
|
|
375
|
+
questions,
|
|
376
|
+
});
|
|
377
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MaNaBo 出欠(出席カード)関連のパーサ。
|
|
3
|
+
*/
|
|
4
|
+
import type { ZodSafeParseResult } from "zod";
|
|
5
|
+
import { type ManaboEntryFormDTO, type ManaboEntryResponseDTO } from "../types/manaboEntry";
|
|
6
|
+
export declare const parseManaboEntryForm: (html: string) => ZodSafeParseResult<ManaboEntryFormDTO>;
|
|
7
|
+
export declare const parseManaboEntryResponse: (json: string) => ZodSafeParseResult<ManaboEntryResponseDTO>;
|
|
8
|
+
//# sourceMappingURL=manaboEntry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manaboEntry.d.ts","sourceRoot":"","sources":["../../../../src/manabo/parser/manaboEntry.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,KAAK,CAAC;AAG9C,OAAO,EAAoD,KAAK,kBAAkB,EAAE,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9I,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,kBAAkB,CAqBxF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,sBAAsB,CAQhG,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getAttribute, getTextContent, loadDocument, queryAll, queryOne } from "../../common/dom";
|
|
2
|
+
import { normalizeWhitespace } from "../../common/utils";
|
|
3
|
+
import { ManaboEntryFormSchema, ManaboEntryResponseSchema } from "../types/manaboEntry";
|
|
4
|
+
export const parseManaboEntryForm = (html) => {
|
|
5
|
+
const document = loadDocument(html);
|
|
6
|
+
const form = queryOne("#form-entry", document);
|
|
7
|
+
const messages = form
|
|
8
|
+
? queryAll("p", form)
|
|
9
|
+
.map((element) => normalizeWhitespace(getTextContent(element)))
|
|
10
|
+
.filter((message) => message.length > 0)
|
|
11
|
+
: [];
|
|
12
|
+
return ManaboEntryFormSchema.safeParse({
|
|
13
|
+
action: getAttribute(queryOne('input[name="action"]', form), "value") ?? "",
|
|
14
|
+
classId: getAttribute(queryOne('input[name="class_id"]', form), "value") ?? "",
|
|
15
|
+
directoryId: getAttribute(queryOne('input[name="directory_id"]', form), "value") ?? "",
|
|
16
|
+
entryId: getAttribute(queryOne('input[name="entry_id"]', form), "value") ?? "",
|
|
17
|
+
uniqid: getAttribute(queryOne('input[name="uniqid"]', form), "value") ?? "",
|
|
18
|
+
// 出席コード(パスワード)入力欄の有無で必須かを判定する。
|
|
19
|
+
// パスワードなし授業ではこの input が存在しない。
|
|
20
|
+
requiresCode: queryOne('input[name="code"]', form) != null,
|
|
21
|
+
messages,
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
export const parseManaboEntryResponse = (json) => {
|
|
25
|
+
let parsed;
|
|
26
|
+
try {
|
|
27
|
+
parsed = JSON.parse(json);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
parsed = undefined;
|
|
31
|
+
}
|
|
32
|
+
return ManaboEntryResponseSchema.safeParse(parsed);
|
|
33
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ZodSafeParseResult } from "zod";
|
|
2
|
+
import { type ManaboMailMemberDTO, type ManaboMailSendDTO, type ManaboMailViewDTO, type ManaboReceivedMailDTO, type ManaboSentMailDTO } from "../types/manaboMail";
|
|
3
|
+
export declare const parseManaboReceivedMail: (html: string) => ZodSafeParseResult<ManaboReceivedMailDTO>;
|
|
4
|
+
export declare const parseManaboSentMail: (html: string) => ZodSafeParseResult<ManaboSentMailDTO>;
|
|
5
|
+
export declare const parseManaboMailView: (html: string) => ZodSafeParseResult<ManaboMailViewDTO>;
|
|
6
|
+
export declare const parseManaboMailSend: (html: string) => ZodSafeParseResult<ManaboMailSendDTO>;
|
|
7
|
+
export declare const parseManaboMailMember: (html: string) => ZodSafeParseResult<ManaboMailMemberDTO>;
|
|
8
|
+
//# sourceMappingURL=manaboMail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manaboMail.d.ts","sourceRoot":"","sources":["../../../../src/manabo/parser/manaboMail.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,KAAK,CAAC;AAG9C,OAAO,EAMH,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACzB,MAAM,qBAAqB,CAAC;AA8B7B,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,qBAAqB,CA+B9F,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,iBAAiB,CAmCtF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,iBAAiB,CAoCtF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,iBAAiB,CAetF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,MAAM,MAAM,KAAG,kBAAkB,CAAC,mBAAmB,CAY1F,CAAC"}
|