Code Duplication    Length = 74-95 lines in 2 locations

app.js 2 locations

@@ 66-160 (lines=95) @@
63
var app = express();
64
65
// 查成绩API,通过GET传入用户名和密码
66
app.get('/grades', function (req, res, next) {
67
    if (!req.query.id || !req.query.pwd || (req.query.sem && !(/^20\d{2}-20\d{2}-[1-2]$/).test(req.query.sem))) {
68
        res.send({ error: "参数不正确" });
69
        return;
70
    }
71
    if (fullLog) {
72
        var start = new Date();
73
        console.log(`${timeStamp()} Started to query the grades: `.cyan + req.query.id.yellow);
74
    }
75
    access.login(req.query.id, req.query.pwd, res, function (headers, ires) {
76
        if (fullLog) {
77
            console.log(`${timeStamp()} Successfully logged in.`.green);
78
        }
79
80
        var ret = {};
81
        var $ = cheerio.load(ires.text);
82
83
        ret.name = escaper.unescape($('.block1text').html()).match(/姓名:.+</)[0].substring(3).replace(/</, '');
84
        ret.id = req.query.id;
85
86
        // 实际上xnxq01id为空的时候和GET这个URL的效果是一样的,都是查询所有学期
87
        superagent
88
            .post('http://csujwc.its.csu.edu.cn/jsxsd/kscj/yscjcx_list')
89
            .set(headers)
90
            .type('form')
91
            .send({
92
                xnxq01id: req.query.sem
93
            })
94
            .end(function (err, iires) {
95
                if (err) {
96
                    console.log(`${timeStamp()} Failed to get grades page\n${err.stack}`.red);
97
                    res.send({ error: '无法进入成绩页面' });
98
                    return next(err);
99
                }
100
                if (fullLog) {
101
                    console.log(`${timeStamp()} Successfully entered grades page.`.green);
102
                }
103
104
                $ = cheerio.load(iires.text);
105
                
106
                ret.grades = {};
107
                ret.failed = {};
108
109
                // 获取成绩列表
110
                $('#dataList tr').each(function (index) {
111
                    if (index === 0) {
112
                        return;
113
                    }
114
                    let element = $(this).find('td');
115
                    let title = escaper.unescape(element.eq(3).text().match(/].+$/)[0].substring(1));
116
117
                    let item = {
118
                        sem: escaper.unescape(element.eq(2).text()),
119
                        reg: escaper.unescape(element.eq(4).text()),
120
                        exam: escaper.unescape(element.eq(5).text()),
121
                        overall: escaper.unescape(element.eq(6).text())
122
                    };
123
                    if (req.query.details) {
124
                        item.id = escaper.unescape(element.eq(3).text().match(/\[.+\]/)[0].replace(/\[|\]/g, ''));
125
                        item.attr = escaper.unescape(element.eq(8).text());
126
                        item.genre = escaper.unescape(element.eq(9).text());
127
                        item.credit = escaper.unescape(element.eq(7).text());
128
                    }
129
130
                    // 如果有补考记录,则以最高分的为准
131
                    if (title in ret.grades) {
132
                        // 暂不考虑NaN
133
                        if (item.overall < ret.grades[title].overall) {
134
                            return;
135
                        }
136
                        if (!element.eq(6).css('color')) {
137
                            delete ret.failed[title];
138
                        }
139
                    } else if (element.eq(6).css('color')) {
140
                        ret.failed[title] = item;
141
                    }
142
143
                    ret.grades[title] = item;
144
                });
145
146
                ret['subject-count'] = Object.keys(ret.grades).length;
147
                ret['failed-count'] = Object.keys(ret.failed).length;
148
149
                access.logout(headers, res, function() {
150
                    // 返回JSON
151
                    res.send(JSON.stringify(ret));
152
                    if (fullLog) {
153
                        console.log(`${timeStamp()} Successfully logged out: `.green +
154
                            req.query.id.yellow +
155
                            ` (processed in ${new Date() - start} ms)`.green);
156
                    }
157
                });
158
            });
159
    });
160
});
161
162
// 查考试API,通过GET传入用户名和密码
163
app.get('/exams', function (req, res, next) {
@@ 163-236 (lines=74) @@
160
});
161
162
// 查考试API,通过GET传入用户名和密码
163
app.get('/exams', function (req, res, next) {
164
    if (!req.query.id || !req.query.pwd || (req.query.sem && !(/^20\d{2}-20\d{2}-[1-2]$/).test(req.query.sem))) {
165
        res.send({ error: "参数不正确" });
166
        return;
167
    }
168
    if (fullLog) {
169
        var start = new Date();
170
        console.log(`${timeStamp()} Started to query the exams: `.cyan + req.query.id.yellow);
171
    }
172
    access.login(req.query.id, req.query.pwd, res, function (headers, ires) {
173
        if (fullLog) {
174
            console.log(`${timeStamp()} Successfully logged in.`.green);
175
        }
176
177
        var ret = {};
178
        var $ = cheerio.load(ires.text);
179
180
        ret.name = escaper.unescape($('.block1text').html()).match(/姓名:.+</)[0].replace('<', '').substring(3);
181
        ret.id = req.query.id;
182
        ret.sem = req.query.sem || getSem();
183
184
        superagent
185
            .post('http://csujwc.its.csu.edu.cn/jsxsd/xsks/xsksap_list')
186
            .set(headers)
187
            .type('form')
188
            .send({
189
                xqlbmc: '',
190
                xnxqid: ret.sem,
191
                xqlb: ''
192
            })
193
            .end(function (err, iires) {
194
                if (err) {
195
                    console.log(`${timeStamp()} Failed to reach exams page\n${err.stack}`.red);
196
                    res.send({ error: '获取成绩失败' });
197
                    return next(err);
198
                }
199
                if (fullLog) {
200
                    console.log(`${timeStamp()} Successfully entered exams page.`.green);
201
                }
202
203
                $ = cheerio.load(iires.text);
204
205
                ret.exams = {};
206
                ret['exams-count'] = 0;
207
208
                $('#dataList tr').each(function (index) {
209
                    if (index === 0) {
210
                        return;
211
                    }
212
                    let element = $(this).find('td');
213
                    let title = escaper.unescape(element.eq(3).text());
214
215
                    let item = {
216
                        time: escaper.unescape(element.eq(4).text()),
217
                        location: escaper.unescape(element.eq(5).text()),
218
                        seat: escaper.unescape(element.eq(6).text())
219
                    };
220
221
                    ret.exams[title] = item;
222
                    ret['exams-count']++;
223
                });
224
225
                access.logout(headers, res, function() {
226
                    res.send(JSON.stringify(ret));
227
                    if (fullLog) {
228
                        console.log(`${timeStamp()} Successfully logged out: `.green +
229
                            req.query.id.yellow +
230
                            ` (processed in ${new Date() - start} ms)`.green);
231
                    }
232
                    
233
                });
234
            });
235
    });
236
});
237
238
app.listen(port);
239
console.log(`${timeStamp()} The API is now running on port ${port}. Full logging is ${fullLog ? 'enabled' : 'disabled'}`.green);