<commit_before>import React, { PropTypes } from 'react';

const Link = ({ active, children, onClick }) => {
  if (active) {
    return {children};
  }

  return (
     {
        e.preventDefault();
        onClick();
      }}
    >
      {children}

  );
};

Link.propTypes = {
  active: PropTypes.bool.isRequired,
  children: PropTypes.node.isRequired,
  onClick: PropTypes.func.isRequired,
};

export default Link;
<commit_msg>Add special class to every Link element<commit_after>import React, { PropTypes } from 'react';

const Link = ({ active, children, onClick }) => {
  if (active) {
    return (

        {children}

    );
  }

  return (
     {
        e.preventDefault();
        onClick();
      }}
    >
      {children}

  );
};

Link.propTypes = {
  active: PropTypes.bool.isRequired,
  children: PropTypes.node.isRequired,
  onClick: PropTypes.func.isRequired,
};

export default Link;
<|endoftext|>


<commit_before>const path = require('path');
const fs = require('fs');
const _ = require('lodash');
const format = require('string-format');
const constants = require('./constants');

function generateBoilerplate(routerPath) {
    console.log("generating app routing...");
    if (!fs.existsSync(routerPath + 'app')) {
        fs.mkdirSync(routerPath + 'app');
        console.log(routerPath + 'app', "created.");

    }
    if (!fs.existsSync(routerPath + 'app/controllers')) {
        fs.mkdirSync(routerPath + 'app/controllers');
        console.log(routerPath + 'app/controllers', "created.");

    }
    if (!fs.existsSync(routerPath + 'app/middleware')) {
        fs.mkdirSync(routerPath + 'app/middleware');
        console.log(routerPath + 'app/middleware', "created.");

    }
    if (!fs.existsSync(routerPath + 'app/routes')) {
        fs.mkdirSync(routerPath + 'app/routes');
        console.log(routerPath + 'app/routes', "created.");

    }
    const routerFilePath = routerPath + 'app/Router.js';

    console.log("Processing Router.js ", routerFilePath);
    if (!fs.existsSync(routerFilePath)) {
        console.log("No Route.js was found!");

        fs.openSync(routerFilePath, 'a');
        console.log("Router.js created!");

        fs.writeFileSync(routerFilePath, constants.ROUTER_JS_STARTER);

        console.log("Router.js boilerplate ready!");
        return require(routerFilePath);
    } else {
        return require(routerFilePath);
    }
}

const initEndpointStructure = function ({test}) {
    let routerPath = path.normalize(`${__dirname}/../../../`);

    if (test) {
        routerPath = `${__dirname}/../`;
        console.log('testing mode, routing folder', routerPath);
    }
    generateBoilerplate(routerPath);
};

function constructPath({pathParsed, endpointData, Router}) {
    console.log(Router);
    if (Router.length === 0) {
        if (pathParsed.length === 1) {
            Router.push({path: `/${pathParsed[0]}`, handler: endpointData.routerPath});
            return Router;
        } else {
            let constructed_subpaths = constructPath({pathParsed: pathParsed.splice(1), endpointData, Router: []});
            if(!constructed_subpaths) return null;
            Router.push({
                path: `/${pathParsed[0]}`,
                subpaths: constructed_subpaths
            });
        }
    }

    Router.forEach((endpoint, idx, array) => {
        console.log(`running in router... idx = ${idx},  array.length =${array.length}`);
        if (idx === array.length - 1 && endpoint.path !== ('/' + pathParsed[0])) {
            console.log("last element and pathParse is not equal pathParsed[0]... pushing ");
            if (pathParsed.length === 1) {
                console.log("last element in pathParsed...pusing directry");
                Router.push({path: `/${pathParsed[0]}`, handler: endpointData.routerPath});
                return Router;
            } else {
                console.log("still not at end of pathParsed");
                const subpaths_constructed = constructPath({pathParsed: pathParsed.splice(1), endpointData, Router: []})
                if(!subpaths_constructed) return null;
                Router.push({
                    path: `/${pathParsed[0]}`,
                    subpaths: subpaths_constructed
                });
            }
        }

        if (pathParsed.length === 1 && endpoint.path === ('/' + pathParsed[0])) {
            console.error("endpoint already exists!");
            return null;
        }
        if (pathParsed.length > 1 && endpoint.path === ('/' + pathParsed[0])) {
                console.log("part of endpoint matched moving on...");
                if (_.has(endpoint, "subpaths")) {
                    endpoint.subpaths = constructPath({
                        pathParsed: pathParsed.splice(1),
                        endpointData,
                        Router: endpoint.subpaths
                    });
                    return Router;
                } else {
                    return null;
                    console.log("handler for this endpoint already exists!");
                }
            }

    });

    return Router;
}

const addEndpoint = function ({endpointPath, router, controller}, test) {
    let appPath = path.normalize(`${__dirname}/../../../app/`);
    if (test) {
        appPath = path.normalize(`${__dirname}/../app/`);
        console.log('testing mode, routing folder', appPath);
    }
    const ROUTER_FILE = 'Router.js';
    const CONTROLLERS_FOLDER = 'controllers/';
    const ROUTES_FOLDER = 'routes/';

    const controllerFilePath = appPath + CONTROLLERS_FOLDER + controller;
    const routerFilePath = appPath + ROUTES_FOLDER + router;
    const routerJsFilePath = appPath + ROUTER_FILE;

    let endpointData = {
        endpointPath,
        controllerPath: 'app/' + CONTROLLERS_FOLDER + controller,
        routerPath: 'app/' + ROUTES_FOLDER + router
    };

    let Router;
    try {
        Router = require(routerJsFilePath);
    } catch (err) {
        console.error("could not find Router.js... did you call endpoint --init ?");
        return;
    }
    console.log("Router.js: ", Router);

    const pathParsed = endpointPath.split('/').splice(1);
    console.log(pathParsed);

    console.log("constructing Path");
    let res = constructPath({pathParsed, endpointData, Router});
    console.log("Construct res", JSON.stringify(res));
    var dumpData = "module.exports = \n" + JSON.stringify(res, null, 2);

    fs.openSync(routerJsFilePath, 'a');
    fs.writeFileSync(routerJsFilePath, dumpData);
    console.log(routerJsFilePath + " updated!");
    return;

    // router file
    if (!fs.existsSync(routerFilePath)) {
        fs.openSync(routerFilePath, 'a');
        fs.writeFileSync(routerFilePath, format(constants.ROUTER_FILE_BOILERPLATE, endpointData));
        console.log(routerFilePath + " created!");
    }

    // controller file
    if (!fs.existsSync(controllerFilePath)) {
        fs.openSync(controllerFilePath, 'a');
        fs.writeFileSync(controllerFilePath, constants.CONTROLLER_FILE_BOILERPLATE);
        console.log(controllerFilePath + " created!");
    }

    // main Router.js
    Router.push({path: endpointPath, handler: endpointData.routerPath});
    const routerJsData = "module.exports = \n" + JSON.stringify(Router, null, 2);

    fs.openSync(routerJsFilePath, 'a');
    fs.writeFileSync(routerJsFilePath, routerJsData);
    console.log(routerJsFilePath + " updated!");
};

module.exports = {
    initEndpoint: initEndpointStructure,
    addEndpoint: addEndpoint
};<commit_msg>algorithm bugfixes<commit_after>const path = require('path');
const fs = require('fs');
const _ = require('lodash');
const format = require('string-format');
const constants = require('./constants');

function generateBoilerplate(routerPath) {
    console.log("generating app routing...");
    if (!fs.existsSync(routerPath + 'app')) {
        fs.mkdirSync(routerPath + 'app');
        console.log(routerPath + 'app', "created.");

    }
    if (!fs.existsSync(routerPath + 'app/controllers')) {
        fs.mkdirSync(routerPath + 'app/controllers');
        console.log(routerPath + 'app/controllers', "created.");

    }
    if (!fs.existsSync(routerPath + 'app/middleware')) {
        fs.mkdirSync(routerPath + 'app/middleware');
        console.log(routerPath + 'app/middleware', "created.");

    }
    if (!fs.existsSync(routerPath + 'app/routes')) {
        fs.mkdirSync(routerPath + 'app/routes');
        console.log(routerPath + 'app/routes', "created.");

    }
    const routerFilePath = routerPath + 'app/Router.js';

    console.log("Processing Router.js ", routerFilePath);
    if (!fs.existsSync(routerFilePath)) {
        console.log("No Route.js was found!");

        fs.openSync(routerFilePath, 'a');
        console.log("Router.js created!");

        fs.writeFileSync(routerFilePath, constants.ROUTER_JS_STARTER);

        console.log("Router.js boilerplate ready!");
        return require(routerFilePath);
    } else {
        return require(routerFilePath);
    }
}

const initEndpointStructure = function ({test}) {
    let routerPath = path.normalize(`${__dirname}/../../../`);

    if (test) {
        routerPath = `${__dirname}/../`;
        console.log('testing mode, routing folder', routerPath);
    }
    generateBoilerplate(routerPath);
};

function constructPath({pathParsed, endpointData, Router}) {
    console.log("pathParsed[0]: ",pathParsed[0]);
    if (Router.length === 0) {
        if (pathParsed.length === 1) {
            Router.push({path: `/${pathParsed[0]}`, handler: endpointData.routerPath});
            return Router;
        } else {
            Router.push({
                path: `/${pathParsed[0]}`,
                subpaths: constructPath({pathParsed: pathParsed.splice(1), endpointData, Router: []})
            });
            return Router;
        }
    }

    Router.forEach((endpoint, idx, array) => {
        console.log(`idx: ${idx} out of ${array.length}, path: ${endpoint.path}`);
        if (idx === array.length - 1 && endpoint.path !== ('/' + pathParsed[0])) {
            console.log("last element and pathParse is not equal pathParsed[0]... pushing ");
            if (pathParsed.length === 1) {
                console.log("last element in pathParsed...pusing directry");
                Router.push({path: `/${pathParsed[0]}`, handler: endpointData.routerPath});
            } else {
                console.log("still not at end of pathParsed");
                Router.push({
                    path: `/${pathParsed[0]}`,
                    subpaths: constructPath({pathParsed: pathParsed.splice(1), endpointData, Router: []})
                });
            }
            return Router;
        }

        if (pathParsed.length === 1 && endpoint.path === ('/' + pathParsed[0])) {
            console.error("endpoint already exists!");
            throw new Error("endpoint already exists!");
        }
        if (pathParsed.length > 1 && endpoint.path === ('/' + pathParsed[0])) {
                console.log("part of endpoint matched moving on...");
                if (_.has(endpoint, "subpaths")) {
                    endpoint.subpaths = constructPath({
                        pathParsed: pathParsed.splice(1),
                        endpointData,
                        Router: endpoint.subpaths
                    });
                    return Router;
                } else {
                    throw new Error("handler for this endpoint already exists!");
                }
            }

    });

    return Router;
}

