<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var EventEmitter = require('events').EventEmitter;
var inherits = require('util').inherits;

var emptyTracing = Buffer(25); // TODO: proper tracing object
var emptyBuffer = Buffer(0);

// TODO: provide streams for arg2/3

function TChannelIncomingRequest(id, options) {
    if (!(this instanceof TChannelIncomingRequest)) {
        return new TChannelIncomingRequest(id, options);
    }
    options = options || {};
    var self = this;
    EventEmitter.call(self);
    self.id = id || 0;
    self.ttl = options.ttl || 0;
    self.tracing = options.tracing || emptyTracing;
    self.service = options.service || '';
    self.remoteAddr = null;
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.arg1 = options.arg1 || emptyBuffer;
    self.arg2 = options.arg2 || emptyBuffer;
    self.arg3 = options.arg3 || emptyBuffer;
}

inherits(TChannelIncomingRequest, EventEmitter);

function TChannelIncomingResponse(id, options) {
    if (!(this instanceof TChannelIncomingResponse)) {
        return new TChannelIncomingResponse(id, options);
    }
    options = options || {};
    var self = this;
    EventEmitter.call(self);
    self.id = id || 0;
    self.code = options.code || 0;
    self.arg1 = options.arg1 || emptyBuffer;
    self.arg2 = options.arg2 || emptyBuffer;
    self.arg3 = options.arg3 || emptyBuffer;
    self.ok = self.code === 0; // TODO: probably okay, but a bit jank
}

inherits(TChannelIncomingResponse, EventEmitter);

function TChannelOutgoingRequest(id, options, sendFrame) {
    if (!(this instanceof TChannelOutgoingRequest)) {
        return new TChannelOutgoingRequest(id, options, sendFrame);
    }
    options = options || {};
    var self = this;
    EventEmitter.call(self);
    self.id = id || 0;
    self.ttl = options.ttl || 0;
    self.tracing = options.tracing || emptyTracing;
    self.service = options.service || '';
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.sendFrame = sendFrame;
    self.sent = false;
}

inherits(TChannelOutgoingRequest, EventEmitter);

TChannelOutgoingRequest.prototype.send = function send(arg1, arg2, arg3, callback) {
    var self = this;
    if (callback) self.hookupCallback(callback);
    if (self.sent) {
        throw new Error('request already sent');
    }
    self.sent = true;
    self.sendFrame(arg1, arg2, arg3);
    self.emit('end');
    return self;
};

TChannelOutgoingRequest.prototype.hookupCallback = function hookupCallback(callback) {
    var self = this;
    self.once('error', onError);
    self.once('response', onResponse);
    function onError(err) {
        self.removeListener('response', onResponse);
        callback(err, null);
    }
    function onResponse(res) {
        self.removeListener('error', onError);
        callback(null, res);
    }
    return self;
};

function TChannelOutgoingResponse(id, options, senders) {
    if (!(this instanceof TChannelOutgoingResponse)) {
        return new TChannelOutgoingResponse(id, options, senders);
    }

    options = options || {};
    var self = this;
    EventEmitter.call(self);
    self.id = id || 0;
    self.code = options.code || 0;
    self.tracing = options.tracing || emptyTracing;
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.ok = true;
    self.arg1 = options.arg1 || emptyBuffer;
    self.arg2 = options.arg2 || emptyBuffer;
    self.arg3 = options.arg3 || emptyBuffer;
    self.sendCallResponseFrame = senders.callResponseFrame;
    self.sendErrorFrame = senders.errorFrame;
    self.sent = false;
}

inherits(TChannelOutgoingResponse, EventEmitter);

TChannelOutgoingResponse.prototype.sendOk = function send(res1, res2) {
    var self = this;
    if (self.sent) {
        throw new Error('response already sent');
    }

    self.sent = true;
    self.ok = true;

    self.sendCallResponseFrame(self.arg1, res1, res2);
    self.emit('end');
};

TChannelOutgoingResponse.prototype.sendNotOk = function sendNotOk(res1, res2) {
    var self = this;
    if (self.sent) {
        throw new Error('response already sent');
    }

    self.sent = true;
    self.ok = false;
    self.code = 1;

    self.sendCallResponseFrame(self.arg1, res1, res2);
    self.emit('end');
};

module.exports.IncomingRequest = TChannelIncomingRequest;
module.exports.IncomingResponse = TChannelIncomingResponse;
module.exports.OutgoingRequest = TChannelOutgoingRequest;
module.exports.OutgoingResponse = TChannelOutgoingResponse;
<commit_msg>Cast args to buffers in reqres sending<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var EventEmitter = require('events').EventEmitter;
var inherits = require('util').inherits;

var emptyTracing = Buffer(25); // TODO: proper tracing object
var emptyBuffer = Buffer(0);

// TODO: provide streams for arg2/3

function TChannelIncomingRequest(id, options) {
    if (!(this instanceof TChannelIncomingRequest)) {
        return new TChannelIncomingRequest(id, options);
    }
    options = options || {};
    var self = this;
    EventEmitter.call(self);
    self.id = id || 0;
    self.ttl = options.ttl || 0;
    self.tracing = options.tracing || emptyTracing;
    self.service = options.service || '';
    self.remoteAddr = null;
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.arg1 = options.arg1 || emptyBuffer;
    self.arg2 = options.arg2 || emptyBuffer;
    self.arg3 = options.arg3 || emptyBuffer;
}

inherits(TChannelIncomingRequest, EventEmitter);

function TChannelIncomingResponse(id, options) {
    if (!(this instanceof TChannelIncomingResponse)) {
        return new TChannelIncomingResponse(id, options);
    }
    options = options || {};
    var self = this;
    EventEmitter.call(self);
    self.id = id || 0;
    self.code = options.code || 0;
    self.arg1 = options.arg1 || emptyBuffer;
    self.arg2 = options.arg2 || emptyBuffer;
    self.arg3 = options.arg3 || emptyBuffer;
    self.ok = self.code === 0; // TODO: probably okay, but a bit jank
}

inherits(TChannelIncomingResponse, EventEmitter);

function TChannelOutgoingRequest(id, options, sendFrame) {
    if (!(this instanceof TChannelOutgoingRequest)) {
        return new TChannelOutgoingRequest(id, options, sendFrame);
    }
    options = options || {};
    var self = this;
    EventEmitter.call(self);
    self.id = id || 0;
    self.ttl = options.ttl || 0;
    self.tracing = options.tracing || emptyTracing;
    self.service = options.service || '';
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.sendFrame = sendFrame;
    self.sent = false;
}

inherits(TChannelOutgoingRequest, EventEmitter);

TChannelOutgoingRequest.prototype.send = function send(arg1, arg2, arg3, callback) {
    var self = this;
    if (callback) self.hookupCallback(callback);
    if (self.sent) {
        throw new Error('request already sent');
    }
    self.sent = true;
    self.sendFrame(
        arg1 ? Buffer(arg1) : null,
        arg2 ? Buffer(arg2) : null,
        arg3 ? Buffer(arg3) : null);
    self.emit('end');
    return self;
};

TChannelOutgoingRequest.prototype.hookupCallback = function hookupCallback(callback) {
    var self = this;
    self.once('error', onError);
    self.once('response', onResponse);
    function onError(err) {
        self.removeListener('response', onResponse);
        callback(err, null);
    }
    function onResponse(res) {
        self.removeListener('error', onError);
        callback(null, res);
    }
    return self;
};

function TChannelOutgoingResponse(id, options, senders) {
    if (!(this instanceof TChannelOutgoingResponse)) {
        return new TChannelOutgoingResponse(id, options, senders);
    }

    options = options || {};
    var self = this;
    EventEmitter.call(self);
    self.id = id || 0;
    self.code = options.code || 0;
    self.tracing = options.tracing || emptyTracing;
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.ok = true;
    self.arg1 = options.arg1 || emptyBuffer;
    self.arg2 = options.arg2 || emptyBuffer;
    self.arg3 = options.arg3 || emptyBuffer;
    self.sendCallResponseFrame = senders.callResponseFrame;
    self.sendErrorFrame = senders.errorFrame;
    self.sent = false;
}

inherits(TChannelOutgoingResponse, EventEmitter);

TChannelOutgoingResponse.prototype.sendOk = function send(res1, res2) {
    var self = this;
    if (self.sent) {
        throw new Error('response already sent');
    }

    self.sent = true;
    self.ok = true;

    self.sendCallResponseFrame(self.arg1,
        res1 ? Buffer(res1) : null,
        res2 ? Buffer(res2) : null);
    self.emit('end');
};

TChannelOutgoingResponse.prototype.sendNotOk = function sendNotOk(res1, res2) {
    var self = this;
    if (self.sent) {
        throw new Error('response already sent');
    }

    self.sent = true;
    self.ok = false;
    self.code = 1;

    self.sendCallResponseFrame(self.arg1,
        res1 ? Buffer(res1) : null,
        res2 ? Buffer(res2) : null);
    self.emit('end');
};

module.exports.IncomingRequest = TChannelIncomingRequest;
module.exports.IncomingResponse = TChannelIncomingResponse;
module.exports.OutgoingRequest = TChannelOutgoingRequest;
module.exports.OutgoingResponse = TChannelOutgoingResponse;
<|endoftext|>


<commit_before>// JSON-P Twitter fetcher for Octopress
// (c) Brandon Mathis // MIT Lisence

/* Sky Slavin, Ludopoli. MIT license.  * based on JavaScript Pretty Date * Copyright (c) 2008 John Resig (jquery.com) * Licensed under the MIT license.  */
function prettyDate(time) {
  if (navigator.appName === 'Microsoft Internet Explorer') {
    return "∞"; // because IE date parsing isn't fun.
  }

  var say = {
    just_now:    " now",
    minute_ago:  "1m",
    minutes_ago: "m",
    hour_ago:    "1h",
    hours_ago:   "h",
    yesterday:   "1d",
    days_ago:    "d",
    weeks_ago:   "w"
  };

  var current_date = new Date(),
      current_date_time = current_date.getTime(),
      current_date_full = current_date_time + (1 * 60000),
      date = new Date(time),
      diff = ((current_date_full - date.getTime()) / 1000),
      day_diff = Math.floor(diff / 86400);

  if (isNaN(day_diff) || day_diff < 0) { return "∞"; }

  return day_diff === 0 && (
    diff < 60 && say.just_now ||
    diff < 120 && say.minute_ago ||
    diff < 3600 && Math.floor(diff / 60) + say.minutes_ago ||
    diff < 7200 && say.hour_ago ||
    diff < 86400 && Math.floor(diff / 3600) + say.hours_ago) ||
    day_diff === 1 && say.yesterday ||
    day_diff < 7 && day_diff + say.days_ago ||
    day_diff > 7 && Math.ceil(day_diff / 7) + say.weeks_ago;
}

