diff --git a/README.md b/README.md
index 421baef..d3cde5a 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ A simple and useful Command Line tool for Codeforces coders
## Releases
#### Work in progress
-
+
## Inspirations
- [Codeforces API](http://codeforces.com/api/help)
diff --git a/package.json b/package.json
index b1b9d6a..95c62ff 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,12 @@
"single": "./node_modules/.bin/nyc ./node_modules/.bin/mocha --compilers js:babel-register \"tests/crawler/test_ratings.js\" & npm run cov-html"
},
"nyc": {
- "include": ["src/lib/crawler/*.js", "src/lib/api/*.js", "src/lib/utils/*.js", "tests/**/*.js"]
+ "include": [
+ "src/lib/crawler/*.js",
+ "src/lib/api/*.js",
+ "src/lib/utils/*.js",
+ "tests/**/*.js"
+ ]
},
"repository": {
"type": "git",
diff --git a/src/bin/cli/cf.js b/src/bin/cli/cf.js
index fb8635e..1e060e5 100644
--- a/src/bin/cli/cf.js
+++ b/src/bin/cli/cf.js
@@ -17,9 +17,31 @@ program
.version(version)
.usage('[options] [command]');
+program.on('--help', () => {
+ log(' All options:');
+ log(' -r, --remember save/update handle');
+ log(' -c, --count total items to fetch and show');
+ log(' -w, --watch watch submission status live');
+ log(' -p, --problem also download problem statement');
+ log(' -u, --user codeforces user handle');
+ log(' -l, --language programming language id of the solution');
+ log(' -d, --directory directory to save solutions');
+ log(' --logout delete saved password');
+ log(' --gym gym problem submit');
+ log(' --no-chart disable showing chart of user rating');
+ log(' --org show Organization of users');
+ log(' --unofficial unofficial standings');
+ log(' --handles comma separated codeforces handles');
+ log(' --offset offset of the items to fetch from');
+ log(' --limit maximum number of simultaneous downloads');
+ log(' --country country name for rating');
+ log(' --delay refreshing delay of live submission status [in millisecond]');
+ log(' --contest specific contest submissions');
+});
+
program
.command('runs')
- .option('-r, --remember', 'save handle for future')
+ .option('-r, --remember', 'save/update handle')
.option('-c, --count ', 'total submission status to display')
.option('-w, --watch', 'watch submission status live')
.option('--delay ', 'refreshing delay of live submission status [in millisecond]')
@@ -104,10 +126,10 @@ program
program
.command('rating')
- .option('-u, --user ', 'user handle for rating')
+ .option('-u, --user ', 'codeforces user handle')
.option('--country ', 'country name for rating')
- .option('--no-chart', 'disable showing chart for user')
- .option('--org', 'show Organization for country rating')
+ .option('--no-chart', 'disable showing chart of user rating')
+ .option('--org', 'show Organization of users')
.description('user ratings')
.action( (prg) => {
@@ -129,7 +151,7 @@ program
program
.command('tags')
- .description('all tags and problem quantity')
+ .description('all tags distribution')
.action( () => {
CF.tags();
});
@@ -187,7 +209,7 @@ program
.command('solutions ')
.option('-d, --directory ','directory to save solutions')
.option('-p, --problem','also download problem statement')
- .option('--limit ','limit async task')
+ .option('--limit ','maximum number of simultaneous downloads')
.description('user solution download')
.action( (handle,prg) => {
@@ -209,7 +231,7 @@ program
program
.command('standings ')
.description('contest standings')
- .option('--handles ', 'handles for standings')
+ .option('--handles ', 'comma separated codeforces handles')
.option('--country ', 'country name for standings')
.option('-c, --count ', 'total standings to display')
.option('--offset ', 'standings offset')
@@ -266,7 +288,7 @@ if( !program.args.length && has(program,'help') ){
// https://github.com/tj/programer.js/issues/57
//
if (!program.args.length) {
- figlet('Codeforces CLI',{ font: 'ANSI Shadow' }, (err, data) => {
+ figlet('Codeforces CLI', (err, data) => {
log('');
log('');
if(!err){
@@ -279,19 +301,18 @@ if (!program.args.length) {
//warn aboud invalid programs
var validprograms = program.commands.map(function(cmd){
- return cmd.name;
+ return cmd._name;
});
- var invalidprograms = program.args.filter(function(cmd){
- //if program executed it will be an object and not a string
- return (typeof cmd === 'string' && validprograms.indexOf(cmd) === -1 );
+ var invalidprograms = program.args.map(function(cmd){
+ return cmd._name;
});
-
-
if (invalidprograms.length) {
- // log('\n [ERROR] - Invalid program: "%s". See "--help" for a list of available programs.\n', invalidprograms.join(', '));
+ log('');
+ log(` [ERROR] - Invalid command: ${invalidprograms.join(', ')}. run "cf --help" for a list of available commands.`);
+ log('');
}
}
*/
diff --git a/src/lib/api/Userrating.js b/src/lib/api/Userrating.js
index d944dee..b1c3607 100644
--- a/src/lib/api/Userrating.js
+++ b/src/lib/api/Userrating.js
@@ -5,6 +5,7 @@ import ora from 'ora';
import Table from 'cli-table2';
import chalk from 'chalk';
import qs from 'qs';
+import has from 'has';
import forEach from 'lodash/forEach';
import * as contrib from 'blessed-contrib';
import blessed from 'blessed';
@@ -50,33 +51,28 @@ export default class Userrating {
if (err) {
spinner.fail();
- logr('Failed [Request]');
- return;
+ return logr('Failed [Request]');
}
- if (response.statusCode !== 200) {
+ let {statusCode} = response;
+ if (statusCode !== 200) {
spinner.fail();
- logr('Failed HTTP');
- return;
+ return logr( has(body,'comment') ? body.comment : `HTTP Failed with status ${statusCode}`);
}
let contentType = response.headers['content-type'];
if (contentType.indexOf('application/json') === -1) {
spinner.fail();
- logr('Failed.Not valid data.');
- return;
+ return logr('Failed.Not valid data.');
}
if (body.status !== 'OK') {
spinner.fail();
- logr(body.comment);
- return;
+ return logr(body.comment);
}
-
spinner.succeed();
if ( self.noChart ) {
-
let table = new Table({
head: [CB('Contest'), CB('Rank'), CB('Rating change'), CB('New rating')]
});
@@ -90,8 +86,7 @@ export default class Userrating {
]);
});
- log(table.toString());
- return;
+ return log(table.toString());
}
let axisX = [];
diff --git a/src/lib/api/standings.js b/src/lib/api/standings.js
index dac3580..0edbeae 100644
--- a/src/lib/api/standings.js
+++ b/src/lib/api/standings.js
@@ -54,120 +54,104 @@ export default ({ contestId = null, count = 200, unofficial = false, from = 1, h
spinner.start();
/* istanbul ignore next */
- request
- .get(reqOptions)
- .on('error', (err) => {
-
- debugs('Failed: Request error');
- debugs(err);
-
- logr(err);
- })
- .on('complete', () => {
-
- debugs('parsing completed');
-
- if( responseCode !== 200 ){
- log('a ' + responseCode);
- spinner.fail();
- if( apiMsg !== null ){
- return logr(apiMsg);
- }
- return logr('Failed HTTP');
- }
-
- if( contentType.indexOf('application/json;') === -1 ){
- spinner.fail();
- return logr('Failed.Not valid data.');
- }
-
- if( apiFailed ){
- spinner.fail();
- return logr(apiMsg);
- }
-
- spinner.succeed();
-
- let head = [ GB('Rank'), GB('Who'), GB('Points'), GB('Hacks') ];
- forEach(problemSet, prb => {
- head.push( GB(prb.index) );
- });
- table.options.head = head;
-
- log('');
- log( CB(` Title: ${contestInfo.name}`) );
- log( CB(` Type : ${contestInfo.type}`) );
- log( CB(` Phase: ${contestInfo.phase}`) );
- log(table.toString());
-
- })
- .on('response', (response) => {
-
- responseCode = response.statusCode;
- contentType = response.headers['content-type'];
-
- log(responseCode);
-
- debugs(`HTTP Code: ${responseCode}`);
- debugs(`Content-Type: ${contentType}`);
- })
- .pipe( JSONStream.parse('result.rows.*') )
- .on('header', (data) => {
-
- debugs(`API Status: ${data.status}`);
-
- if( data.status !== 'OK' ){
- apiFailed = true;
- apiMsg = data.comment;
- return;
- }
- contestInfo = data.contest;
- problemSet = data.problems;
- })
- .on('data', (data) => {
-
- let hacks = '';
-
- if( data.successfulHackCount > 0 ){
- hacks = `+${data.successfulHackCount.toString()}`;
+ let reqStream = request.get(reqOptions);
+ let jsonStream = reqStream.pipe( JSONStream.parse('result.rows.*') );
+
+ reqStream.on('error', (err) => {
+ debugs('Failed: Request error');
+ logr(err);
+ });
+
+ reqStream.on('complete', () => {
+ debugs('parsing completed');
+
+ if( responseCode !== 200 ){
+ spinner.fail();
+ return logr(apiMsg || `HTTP Failed with status ${responseCode}`);
+ }
+
+ if( contentType.indexOf('application/json;') === -1 ){
+ spinner.fail();
+ return logr('Failed.Invalid data.');
+ }
+
+ if( apiFailed ){
+ spinner.fail();
+ return logr(apiMsg || 'Unknown error.[Report?]');
+ }
+ spinner.succeed();
+
+ let head = [ GB('Rank'), GB('Who'), GB('Points'), GB('Hacks') ];
+ forEach(problemSet, prb => {
+ head.push( GB(prb.index) );
+ });
+ table.options.head = head;
+
+ log('');
+ log( CB(` Title: ${contestInfo.name}`) );
+ log( CB(` Type : ${contestInfo.type}`) );
+ log( CB(` Phase: ${contestInfo.phase}`) );
+ log(table.toString());
+ });
+
+ reqStream.on('response', (response) => {
+ responseCode = response.statusCode;
+ contentType = response.headers['content-type'];
+
+ debugs(`HTTP Code: ${responseCode}`);
+ debugs(`Content-Type: ${contentType}`);
+ });
+
+ jsonStream.on('header', (data) => {
+ debugs(`API Status: ${data.status}`);
+
+ if( data.status !== 'OK' ){
+ apiFailed = true;
+ apiMsg = data.comment;
+ return;
+ }
+ contestInfo = data.contest;
+ problemSet = data.problems;
+ });
+
+ jsonStream.on('data', (data) => {
+ let hacks = '';
+
+ if( data.successfulHackCount > 0 ){
+ hacks = `+${data.successfulHackCount.toString()}`;
+ }
+
+ if( data.unsuccessfulHackCount > 0 ){
+ hacks = `${hacks} : -${data.unsuccessfulHackCount.toString()}`; // +x : -y
+ }
+
+ /**********TO-DO*************/
+ // handle Multiple members (team)
+ //
+ let chunk = [data.rank.toString(), CB(data.party.members[0].handle), data.points.toString(), hacks];
+
+ let results = map(data.problemResults, (result) => {
+
+ if( result.points === 0 && result.rejectedAttemptCount > 0 ){
+ return RB(`-${result.rejectedAttemptCount.toString()}`);
}
-
- if( data.unsuccessfulHackCount > 0 ){
- hacks = `${hacks} : -${data.unsuccessfulHackCount.toString()}`;
+ else if( result.points === 0 && result.rejectedAttemptCount === 0 ){
+ return '';
}
- /**********TO-DO*************/
- // handle Multiple members (team)
- //
- let chunk = [
- data.rank.toString(),
- CB(data.party.members[0].handle),
- data.points.toString(),
- hacks
- ];
-
+ let subSecond = duration(result.bestSubmissionTimeSeconds, 'seconds');
+ let h = parseInt(subSecond.hours(),10);
+ let s = parseInt(subSecond.minutes(),10);
+ let subTime = `${Math.floor(h/10)}${h%10}:${Math.floor(s/10)}${s%10}`;
- let results = map(data.problemResults, (result) => {
-
- if( result.points === 0 && result.rejectedAttemptCount > 0 ){
- return RB(`-${result.rejectedAttemptCount.toString()}`);
- }
- else if( result.points === 0 && result.rejectedAttemptCount === 0 ){
- return '';
- }
-
- let subSecond = duration(result.bestSubmissionTimeSeconds, 'seconds');
- let h = parseInt(subSecond.hours(),10);
- let s = parseInt(subSecond.minutes(),10);
- let subTime = `${Math.floor(h/10)}${h%10}:${Math.floor(s/10)}${s%10}`;
-
- return ` ${result.points.toString()}\n${subTime}`;
- });
-
- table.push(chunk.concat(results));
+ return ` ${result.points.toString()}\n${subTime}`;
});
+
+ table.push(chunk.concat(results));
+ });
};
+
/**
* Generate API url from given parameters
* @param {Object} options
@@ -190,6 +174,7 @@ function generateUrl(options) {
handles = split(handles,',');
param['handles'] = join(handles,';');
}
+ //else invalid handles..may be throw? currently ignore
let sp = qs.stringify(param,{ encode: false });
diff --git a/src/lib/api/submission.js b/src/lib/api/submission.js
index 8fba394..620630c 100644
--- a/src/lib/api/submission.js
+++ b/src/lib/api/submission.js
@@ -23,11 +23,9 @@ var GB = chalk.bold.green;
var RB = chalk.bold.red;
var TIME_OUT = 30000; //30 seconds
-var STATUS_DELAY = 5000; //4 seconds
+var STATUS_DELAY = 5000; //5 seconds
-/**
- *
/**
* @param {Number} count - total submisison to fetch
* @param {Boolean} remember - if true, save handle in config file
@@ -82,11 +80,10 @@ function readConfig(options, next) {
jsonfile.readFile(options.config, (err, obj) => {
let askHandle = false;
-
if( err ){
if( err.code === 'EPERM' ){
- throw new Error('Permission denied config file.');
+ throw new Error(`Permission denied.Can't read config file '${options.config}'`);
}
if( err.code !== 'ENOENT' ){
@@ -96,7 +93,6 @@ function readConfig(options, next) {
debugs('Config file not found');
askHandle = true;
}
-
spinner.stop();
if( askHandle || !has(obj,'user') ){
@@ -107,17 +103,14 @@ function readConfig(options, next) {
validate: validateEmpty
}];
- inquirer.prompt(credentials).then( (answer) => {
-
+ return inquirer.prompt(credentials).then( (answer) => {
options.handle = answer.handle;
jsonfile.writeFileSync(options.config, { user: options.handle });//save handle
return next(null, options);
});
- return;
}
- debugs('Handle found in config file');
spinner.text = `Saved handle found '${obj.user}'`;
spinner.succeed();
@@ -151,7 +144,6 @@ function getSubmission(options, next) {
spinner.text = 'Fetching submissions..';
spinner.start();
-
request
.get(reqOptions, (error, response, body) => {
@@ -161,10 +153,7 @@ function getSubmission(options, next) {
let { statusCode } = response;
if( statusCode!==200 ){
- if( has(body,'comment') ){
- return next(body.comment);
- }
- return next('HTTP error');
+ return next( has(body,'comment') ? body.comment : `HTTP failed with status ${statusCode}`);
}
if( body.status !== 'OK' ){
@@ -213,11 +202,8 @@ function watchRun(options, next) {
}
let { statusCode } = response;
- if( statusCode!==200 ){
- if( has(body,'comment') ){
- return callback(body.comment);
- }
- return callback('HTTP error');
+ if( statusCode !== 200 ){
+ return next( has(body,'comment') ? body.comment : `HTTP failed with status ${statusCode}`);
}
if( body.status !== 'OK' ){
@@ -231,22 +217,15 @@ function watchRun(options, next) {
// Still testing, Wait x seconds and get status again
//
if( keepWatching ) {
- setTimeout(() => {
+ return setTimeout(() => {
callback();
}, STATUS_DELAY);
- return;
}
return callback();
});
},
- (err) => {
- if(err){
- debugs('Error while watching');
- return next(err);
- }
- return next();
- }
+ next
);
}
@@ -273,9 +252,7 @@ function generateTable(runs, isWatch = false){
let passed = parseInt(passedTestCount,10);
who = author.members[0].handle;
- debugs(run.testset);
-
- if( verdict === undefined ){
+ if( verdict === undefined || typeof verdict != 'string' ){
done = false;
verdict = chalk.white.bold('In queue');
}
diff --git a/src/lib/api/tags.js b/src/lib/api/tags.js
index 7a1813e..e98cb50 100644
--- a/src/lib/api/tags.js
+++ b/src/lib/api/tags.js
@@ -4,6 +4,7 @@ import JSONStream from 'JSONStream';
import debug from 'debug';
import request from 'request';
import ora from 'ora';
+import has from 'has';
import _ from 'lodash';
import Table from 'cli-table2';
import chalk from 'chalk';
@@ -14,9 +15,7 @@ var spinner = ora({ spinner: 'line' });
/**
* Get all tags and quantity
- *
- * @param callback
- * if callback given, return tags, otherwise print
+ * @param callback - if callback given, return tags, otherwise print
*/
export default (callback) => {
@@ -25,146 +24,106 @@ export default (callback) => {
json: true
};
- //
- // Request validators
- //
- let apiFailed= false;
- let apiMsg = '';
- let responseCode = '404';
+ let apiMsg = null;
+ let responseCode = 404;
let contentType = '';
-
let allTags = {};
+ let isCallback = typeof callback === 'function';
spinner.text = 'Fetching all tags...';
spinner.start();
- /* istanbul ignore next */
- request
- .get(reqOptions)
- .on('error', (err) => {
-
- debugs('Failed: Request error');
- debugs(err);
+ let reqStream = request.get(reqOptions);
+ let jsonStream = reqStream.pipe( JSONStream.parse('result.problems.*') );
+
+ reqStream.on('error', (err) => {
+ debugs('Failed: Request error');
+ debugs(err);
+
+ return isCallback ? callback(err) : logr('Request connection Failed.');
+ });
+
+
+ reqStream.on('complete', () => {
+ debugs('parsing completed');
+
+ if( responseCode !== 200 ){
+ spinner.fail();
+ apiMsg = apiMsg || `HTTP Failed with status: ${responseCode}`;
+ return isCallback ? callback(apiMsg) : logr(apiMsg);
+ }
+
+ // Content not json, request failed
+ if( contentType.indexOf('application/json;') === -1 ){
+ spinner.fail();
+ apiMsg = 'Failed.Not valid data.';
+ return isCallback ? callback(apiMsg) : logr(apiMsg);
+ }
+
+ // API rejects the request
+ if( apiMsg ){
+ spinner.fail();
+ return isCallback ? callback(apiMsg) : logr(apiMsg);
+ }
+ spinner.succeed();
+
+ if(isCallback){
+ return callback(null,allTags);
+ }
+
+ // Sort tags by problem count, need to update if better way
+ allTags = _
+ .chain(allTags)
+ .map((value, key) => {
+ return {key, value};
+ })
+ .orderBy('value')
+ .reverse()
+ .keyBy('key')
+ .mapValues('value')
+ .value();
- if( typeof callback === 'function'){
- return callback(err);
- }
+ let table = new Table({
+ head: [ chalk.green('TAG'), chalk.green('Total Problem')]
+ });
- logr('Request Failed.Bug?');
+ _.forEach(allTags, (value, key) => {
+ table.push([key, value]);
+ });
- })
- .on('complete', () => {
+ log('');
+ log(chalk.bold.green(` Total tag: ${table.length}`));
+ log(table.toString());
+ });
- /**
- * Very messy code, need to update callback logic for clean code (??)
- */
- debugs('parsing completed');
+ reqStream.on('response', (response) => {
+ debugs(`HTTP Code: ${responseCode}`);
+ debugs(`Content-Type: ${contentType}`);
- let isCallback = typeof callback === 'function';
+ responseCode = response.statusCode;
+ contentType = response.headers['content-type'];
+ });
- if( responseCode !== 200 ){
- spinner.fail();
- if(isCallback){
- return callback(`Failed, HTTP status: ${responseCode}`);
- }
- logr(`Failed, HTTP status: ${responseCode}`);
- return;
- }
-
- //
- // Content not json, request failed
- //
- if( contentType.indexOf('application/json;') === -1 ){
- spinner.fail();
- if(isCallback){
- return callback('Failed.Not valid data.');
- }
- logr('Failed.Not valid data.');
- return;
- }
-
- //
- // API rejects the request
- //
- if( apiFailed ){
- spinner.fail();
- if(isCallback){
- return callback(apiMsg);
- }
- logr(apiMsg);
- return;
- }
- spinner.succeed();
+ jsonStream.on('header', (data) => {
+ debugs(`API Status: ${data.status}`);
- //
- // If callback given, return tags
- //
- if(isCallback){
- return callback(null,allTags);
- }
+ if( data.status !== 'OK' ){
+ apiMsg = data.comment || 'Unknown Error?';
+ }
+ });
- //
- // Sort tags by problem count, need to update if better way
- //
- allTags = _
- .chain(allTags)
- .map((value, key) => {
- return {key, value};
-})
- .orderBy('value')
- .reverse()
- .keyBy('key')
- .mapValues('value')
- .value();
-
- let table = new Table({
- head: [ chalk.green('TAG'), chalk.green('Total Problem')]
- });
-
- _.forEach(allTags, (value, key) => {
- table.push([key, value]);
+ jsonStream.on('data', (data) => {
+ if( has(data,'tags') ) {
+ _.forEach(data.tags, (tag) => {
+ if (has(allTags, tag)) {
+ allTags[tag]++;
+ } else {
+ allTags[tag] = 1;
+ }
});
-
- log('');
- log(chalk.bold.green(` Total tag: ${table.length}`));
- log(table.toString());
- })
- .on('response', (response) => {
-
- responseCode = response.statusCode;
- contentType = response.headers['content-type'];
-
- debugs(`HTTP Code: ${responseCode}`);
- debugs(`Content-Type: ${contentType}`);
- })
- .pipe( JSONStream.parse('result.problems.*') )
- .on('header', (data) => {
-
- debugs(`API Status: ${data.status}`);
-
- if( data.status !== 'OK' ){
- apiFailed = true;
- apiMsg = data.comment;
- }
- })
- .on('data', (data) => {
-
- // debugs('data received');
-
- //
- // If request failed, tags may not exist
- //
- if( _.has(data,'tags') ) {
- _.forEach(data.tags, (tag) => {
- if (_.has(allTags, tag)) {
- allTags[tag]++;
- } else {
- allTags[tag] = 1;
- }
- });
- }
- });
+ }
+ });
};
diff --git a/src/lib/api/userinfo.js b/src/lib/api/userinfo.js
index bea5196..13ecb72 100644
--- a/src/lib/api/userinfo.js
+++ b/src/lib/api/userinfo.js
@@ -4,22 +4,22 @@ import request from 'request';
import debug from 'debug';
import Table from 'cli-table2';
import chalk from 'chalk';
-import _ from 'lodash';
+import has from 'has';
+import { isArray, join , split, forEach } from 'lodash';
import qs from 'qs';
import ora from 'ora';
import { log, logr } from '../helpers';
var debugs = debug('CF:userinfo');
var spinner = ora({ spinner: 'line' });
-var GB = chalk.bold.green;
-
+const GB = chalk.bold.green;
/**
* @param handles
*/
export default (handles) => {
- let invalidHandle = !_.isArray(handles) && typeof handles !== 'string';
+ let invalidHandle = !isArray(handles) && typeof handles !== 'string';
if( invalidHandle ){
throw new Error('handles must be array or string');
}
@@ -30,12 +30,12 @@ export default (handles) => {
};
let handlesString = handles;
- if( _.isArray(handles) ){
- handlesString = _.join(handles,';');
+ if( isArray(handles) ){
+ handlesString = join(handles,';');
}
else if( handles.indexOf(',') !== -1 ){
- handlesString = _.split(handles,',');
- handlesString = _.join(handlesString,';');
+ handlesString = split(handles,',');
+ handlesString = join(handlesString,';');
}
let qsf = qs.stringify({ handles: handlesString }, { encode: false });
@@ -45,56 +45,50 @@ export default (handles) => {
spinner.text = 'fetching user info...';
spinner.start();
- request
- .get(reqOptions, (error, response, body) => {
+ request.get(reqOptions, (error, response, body) => {
- if(error){
- spinner.fail();
- logr(error);
- return;
- }
+ if(error){
+ spinner.fail();
+ return logr(error);
+ }
- let { statusCode } = response;
+ let { statusCode } = response;
+ if( statusCode !== 200 ){
+ spinner.fail();
+ return logr( has(body,'comment') ? body.comment : `HTTP failed with status ${statusCode}`);
+ }
- if( statusCode !== 200 ){
- spinner.fail();
- logr(body.comment || ' HTTP error');
- return;
- }
+ if( body.status !== 'OK' ){
+ spinner.fail();
+ return logr(body.comment);
+ }
+ spinner.succeed();
- if( body.status !== 'OK' ){
- spinner.fail();
- logr(` ${body.comment}`);
- return;
+ let table = new Table({
+ head: [ GB('Name'), GB('Handle'), GB('Rank'), GB('Rating'), GB('Max'), GB('Contrib.'), GB('Country'), GB('Organization') ]
+ });
+
+ forEach(body.result, (data) => {
+
+ let name = '';
+ if( has(data,'firstName') && has(data,'lastName') ){
+ name = `${data.firstName} ${data.lastName}`;
}
- spinner.succeed();
-
- let table = new Table({
- head: [ GB('Name'), GB('Handle'), GB('Rank'), GB('Rating'), GB('Max'), GB('Contrib.'), GB('Country'), GB('Organization') ]
- });
-
- _.forEach(body.result, (data) => {
-
- let name = '';
- if( _.has(data,'firstName') && _.has(data,'lastName') ){
- name = `${data.firstName} ${data.lastName}`;
- }
-
- let info = [
- name,
- data.handle || '',
- data.rank || '0',
- data.rating || '',
- data.maxRating || '',
- data.contribution || '',
- data.country || '',
- data.organization || ''
- ];
- table.push(info);
- });
-
- log('');
- log(table.toString());
+ let info = [
+ name,
+ data.handle || '',
+ data.rank || '0',
+ data.rating || '',
+ data.maxRating || '',
+ data.contribution || '',
+ data.country || '',
+ data.organization || ''
+ ];
+ table.push(info);
});
+
+ log('');
+ log(table.toString());
+ });
};
\ No newline at end of file
diff --git a/src/lib/api/usertags.js b/src/lib/api/usertags.js
index 39207ee..6ec5a9e 100644
--- a/src/lib/api/usertags.js
+++ b/src/lib/api/usertags.js
@@ -14,7 +14,7 @@ import { log, logr } from '../helpers';
import tags from './tags';
var spinner = ora({ spinner: 'line' });
-const debugs = debug('CF:usertags');
+var debugs = debug('CF:usertags');
const CB = chalk.cyan.bold;
const PROGRESS_WIDTH = 20;
@@ -69,94 +69,90 @@ function getUserTags(handle, callback) {
let apiFailed= false;
let apiMsg = null;
- let responseCode = '404';
+ let responseCode = 404;
let contentType = '';
let totalSubmissions = 0;
let totalAccepted = 0;
-
let userTags = new Map();
spinner.text = 'Fetching user tags...';
spinner.start();
- request
- .get(reqOptions)
- .on('error', (err) => {
+ let reqStream = request.get(reqOptions);
+ let jsonStream = reqStream.pipe( JSONStream.parse('result.*') );
- debugs('Failed: Request error');
- debugs(err);
+ reqStream.on('error', (err) => {
+ debugs('Failed: Request error');
+ debugs(err);
- return callback(err);
- })
- .on('complete', () => {
+ return callback(err);
+ });
- debugs('parsing completed');
+ reqStream.on('complete', () => {
+ debugs('parsing completed');
- if( responseCode !== 200 ){
- spinner.fail();
- if( apiMsg !== null ){
- return callback(apiMsg);
- }
- return callback('Connection error.Failed.');
- }
+ if( responseCode !== 200 ){
+ spinner.fail();
+ return callback(apiMsg || `HTTP failed with status ${responseCode}`);
+ }
- if( contentType.indexOf('application/json;') === -1 ){
- spinner.fail();
- return callback('Failed.Invalid data.');
- }
+ if( contentType.indexOf('application/json;') === -1 ){
+ spinner.fail();
+ return callback('Failed.Invalid data.');
+ }
- if( apiFailed ){
- spinner.fail();
- return callback(apiMsg);
- }
+ if( apiFailed ){
+ spinner.fail();
+ return callback(apiMsg);
+ }
+ spinner.succeed();
- spinner.succeed();
+ return callback(null, userTags, totalSubmissions, totalAccepted);
+ });
- return callback(null, userTags, totalSubmissions, totalAccepted);
- })
- .on('response', (response) => {
- responseCode = response.statusCode;
- contentType = response.headers['content-type'];
+ reqStream.on('response', (response) => {
+ debugs(`HTTP Code: ${responseCode}`);
+ debugs(`Content-Type: ${contentType}`);
- debugs(`HTTP Code: ${responseCode}`);
- debugs(`Content-Type: ${contentType}`);
- })
- .pipe( JSONStream.parse('result.*') )
- .on('header', (data) => {
+ responseCode = response.statusCode;
+ contentType = response.headers['content-type'];
+ });
- debugs(`API Status: ${data.status}`);
- if( data.status !== 'OK' ){
- apiFailed = true;
- apiMsg = data.comment;
- }
- })
- .on('data', (data) => {
-
- totalSubmissions++;
-
- if( has(data,'problem') && data.verdict === 'OK' ) {
-
- totalAccepted++;
-
- let prob = `${data.problem.contestId}${data.problem.index}`;
- let problemTags = data.problem.tags;
-
- forEach(problemTags, (tag) => {
- if( userTags.has(tag) ){
- let mySet = userTags.get(tag);
- mySet.add(prob);
- userTags.set(tag, mySet);
- }
- else{
- let mySet = new Set();
- mySet.add(prob);
- userTags.set(tag,mySet);
- }
- });
- }
- });
+ jsonStream.on('header', (data) => {
+ debugs(`API Status: ${data.status}`);
+
+ if( data.status !== 'OK' ){
+ apiFailed = true;
+ apiMsg = data.comment;
+ }
+ });
+
+
+ jsonStream.on('data', (data) => {
+ totalSubmissions++;
+
+ if( has(data,'problem') && data.verdict === 'OK' ) {
+ totalAccepted++;
+
+ let prob = `${data.problem.contestId}${data.problem.index}`;
+ let problemTags = data.problem.tags;
+
+ forEach(problemTags, (tag) => {
+ if( userTags.has(tag) ){
+ let mySet = userTags.get(tag);
+ mySet.add(prob);
+ userTags.set(tag, mySet);
+ }
+ else{
+ let mySet = new Set();
+ mySet.add(prob);
+ userTags.set(tag,mySet);
+ }
+ });
+ }
+ });
}
diff --git a/src/lib/crawler/Countrystandings.js b/src/lib/crawler/Countrystandings.js
index 643a6de..0b2af49 100644
--- a/src/lib/crawler/Countrystandings.js
+++ b/src/lib/crawler/Countrystandings.js
@@ -13,16 +13,13 @@ import countries from '../countries';
var debugs = debug('CF:standings:c');
var spinner = ora({ spinner: 'line' });
-var GB = chalk.bold.green;
-var CB = chalk.bold.cyan;
-var RB = chalk.bold.red;
+const TIME_OUT = 30000;
+const GB = chalk.bold.green;
+const CB = chalk.bold.cyan;
+const RB = chalk.bold.red;
+
-/*
- *********** TO-DO / FIX *********************************
- * check 702 contest, its not match with table headers
- * *******************************************************
- */
export default class Countrystandings {
/*
@@ -30,7 +27,7 @@ export default class Countrystandings {
* @param {String} country
* @param {Number} total
*/
- constructor({contestId = null, country = null, total = 50} = {}) {
+ constructor({contestId = null, country = null, total = 50, offset = 1} = {}) {
let isInvalid = contestId === null || country === null || !Number.isInteger(contestId) || typeof country !== 'string';
if (isInvalid) {
@@ -40,11 +37,13 @@ export default class Countrystandings {
this.error = null;
if (countries.indexOf(country) === -1) {
this.error = `'${country}' not found in supported country list.Please run 'cf country' to see all supported countries.`;
+ return;
}
this.contestId = contestId;
this.country = country;
this.total = total;
+ this.offset = offset;
}
@@ -55,7 +54,7 @@ export default class Countrystandings {
show(callback){
let self = this;
- if( self.error !== null ){
+ if( self.error ){
if( typeof callback === 'function' ){
return callback(self.error);
}
@@ -67,11 +66,12 @@ export default class Countrystandings {
let reqOptions = {
uri: '',
headers: headers,
- timeout: 30000
+ timeout: TIME_OUT
};
+ let head;
let table = new Table();
- var totalPage = 5;
+ var totalPage = 2;
var count = 0;
var found = 0;
var page = 1;
@@ -85,12 +85,13 @@ export default class Countrystandings {
},
(next) => {
- reqOptions.uri = `http://codeforces.com/contest/${self.contestId}/standings/page/${page}`;
-
- debugs(`Fetching from page ${page}...`);
- spinner.text = `Fetching standings - page ${page}...`;
+ let remain = (self.total - found) < 0
+ ? 0
+ : (self.total - found);
+ spinner.text = `Fetching standings - ${found} participants found,${remain} remaining...`;
spinner.start();
+ reqOptions.uri = `http://codeforces.com/contest/${self.contestId}/standings/page/${page}`;
request.get(reqOptions, (err, response, body) => {
if (err) {
@@ -99,26 +100,13 @@ export default class Countrystandings {
let {statusCode} = response;
if (statusCode !== 200) {
- return next('HTTP error');
+ return next(`HTTP failed with status ${statusCode}`);
}
-
spinner.stop();
var $ = cheerio.load(body, {decodeEntities: true});
- let standings = $('table.standings .standings-flag');
-
- standings = _.filter(standings, (stdng) => {
- return $(stdng).attr('title') === self.country;
- });
-
+ let standings = $(`table.standings .standings-flag[title="${self.country}"]`);
found += standings.length;
- let remain = (self.total - found) < 0
- ? 0
- : (self.total - found);
-
- spinner.text = `${standings.length} users found in page ${page} [${remain} remaining]`;
- spinner.start();
- spinner.succeed();
_.forEach(standings, (standing) => {
@@ -148,6 +136,9 @@ export default class Countrystandings {
else if (val.indexOf('-') !== -1) {
val = RB(val);
}
+ else{
+ val = chalk.bold.white(val);
+ }
break;
default:
if (val.indexOf(':') !== -1) {
@@ -165,6 +156,7 @@ export default class Countrystandings {
});
if (page === 1) {
+
contestName = _.replace($('.contest-name a').text(), /\s\s+/g, '');
let pg = $('.page-index');
let indxes = pg.length;
@@ -173,8 +165,19 @@ export default class Countrystandings {
totalPage = parseInt($(pg).attr('pageindex'), 10);
debugs(`Total page: ${totalPage}`);
}
- }
+ let tabHeads = $('table.standings tr')[0];
+ head = _.map( $(tabHeads).children(), (heads) => {
+ let name = _.replace( $(heads).text() , /\s\s+/g, '');
+ if( name === '#' ){
+ name = 'Rank';
+ }
+ else if( name.length > 1 && self.hasDigit(name) ){
+ name = self.splitPenalty(name, 1);
+ }
+ return GB(name);
+ });
+ }
page++;
return next();
});
@@ -197,18 +200,13 @@ export default class Countrystandings {
return;
}
- let totalProblem = table[0].length - 5;
- let problemChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
- let head = [GB('#'), GB('Rank'), GB('Who'), GB('#'), GB('*')];
-
- let problemNames = _
- .slice(problemChar, 0, totalProblem)
- .map(x => {
- return GB(x);
- });
+ let colWidths = [ null, ...(_.map(head, (hd,key) => { //bad practice? who cares! eslint, is that you??
+ return key == 1 ? 30 : null;
+ }))];
- head = head.concat(problemNames);
- table.options.head = head;
+ table.options.head = [ GB('#'), ...head ];
+ table.options.colWidths = colWidths;
+ table.options.wordWrap = true;
log('');
log(CB(`Contest: ${contestName}`));
@@ -229,4 +227,13 @@ export default class Countrystandings {
/* istanbul ignore next */
return ` ${value.substring(0, index)}\n${value.substring(index)}`;
}
+
+
+ /**
+ * Check if a string contains any digit
+ * @param val
+ */
+ hasDigit(val) {
+ return val.match(/\d+/g) != null;
+ }
}
\ No newline at end of file
diff --git a/src/lib/crawler/Ratings.js b/src/lib/crawler/Ratings.js
index bab2067..5bfa1ec 100644
--- a/src/lib/crawler/Ratings.js
+++ b/src/lib/crawler/Ratings.js
@@ -15,9 +15,9 @@ import countries from '../countries';
var spinner = ora({ spinner: 'line' });
var debugs = debug('CF:standings:c');
-var GB = chalk.bold.green;
-var CB = chalk.bold.cyan;
-var RB = chalk.bold.red;
+const GB = chalk.bold.green;
+const CB = chalk.bold.cyan;
+const RB = chalk.bold.red;
export default class Ratings {
@@ -35,14 +35,18 @@ export default class Ratings {
this.error = null;
if (countries.indexOf(country) === -1) {
- this.error = `Invalid country '${country}'.Please run command 'cf country' to see supported country list.`;
+ this.error = `Invalid country '${country}'.Please run 'cf country' to see supported country list.`;
+ return;
}
this.country = country;
this.withOrg = org;
}
- /**
+
+ /******* TO-DO ************************************************
+ * Add count and offset (and may be categorize by CF colors?)
+ **************************************************************
* @param callback
* @returns {*}
*/
@@ -50,16 +54,11 @@ export default class Ratings {
let self = this;
let isCallback = typeof callback === 'function';
- if( self.error !== null ){
- if( isCallback ){
- return callback(self.error);
- }
- logr(self.error);
- return;
+ if( self.error ){
+ return isCallback ? callback(self.error) : logr(self.error);
}
- debugs(`Fetching ratings of ${self.country}...`);
- spinner.text = `fetching top 200 user ratings of ${self.country}...`;
+ spinner.text = `fetching top few user ratings of ${self.country}...`;
spinner.start();
waterfall([
@@ -78,7 +77,7 @@ export default class Ratings {
let {statusCode} = response;
if (statusCode !== 200) {
- return next('HTTP error');
+ return next(`HTTP failed with status ${statusCode}`);
}
var $ = cheerio.load(body, {decodeEntities: true});
@@ -186,16 +185,12 @@ export default class Ratings {
let {statusCode} = response;
if (statusCode !== 200) {
- if( has(body, 'comment') ){
- return callback(body.comment);
- }
- return callback('HTTP error [org]');
+ return callback( has(body, 'comment') ? body.comment : `HTTP failed with status ${statusCode}`);
}
if (body.status !== 'OK') {
return callback(body.comment);
}
-
spinner.succeed();
forEach(body.result, (data, key) => {
diff --git a/src/lib/crawler/Sourcecode.js b/src/lib/crawler/Sourcecode.js
index c110442..4cb140b 100644
--- a/src/lib/crawler/Sourcecode.js
+++ b/src/lib/crawler/Sourcecode.js
@@ -11,13 +11,13 @@ import chalk from 'chalk';
import has from 'has';
import ora from 'ora';
import languages from '../languages';
-import { waterfall, each, eachLimit, parallel } from 'async';
+import { waterfall, eachLimit, series, eachSeries } from 'async';
import { log, logr, checkPath, commonHeaders } from '../helpers';
var debugs = debug('CF:sourcecode');
var spinner = ora({ spinner: 'line' });
-var GB = chalk.green.bold;
+const GB = chalk.green.bold;
const TIME_OUT = 60000; //1 minute
var headers = commonHeaders();
@@ -36,7 +36,7 @@ export default class Sourcecode {
constructor({handle = null, limit = 10, withProblem = false, dir = '.'} = {}) {
if (handle === null || typeof handle != 'string') {
- throw new Error(`handle should not be null or empty`);
+ throw new Error('handle should not be null or empty');
}
this.options = { handle, withProblem, limit, dir };
@@ -66,8 +66,7 @@ export default class Sourcecode {
totalSubmissions = submissions.length;
if (self.options.withProblem) {
- eachLimit(submissions, self.options.limit, self.getResource.bind(self, dir), next);
- return;
+ return eachLimit(submissions, self.options.limit, self.getResource.bind(self, dir), next);
}
eachLimit(submissions, self.options.limit, self.getOnlySource.bind(self, dir), next);
@@ -99,7 +98,6 @@ export default class Sourcecode {
createOutputDir(options, callback) {
let {dir, handle} = options;
-
waterfall([
(next) => {
if (dir !== '.') {
@@ -116,7 +114,6 @@ export default class Sourcecode {
dir = path.join(dir, handle);
}
-
spinner.text = `creating directory ${dir}`;
spinner.start();
@@ -159,85 +156,86 @@ export default class Sourcecode {
spinner.text = 'fetching submissions..';
spinner.start();
- request
- .get(reqOptions)
- .on('error', (err) => {
+ let reqStream = request.get(reqOptions);
+ let jsonStream = reqStream.pipe(JSONStream.parse('result.*'));
- debugs('Failed: Request error');
- debugs(err);
+ reqStream.on('error', (err) => {
+ debugs('Failed: Request error');
+ debugs(err);
- return callback(err);
- })
- .on('complete', () => {
+ return callback(err);
+ });
- debugs('parsing completed');
- if (responseCode !== 200) {
- if (apiMsg !== null) {
- return callback(apiMsg);
- }
- return callback('Failed HTTP');
- }
+ reqStream.on('complete', () => {
+ debugs('parsing completed');
- if (contentType.indexOf('application/json;') === -1) {
- return callback('Failed.Not valid data.');
- }
+ if (responseCode !== 200) {
+ return callback(apiMsg || `HTTP failed with status ${responseCode}`);
+ }
- if (apiFailed) {
- return callback(apiMsg);
- }
+ if (contentType.indexOf('application/json;') === -1) {
+ return callback('Failed.Not valid data.');
+ }
- spinner.stop();
- spinner.text = `total accepted submission: ${acSubmissions.length}`;
- spinner.succeed();
+ if (apiFailed) {
+ return callback(apiMsg);
+ }
- return callback(null, dir, acSubmissions);
- })
- .on('response', (response) => {
+ spinner.stop();
+ spinner.text = `total accepted submission: ${acSubmissions.length}`;
+ spinner.succeed();
- responseCode = response.statusCode;
- contentType = response.headers['content-type'];
+ return callback(null, dir, acSubmissions);
+ });
- debugs(`HTTP Code: ${responseCode}`);
- debugs(`Content-Type: ${contentType}`);
- })
- .pipe(JSONStream.parse('result.*'))
- .on('header', (data) => {
- debugs(`API Status: ${data.status}`);
+ reqStream.on('response', (response) => {
+ debugs(`HTTP Code: ${responseCode}`);
+ debugs(`Content-Type: ${contentType}`);
- if (data.status !== 'OK') {
- apiFailed = true;
- apiMsg = data.comment;
- }
- })
- .on('data', (data) => {
+ responseCode = response.statusCode;
+ contentType = response.headers['content-type'];
+ });
- // `data.contestId < 10000` is for detecting gym.Need authorization
- if (has(data, 'problem') && data.verdict === 'OK' && data.contestId < 10000) {
- let {problem, id, contestId, programmingLanguage} = data;
- let {index} = problem;
- let problemId = `${contestId}${index}`;
- let root = contestId > 10000
+ jsonStream.on('header', (data) => {
+ debugs(`API Status: ${data.status}`);
+
+ if (data.status !== 'OK') {
+ apiFailed = true;
+ apiMsg = data.comment;
+ }
+ });
+
+
+ jsonStream.on('data', (data) => {
+
+ // `data.contestId < 10000` is for detecting gym.Useless now.Need authorization
+ if (has(data, 'problem') && data.verdict === 'OK' && data.contestId < 10000) {
+
+ let {problem, id, contestId, programmingLanguage} = data;
+ let {index} = problem;
+ let problemId = `${contestId}${index}`;
+ let root = contestId > 10000
? 'gym'
: 'contest'; //currently gym not working. need authorization
- let submissionUrl = `http://codeforces.com/${root}/${contestId}/submission/${id}`;
- let problemUrl = `http://codeforces.com/${root}/${contestId}/problem/${index}`;
-
- acSubmissions.push({
- submissionId: id,
- contestId: contestId,
- problemIndex: index,
- problemId: problemId,
- submissionUrl: submissionUrl,
- problemUrl: withProblem
+ let submissionUrl = `http://codeforces.com/${root}/${contestId}/submission/${id}`;
+ let problemUrl = `http://codeforces.com/${root}/${contestId}/problem/${index}`;
+
+ acSubmissions.push({
+ submissionId: id,
+ contestId: contestId,
+ problemIndex: index,
+ problemId: problemId,
+ submissionUrl: submissionUrl,
+ problemUrl: withProblem
? problemUrl
: null,
- language: programmingLanguage
- });
- }
- });
+ language: programmingLanguage
+ });
+ }
+ });
}
/**
@@ -253,16 +251,14 @@ export default class Sourcecode {
let outputPath = path.join(dir, `${problemId}`);
let ext = languages.getExtension(language);
- parallel([
+ series([
(next) => {
-
log(GB(` fetching sourecode ${problemId}_${submissionId}`));
let filePath = path.join(outputPath, `${problemId}_${submissionId}.${ext}`);
self.getSourceCode(submissionUrl, filePath, `code ${problemId}_${submissionId}`, next);
},
(next) => {
-
log(GB(` fetching problem ${problemId}`));
let filePath = path.join(outputPath, `${problemId}.html`);
@@ -281,7 +277,7 @@ export default class Sourcecode {
return callback();
}
- each([data[0], data[1]], self.writeOutputs, callback);
+ eachSeries([data[0], data[1]], self.writeOutputs, callback);
});
}
@@ -299,9 +295,8 @@ export default class Sourcecode {
let outputPath = path.join(dir, `${problemId}`);
let ext = languages.getExtension(language);
- parallel([
+ series([
(next) => {
-
log(GB(` fetching sourecode ${problemId}_${submissionId}`));
let filePath = path.join(outputPath, `${problemId}_${submissionId}.${ext}`);
diff --git a/src/lib/crawler/Submit.js b/src/lib/crawler/Submit.js
index d6f3192..269fdfb 100644
--- a/src/lib/crawler/Submit.js
+++ b/src/lib/crawler/Submit.js
@@ -96,7 +96,7 @@ export default class Submit {
},
self.getCSRFToken,
self.login,
- self.getCSRFToken,
+ // self.getCSRFToken, //ok great, same csrf token working for both login and submit!
self.submitSolution
], (err, res) => {
@@ -116,8 +116,7 @@ export default class Submit {
spinner.fail();
return;
}
- logr(err);
- return;
+ return logr(err);
}
/* istanbul ignore next */
@@ -254,8 +253,6 @@ export default class Submit {
// Ask for handle and password
//
inquirer.prompt(credentials).then((answers) => {
-
-
options.handle = answers.handle;
options.password = answers.password;
@@ -301,13 +298,8 @@ export default class Submit {
return callback('token not found');
}
- debugs('Csrf token found!');
+ debugs(`Csrf token found! ${csrf_token}`);
- // TO-DO?
- // Next form is resistration form.This idea works only for two form
- // and hey, in this module we do not need anymore form
- // but need to keep this idea and improve!
- //
options.form = options.nextForm;
spinner.succeed();
@@ -395,7 +387,7 @@ export default class Submit {
debugs('Successfully logged in');
spinner.succeed();
- return callback(null, options);
+ return callback(null, csrf_token, options);
});
}
@@ -472,8 +464,6 @@ export default class Submit {
return callback('Error: Submission failed.Please check your options.');
}
- debugs('Solution submitted!');
-
spinner.succeed();
spinner.text = chalk.bold.green(`Submitted at ${location.date}`);
spinner.start();
diff --git a/tests/api/test_submission.js b/tests/api/test_submission.js
index 4ddb33f..1c90810 100644
--- a/tests/api/test_submission.js
+++ b/tests/api/test_submission.js
@@ -222,7 +222,7 @@ describe('Codeforces', function() {
expect(jsonfile.writeFileSync.called).to.be.false;
expect(request.get.called).to.be.true;
expect(helpers.logr.called).to.false;
- expect(err).to.equal('HTTP error');
+ expect(err).to.equal('HTTP failed with status 404');
done();
});
}});
@@ -242,7 +242,7 @@ describe('Codeforces', function() {
expect(jsonfile.writeFileSync.called).to.be.false;
expect(request.get.called).to.be.true;
expect(helpers.logr.called).to.false;
- expect(err).to.equal('HTTP error');
+ expect(err).to.equal('HTTP failed with status 404');
done();
});
}});
diff --git a/tests/crawler/test_countrystandings.js b/tests/crawler/test_countrystandings.js
index c138f6c..1dde27e 100644
--- a/tests/crawler/test_countrystandings.js
+++ b/tests/crawler/test_countrystandings.js
@@ -133,7 +133,7 @@ describe('Codeforces',function () {
new Countrystandings({ contestId: 10, country: 'Bangladesh', total: 1 }).show(function (err) {
expect(request.get.called).to.be.true;
expect(helpers.logr.called).to.be.false;
- expect(err).to.equal(`HTTP error`);
+ expect(err).to.equal(`HTTP failed with status 404`);
done();
});
});
@@ -184,7 +184,7 @@ describe('Codeforces',function () {
it('should request call 5 times', function (done) {
new Countrystandings({ contestId: 10, country: 'Bangladesh', total: 1 }).show(function (err) {
expect(request.get.called).to.be.true;
- expect(request.get.callCount).to.equal(5);
+ expect(request.get.callCount).to.equal(2);
expect(err).to.be.null;
done();
});
@@ -211,7 +211,7 @@ describe('Codeforces',function () {
it('should request call 5 times and call log', function (done) {
new Countrystandings({ contestId: 10, country: 'Bangladesh', total: 1 }).show();
expect(request.get.called).to.be.true;
- expect(request.get.callCount).to.equal(5);
+ expect(request.get.callCount).to.equal(2);
expect(helpers.log.called).to.be.true;
done();
});
diff --git a/tests/crawler/test_ratings.js b/tests/crawler/test_ratings.js
index b45d799..c0b923a 100644
--- a/tests/crawler/test_ratings.js
+++ b/tests/crawler/test_ratings.js
@@ -68,7 +68,7 @@ describe('Codeforces',function () {
new Ratings({ country: 'invlid' }).show(function (err,result) {
expect(request.get.called).to.be.false;
expect(helpers.logr.called).to.be.false;
- expect(err).to.equal(`Invalid country 'invlid'.Please run command 'cf country' to see supported country list.`);
+ expect(err).to.equal(`Invalid country 'invlid'.Please run 'cf country' to see supported country list.`);
done();
});
});
@@ -145,7 +145,7 @@ describe('Codeforces',function () {
instnecRating.show(function (err,result) {
expect(request.get.called).to.be.true;
expect(helpers.logr.called).to.be.false;
- expect(err).to.equal('HTTP error');
+ expect(err).to.equal('HTTP failed with status 404');
expect(instnecRating.getOrg.called).to.be.false;
done();
});
@@ -267,7 +267,7 @@ describe('Codeforces',function () {
expect(request.get.called).to.be.true;
expect(helpers.logr.called).to.be.false;
expect(helpers.log.called).to.be.false;
- expect(err).to.equal('HTTP error [org]');
+ expect(err).to.equal('HTTP failed with status 404');
done();
});
});
diff --git a/tests/crawler/test_submit.js b/tests/crawler/test_submit.js
index e232a28..cbdeaa6 100644
--- a/tests/crawler/test_submit.js
+++ b/tests/crawler/test_submit.js
@@ -827,7 +827,7 @@ describe('Codeforces', function() {
sinon.stub(helpers, 'checkPath').yields(null);
sinon.stub(instanceSubmit, 'prepareInput').yields(null, { handle: 'some', password: 'adad' });
sinon.stub(instanceSubmit, 'getCSRFToken').yields(null,'adad', { handle: 'some', password: 'adad', logout: true, contestId: 123, problemIndex: 'A', language: 10, codePath: 'ada' });
- sinon.stub(instanceSubmit, 'login').yields(null, { handle: 'some', password: 'adad' });
+ sinon.stub(instanceSubmit, 'login').yields(null, 'someToken', { handle: 'some', password: 'adad' });
sinon.stub(fs,'createReadStream').returns('adad');
sinon.stub(request,'post').yields('posterror');
sinon.stub(helpers,'log', function (text) {});
@@ -860,7 +860,7 @@ describe('Codeforces', function() {
sinon.stub(helpers, 'checkPath').yields(null);
sinon.stub(instanceSubmit, 'prepareInput').yields(null, { handle: 'some', password: 'adad' });
sinon.stub(instanceSubmit, 'getCSRFToken').yields(null,'adad', { handle: 'some', password: 'adad', logout: true, contestId: 123, problemIndex: 'A', language: 10, codePath: 'ada' });
- sinon.stub(instanceSubmit, 'login').yields(null, { handle: 'some', password: 'adad' });
+ sinon.stub(instanceSubmit, 'login').yields(null, 'someToken', { handle: 'some', password: 'adad' });
sinon.stub(fs,'createReadStream').returns('adad');
sinon.stub(request,'post').yields(null, { headers: { } }, {});
sinon.stub(helpers,'log', function (text) {});
@@ -893,7 +893,7 @@ describe('Codeforces', function() {
sinon.stub(helpers, 'checkPath').yields(null);
sinon.stub(instanceSubmit, 'prepareInput').yields(null, { handle: 'some', password: 'adad' });
sinon.stub(instanceSubmit, 'getCSRFToken').yields(null,'adad', { handle: 'some', password: 'adad', logout: true, contestId: 123, problemIndex: 'A', language: 10, codePath: 'ada' });
- sinon.stub(instanceSubmit, 'login').yields(null, { handle: 'some', password: 'adad' });
+ sinon.stub(instanceSubmit, 'login').yields(null, 'someToken', { handle: 'some', password: 'adad' });
sinon.stub(fs,'createReadStream').returns('adad');
sinon.stub(request,'post').yields(null, { headers: { location: 'adad' } }, {});
sinon.stub(helpers,'log', function (text) {});
@@ -926,7 +926,7 @@ describe('Codeforces', function() {
sinon.stub(helpers, 'checkPath').yields(null);
sinon.stub(instanceSubmit, 'prepareInput').yields(null, { handle: 'some', password: 'adad' });
sinon.stub(instanceSubmit, 'getCSRFToken').yields(null,'adad', { handle: 'some', password: 'adad', logout: true, contestId: 123, problemIndex: 'A', language: 10, codePath: 'ada' });
- sinon.stub(instanceSubmit, 'login').yields(null, { handle: 'some', password: 'adad' });
+ sinon.stub(instanceSubmit, 'login').yields(null, 'someToken', { handle: 'some', password: 'adad' });
sinon.stub(fs,'createReadStream').returns('adad');
sinon.stub(request,'post').yields(null, { headers: { location: 'adad' } }, `someError
`);
sinon.stub(helpers,'log', function (text) {});
@@ -959,7 +959,7 @@ describe('Codeforces', function() {
sinon.stub(helpers, 'checkPath').yields(null);
sinon.stub(instanceSubmit, 'prepareInput').yields(null, { handle: 'some', password: 'adad' });
sinon.stub(instanceSubmit, 'getCSRFToken').yields(null,'adad', { handle: 'some', password: 'adad', logout: true, contestId: 123, problemIndex: 'A', language: 10, codePath: 'ada', type: 'contest' });
- sinon.stub(instanceSubmit, 'login').yields(null, { handle: 'some', password: 'adad' });
+ sinon.stub(instanceSubmit, 'login').yields(null, 'someToken', { handle: 'some', password: 'adad', logout: true, contestId: 123, problemIndex: 'A', language: 10, codePath: 'ada', type: 'contest' });
sinon.stub(fs,'createReadStream').returns('adad');
sinon.stub(request,'post').yields(null, { headers: { location: '/contest/123/my' } }, {});
sinon.stub(helpers,'log', function (text) {});
@@ -992,7 +992,7 @@ describe('Codeforces', function() {
sinon.stub(helpers, 'checkPath').yields(null);
sinon.stub(instanceSubmit, 'prepareInput').yields(null, { handle: 'some', password: 'adad' });
sinon.stub(instanceSubmit, 'getCSRFToken').yields(null,'adad', { handle: 'some', password: 'adad', logout: true, contestId: 123, problemIndex: 'A', language: 10, codePath: 'ada', type: 'gym' });
- sinon.stub(instanceSubmit, 'login').yields(null, { handle: 'some', password: 'adad' });
+ sinon.stub(instanceSubmit, 'login').yields(null, 'someToken', { handle: 'some', password: 'adad', logout: true, contestId: 123, problemIndex: 'A', language: 10, codePath: 'ada', type: 'gym' });
sinon.stub(fs,'createReadStream').returns('adad');
sinon.stub(request,'post').yields(null, { headers: { location: '/gym/123/my' } }, {});
sinon.stub(helpers,'log', function (text) {});