const addEndpoint = function ({endpointPath, router, controller}, test) {
    let appPath = path.normalize(`${__dirname}/../../../app/`);
    if (test) {
        appPath = path.normalize(`${__dirname}/../app/`);
        console.log('testing mode, routing folder', appPath);
    }
    const ROUTER_FILE = 'Router.js';
    const CONTROLLERS_FOLDER = 'controllers/';
    const ROUTES_FOLDER = 'routes/';

    const controllerFilePath = appPath + CONTROLLERS_FOLDER + controller;
    const routerFilePath = appPath + ROUTES_FOLDER + router;
    const routerJsFilePath = appPath + ROUTER_FILE;

    let endpointData = {
        endpointPath,
        controllerPath: 'app/' + CONTROLLERS_FOLDER + controller,
        routerPath: 'app/' + ROUTES_FOLDER + router
    };

    let Router;
    try {
        Router = require(routerJsFilePath);
    } catch (err) {
        console.error("could not find Router.js... did you call endpoint --init ?");
        return;
    }
    console.log("Router.js: ", Router);

    const pathParsed = endpointPath.split('/').splice(1);
    console.log(pathParsed);

    console.log("constructing Path");
    let res;
    try {
        res = constructPath({pathParsed, endpointData, Router})
    } catch (err) {
        console.error(err);
    }
    console.log("Construct Result: ", JSON.stringify(res, null, 2));
    let dumpData = "module.exports = \n" + JSON.stringify(res, null, 2);

    fs.openSync(routerJsFilePath, 'a');
    fs.writeFileSync(routerJsFilePath, dumpData);
    console.log(routerJsFilePath + " updated!");
    return;

    // router file
    if (!fs.existsSync(routerFilePath)) {
        fs.openSync(routerFilePath, 'a');
        fs.writeFileSync(routerFilePath, format(constants.ROUTER_FILE_BOILERPLATE, endpointData));
        console.log(routerFilePath + " created!");
    }

    // controller file
    if (!fs.existsSync(controllerFilePath)) {
        fs.openSync(controllerFilePath, 'a');
        fs.writeFileSync(controllerFilePath, constants.CONTROLLER_FILE_BOILERPLATE);
        console.log(controllerFilePath + " created!");
    }

    // main Router.js
    Router.push({path: endpointPath, handler: endpointData.routerPath});
    const routerJsData = "module.exports = \n" + JSON.stringify(Router, null, 2);

    fs.openSync(routerJsFilePath, 'a');
    fs.writeFileSync(routerJsFilePath, routerJsData);
    console.log(routerJsFilePath + " updated!");
};

module.exports = {
    initEndpoint: initEndpointStructure,
    addEndpoint: addEndpoint
};<|endoftext|>


<commit_before>import React from 'react';
import App from './App';

class Site extends React.Component {
  componentDidMount() {
    console.log('Sites children', this.props);
  }

  render() {
    return (

        <App>Site</App>

    );
  }
}

export default Site;
<commit_msg>fixed error where children were not being rendered<commit_after>import React from 'react';

class Site extends React.Component {
  componentDidMount() {
    console.log('Sites children', this.props);
  }

  render() {
    return (

        {this.props.children}

    );
  }
}

export default Site;
<|endoftext|>


<commit_before>import storage from 'electron-json-storage';
import { requestSpotifyToken, requestUserInfo } from '../api/auth'

export const AUTH_STORAGE_KEY = 'auth';

export function getStoredAuthData(){
  return new Promise((resolve, reject) => {
    storage.get(AUTH_STORAGE_KEY, function(error, authenticationData){
      if (error) reject(error);
      resolve(authenticationData);
    })
  })
}

function setStoredAuthData(authenticationData){
  return new Promise((resolve, reject) => {
    storage.set(AUTH_STORAGE_KEY, authenticationData, function(error, authenticationData){
      if (error) reject(error);
      resolve(authenticationData);
    })
  })
}

function getTokenInformation(options, code){
  return requestSpotifyToken(options, code).then((tokenData) => {
    let currentTime = new Date();
    let expiresIn = tokenData.expires_in;
    let expirationDate = currentTime.setSeconds(currentTime.getSeconds()+expiresIn);

    return {
      accessToken: tokenData.access_token,
      refreshToken: tokenData.refresh_token,
      expiresAt: expirationDate
    };
  });
}

function getAuthData(tokenData){
  return requestUserInfo(tokenData.accessToken)
    .then((userData) => {
      return {tokenData, userData}
    })
    .then((newAuthenticationData) => setStoredAuthData(newAuthenticationData))
}

export function authenticate(options, code){
  return getTokenInformation(options, code)
    .then((tokenData) => getAuthData(tokenData))
}

export function refreshAuthenticationData(options){
  return new Promise((resolve, reject) => {
    getStoredAuthData().then((authenticationData) => {
      let tokenData = authenticationData.tokenData;
      let now = new Date();

      if(tokenData.expiresAt > now){
        //Didn't expire yet, get user data again in case storage data changed
        getAuthData(tokenData)
          .then((storedData) => resolve(storedData))
          .catch((error) => reject(error))
      } else {
        //Token expired, then refresh data
        authenticate(options, tokenData.refreshToken)
          .then((storedData) => resolve(storedData));
      }
    })
      .catch((error) => {throw error})
  });
}
<commit_msg>Proper refreshToken mechanism.<commit_after>import storage from 'electron-json-storage';
import { requestSpotifyToken, requestUserInfo, refreshAccessToken } from '../api/auth'

export const AUTH_STORAGE_KEY = 'auth';

export function getStoredAuthData(){
  return new Promise((resolve, reject) => {
    storage.get(AUTH_STORAGE_KEY, function(error, authenticationData){
      if (error) reject(error);
      resolve(authenticationData);
    })
  })
}

function setStoredAuthData(authenticationData){
  return new Promise((resolve, reject) => {
    storage.set(AUTH_STORAGE_KEY, authenticationData, function(error, authenticationData){
      if (error) reject(error);
      resolve(authenticationData);
    })
  })
}

function extractTokenData(data){
  let tokenData = {};
  let currentTime = new Date();
  let expiresIn = data.expires_in;
  let expirationDate = currentTime.setSeconds(currentTime.getSeconds()+expiresIn);

  if(data.refresh_token){
    tokenData.refreshToken = data.refresh_token;
  }

  tokenData.access_token = data.access_token;
  tokenData.expiresAt = expirationDate;

  return tokenData;
}

function getTokenInformation(options, code){
  return requestSpotifyToken(options, code).then((tokenData) => extractTokenData(tokenData));
}

function getAuthData(tokenData){
  return requestUserInfo(tokenData.accessToken)
    .then((userData) => {
      return {tokenData, userData}
    })
    .then((newAuthenticationData) => setStoredAuthData(newAuthenticationData))
}

export function getRefreshedAccessToken(options, refreshToken){
  return refreshAccessToken(options, refreshToken)
    .then((tokenData) => extractTokenData(tokenData))
    .then((newAccessTokenData) => {
      return getStoredAuthData()
        .then((oldStoredAuthData) => {
          let refreshedAuthData = Object.assign({}, oldStoredAuthData);
          refreshedAuthData.tokenData = Object.assign({}, refreshedAuthData, newAccessTokenData);
          return getAuthData(refreshedAuthData.tokenData);
        })
    })
}

export function authenticate(options, code){
  return getTokenInformation(options, code)
    .then((tokenData) => getAuthData(tokenData))
}

export function refreshAuthenticationData(options){
  return new Promise((resolve, reject) => {
    getStoredAuthData()
      .then((authenticationData) => {
        let tokenData = authenticationData.tokenData;
        let now = new Date();

        if(tokenData.expiresAt > now){
          //Didn't expire yet, get user data again in case storage data changed
          getAuthData(tokenData)
            .then((storedData) => resolve(storedData))
        } else {
          //Token expired, then refresh data
          getRefreshedAccessToken(options, tokenData.refreshToken)
            .then((storedData) => resolve(storedData))
        }
      })
      .catch((error) => {reject(error)})
  });
}
<|endoftext|>


<commit_before>// CartoDB SQL API
//
// all requests expect the following URL args:
// - `sql` {String} SQL to execute
//
// for private (read/write) queries:
// - OAuth. Must have proper OAuth 1.1 headers. For OAuth 1.1 spec see Google
//
// eg. /api/v1/?sql=SELECT 1 as one (with a load of OAuth headers or URL arguments)
//
// for public (read only) queries:
// - sql only, provided the subdomain exists in CartoDB and the table's sharing options are public
//
// eg. vizzuality.cartodb.com/api/v1/?sql=SELECT * from my_table

var express= require('express')
    , app    = express.createServer(
                express.logger({buffer:true,
                                format:'[:req[X-Real-IP] :date] \033[90m:method\033[0m \033[36m:url\033[0m \033[90m:status :response-time ms -> :res[Content-Type]\033[0m'}))
    , Step   = require('step')
    , Meta   = require(global.settings.app_root + '/app/models/metadata')
    , oAuth  = require(global.settings.app_root + '/app/models/oauth')
    , PSQL   = require(global.settings.app_root + '/app/models/psql')
    , _      = require('underscore');

app.use(express.bodyParser());
app.enable('jsonp callback');

