1 | /* TODO |
||
2 | * 完善异常处理 |
||
3 | */ |
||
4 | |||
5 | "use strict"; |
||
6 | |||
7 | var express = require('express'), |
||
8 | superagent = require('superagent'), |
||
9 | cheerio = require('cheerio'), |
||
10 | escaper = require('true-html-escape'), |
||
11 | colors = require('colors'), |
||
12 | program = require('commander'), |
||
13 | Date = require('./lib/Date.js'), |
||
14 | access = require('./lib/access.js'); |
||
15 | |||
16 | program |
||
17 | .option('-h, --help') |
||
18 | .option('-v, --version') |
||
19 | .option('-p, --port [n]', parseInt) |
||
20 | .option('-f, --fullLog') |
||
21 | .parse(process.argv); |
||
22 | |||
23 | // 别问我为什么这里逻辑这么奇怪……测试的结果确实是这样的啊hhh |
||
24 | if (!program.help || !program.version) { |
||
25 | console.log(('CSUEMS API v1.0.0').rainbow); |
||
26 | console.log(('by The Liberators').rainbow); |
||
27 | if (!program.help) { |
||
28 | console.log('Preparation:'); |
||
29 | console.log(' \\\\This section is WIP\\\\'); |
||
30 | console.log('\nUsage:'); |
||
31 | console.log(' npm start [-- <options...>]'); |
||
32 | console.log('\nOptions:'); |
||
33 | console.log(' -h, --help print this message and exit.'); |
||
34 | console.log(' -v, --version print the version and exit.'); |
||
35 | console.log(' -f, --fullLog enable full log, by default only errors are logged.'); |
||
36 | console.log(' -p, --port [value] specify a port to listen, 2333 by default.'); |
||
37 | console.log('\nExamples:'); |
||
38 | console.log(' $ npm start -p 43715 # listening to 43715'); |
||
39 | console.log(' $ forever start app.js # deploy with forever as daemon (root access recommended)'); |
||
40 | console.log(' $ pm2 start -i 0 -n "csuapi" app.js # deploy with pm2 as daemon (root access recommended)'); |
||
41 | } |
||
42 | process.exit(0); |
||
43 | } |
||
44 | |||
45 | const timeStamp = () => new Date().format('[MM-dd hh:mm:ss] '), |
||
46 | port = program.port || 2333, |
||
47 | base = 'http://csujwc.its.csu.edu.cn'; |
||
48 | |||
49 | var app = express(); |
||
50 | |||
51 | // 查成绩API,通过GET传入用户名和密码 |
||
52 | app.get('/grades/', function (req, res, next) { |
||
53 | if (!req.query.id || !req.query.pwd) { |
||
54 | res.send({ error: "参数不正确" }); |
||
55 | return; |
||
56 | } |
||
57 | if (program.fullLog) { |
||
58 | var start = new Date(); |
||
59 | console.log((timeStamp() + 'Started to query the grades: ').cyan + req.query.id.yellow); |
||
60 | } |
||
61 | access.login(req.query.id, req.query.pwd, res, function (headers, ires) { |
||
62 | program.fullLog && console.log((timeStamp() + 'Successfully logged in.').green); |
||
63 | var ret = {}; |
||
64 | var $ = cheerio.load(ires.text); |
||
65 | ret.name = escaper.unescape($('.block1text').html()).match(/姓名:.+</)[0].replace('<', '').substring(3); |
||
66 | ret.id = req.query.id; |
||
67 | |||
68 | // 进入成绩页面 |
||
69 | superagent.get(base + $('li[title="我的成绩"] a').attr('href')) |
||
70 | .set(headers) |
||
71 | .end(function (err, iires) { |
||
72 | if (err) { |
||
73 | console.log((timeStamp() + 'Failed to get grades page\n' + err.stack).red); |
||
74 | res.send({ error: '无法进入成绩页面' }); |
||
75 | return next(err); |
||
76 | } |
||
77 | program.fullLog && console.log((timeStamp() + 'Successfully entered grades page.').green); |
||
78 | |||
79 | $ = cheerio.load(iires.text); |
||
80 | |||
81 | // 获取成绩列表 |
||
82 | let grades = {}; |
||
83 | let failed = {}; |
||
84 | $('#dataList').each(function (index) { |
||
85 | // cheerio没有实现jQuery的lt |
||
86 | if (index >= 2) |
||
87 | return; |
||
0 ignored issues
–
show
|
|||
88 | $(this).find('tr[class!="theadCss"]').each(function() { |
||
89 | // 这段写得真是要吐血了 |
||
90 | let subject = escaper.unescape($(this).find('td[align="left"]').eq(1).text()); |
||
91 | if (subject) { |
||
92 | let score = $(this).find('font'); |
||
93 | if (score.text()) |
||
94 | grades[subject] = score.text(); |
||
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. ![]() |
|||
95 | if (score.css('color')) |
||
96 | failed[subject] = score.text(); |
||
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. ![]() |
|||
97 | } |
||
98 | }); |
||
99 | }); |
||
100 | ret.grades = grades; |
||
101 | ret['subject-count'] = Object.getOwnPropertyNames(grades).length; |
||
102 | ret.failed = failed; |
||
103 | ret['failed-count'] = Object.getOwnPropertyNames(failed).length; |
||
104 | |||
105 | // 完成所有工作后,登出 |
||
106 | access.logout(headers, res, function() { |
||
107 | // 第五步:返回JSON |
||
108 | res.send(JSON.stringify(ret)); |
||
109 | program.fullLog && console.log((timeStamp() + 'Successfully logged out: ').green + req.query.id.yellow + (' (processed in ' + (new Date() - start) + 'ms)').green); |
||
1 ignored issue
–
show
|
|||
110 | }); |
||
0 ignored issues
–
show
|
|||
111 | }); |
||
112 | }); |
||
113 | }); |
||
114 | |||
115 | // 查考试API,通过GET传入用户名和密码 |
||
116 | app.get('/exams/', function (req, res, next) { |
||
117 | if (!req.query.id || !req.query.pwd || (req.query.sem && !(/^20\d{2}-20\d{2}-[1-2]$/).test(req.query.sem))) { |
||
118 | res.send({ error: "参数不正确" }); |
||
119 | return; |
||
120 | } |
||
121 | if (program.fullLog) { |
||
122 | var start = new Date(); |
||
123 | console.log((timeStamp() + 'Started to query the exams: ').cyan + req.query.id.yellow); |
||
124 | } |
||
125 | // 获取想要查询的学期,如果没有指定以系统时间为准 |
||
126 | var sem; |
||
127 | if (req.query.sem) { |
||
128 | sem = req.query.sem; |
||
129 | } else { |
||
130 | let now = new Date(); |
||
131 | let month = now.getMonth(); |
||
132 | let year = now.getFullYear(); |
||
133 | if (month === 0) { |
||
134 | sem = (year - 1) + '-' + year + '-1'; |
||
135 | } else if (month <= 6) { |
||
136 | sem = (year - 1) + '-' + year + '-2'; |
||
137 | } else { |
||
138 | sem = year + '-' + (year + 1) + '-1'; |
||
139 | } |
||
140 | } |
||
141 | access.login(req.query.id, req.query.pwd, res, function (headers, ires) { |
||
142 | var ret = {}; |
||
143 | var $ = cheerio.load(ires.text); |
||
144 | ret.name = escaper.unescape($('.block1text').html()).match(/姓名:.+</)[0].replace('<', '').substring(3); |
||
145 | ret.id = req.query.id; |
||
146 | ret.sem = sem; |
||
147 | |||
148 | superagent.post('http://csujwc.its.csu.edu.cn/jsxsd/xsks/xsksap_list') |
||
149 | .set(headers) |
||
150 | .type('form') |
||
151 | .send({ |
||
152 | xqlbmc: '', |
||
153 | xnxqid: sem, |
||
154 | xqlb: '' |
||
155 | }) |
||
156 | .end(function (err, iires) { |
||
157 | if (err) { |
||
158 | console.log((timeStamp() + 'Failed to reach exams page\n' + err.stack).red); |
||
159 | res.send({ error: '获取成绩失败' }); |
||
160 | return next(err); |
||
161 | } |
||
162 | program.fullLog && console.log((timeStamp() + 'Successfully entered exams page.').green); |
||
163 | |||
164 | $ = cheerio.load(iires.text); |
||
165 | |||
166 | let exams = []; |
||
167 | |||
168 | $('#dataList tr').each(function (index) { |
||
169 | if (index === 0) |
||
170 | 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. ![]() |
|||
171 | let item = $(this).find('td'); |
||
172 | let subject = {}; |
||
173 | subject.subject = escaper.unescape(item.eq(3).text()); |
||
174 | subject.time = escaper.unescape(item.eq(4).text()); |
||
175 | subject.location = escaper.unescape(item.eq(5).text()); |
||
176 | subject.seat = escaper.unescape(item.eq(6).text()); |
||
177 | exams.push(subject); |
||
178 | }); |
||
179 | |||
180 | ret.exams = exams; |
||
181 | |||
182 | access.logout(headers, res, function() { |
||
183 | res.send(JSON.stringify(ret)); |
||
184 | program.fullLog && console.log((timeStamp() + 'Successfully logged out: ').green + req.query.id.yellow + (' (processed in ' + (new Date() - start) + 'ms)').green); |
||
0 ignored issues
–
show
|
|||
185 | }); |
||
0 ignored issues
–
show
|
|||
186 | }); |
||
187 | }); |
||
188 | }); |
||
189 | |||
190 | app.listen(port); |
||
191 | console.log((timeStamp() + 'The server is now running on port ' + port + '.').green); |
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 you or someone else later decides to put another statement in, only the first statement will be executed.
In this case the statement
b = 42
will always be executed, while the logging statement will be executed conditionally.ensures that the proper code will be executed conditionally no matter how many statements are added or removed.