diff --git a/docs/classes/Constants.html b/docs/classes/Constants.html index 32bb4f9..927aa64 100644 --- a/docs/classes/Constants.html +++ b/docs/classes/Constants.html @@ -98,7 +98,7 @@
index.js:37
+ Defined in: index.js:31
index.js:429
+ Defined in: index.js:443
Query
Query
index.js:429
+ index.js:443
@@ -409,7 +411,7 @@ body
index.js:463
+ index.js:473
@@ -435,6 +437,8 @@ JSON String
+ @@ -488,7 +492,7 @@category
index.js:658
+ index.js:676
@@ -599,7 +603,7 @@ content
index.js:644
+ index.js:662
@@ -696,7 +700,7 @@ date
index.js:548
+ index.js:564
@@ -735,7 +739,7 @@ If end is undefined it will be set same as start. If String must be in format YYYY-MM-DD
+If end is undefined it will be set same as start. If String, must be in format YYYY-MM-DD
If String must be in format YYYY-MM-DD
+If String, must be in format YYYY-MM-DD
group
index.js:596
+ index.js:614
@@ -986,7 +990,7 @@ interval
index.js:529
+ index.js:545
@@ -1146,7 +1150,7 @@ limit
index.js:630
+ index.js:648
@@ -1237,7 +1241,7 @@ location
index.js:694
+ index.js:712
@@ -1328,7 +1332,7 @@ measures
index.js:616
+ index.js:634
@@ -1418,7 +1422,7 @@ platform
index.js:708
+ index.js:726
@@ -1442,7 +1446,7 @@ <value>
- Number | Array
+ String | Array
@@ -1501,7 +1505,7 @@ ranked
index.js:510
+ index.js:525
@@ -1574,7 +1578,7 @@ time
index.js:576
+ index.js:594
@@ -1675,7 +1679,7 @@ timed
index.js:494
+ index.js:505
@@ -1742,7 +1746,7 @@ transaction
index.js:736
+ index.js:754
@@ -1766,7 +1770,7 @@ <value>
- Number | Array
+ String | Array
@@ -1833,7 +1837,7 @@ type
index.js:722
+ index.js:740
@@ -1857,7 +1861,7 @@ <value>
- Number | Array
+ String | Array
diff --git a/docs/classes/ReportQuery.html b/docs/classes/ReportQuery.html
index cb0a0c0..bbbb75c 100644
--- a/docs/classes/ReportQuery.html
+++ b/docs/classes/ReportQuery.html
@@ -98,7 +98,7 @@ index.js:293
+ Defined in: index.js:305
ReportQuery
index.js:293
+ index.js:305
@@ -378,7 +378,7 @@ [content]
- String | Number | Array
+ Number | Array
optional
@@ -390,7 +390,7 @@ [type]
- String | Number | Array
+ String | Array
optional
@@ -402,7 +402,7 @@ [transaction]
- String | Number | Array
+ String | Array
optional
@@ -414,7 +414,7 @@ [category]
- String | Number | Array
+ Number | Array
optional
@@ -426,7 +426,7 @@ [platform]
- String | Number | Array
+ String | Array
optional
@@ -438,7 +438,7 @@ [location]
- String | Number | Array
+ Number | Array
optional
@@ -676,6 +676,8 @@ ranked
ranked
index.js:369
+ index.js:381
@@ -796,6 +798,8 @@ timed
timed
index.js:399
+ index.js:412
diff --git a/docs/classes/iTunesConnect.html b/docs/classes/iTunesConnect.html
index 4854d30..6e3ef31 100644
--- a/docs/classes/iTunesConnect.html
+++ b/docs/classes/iTunesConnect.html
@@ -260,7 +260,7 @@ [loginURL]
+ [baseURL]
String
optional
@@ -450,7 +450,7 @@ executeRequest
index.js:209
+ index.js:218
@@ -561,7 +561,7 @@ login
index.js:249
+ index.js:261
@@ -666,7 +666,7 @@ metadata
index.js:175
+ index.js:184
@@ -677,7 +677,7 @@ metadata
Fetch iTunes Connect Reporting metadata with given completed
.
Fetch iTunes Connect Reporting metadata with given completed
callback.
Examples:
// Import itc-report
var iTunesConnect = require("itc-report"),
@@ -821,7 +821,7 @@ request
- index.js:143
+ index.js:147
@@ -832,7 +832,7 @@ request
Request iTunes Connect report with the given query
and completed
.
Request iTunes Connect report with the given query
and completed
callback.
Examples:
// Import itc-report
var iTunesConnect = require("itc-report"),
diff --git a/docs/data.json b/docs/data.json
index ed0b687..31dc0c3 100644
--- a/docs/data.json
+++ b/docs/data.json
@@ -43,7 +43,7 @@
"namespaces": {},
"tag": "module",
"file": "index.js",
- "line": 429
+ "line": 443
}
},
"classes": {
@@ -58,7 +58,7 @@
"module": "itc-report",
"namespace": "",
"file": "index.js",
- "line": 37,
+ "line": 31,
"description": "Static constants to make it easier to build query\n\nExamples:\n\n\t// Import itc-report\n\tvar iTunesConnect \t= require(\"itc-report\"),\n\t\tReportQuery \t= iTunesConnect.ReportQuery;\n\t\tConstants \t\t= iTunesConnect.Constants;\n\n\t// Possible Types \n\tConstants.InApp // In-App Purchases\n\tConstants.App // App Purchases\n\n\t// Possible Transactions \n\tConstants.Free\n\tConstants.Paid \n\tConstants.Redownload\n\tConstants.Update\n\tConstants.Refund \n\n\t// Possible Platforms\n\tConstants.Desktop\n\tConstants.iPhone \n\tConstants.iPad \n\tConstants.iPod\n\n\t// Possible Measures\n\tConstants.Proceeds // How much moooooooneeeey\n\tConstants.Units // How many units"
},
"iTunesConnect": {
@@ -93,7 +93,7 @@
"optional": true,
"props": [
{
- "name": "loginURL",
+ "name": "baseURL",
"description": "iTunes Connect Login URL",
"type": "String",
"optional": true
@@ -131,7 +131,7 @@
"module": "itc-report",
"namespace": "",
"file": "index.js",
- "line": 293,
+ "line": 305,
"description": "Initialize a new `Query` with the given `type` and `config`.\n\nExamples:\n\n\t// Import itc-report\n\tvar iTunesConnect \t= require(\"itc-report\"),\n\t\tReportQuery \t= iTunesConnect.ReportQuery;\n\t\tConstants \t\t= iTunesConnect.Constants;\n\t\n\t// Init new iTunes Connect\n\tvar itunes = new iTunesConnect('apple@id.com', 'password');\n\n\t// Timed type query\n\tvar query = ReportQuery('timed');\n\t\n\t// Ranked type query with config object\n\tvar query = ReportQuery('ranked', { limit: 100 });\t\n\n\t// Advanced Example\n\tvar advancedQuery = ReportQuery('timed', {\n\t\tstart \t: '2014-04-08',\n\t\tend \t: '2014-04-25',\n\t\tlimit \t: 100,\n\t\tfilters : {\n\t\t\tcontent: [{AppID}, {AppID}, {AppID}],\n\t\t\tlocation: [{LocationID}, {LocationID}],\n\t\t\ttransaction: Constants.Free,\n\t\t\ttype: [\n\t\t\t\tConstants.InApp, \n\t\t\t\tConstants.App\n\t\t\t],\n\t\t\tcategory: {CategoryID}\n\t\t},\n\t\tgroup: 'content'\n\t});",
"is_constructor": 1,
"params": [
@@ -200,37 +200,37 @@
{
"name": "content",
"description": "",
- "type": "String|Number|Array",
+ "type": "Number|Array",
"optional": true
},
{
"name": "type",
"description": "",
- "type": "String|Number|Array",
+ "type": "String|Array",
"optional": true
},
{
"name": "transaction",
"description": "",
- "type": "String|Number|Array",
+ "type": "String|Array",
"optional": true
},
{
"name": "category",
"description": "",
- "type": "String|Number|Array",
+ "type": "Number|Array",
"optional": true
},
{
"name": "platform",
"description": "",
- "type": "String|Number|Array",
+ "type": "String|Array",
"optional": true
},
{
"name": "location",
"description": "",
- "type": "String|Number|Array",
+ "type": "Number|Array",
"optional": true
}
]
@@ -304,7 +304,7 @@
"module": "itc-report",
"namespace": "",
"file": "index.js",
- "line": 429,
+ "line": 443,
"description": "Initialize a new `Query` with the given `query`.",
"is_constructor": 1,
"access": "private",
@@ -316,6 +316,7 @@
"type": "Object"
}
],
+ "chainable": 1,
"return": {
"description": "",
"type": "Query"
@@ -325,8 +326,8 @@
"classitems": [
{
"file": "index.js",
- "line": 143,
- "description": "Request iTunes Connect report with the given `query` and `completed`.\n\nExamples:\n\n\t// Import itc-report\n\tvar iTunesConnect \t= require(\"itc-report\"),\n\t\tReportQuery \t= iTunesConnect.ReportQuery;\n\t\n\t// Init new iTunes Connect\n\tvar itunes = new iTunesConnect('apple@id.com', 'password');\n\n\t// Request timed report from yesterday to today\n\titunes.request(ReportQuery.timed().time(1, 'day'), function(error, result) {\n\t\tconsole.log(result);\n\t})",
+ "line": 147,
+ "description": "Request iTunes Connect report with the given `query` and `completed` callback.\n\nExamples:\n\n\t// Import itc-report\n\tvar iTunesConnect \t= require(\"itc-report\"),\n\t\tReportQuery \t= iTunesConnect.ReportQuery;\n\t\n\t// Init new iTunes Connect\n\tvar itunes = new iTunesConnect('apple@id.com', 'password');\n\n\t// Request timed report from yesterday to today\n\titunes.request(ReportQuery.timed().time(1, 'day'), function(error, result) {\n\t\tconsole.log(result);\n\t})",
"itemtype": "method",
"name": "request",
"params": [
@@ -365,8 +366,8 @@
},
{
"file": "index.js",
- "line": 175,
- "description": "Fetch iTunes Connect Reporting metadata with given `completed`.\n\nExamples:\n\n\t// Import itc-report\n\tvar iTunesConnect \t= require(\"itc-report\"),\n\t\tReportQuery \t= iTunesConnect.ReportQuery;\n\t\n\t// Init new iTunes Connect\n\tvar itunes = new iTunesConnect('apple@id.com', 'password');\n\n\t// Fetch API Metadata\n\titunes.metadata(function(error, result) {\n\t\tconsole.log(result);\n\t})",
+ "line": 184,
+ "description": "Fetch iTunes Connect Reporting metadata with given `completed` callback.\n\nExamples:\n\n\t// Import itc-report\n\tvar iTunesConnect \t= require(\"itc-report\"),\n\t\tReportQuery \t= iTunesConnect.ReportQuery;\n\t\n\t// Init new iTunes Connect\n\tvar itunes = new iTunesConnect('apple@id.com', 'password');\n\n\t// Fetch API Metadata\n\titunes.metadata(function(error, result) {\n\t\tconsole.log(result);\n\t})",
"itemtype": "method",
"name": "metadata",
"params": [
@@ -399,7 +400,7 @@
},
{
"file": "index.js",
- "line": 209,
+ "line": 218,
"description": "Execute iTunes Connect report request with given `task` and `callback`.",
"access": "private",
"tagname": "",
@@ -422,7 +423,7 @@
},
{
"file": "index.js",
- "line": 249,
+ "line": 261,
"description": "Login to iTunes Connect with given `username` and `password`.",
"access": "private",
"tagname": "",
@@ -445,7 +446,7 @@
},
{
"file": "index.js",
- "line": 369,
+ "line": 381,
"description": "Initialize a new `Query` with the ranked type and given `config`.\n\nExamples:\n\n\t// Import itc-report\n\tvar iTunesConnect \t= require(\"itc-report\"),\n\t\tReportQuery \t= iTunesConnect.ReportQuery;\n\t\n\t// Init new iTunes Connect\n\tvar itunes = new iTunesConnect('apple@id.com', 'password');\n\n\t// Ranked type query\n\tvar query = ReportQuery.ranked();\n\n\t// Another query\n\tvar otherQuery = ReportQuery.ranked({\n\t\tlimit: 10\n\t});",
"itemtype": "method",
"name": "ranked",
@@ -457,6 +458,7 @@
"optional": true
}
],
+ "chainable": 1,
"return": {
"description": "",
"type": "Query"
@@ -466,7 +468,7 @@
},
{
"file": "index.js",
- "line": 399,
+ "line": 412,
"description": "Initialize a new `Query` with the timed type and given `config`.\n\nExamples:\n\n\t// Import itc-report\n\tvar iTunesConnect \t= require(\"itc-report\"),\n\t\tReportQuery \t= iTunesConnect.ReportQuery;\n\t\n\t// Init new iTunes Connect\n\tvar itunes = new iTunesConnect('apple@id.com', 'password');\n\n\t// Timed type query\n\tvar query = ReportQuery.timed();\n\n\t// Another query\n\tvar otherQuery = ReportQuery.timed({\n\t\tlimit: 10\n\t});",
"itemtype": "method",
"name": "timed",
@@ -478,6 +480,7 @@
"optional": true
}
],
+ "chainable": 1,
"return": {
"description": "",
"type": "Query"
@@ -487,14 +490,14 @@
},
{
"file": "index.js",
- "line": 463,
+ "line": 473,
"description": "Builds and returns body for iTunesConnect request as JSON string",
"itemtype": "method",
"name": "body",
"access": "private",
"tagname": "",
"return": {
- "description": "",
+ "description": "JSON String",
"type": "String"
},
"class": "Query",
@@ -502,7 +505,7 @@
},
{
"file": "index.js",
- "line": 494,
+ "line": 505,
"description": "Initialize a new `Query` with the timed type.",
"access": "private",
"tagname": "",
@@ -514,7 +517,7 @@
},
{
"file": "index.js",
- "line": 510,
+ "line": 525,
"description": "Initialize a new `Query` with the ranked type.",
"access": "private",
"tagname": "",
@@ -526,7 +529,7 @@
},
{
"file": "index.js",
- "line": 529,
+ "line": 545,
"description": "Sets interval property for `Query`",
"itemtype": "method",
"name": "interval",
@@ -570,19 +573,19 @@
},
{
"file": "index.js",
- "line": 548,
+ "line": 564,
"description": "Sets start and end property for `Query`\n\nExamples:\n\n\t// Start and end date set manualy\n\tquery.date('2014-04-08', new Date());\n\n\t// Start and end date will be todays date\n\tquery.date(new Date());\n\n\t// Start and end date will be set as 8th of April 2014\n\tquery.date('2014-04-08');",
"itemtype": "method",
"name": "date",
"params": [
{
"name": "",
- "description": "If end is undefined it will be set same as start. If String must be in format YYYY-MM-DD",
+ "description": "If end is undefined it will be set same as start. If String, must be in format YYYY-MM-DD",
"type": "String|Date"
},
{
"name": "end",
- "description": "If String must be in format YYYY-MM-DD",
+ "description": "If String, must be in format YYYY-MM-DD",
"type": "String|Date",
"optional": true
}
@@ -593,7 +596,7 @@
},
{
"file": "index.js",
- "line": 576,
+ "line": 594,
"description": "Sets start property for `Query` in more easy/generic way\n\nExamples:\n\n\tquery.time(1, 'week');\n\tquery.time(20, 'days');",
"itemtype": "method",
"name": "time",
@@ -615,7 +618,7 @@
},
{
"file": "index.js",
- "line": 596,
+ "line": 614,
"description": "Sets `group by` property for `Query`",
"itemtype": "method",
"name": "group",
@@ -664,7 +667,7 @@
},
{
"file": "index.js",
- "line": 616,
+ "line": 634,
"description": "Sets measures property for `Query`",
"itemtype": "method",
"name": "measures",
@@ -681,7 +684,7 @@
},
{
"file": "index.js",
- "line": 630,
+ "line": 648,
"description": "Sets limit property for `Query`",
"itemtype": "method",
"name": "limit",
@@ -698,7 +701,7 @@
},
{
"file": "index.js",
- "line": 644,
+ "line": 662,
"description": "Sets content filter for `Query`",
"itemtype": "method",
"name": "content",
@@ -715,7 +718,7 @@
},
{
"file": "index.js",
- "line": 658,
+ "line": 676,
"description": "Sets category filter for `Query`\n\nExamples:\n\n\t// Import itc-report\n\tvar iTunesConnect \t= require(\"itc-report\"),\n\t\tReportQuery \t= iTunesConnect.ReportQuery;\n\t\n\t// Query\n\tvar query = ReportQuery.timed({\n\t\tlimit: 10\n\t}).category(6001);\t\n\n\t// Another Query\n\tvar otherQuery = ReportQuery.timed({\n\t\tlimit: 10\n\t});\n\t// OK\n\totherQuery.category([6001, 6002, 6003]);\n\n\t// Wrong - This will not work as for version 0.0.1! 6003 will overwrite previously set category ids\n\t// You are more than welcome to sort this out in pull request. I saw no reason to do this.\n\totherQuery.category([6001, 6002, 6003]).category(6003);",
"itemtype": "method",
"name": "category",
@@ -732,7 +735,7 @@
},
{
"file": "index.js",
- "line": 694,
+ "line": 712,
"description": "Sets location filter for `Query`",
"itemtype": "method",
"name": "location",
@@ -749,7 +752,7 @@
},
{
"file": "index.js",
- "line": 708,
+ "line": 726,
"description": "Sets platform filter for `Query`",
"itemtype": "method",
"name": "platform",
@@ -757,7 +760,7 @@
{
"name": "",
"description": "(Look in Constants under Platforms)",
- "type": "Number|Array"
+ "type": "String|Array"
}
],
"chainable": 1,
@@ -766,7 +769,7 @@
},
{
"file": "index.js",
- "line": 722,
+ "line": 740,
"description": "Sets type filter for `Query`",
"itemtype": "method",
"name": "type",
@@ -774,7 +777,7 @@
{
"name": "",
"description": "(Look in Constants under Types)",
- "type": "Number|Array"
+ "type": "String|Array"
}
],
"chainable": 1,
@@ -783,7 +786,7 @@
},
{
"file": "index.js",
- "line": 736,
+ "line": 754,
"description": "Sets transaction filter for `Query`",
"itemtype": "method",
"name": "transaction",
@@ -791,7 +794,7 @@
{
"name": "",
"description": "(Look in Constants under Transactions)",
- "type": "Number|Array"
+ "type": "String|Array"
}
],
"chainable": 1,
diff --git a/docs/files/index.js.html b/docs/files/index.js.html
index 0f41804..2798ce4 100644
--- a/docs/files/index.js.html
+++ b/docs/files/index.js.html
@@ -124,12 +124,6 @@ File: index.js
exports.ReportQuery = ReportQuery;
-/*
-* Expose `Constants`.
-*/
-
-exports.Constants = Constants;
-
/**
* Static constants to make it easier to build query
*
@@ -184,6 +178,12 @@ File: index.js
Units : "units"
};
+/*
+* Expose `Constants`.
+*/
+
+exports.Constants = Constants;
+
/**
* Initialize a new `iTunesConnect` with the given `username`, `password` and `options`.
*
@@ -209,35 +209,39 @@ File: index.js
* @param {String} username Apple ID login
* @param {String} password Apple ID password
* @param {Object} [options]
-* @param {String} [options.loginURL] iTunes Connect Login URL
+* @param {String} [options.baseURL] iTunes Connect Login URL
* @param {String} [options.apiURL] iTunes Connect API URL
* @param {Number} [options.concurrentRequests] Number of concurrent requests
* @param {Function} [options.errorCallback] Error callback function called when requests are failing
*/
function iTunesConnect(username, password, options) {
- this._cookies = [];
-
+ // Default Options
this.options = {
- loginURL : "https://itunesconnect.apple.com",
+ baseURL : "https://itunesconnect.apple.com",
apiURL : "https://reportingitc2.apple.com/api/",
- concurrentRequests : 3,
+ concurrentRequests : 2,
errorCallback : function(e) {}
};
+ // Extend options
_.extend(this.options, options);
+ // Set cookies
+ this._cookies = [];
+
// Task Executor
this._queue = async.queue(
this.executeRequest.bind(this),
this.options.concurrentRequests
);
+ // Pasue queue and wait for login to complete
this._queue.pause();
-
+ // Login to iTunes Connect
this.login(username, password);
}
/**
-* Request iTunes Connect report with the given `query` and `completed`.
+* Request iTunes Connect report with the given `query` and `completed` callback.
*
* Examples:
*
@@ -264,12 +268,17 @@ File: index.js
*/
iTunesConnect.prototype.request = function(query, completed) {
- this._queue.push({query: query, completed: completed});
+ // Push request to queue
+ this._queue.push({
+ query: query,
+ completed: completed
+ });
+
return this;
}
/**
-* Fetch iTunes Connect Reporting metadata with given `completed`.
+* Fetch iTunes Connect Reporting metadata with given `completed` callback.
*
* Examples:
*
@@ -315,8 +324,9 @@ File: index.js
iTunesConnect.prototype.executeRequest = function(task, callback) {
var query = task.query;
var completed = task.completed;
+ // Keep request body for callback
var requestBody = query.body();
-
+ // Run request
request.post({
url : this.options.apiURL + query.endpoint,
body : requestBody,
@@ -337,7 +347,9 @@ File: index.js
body = null;
}
}
+ // Call completed callback
completed(error, body, requestBody);
+ // Call callback to mark queue task as done
callback();
})
}
@@ -355,7 +367,7 @@ File: index.js
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) {
+ request.get(this.options.baseURL, function(error, response, body) {
// Handle Errors
// Search for action attribute
@@ -364,7 +376,7 @@ File: index.js
// Login to ITC
request.post({
- url : self.options.loginURL + action,
+ url : self.options.baseURL + action,
form: {
'theAccountName' : username,
'theAccountPW' : password,
@@ -436,12 +448,12 @@ File: index.js
* @param {String} config.interval.quarter
* @param {String} config.interval.year
* @param {Object} [config.filters] Possible keys:
-* @param {String|Number|Array} [config.filters.content]
-* @param {String|Number|Array} [config.filters.type]
-* @param {String|Number|Array} [config.filters.transaction]
-* @param {String|Number|Array} [config.filters.category]
-* @param {String|Number|Array} [config.filters.platform]
-* @param {String|Number|Array} [config.filters.location]
+* @param {Number|Array} [config.filters.content]
+* @param {String|Array} [config.filters.type]
+* @param {String|Array} [config.filters.transaction]
+* @param {Number|Array} [config.filters.category]
+* @param {String|Array} [config.filters.platform]
+* @param {Number|Array} [config.filters.location]
* @param {String} [config.group] One of following:
* @param {String} config.group.content
* @param {String} config.group.type
@@ -485,6 +497,7 @@ File: index.js
* @method ranked
* @for ReportQuery
* @param {Object} [config]
+* @chainable
* @return {Query}
*/
@@ -515,6 +528,7 @@ File: index.js
* @method timed
* @for ReportQuery
* @param {Object} [config]
+* @chainable
* @return {Query}
*/
@@ -529,6 +543,7 @@ File: index.js
* @constructor
* @private
* @param {Object} config
+* @chainable
* @return {Query}
*/
@@ -536,24 +551,19 @@ File: index.js
this.type = null;
this.endpoint = null;
- this.query = {
+ this.config = {
start : moment(),
end : moment(),
- interval : 'day',
- filters : [],
- group : null,
+ filters : {},
measures : ['units'],
limit : 100
};
// Extend options with user stuff
- _.extend(this.query, config);
+ _.extend(this.config, config);
// Private Options
this._time = null;
- this._filters = this.query.filters || {};
this._body = {};
-
- return this;
}
/**
@@ -562,27 +572,28 @@ File: index.js
* @method body
* @for Query
* @private
-* @return {String}
+* @return {String} JSON String
*/
+
Query.prototype.body = function() {
// Ensure date is moment object
- this.query.start = translateToMoment(this.query.start);
- this.query.end = translateToMoment(this.query.end);
+ this.config.start = TransformValue.toMomentObject(this.config.start);
+ this.config.end = TransformValue.toMomentObject(this.config.end);
// If start and end date are same and time() was used in query calculate new start date
- if (!this.query.end.diff(this.query.start, 'days') && _.isArray(this._time)) {
- this.query.start = this.query.start.subtract(this._time[0], this._time[1]);
+ if (this.config.end.diff(this.config.start, 'days') === 0 && _.isArray(this._time)) {
+ this.config.start = this.config.start.subtract(this._time[0], this._time[1]);
}
// Building body
this._body = {
- "start_date" : this.query.start.format("YYYY-MM-DD[T00:00:00.000Z]"),
- "end_date" : this.query.end.format("YYYY-MM-DD[T00:00:00.000Z]"),
- "interval" : this.query.interval,
- "filters" : translateToFilters(this._filters),
- "group" : translateToAppleKey(this.query.group),
- "measures" : this.query.measures,
- "limit" : this.query.limit
+ "start_date" : this.config.start.format("YYYY-MM-DD[T00:00:00.000Z]"),
+ "end_date" : this.config.end.format("YYYY-MM-DD[T00:00:00.000Z]"),
+ "interval" : this.config.interval,
+ "filters" : TransformValue.toBodyFilters(this.config.filters),
+ "group" : TransformValue.toAppleKey(this.config.group),
+ "measures" : this.config.measures,
+ "limit" : this.config.limit
};
return JSON.stringify(this._body);
}
@@ -600,6 +611,10 @@ File: index.js
this.type = 'timed';
this.endpoint = 'data/timeseries';
+ // Defaults for ranked type
+ this.config.group = this.config.group || null;
+ this.config.interval = this.config.interval || 'day';
+
return this;
}
@@ -617,7 +632,8 @@ File: index.js
this.endpoint = 'data/ranked';
// Defaults for ranked type
- this.query.group = this.query.group || 'content';
+ this.config.group = this.config.group || 'content';
+ this.config.interval = this.config.interval || 'day';
return this;
}
@@ -637,7 +653,7 @@ File: index.js
*/
Query.prototype.interval = function(value) {
- this.query.interval = value;
+ this.config.interval = value;
return this;
}
@@ -657,14 +673,16 @@ File: index.js
*
* @method date
* @for Query
-* @param {String|Date} <start> If end is undefined it will be set same as start. If String must be in format YYYY-MM-DD
-* @param {String|Date} [end] If String must be in format YYYY-MM-DD
+* @param {String|Date} <start> If end is undefined it will be set same as start. If String, must be in format YYYY-MM-DD
+* @param {String|Date} [end] If String, must be in format YYYY-MM-DD
* @chainable
*/
Query.prototype.date = function(start, end) {
- this.query.start = translateToMoment( start );
- this.query.end = translateToMoment( ((typeof end == 'undefined') ? start : end) );
+ this.config.start = TransformValue.toMomentObject( start );
+ this.config.end = TransformValue.toMomentObject(
+ ((typeof end == 'undefined') ? start : end)
+ );
return this;
}
@@ -705,7 +723,7 @@ File: index.js
*/
Query.prototype.group = function(value) {
- this.query.group = value;
+ this.config.group = value;
return this;
}
@@ -719,7 +737,7 @@ File: index.js
*/
Query.prototype.measures = function(value) {
- this.query.measures = value;
+ this.config.measures = value;
return this;
}
@@ -733,7 +751,7 @@ File: index.js
*/
Query.prototype.limit = function(value) {
- this.query.limit = value;
+ this.config.limit = value;
return this;
}
@@ -747,7 +765,7 @@ File: index.js
*/
Query.prototype.content = function(value) {
- this._filters.content = value;
+ this.config.filters.content = value;
return this;
}
@@ -783,7 +801,7 @@ File: index.js
*/
Query.prototype.category = function(value) {
- this._filters.category = value;
+ this.config.filters.category = value;
return this;
}
@@ -797,7 +815,7 @@ File: index.js
*/
Query.prototype.location = function(value) {
- this._filters.location = value;
+ this.config.filters.location = value;
return this;
}
@@ -806,12 +824,12 @@ File: index.js
*
* @method platform
* @for Query
-* @param {Number|Array} <value> (Look in Constants under Platforms)
+* @param {String|Array} <value> (Look in Constants under Platforms)
* @chainable
*/
Query.prototype.platform = function(value) {
- this._filters.platform = value;
+ this.config.filters.platform = value;
return this;
}
@@ -820,12 +838,12 @@ File: index.js
*
* @method type
* @for Query
-* @param {Number|Array} <value> (Look in Constants under Types)
+* @param {String|Array} <value> (Look in Constants under Types)
* @chainable
*/
Query.prototype.type = function(value) {
- this._filters.type = value;
+ this.config.filters.type = value;
return this;
}
@@ -834,39 +852,45 @@ File: index.js
*
* @method transaction
* @for Query
-* @param {Number|Array} <value> (Look in Constants under Transactions)
+* @param {String|Array} <value> (Look in Constants under Transactions)
* @chainable
*/
Query.prototype.transaction = function(value) {
- this._filters.transaction = value;
+ this.config.filters.transaction = value;
return this;
}
+/*
+* Transform Value Object
+*
+* @private
+*/
+
+var TransformValue = {};
+
/*
* Translates simple filters object to apple api format
*
* @private
+* @function toBodyFilters
+* @for TransformValue
* @param {Object} filters
* @return {Object}
*/
-function translateToFilters(filters) {
+TransformValue.toBodyFilters = function(filters) {
var result = [];
- _.each(filters, function(values, dimension) {
- if(!_.isArray(values))
- values = [values];
-
- var dimension_key = translateToAppleKey(dimension);
-
- if(dimension_key === false)
- return;
+ _.each(filters, function(value, dimension) {
+ if(!_.isArray(value))
+ value = [value];
result.push({
- dimension_key : dimension_key,
- option_keys : values
+ dimension_key : TransformValue.toAppleKey(dimension),
+ option_keys : value
});
});
+
return result;
}
@@ -874,12 +898,16 @@ File: index.js
* Translates key to apple key
*
* @private
+* @function toAppleKey
+* @for TransformValue
* @param {String} key
* @return {String}
*/
-function translateToAppleKey(key) {
- if(key === null) return key;
+TransformValue.toAppleKey = function(key) {
+ if(key === null)
+ return null;
+
var keys = {
content : "content",
type : "content_type",
@@ -888,9 +916,10 @@ File: index.js
platform : "platform",
location : "piano_location"
};
- if(typeof keys[key] === 'undefined') {
- throw new Error('Unknown filter or group key: ' + key);
- }
+
+ if(typeof keys[key] === 'undefined')
+ throw new Error('Unknown Apple Key for key: ' + key);
+
return keys[key];
}
@@ -898,11 +927,13 @@ File: index.js
* Translates given date to moment object
*
* @private
+* @function toMomentObject
+* @for TransformValue
* @param {Mixed} date
* @return {Moment}
*/
-function translateToMoment(date) {
+TransformValue.toMomentObject = function(date) {
// Quick check if moment
if(moment.isMoment(date)) {
return date;
@@ -910,7 +941,7 @@ File: index.js
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})/)))) {
+ else if(_.isString(date) && !!(date.match(new RegExp(/([0-9]{4})-([0-9]{2})-([0-9]{2})/)))) {
return moment(date, "YYYY-MM-DD");
}
else {
diff --git a/docs/modules/itc-report.html b/docs/modules/itc-report.html
index ae855ce..dfbe275 100644
--- a/docs/modules/itc-report.html
+++ b/docs/modules/itc-report.html
@@ -98,7 +98,7 @@ itc-report Module
- Defined in: index.js:429
+ Defined in: index.js:443
diff --git a/index.js b/index.js
index 75d3fba..e8d221f 100644
--- a/index.js
+++ b/index.js
@@ -113,35 +113,39 @@ exports.Constants = Constants;
* @param {String} username Apple ID login
* @param {String} password Apple ID password
* @param {Object} [options]
-* @param {String} [options.loginURL] iTunes Connect Login URL
+* @param {String} [options.baseURL] iTunes Connect Login URL
* @param {String} [options.apiURL] iTunes Connect API URL
* @param {Number} [options.concurrentRequests] Number of concurrent requests
* @param {Function} [options.errorCallback] Error callback function called when requests are failing
*/
function iTunesConnect(username, password, options) {
- this._cookies = [];
-
+ // Default Options
this.options = {
- loginURL : "https://itunesconnect.apple.com",
+ baseURL : "https://itunesconnect.apple.com",
apiURL : "https://reportingitc2.apple.com/api/",
- concurrentRequests : 3,
+ concurrentRequests : 2,
errorCallback : function(e) {}
};
+ // Extend options
_.extend(this.options, options);
+ // Set cookies
+ this._cookies = [];
+
// Task Executor
this._queue = async.queue(
this.executeRequest.bind(this),
this.options.concurrentRequests
);
+ // Pasue queue and wait for login to complete
this._queue.pause();
-
+ // Login to iTunes Connect
this.login(username, password);
}
/**
-* Request iTunes Connect report with the given `query` and `completed`.
+* Request iTunes Connect report with the given `query` and `completed` callback.
*
* Examples:
*
@@ -168,12 +172,17 @@ function iTunesConnect(username, password, options) {
*/
iTunesConnect.prototype.request = function(query, completed) {
- this._queue.push({query: query, completed: completed});
+ // Push request to queue
+ this._queue.push({
+ query: query,
+ completed: completed
+ });
+
return this;
}
/**
-* Fetch iTunes Connect Reporting metadata with given `completed`.
+* Fetch iTunes Connect Reporting metadata with given `completed` callback.
*
* Examples:
*
@@ -219,8 +228,9 @@ iTunesConnect.prototype.metadata = function(completed) {
iTunesConnect.prototype.executeRequest = function(task, callback) {
var query = task.query;
var completed = task.completed;
+ // Keep request body for callback
var requestBody = query.body();
-
+ // Run request
request.post({
url : this.options.apiURL + query.endpoint,
body : requestBody,
@@ -241,7 +251,9 @@ iTunesConnect.prototype.executeRequest = function(task, callback) {
body = null;
}
}
+ // Call completed callback
completed(error, body, requestBody);
+ // Call callback to mark queue task as done
callback();
})
}
@@ -259,7 +271,7 @@ iTunesConnect.prototype.executeRequest = function(task, 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) {
+ request.get(this.options.baseURL, function(error, response, body) {
// Handle Errors
// Search for action attribute
@@ -268,7 +280,7 @@ iTunesConnect.prototype.login = function(username, password) {
// Login to ITC
request.post({
- url : self.options.loginURL + action,
+ url : self.options.baseURL + action,
form: {
'theAccountName' : username,
'theAccountPW' : password,
@@ -340,12 +352,12 @@ iTunesConnect.prototype.login = function(username, password) {
* @param {String} config.interval.quarter
* @param {String} config.interval.year
* @param {Object} [config.filters] Possible keys:
-* @param {String|Number|Array} [config.filters.content]
-* @param {String|Number|Array} [config.filters.type]
-* @param {String|Number|Array} [config.filters.transaction]
-* @param {String|Number|Array} [config.filters.category]
-* @param {String|Number|Array} [config.filters.platform]
-* @param {String|Number|Array} [config.filters.location]
+* @param {Number|Array} [config.filters.content]
+* @param {String|Array} [config.filters.type]
+* @param {String|Array} [config.filters.transaction]
+* @param {Number|Array} [config.filters.category]
+* @param {String|Array} [config.filters.platform]
+* @param {Number|Array} [config.filters.location]
* @param {String} [config.group] One of following:
* @param {String} config.group.content
* @param {String} config.group.type
@@ -389,6 +401,7 @@ function ReportQuery(type, config) {
* @method ranked
* @for ReportQuery
* @param {Object} [config]
+* @chainable
* @return {Query}
*/
@@ -419,6 +432,7 @@ ReportQuery.ranked = function(config) {
* @method timed
* @for ReportQuery
* @param {Object} [config]
+* @chainable
* @return {Query}
*/
@@ -433,6 +447,7 @@ ReportQuery.timed = function(config) {
* @constructor
* @private
* @param {Object} config
+* @chainable
* @return {Query}
*/
@@ -440,24 +455,19 @@ function Query(config) {
this.type = null;
this.endpoint = null;
- this.query = {
+ this.config = {
start : moment(),
end : moment(),
- interval : 'day',
- filters : [],
- group : null,
+ filters : {},
measures : ['units'],
limit : 100
};
// Extend options with user stuff
- _.extend(this.query, config);
+ _.extend(this.config, config);
// Private Options
this._time = null;
- this._filters = this.query.filters || {};
this._body = {};
-
- return this;
}
/**
@@ -466,27 +476,28 @@ function Query(config) {
* @method body
* @for Query
* @private
-* @return {String}
+* @return {String} JSON String
*/
+
Query.prototype.body = function() {
// Ensure date is moment object
- this.query.start = translateToMoment(this.query.start);
- this.query.end = translateToMoment(this.query.end);
+ this.config.start = TransformValue.toMomentObject(this.config.start);
+ this.config.end = TransformValue.toMomentObject(this.config.end);
// If start and end date are same and time() was used in query calculate new start date
- if (!this.query.end.diff(this.query.start, 'days') && _.isArray(this._time)) {
- this.query.start = this.query.start.subtract(this._time[0], this._time[1]);
+ if (this.config.end.diff(this.config.start, 'days') === 0 && _.isArray(this._time)) {
+ this.config.start = this.config.start.subtract(this._time[0], this._time[1]);
}
// Building body
this._body = {
- "start_date" : this.query.start.format("YYYY-MM-DD[T00:00:00.000Z]"),
- "end_date" : this.query.end.format("YYYY-MM-DD[T00:00:00.000Z]"),
- "interval" : this.query.interval,
- "filters" : translateToFilters(this._filters),
- "group" : translateToAppleKey(this.query.group),
- "measures" : this.query.measures,
- "limit" : this.query.limit
+ "start_date" : this.config.start.format("YYYY-MM-DD[T00:00:00.000Z]"),
+ "end_date" : this.config.end.format("YYYY-MM-DD[T00:00:00.000Z]"),
+ "interval" : this.config.interval,
+ "filters" : TransformValue.toBodyFilters(this.config.filters),
+ "group" : TransformValue.toAppleKey(this.config.group),
+ "measures" : this.config.measures,
+ "limit" : this.config.limit
};
return JSON.stringify(this._body);
}
@@ -504,6 +515,10 @@ Query.prototype.timed = function() {
this.type = 'timed';
this.endpoint = 'data/timeseries';
+ // Defaults for ranked type
+ this.config.group = this.config.group || null;
+ this.config.interval = this.config.interval || 'day';
+
return this;
}
@@ -521,7 +536,8 @@ Query.prototype.ranked = function() {
this.endpoint = 'data/ranked';
// Defaults for ranked type
- this.query.group = this.query.group || 'content';
+ this.config.group = this.config.group || 'content';
+ this.config.interval = this.config.interval || 'day';
return this;
}
@@ -541,7 +557,7 @@ Query.prototype.ranked = function() {
*/
Query.prototype.interval = function(value) {
- this.query.interval = value;
+ this.config.interval = value;
return this;
}
@@ -561,14 +577,16 @@ Query.prototype.interval = function(value) {
*
* @method date
* @for Query
-* @param {String|Date} If end is undefined it will be set same as start. If String must be in format YYYY-MM-DD
-* @param {String|Date} [end] If String must be in format YYYY-MM-DD
+* @param {String|Date} If end is undefined it will be set same as start. If String, must be in format YYYY-MM-DD
+* @param {String|Date} [end] If String, must be in format YYYY-MM-DD
* @chainable
*/
Query.prototype.date = function(start, end) {
- this.query.start = translateToMoment( start );
- this.query.end = translateToMoment( ((typeof end == 'undefined') ? start : end) );
+ this.config.start = TransformValue.toMomentObject( start );
+ this.config.end = TransformValue.toMomentObject(
+ ((typeof end == 'undefined') ? start : end)
+ );
return this;
}
@@ -609,7 +627,7 @@ Query.prototype.time = function(value, unit) {
*/
Query.prototype.group = function(value) {
- this.query.group = value;
+ this.config.group = value;
return this;
}
@@ -623,7 +641,7 @@ Query.prototype.group = function(value) {
*/
Query.prototype.measures = function(value) {
- this.query.measures = value;
+ this.config.measures = value;
return this;
}
@@ -637,7 +655,7 @@ Query.prototype.measures = function(value) {
*/
Query.prototype.limit = function(value) {
- this.query.limit = value;
+ this.config.limit = value;
return this;
}
@@ -651,7 +669,7 @@ Query.prototype.limit = function(value) {
*/
Query.prototype.content = function(value) {
- this._filters.content = value;
+ this.config.filters.content = value;
return this;
}
@@ -687,7 +705,7 @@ Query.prototype.content = function(value) {
*/
Query.prototype.category = function(value) {
- this._filters.category = value;
+ this.config.filters.category = value;
return this;
}
@@ -701,7 +719,7 @@ Query.prototype.category = function(value) {
*/
Query.prototype.location = function(value) {
- this._filters.location = value;
+ this.config.filters.location = value;
return this;
}
@@ -710,12 +728,12 @@ Query.prototype.location = function(value) {
*
* @method platform
* @for Query
-* @param {Number|Array} (Look in Constants under Platforms)
+* @param {String|Array} (Look in Constants under Platforms)
* @chainable
*/
Query.prototype.platform = function(value) {
- this._filters.platform = value;
+ this.config.filters.platform = value;
return this;
}
@@ -724,12 +742,12 @@ Query.prototype.platform = function(value) {
*
* @method type
* @for Query
-* @param {Number|Array} (Look in Constants under Types)
+* @param {String|Array} (Look in Constants under Types)
* @chainable
*/
Query.prototype.type = function(value) {
- this._filters.type = value;
+ this.config.filters.type = value;
return this;
}
@@ -738,39 +756,45 @@ Query.prototype.type = function(value) {
*
* @method transaction
* @for Query
-* @param {Number|Array} (Look in Constants under Transactions)
+* @param {String|Array} (Look in Constants under Transactions)
* @chainable
*/
Query.prototype.transaction = function(value) {
- this._filters.transaction = value;
+ this.config.filters.transaction = value;
return this;
}
+/*
+* Transform Value Object
+*
+* @private
+*/
+
+var TransformValue = {};
+
/*
* Translates simple filters object to apple api format
*
* @private
+* @function toBodyFilters
+* @for TransformValue
* @param {Object} filters
* @return {Object}
*/
-function translateToFilters(filters) {
+TransformValue.toBodyFilters = function(filters) {
var result = [];
- _.each(filters, function(values, dimension) {
- if(!_.isArray(values))
- values = [values];
-
- var dimension_key = translateToAppleKey(dimension);
-
- if(dimension_key === false)
- return;
+ _.each(filters, function(value, dimension) {
+ if(!_.isArray(value))
+ value = [value];
result.push({
- dimension_key : dimension_key,
- option_keys : values
+ dimension_key : TransformValue.toAppleKey(dimension),
+ option_keys : value
});
});
+
return result;
}
@@ -778,12 +802,16 @@ function translateToFilters(filters) {
* Translates key to apple key
*
* @private
+* @function toAppleKey
+* @for TransformValue
* @param {String} key
* @return {String}
*/
-function translateToAppleKey(key) {
- if(key === null) return key;
+TransformValue.toAppleKey = function(key) {
+ if(key === null)
+ return null;
+
var keys = {
content : "content",
type : "content_type",
@@ -792,9 +820,10 @@ function translateToAppleKey(key) {
platform : "platform",
location : "piano_location"
};
- if(typeof keys[key] === 'undefined') {
- throw new Error('Unknown filter or group key: ' + key);
- }
+
+ if(typeof keys[key] === 'undefined')
+ throw new Error('Unknown Apple Key for key: ' + key);
+
return keys[key];
}
@@ -802,11 +831,13 @@ function translateToAppleKey(key) {
* Translates given date to moment object
*
* @private
+* @function toMomentObject
+* @for TransformValue
* @param {Mixed} date
* @return {Moment}
*/
-function translateToMoment(date) {
+TransformValue.toMomentObject = function(date) {
// Quick check if moment
if(moment.isMoment(date)) {
return date;
@@ -814,7 +845,7 @@ function translateToMoment(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})/)))) {
+ else if(_.isString(date) && !!(date.match(new RegExp(/([0-9]{4})-([0-9]{2})-([0-9]{2})/)))) {
return moment(date, "YYYY-MM-DD");
}
else {
diff --git a/test/ReportQuery.js b/test/ReportQuery.js
index 7252a5c..f08e6a2 100644
--- a/test/ReportQuery.js
+++ b/test/ReportQuery.js
@@ -37,13 +37,13 @@ describe('ReportQuery', function(){
it('should have a default group property', function(done){
var query = ReportQuery.ranked();
- query.query.group.should.not.equal(null);
+ query.config.group.should.not.equal(null);
done();
})
it('should have properties start and end', function(done){
var query = ReportQuery.ranked();
- query.query.should.have.properties('start', 'end');
+ query.config.should.have.properties('start', 'end');
done();
})
@@ -53,20 +53,20 @@ describe('ReportQuery', function(){
var query = ReportQuery.ranked({
limit: 10
});
- query.query.limit.should.equal(10);
+ query.config.limit.should.equal(10);
done();
})
it('should overwrite default group property', function(done){
var query = ReportQuery.ranked({group: 'location'});
- query.query.group.should.not.equal('content');
+ query.config.group.should.not.equal('content');
done();
})
describe('group()', function(){
it('should overwrite query group value', function(done){
var query = ReportQuery.ranked({group: 'location'}).group('category');
- query.query.group.should.equal('category');
+ query.config.group.should.equal('category');
done();
})
})
@@ -143,7 +143,7 @@ describe('ReportQuery', function(){
var query = ReportQuery.timed().date('2014-10-02').time(1, 'day')
query.body();
- moment.isMoment(query.query.start).should.be.true;
+ moment.isMoment(query.config.start).should.be.true;
done();
})
@@ -151,7 +151,7 @@ describe('ReportQuery', function(){
var query = ReportQuery.timed().date('2014-10-02').time(1, 'day')
query.body();
- moment.isMoment(query.query.end).should.be.true;
+ moment.isMoment(query.config.end).should.be.true;
done();
})
@@ -159,28 +159,28 @@ describe('ReportQuery', function(){
var query = ReportQuery.timed().date('2014-10-02').time(1, 'day')
query.body();
- query.query.start.format('YYYY-MM-DD').should.equal('2014-10-01');
+ query.config.start.format('YYYY-MM-DD').should.equal('2014-10-01');
done();
})
it('should have start value one week before end date', function(done){
var query = ReportQuery.timed().date('2014-10-08').time(1, 'week')
query.body();
- query.query.start.format('YYYY-MM-DD').should.equal('2014-10-01');
+ query.config.start.format('YYYY-MM-DD').should.equal('2014-10-01');
done();
})
it('should have start value 2 months before end date', function(done){
var query = ReportQuery.timed().date('2014-10-02').time(2, 'months')
query.body();
- query.query.start.format('YYYY-MM-DD').should.equal('2014-08-02');
+ query.config.start.format('YYYY-MM-DD').should.equal('2014-08-02');
done();
})
it('should have start value 3 years before end date', function(done){
var query = ReportQuery.timed().date('2014-10-02').time(3, 'years')
query.body();
- query.query.start.format('YYYY-MM-DD').should.equal('2011-10-02');
+ query.config.start.format('YYYY-MM-DD').should.equal('2011-10-02');
done();
})
})