app.get('/api/v1/sql',  function(req, res) { handleQuery(req, res) } );
app.post('/api/v1/sql', function(req, res) { handleQuery(req, res) } );
function handleQuery(req, res){

    // sanitize input
    var body      = (req.body) ? req.body : {};
    var sql       = req.query.q || body.q; // get and post
    var database  = req.query.database; // deprecate this in future
    var limit     = parseInt(req.query.rows_per_page);
    var offset    = parseInt(req.query.page);

    sql       = (sql == "")      ? null : sql;
    database  = (database == "") ? null : database;
    limit     = (_.isNumber(limit))  ? limit : null;
    offset    = (_.isNumber(offset)) ? offset * limit : null

    // setup step run
    var that  = this;
    var start = new Date().getTime();

    try {
        if (!_.isString(sql)) throw new Error("You must indicate a sql query");
        var pg;

        // 1. Get database from redis via the username stored in the host header subdomain
        // 2. Run the request through OAuth to get R/W user id if signed
        // 3. Run query with r/w or public user
        // 4. package results and send back
        Step(
            function getDatabaseName(){
                Meta.getDatabase(req, this);
            },
            function setDBGetUser(err, data) {
                if (err) throw err;
                database = (data == "" || _.isNull(data)) ? database : data;
                oAuth.verifyRequest(req, this);
            },
            function querySql(err, user_id){
                if (err) throw err;
                pg = new PSQL(user_id, database, limit, offset);
                pg.query(sql, this);
            },
            function packageResults(err, result){
                if (err) throw err;
                var end = new Date().getTime();
                res.send({'time' : ((end - start)/1000),
                    'total_rows': result.rows.length,
                    'rows'      : result.rows});
            },
            function errorHandle(err, result){
                handleException(err, res);
            }
        );
    } catch (err) {
        console.log('[ERROR]\n' + err);
        handleException(err, res);
    }
}

function handleException(err, res){
    var msg = (global.settings.environment == 'development') ? {error:[err.message], stack: err.stack} : {error:[err.message]}
    if (global.settings.environment !== 'test'){
        // TODO: email this Exception report
        console.log("EXCEPTION REPORT")
        console.log(err.message);
        console.log(err.stack);
    }
    res.send(msg, 400);
}

module.exports = app;
<commit_msg>add instructions for a mapuser<commit_after>// CartoDB SQL API
//
// all requests expect the following URL args:
// - `sql` {String} SQL to execute
//
// for private (read/write) queries:
// - OAuth. Must have proper OAuth 1.1 headers. For OAuth 1.1 spec see Google
//
// eg. /api/v1/?sql=SELECT 1 as one (with a load of OAuth headers or URL arguments)
//
// for public (read only) queries:
// - sql only, provided the subdomain exists in CartoDB and the table's sharing options are public
//
// eg. vizzuality.cartodb.com/api/v1/?sql=SELECT * from my_table

var express= require('express')
    , app    = express.createServer(
                express.logger({buffer:true,
                                format:'[:req[X-Real-IP] :date] \033[90m:method\033[0m \033[36m:url\033[0m \033[90m:status :response-time ms -> :res[Content-Type]\033[0m'}))
    , Step   = require('step')
    , Meta   = require(global.settings.app_root + '/app/models/metadata')
    , oAuth  = require(global.settings.app_root + '/app/models/oauth')
    , PSQL   = require(global.settings.app_root + '/app/models/psql')
    , _      = require('underscore');

app.use(express.bodyParser());
app.enable('jsonp callback');

app.get('/api/v1/sql',  function(req, res) { handleQuery(req, res) } );
app.post('/api/v1/sql', function(req, res) { handleQuery(req, res) } );
function handleQuery(req, res){

    // sanitize input
    var body      = (req.body) ? req.body : {};
    var sql       = req.query.q || body.q; // get and post
    var database  = req.query.database; // deprecate this in future
    var limit     = parseInt(req.query.rows_per_page);
    var offset    = parseInt(req.query.page);

    sql       = (sql == "")      ? null : sql;
    database  = (database == "") ? null : database;
    limit     = (_.isNumber(limit))  ? limit : null;
    offset    = (_.isNumber(offset)) ? offset * limit : null

    // setup step run
    var that  = this;
    var start = new Date().getTime();

    try {
        if (!_.isString(sql)) throw new Error("You must indicate a sql query");
        var pg;

        // 1. Get database from redis via the username stored in the host header subdomain
        // 2. Run the request through OAuth to get R/W user id if signed
        // 3. Run query with r/w or public user
        // 4. package results and send back
        Step(
            function getDatabaseName(){
                Meta.getDatabase(req, this);
            },
            function setDBGetUser(err, data) {
                if (err) throw err;
                database = (data == "" || _.isNull(data)) ? database : data;
                oAuth.verifyRequest(req, this);
            },
            // TODO insert check here for if it's a map request from the internal CartoDB session key
            // TODO if it is, allow RW or R?
            function querySql(err, user_id){
                if (err) throw err;
                pg = new PSQL(user_id, database, limit, offset);
                pg.query(sql, this);
            },
            function packageResults(err, result){
                if (err) throw err;
                var end = new Date().getTime();
                res.send({'time' : ((end - start)/1000),
                    'total_rows': result.rows.length,
                    'rows'      : result.rows});
            },
            function errorHandle(err, result){
                handleException(err, res);
            }
        );
    } catch (err) {
        console.log('[ERROR]\n' + err);
        handleException(err, res);
    }
}

function handleException(err, res){
    var msg = (global.settings.environment == 'development') ? {error:[err.message], stack: err.stack} : {error:[err.message]}
    if (global.settings.environment !== 'test'){
        // TODO: email this Exception report
        console.log("EXCEPTION REPORT")
        console.log(err.message);
        console.log(err.stack);
    }
    res.send(msg, 400);
}

module.exports = app;
<|endoftext|>


<commit_before>// CartoDB SQL API
//
// all requests expect the following URL args:
// - `sql` {String} SQL to execute
//
// for private (read/write) queries:
// - OAuth. Must have proper OAuth 1.1 headers. For OAuth 1.1 spec see Google
//
// eg. /api/v1/?sql=SELECT 1 as one (with a load of OAuth headers or URL arguments)
//
// for public (read only) queries:
// - sql only, provided the subdomain exists in CartoDB and the table's sharing options are public
//
// eg. vizzuality.cartodb.com/api/v1/?sql=SELECT * from my_table
var express = require('express')
    , app      = express.createServer(
    express.logger({
        buffer: true,
        format: '[:date] :req[X-Real-IP] \033[90m:method\033[0m \033[36m:req[Host]:url\033[0m \033[90m:status :response-time ms -> :res[Content-Type]\033[0m'
    }))
    , Step       = require('step')
    , csv        = require('csv')
    , Meta       = require(global.settings.app_root + '/app/models/metadata')
    , oAuth      = require(global.settings.app_root + '/app/models/oauth')
    , PSQL       = require(global.settings.app_root + '/app/models/psql')
    , ApiKeyAuth = require(global.settings.app_root + '/app/models/apikey_auth')
    , _        = require('underscore');

app.use(express.bodyParser());
app.enable('jsonp callback');

app.all('/api/v1/sql',  function(req, res) { handleQuery(req, res) } );
app.all('/api/v1/sql.:f',  function(req, res) { handleQuery(req, res) } );
function handleQuery(req, res){

    // sanitize input
    var body      = (req.body) ? req.body : {};
    var sql       = req.query.q || body.q; // get and post
    var api_key   = req.query.api_key || body.api_key;
    var database  = req.query.database; // deprecate this in future
    var limit     = parseInt(req.query.rows_per_page);
    var offset    = parseInt(req.query.page);
    var format    = (req.query.format) ? req.query.format : null;
    var dp        = (req.query.dp) ? req.query.dp: '15';

    // validate input slightly
    dp        = (dp=== "")        ? '15' : dp;
    format    = (format === "")   ? null : format;
    sql       = (sql === "")      ? null : sql;
    database  = (database === "") ? null : database;
    limit     = (_.isNumber(limit))  ? limit : null;
    offset    = (_.isNumber(offset)) ? offset * limit : null

    // setup step run
    var that  = this;
    var start = new Date().getTime();

    try {
        if (!_.isString(sql)) throw new Error("You must indicate a sql query");
        var pg;

        // 1. Get database from redis via the username stored in the host header subdomain
        // 2. Run the request through OAuth to get R/W user id if signed
        // 3. Run query with r/w or public user
        // 4. package results and send back
        Step(
            function getDatabaseName(){
                Meta.getDatabase(req, this);
            },
            function setDBGetUser(err, data) {
                if (err) throw err;
                database = (data == "" || _.isNull(data)) ? database : data;
                if(api_key) {
                    ApiKeyAuth.verifyRequest(req, this);
                } else {
                    oAuth.verifyRequest(req, this);
                }
            },
            function querySql(err, user_id){
                if (err) throw err;
                pg = new PSQL(user_id, database, limit, offset);

                // TODO: refactor formats to external object
                if (format === 'geojson'){
                    sql = ['SELECT *, ST_AsGeoJSON(the_geom,',dp,') as the_geom FROM (', sql, ') as foo'].join("");
                }

                pg.query(sql, this);
            },
            function setHeaders(err, result){
                if (err) throw err;

                // configure headers for geojson/CSV
                res.header("Content-Disposition", getContentDisposition(format));
                res.header("Content-Type", getContentType(format));

                // allow cross site post
                setCrossDomain(res);

                // set cache headers
                res.header('Last-Modified', new Date().toUTCString());
                res.header('Cache-Control', 'no-cache,max-age=3600,must-revalidate, public');
                res.header('X-Cache-Channel', database);

                return result;
            },
            function packageResults(err, result){
                if (err) throw err;

                // TODO: refactor formats to external object
                if (format === 'geojson'){
                    toGeoJSON(result, res, this);
                } else if (format === 'csv'){
                    toCSV(result, res, this);
                } else {
                    var end = new Date().getTime();
                    return {
                        'time' : ((end - start)/1000),
                        'total_rows': result.rows.length,
                        'rows'      : result.rows
                    };
                }
            },
            function sendResults(err, out){
                if (err) throw err;

                // return to browser
                res.send(out);
            },
            function errorHandle(err, result){
                handleException(err, res);
            }
        );
    } catch (err) {
        console.log('[ERROR]\n' + err);
        handleException(err, res);
    }
}

