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 @@

Constants Class

- Defined in: index.js:37 + Defined in: index.js:31
diff --git a/docs/classes/Query.html b/docs/classes/Query.html index 2d7b83e..829b750 100644 --- a/docs/classes/Query.html +++ b/docs/classes/Query.html @@ -98,7 +98,7 @@

Query Class

- Defined in: index.js:429 + Defined in: index.js:443
@@ -155,6 +155,8 @@

Query

+ chainable + @@ -169,7 +171,7 @@

Query

- index.js:429 + index.js:443

@@ -409,7 +411,7 @@

body

- index.js:463 + index.js:473

@@ -435,6 +437,8 @@

Returns:

String: +

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 @@

Parameters:

-

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

@@ -752,7 +756,7 @@

Parameters:

-

If String must be in format YYYY-MM-DD

+

If String, must be in format YYYY-MM-DD

@@ -813,7 +817,7 @@

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 @@

Parameters:

  • <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 @@

    Parameters:

  • <value> - Number | Array + String | Array @@ -1833,7 +1837,7 @@

    type

    - index.js:722 + index.js:740

    @@ -1857,7 +1861,7 @@

    Parameters:

  • <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 @@

    ReportQuery Class

    - Defined in: index.js:293 + Defined in: index.js:305
    @@ -205,7 +205,7 @@

    ReportQuery

    - index.js:293 + index.js:305

    @@ -378,7 +378,7 @@

    Parameters:

  • [content] - String | Number | Array + Number | Array optional @@ -390,7 +390,7 @@

    Parameters:

  • [type] - String | Number | Array + String | Array optional @@ -402,7 +402,7 @@

    Parameters:

  • [transaction] - String | Number | Array + String | Array optional @@ -414,7 +414,7 @@

    Parameters:

  • [category] - String | Number | Array + Number | Array optional @@ -426,7 +426,7 @@

    Parameters:

  • [platform] - String | Number | Array + String | Array optional @@ -438,7 +438,7 @@

    Parameters:

  • [location] - String | Number | Array + Number | Array optional @@ -676,6 +676,8 @@

    ranked

    + chainable + @@ -690,7 +692,7 @@

    ranked

    - index.js:369 + index.js:381

    @@ -796,6 +798,8 @@

    timed

    + chainable + @@ -810,7 +814,7 @@

    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 @@

    Parameters:

  • - [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(); }) })