function linkifyTweet(text, url) {
  // Linkify urls, usernames, hashtags
  text = text.replace(/(https?:\/\/)([\w\-:;?&=+.%#\/]+)/gi, '$2')
    .replace(/(^|\W)@(\w+)/g, '$1@$2')
    .replace(/(^|\W)#(\w+)/g, '$1#$2');

  // Use twitter's api to replace t.co shortened urls with expanded ones.
  for (var u in url) {
    if(url[u].expanded_url != null){
      var shortUrl = new RegExp( url[u].url.replace(/https?:\/\//, ''), 'g');
      text = text.replace(shortUrl, url[u].display_url);
      console.log(text);
    }
  }
  return text
}

function showTwitterFeed(tweets, twitter_user) {
  var timeline = document.getElementById('tweets'),
      content = '';

  for (var t in tweets) {
    content += '
'+'
'+''+prettyDate(tweets[t].created_at)+''+linkifyTweet(tweets[t].text.replace(/\n/g, '
'), tweets[t].entities.urls)+'
'+'
';
  }
  timeline.innerHTML = content;
}

function getTwitterFeed(user, count, replies) {
  $.ajax({
      url: "http://api.twitter.com/1/statuses/user_timeline/" + user + ".json?trim_user=true&count=" + (parseInt(count, 10)) + "&include_entities=1&exclude_replies=" + (replies ? "0" : "1") + "&callback=?"
    , type: 'jsonp'
    , error: function (err) { $('#tweets li.loading').addClass('error').text("Twitter's busted"); }
    , success: function(data) { showTwitterFeed(data, user); }
  })
}

<commit_msg>added buffer for mentions in twitter stream<commit_after>// JSON-P Twitter fetcher for Octopress
// (c) Brandon Mathis // MIT Lisence

/* Sky Slavin, Ludopoli. MIT license.  * based on JavaScript Pretty Date * Copyright (c) 2008 John Resig (jquery.com) * Licensed under the MIT license.  */
function prettyDate(time) {
  if (navigator.appName === 'Microsoft Internet Explorer') {
    return "∞"; // because IE date parsing isn't fun.
  }

  var say = {
    just_now:    " now",
    minute_ago:  "1m",
    minutes_ago: "m",
    hour_ago:    "1h",
    hours_ago:   "h",
    yesterday:   "1d",
    days_ago:    "d",
    weeks_ago:   "w"
  };

  var current_date = new Date(),
      current_date_time = current_date.getTime(),
      current_date_full = current_date_time + (1 * 60000),
      date = new Date(time),
      diff = ((current_date_full - date.getTime()) / 1000),
      day_diff = Math.floor(diff / 86400);

  if (isNaN(day_diff) || day_diff < 0) { return "∞"; }

  return day_diff === 0 && (
    diff < 60 && say.just_now ||
    diff < 120 && say.minute_ago ||
    diff < 3600 && Math.floor(diff / 60) + say.minutes_ago ||
    diff < 7200 && say.hour_ago ||
    diff < 86400 && Math.floor(diff / 3600) + say.hours_ago) ||
    day_diff === 1 && say.yesterday ||
    day_diff < 7 && day_diff + say.days_ago ||
    day_diff > 7 && Math.ceil(day_diff / 7) + say.weeks_ago;
}

function linkifyTweet(text, url) {
  // Linkify urls, usernames, hashtags
  text = text.replace(/(https?:\/\/)([\w\-:;?&=+.%#\/]+)/gi, '$2')
    .replace(/(^|\W)@(\w+)/g, '$1@$2')
    .replace(/(^|\W)#(\w+)/g, '$1#$2');

  // Use twitter's api to replace t.co shortened urls with expanded ones.
  for (var u in url) {
    if(url[u].expanded_url != null){
      var shortUrl = new RegExp( url[u].url.replace(/https?:\/\//, ''), 'g');
      text = text.replace(shortUrl, url[u].display_url);
    }
  }
  return text
}

function showTwitterFeed(tweets, twitter_user) {
  var timeline = document.getElementById('tweets'),
      content = '';

  for (var t in tweets) {
    content += '
'+'
'+''+prettyDate(tweets[t].created_at)+''+linkifyTweet(tweets[t].text.replace(/\n/g, '
'), tweets[t].entities.urls)+'
'+'
';
  }
  timeline.innerHTML = content;
}

function getTwitterFeed(user, count, replies) {
  count = parseInt(count, 10);
  $.ajax({
      url: "http://api.twitter.com/1/statuses/user_timeline/" + user + ".json?trim_user=true&count=" + (count + 20) + "&include_entities=1&exclude_replies=" + (replies ? "0" : "1") + "&callback=?"
    , type: 'jsonp'
    , error: function (err) { $('#tweets li.loading').addClass('error').text("Twitter's busted"); }
    , success: function(data) { showTwitterFeed(data.slice(0, count), user); }
  })
}
<|endoftext|>


<commit_before>const fs = require('fs');
const http = require('http');
const inquirer = require('inquirer');
const urlParser = require('url');
const querystring = require('querystring');
const request = require('request');

const OAUTH_PORT = 3333;
const DEFAULT_REDIRECT_URI = 'http://localhost:' + OAUTH_PORT;

const datafire = require('../index');
const logger = require('../lib/logger');

const QUESTION_SETS = {
  alias: [
    {name: 'alias', message: "Choose an alias for this account:"}
  ],
  basic: [
    {name: 'username', message: "username:"},
    {name: 'password', message: "password:", type: 'password'},
  ],
  apiKey: [
    {name: 'api_key', message: "api_key:"},
  ],
  oauth_client: [
    {name: 'client_id', message: "client_id:"},
    {name: 'client_secret', message: "client_secret:"},
    {name: 'redirect_uri', message: "redirect_uri:", default: DEFAULT_REDIRECT_URI},
  ],
  oauth_tokens: [
    {name: 'access_token', message: "access_token:"},
    {name: 'refresh_token', message: "refresh_token (optional):"},
  ],
  scopes: [
    {name: 'scopes', type: 'checkbox', message: 'Choose at least one scope to authorize'},
  ]
}

QUESTION_SETS.oauth2 = QUESTION_SETS.oauth_tokens.concat(QUESTION_SETS.oauth_client);

let setDefaults = (questions, defaults) => {
  return questions.map(q => {
    return {
      name: q.name,
      message: q.message,
      type: q.type,
      default: defaults[q.name],
    }
  });
}

let getAccounts = (integration) => {
  let credFile = datafire.credentialsDirectory + '/' + integration + '.json';
  return fs.existsSync(credFile) ? require(credFile) : {};
}

module.exports = (args) => {
  try {
    fs.mkdirSync(datafire.credentialsDirectory);
  } catch (e) {}

  let integration = datafire.Integration.new(args.integration);
  integration.initialize(err => {
    if (err) throw err;
    let secDefs = integration.spec.securityDefinitions;
    if (!secDefs || !Object.keys(secDefs).length) {
      logger.logError("No security definitions found for " + args.integration);
      return;
    }
    let secOptions = Object.keys(secDefs).map(name => {
      return {
        name: name,
        def: secDefs[name],
      }
    });
    let accounts = getAccounts(integration.name);
    let accountToEdit = null;
    let secOption = secOptions[0];
    if (args.as) {
      accountToEdit = accounts[args.as];
      if (!accountToEdit) throw new Error("Account " + args.as + " not found");
      secOption = secOptions.filter(o => o.name === accountToEdit.securityDefinition)[0];
      if (!secOption) throw new Error("Security definition " + accountToEdit.securityDefinition + " not found");
    }
    if (args.generate_token) {
      let clientAccount = accountToEdit;
      if (args.client) {
        clientAccount = accounts[args.client];
      }
      generateToken(integration, secOption, accounts, accountToEdit, clientAccount);
    } else if (secOptions.length === 1) {
      authenticate(integration, secOption, accounts, accountToEdit);
    } else if (accountToEdit) {
      authenticate(integration, secOption, accounts, accountToEdit);
    } else {
      let question = {name: 'definition', message: "This API has multiple authentication flows. Which do you want to use?", type: 'list'};
      question.choices = secOptions.map(o => ({name: o.def.type + ' (' + o.name + ')', value: o}))
      inquirer.prompt([question]).then(answers => {
        authenticate(integration, answers.definition, accounts, accountToEdit);
      })
    }
  })
}

let authenticate = (integration, secOption, accounts, accountToEdit) => {
  let questions = QUESTION_SETS[secOption.def.type];
  if (accountToEdit) questions = setDefaults(questions, accountToEdit);
  inquirer.prompt(questions).then(answers => {
    for (let k in answers) {
      if (!answers[k]) delete answers[k];
    }
    answers.securityDefinition = secOption.name;
    if (accountToEdit) {
      for (let k in answers) accountToEdit[k] = answers[k];
      saveAccounts(integration, accounts);
      return
    } else {
      inquirer.prompt(QUESTION_SETS.alias).then(aliasAnswer => {
        accounts[aliasAnswer.alias] = answers;
        saveAccounts(integration, accounts);
      })
    }
  })
}

let generateToken = (integration, secOption, accounts, accountToEdit, clientAccount) => {
  let questions = [];
  if (!accountToEdit) questions = questions.concat(QUESTION_SETS.alias);
  if (!clientAccount) questions = questions.concat(QUESTION_SETS.oauth_client);
  inquirer.prompt(questions).then(answers => {
    if (answers.alias) accountToEdit = accounts[answers.alias] = {};
    if (answers.client_id) accountToEdit.client_id = answers.client_id;
    if (answers.client_secret) accountToEdit.client_secret = answers.client_secret;
    if (answers.redirect_uri) accountToEdit.redirect_uri = answers.redirect_uri;
    if (!clientAccount) clientAccount = accountToEdit;
    accountToEdit.securityDefinition = secOption.name;
    startOAuthServer(integration, secOption.def, accounts, accountToEdit, clientAccount)
  })
}
let saveAccounts = (integration, accounts) => {
  let oldCreds = getAccounts(integration.name);
  let credFile = datafire.credentialsDirectory + '/' + integration.name + '.json';
  logger.log('Saving credentials to ' + credFile.replace(process.cwd(), '.'));
  fs.writeFileSync(credFile, JSON.stringify(accounts, null, 2));
}

let getOAuthURL = (integration, secDef, clientAccount, scopes) => {
  var flow = secDef.flow;
  var url = secDef.authorizationUrl;
  var state = Math.random();
  url += '?response_type=' + (flow === 'implicit' ? 'token' : 'code');
  url += '&redirect_uri=' + clientAccount.redirect_uri || DEFAULT_REDIRECT_URI;
  url += '&client_id=' + encodeURIComponent(clientAccount.client_id);
  if (flow === 'accessCode') url += '&access_type=offline';
  if (scopes.length > 0) {
    url += '&scope=' + encodeURIComponent(scopes.join(' '));
  }
  url += '&state=' + encodeURIComponent(state);
  return url;
}

let startOAuthServer = (integration, secDef, accounts, accountToEdit, clientAccount) => {
  let server = http.createServer((req, res) => {
    let urlObj = urlParser.parse(req.url);
    if (urlObj.pathname !== '/') {
      res.writeHead(404);
      res.end();
      return;
    }
    let search = urlParser.parse(req.url).search || '?';
    search = search.substring(1);
    search = querystring.parse(search);
    if (search.code) {
      request.post({
        url: secDef.tokenUrl,
        form: {
          code: search.code,
          client_id: clientAccount.client_id,
          client_secret: clientAccount.client_secret,
          redirect_uri: clientAccount.redirect_uri || DEFAULT_REDIRECT_URI,
          grant_type: 'authorization_code',
        },
        json: true,
      }, (err, resp, body) => {
        let newURL = '/?saved=true#access_token=' + encodeURIComponent(body.access_token);
        newURL += '&refresh_token=' + encodeURIComponent(body.refresh_token);
        newURL += '&saved=true';
        res.writeHead(302, {
          'Location': newURL,
        });
        res.end();
        accountToEdit.access_token = body.access_token;
        accountToEdit.refresh_token = body.refresh_token;
        saveAccounts(integration, accounts);
      })
    } else {
      fs.readFile(__dirname + '/../www/oauth_callback.html', 'utf8', (err, data) => {
        if (err) throw err;
        res.end(data);
        if (!search.saved) {
          inquirer.prompt(QUESTION_SETS.oauth_tokens).then(answers => {
            if (answers.access_token) accountToEdit.access_token = answers.access_token;
            if (answers.refresh_token) accountToEdit.refresh_token = answers.refresh_token;
            saveAccounts(integration, accounts);
            server.close();
            process.exit(0);
          })
        } else {
          server.close();
          process.exit(0);
        }
      })
    }
  }).listen(OAUTH_PORT, (err) => {
    if (err) throw err;
    QUESTION_SETS.scopes[0].choices = Object.keys(secDef.scopes).map(s => {
      return {value: s, name: s + ' (' + secDef.scopes[s] + ')'}
    })
    inquirer.prompt(QUESTION_SETS.scopes).then(answers => {
      let url = getOAuthURL(integration, secDef, clientAccount, answers.scopes);
      logger.log("Visit this url to retrieve your access and refresh tokens:")
      logger.logURL(url);
    })
  });
}
<commit_msg>add set default<commit_after>const fs = require('fs');
const http = require('http');
const inquirer = require('inquirer');
const urlParser = require('url');
const querystring = require('querystring');
const request = require('request');

const OAUTH_PORT = 3333;
const DEFAULT_REDIRECT_URI = 'http://localhost:' + OAUTH_PORT;

const datafire = require('../index');
const logger = require('../lib/logger');

const QUESTION_SETS = {
  alias: [
    {name: 'alias', message: "Choose an alias for this account:"}
  ],
  basic: [
    {name: 'username', message: "username:"},
    {name: 'password', message: "password:", type: 'password'},
  ],
  apiKey: [
    {name: 'api_key', message: "api_key:"},
  ],
  oauth_client: [
    {name: 'client_id', message: "client_id:"},
    {name: 'client_secret', message: "client_secret:"},
    {name: 'redirect_uri', message: "redirect_uri:", default: DEFAULT_REDIRECT_URI},
  ],
  oauth_tokens: [
    {name: 'access_token', message: "access_token:"},
    {name: 'refresh_token', message: "refresh_token (optional):"},
  ],
  scopes: [
    {name: 'scopes', type: 'checkbox', message: 'Choose at least one scope to authorize'},
  ]
}

QUESTION_SETS.oauth2 = QUESTION_SETS.oauth_tokens.concat(QUESTION_SETS.oauth_client);

let setDefaults = (questions, defaults) => {
  return questions.map(q => {
    return {
      name: q.name,
      message: q.message,
      type: q.type,
      default: defaults[q.name],
    }
  });
}

let getAccounts = (integration) => {
  let credFile = datafire.credentialsDirectory + '/' + integration + '.json';
  return fs.existsSync(credFile) ? require(credFile) : {};
}

module.exports = (args) => {
  try {
    fs.mkdirSync(datafire.credentialsDirectory);
  } catch (e) {}

  let integration = datafire.Integration.new(args.integration);
  integration.initialize(err => {
    if (err) throw err;
    let secDefs = integration.spec.securityDefinitions;
    if (!secDefs || !Object.keys(secDefs).length) {
      logger.logError("No security definitions found for " + args.integration);
      return;
    }
    let secOptions = Object.keys(secDefs).map(name => {
      return {
        name: name,
        def: secDefs[name],
      }
    });
    let accounts = getAccounts(integration.name);
    let accountToEdit = null;
    let secOption = secOptions[0];
    if (args.as) {
      accountToEdit = accounts[args.as];
      if (!accountToEdit) throw new Error("Account " + args.as + " not found");
      secOption = secOptions.filter(o => o.name === accountToEdit.securityDefinition)[0];
      if (!secOption) throw new Error("Security definition " + accountToEdit.securityDefinition + " not found");
    }
    if (args.set_default) {
      accounts.default = args.set_default;
      saveAccounts(integration, accounts);
    } else if (args.generate_token) {
      let clientAccount = accountToEdit;
      if (args.client) {
        clientAccount = accounts[args.client];
      }
      generateToken(integration, secOption, accounts, accountToEdit, clientAccount);
    } else if (secOptions.length === 1) {
      authenticate(integration, secOption, accounts, accountToEdit);
    } else if (accountToEdit) {
      authenticate(integration, secOption, accounts, accountToEdit);
    } else {
      let question = {name: 'definition', message: "This API has multiple authentication flows. Which do you want to use?", type: 'list'};
      question.choices = secOptions.map(o => ({name: o.def.type + ' (' + o.name + ')', value: o}))
      inquirer.prompt([question]).then(answers => {
        authenticate(integration, answers.definition, accounts, accountToEdit);
      })
    }
  })
}

let authenticate = (integration, secOption, accounts, accountToEdit) => {
  let questions = QUESTION_SETS[secOption.def.type];
  if (accountToEdit) questions = setDefaults(questions, accountToEdit);
  inquirer.prompt(questions).then(answers => {
    for (let k in answers) {
      if (!answers[k]) delete answers[k];
    }
    answers.securityDefinition = secOption.name;
    if (accountToEdit) {
      for (let k in answers) accountToEdit[k] = answers[k];
      saveAccounts(integration, accounts);
      return
    } else {
      inquirer.prompt(QUESTION_SETS.alias).then(aliasAnswer => {
        accounts[aliasAnswer.alias] = answers;
        saveAccounts(integration, accounts);
      })
    }
  })
}

let generateToken = (integration, secOption, accounts, accountToEdit, clientAccount) => {
  let questions = [];
  if (!accountToEdit) questions = questions.concat(QUESTION_SETS.alias);
  if (!clientAccount) questions = questions.concat(QUESTION_SETS.oauth_client);
  inquirer.prompt(questions).then(answers => {
    if (answers.alias) accountToEdit = accounts[answers.alias] = {};
    if (answers.client_id) accountToEdit.client_id = answers.client_id;
    if (answers.client_secret) accountToEdit.client_secret = answers.client_secret;
    if (answers.redirect_uri) accountToEdit.redirect_uri = answers.redirect_uri;
    if (!clientAccount) clientAccount = accountToEdit;
    accountToEdit.securityDefinition = secOption.name;
    startOAuthServer(integration, secOption.def, accounts, accountToEdit, clientAccount)
  })
}
let saveAccounts = (integration, accounts) => {
  let oldCreds = getAccounts(integration.name);
  let credFile = datafire.credentialsDirectory + '/' + integration.name + '.json';
  logger.log('Saving credentials to ' + credFile.replace(process.cwd(), '.'));
  fs.writeFileSync(credFile, JSON.stringify(accounts, null, 2));
}

let getOAuthURL = (integration, secDef, clientAccount, scopes) => {
  var flow = secDef.flow;
  var url = secDef.authorizationUrl;
  var state = Math.random();
  url += '?response_type=' + (flow === 'implicit' ? 'token' : 'code');
  url += '&redirect_uri=' + clientAccount.redirect_uri || DEFAULT_REDIRECT_URI;
  url += '&client_id=' + encodeURIComponent(clientAccount.client_id);
  if (flow === 'accessCode') url += '&access_type=offline';
  if (scopes.length > 0) {
    url += '&scope=' + encodeURIComponent(scopes.join(' '));
  }
  url += '&state=' + encodeURIComponent(state);
  return url;
}

let startOAuthServer = (integration, secDef, accounts, accountToEdit, clientAccount) => {
  let server = http.createServer((req, res) => {
    let urlObj = urlParser.parse(req.url);
    if (urlObj.pathname !== '/') {
      res.writeHead(404);
      res.end();
      return;
    }
    let search = urlParser.parse(req.url).search || '?';
    search = search.substring(1);
    search = querystring.parse(search);
    if (search.code) {
      request.post({
        url: secDef.tokenUrl,
        form: {
          code: search.code,
          client_id: clientAccount.client_id,
          client_secret: clientAccount.client_secret,
          redirect_uri: clientAccount.redirect_uri || DEFAULT_REDIRECT_URI,
          grant_type: 'authorization_code',
        },
        json: true,
      }, (err, resp, body) => {
        let newURL = '/?saved=true#access_token=' + encodeURIComponent(body.access_token);
        newURL += '&refresh_token=' + encodeURIComponent(body.refresh_token);
        newURL += '&saved=true';
        res.writeHead(302, {
          'Location': newURL,
        });
        res.end();
        accountToEdit.access_token = body.access_token;
        accountToEdit.refresh_token = body.refresh_token;
        saveAccounts(integration, accounts);
      })
    } else {
      fs.readFile(__dirname + '/../www/oauth_callback.html', 'utf8', (err, data) => {
        if (err) throw err;
        res.end(data);
        if (!search.saved) {
          inquirer.prompt(QUESTION_SETS.oauth_tokens).then(answers => {
            if (answers.access_token) accountToEdit.access_token = answers.access_token;
            if (answers.refresh_token) accountToEdit.refresh_token = answers.refresh_token;
            saveAccounts(integration, accounts);
            server.close();
            process.exit(0);
          })
        } else {
          server.close();
          process.exit(0);
        }
      })
    }
  }).listen(OAUTH_PORT, (err) => {
    if (err) throw err;
    QUESTION_SETS.scopes[0].choices = Object.keys(secDef.scopes).map(s => {
      return {value: s, name: s + ' (' + secDef.scopes[s] + ')'}
    })
    inquirer.prompt(QUESTION_SETS.scopes).then(answers => {
      let url = getOAuthURL(integration, secDef, clientAccount, answers.scopes);
      logger.log("Visit this url to retrieve your access and refresh tokens:")
      logger.logURL(url);
    })
  });
}
<|endoftext|>


<commit_before>/*
 *  ExpressTransport.js
 *
 *  David Janes
 *  IOTDB.org
 *  2015-03-27
 *
 *  Copyright [2013-2015] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict";

var iotdb = require('iotdb');
var iotdb_transport = require('iotdb-transport');
var errors = iotdb_transport.errors;
var _ = iotdb._;

var path = require('path');

var events = require('events');
var util = require('util');
var url = require('url');

var logger = iotdb.logger({
    name: 'iotdb-transport-express',
    module: 'ExpressTransport',
});

/* --- forward definitions --- */
var _encode;
var _decode;
var _unpack;
var _pack;

/* --- constructor --- */

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 *

 *  Create a web interface for Express.
 *
 *  @param {dictionary} initd
 *
 *  @param {object} app
 *  An ExpressJS app
 */
var ExpressTransport = function (initd, app) {
    var self = this;

    self.initd = _.defaults(
        initd, {
            channel: iotdb_transport.channel,
            unchannel: iotdb_transport.unchannel,
            encode: _encode,
            decode: _decode,
            pack: _pack,
            unpack: _unpack,
        },
        iotdb.keystore().get("/transports/ExpressTransport/initd"), {
            prefix: "/",
            key_things: "item",
        }
    );

    self.native = app;

    self._setup_app_thing_band();
    self._setup_app_thing();
    self._setup_app_things();

    this._emitter = new events.EventEmitter();
};

ExpressTransport.prototype = new iotdb_transport.Transport();
ExpressTransport.prototype._class = "ExpressTransport";

/* --- web --- */

ExpressTransport.prototype._setup_app_things = function () {
    var self = this;

    var channel = self.initd.channel(self.initd);

    self.native.use(channel, function (request, response) {
        var ids = [];
        self.list({
            user: request.user,
        }, function (ld) {
            if (ld.end) {
                var rd = {
                    "@id": self.initd.channel(self.initd),
                    "@context": "https://iotdb.org/pub/iot",
                };
                rd[self.initd.key_things] = ids;

                if (ld.error) {
                    rd.error = _.error.message(ld.error);

                    response.status(_.error.code(ld.error));
                }

                return response
                    .set('Content-Type', 'application/json')
                    .set('Access-Control-Allow-Origin', '*')
                    .send(JSON.stringify(rd, null, 2));
            }

            ids.push(self.initd.channel(self.initd, ld.id));
        });
    });
};

ExpressTransport.prototype._setup_app_thing = function () {
    var self = this;

    var channel = self.initd.channel(self.initd, ':id');

    self.native.use(channel, function (request, response) {
        self.bands({
            id: request.params.id,
            user: request.user,
        }, function (ad) {
            var rd = {
                "@id": self.initd.channel(self.initd, request.params.id),
                "@context": "https://iotdb.org/pub/iot",
            };

            if (!ad.bandd) {
                var not_found = new errors.NotFound();
                response.status(_.error.code(not_found));
                rd.error = _.error.message(not_found);
            } else {
                _.mapObject(ad.bandd, function(url, band) {
                    if (url) {
                        rd[band] = url;
                    } else {
                        rd[band] = self.initd.channel(self.initd, request.params.id, band);
                    }
                });
            }

            return response
                .set('Content-Type', 'application/json')
                .set('Access-Control-Allow-Origin', '*')
                .send(JSON.stringify(rd, null, 2));
        });
    });
};

ExpressTransport.prototype._setup_app_thing_band = function () {
    var self = this;

    var channel = self.initd.channel(self.initd, ':id', ':band');

    self.native.get(channel, function (request, response) {
        self.get({
            id: request.params.id,
            band: request.params.band,
            user: request.user,
        }, function (error, gd) {
            var rd = {
                "@id": self.initd.channel(self.initd, request.params.id, request.params.band),
            };

            if ((request.params.band === "istate") || (request.params.band === "ostate")) {
                rd["@context"] = self.initd.channel(self.initd, request.params.id, "model")
            } else if (request.params.band === "meta") {
                rd["@context"] = "https://iotdb.org/pub/iot"
            }

            if (!error && !gd.value) {
                error = new errors.NotFound();
            }

            if (error) {
                response.status(_.error.code(error));
            } else {
                _.defaults(rd, gd.value);
            }

            if (request.params.band === "model") {
                delete rd["@context"]["@base"];
                delete rd["@context"]["@vocab"];
            }

            return response
                .set('Content-Type', 'application/json')
                .set('Access-Control-Allow-Origin', '*')
                .send(JSON.stringify(rd, null, 2));
        });
    });

    self.native.put(channel, function (request, response) {
        self.get({
            id: request.params.id,
            band: request.params.band,
            user: request.user,
        }, function(error, gd) {
            if (error) {
                var rd = {
                    "@id": self.initd.channel(self.initd, gd.id, gd.band),
                };
                rd.error = _.error.message(gd.error);

                response.status(_.error.code(gd.error));

                return response
                    .set('Content-Type', 'application/json')
                    .send(JSON.stringify(rd, null, 2));
            }

            var d = request.body;
            _.timestamp.update(d);

            self._emitter.emit("updated", {
                id: request.params.id,
                band: request.params.band,
                value: d,
                user: request.user,
                response: response,
            });
        });
    });
};

/* --- methods --- */

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 *

 *  Inherently this does nothing. To properly support this
 *  you should use iotdb.transport.bind
 *  to effectively replace this function.
 */
ExpressTransport.prototype.list = function (paramd, callback) {
    var self = this;

    if (arguments.length === 1) {
        paramd = {};
        callback = arguments[0];
    }

    callback({
        end: true,
        error: new errors.NotImplemented(),
    });
};

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 *

 *  Inherently this does nothing. To properly support this
 *  you should use iotdb.transport.bind
 *  to effectively replace this function.
 */
ExpressTransport.prototype.added = function (paramd, callback) {
    var self = this;

    if (arguments.length === 1) {
        paramd = {};
        callback = arguments[0];
    }

    var channel = self.initd.channel(self.initd);
};

/**
 *  See {iotdb_transport.Transport#bands} for documentation.
 *

 *  Inherently this does nothing. To properly support this
 *  you should use iotdb.transport.bind
 *  to effectively replace this function.
 */
ExpressTransport.prototype.bands = function (paramd, callback) {};

/**
 *  See {iotdb_transport.Transport#get} for documentation.
 *

 *  Inherently this does nothing. To properly support this
 *  you should use iotdb.transport.bind
 *  to effectively replace this function.
 */
ExpressTransport.prototype.get = function (paramd, callback) {
    callback(new errors.NeverImplemented(), null);
};

/**
 *  See {iotdb_transport.Transport#update} for documentation.
 *

 *  Inherently this does nothing. To properly support this
 *  you should use iotdb.transport.bind
 *  to effectively replace this function.
 */
ExpressTransport.prototype.put = function (paramd, callback) {
    callback(new errors.NeverImplemented(), null);
};

/**
 *  See {iotdb_transport.Transport#updated} for documentation.
 *

 *  This will be triggered from the Express/Express API
 */
ExpressTransport.prototype.updated = function (paramd, callback) {
    var self = this;

    if (arguments.length === 1) {
        paramd = {};
        callback = arguments[0];
    }

    self._validate_updated(paramd, callback);

    self._emitter.on("updated", function (ud) {
        if (paramd.id && (ud.id !== paramd.id)) {
            return;
        }
        if (paramd.band && (ud.band !== paramd.band)) {
            return;
        }

        var response = ud.response;
        delete ud.response;

        callback(ud);

        var rd = {
            "@id": self.initd.channel(self.initd, ud.id, ud.band),
        };

        return response
            .set('Content-Type', 'application/json')
            .send(JSON.stringify(rd, null, 2));
    });
};

/**
 *  See {iotdb_transport.Transport#remove} for documentation.
 *

 *  Inherently this does nothing. To properly support this
 *  you should use iotdb.transport.bind
 *  to effectively replace this function.
 */
ExpressTransport.prototype.remove = function (paramd) {};

/* -- internals -- */
var _encode = function (s) {
    return s.replace(/[\/$%#.\]\[]/g, function (c) {
        return '%' + c.charCodeAt(0).toString(16);
    });
};

var _decode = function (s) {
    return decodeURIComponent(s);
};

var _unpack = function (d) {
    return _.d.transform(d, {
        pre: _.ld_compact,
        key: _decode,
    });
};

var _pack = function (d) {
    return _.d.transform(d, {
        pre: _.ld_compact,
        key: _encode,
    });
};

/**
 *  API
 */
exports.ExpressTransport = ExpressTransport;
<commit_msg>bands() modernized<commit_after>/*
 *  ExpressTransport.js
 *
 *  David Janes
 *  IOTDB.org
 *  2015-03-27
 *
 *  Copyright [2013-2015] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict";

var iotdb = require('iotdb');
var iotdb_transport = require('iotdb-transport');
var errors = iotdb_transport.errors;
var _ = iotdb._;

var path = require('path');

var events = require('events');
var util = require('util');
var url = require('url');

var logger = iotdb.logger({
    name: 'iotdb-transport-express',
    module: 'ExpressTransport',
});

/* --- forward definitions --- */
var _encode;
var _decode;
var _unpack;
var _pack;

/* --- constructor --- */

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 *

 *  Create a web interface for Express.
 *
 *  @param {dictionary} initd
 *
 *  @param {object} app
 *  An ExpressJS app
 */
var ExpressTransport = function (initd, app) {
    var self = this;

    self.initd = _.defaults(
        initd, {
            channel: iotdb_transport.channel,
            unchannel: iotdb_transport.unchannel,
            encode: _encode,
            decode: _decode,
            pack: _pack,
            unpack: _unpack,
        },
        iotdb.keystore().get("/transports/ExpressTransport/initd"), {
            prefix: "/",
            key_things: "item",
        }
    );

    self.native = app;

    self._setup_app_thing_band();
    self._setup_app_thing();
    self._setup_app_things();

    this._emitter = new events.EventEmitter();
};

ExpressTransport.prototype = new iotdb_transport.Transport();
ExpressTransport.prototype._class = "ExpressTransport";

/* --- web --- */

ExpressTransport.prototype._setup_app_things = function () {
    var self = this;

    var channel = self.initd.channel(self.initd);

    self.native.use(channel, function (request, response) {
        var ids = [];
        self.list({
            user: request.user,
        }, function (ld) {
            if (ld.end) {
                var rd = {
                    "@id": self.initd.channel(self.initd),
                    "@context": "https://iotdb.org/pub/iot",
                };
                rd[self.initd.key_things] = ids;

                if (ld.error) {
                    rd.error = _.error.message(ld.error);

                    response.status(_.error.code(ld.error));
                }

                return response
                    .set('Content-Type', 'application/json')
                    .set('Access-Control-Allow-Origin', '*')
                    .send(JSON.stringify(rd, null, 2));
            }

            ids.push(self.initd.channel(self.initd, ld.id));
        });
    });
};

ExpressTransport.prototype._setup_app_thing = function () {
    var self = this;

    var channel = self.initd.channel(self.initd, ':id');

    self.native.use(channel, function (request, response) {
        self.bands({
            id: request.params.id,
            user: request.user,
        }, function (error, ad) {
            var rd = {
                "@id": self.initd.channel(self.initd, request.params.id),
                "@context": "https://iotdb.org/pub/iot",
            };

            _.mapObject(ad.bandd, function(url, band) {
                if (url) {
                    rd[band] = url;
                } else {
                    rd[band] = self.initd.channel(self.initd, request.params.id, band);
                }
            });

            return response
                .set('Content-Type', 'application/json')
                .set('Access-Control-Allow-Origin', '*')
                .send(JSON.stringify(rd, null, 2));
        });
    });
};

ExpressTransport.prototype._setup_app_thing_band = function () {
    var self = this;

    var channel = self.initd.channel(self.initd, ':id', ':band');

    self.native.get(channel, function (request, response) {
        self.get({
            id: request.params.id,
            band: request.params.band,
            user: request.user,
        }, function (error, gd) {
            var rd = {
                "@id": self.initd.channel(self.initd, request.params.id, request.params.band),
            };

            if ((request.params.band === "istate") || (request.params.band === "ostate")) {
                rd["@context"] = self.initd.channel(self.initd, request.params.id, "model")
            } else if (request.params.band === "meta") {
                rd["@context"] = "https://iotdb.org/pub/iot"
            }

            if (!error && !gd.value) {
                error = new errors.NotFound();
            }

            if (error) {
                response.status(_.error.code(error));
            } else {
                _.defaults(rd, gd.value);
            }

            if (request.params.band === "model") {
                delete rd["@context"]["@base"];
                delete rd["@context"]["@vocab"];
            }

            return response
                .set('Content-Type', 'application/json')
                .set('Access-Control-Allow-Origin', '*')
                .send(JSON.stringify(rd, null, 2));
        });
    });

    self.native.put(channel, function (request, response) {
        self.get({
            id: request.params.id,
            band: request.params.band,
            user: request.user,
        }, function(error, gd) {
            if (error) {
                var rd = {
                    "@id": self.initd.channel(self.initd, gd.id, gd.band),
                };
                rd.error = _.error.message(gd.error);

                response.status(_.error.code(gd.error));

                return response
                    .set('Content-Type', 'application/json')
                    .send(JSON.stringify(rd, null, 2));
            }

            var d = request.body;
            _.timestamp.update(d);

            self._emitter.emit("updated", {
                id: request.params.id,
                band: request.params.band,
                value: d,
                user: request.user,
                response: response,
            });
        });
    });
};

/* --- methods --- */

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 *

 *  Inherently this does nothing. To properly support this
 *  you should use iotdb.transport.bind
 *  to effectively replace this function.
 */
ExpressTransport.prototype.list = function (paramd, callback) {
    var self = this;

    if (arguments.length === 1) {
        paramd = {};
        callback = arguments[0];
    }

    callback({
        end: true,
        error: new errors.NotImplemented(),
    });
};

/**
 *  See {iotdb_transport.Transport#Transport} for documentation.
 *

 *  Inherently this does nothing. To properly support this
 *  you should use iotdb.transport.bind
 *  to effectively replace this function.
 */
ExpressTransport.prototype.added = function (paramd, callback) {
    var self = this;

    var channel = self.initd.channel(self.initd);
};

/**
 *  See {iotdb_transport.Transport#bands} for documentation.
 *

 *  Inherently this does nothing. To properly support this
 *  you should use iotdb.transport.bind
 *  to effectively replace this function.
 */
ExpressTransport.prototype.bands = function (paramd, callback) {
    callback(new errors.NeverImplemented(), null);
};

/**
 *  See {iotdb_transport.Transport#get} for documentation.
 *

 *  Inherently this does nothing. To properly support this
 *  you should use iotdb.transport.bind
 *  to effectively replace this function.
 */
ExpressTransport.prototype.get = function (paramd, callback) {
    callback(new errors.NeverImplemented(), null);
};

/**
 *  See {iotdb_transport.Transport#update} for documentation.
 *

 *  Inherently this does nothing. To properly support this
 *  you should use iotdb.transport.bind
 *  to effectively replace this function.
 */
ExpressTransport.prototype.put = function (paramd, callback) {
    callback(new errors.NeverImplemented(), null);
};

/**
 *  See {iotdb_transport.Transport#updated} for documentation.
 *

 *  This will be triggered from the Express/Express API
 */
ExpressTransport.prototype.updated = function (paramd, callback) {
    var self = this;

    if (arguments.length === 1) {
        paramd = {};
        callback = arguments[0];
    }

    self._validate_updated(paramd, callback);

    self._emitter.on("updated", function (ud) {
        if (paramd.id && (ud.id !== paramd.id)) {
            return;
        }
        if (paramd.band && (ud.band !== paramd.band)) {
            return;
        }

        var response = ud.response;
        delete ud.response;

        callback(ud);

        var rd = {
            "@id": self.initd.channel(self.initd, ud.id, ud.band),
        };

        return response
            .set('Content-Type', 'application/json')
            .send(JSON.stringify(rd, null, 2));
    });
};

/**
 *  See {iotdb_transport.Transport#remove} for documentation.
 *

 *  Inherently this does nothing. To properly support this
 *  you should use iotdb.transport.bind
 *  to effectively replace this function.
 */
ExpressTransport.prototype.remove = function (paramd) {};

/* -- internals -- */
var _encode = function (s) {
    return s.replace(/[\/$%#.\]\[]/g, function (c) {
        return '%' + c.charCodeAt(0).toString(16);
    });
};

var _decode = function (s) {
    return decodeURIComponent(s);
};

var _unpack = function (d) {
    return _.d.transform(d, {
        pre: _.ld_compact,
        key: _decode,
    });
};

var _pack = function (d) {
    return _.d.transform(d, {
        pre: _.ld_compact,
        key: _encode,
    });
};

/**
 *  API
 */
exports.ExpressTransport = ExpressTransport;
<|endoftext|>


<commit_before>import DS from 'ember-data';
import Ember from 'ember';
import NamedBase from './namedbase';

var attr = DS.attr,
    hasMany = DS.hasMany,
    belongsTo = DS.belongsTo;

export default NamedBase.extend({
  lots: hasMany("lot", {async: true}),
  parent: belongsTo("box", {async: true, inverse: "boxes"}),
  boxes: hasMany("box", {async: true, inverse: "parent"}),
  code: belongsTo("code", {async: true}),

  children: function() {
      return this.get('boxes');
  }.property('boxes'),
  hasChildren: function() {
      return this.get('boxes.length') != 0;
  }.property('boxes'),
  hasParent: function() {
      // XXX this is a hack, belongsTo returns a promise..
      return !Ember.isNone(this.get('parent.content'));
  }.property('parent.content'),
  fullName: function() {
      if (Ember.isNone(this.get('parent.content'))) {
          return this.get('name');
      } else {
          return this.get('parent.content.fullName') + ' | ' + this.get('name');
      }
  }.property('parent.content', 'parent.content.fullName', 'name'),

  count: function () {
    var sum = 0;
    this.get('lots').filterBy('next.length', 0).forEach(function (item, index) {
      sum += item.get('count');
    });
    return sum;
  }.property('lots.@each.count', 'lots.@each.next.length')
});
<commit_msg>Use valid flag to filter out lots when doing box count<commit_after>import DS from 'ember-data';
import Ember from 'ember';
import NamedBase from './namedbase';

var attr = DS.attr,
    hasMany = DS.hasMany,
    belongsTo = DS.belongsTo;

export default NamedBase.extend({
  lots: hasMany("lot", {async: true}),
  parent: belongsTo("box", {async: true, inverse: "boxes"}),
  boxes: hasMany("box", {async: true, inverse: "parent"}),
  code: belongsTo("code", {async: true}),

  children: function() {
      return this.get('boxes');
  }.property('boxes'),
  hasChildren: function() {
      return this.get('boxes.length') != 0;
  }.property('boxes'),
  hasParent: function() {
      // XXX this is a hack, belongsTo returns a promise..
      return !Ember.isNone(this.get('parent.content'));
  }.property('parent.content'),
  fullName: function() {
      if (Ember.isNone(this.get('parent.content'))) {
          return this.get('name');
      } else {
          return this.get('parent.content.fullName') + ' | ' + this.get('name');
      }
  }.property('parent.content', 'parent.content.fullName', 'name'),

  count: function () {
    var sum = 0;
    this.get('lots').filterBy('valid', true).forEach(function (item, index) {
      sum += item.get('count');
    });
    return sum;
  }.property('lots.@each.count', 'lots.@each.valid')
});
<|endoftext|>


<commit_before>// @flow
/* eslint-disable jsx-a11y/href-no-hash */

import React from "react";
import Request from "libs/request";
import { Spin, Input, Table, Button, Upload } from "antd";
import type { APIAnnotationType } from "admin/api_flow_types";
import FormatUtils from "libs/format_utils";
import Toast from "libs/toast";
import Utils from "libs/utils";
import update from "immutability-helper";
import app from "app";
import EditableTextLabel from "oxalis/view/components/editable_text_label";

const { Column } = Table;
const { Search } = Input;

type Props = {
  userID: ?string,
  isAdminView: boolean,
};

export default class ExplorativeAnnotationsView extends React.PureComponent {
  props: Props;
  state: {
    shouldShowArchivedTracings: boolean,
    archivedTracings: Array<APIAnnotationType>,
    unarchivedTracings: Array<APIAnnotationType>,
    didAlreadyFetchMetaInfo: {
      isArchived: boolean,
      isUnarchived: boolean,
    },
    searchQuery: string,
    requestCount: number,
    isUploadingNML: boolean,
  } = {
    shouldShowArchivedTracings: false,
    archivedTracings: [],
    unarchivedTracings: [],
    didAlreadyFetchMetaInfo: {
      isArchived: false,
      isUnarchived: false,
    },
    searchQuery: "",
    requestCount: 0,
    isUploadingNML: false,
  };

  componentDidMount() {
    this.fetchDataMaybe();
  }

  isFetchNecessary(): boolean {
    const accessor = this.state.shouldShowArchivedTracings ? "isArchived" : "isUnarchived";
    return !this.state.didAlreadyFetchMetaInfo[accessor];
  }

  enterRequest() {
    this.setState({ requestCount: this.state.requestCount + 1 });
  }

  leaveRequest() {
    this.setState({ requestCount: this.state.requestCount - 1 });
  }

  async fetchDataMaybe(): Promise<void> {
    if (!this.isFetchNecessary()) {
      return;
    }

    const isFinishedString = this.state.shouldShowArchivedTracings.toString();
    const url = this.props.userID
      ? `/api/users/${this.props.userID}/annotations?isFinished=${isFinishedString}`
      : `/api/user/annotations?isFinished=${isFinishedString}`;

    this.enterRequest();
    const tracings = await Request.receiveJSON(url);
    this.leaveRequest();
    if (this.state.shouldShowArchivedTracings) {
      this.setState(
        update(this.state, {
          archivedTracings: { $set: tracings },
          didAlreadyFetchMetaInfo: {
            isArchived: { $set: true },
          },
        }),
      );
    } else {
      this.setState(
        update(this.state, {
          unarchivedTracings: { $set: tracings },
          didAlreadyFetchMetaInfo: {
            isUnarchived: { $set: true },
          },
        }),
      );
    }
  }

  toggleShowArchived = () => {
    this.setState({ shouldShowArchivedTracings: !this.state.shouldShowArchivedTracings });
    this.fetchDataMaybe();
  };

  finishOrReopenTracing = (type: "finish" | "reopen", tracing: APIAnnotationType) => {
    const controller = jsRoutes.controllers.AnnotationController;
    const url =
      type === "finish"
        ? controller.finish(tracing.typ, tracing.id).url
        : controller.reopen(tracing.typ, tracing.id).url;

    Request.receiveJSON(url).then(newTracing => {
      Toast.message(newTracing.messages);

      const newTracings = this.getCurrentTracings().filter(t => t.id !== tracing.id);

      if (type === "finish") {
        this.setState({
          unarchivedTracings: newTracings,
          archivedTracings: [newTracing].concat(this.state.archivedTracings),
        });
      } else {
        this.setState({
          archivedTracings: newTracings,
          unarchivedTracings: [newTracing].concat(this.state.unarchivedTracings),
        });
      }
    });
  };

  handleNMLUpload = (info: {
    file: { response: Object, status: "uploading" | "error" | "done" },
    fileList: Array<Object>,
    event: SyntheticInputEvent,
  }) => {
    const response = info.file.response;
    if (info.file.status === "uploading") {
      this.setState({ isUploadingNML: true });
    }
    if (info.file.status === "error") {
      response.messages.map(m => Toast.error(m.error));
    }
    if (info.file.status === "done") {
      response.messages.map(m => Toast.success(m.success));
      app.router.navigate(`/annotations/${response.annotation.typ}/${response.annotation.id}`, {
        trigger: true,
      });
    }
  };

  renderActions = (tracing: APIAnnotationType) => {
    if (tracing.typ !== "Explorational") {
      return null;
    }

    const controller = jsRoutes.controllers.AnnotationController;
    const { typ, id } = tracing;
    if (!this.state.shouldShowArchivedTracings) {
      return (

            Trace

            Download

           this.finishOrReopenTracing("finish", tracing)}>

            Archive

      );
    } else {
      return (

           this.finishOrReopenTracing("reopen", tracing)}>

            reopen

      );
    }
  };

  getCurrentTracings(): Array<APIAnnotationType> {
    return this.state.shouldShowArchivedTracings
      ? this.state.archivedTracings
      : this.state.unarchivedTracings;
  }

  handleSearch = (event: SyntheticInputEvent): void => {
    this.setState({ searchQuery: event.target.value });
  };

  renameTracing(tracing: APIAnnotationType, name: string) {
    const tracings = this.getCurrentTracings();

    const newTracings = tracings.map(currentTracing => {
      if (currentTracing.id !== tracing.id) {
        return currentTracing;
      } else {
        return update(currentTracing, { name: { $set: name } });
      }
    });

    this.setState({
      [this.state.shouldShowArchivedTracings
        ? "archivedTracings"
        : "unarchivedTracings"]: newTracings,
    });

    const url = `/annotations/${tracing.typ}/${tracing.id}/name`;
    const payload = { data: { name } };

    Request.sendJSONReceiveJSON(url, payload).then(response => {
      Toast.message(response.messages);
    });
  }

  archiveAll = () => {
    if (!confirm("Are you sure you want to archive all explorative annotations?")) {
      return;
    }

    const unarchivedAnnoationIds = this.state.unarchivedTracings.map(t => t.id);
    Request.sendJSONReceiveJSON(
      jsRoutes.controllers.AnnotationController.finishAll("Explorational").url,
      {
        method: "POST",
        data: {
          annotations: unarchivedAnnoationIds,
        },
      },
    ).then(data => {
      Toast.message(data.messages);

      this.setState({
        archivedTracings: this.state.unarchivedTracings.concat(this.state.archivedTracings),
        unarchivedTracings: [],
      });
    });
  };

  renderTable() {
    return (

        <Column
          title="#"
          dataIndex="id"
          render={(__, tracing) => FormatUtils.formatHash(tracing.id)}
          sorter
          className="monospace-id"
        />
        <Column
          title="Name"
          dataIndex="name"
          sorter
          render={(name, tracing) =>
            <EditableTextLabel
              value={name}
              onChange={newName => this.renameTracing(tracing, newName)}
            />}
        />
        <Column title="Dataset" dataIndex="dataSetName" sorter />
        <Column
          title="Stats"
          render={(__, tracing) =>
            tracing.stats && tracing.contentType === "skeletonTracing"
              ?

                    {tracing.stats.numberOfTrees}

                    {tracing.stats.numberOfNodes}

                    {tracing.stats.numberOfEdges}

              : null}
        />
        <Column title="Type" dataIndex="contentType" />
        <Column title="Creation Date" dataIndex="created" sorter />
        <Column
          title="Actions"
          className="nowrap"
          key="action"
          render={(__, tracing) => this.renderActions(tracing)}
        />

    );
  }

  render() {
    return (

        <Search
          style={{ width: 200, float: "right" }}
          onPressEnter={this.handleSearch}
          onChange={this.handleSearch}
        />

Explorative Annotations

        {this.props.isAdminView
          ? null
          :

              <Upload
                action="/admin/nml/upload"
                accept=".nml, .zip"
                name="nmlFile"
                multiple
                showUploadList={false}
                onChange={this.handleNMLUpload}
              >
                <Button icon="upload" loading={this.state.isUploadingNML}>
                  Upload Annotation
                </Button>
              </Upload>

              <Button onClick={this.toggleShowArchived}>
                Show {this.state.shouldShowArchivedTracings ? "Open" : "Archived"} Tracings
              </Button>

                {!this.state.shouldShowArchivedTracings
                  ? <Button onClick={this.archiveAll}>Archive All</Button>
                  : null}

}

        {this.state.requestCount === 0
          ? this.renderTable()
          :

              <Spin size="large" />

}

    );
  }
}
<commit_msg>fix sorting in explorative tracings tab (#1938)<commit_after>// @flow
/* eslint-disable jsx-a11y/href-no-hash */

import React from "react";
import Request from "libs/request";
import { Spin, Input, Table, Button, Upload } from "antd";
import type { APIAnnotationType } from "admin/api_flow_types";
import FormatUtils from "libs/format_utils";
import Toast from "libs/toast";
import Utils from "libs/utils";
import update from "immutability-helper";
import app from "app";
import EditableTextLabel from "oxalis/view/components/editable_text_label";

const { Column } = Table;
const { Search } = Input;

type Props = {
  userID: ?string,
  isAdminView: boolean,
};

export default class ExplorativeAnnotationsView extends React.PureComponent {
  props: Props;
  state: {
    shouldShowArchivedTracings: boolean,
    archivedTracings: Array<APIAnnotationType>,
    unarchivedTracings: Array<APIAnnotationType>,
    didAlreadyFetchMetaInfo: {
      isArchived: boolean,
      isUnarchived: boolean,
    },
    searchQuery: string,
    requestCount: number,
    isUploadingNML: boolean,
  } = {
    shouldShowArchivedTracings: false,
    archivedTracings: [],
    unarchivedTracings: [],
    didAlreadyFetchMetaInfo: {
      isArchived: false,
      isUnarchived: false,
    },
    searchQuery: "",
    requestCount: 0,
    isUploadingNML: false,
  };

  componentDidMount() {
    this.fetchDataMaybe();
  }

  isFetchNecessary(): boolean {
    const accessor = this.state.shouldShowArchivedTracings ? "isArchived" : "isUnarchived";
    return !this.state.didAlreadyFetchMetaInfo[accessor];
  }

  enterRequest() {
    this.setState({ requestCount: this.state.requestCount + 1 });
  }

  leaveRequest() {
    this.setState({ requestCount: this.state.requestCount - 1 });
  }

  async fetchDataMaybe(): Promise<void> {
    if (!this.isFetchNecessary()) {
      return;
    }

    const isFinishedString = this.state.shouldShowArchivedTracings.toString();
    const url = this.props.userID
      ? `/api/users/${this.props.userID}/annotations?isFinished=${isFinishedString}`
      : `/api/user/annotations?isFinished=${isFinishedString}`;

    this.enterRequest();
    const tracings = await Request.receiveJSON(url);
    this.leaveRequest();
    if (this.state.shouldShowArchivedTracings) {
      this.setState(
        update(this.state, {
          archivedTracings: { $set: tracings },
          didAlreadyFetchMetaInfo: {
            isArchived: { $set: true },
          },
        }),
      );
    } else {
      this.setState(
        update(this.state, {
          unarchivedTracings: { $set: tracings },
          didAlreadyFetchMetaInfo: {
            isUnarchived: { $set: true },
          },
        }),
      );
    }
  }

  toggleShowArchived = () => {
    this.setState({ shouldShowArchivedTracings: !this.state.shouldShowArchivedTracings });
    this.fetchDataMaybe();
  };

  finishOrReopenTracing = (type: "finish" | "reopen", tracing: APIAnnotationType) => {
    const controller = jsRoutes.controllers.AnnotationController;
    const url =
      type === "finish"
        ? controller.finish(tracing.typ, tracing.id).url
        : controller.reopen(tracing.typ, tracing.id).url;

    Request.receiveJSON(url).then(newTracing => {
      Toast.message(newTracing.messages);

      const newTracings = this.getCurrentTracings().filter(t => t.id !== tracing.id);

      if (type === "finish") {
        this.setState({
          unarchivedTracings: newTracings,
          archivedTracings: [newTracing].concat(this.state.archivedTracings),
        });
      } else {
        this.setState({
          archivedTracings: newTracings,
          unarchivedTracings: [newTracing].concat(this.state.unarchivedTracings),
        });
      }
    });
  };

  handleNMLUpload = (info: {
    file: { response: Object, status: "uploading" | "error" | "done" },
    fileList: Array<Object>,
    event: SyntheticInputEvent,
  }) => {
    const response = info.file.response;
    if (info.file.status === "uploading") {
      this.setState({ isUploadingNML: true });
    }
    if (info.file.status === "error") {
      response.messages.map(m => Toast.error(m.error));
    }
    if (info.file.status === "done") {
      response.messages.map(m => Toast.success(m.success));
      app.router.navigate(`/annotations/${response.annotation.typ}/${response.annotation.id}`, {
        trigger: true,
      });
    }
  };

  renderActions = (tracing: APIAnnotationType) => {
    if (tracing.typ !== "Explorational") {
      return null;
    }

    const controller = jsRoutes.controllers.AnnotationController;
    const { typ, id } = tracing;
    if (!this.state.shouldShowArchivedTracings) {
      return (

            Trace

            Download

           this.finishOrReopenTracing("finish", tracing)}>

            Archive

      );
    } else {
      return (

           this.finishOrReopenTracing("reopen", tracing)}>

            reopen

      );
    }
  };

  getCurrentTracings(): Array<APIAnnotationType> {
    return this.state.shouldShowArchivedTracings
      ? this.state.archivedTracings
      : this.state.unarchivedTracings;
  }

  handleSearch = (event: SyntheticInputEvent): void => {
    this.setState({ searchQuery: event.target.value });
  };

  renameTracing(tracing: APIAnnotationType, name: string) {
    const tracings = this.getCurrentTracings();

    const newTracings = tracings.map(currentTracing => {
      if (currentTracing.id !== tracing.id) {
        return currentTracing;
      } else {
        return update(currentTracing, { name: { $set: name } });
      }
    });

    this.setState({
      [this.state.shouldShowArchivedTracings
        ? "archivedTracings"
        : "unarchivedTracings"]: newTracings,
    });

    const url = `/annotations/${tracing.typ}/${tracing.id}/name`;
    const payload = { data: { name } };

    Request.sendJSONReceiveJSON(url, payload).then(response => {
      Toast.message(response.messages);
    });
  }

  archiveAll = () => {
    if (!confirm("Are you sure you want to archive all explorative annotations?")) {
      return;
    }

    const unarchivedAnnoationIds = this.state.unarchivedTracings.map(t => t.id);
    Request.sendJSONReceiveJSON(
      jsRoutes.controllers.AnnotationController.finishAll("Explorational").url,
      {
        method: "POST",
        data: {
          annotations: unarchivedAnnoationIds,
        },
      },
    ).then(data => {
      Toast.message(data.messages);

      this.setState({
        archivedTracings: this.state.unarchivedTracings.concat(this.state.archivedTracings),
        unarchivedTracings: [],
      });
    });
  };

  renderTable() {
    return (

        <Column
          title="#"
          dataIndex="id"
          render={(__, tracing) => FormatUtils.formatHash(tracing.id)}
          sorter={Utils.localeCompareBy("id")}
          className="monospace-id"
        />
        <Column
          title="Name"
          dataIndex="name"
          sorter={Utils.localeCompareBy("name")}
          render={(name, tracing) =>
            <EditableTextLabel
              value={name}
              onChange={newName => this.renameTracing(tracing, newName)}
            />}
        />
        <Column
          title="Dataset"
          dataIndex="dataSetName"
          sorter={Utils.localeCompareBy("dataSetName")}
        />
        <Column
          title="Stats"
          render={(__, tracing) =>
            tracing.stats && tracing.contentType === "skeletonTracing"
              ?

                    {tracing.stats.numberOfTrees}

                    {tracing.stats.numberOfNodes}

                    {tracing.stats.numberOfEdges}

              : null}
        />
        <Column title="Type" dataIndex="contentType" />
        <Column
          title="Creation Date"
          dataIndex="created"
          sorter={Utils.localeCompareBy("created")}
        />
        <Column
          title="Actions"
          className="nowrap"
          key="action"
          render={(__, tracing) => this.renderActions(tracing)}
        />

    );
  }

  render() {
    return (

        <Search
          style={{ width: 200, float: "right" }}
          onPressEnter={this.handleSearch}
          onChange={this.handleSearch}
        />

Explorative Annotations

        {this.props.isAdminView
          ? null
          :

              <Upload
                action="/admin/nml/upload"
                accept=".nml, .zip"
                name="nmlFile"
                multiple
                showUploadList={false}
                onChange={this.handleNMLUpload}
              >
                <Button icon="upload" loading={this.state.isUploadingNML}>
                  Upload Annotation
                </Button>
              </Upload>

              <Button onClick={this.toggleShowArchived}>
                Show {this.state.shouldShowArchivedTracings ? "Open" : "Archived"} Tracings
              </Button>

                {!this.state.shouldShowArchivedTracings
                  ? <Button onClick={this.archiveAll}>Archive All</Button>
                  : null}

}

        {this.state.requestCount === 0
          ? this.renderTable()
          :

              <Spin size="large" />

}

    );
  }
}
<|endoftext|>


<commit_before>/***

  RESTly API Framework, based on Express

***/

var _       = require('underscore'),
    fs      = require('fs'),
    routes  = require('./lib/routes.js'),
    caching  = require('./lib/caching.js');

// global for exporting
var restly = {};

// set up express
var express = require('express');
var app = express();

// force express to parse posted and putted parameters
app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/tmp' }));

// define public directory for docs
app.use(express.static(__dirname+'/public'));

// wrapper for passing middleware to express
restly.use = function() {
  app.use.apply(app, arguments);
}

// init
restly.init = function(r, opts) {

  function addHeaders(apicall, res) {
    if(apicall.cross_origin) {
      res.header("Access-Control-Allow-Origin", "*");
      res.header("Access-Control-Allow-Headers", "X-Requested-With");
    }
  }

  // make sure all our defaults are set
  var opts = defaultOpts(opts);

  // get our routes
  var routesCollection = routes.getRoutes(r);

  // for each route
  for(var rc in routesCollection) {

    var apicall = routesCollection[rc];

    // add authentication object to apicall
    if (apicall.authentication) {

      // get authentication methods
      apicall.authentication = routes.getAuthentication(r, apicall.authentication);

      // combine api call params with authentication params
      apicall = routes.combineWithAuthentication(apicall);

      routesCollection[rc] = apicall;
    }

    // get the full and correct path for the library
    apicall.library = process.cwd()+"/"+opts.lib+apicall.library;

    // and for the authentication library, if required
    if (apicall.authentication && apicall.authentication.library) {
      apicall.authentication.library = process.cwd()+"/"+opts.lib+apicall.authentication.library;
    }

    // are we enabling caching?
    if (!opts.caching || !apicall.caching) {
      apicall.caching = false;
    }

    else {
      apicall.caching = caching.parseOptsCache(opts.caching);

      // add special _use_cache param to API call
      apicall.parameters._use_cache = {
        "required": false,
        "type": "bool",
        "description":"Do you want to read from the cache",
        "default": true
      }
    }

    //Set up addition headers here
    if(apicall.cross_origin) {
      app.all('/', function(req, res, next) {
        res.header("Access-Control-Allow-Origin", "*");
        res.header("Access-Control-Allow-Headers", "X-Requested-With");
        next();
      });
    }

    // set up a express listener for each call
    switch(apicall.method) {
      case 'put':

        (function(ac) {
          app.put(ac.endpoint, function (req,res) {
            addHeaders(ac, res);
            routes.parseRequest(ac, req, res);
          });
        })(apicall);
        break;

      case 'post':

        (function(ac) {
          app.post(ac.endpoint, function (req,res) {
            addHeaders(ac, res);
            routes.parseRequest(ac, req, res);
          });
        })(apicall);
        break;

      case 'delete':

        (function(ac) {
          app.delete(ac.endpoint, function (req,res) {
            addHeaders(ac, res);
            routes.parseRequest(ac, req, res);
          });
        })(apicall);
        break;

      case 'get':

        (function(ac) {
          app.get(ac.endpoint, function (req,res) {
            addHeaders(ac, res);
            routes.parseRequest(ac, req, res);
          });
        })(apicall);
        break;
    }

  }

  // documentation page
  app.get(opts.docs_endpoint, function(req, res) {

    var sections = [];
    for (var r in routesCollection) {
      sections.push(routesCollection[r].section);
    }

    sections = _.uniq(sections)

    // prepare the page data
    var page = {
                  routes: routesCollection,
                  config: opts,
                  section: false,
                  sections: sections,
                  docs_endpoint: opts.docs_endpoint
                };

    // render the channel list page
    res.render(process.cwd()+"/node_modules/restly/views/index.jade", page);

  });

  // documentation page by section
  app.get(opts.docs_endpoint+"section/:section", function(req, res) {

    var sections = [];
    for (var r in routesCollection) {
      sections.push(routesCollection[r].section);
    }

    sections = _.uniq(sections)

    // prepare the page data
    var page = {
                  routes: routesCollection,
                  config: opts,
                  section: req.params.section,
                  sections: sections,
                  docs_endpoint: opts.docs_endpoint
                };

    // render the channel list page
    res.render(process.cwd()+"/node_modules/restly/views/index.jade", page);

  });

  // listen on the specified port
  if (opts.protocol == 'https') {
    // set up for secure server
    var fs = require('fs');
    var https = require('https');

    try {
        var privateKey  = fs.readFileSync(opts.ssl_private_key, 'utf8');
        var certificate = fs.readFileSync(opts.ssl_certificate, 'utf8');
    } catch (e) {
        if (e.code === 'ENOENT') {
            console.log('\n    Cannot find SSL private key or certificate file.');
            console.log('   Make sure "'+opts.ssl_private_key+'" and "'+opts.ssl_certificate+'" exist.')

            throw e;
        }
    }

    var credentials = { key: privateKey, cert: certificate };

    var server = https.createServer(credentials, app);

    server.listen(opts.port);
  } else {
      var server = app.listen(opts.port);
  }

  // this function is called when you want the server to die gracefully
  // i.e. wait for existing connections
  var gracefulShutdown = function() {
    console.log("Received kill signal, shutting down gracefully.");
    server.close(function() {
      console.log("Closed out remaining connections.");
      process.exit()
    });

    // if after
    setTimeout(function() {
        console.error("Could not close connections in time, forcefully shutting down");
        process.exit()
   }, 3*1000);

  }

  // listen for TERM signal .e.g. kill <pid>
  process.on ('SIGTERM', gracefulShutdown);

  // listen for INT signal e.g. Ctrl-C
  process.on ('SIGINT', gracefulShutdown);

}

// default options
var defaultOpts = function(opts) {

  // define defaults
  var defaults = {
    lib: "",
    protocol: "http",
    domain: "localhost",
    port: 8000,
    ssl_private_key: "sslcert/server.key",
    ssl_certificate: "sslcert/server.crt",
    name: "My API",
    description: "Interactive API docs",
    docs_endpoint: "/",
    caching: false
  }

  // change defaults with supplied opts
  if (!_.isUndefined(opts) && _.isObject(opts)) {

    for (var o in opts) {

      if (!_.isUndefined(defaults[o])) {
        defaults[o] = opts[o];
      }

    }

  }

  // check for sane protocol values
  if (!_.isString(defaults.protocol)) { defaults.protocol = "http"; }
  defaults.protocol = defaults.protocol.toLowerCase();
  if (defaults.protocol != 'http' && defaults.protocol != 'https') { defaults.protocol = 'http'; }

  // sane port values
  if (!_.isNumber(defaults.port)) {
    // sane secure server values
    if (defaults.protocol == 'https') {
      defaults.port = 8443;
    } else {
      defaults.port = 8000;
    }
  }

  // sane docs endpoints value
  if (defaults.docs_endpoint != "/") {
    if (defaults.docs_endpoint == "") {
      defaults.docs_endpoint = "/";
    } else {
      defaults.docs_endpoint = defaults.docs_endpoint.replace(/^\/?(.*?)\/?$/, '/$1/');
    }
  }

  // return
  return defaults;

}

// export
module.exports = restly
<commit_msg>Testing exposing express object via restly export<commit_after>/***

  RESTly API Framework, based on Express

***/

var _       = require('underscore'),
    fs      = require('fs'),
    routes  = require('./lib/routes.js'),
    caching  = require('./lib/caching.js');

// global for exporting
var restly = {};

// set up express
var express = require('express');
var app = express();

restly.express = app;

// force express to parse posted and putted parameters
app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/tmp' }));

// define public directory for docs
app.use(express.static(__dirname+'/public'));

// wrapper for passing middleware to express
restly.use = function() {
  app.use.apply(app, arguments);
}

// init
restly.init = function(r, opts) {

  function addHeaders(apicall, res) {
    if(apicall.cross_origin) {
      res.header("Access-Control-Allow-Origin", "*");
      res.header("Access-Control-Allow-Headers", "X-Requested-With");
    }
  }

  // make sure all our defaults are set
  var opts = defaultOpts(opts);

  // get our routes
  var routesCollection = routes.getRoutes(r);

  // for each route
  for(var rc in routesCollection) {

    var apicall = routesCollection[rc];

    // add authentication object to apicall
    if (apicall.authentication) {

      // get authentication methods
      apicall.authentication = routes.getAuthentication(r, apicall.authentication);

      // combine api call params with authentication params
      apicall = routes.combineWithAuthentication(apicall);

      routesCollection[rc] = apicall;
    }

    // get the full and correct path for the library
    apicall.library = process.cwd()+"/"+opts.lib+apicall.library;

    // and for the authentication library, if required
    if (apicall.authentication && apicall.authentication.library) {
      apicall.authentication.library = process.cwd()+"/"+opts.lib+apicall.authentication.library;
    }

    // are we enabling caching?
    if (!opts.caching || !apicall.caching) {
      apicall.caching = false;
    }

    else {
      apicall.caching = caching.parseOptsCache(opts.caching);

      // add special _use_cache param to API call
      apicall.parameters._use_cache = {
        "required": false,
        "type": "bool",
        "description":"Do you want to read from the cache",
        "default": true
      }
    }

    //Set up addition headers here
    if(apicall.cross_origin) {
      app.all('/', function(req, res, next) {
        res.header("Access-Control-Allow-Origin", "*");
        res.header("Access-Control-Allow-Headers", "X-Requested-With");
        next();
      });
    }

    // set up a express listener for each call
    switch(apicall.method) {
      case 'put':

        (function(ac) {
          app.put(ac.endpoint, function (req,res) {
            addHeaders(ac, res);
            routes.parseRequest(ac, req, res);
          });
        })(apicall);
        break;

      case 'post':

        (function(ac) {
          app.post(ac.endpoint, function (req,res) {
            addHeaders(ac, res);
            routes.parseRequest(ac, req, res);
          });
        })(apicall);
        break;

      case 'delete':

        (function(ac) {
          app.delete(ac.endpoint, function (req,res) {
            addHeaders(ac, res);
            routes.parseRequest(ac, req, res);
          });
        })(apicall);
        break;

      case 'get':

        (function(ac) {
          app.get(ac.endpoint, function (req,res) {
            addHeaders(ac, res);
            routes.parseRequest(ac, req, res);
          });
        })(apicall);
        break;
    }

  }

  // documentation page
  app.get(opts.docs_endpoint, function(req, res) {

    var sections = [];
    for (var r in routesCollection) {
      sections.push(routesCollection[r].section);
    }

    sections = _.uniq(sections)

    // prepare the page data
    var page = {
                  routes: routesCollection,
                  config: opts,
                  section: false,
                  sections: sections,
                  docs_endpoint: opts.docs_endpoint
                };

    // render the channel list page
    res.render(process.cwd()+"/node_modules/restly/views/index.jade", page);

  });

  // documentation page by section
  app.get(opts.docs_endpoint+"section/:section", function(req, res) {

    var sections = [];
    for (var r in routesCollection) {
      sections.push(routesCollection[r].section);
    }

    sections = _.uniq(sections)

    // prepare the page data
    var page = {
                  routes: routesCollection,
                  config: opts,
                  section: req.params.section,
                  sections: sections,
                  docs_endpoint: opts.docs_endpoint
                };

    // render the channel list page
    res.render(process.cwd()+"/node_modules/restly/views/index.jade", page);

  });

  // listen on the specified port
  if (opts.protocol == 'https') {
    // set up for secure server
    var fs = require('fs');
    var https = require('https');

    try {
        var privateKey  = fs.readFileSync(opts.ssl_private_key, 'utf8');
        var certificate = fs.readFileSync(opts.ssl_certificate, 'utf8');
    } catch (e) {
        if (e.code === 'ENOENT') {
            console.log('\n    Cannot find SSL private key or certificate file.');
            console.log('   Make sure "'+opts.ssl_private_key+'" and "'+opts.ssl_certificate+'" exist.')

            throw e;
        }
    }

    var credentials = { key: privateKey, cert: certificate };

    var server = https.createServer(credentials, app);

    server.listen(opts.port);
  } else {
      var server = app.listen(opts.port);
  }

  // this function is called when you want the server to die gracefully
  // i.e. wait for existing connections
  var gracefulShutdown = function() {
    console.log("Received kill signal, shutting down gracefully.");
    server.close(function() {
      console.log("Closed out remaining connections.");
      process.exit()
    });

    // if after
    setTimeout(function() {
        console.error("Could not close connections in time, forcefully shutting down");
        process.exit()
   }, 3*1000);

  }

  // listen for TERM signal .e.g. kill <pid>
  process.on ('SIGTERM', gracefulShutdown);

  // listen for INT signal e.g. Ctrl-C
  process.on ('SIGINT', gracefulShutdown);

}

// default options
var defaultOpts = function(opts) {

  // define defaults
  var defaults = {
    lib: "",
    protocol: "http",
    domain: "localhost",
    port: 8000,
    ssl_private_key: "sslcert/server.key",
    ssl_certificate: "sslcert/server.crt",
    name: "My API",
    description: "Interactive API docs",
    docs_endpoint: "/",
    caching: false
  }

  // change defaults with supplied opts
  if (!_.isUndefined(opts) && _.isObject(opts)) {

    for (var o in opts) {

      if (!_.isUndefined(defaults[o])) {
        defaults[o] = opts[o];
      }

    }

  }

  // check for sane protocol values
  if (!_.isString(defaults.protocol)) { defaults.protocol = "http"; }
  defaults.protocol = defaults.protocol.toLowerCase();
  if (defaults.protocol != 'http' && defaults.protocol != 'https') { defaults.protocol = 'http'; }

  // sane port values
  if (!_.isNumber(defaults.port)) {
    // sane secure server values
    if (defaults.protocol == 'https') {
      defaults.port = 8443;
    } else {
      defaults.port = 8000;
    }
  }

  // sane docs endpoints value
  if (defaults.docs_endpoint != "/") {
    if (defaults.docs_endpoint == "") {
      defaults.docs_endpoint = "/";
    } else {
      defaults.docs_endpoint = defaults.docs_endpoint.replace(/^\/?(.*?)\/?$/, '/$1/');
    }
  }

  // return
  return defaults;

}

// export
module.exports = restly
<|endoftext|>


<commit_before>core.Class("core.mvc.DomView",
{
  include : [core.mvc.View],

  construct: function(properties, events)
  {
    core.mvc.View.call(this, properties);

    for (var key in events) {

    }
  },

  properties :
  {
    /** The root element to render into */
    root :
    {
      check: "Element",
      nullable : true,
      apply : function(value, old) {

      }
    }

  },

  members :
  {
    render : function()
    {
      var data = this.getModel();

      var elem = this.getRoot();
      if (!elem)
      {
        var id = this.getId();
        elem = document.getElementById(id);
        this.setRoot(elem);
      }

      elem.innerHTML = this.getTemplate().render(data ? data.toJSON() : {});

      return this;
    }
  }

});
<commit_msg>Minor tweaks<commit_after>core.Class("core.mvc.DomView",
{
  include : [core.mvc.View],

  construct: function(properties, events)
  {
    core.mvc.View.call(this, properties);

    for (var key in events) {

    }
  },

  properties :
  {
    /** The root element to render into */
    root :
    {
      check: "Element",
      nullable : true,
      apply : function(value, old) {
        this.render();
      }
    }

  },

  members :
  {
    // Definition of abstract method
    render : function()
    {
      var elem = this.getRoot();
      if (!elem)
      {
        var id = this.getId();
        if (jasy.Env.isSet("debug"))
        {
          if (!id) {
            throw new Error("Please define either an element or an ID for having a valid render target.");
          }
        }

        this.setRoot(document.getElementById(id));

        // Setting the root leads to another render() call
        return;
      }

      var data = this.getModel();
      elem.innerHTML = this.getTemplate().render(data ? data.toJSON() : {});

      return this;
    }
  }

});
<|endoftext|>