1 | 'use strict'; |
||
2 | |||
3 | const |
||
4 | express = require('express'), |
||
5 | superagent = require('superagent'), |
||
6 | cheerio = require('cheerio'), |
||
7 | colors = require('colors'), |
||
0 ignored issues
–
show
Unused Code
introduced
by
![]() |
|||
8 | program = require('commander'), |
||
9 | moment = require('moment'), |
||
10 | co = require('co'), |
||
11 | thunkify = require('thunkify'), |
||
12 | access = require('./lib/access.js'); |
||
13 | |||
14 | program |
||
15 | .option('-h, --help') |
||
16 | .option('-v, --version') |
||
17 | .option('-p, --port [value]', parseInt) |
||
0 ignored issues
–
show
The variable
parseInt seems to be never declared. If this is a global, consider adding a /** global: parseInt */ comment.
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed. To learn more about declaring variables in Javascript, see the MDN. ![]() |
|||
18 | .option('-f, --fullLog') |
||
19 | .parse(process.argv); |
||
20 | |||
21 | // 别问我为什么这里逻辑这么奇怪……测试的结果确实是这样的啊hhh |
||
22 | if (!program.help || !program.version) { |
||
23 | console.log( |
||
24 | `${`CSUEMS API v${require('./package').version} |
||
25 | by The Liberators`.rainbow}${program.help ? '' : |
||
26 | ` |
||
27 | |||
28 | Preparation: |
||
29 | ${'(This section is WIP)'.grey} |
||
30 | |||
31 | Usage: |
||
32 | npm start [-- <options...>] |
||
33 | |||
34 | Options: |
||
35 | -h, --help print this message and exit. |
||
36 | -v, --version print the version and exit. |
||
37 | -f, --fullLog enable full log, by default only errors are logged. |
||
38 | -p, --port [value] specify a port to listen, process.env.PORT || 2333 by default. |
||
39 | |||
40 | Examples: |
||
41 | $ npm start -- -p 43715 # listening to 43715 |
||
42 | $ forever start app.js # deploy with forever as daemon (root access recommended) |
||
43 | $ pm2 start -i 0 -n "csuapi" app.js # deploy with pm2 as daemon (root access recommended)`}`); |
||
44 | process.exit(0); |
||
45 | } |
||
46 | |||
47 | superagent.Request.prototype.endThunk = thunkify(superagent.Request.prototype.end); |
||
48 | |||
49 | const |
||
50 | logging = log => console.log(`${moment().format('[[]YY-MM-DD HH:mm:ss[]]')} ${log}`), |
||
51 | fullLogging = log => program.fullLog && logging(log), |
||
52 | getSem = () => { |
||
53 | // 以系统时间获取当前学期 |
||
54 | let now = new Date(); |
||
55 | let month = now.getMonth(); |
||
56 | let year = now.getFullYear(); |
||
57 | if (month <= 6) { |
||
58 | return `${year - 1}-${year}-${month > 0 ? 2 : 1}`; |
||
59 | } else { |
||
60 | return `${year}-${year + 1}-1`; |
||
61 | } |
||
62 | }, |
||
63 | // wait = ms => callback => setTimeout(callback, ms), |
||
64 | port = program.port || process.env.PORT || 2333, |
||
65 | app = express(); |
||
66 | |||
67 | // 获取文档 |
||
68 | app.get('/doc', (req, res) => res.sendFile(`${__dirname}/doc/API.html`)); |
||
69 | |||
70 | // 查成绩API,通过GET传入用户名和密码 |
||
71 | View Code Duplication | app.get(/^\/g(?:|rades)$/, co.wrap(function* (req, res) { |
|
0 ignored issues
–
show
|
|||
72 | if (!req.query.id || !req.query.pwd || (req.query.sem && !(/^20\d{2}-20\d{2}-[1-2]$/).test(req.query.sem))) { |
||
73 | res.status(404).send({ error: "参数不正确" }); |
||
74 | return; |
||
75 | } |
||
76 | |||
77 | let start = new Date(); |
||
78 | fullLogging('Started to query the grades: '.cyan + req.query.id.yellow); |
||
79 | |||
80 | let headers; |
||
81 | try { |
||
82 | headers = yield access.login(req.query.id, req.query.pwd, res); |
||
83 | } catch (err) { return; } |
||
84 | fullLogging('Successfully logged in.'.green); |
||
85 | |||
86 | let ires; |
||
87 | try { |
||
88 | // 实际上xnxq01id为空的时候和GET这个URL的效果是一样的,都是查询所有学期 |
||
89 | ires = yield superagent |
||
90 | .post('http://csujwc.its.csu.edu.cn/jsxsd/kscj/yscjcx_list') |
||
91 | .set(headers) |
||
92 | .type('form') |
||
93 | .send({ xnxq01id: req.query.sem }) |
||
94 | .endThunk(); |
||
95 | } catch (err) { |
||
96 | logging(` Failed to get grades page\n${err.stack}`.red); |
||
97 | res.status(404).send({ error: '无法进入成绩页面' }); |
||
98 | return; |
||
99 | } finally { |
||
100 | // 直接异步进行? |
||
101 | co(function* () { |
||
102 | yield access.logout(headers); |
||
103 | fullLogging('Successfully logged out: '.green + req.query.id.yellow); |
||
104 | }); |
||
105 | } |
||
106 | fullLogging('Successfully entered grades page.'.green); |
||
107 | |||
108 | let $ = cheerio.load(ires.text); |
||
109 | |||
110 | let top = $('#Top1_divLoginName').text(); |
||
111 | let result = { |
||
112 | name: top.match(/\s.+\(/)[0].replace(/\s|\(/g, ''), |
||
113 | id: top.match(/\(.+\)/)[0].replace(/\(|\)/g, ''), |
||
114 | grades: {}, |
||
115 | 'subject-count': 0, |
||
116 | failed: {}, |
||
117 | 'failed-count': 0, |
||
118 | }; |
||
119 | // 获取成绩列表 |
||
120 | $('#dataList tr').each(function (index) { |
||
121 | if (index === 0) return; |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed. ![]() |
|||
122 | |||
123 | let element = $(this).find('td'); |
||
124 | |||
125 | let title = element.eq(3).text().match(/].+$/)[0].substring(1); |
||
126 | let item = { |
||
127 | sem: element.eq(2).text(), |
||
128 | reg: element.eq(4).text(), |
||
129 | exam: element.eq(5).text(), |
||
130 | overall: element.eq(6).text() |
||
131 | }; |
||
132 | if (req.query.details) { |
||
133 | item.id = element.eq(3).text().match(/\[.+\]/)[0].replace(/\[|\]/g, ''); |
||
134 | item.attr = element.eq(8).text(); |
||
135 | item.genre = element.eq(9).text(); |
||
136 | item.credit = element.eq(7).text(); |
||
137 | } |
||
138 | |||
139 | // 如果有补考记录,则以最高分的为准 |
||
140 | // 这段代码是拿可读性换了时间复杂度…… |
||
141 | if (title in result.grades) { |
||
142 | // 暂不考虑NaN |
||
143 | if (item.overall < result.grades[title].overall) { |
||
144 | return; |
||
145 | } |
||
146 | // 如果新的成绩不是挂科的 |
||
147 | if (!element.eq(6).css('color')) { |
||
148 | delete result.failed[title]; |
||
149 | } |
||
150 | } else if (element.eq(6).css('color')) { |
||
151 | result.failed[title] = item; |
||
152 | } |
||
153 | |||
154 | result.grades[title] = item; |
||
155 | }); |
||
156 | |||
157 | result['subject-count'] = Object.keys(result.grades).length; |
||
158 | result['failed-count'] = Object.keys(result.failed).length; |
||
159 | |||
160 | res.send(JSON.stringify(result)); |
||
161 | fullLogging(`Successfully responded. (req -> res processed in ${new Date() - start} ms)`.green); |
||
162 | })); |
||
163 | |||
164 | // 查考试API,通过GET传入用户名和密码 |
||
165 | View Code Duplication | app.get(/^\/e(?:|xams)$/, co.wrap(function* (req, res) { |
|
0 ignored issues
–
show
|
|||
166 | if (!req.query.id || !req.query.pwd || (req.query.sem && !(/^20\d{2}-20\d{2}-[1-2]$/).test(req.query.sem))) { |
||
167 | res.status(404).send({ error: "参数不正确" }); |
||
168 | return; |
||
169 | } |
||
170 | |||
171 | let start = new Date(); |
||
172 | fullLogging('Started to query the exams: '.cyan + req.query.id.yellow); |
||
173 | |||
174 | let headers; |
||
175 | try { |
||
176 | headers = yield access.login(req.query.id, req.query.pwd, res); |
||
177 | } catch (err) { return; } |
||
178 | fullLogging('Successfully logged in.'.green); |
||
179 | |||
180 | let ires; |
||
181 | let _sem = req.query.sem || getSem(); |
||
182 | try { |
||
183 | ires = yield superagent |
||
184 | .post('http://csujwc.its.csu.edu.cn/jsxsd/xsks/xsksap_list') |
||
185 | .set(headers) |
||
186 | .type('form') |
||
187 | .send({ |
||
188 | xqlbmc: '', |
||
189 | xnxqid: _sem, |
||
190 | xqlb: '' |
||
191 | }) |
||
192 | .endThunk(); |
||
193 | } catch (err) { |
||
194 | logging(` Failed to reach exams page\n${err.stack}`.red); |
||
195 | res.status(404).send({ error: '无法进入考试页面' }); |
||
196 | return; |
||
197 | } finally { |
||
198 | co(function* () { |
||
199 | yield access.logout(headers); |
||
200 | fullLogging('Successfully logged out: '.green + req.query.id.yellow); |
||
201 | }); |
||
202 | } |
||
203 | fullLogging('Successfully entered exams page.'.green); |
||
204 | |||
205 | let $ = cheerio.load(ires.text); |
||
206 | |||
207 | let top = $('#Top1_divLoginName').text(); |
||
208 | let result = { |
||
209 | name: top.match(/\s.+\(/)[0].replace(/\s|\(/g, ''), |
||
210 | id: top.match(/\(.+\)/)[0].replace(/\(|\)/g, ''), |
||
211 | sem: _sem, |
||
212 | exams: {}, |
||
213 | 'exams-count': 0, |
||
214 | }; |
||
215 | $('#dataList tr').each(function (index) { |
||
216 | if (index === 0) return; |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed. ![]() |
|||
217 | |||
218 | let element = $(this).find('td'); |
||
219 | |||
220 | let title = element.eq(3).text(); |
||
221 | let item = { |
||
222 | time: element.eq(4).text(), |
||
223 | location: element.eq(5).text(), |
||
224 | seat: element.eq(6).text() |
||
225 | }; |
||
226 | |||
227 | result.exams[title] = item; |
||
228 | result['exams-count']++; |
||
229 | }); |
||
230 | |||
231 | res.send(JSON.stringify(result)); |
||
232 | fullLogging(`Successfully responded. (req -> res processed in ${new Date() - start} ms)`.green); |
||
233 | })); |
||
234 | |||
235 | app.listen(port, () => { |
||
236 | logging(` The API is now running on port ${port}. Full logging is ${program.fullLog ? 'enabled' : 'disabled'}`.green); |
||
237 | }); |