function toGeoJSON(data, res, callback){
    try{
        var out = {
            type: "FeatureCollection",
            features: []
        };

        _.each(data.rows, function(ele){
            var geojson = {
                type: "Feature",
                properties: { },
                geometry: { }
            };
            geojson.geometry = JSON.parse(ele["the_geom"]);
            delete ele["the_geom"];
            delete ele["the_geom_webmercator"];
            geojson.properties = ele;
            out.features.push(geojson);
        });

        // return payload
        callback(null, out);
    } catch (err) {
        callback(err,null);
    }
}

function toCSV(data, res, callback){
    try{
        // pull out keys for column headers
        var columns = _.keys(data.rows[0]);

        // stream the csv out over http
        csv()
          .from(data.rows)
          .toStream(res, {end: true, columns: columns, header: true});
        return true;
    } catch (err) {
        callback(err,null);
    }
}

function getContentDisposition(format){
    var ext = 'json';
    if (format === 'geojson'){
        ext = 'geojson';
    }
    if (format === 'csv'){
        ext = 'csv';
    }
    var time = new Date().toUTCString();
    return 'inline; filename=cartodb-query.' + ext + '; modification-date="' + time + '";';
}

function getContentType(format){
    var type = "application/json; charset=utf-8";
    if (format === 'csv'){
        type = "text/csv; charset=utf-8";
    }
    return type;
}

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

function handleException(err, res){
    var msg = (global.settings.environment == 'development') ? {error:[err.message], stack: err.stack} : {error:[err.message]}
    if (global.settings.environment !== 'test'){
        // TODO: email this Exception report
        console.log("EXCEPTION REPORT")
        console.log(err.message);
        console.log(err.stack);
    }

    // allow cross site post
    setCrossDomain(res);

    // if the exception defines a http status code, use that, else a 500
    if (!_.isUndefined(err.http_status)){
        res.send(msg, err.http_status);
    } else {
        res.send(msg, 400);
    }
}

module.exports = app;
<commit_msg>close connections<commit_after>// CartoDB SQL API
//
// all requests expect the following URL args:
// - `sql` {String} SQL to execute
//
// for private (read/write) queries:
// - OAuth. Must have proper OAuth 1.1 headers. For OAuth 1.1 spec see Google
//
// eg. /api/v1/?sql=SELECT 1 as one (with a load of OAuth headers or URL arguments)
//
// for public (read only) queries:
// - sql only, provided the subdomain exists in CartoDB and the table's sharing options are public
//
// eg. vizzuality.cartodb.com/api/v1/?sql=SELECT * from my_table
var express = require('express')
    , app      = express.createServer(
    express.logger({
        buffer: true,
        format: '[:date] :req[X-Real-IP] \033[90m:method\033[0m \033[36m:req[Host]:url\033[0m \033[90m:status :response-time ms -> :res[Content-Type]\033[0m'
    }))
    , Step       = require('step')
    , csv        = require('csv')
    , Meta       = require(global.settings.app_root + '/app/models/metadata')
    , oAuth      = require(global.settings.app_root + '/app/models/oauth')
    , PSQL       = require(global.settings.app_root + '/app/models/psql')
    , ApiKeyAuth = require(global.settings.app_root + '/app/models/apikey_auth')
    , _        = require('underscore');

app.use(express.bodyParser());
app.enable('jsonp callback');

app.all('/api/v1/sql',  function(req, res) { handleQuery(req, res) } );
app.all('/api/v1/sql.:f',  function(req, res) { handleQuery(req, res) } );
function handleQuery(req, res){

    // sanitize input
    var body      = (req.body) ? req.body : {};
    var sql       = req.query.q || body.q; // get and post
    var api_key   = req.query.api_key || body.api_key;
    var database  = req.query.database; // deprecate this in future
    var limit     = parseInt(req.query.rows_per_page);
    var offset    = parseInt(req.query.page);
    var format    = (req.query.format) ? req.query.format : null;
    var dp        = (req.query.dp) ? req.query.dp: '15';

    // validate input slightly
    dp        = (dp=== "")        ? '15' : dp;
    format    = (format === "")   ? null : format;
    sql       = (sql === "")      ? null : sql;
    database  = (database === "") ? null : database;
    limit     = (_.isNumber(limit))  ? limit : null;
    offset    = (_.isNumber(offset)) ? offset * limit : null

    // setup step run
    var that  = this;
    var start = new Date().getTime();

    try {
        if (!_.isString(sql)) throw new Error("You must indicate a sql query");
        var pg;

        // 1. Get database from redis via the username stored in the host header subdomain
        // 2. Run the request through OAuth to get R/W user id if signed
        // 3. Run query with r/w or public user
        // 4. package results and send back
        Step(
            function getDatabaseName(){
                Meta.getDatabase(req, this);
            },
            function setDBGetUser(err, data) {
                if (err) throw err;
                database = (data == "" || _.isNull(data)) ? database : data;
                if(api_key) {
                    ApiKeyAuth.verifyRequest(req, this);
                } else {
                    oAuth.verifyRequest(req, this);
                }
            },
            function querySql(err, user_id){
                if (err) throw err;
                pg = new PSQL(user_id, database, limit, offset);

                // TODO: refactor formats to external object
                if (format === 'geojson'){
                    sql = ['SELECT *, ST_AsGeoJSON(the_geom,',dp,') as the_geom FROM (', sql, ') as foo'].join("");
                }

                pg.query(sql, this);
            },
            function setHeaders(err, result){
                if (err) throw err;

                // close connection to psql. be nice.
                pg.end();

                // configure headers for geojson/CSV
                res.header("Content-Disposition", getContentDisposition(format));
                res.header("Content-Type", getContentType(format));

                // allow cross site post
                setCrossDomain(res);

                // set cache headers
                res.header('Last-Modified', new Date().toUTCString());
                res.header('Cache-Control', 'no-cache,max-age=3600,must-revalidate, public');
                res.header('X-Cache-Channel', database);

                return result;
            },
            function packageResults(err, result){
                if (err) throw err;

                // TODO: refactor formats to external object
                if (format === 'geojson'){
                    toGeoJSON(result, res, this);
                } else if (format === 'csv'){
                    toCSV(result, res, this);
                } else {
                    var end = new Date().getTime();
                    return {
                        'time' : ((end - start)/1000),
                        'total_rows': result.rows.length,
                        'rows'      : result.rows
                    };
                }
            },
            function sendResults(err, out){
                if (err) throw err;

                // return to browser
                res.send(out);
            },
            function errorHandle(err, result){
                handleException(err, res);
            }
        );
    } catch (err) {
        console.log('[ERROR]\n' + err);
        handleException(err, res);
    }
}

function toGeoJSON(data, res, callback){
    try{
        var out = {
            type: "FeatureCollection",
            features: []
        };

        _.each(data.rows, function(ele){
            var geojson = {
                type: "Feature",
                properties: { },
                geometry: { }
            };
            geojson.geometry = JSON.parse(ele["the_geom"]);
            delete ele["the_geom"];
            delete ele["the_geom_webmercator"];
            geojson.properties = ele;
            out.features.push(geojson);
        });

        // return payload
        callback(null, out);
    } catch (err) {
        callback(err,null);
    }
}

function toCSV(data, res, callback){
    try{
        // pull out keys for column headers
        var columns = _.keys(data.rows[0]);

        // stream the csv out over http
        csv()
          .from(data.rows)
          .toStream(res, {end: true, columns: columns, header: true});
        return true;
    } catch (err) {
        callback(err,null);
    }
}

function getContentDisposition(format){
    var ext = 'json';
    if (format === 'geojson'){
        ext = 'geojson';
    }
    if (format === 'csv'){
        ext = 'csv';
    }
    var time = new Date().toUTCString();
    return 'inline; filename=cartodb-query.' + ext + '; modification-date="' + time + '";';
}

function getContentType(format){
    var type = "application/json; charset=utf-8";
    if (format === 'csv'){
        type = "text/csv; charset=utf-8";
    }
    return type;
}

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

function handleException(err, res){
    var msg = (global.settings.environment == 'development') ? {error:[err.message], stack: err.stack} : {error:[err.message]}
    if (global.settings.environment !== 'test'){
        // TODO: email this Exception report
        console.log("EXCEPTION REPORT")
        console.log(err.message);
        console.log(err.stack);
    }

    // allow cross site post
    setCrossDomain(res);

    // if the exception defines a http status code, use that, else a 500
    if (!_.isUndefined(err.http_status)){
        res.send(msg, err.http_status);
    } else {
        res.send(msg, 400);
    }
}

module.exports = app;
<|endoftext|>


<commit_before>if (!Array.prototype.filter) {
    Array.prototype.filter = function(fun/*, thisArg*/) {
        'use strict';

        if (this === void 0 || this === null) {
            throw new TypeError();
        }

        var t = Object(this);
        var len = t.length >>> 0;
        if (typeof fun !== 'function') {
            throw new TypeError();
        }

        var res = [];
        var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
        for (var i = 0; i < len; i++) {
            if (i in t) {
                var val = t[i];

                // NOTE: Technically this should Object.defineProperty at
                //       the next index, as push can be affected by
                //       properties on Object.prototype and Array.prototype.
                //       But that method's new, and collisions should be
                //       rare, so use the more-compatible alternative.
                if (fun.call(thisArg, val, i, t)) {
                    res.push(val);
                }
            }
        }

        return res;
    };
}

