Skip to content

Commit c0d79fe

Browse files
committed
refs skygragon#32: update 'star' to use latest leetcode API.
Signed-off-by: Eric Wang <skygragon@gmail.com>
1 parent 88a7729 commit c0d79fe

File tree

5 files changed

+93
-41
lines changed

5 files changed

+93
-41
lines changed

lib/config.js

+11-10
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@ var h = require('./helper');
44

55
var DEFAULT_CONFIG = {
66
// usually you don't wanna change those
7-
URL_BASE: 'https://leetcode.com',
8-
URL_LOGIN: 'https://leetcode.com/accounts/login/',
9-
URL_PROBLEMS: 'https://leetcode.com/api/problems/algorithms/',
10-
URL_PROBLEM: 'https://leetcode.com/problems/$id',
11-
URL_TEST: 'https://leetcode.com/problems/$key/interpret_solution/',
12-
URL_SUBMIT: 'https://leetcode.com/problems/$key/submit/',
13-
URL_SUBMISSIONS: 'https://leetcode.com/api/submissions/$key',
14-
URL_SUBMISSION: 'https://leetcode.com/submissions/detail/$id/',
15-
URL_VERIFY: 'https://leetcode.com/submissions/detail/$id/check/',
16-
URL_STAR: 'https://leetcode.com/problems/favor/',
7+
URL_BASE: 'https://leetcode.com',
8+
URL_LOGIN: 'https://leetcode.com/accounts/login/',
9+
URL_PROBLEMS: 'https://leetcode.com/api/problems/algorithms/',
10+
URL_PROBLEM: 'https://leetcode.com/problems/$id',
11+
URL_TEST: 'https://leetcode.com/problems/$key/interpret_solution/',
12+
URL_SUBMIT: 'https://leetcode.com/problems/$key/submit/',
13+
URL_SUBMISSIONS: 'https://leetcode.com/api/submissions/$key',
14+
URL_SUBMISSION: 'https://leetcode.com/submissions/detail/$id/',
15+
URL_VERIFY: 'https://leetcode.com/submissions/detail/$id/check/',
16+
URL_FAVORITES: 'https://leetcode.com/list/api/questions',
17+
URL_FAVORITE_DELETE: 'https://leetcode.com/list/api/questions/$hash/$id',
1718

1819
// but you will want change these
1920
LANG: 'cpp', // avail: [c,cpp,csharp,golang,java,javascript,python,ruby,swift]

lib/core.js

+14-4
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ core.starProblem = function(problem, starred, cb) {
111111
return cb(null, starred);
112112
}
113113

114-
client.starProblem(problem, starred, cb);
114+
var user = core.getUser();
115+
client.starProblem(user, problem, starred, cb);
115116
};
116117

