Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions lib/commands/contest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use strict';
var _ = require('underscore');

var h = require('../helper');
var chalk = require('../chalk');
var icon = require('../icon');
var log = require('../log');
var core = require('../core');

const cmd = {
command: 'contest [keyword]',
aliases: ['contests'],
desc: 'Solve questions from a contest',
builder: function(yargs) {
return yargs
.positional('keyword', {
type: 'string',
default: '',
describe: 'Filter contests by keyword'
})
.example(chalk.yellow('leetcode contest'), 'List all contests')
.example(chalk.yellow('leetcode contest weekly-contest-155'), 'List questions from a contest');
}
};

cmd.handler = function(argv) {
let keyword = argv.keyword;
log.debug('argv: ' + keyword);
if (keyword.length > 0) {
// Show questions of a specific contest
core.getContestQuestions(keyword, function(e, questions) {
if (e) return log.fail(e);

for (let q of questions) {
log.printf('%-60s (%s)',
q.name,
q.slug
);
}
});
} else {
// List all contests
core.getContests(function(e, contests) {
if (e) return log.fail(e);

for (let c of contests) {
log.printf('%s (%s)',
c.title,
c.titleSlug
);
}
});
}
};

module.exports = cmd;
1 change: 1 addition & 0 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const DEFAULT_CONFIG = {
base: 'https://leetcode.com',
graphql: 'https://leetcode.com/graphql',
login: 'https://leetcode.com/accounts/login/',
contest: 'https://leetcode.com/contest/api/info/$slug',
problems: 'https://leetcode.com/api/problems/$category/',
problem: 'https://leetcode.com/problems/$slug/description/',
test: 'https://leetcode.com/problems/$slug/interpret_solution/',
Expand Down
8 changes: 8 additions & 0 deletions lib/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,12 @@ core.exportProblem = function(problem, opts) {
return file.render(opts.tpl, data);
};

core.getContests = function(cb) {
core.next.getContests(cb);
};

core.getContestQuestions = function(titleSlug, cb) {
core.next.getContestQuestions(titleSlug, cb);
};

module.exports = core;
63 changes: 63 additions & 0 deletions lib/plugins/leetcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,69 @@ plugin.init = function() {
config.app = 'leetcode';
}

plugin.getContests = function(cb) {
log.debug('running leetcode.getContests');

const opts = plugin.makeOpts(config.sys.urls.graphql);
opts.headers.Origin = config.sys.urls.base;
opts.headers.Referer = config.sys.urls.base;
opts.json = true;
opts.body = {
query: [
'{',
' allContests {',
' containsPremium',
' title',
' titleSlug',
' }',
'}',
].join('\n'),
variables: {}
};

const spin = h.spin('Fetching contests');
request.post(opts, function(e, resp, body) {
spin.stop();
e = plugin.checkError(e, resp, 200);
if (e) return cb(e);

const contests = body.data.allContests;
return cb(null, contests.reverse());
});
};

plugin.getContestQuestions = function(titleSlug, cb) {
log.debug('running leetcode.getContest');
const opts = plugin.makeOpts(config.sys.urls.contest.replace('$slug', titleSlug));

// TODO add spin text
request(opts, function(e, resp, body) {
e = plugin.checkError(e, resp, 200);
if (e) return cb(e);

const json = JSON.parse(body);
const questions = json.questions
.map(function(p) {
return {
id: p.id,
fid: p.question_id,
name: p.title,
slug: p.title_slug,
credit: p.credit,
};
});

return cb(null, questions);
});

// spin = h.spin('Downloading problems');
// const q = new Queue(config.sys.categories, {}, getCategory);
// q.run(null, function(e) {
// spin.stop();
// return cb(e, problems);
// });
}

plugin.getProblems = function(cb) {
log.debug('running leetcode.getProblems');
let problems = [];
Expand Down
1 change: 1 addition & 0 deletions test/mock/weekly-contest-sample.20190926.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"contest":{"id":245,"title":"Weekly Contest 155","title_slug":"weekly-contest-155","description":"<style>\r\n.contest-information ol:not(.list-group) {\r\n padding-left: 20px;\r\n}\r\n.contest-information ul:not(.list-group) {\r\n padding-left: 20px;\r\n}\r\n.contest-information li:not(.list-group-item) {\r\n margin-top: 5px;\r\n}\r\n\r\n.contest-information .list-group .list-group-item {\r\n border: none;\r\n margin-bottom: 1px;\r\n}\r\n.contest-information img[alt=\"LeetCoin\"] {\r\n position: relative;\r\n top: -2px;\r\n}\r\n</style>\r\n\r\n<div class=\"contest-information container\">\r\n <div class=\"row\">\r\n <div class=\"col-sm-8 col-md-9\">\r\n <h3 class=\"text-300\">\r\n Welcome to the 155th LeetCode Weekly Contest\r\n </h3>\r\n <br>\r\n <h4 class=\"text-300\">\r\n <i class=\"fa fa-newspaper-o\" style=\"color: #1DA09C\" aria-hidden=\"true\"></i>\r\n &nbsp;Important Note\r\n </h4>\r\n <ol>\r\n <li>\r\n The penalty time has been changed from <b>10</b> minutes to <b>5</b> minutes for each wrong submission.\r\n </li>\r\n <li>\r\n All submissions will be run through a plagiarism checker. Any detected plagiarism will result in <b>immediate disqualification</b> + <b>3 weeks</b> account ban. Cheating will <b>NOT</b> be tolerated in any way, shape, or form. Please read the <a href=\"/contest/faq/\" target=\"_blank\">Contest FAQ</a> for more information.\r\n </li>\r\n </ol>\r\n <br><br>\r\n <h4 class=\"text-300\">\r\n <i class=\"fa fa-bullhorn\" style=\"color: #FEA116\" aria-hidden=\"true\"></i>\r\n &nbsp;Announcement\r\n </h4>\r\n <p>\r\n Users <b class=\"text-orange\">must register</b> to participate. We hope you enjoy this contest!\r\n </p>\r\n <br>\r\n <a href=\"https://leetcode.com/discuss/general-discussion/386455/\" target=\"_blank\">\r\n <img src=\"https://assets.leetcode.com/uploads/2019/09/20/wc_155_discuss.png\" style=\"width:250px; border-radius: 10px; margin: 10px 0;\"/>\r\n </a>\r\n </div>\r\n <div class=\"col-sm-4 col-md-3\">\r\n <h3 class=\"text-300\">\r\n <i class=\"fa fa-trophy text-orange\" aria-hidden=\"true\"></i>\r\n &nbsp;Prize\r\n </h3>\r\n <ul class=\"list-group\" style=\"margin-top: 20px\">\r\n <li class=\"list-group-item\">\r\n <b>1st</b>\r\n <span class=\"pull-right\">\r\n 5,000 <a href=\"/points/\" target=\"_blank\"><img src=\"/static/images/LeetCoin.png\" height=\"15px\" alt=\"LeetCoin\"></a>\r\n </span>\r\n </li>\r\n <li class=\"list-group-item\">\r\n <b>2nd</b>\r\n <span class=\"pull-right\">\r\n 2,500 <a href=\"/points/\" target=\"_blank\"><img src=\"/static/images/LeetCoin.png\" height=\"15px\" alt=\"LeetCoin\"></a>\r\n </span>\r\n </li>\r\n <li class=\"list-group-item\">\r\n <b>3rd</b>\r\n <span class=\"pull-right\">\r\n 1,000 <a href=\"/points/\" target=\"_blank\"><img src=\"/static/images/LeetCoin.png\" height=\"15px\" alt=\"LeetCoin\"></a>\r\n </span>\r\n </li>\r\n <li class=\"list-group-item\">\r\n <b>4</b> - <b>50th</b>\r\n <span class=\"pull-right\">\r\n 300 <a href=\"/points/\" target=\"_blank\"><img src=\"/static/images/LeetCoin.png\" height=\"15px\" alt=\"LeetCoin\"></a>\r\n </span>\r\n </li>\r\n <li class=\"list-group-item\">\r\n <b>51</b> - <b>100th</b>\r\n <span class=\"pull-right\">\r\n 100 <a href=\"/points/\" target=\"_blank\"><img src=\"/static/images/LeetCoin.png\" height=\"15px\" alt=\"LeetCoin\"></a>\r\n </span>\r\n </li>\r\n <li class=\"list-group-item\">\r\n <b>101</b> - <b>200th</b>\r\n <span class=\"pull-right\">\r\n 50 <a href=\"/points/\" target=\"_blank\"><img src=\"/static/images/LeetCoin.png\" height=\"15px\" alt=\"LeetCoin\"></a>\r\n </span>\r\n </li>\r\n <li class=\"list-group-item\">\r\n <b>Participate</b>\r\n <span class=\"pull-right\">\r\n 5 <a href=\"/points/\" target=\"_blank\"><img src=\"/static/images/LeetCoin.png\" height=\"15px\" alt=\"LeetCoin\"></a>\r\n </span>\r\n </li>\r\n <li class=\"list-group-item\">\r\n <b>First Time Participate</b>\r\n <span class=\"pull-right\">\r\n 200 <a href=\"/points/\" target=\"_blank\"><img src=\"/static/images/LeetCoin.png\" height=\"15px\" alt=\"LeetCoin\"></a>\r\n </span>\r\n </li>\r\n <li class=\"list-group-item\">\r\n<span style=\"\r\n position: absolute;\r\n color: rgb(245, 0, 87);\r\n font-size: 10px;\r\n transform: translate(-8px, -9px);\r\n\">NEW</span>\r\n <b>Participate Biweekly + Weekly Contests in Same Week</b>\r\n <span class=\"pull-right\">\r\n 100 <a href=\"/points/\" target=\"_blank\"><img src=\"/static/images/LeetCoin.png\" height=\"15px\" alt=\"LeetCoin\"></a>\r\n </span>\r\n </li>\r\n </ul>\r\n </div>\r\n </div>\r\n</div>\r\n<hr>\r\n<p><b>Want millions of LeetCode users to <i>recognize your company</i>? <a href=\"mailto:[email protected]\" target=\"_href\">Contact us</a> to sponsor a contest.</b></p>","duration":5400,"start_time":1569119400,"is_virtual":false,"origin_start_time":1569119400,"is_private":false,"related_contest_title":null},"questions":[{"id":974,"question_id":1306,"credit":3,"title":"Minimum Absolute Difference","title_slug":"minimum-absolute-difference"},{"id":975,"question_id":1307,"credit":4,"title":"Ugly Number III","title_slug":"ugly-number-iii"},{"id":976,"question_id":1308,"credit":5,"title":"Smallest String With Swaps","title_slug":"smallest-string-with-swaps"},{"id":977,"question_id":1309,"credit":8,"title":"Sort Items by Groups Respecting Dependencies","title_slug":"sort-items-by-groups-respecting-dependencies"}],"user_num":4979,"has_chosen_contact":false,"company":{"name":"LeetCode","description":"LeetCode's mission is to create the best code learning platform helping students and engineers to land on their dream jobs. For more information please see <a href=\"/jobs\">our Jobs page</a>.","logo":"https://assets.leetcode.com/contest/LeetCode/company_logo"},"registered":false,"containsPremium":false}
18 changes: 18 additions & 0 deletions test/plugins/test_leetcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,24 @@ describe('plugin:leetcode', function() {
});
}); // #login

describe('#getContests', function() {
// TODO
}); // #getContests

describe('#getContestQuestions', function() {
it('should ok', function(done) {
nock('https://leetcode.com')
.get('/contest/api/info/weekly-contest-155')
.replyWithFile(200, './test/mock/weekly-contest-sample.20190926.json');

plugin.getContestQuestions('weekly-contest-155', function(e, questions) {
assert.equal(e, null);
assert.equal(questions.length, 4);
done();
});
});
});

describe('#getProblems', function() {
it('should ok', function(done) {
nock('https://leetcode.com')
Expand Down