(function ($) {
    "use strict";

    var operators = [
        {'name': 'equals'     , 'fn': function (a , b) { return a == b }}         ,
        {'name': 'startsWith' , 'fn': function (a , b){ return a.startsWith(b) }} ,
        {'name': 'endsWith'   , 'fn': function (a , b){ return a.endsWith(b) }}   ,
        {'name': 'contains'   , 'fn': function (a , b) { return a.indexOf(b) != -1 }}
    ];

    function DjSet(k, l){
        this.key = k;
        this.items = {};
        if ( l ){
            for ( var i = 0; i < l.length; i ++){
                this.add(l[i]);
            }
        }
    }

    DjSet.prototype.add = function(obj){
        this.items[obj[this.key]] = obj;
    }

    DjSet.prototype.remove = function(obj){
        delete this.items[obj[this.key]];
    }

    DjSet.prototype.array = function(){
        var l = [];
        for ( var k in this.items ){
            l.push(this.items[k]);
        }
        return l;
    }

    DjSet.prototype.union = function(other){
        if ( $.isArray(other) ){
            for ( var i = 0 ; i < other.length; i ++){
                this.add(other[i]);
            }
        }else{
            // assume DjSet
            for ( var k in other){
                this.add(other[k]);
            }
        }
    }

    DjSet.prototype.clone = function(){
        var clone = new DjSet(this.key);
        clone.items = jQuery.extend({}, this.items);
        return clone;
    };

    DjSet.prototype.contains = function(obj){
        return this.items[obj[this.key]];
    }

    DjSet.prototype.difference = function(other){
        var otherSet;
        if ( $.isArray(other) ){
            otherSet = new DjSet(other);
        }else{
            // assume DjSet
            otherSet = other;

        }
        for ( var k in this.items){
            if ( otherSet.contains(this.items[k]) ){
                delete this.items[k];
            }
        }
    }

    DjSet.prototype.intersect = function(other){
        var otherSet;
        if ( $.isArray(other) ){
            otherSet = new DjSet(other);
        }else{
            // assume DjSet
            otherSet = other;

        }
        for ( var k in this.items){
            if ( !otherSet.contains(this.items[k]) ){
                delete this.items[k];
            }
        }
    }

    function predicateFromString(predicateExpression){
        var predicate;
        if ( predicateExpression != '' ){
            var fnStr = '(function(x){ console.log(x + " " + (' + predicateExpression + '));return (' + predicateExpression + ');})';
            try{
                predicate = eval(fnStr);
            }catch(e){
                console.log(e);
                predicate = function(){ return true };
            }
        }else{
            predicate = function(){ return true };
        }

        return predicate
    }

    function Djcategorize(el, options){
        this.element = $(el);
        this.options = options;
        this.init();
    }

    Djcategorize.prototype = {
        init: function(){
            var self = this;

            self.steps = [];

            self.addStepButton = $('<button/>');
            self.addStepButton.text('Add Step');
            self.element.append(self.addStepButton);
            self.addStepButton.on('click', function(){
                self.steps.push('');
                self.update();
            });

            self.stepContainer = $('
');
            self.element.append(self.stepContainer);

            self.dataProperties = [];
            var propSet = {};
            for ( var i = 0 ; i < self.options.data.length; i ++){
                var datum = self.options.data[i];
                for (var k in datum){
                    if ( !propSet[k] ){
                        self.dataProperties.push(k);
                        propSet[k] = true;
                    }
                }
            }

            self.$tableContainer = $('
');
            self.element.append(self.$tableContainer);

            self.resultData = new DjSet(self.options.data_key, self.options.data);
            self.updateTable();

        },

        stringifyData: function(data){
            var self = this;
            var ss = [];
            for ( var i = 0; i < data.length; i ++){
                ss.push(data[i][self.options.name_key]);
            }
            return ss.join(', ');
        },
        updateTable: function(){
            var self = this;
            // expects self.resultData to be set
            var $table = $('
');
            $table.addClass('table');
            $table.addClass('table-striped');
            $table.addClass('table-condensed');

            var $header = $('
');
            for (var k = 0; k < self.dataProperties.length; k ++){
                var $th = $('');
                $th.text(self.dataProperties[k]);
                $header.append($th);
            }
            $table.append($header);

            function addRow(datum){
                var $tr = $('
');
                for (var k = 0; k < self.dataProperties.length; k ++){
                    var prop = self.dataProperties[k];
                    var $td = $('');
                    $td.text(datum[prop]);
                    $tr.append($td);
                }
                $table.append($tr);
                return $tr;
            }

            var dataArray = self.options.data;
            var data = new DjSet(self.options.data_key, self.options.data);
            for ( var j = 0 ; j < dataArray.length; j ++){
                var datum = dataArray[j];
                var $tr = addRow(datum);
                if ( data.contains(datum) && !self.resultData.contains(datum) ){
                    $tr.addClass('danger');
                }
            }

            self.$tableContainer.html($table);

        },
        update: function(){
            var self = this;

            var $stepElems = self.stepContainer.children('.step');
            var data = new DjSet(self.options.data_key, self.options.data);
            for ( var i = 0; i < self.steps.length; i ++){
                var $elem;
                if ( i >= $stepElems.length ){
                    $elem = $('
<select class="addorsubtract"><option value="removematching">Remove matching</option><option value="reinclude">Include matching full set</option><option value="keepmatching">Keep Matching</option><option value="includeall">Include all</option><option value="removeall">Remove all</option></select><select class="property" ></select><select class="operator" ></select><input class="operand" type="text"/><button>Remove</button>
');
                    self.stepContainer.append($elem);

                    $elem.find('button').on('click', function(i,$elem){

                        self.steps.splice(i,1);
                        $elem.remove();

                    }.bind(null,i, $elem));

                    $elem.find('input').on('input', function(){
                        self.update();
                    });
                    $elem.find('select').on('input', function(){
                        self.update();
                    });

                    var $properties = $elem.find('.property');
                    for (var j = 0; j < self.dataProperties.length; j ++){
                        var $option = $('<option/>');
                        $option.text(self.dataProperties[j]);
                        $properties.append($option);
                    }

                    var $operators = $elem.find('.operator');
                    for ( var j = 0; j < operators.length; j ++){
                        var operator = operators[j];
                        console.log(operator)
                        var $option = $('<option/>');
                        $option.text(operator.name);
                        $operators.append($option);
                    }

                }else{
                    $elem = $stepElems.eq(i);
                }

                var operator_name = $elem.find('.operator').val();
                var operator_fn;
                for ( var j = 0; j < operators.length; j ++){
                    if ( operator_name == operators[j].name ){
                        operator_fn = operators[j].fn;
                    }
                }

                var operand =  $elem.find('.operand').val();
                var property = $elem.find('.property').val();
                var predicate = function(x){
                    return operator_fn(x[property], operand);
                }

                var previousData = data.clone();
                var filterType = $elem.find('.addorsubtract').val()
                if ( filterType == 'removematching'){

                    var toRemove = data.array().filter(predicate);
                    console.log('to remove');
                    console.log(toRemove);
                    for ( var j = 0; j < toRemove.length; j ++){
                        data.remove(toRemove[j]);
                    }
                }else if (filterType == 'reinclude'){
                    data.union(self.options.data.filter(predicate));

                }else if ( filterType == 'keepmatching'){
                    data= new DjSet(data.key, data.array().filter(predicate));
                }else if ( filterType == 'includeall'){
                    data = new DjSet(self.options.data_key, self.options.data);
                }else if ( filterType == 'removeall'){
                    data = new DjSet(self.options.data_key);
                }else{
                    console.log('unknown filter type ' + filterType );
                }

            }

            for ( var i = self.steps.length; i < $stepElems.length ; i ++){
                $stepElems.get(i).remove();
            }
            self.resultData = data;
            self.updateTable();

        }

    }

    $.fn.djcategorize = function(options) {
        var opts = $.extend( {}, $.fn.djcategorize.defaults, options );
        return new Djcategorize($(this), opts);
    };

    $.fn.djcategorize.defaults = {

    };
})(jQuery);
<commit_msg>Code cleanup.<commit_after>if (!Array.prototype.filter) {
    Array.prototype.filter = function(fun/*, thisArg*/) {
        'use strict';

        if (this === void 0 || this === null) {
            throw new TypeError();
        }

        var t = Object(this);
        var len = t.length >>> 0;
        if (typeof fun !== 'function') {
            throw new TypeError();
        }

        var res = [];
        var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
        for (var i = 0; i < len; i++) {
            if (i in t) {
                var val = t[i];

                // NOTE: Technically this should Object.defineProperty at
                //       the next index, as push can be affected by
                //       properties on Object.prototype and Array.prototype.
                //       But that method's new, and collisions should be
                //       rare, so use the more-compatible alternative.
                if (fun.call(thisArg, val, i, t)) {
                    res.push(val);
                }
            }
        }

        return res;
    };
}

(function ($) {
    "use strict";

    var operators = [
        {'name': 'equals'     , 'fn': function (a , b) { return a == b }}         ,
        {'name': 'startsWith' , 'fn': function (a , b){ return a.startsWith(b) }} ,
        {'name': 'endsWith'   , 'fn': function (a , b){ return a.endsWith(b) }}   ,
        {'name': 'contains'   , 'fn': function (a , b) { return a.indexOf(b) != -1 }}
    ];

    function DjSet(k, l){
        this.key = k;
        this.items = {};
        if ( l ){
            for ( var i = 0; i < l.length; i ++){
                this.add(l[i]);
            }
        }
    }

    DjSet.prototype.add = function(obj){
        this.items[obj[this.key]] = obj;
    }

    DjSet.prototype.remove = function(obj){
        delete this.items[obj[this.key]];
    }

    DjSet.prototype.array = function(){
        var l = [];
        for ( var k in this.items ){
            l.push(this.items[k]);
        }
        return l;
    }

    DjSet.prototype.union = function(other){
        if ( $.isArray(other) ){
            for ( var i = 0 ; i < other.length; i ++){
                this.add(other[i]);
            }
        }else{
            // assume DjSet
            for ( var k in other){
                this.add(other[k]);
            }
        }
    }

    DjSet.prototype.clone = function(){
        var clone = new DjSet(this.key);
        clone.items = jQuery.extend({}, this.items);
        return clone;
    };

    DjSet.prototype.contains = function(obj){
        return this.items[obj[this.key]];
    }

    DjSet.prototype.difference = function(other){
        var otherSet;
        if ( $.isArray(other) ){
            otherSet = new DjSet(other);
        }else{
            // assume DjSet
            otherSet = other;

        }
        for ( var k in this.items){
            if ( otherSet.contains(this.items[k]) ){
                delete this.items[k];
            }
        }
    }

    DjSet.prototype.intersect = function(other){
        var otherSet;
        if ( $.isArray(other) ){
            otherSet = new DjSet(other);
        }else{
            // assume DjSet
            otherSet = other;

        }
        for ( var k in this.items){
            if ( !otherSet.contains(this.items[k]) ){
                delete this.items[k];
            }
        }
    }

    function Djcategorize(el, options){
        this.element = $(el);
        this.options = options;
        this.init();
    }

    Djcategorize.prototype = {
        init: function(){
            var self = this;

            self.steps = [];

            self.addStepButton = $('<button/>');
            self.addStepButton.text('Add Step');
            self.element.append(self.addStepButton);
            self.addStepButton.on('click', function(){
                self.steps.push('');
                self.update();
            });

            self.stepContainer = $('
');
            self.element.append(self.stepContainer);

            self.dataProperties = [];
            var propSet = {};
            for ( var i = 0 ; i < self.options.data.length; i ++){
                var datum = self.options.data[i];
                for (var k in datum){
                    if ( !propSet[k] ){
                        self.dataProperties.push(k);
                        propSet[k] = true;
                    }
                }
            }

            self.$tableContainer = $('
');
            self.element.append(self.$tableContainer);

            self.resultData = new DjSet(self.options.data_key, self.options.data);
            self.updateTable();

        },

        stringifyData: function(data){
            var self = this;
            var ss = [];
            for ( var i = 0; i < data.length; i ++){
                ss.push(data[i][self.options.name_key]);
            }
            return ss.join(', ');
        },
        updateTable: function(){
            var self = this;
            // expects self.resultData to be set
            var $table = $('
');
            $table.addClass('table');
            $table.addClass('table-striped');
            $table.addClass('table-condensed');

            var $header = $('
');
            for (var k = 0; k < self.dataProperties.length; k ++){
                var $th = $('');
                $th.text(self.dataProperties[k]);
                $header.append($th);
            }
            $table.append($header);

            function addRow(datum){
                var $tr = $('
');
                for (var k = 0; k < self.dataProperties.length; k ++){
                    var prop = self.dataProperties[k];
                    var $td = $('');
                    $td.text(datum[prop]);
                    $tr.append($td);
                }
                $table.append($tr);
                return $tr;
            }

            var dataArray = self.options.data;
            var data = new DjSet(self.options.data_key, self.options.data);
            for ( var j = 0 ; j < dataArray.length; j ++){
                var datum = dataArray[j];
                var $tr = addRow(datum);
                if ( data.contains(datum) && !self.resultData.contains(datum) ){
                    $tr.addClass('danger');
                }
            }

            self.$tableContainer.html($table);

        },
        update: function(){
            var self = this;

            var $stepElems = self.stepContainer.children('.step');
            var data = new DjSet(self.options.data_key, self.options.data);
            for ( var i = 0; i < self.steps.length; i ++){
                var $elem;
                if ( i >= $stepElems.length ){
                    $elem = $('
<select class="addorsubtract"><option value="removematching">Remove matching</option><option value="reinclude">Include matching full set</option><option value="keepmatching">Keep Matching</option><option value="includeall">Include all</option><option value="removeall">Remove all</option></select><select class="property" ></select><select class="operator" ></select><input class="operand" type="text"/><button>Remove</button>
');
                    self.stepContainer.append($elem);

                    $elem.find('button').on('click', function(i,$elem){

                        self.steps.splice(i,1);
                        $elem.remove();

                    }.bind(null,i, $elem));

                    $elem.find('input').on('input', function(){
                        self.update();
                    });
                    $elem.find('select').on('input', function(){
                        self.update();
                    });

                    var $properties = $elem.find('.property');
                    for (var j = 0; j < self.dataProperties.length; j ++){
                        var $option = $('<option/>');
                        $option.text(self.dataProperties[j]);
                        $properties.append($option);
                    }

                    var $operators = $elem.find('.operator');
                    for ( var j = 0; j < operators.length; j ++){
                        var operator = operators[j];
                        var $option = $('<option/>');
                        $option.text(operator.name);
                        $operators.append($option);
                    }

                }else{
                    $elem = $stepElems.eq(i);
                }

                var operator_name = $elem.find('.operator').val();
                var operator_fn;
                for ( var j = 0; j < operators.length; j ++){
                    if ( operator_name == operators[j].name ){
                        operator_fn = operators[j].fn;
                    }
                }

                var operand =  $elem.find('.operand').val();
                var property = $elem.find('.property').val();
                var predicate = function(x){
                    return operator_fn(x[property], operand);
                }

                var previousData = data.clone();
                var filterType = $elem.find('.addorsubtract').val()
                if ( filterType == 'removematching'){

                    var toRemove = data.array().filter(predicate);
                    for ( var j = 0; j < toRemove.length; j ++){
                        data.remove(toRemove[j]);
                    }
                }else if (filterType == 'reinclude'){
                    data.union(self.options.data.filter(predicate));

                }else if ( filterType == 'keepmatching'){
                    data= new DjSet(data.key, data.array().filter(predicate));
                }else if ( filterType == 'includeall'){
                    data = new DjSet(self.options.data_key, self.options.data);
                }else if ( filterType == 'removeall'){
                    data = new DjSet(self.options.data_key);
                }else{
                    // console.log('unknown filter type ' + filterType );
                }

            }

            for ( var i = self.steps.length; i < $stepElems.length ; i ++){
                $stepElems.get(i).remove();
            }
            self.resultData = data;
            self.updateTable();

        }

    }

    $.fn.djcategorize = function(options) {
        var opts = $.extend( {}, $.fn.djcategorize.defaults, options );
        return new Djcategorize($(this), opts);
    };

    $.fn.djcategorize.defaults = {

    };
})(jQuery);
<|endoftext|>


<commit_before>var mongoose = require('mongoose');

var Schema = mongoose.Schema;

var dogSchema = new Schema({
  name: String,
  breed: String,
  color: String,
  age: { type: Number, max: 50 },
  size: { type: String, enum: ["small", "medium", "large"] },
  location: String,
  image: String,
  reward: String,
  phoneNumber: String,
  description: String,
  lost: Boolean,
  createdOn: { type: Date, default: Date.now },
  isActive: { type: Boolean, default: true }
});

var Dog = mongoose.model("Dog", dogSchema);

module.exports = Dog;
<commit_msg>add enumerated neighborhoods to dog model<commit_after>var mongoose = require('mongoose');

var Schema = mongoose.Schema;

var dogSchema = new Schema({
  name: String,
  breed: String,
  color: String,
  age: { type: Number, max: 50 },
  size: { type: String, enum: ["small", "medium", "large"] },
  location: { type: String, enum: neighborhoods },
  image: String,
  reward: String,
  phoneNumber: String,
  description: String,
  lost: Boolean,
  createdOn: { type: Date, default: Date.now },
  isActive: { type: Boolean, default: true }
});

var neighborhoods = ["Bernal Heights", "The Castro", "Chinatown", "Cole Valley", "Deco Ghetto", "Fisherman's Wharf", "Golden Gate Park", "The Haight", "Hayes Valley", "Inner Richmond", "Inner Sunset", "The Marina", "The Mission", "Mission to Potrero", "Dolores and Valencia Corridor", "24th Street", "Nob Hill", "Noe Valley", "North Beach", "Outer Richmond", "Outer Sunset", "Pacific Heights", "Potrero Hill", "Russian Hill", "SoMa", "Tenderloin", "Union Square", "Western Addition"];

var Dog = mongoose.model("Dog", dogSchema);

module.exports = Dog;
<|endoftext|>


<commit_before>const mongoose = require('../lib/mongooseinit');
const ObjectId = mongoose.Types.ObjectId;
const CronJob = require('cron').CronJob;
const debug = require('debug')('tilloo:job');

const constants = require('../lib/constants');
const Run = require('./run');
const K8sJob = require('../lib/k8s/job');

const Job = new mongoose.Schema({
    name: { type: String, required: true },
    path: { type: String },
    args: [String],
    description: { type: String },
    schedule: {
        type: String, validate: function (v) {
            try {
                return String(v).length === 0 || new CronJob(v);
            }
            catch (e) {
                return false;
            }
        }
    },
    imageUri: { type: String, required: true },
    nodeSelector: { type: String },
    enabled: { type: Boolean, default: 'true' },
    createdAt: { type: Date, default: function () { return new Date(); } }, // eslint-disable-line brace-style
    updatedAt: { type: Date },
    lastRanAt: { type: Date },
    lastStatus: { type: String },
    mutex: { type: Boolean, default: true },
    timeout: { type: Number, default: 0 },
    deleted: { type: Boolean, default: false },
    failuresBeforeAlert: { type: Number, default: 1 }
});

Job.pre('save', function save(done) {
    if (!this.createdAt) {
        this.createdAt = new Date();
    }
    this.updatedAt = new Date();

    return done();
});

Job.methods.newRun = function newRun() {
    return new Run({
        jobId: this._id,
        name: this.name,
        path: this.path,
        args: this.args,
        //queueName: this.queueName,
        imageUri: this.imageUri,
        nodeSelector: this.nodeSelector,
        timeout: this.timeout
    });
};

Job.methods.triggerRun = async function triggerRun() {
    const self = this;
    const run = self.newRun();
    try {
        await run.save();
        debug('sending start message for %s :: %s.', self.name, self._id);

        const k8sJob = new K8sJob(self._id, run._id, self.name, self.imageUri, self.path, self.args, self.nodeSelector, self.timeout);

        k8sJob.start();

        self.lastRanAt = new Date();
        await self.save();
    }
    catch (err) {
        debug('unable to save run for %s.', self.name);
        console.error(err);
        throw err;
    }
};

Job.methods.startCron = function startCron() {
    const self = this;

    this.__cron = new CronJob(this.schedule, async function () {
        debug('Cron trigger', self);
        if (self.mutex) {
            try {
                const run = await Run.findOne({ jobId: new ObjectId(self._id) }, null, { sort: { createdAt: -1 } }).exec();
                if (run && (run.status === constants.JOBSTATUS.BUSY || run.status === constants.JOBSTATUS.IDLE)) {
                    debug('Mutex not scheduling jobId: %s, runId: %s already running', self._id, run._id);
                }
                else {
                    await self.triggerRun();
                }
            }
            catch (err) {
                console.error(err);
                debug('Unable to check for running job not scheduling jobId: %s', self._id);
            }
        }
        else {
            await self.triggerRun();
        }
    });

    debug('starting cron %s for %s.', this.schedule, this.name);
    this.__cron.start();
};

Job.methods.stopCron = function stopCron() {
    if (this.__cron) {
        debug('stopping cron %s for %s.', this.schedule, this.name);
        this.__cron.stop();
        delete this.__cron;
    }
};

Job.statics.loadAllJobs = async function loadAllJobs() {
    debug('loading all jobs');
    try {
        return await Model.find({ deleted: false, enabled: true });
    }
    catch (err) {
        console.error('Error loading alljobs', err);
        throw err;
    }
};

Job.statics.findAllJobs = async function findAllJobs() {
    console.info('findAllJobs');
    try {
        return await Model.find({ deleted: false }, null, { sort: { name: 1 } });
    }
    catch (err) {
        console.error('Error finding all jobs', err);
        throw err;
    }

};

Job.statics.findByJobId = async function findByJobId(jobId) {
    try {
        return await Model.findById(new ObjectId(jobId));
    }
    catch (err) {
        console.error('Error finding job', err);
        throw err;
    }
};

const Model = mongoose.model('job', Job);
module.exports = Model;<commit_msg>Remove console.info<commit_after>const mongoose = require('../lib/mongooseinit');
const ObjectId = mongoose.Types.ObjectId;
const CronJob = require('cron').CronJob;
const debug = require('debug')('tilloo:job');

const constants = require('../lib/constants');
const Run = require('./run');
const K8sJob = require('../lib/k8s/job');

const Job = new mongoose.Schema({
    name: { type: String, required: true },
    path: { type: String },
    args: [String],
    description: { type: String },
    schedule: {
        type: String, validate: function (v) {
            try {
                return String(v).length === 0 || new CronJob(v);
            }
            catch (e) {
                return false;
            }
        }
    },
    imageUri: { type: String, required: true },
    nodeSelector: { type: String },
    enabled: { type: Boolean, default: 'true' },
    createdAt: { type: Date, default: function () { return new Date(); } }, // eslint-disable-line brace-style
    updatedAt: { type: Date },
    lastRanAt: { type: Date },
    lastStatus: { type: String },
    mutex: { type: Boolean, default: true },
    timeout: { type: Number, default: 0 },
    deleted: { type: Boolean, default: false },
    failuresBeforeAlert: { type: Number, default: 1 }
});

Job.pre('save', function save(done) {
    if (!this.createdAt) {
        this.createdAt = new Date();
    }
    this.updatedAt = new Date();

    return done();
});

Job.methods.newRun = function newRun() {
    return new Run({
        jobId: this._id,
        name: this.name,
        path: this.path,
        args: this.args,
        //queueName: this.queueName,
        imageUri: this.imageUri,
        nodeSelector: this.nodeSelector,
        timeout: this.timeout
    });
};

Job.methods.triggerRun = async function triggerRun() {
    const self = this;
    const run = self.newRun();
    try {
        await run.save();
        debug('sending start message for %s :: %s.', self.name, self._id);

        const k8sJob = new K8sJob(self._id, run._id, self.name, self.imageUri, self.path, self.args, self.nodeSelector, self.timeout);

        k8sJob.start();

        self.lastRanAt = new Date();
        await self.save();
    }
    catch (err) {
        debug('unable to save run for %s.', self.name);
        console.error(err);
        throw err;
    }
};

Job.methods.startCron = function startCron() {
    const self = this;

    this.__cron = new CronJob(this.schedule, async function () {
        debug('Cron trigger', self);
        if (self.mutex) {
            try {
                const run = await Run.findOne({ jobId: new ObjectId(self._id) }, null, { sort: { createdAt: -1 } }).exec();
                if (run && (run.status === constants.JOBSTATUS.BUSY || run.status === constants.JOBSTATUS.IDLE)) {
                    debug('Mutex not scheduling jobId: %s, runId: %s already running', self._id, run._id);
                }
                else {
                    await self.triggerRun();
                }
            }
            catch (err) {
                console.error(err);
                debug('Unable to check for running job not scheduling jobId: %s', self._id);
            }
        }
        else {
            await self.triggerRun();
        }
    });

    debug('starting cron %s for %s.', this.schedule, this.name);
    this.__cron.start();
};

Job.methods.stopCron = function stopCron() {
    if (this.__cron) {
        debug('stopping cron %s for %s.', this.schedule, this.name);
        this.__cron.stop();
        delete this.__cron;
    }
};

Job.statics.loadAllJobs = async function loadAllJobs() {
    debug('loading all jobs');
    try {
        return await Model.find({ deleted: false, enabled: true });
    }
    catch (err) {
        console.error('Error loading alljobs', err);
        throw err;
    }
};

Job.statics.findAllJobs = async function findAllJobs() {
    try {
        return await Model.find({ deleted: false }, null, { sort: { name: 1 } });
    }
    catch (err) {
        console.error('Error finding all jobs', err);
        throw err;
    }

};

Job.statics.findByJobId = async function findByJobId(jobId) {
    try {
        return await Model.findById(new ObjectId(jobId));
    }
    catch (err) {
        console.error('Error finding job', err);
        throw err;
    }
};

const Model = mongoose.model('job', Job);
module.exports = Model;<|endoftext|>


<commit_before>/*global FormplayerFrontend, Formplayer */

/**
 * Backbone model for listing and selecting CommCare menus (modules, forms, and cases)
 */

FormplayerFrontend.module("Menus", function (Menus, FormplayerFrontend, Backbone, Marionette, $) {

    Menus.API = {

        queryFormplayer: function (params, route) {
            var user = FormplayerFrontend.request('currentUser'),
                lastRecordedLocation = FormplayerFrontend.request('lastRecordedLocation'),
                timezoneOffsetMillis = (new Date()).getTimezoneOffset() * 60 * 1000 * -1,
                formplayerUrl = user.formplayer_url,
                displayOptions = user.displayOptions || {},
                defer = $.Deferred(),
                options,
                menus;

            $.when(FormplayerFrontend.request("appselect:apps")).done(function (appCollection) {
                if (!params.preview) {
                    // Make sure the user has access to the app
                    if (!appCollection.find(function (app) {
                        return app.id === params.appId || app.get('copy_of') === params.copyOf;
                    })) {
                        FormplayerFrontend.trigger(
                            'showError',
                            gettext('Permission Denied')
                        );
                        FormplayerFrontend.trigger('navigateHome');
                        defer.reject();
                    }
                }

                options = {
                    success: function (parsedMenus, response) {
                        if (response.status === 'retry') {
                            FormplayerFrontend.trigger('retry', response, function () {
                                var newOptionsData = JSON.stringify($.extend(true, { mustRestore: true }, JSON.parse(options.data)));
                                menus.fetch($.extend(true, {}, options, { data: newOptionsData }));
                            }, gettext('Waiting for server progress'));
                        } else if (response.hasOwnProperty('exception')) {
                            FormplayerFrontend.trigger('clearProgress');
                            FormplayerFrontend.trigger(
                                'showError',
                                response.exception || FormplayerFrontend.Constants.GENERIC_ERROR,
                                response.type === 'html'
                            );
                            FormplayerFrontend.trigger('navigation:back');
                        } else {
                            FormplayerFrontend.trigger('clearProgress');
                            defer.resolve(parsedMenus);
                            // Only configure menu debugger if we didn't get a form entry response
                            if (!(response.session_id)) {
                                FormplayerFrontend.trigger('configureDebugger');
                            }
                        }
                    },
                    error: function (_, response) {
                        if (response.status === 423) {
                            FormplayerFrontend.trigger(
                                'showError',
                                Formplayer.Errors.LOCK_TIMEOUT_ERROR
                            );
                        } else if (response.status === 401) {
                            FormplayerFrontend.trigger(
                                'showError',
                                Formplayer.Utils.reloginErrorHtml(),
                                true
                            );
                        } else {
                            FormplayerFrontend.trigger(
                                'showError',
                                gettext('Unable to connect to form playing service. ' +
                                        'Please report an issue if you continue to see this message.')
                            );
                        }
                        defer.reject();
                    },
                };
                options.data = JSON.stringify({
                    "username": user.username,
                    "restoreAs": user.restoreAs,
                    "domain": user.domain,
                    "app_id": params.appId,
                    "locale": displayOptions.language,
                    "selections": params.steps,
                    "offset": params.page * 10,
                    "search_text": params.search,
                    "menu_session_id": params.sessionId,
                    "query_dictionary": params.queryDict,
                    "installReference": params.installReference,
                    "oneQuestionPerScreen": displayOptions.oneQuestionPerScreen,
                    "isPersistent": params.isPersistent,
                    "useLiveQuery": user.useLiveQuery,
                    "sortIndex": params.sortIndex,
                    "preview": params.preview,
                    "geo_location": lastRecordedLocation,
                    "tz_offset_millis": timezoneOffsetMillis,
                });
                options.url = formplayerUrl + '/' + route;

                menus = new FormplayerFrontend.Menus.Collections.MenuSelect();

                if (Object.freeze) {
                    Object.freeze(options);
                }
                menus.fetch($.extend(true, {}, options));
            });

            return defer.promise();
        },
    };

    FormplayerFrontend.reqres.setHandler("app:select:menus", function (options) {
        var isInitial = options.isInitial;
        return Menus.API.queryFormplayer(options, isInitial ? 'navigate_menu_start' : 'navigate_menu');
    });

    FormplayerFrontend.reqres.setHandler("entity:get:details", function (options, isPersistent) {
        options.isPersistent = isPersistent;
        options.preview = FormplayerFrontend.currentUser.displayOptions.singleAppMode;
        return Menus.API.queryFormplayer(options, 'get_details');
    });
});

<commit_msg>Navigate home if we are likely to be in an error loop<commit_after>/*global FormplayerFrontend, Formplayer */

/**
 * Backbone model for listing and selecting CommCare menus (modules, forms, and cases)
 */

FormplayerFrontend.module("Menus", function (Menus, FormplayerFrontend, Backbone, Marionette, $) {

    Menus.API = {

        queryFormplayer: function (params, route) {
            var user = FormplayerFrontend.request('currentUser'),
                lastRecordedLocation = FormplayerFrontend.request('lastRecordedLocation'),
                timezoneOffsetMillis = (new Date()).getTimezoneOffset() * 60 * 1000 * -1,
                formplayerUrl = user.formplayer_url,
                displayOptions = user.displayOptions || {},
                defer = $.Deferred(),
                options,
                menus;

            $.when(FormplayerFrontend.request("appselect:apps")).done(function (appCollection) {
                if (!params.preview) {
                    // Make sure the user has access to the app
                    if (!appCollection.find(function (app) {
                        return app.id === params.appId || app.get('copy_of') === params.copyOf;
                    })) {
                        FormplayerFrontend.trigger(
                            'showError',
                            gettext('Permission Denied')
                        );
                        FormplayerFrontend.trigger('navigateHome');
                        defer.reject();
                    }
                }

                options = {
                    success: function (parsedMenus, response) {
                        if (response.status === 'retry') {
                            FormplayerFrontend.trigger('retry', response, function () {
                                var newOptionsData = JSON.stringify($.extend(true, { mustRestore: true }, JSON.parse(options.data)));
                                menus.fetch($.extend(true, {}, options, { data: newOptionsData }));
                            }, gettext('Waiting for server progress'));
                        } else if (response.hasOwnProperty('exception')) {
                            FormplayerFrontend.trigger('clearProgress');
                            FormplayerFrontend.trigger(
                                'showError',
                                response.exception || FormplayerFrontend.Constants.GENERIC_ERROR,
                                response.type === 'html'
                            );

                            var currentUrl = FormplayerFrontend.getCurrentRoute();
                            if (FormplayerFrontend.lastError === currentUrl) {
                                FormplayerFrontend.lastError = null;
                                FormplayerFrontend.trigger('navigateHome');
                            } else {
                                FormplayerFrontend.lastError = currentUrl;
                                FormplayerFrontend.trigger('navigation:back');
                            }

                        } else {
                            FormplayerFrontend.trigger('clearProgress');
                            defer.resolve(parsedMenus);
                            // Only configure menu debugger if we didn't get a form entry response
                            if (!(response.session_id)) {
                                FormplayerFrontend.trigger('configureDebugger');
                            }
                        }
                    },
                    error: function (_, response) {
                        if (response.status === 423) {
                            FormplayerFrontend.trigger(
                                'showError',
                                Formplayer.Errors.LOCK_TIMEOUT_ERROR
                            );
                        } else if (response.status === 401) {
                            FormplayerFrontend.trigger(
                                'showError',
                                Formplayer.Utils.reloginErrorHtml(),
                                true
                            );
                        } else {
                            FormplayerFrontend.trigger(
                                'showError',
                                gettext('Unable to connect to form playing service. ' +
                                        'Please report an issue if you continue to see this message.')
                            );
                        }
                        defer.reject();
                    },
                };
                options.data = JSON.stringify({
                    "username": user.username,
                    "restoreAs": user.restoreAs,
                    "domain": user.domain,
                    "app_id": params.appId,
                    "locale": displayOptions.language,
                    "selections": params.steps,
                    "offset": params.page * 10,
                    "search_text": params.search,
                    "menu_session_id": params.sessionId,
                    "query_dictionary": params.queryDict,
                    "installReference": params.installReference,
                    "oneQuestionPerScreen": displayOptions.oneQuestionPerScreen,
                    "isPersistent": params.isPersistent,
                    "useLiveQuery": user.useLiveQuery,
                    "sortIndex": params.sortIndex,
                    "preview": params.preview,
                    "geo_location": lastRecordedLocation,
                    "tz_offset_millis": timezoneOffsetMillis,
                });
                options.url = formplayerUrl + '/' + route;

                menus = new FormplayerFrontend.Menus.Collections.MenuSelect();

                if (Object.freeze) {
                    Object.freeze(options);
                }
                menus.fetch($.extend(true, {}, options));
            });

            return defer.promise();
        },
    };

    FormplayerFrontend.reqres.setHandler("app:select:menus", function (options) {
        var isInitial = options.isInitial;
        return Menus.API.queryFormplayer(options, isInitial ? 'navigate_menu_start' : 'navigate_menu');
    });

    FormplayerFrontend.reqres.setHandler("entity:get:details", function (options, isPersistent) {
        options.isPersistent = isPersistent;
        options.preview = FormplayerFrontend.currentUser.displayOptions.singleAppMode;
        return Menus.API.queryFormplayer(options, 'get_details');
    });
});

<|endoftext|>


<commit_before>/*global FormplayerFrontend, Util */

/**
 * Backbone model for listing and selecting CommCare menus (modules, forms, and cases)
 */

FormplayerFrontend.module("Menus", function (Menus, FormplayerFrontend, Backbone, Marionette, $) {

    Menus.API = {

        queryFormplayer: function (params, route) {

            var user = FormplayerFrontend.request('currentUser'),
                formplayerUrl = user.formplayer_url,
                displayOptions = user.displayOptions || {},
                defer = $.Deferred(),
                options,
                menus;
            options = {
                success: function (parsedMenus, response) {
                    if (response.status === 'retry') {
                        FormplayerFrontend.trigger('retry', response, function() {
                            var newOptionsData = JSON.stringify($.extend(true, { mustRestore: true }, JSON.parse(options.data)));
                            menus.fetch($.extend(true, {}, options, { data: newOptionsData }));
                        }, gettext('Waiting for server progress'));
                    } else if (response.hasOwnProperty('exception')){
                        FormplayerFrontend.trigger(
                            'showError',
                            response.exception || FormplayerFrontend.Constants.GENERIC_ERROR,
                            response.type === 'html'
                        );
                        FormplayerFrontend.trigger('navigation:back');
                    } else {
                        FormplayerFrontend.trigger('clearProgress');
                        defer.resolve(parsedMenus);
                        if (response.menuSessionId) {
                            FormplayerFrontend.trigger('configureDebugger', response.menuSessionId);
                        }
                    }
                },
                error: function () {
                    FormplayerFrontend.trigger(
                        'showError',
                        gettext('Unable to connect to form playing service. ' +
                                'Please report an issue if you continue to see this message.')
                    );
                    defer.reject();
                },
            };

            options.data = JSON.stringify({
                "username": user.username,
                "restoreAs": user.restoreAs,
                "domain": user.domain,
                "app_id": params.appId,
                "locale": displayOptions.language,
                "selections": params.steps,
                "offset": params.page * 10,
                "search_text": params.search,
                "menu_session_id": params.sessionId,
                "query_dictionary": params.queryDict,
                "previewCommand": params.previewCommand,
                "installReference": params.installReference,
                "oneQuestionPerScreen": displayOptions.oneQuestionPerScreen,
                "isPersistent": params.isPersistent,
            });
            options.url = formplayerUrl + '/' + route;

            menus = new FormplayerFrontend.Menus.Collections.MenuSelect();

            if (Object.freeze) {
                Object.freeze(options);
            }
            menus.fetch($.extend(true, {}, options));
            return defer.promise();
        },
    };

    FormplayerFrontend.reqres.setHandler("app:select:menus", function (options) {
        return Menus.API.queryFormplayer(options, 'navigate_menu');
    });

    FormplayerFrontend.reqres.setHandler("entity:get:details", function (options, isPersistent) {
        options.isPersistent = isPersistent;
        return Menus.API.queryFormplayer(options, 'get_details');
    });
});

<commit_msg>add useLiveQuery param to normal request route<commit_after>/*global FormplayerFrontend, Util */

/**
 * Backbone model for listing and selecting CommCare menus (modules, forms, and cases)
 */

FormplayerFrontend.module("Menus", function (Menus, FormplayerFrontend, Backbone, Marionette, $) {

    Menus.API = {

        queryFormplayer: function (params, route) {

            var user = FormplayerFrontend.request('currentUser'),
                formplayerUrl = user.formplayer_url,
                displayOptions = user.displayOptions || {},
                defer = $.Deferred(),
                options,
                menus;
            options = {
                success: function (parsedMenus, response) {
                    if (response.status === 'retry') {
                        FormplayerFrontend.trigger('retry', response, function() {
                            var newOptionsData = JSON.stringify($.extend(true, { mustRestore: true }, JSON.parse(options.data)));
                            menus.fetch($.extend(true, {}, options, { data: newOptionsData }));
                        }, gettext('Waiting for server progress'));
                    } else if (response.hasOwnProperty('exception')){
                        FormplayerFrontend.trigger(
                            'showError',
                            response.exception || FormplayerFrontend.Constants.GENERIC_ERROR,
                            response.type === 'html'
                        );
                        FormplayerFrontend.trigger('navigation:back');
                    } else {
                        FormplayerFrontend.trigger('clearProgress');
                        defer.resolve(parsedMenus);
                        if (response.menuSessionId) {
                            FormplayerFrontend.trigger('configureDebugger', response.menuSessionId);
                        }
                    }
                },
                error: function () {
                    FormplayerFrontend.trigger(
                        'showError',
                        gettext('Unable to connect to form playing service. ' +
                                'Please report an issue if you continue to see this message.')
                    );
                    defer.reject();
                },
            };

            options.data = JSON.stringify({
                "username": user.username,
                "restoreAs": user.restoreAs,
                "domain": user.domain,
                "app_id": params.appId,
                "locale": displayOptions.language,
                "selections": params.steps,
                "offset": params.page * 10,
                "search_text": params.search,
                "menu_session_id": params.sessionId,
                "query_dictionary": params.queryDict,
                "previewCommand": params.previewCommand,
                "installReference": params.installReference,
                "oneQuestionPerScreen": displayOptions.oneQuestionPerScreen,
                "isPersistent": params.isPersistent,
                "useLiveQuery": user.useLiveQuery,
            });
            options.url = formplayerUrl + '/' + route;

            menus = new FormplayerFrontend.Menus.Collections.MenuSelect();

            if (Object.freeze) {
                Object.freeze(options);
            }
            menus.fetch($.extend(true, {}, options));
            return defer.promise();
        },
    };

    FormplayerFrontend.reqres.setHandler("app:select:menus", function (options) {
        return Menus.API.queryFormplayer(options, 'navigate_menu');
    });

    FormplayerFrontend.reqres.setHandler("entity:get:details", function (options, isPersistent) {
        options.isPersistent = isPersistent;
        return Menus.API.queryFormplayer(options, 'get_details');
    });
});

<|endoftext|>