twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

helpers.js (3881B)


      1 var querystring = require('querystring');
      2 var request = require('request');
      3 
      4 var endpoints = require('./endpoints');
      5 
      6 /**
      7  * Encodes object as a querystring, to be used as the suffix of request URLs.
      8  * @param  {Object} obj
      9  * @return {String}
     10  */
     11 exports.makeQueryString = function (obj) {
     12   var qs = querystring.stringify(obj)
     13   qs = qs.replace(/\!/g, "%21")
     14          .replace(/\'/g, "%27")
     15          .replace(/\(/g, "%28")
     16          .replace(/\)/g, "%29")
     17          .replace(/\*/g, "%2A");
     18   return qs
     19 }
     20 
     21 /**
     22  * For each `/:param` fragment in path, move the value in params
     23  * at that key to path. If the key is not found in params, throw.
     24  * Modifies both params and path values.
     25  *
     26  * @param  {Objet} params  Object used to build path.
     27  * @param  {String} path   String to transform.
     28  * @return {Undefined}
     29  *
     30  */
     31 exports.moveParamsIntoPath = function (params, path) {
     32   var rgxParam = /\/:(\w+)/g
     33   var missingParamErr = null
     34 
     35   path = path.replace(rgxParam, function (hit) {
     36     var paramName = hit.slice(2)
     37     var suppliedVal = params[paramName]
     38     if (!suppliedVal) {
     39       throw new Error('Twit: Params object is missing a required parameter for this request: `'+paramName+'`')
     40     }
     41     var retVal = '/' + suppliedVal
     42     delete params[paramName]
     43     return retVal
     44   })
     45   return path
     46 }
     47 
     48 /**
     49  * When Twitter returns a response that looks like an error response,
     50  * use this function to attach the error info in the response body to `err`.
     51  *
     52  * @param  {Error} err   Error instance to which body info will be attached
     53  * @param  {Object} body JSON object that is the deserialized HTTP response body received from Twitter
     54  * @return {Undefined}
     55  */
     56 exports.attachBodyInfoToError = function (err, body) {
     57   err.twitterReply = body;
     58   if (!body) {
     59     return
     60   }
     61   if (body.error) {
     62     // the body itself is an error object
     63     err.message = body.error
     64     err.allErrors = err.allErrors.concat([body])
     65   } else if (body.errors && body.errors.length) {
     66     // body contains multiple error objects
     67     err.message = body.errors[0].message;
     68     err.code = body.errors[0].code;
     69     err.allErrors = err.allErrors.concat(body.errors)
     70   }
     71 }
     72 
     73 exports.makeTwitError = function (message) {
     74   var err = new Error()
     75   if (message) {
     76     err.message = message
     77   }
     78   err.code = null
     79   err.allErrors = []
     80   err.twitterReply = null
     81   return err
     82 }
     83 
     84 /**
     85  * Get a bearer token for OAuth2
     86  * @param  {String}   consumer_key
     87  * @param  {String}   consumer_secret
     88  * @param  {Function} cb
     89  *
     90  * Calls `cb` with Error, String
     91  *
     92  * Error (if it exists) is guaranteed to be Twit error-formatted.
     93  * String (if it exists) is the bearer token received from Twitter.
     94  */
     95 exports.getBearerToken = function (consumer_key, consumer_secret, cb) {
     96   // use OAuth 2 for app-only auth (Twitter requires this)
     97   // get a bearer token using our app's credentials
     98   var b64Credentials = new Buffer(consumer_key + ':' + consumer_secret).toString('base64');
     99   request.post({
    100     url: endpoints.API_HOST + 'oauth2/token',
    101     headers: {
    102       'Authorization': 'Basic ' + b64Credentials,
    103       'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
    104     },
    105     body: 'grant_type=client_credentials',
    106     json: true,
    107   }, function (err, res, body) {
    108     if (err) {
    109       var error = exports.makeTwitError(err.toString());
    110       exports.attachBodyInfoToError(error, body);
    111       return cb(error, body, res);
    112     }
    113 
    114     if ( !body ) {
    115       var error = exports.makeTwitError('Not valid reply from Twitter upon obtaining bearer token');
    116       exports.attachBodyInfoToError(error, body);
    117       return cb(error, body, res);
    118     }
    119 
    120     if (body.token_type !== 'bearer') {
    121       var error = exports.makeTwitError('Unexpected reply from Twitter upon obtaining bearer token');
    122       exports.attachBodyInfoToError(error, body);
    123       return cb(error, body, res);
    124     }
    125 
    126     return cb(err, body.access_token);
    127   })
    128 }