117118
core.exportProblem = function(problem, f, codeOnly) {
@@ -148,10 +149,19 @@ core.login = function(user, cb) {
148149
client.login(user, function(e, user) {
149150
if (e) return cb(e);
150151

151-
self.logout();
152+
client.getFavorites(function(e, favorites) {
153+
if (e) return cb(e);
154+
self.logout();
155+
156+
// TODO: pick other useful values from favorites
157+
var favorite = _.find(favorites.favorites.private_favorites, function(f) {
158+
return f.name === 'Favorite';
159+
});
160+
user.hash = favorite.id_hash;
152161

153-
saveUser(user);
154-
return cb(null, user);
162+
saveUser(user);
163+
return cb(null, user);
164+
});
155165
});
156166
};
157167

lib/leetcode_client.js

+40-13
Original file line numberDiff line numberDiff line change
@@ -46,27 +46,27 @@ function checkError(e, resp, expectedStatus, msg) {
4646
// expired immediately. In that case we will try to re-login in
4747
// the backend to give a seamless user experience.
4848
function requestWithReLogin(opts, cb) {
49-
request(opts, function(e, resp, body) {
49+
var req = request(opts, function(e, resp, body) {
5050
e = checkError(e, resp, opts.expectedStatus);
5151

5252
// not 403: transparently pass down
5353
if (!config.AUTO_LOGIN || !e || e.statusCode !== 403)
54-
return cb(e, resp, body);
54+
return cb(e, resp, body, req);
5555

5656
// if 403: try re-login
5757
log.debug('session expired, auto re-login...');
5858

5959
var core = require('./core');
6060
var user = core.getUser();
6161
core.login(user, function(e2, user) {
62-
if (e2) return cb(e, resp, body);
62+
if (e2) return cb(e, resp, body, req);
6363

6464
log.debug('login successfully, cont\'d...');
6565
signOpts(opts, user);
6666

67-
request(opts, function(e, resp, body) {
67+
req = request(opts, function(e, resp, body) {
6868
e = checkError(e, resp, opts.expectedStatus);
69-
return cb(e, resp, body);
69+
return cb(e, resp, body, req);
7070
});
7171
});
7272
});
@@ -215,6 +215,19 @@ leetcodeClient.login = function(user, cb) {
215215
});
216216
};
217217

218+
leetcodeClient.getFavorites = function(cb) {
219+
var opts = makeOpts();
220+
opts.method = 'GET';
221+
opts.url = config.URL_FAVORITES;
222+
223+
requestWithReLogin(opts, function(e, resp, body) {
224+
if (e) return cb(e);
225+
226+
var favorites = JSON.parse(body);
227+
return cb(null, favorites);
228+
});
229+
};
230+
218231
function verifyResult(opts, jobs, results, cb) {
219232
if (jobs.length === 0)
220233
return cb(null, results);
@@ -305,18 +318,32 @@ leetcodeClient.submitProblem = function(problem, cb) {
305318
});
306319
};
307320

308-
leetcodeClient.starProblem = function(problem, starred, cb) {
309-
var opts = makeOpts(config.URL_STAR);
310-
opts.method = (starred ? 'POST' : 'DELETE');
321+
leetcodeClient.starProblem = function(user, problem, starred, cb) {
322+
var opts = makeOpts(null, 204);
323+
if (starred) {
324+
opts.url = config.URL_FAVORITES;
325+
opts.method = 'POST';
326+
opts.json = true;
327+
opts.body = {
328+
'favorite_id_hash': user.hash,
329+
'question_id': problem.id
330+
};
331+
} else {
332+
opts.url = config.URL_FAVORITE_DELETE
333+
.replace('$hash', user.hash)
334+
.replace('$id', problem.id);
335+
opts.method = 'DELETE';
336+
}
311337
opts.headers.Origin = config.URL_BASE;
312338
opts.headers.Referer = problem.link;
313-
opts.json = true;
314-
opts.body = {'qid': problem.id};
315339

316-
requestWithReLogin(opts, function(e, resp, body) {
317-
if (e) return cb(e);
340+
requestWithReLogin(opts, function(e, resp, body, req) {
341+
// FIXME: not sure why we hit HPE_INVALID_CONSTANT error?
342+
if (req && req.response && req.response.statusCode === 204)
343+
return cb(null, starred);
318344

319-
cb(null, body.is_favor);
345+
if (e) return cb(e);
346+
cb(null, starred);
320347
});
321348
};
322349

test/test_core.js

+19-6
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,17 @@ describe('core', function() {
3030

3131
describe('#user', function() {
3232
var USER = {name: 'test-user', pass: 'password'};
33-
var SAFE_USER = {name: 'test-user'};
33+
var USER_AFTER = {name: 'test-user', pass: 'password', hash: 'abcdef'};
34+
var USER_AFTER_SAFE = {name: 'test-user', hash: 'abcdef'};
35+
36+
var FAVORITES = {
37+
'favorites': {
38+
'private_favorites': [{
39+
'id_hash': 'abcdef',
40+
'name': 'Favorite'
41+
}]
42+
}
43+
};
3444

3545
it('should login ok', function(done) {
3646
config.AUTO_LOGIN = true;
@@ -42,13 +52,16 @@ describe('core', function() {
4252
client.login = function(user, cb) {
4353
return cb(null, user);
4454
};
55+
client.getFavorites = function(cb) {
56+
return cb(null, FAVORITES);
57+
};
4558

4659
core.login(USER, function(e, user) {
4760
assert.equal(e, null);
48-
assert.deepEqual(USER, user);
61+
assert.deepEqual(user, USER_AFTER);
4962

5063
// after login
51-
assert.deepEqual(core.getUser(), user);
64+
assert.deepEqual(core.getUser(), USER_AFTER);
5265
assert.equal(core.isLogin(), true);
5366
done();
5467
});
@@ -64,8 +77,8 @@ describe('core', function() {
6477

6578
core.login(USER, function(e, user) {
6679
assert.equal(e, null);
67-
assert.deepEqual(USER, user);
68-
assert.deepEqual(SAFE_USER, core.getUser());
80+
assert.deepEqual(user, USER_AFTER);
81+
assert.deepEqual(core.getUser(), USER_AFTER_SAFE);
6982
assert.equal(core.isLogin(), true);
7083
done();
7184
});
@@ -262,7 +275,7 @@ describe('core', function() {
262275

263276
describe('#starProblem', function() {
264277
it('should starProblem ok', function(done) {
265-
client.starProblem = function(problem, starred, cb) {
278+
client.starProblem = function(user, problem, starred, cb) {
266279
return cb(null, starred);
267280
};
268281

test/test_leetcode_client.js

+9-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var config = require('../lib/config');
77
var core = require('../lib/core');
88

99
describe('leetcode_client', function() {
10+
var USER = {hash: 'abcdef'};
1011
var PROBLEM = {
1112
id: 389,
1213
name: 'Find the Difference',
@@ -372,10 +373,10 @@ describe('leetcode_client', function() {
372373
describe('#starProblem', function() {
373374
it('should star ok', function(done) {
374375
nock('https://leetcode.com')
375-
.post('/problems/favor/')
376-
.reply(200, '{"is_favor": true}');
376+
.post('/list/api/questions')
377+
.reply(204, '');
377378

378-
client.starProblem(PROBLEM, true, function(e, starred) {
379+
client.starProblem(USER, PROBLEM, true, function(e, starred) {
379380
assert.equal(e, null);
380381
assert.equal(starred, true);
381382
done();
@@ -384,10 +385,10 @@ describe('leetcode_client', function() {
384385

385386
it('should unstar ok', function(done) {
386387
nock('https://leetcode.com')
387-
.delete('/problems/favor/')
388-
.reply(200, '{"is_favor": false}');
388+
.delete('/list/api/questions/abcdef/389')
389+
.reply(204, '');
389390

390-
client.starProblem(PROBLEM, false, function(e, starred) {
391+
client.starProblem(USER, PROBLEM, false, function(e, starred) {
391392
assert.equal(e, null);
392393
assert.equal(starred, false);
393394
done();
@@ -396,10 +397,10 @@ describe('leetcode_client', function() {
396397

397398
it('should star fail if http error', function(done) {
398399
nock('https://leetcode.com')
399-
.post('/problems/favor/')
400+
.post('/list/api/questions')
400401
.replyWithError('unknown error!');
401402

402-
client.starProblem(PROBLEM, true, function(e, starred) {
403+
client.starProblem(USER, PROBLEM, true, function(e, starred) {
403404
assert.equal(e.message, 'unknown error!');
404405
done();
405406
});

0 commit comments

Comments
 (0)