Skip to content

Commit

Permalink
Work in progress...
Browse files Browse the repository at this point in the history
  • Loading branch information
stoprocent committed Aug 4, 2014
1 parent 6f4c9a9 commit 39f3972
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 2 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2014 Marek Serafin
Copyright (c) 2014 Marek Serafin, itcReport Creator

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
24 changes: 24 additions & 0 deletions examples/basic-example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
var iTunesConnect = require("../"),
ReportQuery = iTunesConnect.ReportQuery;

var itunes = new iTunesConnect('', '');


itunes.request(new ReportQuery().timed().time(2, 'week').content(804089146), function(error, result) {

console.log(result);

});

var reportQuery = new ReportQuery({
limit: 10,
start: '2013-01-01',
end: '2013-02-01'
}).ranked();



itunes.request(reportQuery, function(error, result) {
console.log(result);
});

245 changes: 245 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
//! itc-report.js
//! version : 0.0.1
//! authors : Marek Serafin
//! license : MIT
//! github.com/stoprocent/itc-report

var async = require('async');
request = require('request'),
cheerio = require('cheerio'),
moment = require('moment'),
fs = require('fs'),
path = require('path'),
_ = require('underscore');

/**
* Expose `iTunesConnect`
*/

exports = module.exports = iTunesConnect;

/**
* Expose `ReportQuery`.
*/

exports.ReportQuery = ReportQuery;

/**
* Initialize a new `iTunesConnect` with the given `username`, `password` and `options`.
*
* @param {String} flags
* @param {String} description
* @api public
*/

function iTunesConnect(username, password, options) {
this._cookies = [];

this.options = {
loginURL : "https://itunesconnect.apple.com",
apiURL : "https://reportingitc2.apple.com/api/",
concurrentRequests : 3
};
_.extend(this.options, options);

// Task Executor
this._queue = async.queue(
this.executeRequest.bind(this),
this.options.concurrentRequests
);
this._queue.pause();

this.login(username, password);
}

iTunesConnect.prototype.request = function(query, completed) {
this._queue.push({query: query, completed: completed});
return this;
}

iTunesConnect.prototype.executeRequest = function(task, callback) {
var query = task.query;
var completed = task.completed;

console.log(query.body());

request.post({
url : this.options.apiURL + query.endpoint,
body : query.body(),
headers : {
'Content-Type': 'application/json',
'Cookie': this._cookies
}
}, function(error, response, body) {
if(response.statusCode == 401) {
error = new Error('This request requires authentication. Please check your username and password.');
body = null;
}
else {
try {
body = JSON.parse(body);
} catch (e) {
error = new Error('There was an error while parsing JSON.');
body = null;
}
}
completed(error, body);
callback();
})
}

iTunesConnect.prototype.login = function(username, password) {
var self = this;
// Request ITC to get fresh post action
request.get(this.options.loginURL, function(error, response, body) {
// Handle Errors

// Search for action attribute
var html = cheerio.load(body);
var action = html('form').attr('action');

// Login to ITC
request.post({
url : self.options.loginURL + action,
form: {
'theAccountName' : username,
'theAccountPW' : password,
'theAuxValue' : ""
}
}, function(error, response, body) {
var cookies = response.headers['set-cookie'];
// Handle Errors
if(error || !cookies.length) {

}
else {
// Set Cookies and emit event
self._cookies = cookies;
self._queue.resume();
}
});
});
}

function ReportQuery(query) {
this.type = null;
this.endpoint = null;

this._body = {
start : moment(),
end : moment(),
interval : 'day',
filters : [],
group : null,
measures : ['units'],
limit : 100
};
// Extend options with user stuff
_.extend(this._body, query);

// Private Options
this._body._time = null;
}

ReportQuery.prototype.body = function() {
// Ensure date is moment object
this._body.start = parseToMoment(this._body.start);
this._body.end = parseToMoment(this._body.end);

// If start and end date are same and time() was used in query calculate new start date
if (!this._body.end.diff(this._body.start, 'days') && _.isArray(this._body._time)) {
this._body.start = this._body.start.subtract(this._body._time[0], this._body._time[1]);
}

// Ensure if ranked and group = null set group to default
if(this.type == 'ranked' && this._body.group == null) {
this._body.group = 'content';
}

// Building body
var body = {
"start_date" : this._body.start.format("YYYY-MM-DD[T00:00:00.000Z]"),
"end_date" : this._body.end.format("YYYY-MM-DD[T00:00:00.000Z]"),
"interval" : this._body.interval,
"filters" : this._body.filters,
"group" : this._body.group,
"measures" : this._body.measures,
"limit" : this._body.limit
};
return JSON.stringify(body);
}

ReportQuery.prototype.timed = function() {
this.type = 'timed';
this.endpoint = 'data/timeseries';

return this;
}

ReportQuery.prototype.ranked = function() {
this.type = 'ranked';
this.endpoint = 'data/ranked';

return this;
}

ReportQuery.prototype.interval = function(value) {
this._body.interval = value;
return this;
}

ReportQuery.prototype.date = function(start, end) {
this._body.start = parseToMoment( start );
this._body.end = parseToMoment( ((typeof end == 'undefined') ? start : end) );

return this;
}

ReportQuery.prototype.time = function(value, unit) {
this._body._time = [value, unit];
return this;
}

ReportQuery.prototype.group = function(value) {
this._body.group = value;
return this;
}

ReportQuery.prototype.measures = function(value) {
this._body.measures = value;
return this;
}

ReportQuery.prototype.limit = function(value) {
this._body.limit = value;
return this;
}

ReportQuery.prototype.addFilters = function(dimension, values) {
if (!_.isArray(values)) {
values = [values];
};
this._body.filters.push({
dimension_key : dimension,
option_keys : values
});
}

ReportQuery.prototype.content = function(value) {
this.addFilters('content', value);
return this;
}

function parseToMoment(date) {
// Quick check if moment
if(moment.isMoment(date)) {
return date;
}
else if(date instanceof Date) {
return moment(date);
}
else if(typeof date === "string" && !!(date.match(new RegExp(/([0-9]{4})-([0-9]{2})-([0-9]{2})/)))) {
return moment(date, "YYYY-MM-DD");
}
return false;
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"underscore": "~1.6.0",
"moment": "~2.8.1",
"request": "~2.39.0",
"cheerio": "~0.17.0"
"cheerio": "~0.17.0",
"async": "~0.9.0"
}
}

0 comments on commit 39f3972

Please sign in to comment.