├── sjs-lib-index.txt
├── test
├── run.html
├── yql-tests.sjs
└── google-tests.sjs
├── freebase.sjs
├── lastfm.sjs
├── yql.sjs
├── google.sjs
└── asana.sjs
/sjs-lib-index.txt:
--------------------------------------------------------------------------------
1 | @lib SJS Web API Modules
2 | @summary Bindings to popular web apis
3 |
4 | @module asana
5 | @module freebase
6 | @module google
7 | @module lastfm
8 | @module yql
9 |
--------------------------------------------------------------------------------
/test/run.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | sjs-webapi tests
5 |
6 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/test/yql-tests.sjs:
--------------------------------------------------------------------------------
1 | var yql=require('../yql');
2 | var {test, context, assert} = require('sjs:test/suite');
3 |
4 | context {||
5 | test("query") {||
6 | var rv = yql.query("select * from html where url=@url and xpath='//h1'",
7 | {url:"http://www.stratifiedjs.org"});
8 | rv.results.h1.content .. assert.eq("Stratified");
9 | }
10 |
11 | test("getFile") {||
12 | var file = yql.getFile("http://stratifiedjs.org/presentations/OSCON2010/");
13 | file.indexOf("Alexander Fritze") .. assert.notEq(-1);
14 | }
15 |
16 | }.ignoreLeaks('_oni_jsonpcb');
17 |
--------------------------------------------------------------------------------
/test/google-tests.sjs:
--------------------------------------------------------------------------------
1 | var {test, assert, context} = require('sjs:test/suite');
2 | var g = require('../google');
3 | var logging = require('sjs:logging');
4 |
5 | context {||
6 | test('search') {||
7 | var results = g.search("croczilla");
8 | results.responseData.results[0].url .. assert.ok();
9 | }
10 |
11 | test('search(., {start:4})') {||
12 | var results = g.search("croczilla", {start:4});
13 | results.responseData.results[0].url .. assert.ok();
14 | }
15 |
16 | test('siteSearch(., {start:4})') {||
17 | var results = g.siteSearch("news", "http://cnn.com", {start:4});
18 | logging.info(results);
19 | results.responseData.results[0].url .. assert.ok();
20 | }
21 |
22 | test('translate') {||
23 | var response = g.translate("hello", "de");
24 | if (!response.responseData) return response.responseDetails;
25 | response.responseData.translatedText .. assert.eq("Hallo");
26 | }.skip("translate is now a paid api");
27 |
28 | test('BROKEN: load') {||
29 | g.load("language", "1");
30 | google.language.isFontRenderingSupported("hi") .. assert.ok();
31 | }.skip();
32 |
33 | }.ignoreLeaks('_oni_jsonpcb');
34 |
--------------------------------------------------------------------------------
/freebase.sjs:
--------------------------------------------------------------------------------
1 | /*
2 | * 'freebase' module
3 | * Bindings to the Freebase API
4 | *
5 | * (c) 2011 Oni Labs, http://onilabs.com
6 | *
7 | * This file is licensed under the terms of the MIT License:
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | *
27 | */
28 | /**
29 | @module freebase
30 | @summary Bindings to the [Freebase](http://freebase.com) API
31 | @home github:onilabs/sjs-webapi/master/freebase
32 | */
33 | var http = require("sjs:http");
34 | var sys = require("builtin:apollo-sys");
35 |
36 | var api_base = "http://api.freebase.com/api/service/"; // XXX do we want https?
37 |
38 | /**
39 | @function mqlread
40 | @summary See [freebase mqlread docs](http://freebase.com/docs/web_services/mqlread)
41 | @param {Object} [query] MQL query object
42 | @param {optional Object} [envelope_props] Hash of envelope parameters
43 | @return {Object}
44 | */
45 | function mqlread(query, envelope_props) {
46 | return http.jsonp([api_base, "mqlread",
47 | {query: JSON.stringify(sys.extendObject({query:query},
48 | envelope_props))}]);
49 | }
50 | exports.mqlread = mqlread;
51 |
52 | /**
53 | @function search
54 | @summary See [freebase api/service/search](http://freebase.com/docs/web_services/search)
55 | @param {String} [query] Search string
56 | @param {optional Object} [props] Hash of additional query parameters
57 | @return {Object}
58 | */
59 | function search(query, props) {
60 | return http.jsonp([api_base,"search",{query:query},props]);
61 | }
62 | exports.search = search;
63 |
64 |
--------------------------------------------------------------------------------
/lastfm.sjs:
--------------------------------------------------------------------------------
1 | /*
2 | * 'lastfm' module
3 | * Bindings to the lastfm API
4 | *
5 | * (c) 2010-2011 Oni Labs, http://onilabs.com
6 | *
7 | * This file is licensed under the terms of the MIT License:
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | *
27 | */
28 |
29 | /**
30 | @module lastfm
31 | @summary A wrapper around the Last.fm API
32 | @home github:onilabs/sjs-webapi/master/lastfm
33 | @desc
34 | This module uses the JSONP interface of [the Last.fm API](http://www.last.fm/api).
35 |
36 | var lastfm = require("sjs:webapi/lastfm");
37 | lastfm.key = "somekey...";
38 | var tracks = lastfm.get({
39 | method: "user.getrecenttracks",
40 | user: "rj"
41 | }).track;
42 | for (var i = 0; i < tracks.length; i++) {
43 | console.log(tracks[i].name);
44 | }
45 |
46 | */
47 | var http = require("sjs:http");
48 | var defaultKey = "b25b959554ed76058ac220b7b2e0a026";
49 |
50 | /**
51 | @variable key
52 | @summary A string containing the API key.
53 | By default it will use Last.fm's own demo key (which should not be used in production).
54 | */
55 | exports.key = defaultKey;
56 |
57 | /**
58 | @function get
59 | @summary Execute a remote method on the Last.fm API.
60 | @param {optional String} [method] A string defining the remote method you want to call.
61 | @param {optional Object} [params] Object with key/value pairs describing the request parameters.
62 | @return {Object}
63 | @desc
64 | ###Example
65 |
66 | var name = require("sjs:webapi/lastfm").get({
67 | method: "user.getinfo",
68 | user: "rj"
69 | }).realname;
70 | */
71 | exports.get = function () {
72 | if (!exports.key) {
73 | throw new Error("No Last.fm API key supplied");
74 | }
75 | if (exports.key == defaultKey) {
76 | //require("../xbrowser/console").warn() ??
77 | //using lastfm's demo key
78 | }
79 | if (typeof arguments[0] == "string") {
80 | var params = arguments[1] || {};
81 | params.method = arguments[0];
82 | }
83 | else {
84 | var params = arguments[0] || {};
85 | }
86 | var rv = http.jsonp(["http://ws.audioscrobbler.com/2.0/",
87 | {
88 | api_key: exports.key,
89 | format: "json",
90 | cb: Math.random()
91 | },
92 | params]);
93 | if (rv.error) {
94 | var e = new Error(rv.message);
95 | e.code = rv.error;
96 | throw e;
97 | }
98 | // prettify lastfm's xml->json conversion
99 | var count = 0;
100 | var first;
101 | for (first in rv) { if (++count > 1) break; }
102 | if (count == 1) return rv[first];
103 | return rv;
104 | };
105 | /*
106 | exports.getRecentTracks = function (user, limit) {
107 | limit = limit || 0;
108 | return exports.get({method: "user.getrecenttracks", user: user, limit: limit}).recenttracks.track;
109 | };
110 |
111 | exports.getFriends = function (user, recenttracks, limit) {
112 | limit = limit || 0;
113 | recenttracks = recenttracks || false;
114 | return exports.get({
115 | method: "user.getfriends",
116 | user: user,
117 | limit: limit,
118 | recenttracks: recenttracks
119 | }).friends.user;
120 | };
121 |
122 | exports.getTopArtists = function (user, period) {
123 | period = period || "overall";
124 | var rv = exports.get({
125 | method: "user.gettopartists",
126 | user: user,
127 | period: period
128 | }).topartists.artist;
129 | return (rv && rv.hasOwnProperty("length")) ? rv : [rv];
130 | //return toString.call(rv) === "[object Array]" ? rv : [rv]; // XXX doesn't work in Fx
131 | }
132 | */
133 |
134 |
--------------------------------------------------------------------------------
/yql.sjs:
--------------------------------------------------------------------------------
1 | /*
2 | * 'yql' module
3 | * Stratified wrapper for the YQL web service
4 | *
5 | * (c) 2010-2011 Oni Labs, http://onilabs.com
6 | *
7 | * This file is licensed under the terms of the MIT License:
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | *
27 | */
28 | /**
29 | @module yql
30 | @summary A stratified wrapper for the [Yahoo! Query Language](http://developer.yahoo.com/yql/) (YQL) Web Service,
31 | which enables you to access Internet data with SQL-like commands.
32 | @home github:onilabs/sjs-webapi/master/yql
33 | @desc
34 |
35 | var yql = require("sjs:webapi/yql");
36 | var q = "select * from html where url=@url and xpath='//h1'";
37 | var rv = yql.query(q, {url:"http://www.onilabs.com"});
38 |
39 | See the [::query] function for more examples.
40 | */
41 |
42 | var http = require("sjs:http");
43 |
44 | /**
45 | @function query
46 | @summary Execute a [YQL query](http://developer.yahoo.com/yql/guide/yql_overview_guide.html) on the Yahoo Web Service.
47 | @param {String} [statement] YQL query.
48 | @param {optional Object} [parameters] Key-value hash of parameters for the query.
49 | @return {Object} The query result.
50 | @desc
51 | The Yahoo! Query Language is an expressive SQL-like language that lets you query, filter, and join data across Web services.
52 | Debug your YQL queries in the [YQL Console](http://developer.yahoo.com/yql/console)
53 |
54 | ### HTML selector Example
55 |
56 | var yql = require("sjs:webapi/yql");
57 | var q = "select * from html where url=@url and xpath='//h1'";
58 | var rv = yql.query(q, {url:"http://www.onilabs.com"});
59 | c.log(rv.results.h1);
60 |
61 | ### Cross-domain XML Example
62 |
63 | var yql = require("sjs:webapi/yql");
64 | var q = "select * from xml where url=@url";
65 | var rv = yql.query(q, {
66 | url:"http://www.weather.gov/xml/current_obs/OOUH1.xml"
67 | });
68 | c.log(rv.results.current_observation.temp_c)
69 | */
70 | exports.query = function (statement, params) {
71 | var url = "http://query.yahooapis.com/v1/public/yql";
72 |
73 | params = params || {};
74 | if (params.communitytables) {
75 | delete params.communitytables;
76 | params.env = "store://datatables.org/alltableswithkeys";
77 | }
78 | var rv = http.jsonp([url, { q: statement, format: "json"}, params]);
79 | if (rv["error"]) {
80 | throw new Error(rv.error.description); // syntax error
81 | }
82 | if (rv.query && rv.query.results && rv.query.results.error) {
83 | var error = rv.query.results.error;
84 | throw new Error(error.description || error); // content error
85 | }
86 | return rv.query;
87 | };
88 |
89 | /**
90 | @function getFeed
91 | @summary Load a feed through the Yahoo Web Service.
92 | @shortcut query
93 | @param {String} [url] A string containing the URL of the requested Atom feed.
94 | @return {Array} An array of Atom entries
95 | @desc
96 | This is a convenience wrapper for [the feed table](http://developer.yahoo.com/yql/console/#h=desc%20feed).
97 |
98 | var yql = require("sjs:webapi/yql");
99 | var rv = yql.getFeed("http://planet.mozilla.org/atom.xml"});
100 | console.log(rv[0].title);`
101 | */
102 | exports.getFeed = function(url) {
103 | var q = "select * from atom where url=@url";
104 | return exports.query(q, {url:url}).results.item;
105 | };
106 |
107 | /*
108 | @function getXML
109 | @summary Loads an XML document through the Yahoo Web Service.
110 | @shortcut query
111 | @desc
112 | This is a convenience wrapper for [the xml table](http://developer.yahoo.com/yql/console/#h=desc%20xml).
113 | `var yql = require("sjs:webapi/yql");
114 | var xmlUrl = "http://www.weather.gov/xml/current_obs/OOUH1.xml";
115 | var honoluluWeather = yql.getXML(xmlUrl).current_observation;
116 | console.log(honoluluWeather.temp_c);`
117 | @param {String} [url] A string containing the URL of the requested XML document.
118 | @return {Object} An object describing the XML document.
119 | exports.getXML = function(url) {
120 | var q = "select * from xml where url=@url";
121 | return exports.query(q, {url:url}).results;
122 | };
123 | */
124 |
125 | /*
126 | @function getDataURI
127 | @summary Returns any file smaller than 25kb through the Yahoo Web Service as a data URI.
128 | @shortcut query
129 | @param {String} [url] A string containing the URL of the requested file.
130 | @return {Array} An array of Atom entries
131 | */
132 | exports.getDataURI = function(url) {
133 | var q = "select * from data.uri where url=@url";
134 | return exports.query(q, {url:url}).results.url;
135 | };
136 |
137 | /**
138 | @function getFile
139 | @summary Returns any file smaller than 25kb through the Yahoo Web Service as a string.
140 | @shortcut query
141 | @desc
142 | This is a convenience wrapper for [the data.uri table](http://developer.yahoo.com/yql/console/#h=desc%20data.uri).
143 | @param {String} [url] A string containing the URL of the requested file.
144 | @return {String}
145 | */
146 | exports.getFile = function(url) {
147 | var str = require("sjs:string");
148 | return str.utf8ToUtf16(str.base64ToOctets(exports.getDataURI(url).split("base64,")[1]));
149 | };
150 |
151 | /*
152 | var title = y.cssGet("http://www.croczilla.com/stratified", "h1").h1.content;
153 |
154 | exports.cssGet = function() {
155 | var rv = exports.query("select * from data.html.cssselect where url=@url and css=@css",
156 | {url:arguments[0],css:arguments[1]}, {communitytables:true}).results;
157 | return rv ? rv.results : null;
158 | };
159 | */
--------------------------------------------------------------------------------
/google.sjs:
--------------------------------------------------------------------------------
1 | /*
2 | * 'google' module
3 | * Bindings to various Google webservices and APIs
4 | *
5 | * (c) 2010-2011 Oni Labs, http://onilabs.com
6 | *
7 | * This file is licensed under the terms of the MIT License:
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | *
27 | */
28 | /**
29 | @module google
30 | @summary Bindings to various Google webservices and APIs
31 | @home github:onilabs/sjs-webapi/master/google
32 | */
33 | var http = require("sjs:http");
34 |
35 | /**
36 | @function search
37 | @summary Performs a Google web search query
38 | @param {String} [query] The search query to execute.
39 | @param {optional Object} [settings] Hash of additional
40 | key/value query parameters.
41 | @return {Object} The query result.
42 | @desc
43 | Uses the RESTful Google search API.
44 | See .
45 |
46 | **Example:**
47 |
48 | var s = require("sjs:webapi/google").search("Onilabs", {start:4});
49 | console.log(s.responseData.results[0].url); // first result
50 | */
51 | function search(q, settings) {
52 | return http.jsonp(["http://ajax.googleapis.com/ajax/services/search/web", {v: "1.0", q : q }, settings]);
53 | };
54 | exports.search = search;
55 |
56 | /**
57 | @function siteSearch
58 | @summary Performs a web search query limited to a particular site.
59 | @param {String} [query] The search query to execute.
60 | @param {String} [site] URL of site to limit the search to.
61 | @param {optional Object} [settings] Hash of additional
62 | key/value query parameters.
63 | @return {Object} The query result.
64 | @desc
65 | See [::search].
66 | */
67 | exports.siteSearch = function (q, site, settings) {
68 | q = q || "";
69 | q += " site:" + site;
70 | return search(q, settings);
71 | };
72 |
73 | /**
74 | @function translate
75 | @summary Translates a string of text using the Google Translation webservice.
76 | @param {String|Array} [text] A string containing the text to translate or an array specifying several strings for translation.
77 | @param {String|Array} [to] A string specifying the target language or an array specifying several target languages.
78 | @param {optional String} [from] An optional string specifying the source language.
79 | @param {optional Object} [extra] A hash of key/value pairs to append to the request.
80 | @return {Object} A ['Language Detection Result'](http://code.google.com/apis/ajaxlanguage/documentation/reference.html#detectResult)
81 | @desc
82 | Uses the RESTful Google Translation API v2
83 | See
84 |
85 | Note that as of August 2011, the Google Translate API is a paid service, so it
86 | requires an API key.
87 |
88 | Note that Google places a limit of ~2000 characters on request
89 | URIs. This limits the number of characters that can be translated by
90 | the API in one go.
91 |
92 | **Example:**
93 |
94 | var t = google.translate("hello", "de");
95 | console.log(t.translation, t.detectedSourceLanguage); // hallo, en
96 |
97 | */
98 | exports.translate = function(text, to, /* [opt] */ from, /* [opt] */ extra) {
99 | from = from || ""; // "" == autodetect
100 | var langpair;
101 | if (require('builtin:apollo-sys').isArrayLike(to)) {
102 | langpair = [];
103 | for (var i=0; i
191 |
192 | **Example:**
193 |
194 | require('sjs:webapi/google').load("language", "1");
195 | if (google.language.isFontRenderingSupported("hi"))
196 | ...
197 | */
198 | exports.load = function(moduleName, moduleVersion, settings) {
199 | ensureAPI();
200 | waitfor() {
201 | settings = settings || {};
202 | settings.callback = resume; // XXX we should really take a copy of settings
203 | google.load(moduleName, moduleVersion, settings);
204 | }
205 | return google[moduleName];
206 | };
207 |
208 |
--------------------------------------------------------------------------------
/asana.sjs:
--------------------------------------------------------------------------------
1 | /*
2 | * 'asana' module
3 | * Bindings to the Asana API
4 | *
5 | * (c) 2012 Oni Labs, http://onilabs.com
6 | *
7 | * This file is licensed under the terms of the MIT License:
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | *
27 | */
28 | /**
29 | @module asana
30 | @summary Bindings to the [Asana](http://asana.com) API
31 | @home github:onilabs/sjs-webapi/master/asana
32 | @hostenv nodejs
33 | @desc
34 | For more information about the Asana API, see http://developer.asana.com/documentation/
35 |
36 | ### Limitations:
37 |
38 | Because of Asana cross-domain policies, this module doesn't work in
39 | the xbrowser host environment (yet).
40 | */
41 |
42 | var http = require("sjs:http");
43 | var { merge } = require("sjs:object");
44 |
45 | /**
46 | @class Client
47 | @summary Asana API client
48 | @constructor Client
49 | @param {String} [apiKey] [Asana API Key](http://developer.asana.com/documentation/#api_keys)
50 | */
51 | function Client(apiKey) {
52 | this.apiKey = apiKey;
53 | }
54 | exports.Client = Client;
55 | /**
56 | @function makeClient
57 | @summary Shorthand for "`new Client(.)`".
58 | @param {String} [apiKey] [Asana API Key](http://developer.asana.com/documentation/#api_keys)
59 | */
60 | exports.makeClient = function(apiKey) { return new Client(apiKey); };
61 |
62 | Client.prototype = {};
63 |
64 | Client.prototype.request = function(method, path, opts) {
65 | opts = merge(
66 | {
67 | username: this.apiKey,
68 | password: "",
69 | method: method
70 | },
71 | opts);
72 | try {
73 | var rv = http.request(["https://app.asana.com/api/1.0/", path], opts);
74 | }
75 | catch (e){
76 | throw new Error("Asana API: "+e.status+" "+e.data);
77 | }
78 | return JSON.parse(rv).data;
79 | };
80 |
81 | //----------------------------------------------------------------------
82 | // Workspaces
83 |
84 | /**
85 | @function Client.listWorkspaces
86 | @summary Retrieve list of all reachable workspaces
87 | @return {Array} Array of `{id,name}` objects
88 | @desc
89 | Throws in error case.
90 | */
91 | Client.prototype.listWorkspaces = function() {
92 | return this.request("GET", "workspaces");
93 | };
94 |
95 | //----------------------------------------------------------------------
96 | // Projects
97 |
98 | /**
99 | @function Client.listProjects
100 | @summary Retrieve list of projects
101 | @param {optional Object} [settings] Hash of settings
102 | @setting {Boolean} [archived] If provided, this parameter will
103 | filter on projects whose `archived` field takes on the specified value.
104 | @setting {String|Integer} [workspace] If provided, this parameter will filter on projects
105 | which belong in the workspace with the specified id.
106 | @return {Array} Array of `{id,name}` objects
107 | @desc
108 | Throws in error case.
109 | */
110 | Client.prototype.listProjects = function(settings) {
111 | var params = {};
112 | if (settings) {
113 | if (typeof settings.archived != 'undefined') params.archived = settings.archived;
114 | if (typeof settings.workspace != 'undefined') params.workspace = settings.workspace;
115 | }
116 |
117 | return this.request("GET", ["projects", params]);
118 | };
119 |
120 | /**
121 | @function Client.getProject
122 | @summary Retrieve full record of project with given id
123 | @param {String|Integer} [id] Project ID
124 | @return {Object} [ ] [Project record](http://developer.asana.com/documentation/#projects)
125 | @desc
126 | Throws in error case.
127 | */
128 | Client.prototype.getProject = function(id) {
129 | return this.request("GET", ["projects", ""+id]);
130 | };
131 |
132 | /**
133 | @function Client.modifyProject
134 | @summary Modify project with given id
135 | @param {String|Integer} [id] Project ID
136 | @param {Object} [data] Object with data to modify (see http://developer.asana.com/documentation/#projects)
137 | @return {Object} Updated [project record](http://developer.asana.com/documentation/#projects)
138 | */
139 | Client.prototype.modifyProject = function(id, data) {
140 | return this.request("PUT", ["projects", ""+id], {body:JSON.stringify({data:data})});
141 | };
142 |
143 | //----------------------------------------------------------------------
144 | // Tasks
145 |
146 | /**
147 | @function Client.listTasks
148 | @summary Retrieve list of tasks
149 | @param {optional Object} [settings] Hash of settings
150 | @setting {String|Integer} [assignee] The ID of the assignee to filter tasks on.
151 | Only unarchived tasks in the assignee's list will be returned. **Note:**
152 | If you specify an `assignee`, you must also specify a `workspace` to
153 | filter on.
154 | @setting {String|Integer} [workspace] The ID of the workspace to filter tasks on.
155 | **Note:** If you specify a `workspace`, you must also specify an `assignee`
156 | to filter on.
157 | @setting {String|Integer} [project] The ID of the project to get tasks from.
158 | Only unarchived tasks in the project will be returned.
159 | @return {Array} Array of `{id,name}` objects
160 | @desc
161 | Throws in error case.
162 | */
163 | Client.prototype.listTasks = function(settings) {
164 | var params = {};
165 | if (settings) {
166 | for (var p in {'assignee':1, 'workspace':1, 'project':1}) {
167 | if (typeof settings[p] != 'undefined')
168 | params[p] = settings[p];
169 | }
170 | }
171 | return this.request("GET", ["tasks", params]);
172 | };
173 |
174 | /**
175 | @function Client.getTask
176 | @summary Retrieve full record of task with given id
177 | @param {String|Integer} [id] Task ID
178 | @return {Object} [ ] [Task record](http://developer.asana.com/documentation/#tasks)
179 | @desc
180 | Throws in error case.
181 | */
182 | Client.prototype.getTask = function(id) {
183 | return this.request("GET", ["tasks", ""+id]);
184 | };
185 |
186 | /**
187 | @function Client.modifyTask
188 | @summary Modify task with given id
189 | @param {String|Integer} [id] Task ID
190 | @param {Object} [data] Object with data to modify (see http://developer.asana.com/documentation/#tasks)
191 | @return {Object} Updated [task record](http://developer.asana.com/documentation/#tasks)
192 | */
193 | Client.prototype.modifyTask = function(id, data) {
194 | return this.request("PUT", ["tasks", ""+id], {body:JSON.stringify({data:data})});
195 | };
196 |
197 | /**
198 | @function Client.createTask
199 | @summary Create a new task
200 | @param {Object|Integer} [workspace_id] ID of workspace to create task in
201 | @param {Object} [data] Object with task data (see http://developer.asana.com/documentation/#tasks)
202 | @return {Object} [ ] [Task record](http://developer.asana.com/documentation/#tasks)
203 | */
204 | Client.prototype.createTask = function(workspace_id, data) {
205 | return this.request("POST", ["tasks",{workspace:""+workspace_id}], {body:JSON.stringify({data:data})});
206 | };
207 |
208 | /**
209 | @function Client.addTaskToProject
210 | @summary Associate a task with a project
211 | @param {Object|Integer} [task_id] ID of task
212 | @param {Object|Integer} [project_id] ID of project
213 | */
214 | Client.prototype.addTaskToProject = function(task_id, project_id) {
215 | return this.request("POST", ["tasks",""+task_id,"addProject"],{body:JSON.stringify({data:{project:""+project_id}})});
216 | };
217 |
218 | /**
219 | @function Client.removeTaskFromProject
220 | @summary Dissociate a task from a project
221 | @param {Object|Integer} [task_id] ID of task
222 | @param {Object|Integer} [project_id] ID of project
223 | */
224 | Client.prototype.removeTaskFromProject = function(task_id, project_id) {
225 | return this.request("POST", ["tasks",""+task_id,"removeProject"],{body:JSON.stringify({data:{project:""+project_id}})});
226 | };
227 |
228 |
229 | //----------------------------------------------------------------------
230 | // Users
231 |
232 | /**
233 | @function Client.listUsers
234 | @summary Retrieve list of users
235 | @param {optional Object} [settings] Hash of settings
236 | @setting {String|Integer} [workspace] If provided, this parameter will
237 | filter on users in the specified workspace.
238 | @return {Array} Array of `{id,name}` objects
239 | @desc
240 | Throws in error case.
241 | */
242 | Client.prototype.listUsers = function(settings) {
243 | var params = {};
244 | if (settings) {
245 | if (typeof settings.workspace != 'undefined') params.workspace = settings.workspace;
246 | }
247 |
248 | return this.request("GET", ["users", params]);
249 | };
250 |
251 |
252 | /**
253 | @function Client.getUser
254 | @summary Retrieve full record of user with given id
255 | @param {String|Integer} [id] User ID
256 | @return {Object} [ ] [User record](http://developer.asana.com/documentation/#users)
257 | @desc
258 | Throws in error case.
259 | */
260 | Client.prototype.getUser = function(id) {
261 | return this.request("GET", ["users", ""+id]);
262 | };
263 |
264 | //----------------------------------------------------------------------
265 | // Stories
266 |
267 | /**
268 | @function Client.listStories
269 | @summary Retrieve list of stories for a task
270 | @param {String|Integer} [task_id] ID of task
271 | @return {Array} Array of (compact) [story objects](http://developer.asana.com/documentation/#stories)
272 | @desc
273 | Throws in error case.
274 | */
275 | Client.prototype.listStories = function(task_id) {
276 | return this.request("GET", ["tasks", ""+task_id,"stories"]);
277 | };
278 |
279 | /**
280 | @function Client.getStory
281 | @summary Retrieve full record of story with given id
282 | @param {String|Integer} [id] Story ID
283 | @return {Object} [ ] [Story record](http://developer.asana.com/documentation/#stories)
284 | @desc
285 | Throws in error case.
286 | */
287 | Client.prototype.getStory = function(id) {
288 | return this.request("GET", ["stories", ""+id]);
289 | };
290 |
291 | /**
292 | @function Client.comment
293 | @summary Adds a comment to a task
294 | @param {String|Integer} [id] Task ID
295 | @param {String} [text] Comment text
296 | @return {Object} [ ] [Story record](http://developer.asana.com/documentation/#stories)
297 | @desc
298 | Throws in error case.
299 | */
300 | Client.prototype.comment = function(id, text) {
301 | return this.request("POST", ["tasks", ""+id, "stories"],{body:JSON.stringify({data:{text:""+text}})});
302 | };
303 |
--------------------------------------------------------------------------------