<commit_before>var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var kue = require('kue');
var Job = require('kue/lib/queue/job');
var reds = require('reds');
var filesize = require('filesize');
var async = require('async');
var moment = require('moment');

module.exports = function(log, conf) {

    var processor = require('../lib/job_processor')(log);
    log.debug('Redis Configuration', conf.get('redis'));
    var jobs = kue.createQueue({
        redis: conf.get('redis'),
        disableSearch: false
    });

    var search;

    function getSearch() {
        if (search) return search;
        reds.createClient = require('kue/lib/redis').createClient;
        return search = reds.createSearch(jobs.client.getKey('search'));
    }

    function getProjectDetails(project) {
        // TODO: Switch to something else or keep md5?
        project.hash = crypto.createHash('md5').update(JSON.stringify(project)).digest('hex');
        // storage directory for projects
        project.storageDir = conf.get('storage');
        // path where tar.gz will be saved
        project.bundlePath = path.join(project.storageDir, project.name + '-' + project.hash + '.tar.gz');
        project.productionBundlePath = path.join(project.storageDir, project.name + '-production-' + project.hash + '.tar.gz');
        // temp storage directory where things install to
        project.tempPath = path.join(project.storageDir, project.hash);
        return project;
    }

    processor.setup(jobs);

    var freighter = require('../lib/freighter')(log, conf, jobs);
    var tracker = require('../lib/tracker')(log, conf, jobs);
    var freightAuth = require('../lib/auth')(log, conf);
    var Routes = {};

    Routes.usage = function(req, res, next) {
        var memory = process.memoryUsage();
        var storage = conf.get('storage');

        var data = {
            title: 'Granary Server',
            process: {
                heap: filesize(memory.heapUsed)
            }
        };

        fs.readdir(storage, function(err, files) {
            if (err) {
                log.error(err);
                throw err;
            }

            async.map(files,
                function(file, complete) {
                    fs.stat(path.join(storage, file), function(err, stat) {
                        stat.size = filesize(stat.size);
                        stat.download = '/storage/' + file;
                        stat.ctime = moment(stat.ctime).format('MMMM Do YYYY, h:mm:ss a');
                        if (file.indexOf('tar.gz') > -1) {
                            complete(err, {
                                name: file,
                                details: stat
                            });
                        } else {
                            complete(err, {});
                        }
                    });
                },
                function(err, results) {
                    if (err) {
                        log.error('Failed to get statistics on all bundle files');
                        throw err;
                    }

                    var bundles = results.filter(function(file) {
                        return file.hasOwnProperty('name');
                    });

                    bundles.sort(function(a, b) {
                        return b.details.mtime.getTime() - a.details.mtime.getTime();
                    });

                    data.files = bundles;
                    req.data = data;
                    next();
                });
        });
    }

    Routes.check = function(req, res) {
        if (!req.body && !req.body.project && !req.body.project.name) {
            return res.sendStatus(404);
        }

        var project = req.body.project;
        var extra = req.body.extra;

        project = getProjectDetails(project);

        log.debug('Incoming Project', project, extra);

        // check if Granary file exists
        fs.exists(project.bundlePath, function(bundleExists) {
            var response = {
                creating: false,
                available: false,
                authenticated: freightAuth.checkPassword(extra.password)
            };

            if (bundleExists) {
                response.available = true;
                response.hash = project.hash;
            }

            if (freightAuth.checkPassword(extra.password) && extra.create === 'true') {
                // TODO: delete stale jobs, try again to cache, fail if tries too many times.
                // TODO: restart stale job if timeout > x.
                getSearch().query(project.hash).end(function(err, ids) {
                    if (ids.length == 0) {
                        if (!bundleExists || extra.force === 'true') {
                            try {
                                fs.unlinkSync(project.bundlePath);
                                fs.unlinkSync(project.productionBundlePath);
                            } catch (ex) { /* doesn't matter if it fails */ }
                            response.creating = true;
                            response.hash = project.hash;
                            freighter.create(project, extra);
                            return res.json(response);
                        } else {
                            return res.json(response);
                        }
                    } else if (ids.length == 1) {
                        Job.get(ids[0], function(err, job) {
                            if (err) {
                                return res.json(err);
                            }
                            response.creating = true;
                            response.hash = project.hash;
                            response.progress = job._progress;
                            response.state = job._state;
                            response.started_at = job.started_at;
                            response.duration = job.duration;
                            return res.json(response);
                        });
                    } else {
                        return res.json(response);
                    }
                });
            } else {
                return res.json(response);
            }
        });
    };

    Routes.download = function(req, res) {
        log.debug('Download request', req.body);
        if (req.body.hash) {
            var hashFile = path.join(conf.get('storage'), req.body.name + '-' + req.body.hash + '.tar.gz');
            if (req.body.options && req.body.options.production === 'true') {
                hashFile = path.join(conf.get('storage'), req.body.name + '-production-' + req.body.hash + '.tar.gz');
            }

            fs.exists(hashFile, function(exists) {
                if (exists) {
                    log.debug('Download bundle:', hashFile);
                    return res.sendFile(hashFile);
                } else {
                    log.debug('Bundle does not exist:', hashFile);
                    return res.sendStatus(404);
                }
            });
        } else {
            log.debug('Hash not set.');
            return res.sendStatus(404);
        }

    };

    Routes.track = function(req, res) {
        if (req.body && req.body.repository && req.body.password && req.body.branch) {
            log.debug('Tracking request:', req.body);

            if (!freightAuth.checkPassword(req.body.password)) {
                log.debug('Password does not match');
                return res.sendStatus(403);
            }

            var extraOptions = {
                trackDirectory: req.body.trackDirectory
            };

            tracker.create(req.body.repository, req.body.branch, extraOptions, function(err) {
                if (err) {
                    // fetch $REPO, run freight on it
                    // keep fetching the master branch, run freight on it
                    log.debug('Cannot track repository: ', err);
                    return res.sendStatus(500);
                } else {
                    return res.sendStatus(200);
                }
            });

        } else {
            log.debug('Repository or password not set');
            return res.sendStatus(500);
        }

    };

    return Routes;
};
<commit_msg>removing password check this is done at the middleware level<commit_after>var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var kue = require('kue');
var Job = require('kue/lib/queue/job');
var reds = require('reds');
var filesize = require('filesize');
var async = require('async');
var moment = require('moment');

module.exports = function(log, conf) {

    var processor = require('../lib/job_processor')(log);
    log.debug('Redis Configuration', conf.get('redis'));
    var jobs = kue.createQueue({
        redis: conf.get('redis'),
        disableSearch: false
    });

    var search;

    function getSearch() {
        if (search) return search;
        reds.createClient = require('kue/lib/redis').createClient;
        return search = reds.createSearch(jobs.client.getKey('search'));
    }

    function getProjectDetails(project) {
        // TODO: Switch to something else or keep md5?
        project.hash = crypto.createHash('md5').update(JSON.stringify(project)).digest('hex');
        // storage directory for projects
        project.storageDir = conf.get('storage');
        // path where tar.gz will be saved
        project.bundlePath = path.join(project.storageDir, project.name + '-' + project.hash + '.tar.gz');
        project.productionBundlePath = path.join(project.storageDir, project.name + '-production-' + project.hash + '.tar.gz');
        // temp storage directory where things install to
        project.tempPath = path.join(project.storageDir, project.hash);
        return project;
    }

    processor.setup(jobs);

    var freighter = require('../lib/freighter')(log, conf, jobs);
    var tracker = require('../lib/tracker')(log, conf, jobs);
    var freightAuth = require('../lib/auth')(log, conf);
    var Routes = {};

    Routes.usage = function(req, res, next) {
        var memory = process.memoryUsage();
        var storage = conf.get('storage');

        var data = {
            title: 'Granary Server',
            process: {
                heap: filesize(memory.heapUsed)
            }
        };

        fs.readdir(storage, function(err, files) {
            if (err) {
                log.error(err);
                throw err;
            }

            async.map(files,
                function(file, complete) {
                    fs.stat(path.join(storage, file), function(err, stat) {
                        stat.size = filesize(stat.size);
                        stat.download = '/storage/' + file;
                        stat.ctime = moment(stat.ctime).format('MMMM Do YYYY, h:mm:ss a');
                        if (file.indexOf('tar.gz') > -1) {
                            complete(err, {
                                name: file,
                                details: stat
                            });
                        } else {
                            complete(err, {});
                        }
                    });
                },
                function(err, results) {
                    if (err) {
                        log.error('Failed to get statistics on all bundle files');
                        throw err;
                    }

                    var bundles = results.filter(function(file) {
                        return file.hasOwnProperty('name');
                    });

                    bundles.sort(function(a, b) {
                        return b.details.mtime.getTime() - a.details.mtime.getTime();
                    });

                    data.files = bundles;
                    req.data = data;
                    next();
                });
        });
    }

    Routes.check = function(req, res) {
        if (!req.body && !req.body.project && !req.body.project.name) {
            return res.sendStatus(404);
        }

        var project = req.body.project;
        var extra = req.body.extra;

        project = getProjectDetails(project);

        log.debug('Incoming Project', project, extra);

        // check if Granary file exists
        fs.exists(project.bundlePath, function(bundleExists) {
            var response = {
                creating: false,
                available: false,
                authenticated: freightAuth.checkPassword(extra.password)
            };

            if (bundleExists) {
                response.available = true;
                response.hash = project.hash;
            }

            if (freightAuth.checkPassword(extra.password) && extra.create === 'true') {
                // TODO: delete stale jobs, try again to cache, fail if tries too many times.
                // TODO: restart stale job if timeout > x.
                getSearch().query(project.hash).end(function(err, ids) {
                    if (ids.length == 0) {
                        if (!bundleExists || extra.force === 'true') {
                            try {
                                fs.unlinkSync(project.bundlePath);
                                fs.unlinkSync(project.productionBundlePath);
                            } catch (ex) { /* doesn't matter if it fails */ }
                            response.creating = true;
                            response.hash = project.hash;
                            freighter.create(project, extra);
                            return res.json(response);
                        } else {
                            return res.json(response);
                        }
                    } else if (ids.length == 1) {
                        Job.get(ids[0], function(err, job) {
                            if (err) {
                                return res.json(err);
                            }
                            response.creating = true;
                            response.hash = project.hash;
                            response.progress = job._progress;
                            response.state = job._state;
                            response.started_at = job.started_at;
                            response.duration = job.duration;
                            return res.json(response);
                        });
                    } else {
                        return res.json(response);
                    }
                });
            } else {
                return res.json(response);
            }
        });
    };

    Routes.download = function(req, res) {
        log.debug('Download request', req.body);
        if (req.body.hash) {
            var hashFile = path.join(conf.get('storage'), req.body.name + '-' + req.body.hash + '.tar.gz');
            if (req.body.options && req.body.options.production === 'true') {
                hashFile = path.join(conf.get('storage'), req.body.name + '-production-' + req.body.hash + '.tar.gz');
            }

            fs.exists(hashFile, function(exists) {
                if (exists) {
                    log.debug('Download bundle:', hashFile);
                    return res.sendFile(hashFile);
                } else {
                    log.debug('Bundle does not exist:', hashFile);
                    return res.sendStatus(404);
                }
            });
        } else {
            log.debug('Hash not set.');
            return res.sendStatus(404);
        }

    };

    Routes.track = function(req, res) {
        if (req.body && req.body.repository && req.body.password && req.body.branch) {
            log.debug('Tracking request:', req.body);

            var extraOptions = {
                trackDirectory: req.body.trackDirectory
            };

            tracker.create(req.body.repository, req.body.branch, extraOptions, function(err) {
                if (err) {
                    // fetch $REPO, run freight on it
                    // keep fetching the master branch, run freight on it
                    log.debug('Cannot track repository: ', err);
                    return res.sendStatus(500);
                } else {
                    return res.sendStatus(200);
                }
            });

        } else {
            log.debug('Repository or password not set');
            return res.sendStatus(500);
        }

    };

    return Routes;
};
<|endoftext|>


<commit_before>var crypto = require("crypto");
var exec = require('child_process').exec;
var fs = require('fs');

helpers = {

  boxFromParam: function (param, res) {
    var box = null
    if(param == null) {
      res.writeHead(500, { 'Content-Type': 'application/json' });
      res.end('{"error": "No box param given. Should be in format: '+
        '?box=253723.176600653,6660500.4670516,267723.176600653,6646500.4670516"}');
      return;
    } else {
      param = param.split("|")[0];
      box = param.split(',');
    }
    if (Math.abs(box[0]) > Math.abs(box[2])) {
      p = box[2]
      box[2] = box[0]
      box[0] = p
      console.log("Swapped box 0 <-> 2")
    }
    if (box[1] < box[3]) {
      p = box[3]
      box[3] = box[1]
      box[1] = p
      console.log("Swapped box 1 <-> 3")
    }
    return box;
  },

  outsizeFromParam: function(param, res) {
    var outsize = null;
    if(param == null) {
      res.writeHead(500, { 'Content-Type': 'application/json' });
      res.end('{"error": "No outsize param given. ' +
        'Should be in format: ?outsize=1000,1000  (x,y)"}');
      return false;
    } else {
      outsize = param.split(",");
      if(outsize.length == 1) {
        outsize = [outsize,outsize];
      }
    }
    return outsize;
  },
  numericParams: function(params, res) {
  	var non_number = false;
  	params.forEach(function(i) {
  	      if(!(typeof Number(i) === 'number' &&
              isFinite(Number(i)))) {
  	        non_number = i;
  	        return;
  	      }
  	    }
  	  );
    if(non_number) {
      res.writeHead(500, { 'Content-Type': 'application/json' });
      res.end('{"error": "box or outsize param contains non-numerics"}');
    }
    return !non_number;
  },
  fileHash: function(filename, extension) {
    return crypto.createHash('sha1').update(filename).digest('hex')+"."+extension;
  },
  isLoggedIn: function(session) {
    if (!session.oauth_access_token) {
      return false;
    }
    return true;
  },
  generate: function(filename, box, callback) {
    var output = "";
    var generator = exec("node "+__dirname+"/../generate.js "+filename+" \""+box.join(',')+"\"", function(err, stdout, stderr) {
      if (err) {
        output += err;
      };
      if (stdout) {
        console.log("generator: ", stdout.toString())
        output += stdout.toString();
      };
      if (stderr) {
        console.log("generator: ", stderr.toString())
        output += stderr.toString();
      }
    });
    generator.on('exit', function(code, signal) {
      if (code != 0) {
        callback("Generator failed with code "+code+"\n <!-- "+output+" -->", null);
      } else {
        callback(null, filename);
      }
    });
  }
};
module.exports = helpers;
<commit_msg>Crisis tweak to get this to work before launch<commit_after>var crypto = require("crypto");
var exec = require('child_process').exec;
var fs = require('fs');

helpers = {

  boxFromParam: function (param, res) {
    var box = null
    if(param == null) {
      res.writeHead(500, { 'Content-Type': 'application/json' });
      res.end('{"error": "No box param given. Should be in format: '+
        '?box=253723.176600653,6660500.4670516,267723.176600653,6646500.4670516"}');
      return;
    } else {
      param = param.split("|")[0];
      box = param.split(',');
    }
    if (box[0] > box[2] && !(box[0]<0 && box[1]<0)) {
      p = box[2]
      box[2] = box[0]
      box[0] = p
      console.log("Swapped box 0 <-> 2")
    }
    if (box[1] < box[3]) {
      p = box[3]
      box[3] = box[1]
      box[1] = p
      console.log("Swapped box 1 <-> 3")
    }
    return box;
  },

  outsizeFromParam: function(param, res) {
    var outsize = null;
    if(param == null) {
      res.writeHead(500, { 'Content-Type': 'application/json' });
      res.end('{"error": "No outsize param given. ' +
        'Should be in format: ?outsize=1000,1000  (x,y)"}');
      return false;
    } else {
      outsize = param.split(",");
      if(outsize.length == 1) {
        outsize = [outsize,outsize];
      }
    }
    return outsize;
  },
  numericParams: function(params, res) {
  	var non_number = false;
  	params.forEach(function(i) {
  	      if(!(typeof Number(i) === 'number' &&
              isFinite(Number(i)))) {
  	        non_number = i;
  	        return;
  	      }
  	    }
  	  );
    if(non_number) {
      res.writeHead(500, { 'Content-Type': 'application/json' });
      res.end('{"error": "box or outsize param contains non-numerics"}');
    }
    return !non_number;
  },
  fileHash: function(filename, extension) {
    return crypto.createHash('sha1').update(filename).digest('hex')+"."+extension;
  },
  isLoggedIn: function(session) {
    if (!session.oauth_access_token) {
      return false;
    }
    return true;
  },
  generate: function(filename, box, callback) {
    var output = "";
    var generator = exec("node "+__dirname+"/../generate.js "+filename+" \""+box.join(',')+"\"", function(err, stdout, stderr) {
      if (err) {
        output += err;
      };
      if (stdout) {
        console.log("generator: ", stdout.toString())
        output += stdout.toString();
      };
      if (stderr) {
        console.log("generator: ", stderr.toString())
        output += stderr.toString();
      }
    });
    generator.on('exit', function(code, signal) {
      if (code != 0) {
        callback("Generator failed with code "+code+"\n <!-- "+output+" -->", null);
      } else {
        callback(null, filename);
      }
    });
  }
};
module.exports = helpers;
<|endoftext|>


<commit_before>var express = require('express')
var router = express.Router({
  strict: true,
  mergeParams: true
})
var Defer = require('promised-io/promise').defer
var when = require('promised-io/promise').when
var all = require('promised-io/promise').all
var Request = require('request')
var config = require('../config')
var authMiddleware = require('../middleware/auth')
var httpParams = require('../middleware/http-params')
var Queue = require('file-queue').Queue
var debug = require('debug')('p3api-server:route/indexer')
var formidable = require('formidable')
var uuid = require('uuid')
var fs = require('fs-extra')
var Path = require('path')

debug('Queue Directory: ', config.get('queueDirectory'))
var qdir = config.get('queueDirectory')
var queue
fs.mkdirs(Path.join(qdir, 'file_data'), function (err) {
  if (err) {
    debug('Error Creating Index Directory Structure: ', err)
    return
  }
  fs.mkdirs(Path.join(qdir, 'history'), function (err) {
    if (err) {
      debug('Error Creating Index History Directory: ', err)
      return
    }
    fs.mkdirs(Path.join(qdir, 'errors'), function (err) {
      if (err) {
        debug('Error Creating Index Error Directory: ', err)
        return
      }

      queue = new Queue(qdir, function (err) {
        if (err) {
          debug('error: ', err)
          return
        }
        debug('Created Queue.')
      })
    })
  })
})

router.use(httpParams)
router.use(authMiddleware)

router.use(function (req, res, next) {
  debug('req.path', req.path)
  // debug('req content-type', req.get('content-type'))
  // debug('accept', req.get('accept'))
  // debug('req.url', req.url)
  // debug('req.path', req.path)
  // debug('req.params:', JSON.stringify(req.params))
  next()
})

router.get('/:id', function (req, res, next) {
  debug('Read Data from History: ', Path.join(qdir, 'history', req.params.id))
  fs.readJson(Path.join(qdir, 'history', req.params.id), function (err, data) {
    if (err) {
      return next(err)
    }

    if (data.state === 'indexed') {
      respondWithData(res, data)
    } else {
      if (data.genomeId) {
        checkSolr(data.genomeId)
          .then((isAllIndexed) => {
            if (isAllIndexed) {
              updateHistory(req.params.id, data).then((data) => {
                respondWithData(res, data)
              })
              // now delete files
              const fileDirPath = Path.dirname(data.files['genome']['path'])
              debug(`Removing files from ${fileDirPath}`)
              fs.removeSync(fileDirPath)
            } else {
              // as is, state is submitted
              respondWithData(res, data)
            }
          }, (err) => {
            console.log(err)
            next(err)
          })
      } else {
        // before it submitted, state is queued
        respondWithData(res, data)
      }
    }
  })
})

function respondWithData (res, data) {
  res.set('content-type', 'application/json')
  res.send(JSON.stringify(data))
  res.end()
}

function checkSolr (genome_id) {
  const def = new Defer()
  const cores = ['genome_sequence', 'genome_feature', 'genome']
  const defs = cores.map((core) => {
    const url = `${config.get('solr').url}/${core}/select?q=genome_id:${genome_id}&rows=1&wt=json`
    // console.log(`${url}`)
    const def = new Defer()
    Request.get(url, (err, res, body) => {
      if (err) {
        def.reject(err)
        return def.promise
      }
      var data = JSON.parse(body)
      if (res.statusCode !== 200 || data.error) {
        def.reject(new Error(data.error.msg))
        return def.promise
      }
      debug(`checking index status for ${genome_id}: [${core}] ${data.response.numFound} row(s) found`)
      def.resolve(data['response']['numFound'] > 0)
    })
    return def.promise
  })
  when(all(defs), (results) => {
    def.resolve(results.every((hasIndexed) => hasIndexed))
  }, (err) => {
    def.reject(err)
  })
  return def.promise
}

function updateHistory (id, data) {
  const def = new Defer()

  data.state = 'indexed'
  data.indexCompletionTime = new Date()

  fs.writeJson(Path.join(qdir, 'history', id), data, function (err) {
    if (err) {
      def.reject(err)
      return def.promise
    }

    def.resolve(data)
  })
  return def.promise
}

router.post('/:type', [
  function (req, res, next) {
    if (!req.user) {
      res.sendStatus(401)
      return
    }

    if (!req.params || !req.params.type || (!req.params.type === 'genome')) {
      res.sendStatus(406)
      return
    }

    if (!queue) {
      res.send('Indexing is unavailable due to a queueing error')
      res.end(500)
      return
    }
    var form = new formidable.IncomingForm()
    var qid = uuid.v4()
    fs.mkdirs(Path.join(qdir, 'file_data', qid), function (err) {
      if (err) {
        debug('Error creating output directory for index files to be queued: ', Path.join(qdir, 'file_data', qid))
        res.end(500)
        return
      }
      form.keepExtensions = true
      form.uploadDir = Path.join(qdir, 'file_data', qid)
      form.multiples = true
      debug('Begin parse')
      form.parse(req, function (err, fields, files) {
        var d = {id: qid, type: req.params.type, user: req.user, options: fields, files: {}}

        Object.keys(files).forEach(function (type) {
          d.files[type] = files[type]
        })

        queue.push(d, function (err) {
          if (err) {
            res.error('Error Adding to queue: ' + err)
            res.end(500)
            return
          }
          d.state = 'queued'
          d.queueTime = new Date()

          fs.writeJson(Path.join(qdir, 'history', qid), d, function (err) {
            res.set('content-type', 'application/json')
            res.send(JSON.stringify({id: qid, state: 'queued', queueTime: d.queueTime}))
            res.end()
          })
        })
      })
    })
  }
])

module.exports = router
<commit_msg>return indexer queue size<commit_after>var express = require('express')
var router = express.Router({
  strict: true,
  mergeParams: true
})
var Defer = require('promised-io/promise').defer
var when = require('promised-io/promise').when
var all = require('promised-io/promise').all
var Request = require('request')
var config = require('../config')
var authMiddleware = require('../middleware/auth')
var httpParams = require('../middleware/http-params')
var Queue = require('file-queue').Queue
var debug = require('debug')('p3api-server:route/indexer')
var formidable = require('formidable')
var uuid = require('uuid')
var fs = require('fs-extra')
var Path = require('path')

debug('Queue Directory: ', config.get('queueDirectory'))
var qdir = config.get('queueDirectory')
var queue
fs.mkdirs(Path.join(qdir, 'file_data'), function (err) {
  if (err) {
    debug('Error Creating Index Directory Structure: ', err)
    return
  }
  fs.mkdirs(Path.join(qdir, 'history'), function (err) {
    if (err) {
      debug('Error Creating Index History Directory: ', err)
      return
    }
    fs.mkdirs(Path.join(qdir, 'errors'), function (err) {
      if (err) {
        debug('Error Creating Index Error Directory: ', err)
        return
      }

      queue = new Queue(qdir, function (err) {
        if (err) {
          debug('error: ', err)
          return
        }
        debug('Created Queue.')
      })
    })
  })
})

router.use(httpParams)
router.use(authMiddleware)

router.use(function (req, res, next) {
  debug('req.path', req.path)
  // debug('req content-type', req.get('content-type'))
  // debug('accept', req.get('accept'))
  // debug('req.url', req.url)
  // debug('req.path', req.path)
  // debug('req.params:', JSON.stringify(req.params))
  next()
})

router.get('/:id', function (req, res, next) {
  debug('Read Data from History: ', Path.join(qdir, 'history', req.params.id))
  fs.readJson(Path.join(qdir, 'history', req.params.id), function (err, data) {
    if (err) {
      return next(err)
    }

    if (data.state === 'indexed') {
      respondWithData(res, data)
    } else {
      if (data.genomeId) {
        checkSolr(data.genomeId)
          .then((isAllIndexed) => {
            if (isAllIndexed) {
              updateHistory(req.params.id, data).then((data) => {
                respondWithData(res, data)
              })
              // now delete files
              const fileDirPath = Path.dirname(data.files['genome']['path'])
              debug(`Removing files from ${fileDirPath}`)
              fs.removeSync(fileDirPath)
            } else {
              // as is, state is submitted
              respondWithData(res, data)
            }
          }, (err) => {
            console.log(err)
            next(err)
          })
      } else {
        // before it submitted, state is queued
        respondWithData(res, data)
      }
    }
  })
})

function respondWithData (res, data) {
  res.set('content-type', 'application/json')
  res.send(JSON.stringify(data))
  res.end()
}

function checkSolr (genome_id) {
  const def = new Defer()
  const cores = ['genome_sequence', 'genome_feature', 'genome']
  const defs = cores.map((core) => {
    const url = `${config.get('solr').url}/${core}/select?q=genome_id:${genome_id}&rows=1&wt=json`
    // console.log(`${url}`)
    const def = new Defer()
    Request.get(url, (err, res, body) => {
      if (err) {
        def.reject(err)
        return def.promise
      }
      var data = JSON.parse(body)
      if (res.statusCode !== 200 || data.error) {
        def.reject(new Error(data.error.msg))
        return def.promise
      }
      debug(`checking index status for ${genome_id}: [${core}] ${data.response.numFound} row(s) found`)
      def.resolve(data['response']['numFound'] > 0)
    })
    return def.promise
  })
  when(all(defs), (results) => {
    def.resolve(results.every((hasIndexed) => hasIndexed))
  }, (err) => {
    def.reject(err)
  })
  return def.promise
}

function updateHistory (id, data) {
  const def = new Defer()

  data.state = 'indexed'
  data.indexCompletionTime = new Date()

  fs.writeJson(Path.join(qdir, 'history', id), data, function (err) {
    if (err) {
      def.reject(err)
      return def.promise
    }

    def.resolve(data)
  })
  return def.promise
}

router.post('/:type', [
  function (req, res, next) {
    if (!req.user) {
      res.sendStatus(401)
      return
    }

    if (!req.params || !req.params.type || (!req.params.type === 'genome')) {
      res.sendStatus(406)
      return
    }

    if (!queue) {
      res.send('Indexing is unavailable due to a queueing error')
      res.end(500)
      return
    }
    var form = new formidable.IncomingForm()
    var qid = uuid.v4()
    fs.mkdirs(Path.join(qdir, 'file_data', qid), function (err) {
      if (err) {
        debug('Error creating output directory for index files to be queued: ', Path.join(qdir, 'file_data', qid))
        res.end(500)
        return
      }
      form.keepExtensions = true
      form.uploadDir = Path.join(qdir, 'file_data', qid)
      form.multiples = true
      debug('Begin parse')
      form.parse(req, function (err, fields, files) {
        var d = {id: qid, type: req.params.type, user: req.user, options: fields, files: {}}

        Object.keys(files).forEach(function (type) {
          d.files[type] = files[type]
        })

        queue.push(d, function (err) {
          if (err) {
            res.error('Error Adding to queue: ' + err)
            res.end(500)
            return
          }
          d.state = 'queued'
          d.queueTime = new Date()

          fs.writeJson(Path.join(qdir, 'history', qid), d, function (err) {
            res.set('content-type', 'application/json')
            res.send(JSON.stringify({id: qid, state: 'queued', queueTime: d.queueTime}))
            res.end()
          })
        })
      })
    })
  }
])

// fallback. return number of genomes in queue
router.get('/', function (req, res, next) {
  queue.length((err, length) => {
    respondWithData(res, {'genomesInQueue': length})
  })
})

module.exports = router
<|endoftext|>


<commit_before>var db = require('../lib/db');
var config = require('../lib/config.js');
var util = require('../lib/util.js');
var async = require('async');
var ResponseTimes = require('../lib/response-times');

var FunctionCallCounter = require('../lib/function-call-counter');

var responseTimes = new ResponseTimes(100);
var updateTrackerTimes = new ResponseTimes(100);
var updateTrackerTimesAsync = new ResponseTimes(100);
var addMessageToTripTimes = new ResponseTimes(100);
var addMessageToTripTimesAsync = new ResponseTimes(100);
var responseCounter = new FunctionCallCounter();
var DEFAULT_TRIP_DURATION = 6 * 60 * 60 * 1000;

var getTrackerCollection = function () {
    return db.getDb().collection('trackers');
};

var getTripCollection = function () {
    return db.getDb().collection('trips');
};

var getMessageCollection = function () {
    return db.getDb().collection('messages');
};

var updateTracker = function (serial, message, callback) {
    var query = { serial: serial};
    var data = { $set: { lastMessage: message } };
    var timeBefore = new Date().getTime();
    getTrackerCollection().findAndModify(query, null, data, { new:true /*fields:{ id_:1}*/ }, function(err, doc) {
        updateTrackerTimes.addTime(new Date().getTime() - timeBefore);
        // if the query does not find any documents, findAndModify can call back with no error and a null document
        if (!doc) {
            err = 'not found';
        }
        callback(err, doc);
    });
};

var addMessage = function(userId, trackerId, message, timestampNow, callback) {
    message.receivedTimestamp = timestampNow;
    var object = {
        timestamp: timestampNow,
        message: message,
        trackerId: trackerId,
        userId: userId
    };
    getMessageCollection().insert(object, callback);
};

var findOldestMessage = function(trackerId, callback) {
    var options = {
        sort: [['_id','asc']],
        limit: 1
    };

    var cursor = getMessageCollection().find({trackerId: trackerId}, undefined, options);
    cursor.toArray(function(err, docs) {
        var doc;
        if (docs) {
            doc = docs[0];
        }
        callback(err, doc);
    });
};

var isConversionRequired = function(trackerId, tripDuration, timestampNow, callback) {
    findOldestMessage(trackerId, function(err, doc) {
        if (!tripDuration) {
            tripDuration = DEFAULT_TRIP_DURATION;
        }
        callback(null, doc && doc.timestamp + tripDuration <= timestampNow);
    })
};

var buildMessageArray = function(messages) {
    var messageArray = [];
    messages.forEach(function(messageContainer) {
       messageArray.push(messageContainer.message);
    });
    return messageArray;
};

var convertMessagesToTrips = function(trackerId, userId, callback) {

    async.waterfall([function(callback) {
        var sort = {
            "sort": [['_id','asc']]
        };
        var cursor = getMessageCollection().find({trackerId: trackerId}, undefined, sort);
        cursor.toArray(callback);
    }, function(docs, callback) {
        console.log('adding trip ');
        var data = {
            messages: buildMessageArray(docs),
            startTime: new Date(docs[0].timestamp),
            endTime: new Date(docs[docs.length - 1].timestamp),
            userId: userId,
            trackerId: trackerId
        };
        console.log(data);
        getTripCollection().insert(data, callback);
    }, function(result, callback) {
        getMessageCollection().remove({trackerId: trackerId}, callback);
    }], function(err) {
        callback(err);
    });
};

var handleIdChanged = function(doc) {
    var obj = outstandingRequests[doc._id];
    if (obj &&  obj.userId.equals(doc.userId)) {
        obj.res.json(doc);

        // remove all keys from outstandingRequests that point to obj
        for(var key in outstandingRequests){
            request = outstandingRequests[key];
            if (request === obj) {
                delete outstandingRequests[key];
            }
        }
    }
};

var configureCleanup = function() {
    var cleanupInterval = config.getLongPollCleanupInterval();
    setTimeout(function() {
        var timeNow = util.currentTimeMillis();
        for(var key in outstandingRequests){
            request = outstandingRequests[key];
            if (request.timestamp + config.getLongPollTimeOut() < timeNow) {
                request.res.json(408, {});
                delete outstandingRequests[key];
            }
        }
        configureCleanup();
    },cleanupInterval);

};
configureCleanup();

var outstandingRequests = {};

var findObjects = function(query, callback) {
    var cursor = getTrackerCollection().find(query, {});
    cursor.toArray(function(err, docs) {
        callback(err, docs);
    });
};

var addRequest = function(id, request) {
    outstandingRequests[id] = request;
};

var createRequest =  function(req, res, userId) {
    var request = {
        req: req,
        res: res,
        userId: userId,
        timestamp: util.currentTimeMillis()
    };
    return request;
};

module.exports =
{
    message: {
        ":id": {
            post: function (req, res) {
                responseCounter.called();
                var timestampNow = util.currentTimeMillis();
                var timeBefore = new Date().getTime();
                var timeBeforeAddMessageToTrip;
                var message = req.body;
                var trackerDoc;
                async.waterfall([function(callback) {
                    updateTracker(req.params.id, message, callback);
                }, function(pTrackerDoc, callback) {
                    trackerDoc = pTrackerDoc;
                    updateTrackerTimesAsync.addTime(new Date().getTime() - timeBefore);
                    handleIdChanged(trackerDoc);
                    timeBeforeAddMessageToTrip = new Date().getTime();
                    isConversionRequired(trackerDoc._id, trackerDoc.tripDuration, timestampNow, callback);
                }, function(conversionRequired, callback) {
                    if (conversionRequired) {
                        convertMessagesToTrips(trackerDoc._id, trackerDoc.userId, callback);
                    } else {
                        callback(null);
                    }
                }, function(callback) {
                    addMessage(trackerDoc.userId, trackerDoc._id, message, timestampNow, callback);
                }
                ], function(err) {
                    responseTimes.addTime(new Date().getTime() - timeBefore);
                    addMessageToTripTimesAsync.addTime(new Date().getTime() - timeBeforeAddMessageToTrip);
                    if (err) {

                        if (err === 'not found') {
                            res.json(404, {});
                        } else {
                            res.json(500, {});
                        }
                    } else {
                        res.json(200, {});
                    }
                });

            }
        },
        notify: {
            use: function (req, res, next) {
                if (req.isAuthenticated()) {
                    next();
                } else {
                    res.json(401, {message: 'not logged in'});
                }
            },
            ":id": {
                get: function (req, res) {
                    addRequest(req.params.id, createRequest(req, res, req.user._id));
                }
            },
            get: function (req, res) {
                var query = { userId: req.user._id };
                var request = createRequest(req, res, req.user._id);
                findObjects(query, function(err, objects) {
                    for (var i = 0; i < objects.length; i++) {
                        addRequest(objects[i]._id, request);
                    }
                });
            }
        }
    }
};

var printAverageResponseTime = function() {

    console.log('called '+ responseCounter.count() + ' per second average response time ' + responseTimes.calculateAverage() + ' updateTrackerTimes ' + updateTrackerTimes.calculateAverage() + ' ' + updateTrackerTimesAsync.calculateAverage() + ' addMessageToTrip ' + addMessageToTripTimes.calculateAverage() + ' ' + addMessageToTripTimesAsync.calculateAverage() );
    setTimeout(printAverageResponseTime, 1000);
};

printAverageResponseTime();
<commit_msg>turn off average response time debug<commit_after>var db = require('../lib/db');
var config = require('../lib/config.js');
var util = require('../lib/util.js');
var async = require('async');
var ResponseTimes = require('../lib/response-times');

var FunctionCallCounter = require('../lib/function-call-counter');

var responseTimes = new ResponseTimes(100);
var updateTrackerTimes = new ResponseTimes(100);
var updateTrackerTimesAsync = new ResponseTimes(100);
var addMessageToTripTimes = new ResponseTimes(100);
var addMessageToTripTimesAsync = new ResponseTimes(100);
var responseCounter = new FunctionCallCounter();
var DEFAULT_TRIP_DURATION = 6 * 60 * 60 * 1000;

var getTrackerCollection = function () {
    return db.getDb().collection('trackers');
};

var getTripCollection = function () {
    return db.getDb().collection('trips');
};

var getMessageCollection = function () {
    return db.getDb().collection('messages');
};

var updateTracker = function (serial, message, callback) {
    var query = { serial: serial};
    var data = { $set: { lastMessage: message } };
    var timeBefore = new Date().getTime();
    getTrackerCollection().findAndModify(query, null, data, { new:true /*fields:{ id_:1}*/ }, function(err, doc) {
        updateTrackerTimes.addTime(new Date().getTime() - timeBefore);
        // if the query does not find any documents, findAndModify can call back with no error and a null document
        if (!doc) {
            err = 'not found';
        }
        callback(err, doc);
    });
};

var addMessage = function(userId, trackerId, message, timestampNow, callback) {
    message.receivedTimestamp = timestampNow;
    var object = {
        timestamp: timestampNow,
        message: message,
        trackerId: trackerId,
        userId: userId
    };
    getMessageCollection().insert(object, callback);
};

var findOldestMessage = function(trackerId, callback) {
    var options = {
        sort: [['_id','asc']],
        limit: 1
    };

    var cursor = getMessageCollection().find({trackerId: trackerId}, undefined, options);
    cursor.toArray(function(err, docs) {
        var doc;
        if (docs) {
            doc = docs[0];
        }
        callback(err, doc);
    });
};

var isConversionRequired = function(trackerId, tripDuration, timestampNow, callback) {
    findOldestMessage(trackerId, function(err, doc) {
        if (!tripDuration) {
            tripDuration = DEFAULT_TRIP_DURATION;
        }
        callback(null, doc && doc.timestamp + tripDuration <= timestampNow);
    })
};

var buildMessageArray = function(messages) {
    var messageArray = [];
    messages.forEach(function(messageContainer) {
       messageArray.push(messageContainer.message);
    });
    return messageArray;
};

var convertMessagesToTrips = function(trackerId, userId, callback) {

    async.waterfall([function(callback) {
        var sort = {
            "sort": [['_id','asc']]
        };
        var cursor = getMessageCollection().find({trackerId: trackerId}, undefined, sort);
        cursor.toArray(callback);
    }, function(docs, callback) {
        console.log('adding trip ');
        var data = {
            messages: buildMessageArray(docs),
            startTime: new Date(docs[0].timestamp),
            endTime: new Date(docs[docs.length - 1].timestamp),
            userId: userId,
            trackerId: trackerId
        };
        console.log(data);
        getTripCollection().insert(data, callback);
    }, function(result, callback) {
        getMessageCollection().remove({trackerId: trackerId}, callback);
    }], function(err) {
        callback(err);
    });
};

var handleIdChanged = function(doc) {
    var obj = outstandingRequests[doc._id];
    if (obj &&  obj.userId.equals(doc.userId)) {
        obj.res.json(doc);

        // remove all keys from outstandingRequests that point to obj
        for(var key in outstandingRequests){
            request = outstandingRequests[key];
            if (request === obj) {
                delete outstandingRequests[key];
            }
        }
    }
};

var configureCleanup = function() {
    var cleanupInterval = config.getLongPollCleanupInterval();
    setTimeout(function() {
        var timeNow = util.currentTimeMillis();
        for(var key in outstandingRequests){
            request = outstandingRequests[key];
            if (request.timestamp + config.getLongPollTimeOut() < timeNow) {
                request.res.json(408, {});
                delete outstandingRequests[key];
            }
        }
        configureCleanup();
    },cleanupInterval);

};
configureCleanup();

var outstandingRequests = {};

var findObjects = function(query, callback) {
    var cursor = getTrackerCollection().find(query, {});
    cursor.toArray(function(err, docs) {
        callback(err, docs);
    });
};

var addRequest = function(id, request) {
    outstandingRequests[id] = request;
};

var createRequest =  function(req, res, userId) {
    var request = {
        req: req,
        res: res,
        userId: userId,
        timestamp: util.currentTimeMillis()
    };
    return request;
};

module.exports =
{
    message: {
        ":id": {
            post: function (req, res) {
                responseCounter.called();
                var timestampNow = util.currentTimeMillis();
                var timeBefore = new Date().getTime();
                var timeBeforeAddMessageToTrip;
                var message = req.body;
                var trackerDoc;
                async.waterfall([function(callback) {
                    updateTracker(req.params.id, message, callback);
                }, function(pTrackerDoc, callback) {
                    trackerDoc = pTrackerDoc;
                    updateTrackerTimesAsync.addTime(new Date().getTime() - timeBefore);
                    handleIdChanged(trackerDoc);
                    timeBeforeAddMessageToTrip = new Date().getTime();
                    isConversionRequired(trackerDoc._id, trackerDoc.tripDuration, timestampNow, callback);
                }, function(conversionRequired, callback) {
                    if (conversionRequired) {
                        convertMessagesToTrips(trackerDoc._id, trackerDoc.userId, callback);
                    } else {
                        callback(null);
                    }
                }, function(callback) {
                    addMessage(trackerDoc.userId, trackerDoc._id, message, timestampNow, callback);
                }
                ], function(err) {
                    responseTimes.addTime(new Date().getTime() - timeBefore);
                    addMessageToTripTimesAsync.addTime(new Date().getTime() - timeBeforeAddMessageToTrip);
                    if (err) {

                        if (err === 'not found') {
                            res.json(404, {});
                        } else {
                            res.json(500, {});
                        }
                    } else {
                        res.json(200, {});
                    }
                });

            }
        },
        notify: {
            use: function (req, res, next) {
                if (req.isAuthenticated()) {
                    next();
                } else {
                    res.json(401, {message: 'not logged in'});
                }
            },
            ":id": {
                get: function (req, res) {
                    addRequest(req.params.id, createRequest(req, res, req.user._id));
                }
            },
            get: function (req, res) {
                var query = { userId: req.user._id };
                var request = createRequest(req, res, req.user._id);
                findObjects(query, function(err, objects) {
                    for (var i = 0; i < objects.length; i++) {
                        addRequest(objects[i]._id, request);
                    }
                });
            }
        }
    }
};

var printAverageResponseTime = function() {

    console.log('called '+ responseCounter.count() + ' per second average response time ' + responseTimes.calculateAverage() + ' updateTrackerTimes ' + updateTrackerTimes.calculateAverage() + ' ' + updateTrackerTimesAsync.calculateAverage() + ' addMessageToTrip ' + addMessageToTripTimes.calculateAverage() + ' ' + addMessageToTripTimesAsync.calculateAverage() );
    setTimeout(printAverageResponseTime, 1000);
};

//printAverageResponseTime();
<|endoftext|>


<commit_before>var connect = require('connect'),
    cadence = require('cadence'),
    quip = require('quip'),
    dispatch = require('dispatch'),
    bodyParser = require('body-parser'),
    errorHandler = require('errorhandler'),
    logger = require('../monitor/logger')('http.middleware')

function HTTPError (code, data) {
    this.code = code
    this.data = data
}

exports.dispatch = function (binder, structure, remote) {
    if (!binder) throw new Error
    return connect()
        .use(function (request, response, next) {
            request.binder = binder
            request.context = {
                endpoint: binder.location,
                socket: {
                    address: request.socket.remoteAddress,
                    port: request.socket.remotePort
                }
            }
            if (remote) {
                request.context.remote = {
                    address: request.headers['x-forwarded-for'] || request.socket.remoteAddress,
                    port: request.headers['x-forwarded-port'] || request.socket.remotePort
                }
            }
            logger.info('request', {
                headers: request.headers
            }, request.context)
            next()
        })
        .use(authorizationParser)
        .use(quip)
        .use(jump)
        .use(bodyParser.json())
        .use(dispatch(structure))
        .use(function (request, response, next) {
            response.status(404).json({ message: 'Not found' })
        })
        .use(errorHandler())
}

var jump = exports.jump = function (request, response, next) {
    request.raise = function (code, data) {
        if (typeof data == 'string') data = { message: data }
        throw new HTTPError(code, data)
    }
    next()
}

var authorizationParser = exports.authorizationParser = function (request, response, next) {
    if (request.headers.authorization) {
        var auth = request.headers.authorization.split(' ')
        if (auth.length == 2) {
            request.authorization = { scheme: auth[0], credentials: auth[1] }
        }
    }
    next()
}

var handle = exports.handle = function (handler) {
    return function (request, response, next) {
        handler(request, function (error, result) {
            if (error) {
                if (error instanceof HTTPError) {
                    response.status(error.code).json(error.data)
                } else {
                    next(error)
                }
            } else {
                switch (typeof result) {
                case 'function':
                    result(response)
                    break
                case 'string':
                    response.ok().text(result)
                    break
                default:
                    response.ok().json(result)
                    break
                }
            }
        })
    }
}

exports.authorize = function (authorizer, handler) {
    return handle(cadence(function (step, request) {
        step(function () {
            authorizer(request, step())
        }, function (identity) {
            if (identity) {
                request.authorization.identity = identity
                handler(request, step())
            } else {
                request.raise(401, 'Forbidden')
            }
        })
    }))
}

exports.send = function (statusCode, headers, body) {
    return function (response) {
        var h = {
            'content-type': headers['content-type'],
            'content-length': body.length
        }
        logger.info('send', {
            statusCode: statusCode,
            headers: h,
            body: JSON.parse(body.toString())
        })
        response.status(statusCode).headers(h)
        response.write(body)
        response.end()
    }
}

exports.isBearer = function (request) {
    return request.authorization && request.authorization.scheme == 'Bearer'
}
<commit_msg>[NEWRELIC] initial new relic support<commit_after>var connect = require('connect'),
    cadence = require('cadence'),
    quip = require('quip'),
    dispatch = require('dispatch'),
    bodyParser = require('body-parser'),
    errorHandler = require('errorhandler'),
    logger = require('../monitor/logger')('http.middleware')

function HTTPError (code, data) {
    this.code = code
    this.data = data
}

var newrelic;

exports.dispatch = function (binder, structure, remote, nr, prefix) {
    if (!binder) throw new Error
    newrelic = nr
    if (!!nr) structure = reliquary(prefix, structure)
    return connect()
        .use(function (request, response, next) {
            request.binder = binder
            request.context = {
                endpoint: binder.location,
                socket: {
                    address: request.socket.remoteAddress,
                    port: request.socket.remotePort
                }
            }
            if (remote) {
                request.context.remote = {
                    address: request.headers['x-forwarded-for'] || request.socket.remoteAddress,
                    port: request.headers['x-forwarded-port'] || request.socket.remotePort
                }
            }
            logger.info('request', {
                headers: request.headers
            }, request.context)
            next()
        })
        .use(authorizationParser)
        .use(quip)
        .use(jump)
        .use(bodyParser.json())
        .use(dispatch(structure))
        .use(function (request, response, next) {
            response.status(404).json({ message: 'Not found' })
        })
        .use(errorHandler())
}

function reliquary(prefix, structure) {
    var result = {}

    callback = function(prop) {
        return function(request, response, next) {
            var err, m, method

            m = prop.indexOf(' ')
            method = m > 0 ? prop.substr(0, m) : prop
            newrelic.addCustomParameter('method', method)
            try {
                structure[prop](request, response, next)
            } catch(ex) {
                newrelic.noticeError(ex, {})
                err = ex
            }
            newrelic.endTransaction()
            if (!!err) throw(err)
        }
    }

    for (var prop in structure) if (structure.hasOwnProperty(prop)) {
        var p, path

        p = prop.indexOf('/')
        path = p !== -1 ? prop.substr(p + 1) : prop
        if (!!prefix) path = prefix + '/' + path
        result[prop] = newrelic.createWebTransaction(path, callback(prop))
    }

    return result
}

var jump = exports.jump = function (request, response, next) {
    request.raise = function (code, data) {
        if (typeof data == 'string') data = { message: data }
        throw new HTTPError(code, data)
    }
    next()
}

var authorizationParser = exports.authorizationParser = function (request, response, next) {
    if (request.headers.authorization) {
        var auth = request.headers.authorization.split(' ')
        if (auth.length == 2) {
            request.authorization = { scheme: auth[0], credentials: auth[1] }
        }
    }
    next()
}

var handle = exports.handle = function (handler) {
    return function (request, response, next) {
        handler(request, function (error, result) {
            if (error) {
                if (!!newrelic) newrelic.noticeError(error, {})

                if (error instanceof HTTPError) {
                    response.status(error.code).json(error.data)
                } else {
                    next(error)
                }
            } else {
                switch (typeof result) {
                case 'function':
                    result(response)
                    break
                case 'string':
                    response.ok().text(result)
                    break
                default:
                    response.ok().json(result)
                    break
                }
            }
        })
    }
}

exports.authorize = function (authorizer, handler) {
    return handle(cadence(function (step, request) {
        step(function () {
            authorizer(request, step())
        }, function (identity) {
            if (identity) {
                request.authorization.identity = identity
                handler(request, step())
            } else {
                request.raise(401, 'Forbidden')
            }
        })
    }))
}

exports.send = function (statusCode, headers, body) {
    return function (response) {
        var h = {
            'content-type': headers['content-type'],
            'content-length': body.length
        }
        logger.info('send', {
            statusCode: statusCode,
            headers: h,
            body: JSON.parse(body.toString())
        })
        response.status(statusCode).headers(h)
        response.write(body)
        response.end()
    }
}

exports.isBearer = function (request) {
    return request.authorization && request.authorization.scheme == 'Bearer'
}
<|endoftext|>


<commit_before>var express = require('express');
var request = require('request');
var xml2js = require('xml2js');
var router = express.Router();

var parser = new xml2js.Parser({explicitArray: false});
var parseString = parser.parseString;

var safeTitle = function (str) {
    str = str.replace(/\s/g, '-');
    str = str.replace(/[^a-zA-Z0-9\-]/g, '');
    return str;
};

router.get('/:id/:title?', function (req, res, next) {
    var id = req.params.id;

    console.log('https://itunes.apple.com/lookup?id=' + id);

    request('https://itunes.apple.com/lookup?id=' + id, function (error, response, body) {
        if (response.statusCode == 400) {
            var error = new Error('Not Found');
            error.status = 404;
            res.render('error', { message: "Podcast not found.", error: error});
        }
        else {
            var result = JSON.parse(body).results[0],
                feed = result.feedUrl,
                title = result.collectionCensoredName;
            request(feed, function (error, response, body) {
                parseString(body, function (err, obj) {
                    obj.rss.channel.genre = result.primaryGenreName;
                    if (!obj.rss.channel.genre) obj.rss.channel.genre = "N/A";
                    obj.rss.channel.imgs = { i600 : result.artworkUrl600,
                                                   i100 : result.artworkUrl100,
                                                   i60 : result.artworkUrl60,
                                                   i30 : result.artworkUrl30 };

                    res.render('podcast', { id: id, title: title, javascripts: ['podcast'], safetitle: safeTitle(title), feed: obj.rss.channel });
                });
            });
        }
    });
});

module.exports = router;<commit_msg>podcast notfound hotfix<commit_after>var express = require('express');
var request = require('request');
var xml2js = require('xml2js');
var router = express.Router();

var parser = new xml2js.Parser({explicitArray: false});
var parseString = parser.parseString;

var safeTitle = function (str) {
    str = str.replace(/\s/g, '-');
    str = str.replace(/[^a-zA-Z0-9\-]/g, '');
    return str;
};

router.get('/:id/:title?', function (req, res, next) {
    var id = req.params.id;

    console.log('https://itunes.apple.com/lookup?id=' + id);

    request('https://itunes.apple.com/lookup?id=' + id, function (error, response, body) {
        if (response.statusCode == 400) {
            var error = new Error('Not Found');
            error.status = 404;
            res.render('error', { message: "Podcast not found.", error: error});
        }
        else {
            var result = JSON.parse(body).results;
            if (result.length > 0) {
                    result = result[0];
                    var feed = result.feedUrl,
                    title = result.collectionCensoredName;
                request(feed, function (error, response, body) {
                    parseString(body, function (err, obj) {
                        obj.rss.channel.genre = result.primaryGenreName;
                        if (!obj.rss.channel.genre) obj.rss.channel.genre = "N/A";
                        obj.rss.channel.imgs = { i600 : result.artworkUrl600,
                                                       i100 : result.artworkUrl100,
                                                       i60 : result.artworkUrl60,
                                                       i30 : result.artworkUrl30 };

                        res.render('podcast', { id: id, title: title, javascripts: ['podcast'], safetitle: safeTitle(title), feed: obj.rss.channel });
                    });
                });
            }
            else {
                var error = new Error('Not Found');
                error.status = 404;
                res.render('error', { message: "Podcast not found.", error: error});
            }
        }
    });
});

module.exports = router;<|endoftext|>


<commit_before>/*!
 * jQuery.scrollTo
 * Copyright (c) 2007-2015 Ariel Flesler - aflesler<a>gmail<d>com | http://flesler.blogspot.com
 * Licensed under MIT
 * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
 * @projectDescription Lightweight, cross-browser and highly customizable animated scrolling with jQuery
 * @author Ariel Flesler
 * @version 2.1.1
 */
;(function(factory) {
	'use strict';
	if (typeof define === 'function' && define.amd) {
		// AMD
		define(['jquery'], factory);
	} else if (typeof module !== 'undefined' && module.exports) {
		// CommonJS
		module.exports = factory(require('jquery'));
	} else {
		// Global
		factory(jQuery);
	}
})(function($) {
	'use strict';

	var $scrollTo = $.scrollTo = function(target, duration, settings) {
		return $(window).scrollTo(target, duration, settings);
	};

	$scrollTo.defaults = {
		axis:'xy',
		duration: 0,
		limit:true
	};

	function isWin(elem) {
		return !elem.nodeName ||
			$.inArray(elem.nodeName.toLowerCase(), ['iframe','#document','html','body']) !== -1;
	}

	$.fn.scrollTo = function(target, duration, settings) {
		if (typeof duration === 'object') {
			settings = duration;
			duration = 0;
		}
		if (typeof settings === 'function') {
			settings = { onAfter:settings };
		}
		if (target === 'max') {
			target = 9e9;
		}

		settings = $.extend({}, $scrollTo.defaults, settings);
		// Speed is still recognized for backwards compatibility
		duration = duration || settings.duration;
		// Make sure the settings are given right
		var queue = settings.queue && settings.axis.length > 1;
		if (queue) {
			// Let's keep the overall duration
			duration /= 2;
		}
		settings.offset = both(settings.offset);
		settings.over = both(settings.over);

		return this.each(function() {
			// Null target yields nothing, just like jQuery does
			if (target === null) return;

			var win = isWin(this),
				elem = win ? this.contentWindow || window : this,
				$elem = $(elem),
				targ = target,
				attr = {},
				toff;

			switch (typeof targ) {
				// A number will pass the regex
				case 'number':
				case 'string':
					if (/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)) {
						targ = both(targ);
						// We are done
						break;
					}
					// Relative/Absolute selector
					targ = win ? $(targ) : $(targ, elem);
					if (!targ.length) return;
					/* falls through */
				case 'object':
					// DOMElement / jQuery
					if (targ.is || targ.style) {
						// Get the real position of the target
						toff = (targ = $(targ)).offset();
					}
			}

			var offset = $.isFunction(settings.offset) && settings.offset(elem, targ) || settings.offset;

			$.each(settings.axis.split(''), function(i, axis) {
				var Pos	= axis === 'x' ? 'Left' : 'Top',
					pos = Pos.toLowerCase(),
					key = 'scroll' + Pos,
					prev = $elem[key](),
					max = $scrollTo.max(elem, axis);

				if (toff) {// jQuery / DOMElement
					attr[key] = toff[pos] + (win ? 0 : prev - $elem.offset()[pos]);

					// If it's a dom element, reduce the margin
					if (settings.margin) {
						attr[key] -= parseInt(targ.css('margin'+Pos), 10) || 0;
						attr[key] -= parseInt(targ.css('border'+Pos+'Width'), 10) || 0;
					}

					attr[key] += offset[pos] || 0;

					if (settings.over[pos]) {
						// Scroll to a fraction of its width/height
						attr[key] += targ[axis === 'x'?'width':'height']() * settings.over[pos];
					}
				} else {
					var val = targ[pos];
					// Handle percentage values
					attr[key] = val.slice && val.slice(-1) === '%' ?
						parseFloat(val) / 100 * max
						: val;
				}

				// Number or 'number'
				if (settings.limit && /^\d+$/.test(attr[key])) {
					// Check the limits
					attr[key] = attr[key] <= 0 ? 0 : Math.min(attr[key], max);
				}

				// Don't waste time animating, if there's no need.
				if (!i && settings.axis.length > 1) {
					if (prev === attr[key]) {
						// No animation needed
						attr = {};
					} else if (queue) {
						// Intermediate animation
						animate(settings.onAfterFirst);
						// Don't animate this axis again in the next iteration.
						attr = {};
					}
				}
			});

			animate(settings.onAfter);

			function animate(callback) {
				var opts = $.extend({}, settings, {
					// The queue setting conflicts with animate()
					// Force it to always be true
					queue: true,
					duration: duration,
					complete: callback && function() {
						callback.call(elem, targ, settings);
					}
				});
				$elem.animate(attr, opts);
			}
		});
	};

	// Max scrolling position, works on quirks mode
	// It only fails (not too badly) on IE, quirks mode.
	$scrollTo.max = function(elem, axis) {
		var Dim = axis === 'x' ? 'Width' : 'Height',
			scroll = 'scroll'+Dim;

		if (!isWin(elem))
			return elem[scroll] - $(elem)[Dim.toLowerCase()]();

		var size = 'client' + Dim,
			doc = elem.ownerDocument || elem.document,
			html = doc.documentElement,
			body = doc.body;

		return Math.max(html[scroll], body[scroll]) - Math.min(html[size], body[size]);
	};

	function both(val) {
		return $.isFunction(val) || $.isPlainObject(val) ? val : { top:val, left:val };
	}

	// Add special hooks so that window scroll properties can be animated
	$.Tween.propHooks.scrollLeft =
	$.Tween.propHooks.scrollTop = {
		get: function(t) {
			return $(t.elem)[t.prop]();
		},
		set: function(t) {
			var curr = this.get(t);
			// If interrupt is true and user scrolled, stop animating
			if (t.options.interrupt && t._last && t._last !== curr) {
				return $(t.elem).stop();
			}
			var next = Math.round(t.now);
			// Don't waste CPU
			// Browsers don't render floating point scroll
			if (curr !== next) {
				$(t.elem)[t.prop](next);
				t._last = this.get(t);
			}
		}
	};

	// AMD requirement
	return $scrollTo;
});
<commit_msg>Delete jquery.scrollTo.js<commit_after><|endoftext|>


<commit_before>const router = require('express').Router();

router.get('/', (req, res) => {
	if (!req.user) {
		return res.redirect('/');
	}
	const userInfo = {
		avatar: req.user.avatar,
		username: req.user.username,
		email: req.user.email,
		gender: (req.user.isMale) ? "Male" : "Female",
	};
	console.log(userInfo);
	return res.render('profile/profile', userInfo);
});

module.exports = exports = router;
<commit_msg>Add update endpoint for profile that renders new profile if valid edit<commit_after>const router = require('express').Router();
// Custom Node Helper
const usersData = require('../data/').user;

router.get('/', (req, res) => {
	if (!req.user) {
		return res.redirect('/log_in');
	}
	const userInfo = {
		avatar: req.user.avatar,
		username: req.user.username,
		email: req.user.email,
		gender: (req.user.isMale) ? "Male" : "Female",
	};
	console.log(userInfo);
	return res.render('profile/profile', userInfo);
});

router.get('/edit/', (req, res) => {
    if (!req.user) {
		return res.redirect('/log_in');
	}
    const userInfo = {
		avatar: req.user.avatar,
		username: req.user.username,
		email: req.user.email,
		gender: (req.user.isMale),
        layout: false,
	};
    console.log(userInfo);
    return res.render('profile/editProfile.handlebars', userInfo);
});

router.post('/edit/', (req, res) => {
    if (!req.user) {
		return res.redirect('/log_in');
	}
    usersData.updateUser(req.user._id, req.body).then((newProfile) => {
        newProfile.gender = (newProfile.isMale) ? "Male" : "Female",
        newProfile.layout = false;
        return res.render('profile/profile.handlebars', newProfile);
    }).catch((err) => {
        console.log(err);
        return res.status(500).json({error: err});
    });
});

module.exports = exports = router;
<|endoftext|>


<commit_before>/*!
 * OS.js - JavaScript Cloud/Web Desktop Platform
 *
 * Copyright (c) 2011-2017, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
import * as DOM from 'utils/dom';
import * as Events from 'utils/events';
import Theme from 'core/theme';

/*
 * Holds information about current behaviour
 */
class BehaviourState {
  constructor(wm, win, action, mousePosition) {
    this.win = win;
    this.$element = win._$element;
    this.$top = win._$top;
    this.$handle = win._$resize;

    this.rectWorkspace  = wm.getWindowSpace(true);
    this.rectWindow     = {
      x: win._position.x,
      y: win._position.y,
      w: win._dimension.w,
      h: win._dimension.h,
      r: win._dimension.w + win._position.x,
      b: win._dimension.h + win._position.y
    };

    const theme = Object.assign({}, Theme.getStyleTheme(true, true));
    if ( !theme.style ) {
      theme.style = {'window': {margin: 0, border: 0}};
    }

    this.theme = {
      topMargin: theme.style.window.margin || 0, // FIXME
      borderSize: theme.style.window.border || 0
    };

    this.snapping   = {
      cornerSize: wm.getSetting('windowCornerSnap') || 0,
      windowSize: wm.getSetting('windowSnap') || 0
    };

    this.action     = action;
    this.moved      = false;
    this.direction  = null;
    this.startX     = mousePosition.x;
    this.startY     = mousePosition.y;
    this.minWidth   = win._properties.min_width;
    this.minHeight  = win._properties.min_height;

    const windowRects = [];
    wm.getWindows().forEach((w) => {
      if ( w && w._wid !== win._wid ) {
        const pos = w._position;
        const dim = w._dimension;
        const rect = {
          left: pos.x - this.theme.borderSize,
          top: pos.y - this.theme.borderSize,
          width: dim.w + (this.theme.borderSize * 2),
          height: dim.h + (this.theme.borderSize * 2) + this.theme.topMargin
        };

        rect.right = rect.left + rect.width;
        rect.bottom = (pos.y + dim.h) + this.theme.topMargin + this.theme.borderSize;//rect.top + rect.height;

        windowRects.push(rect);
      }
    });

    this.snapRects = windowRects;
  }

  getRect() {
    const win = this.win;

    return {
      left: win._position.x,
      top: win._position.y,
      width: win._dimension.w,
      height: win._dimension.h
    };
  }

  calculateDirection() {
    const dir = DOM.$position(this.$handle);
    const dirX = this.startX - dir.left;
    const dirY = this.startY - dir.top;
    const dirD = 20;

    const checks = {
      nw: (dirX <= dirD) && (dirY <= dirD),
      n: (dirX > dirD) && (dirY <= dirD),
      w: (dirX <= dirD) && (dirY >= dirD),
      ne: (dirX >= (dir.width - dirD)) && (dirY <= dirD),
      e: (dirX >= (dir.width - dirD)) && (dirY > dirD),
      se: (dirX >= (dir.width - dirD)) && (dirY >= (dir.height - dirD)),
      sw: (dirX <= dirD) && (dirY >= (dir.height - dirD))
    };

    let direction = 's';
    Object.keys(checks).forEach(function(k) {
      if ( checks[k] ) {
        direction = k;
      }
    });

    this.direction = direction;
  }
}

/*
 * Window Behavour Abstraction
 */
export function createWindowBehaviour(win, wm) {
  let current = null;
  let newRect = {};

  /*
   * Resizing action
   */
  function onWindowResize(ev, mousePosition, dx, dy) {
    if ( !current || !current.direction ) {
      return false;
    }

    let nw, nh, nl, nt;

    (function() { // North/South
      if ( current.direction.indexOf('s') !== -1 ) {
        nh = current.rectWindow.h + dy;

        newRect.height = Math.max(current.minHeight, nh);
      } else if ( current.direction.indexOf('n') !== -1 ) {
        nh = current.rectWindow.h - dy;
        nt = current.rectWindow.y + dy;

        if ( nt < current.rectWorkspace.top ) {
          nt = current.rectWorkspace.top;
          nh = newRect.height;
        } else {
          if ( nh < current.minHeight ) {
            nt = current.rectWindow.b - current.minHeight;
          }
        }

        newRect.height = Math.max(current.minHeight, nh);
        newRect.top = nt;
      }
    })();

    (function() { // East/West
      if ( current.direction.indexOf('e') !== -1 ) {
        nw = current.rectWindow.w + dx;

        newRect.width = Math.max(current.minWidth, nw);
      } else if ( current.direction.indexOf('w') !== -1 ) {
        nw = current.rectWindow.w - dx;
        nl = current.rectWindow.x + dx;

        if ( nw < current.minWidth ) {
          nl = current.rectWindow.r - current.minWidth;
        }

        newRect.width = Math.max(current.minWidth, nw);
        newRect.left = nl;
      }
    })();

    return newRect;
  }

  /*
   * Movement action
   */
  function onWindowMove(ev, mousePosition, dx, dy) {
    let newWidth = null;
    let newHeight = null;
    let newLeft = current.rectWindow.x + dx;
    let newTop = current.rectWindow.y + dy;

    const borderSize = current.theme.borderSize;
    const topMargin = current.theme.topMargin;
    const cornerSnapSize = current.snapping.cornerSize;
    const windowSnapSize = current.snapping.windowSize;

    if ( newTop < current.rectWorkspace.top ) {
      newTop = current.rectWorkspace.top;
    }

    let newRight = newLeft + current.rectWindow.w + (borderSize * 2);
    let newBottom = newTop + current.rectWindow.h + topMargin + (borderSize);

    // 8-directional corner window snapping
    if ( cornerSnapSize > 0 ) {
      if ( ((newLeft - borderSize) <= cornerSnapSize) && ((newLeft - borderSize) >= -cornerSnapSize) ) { // Left
        newLeft = borderSize;
      } else if ( (newRight >= (current.rectWorkspace.width - cornerSnapSize)) && (newRight <= (current.rectWorkspace.width + cornerSnapSize)) ) { // Right
        newLeft = current.rectWorkspace.width - current.rectWindow.w - borderSize;
      }
      if ( (newTop <= (current.rectWorkspace.top + cornerSnapSize)) && (newTop >= (current.rectWorkspace.top - cornerSnapSize)) ) { // Top
        newTop = current.rectWorkspace.top + (borderSize);
      } else if (
        (newBottom >= ((current.rectWorkspace.height + current.rectWorkspace.top) - cornerSnapSize)) &&
          (newBottom <= ((current.rectWorkspace.height + current.rectWorkspace.top) + cornerSnapSize))
      ) { // Bottom
        newTop = (current.rectWorkspace.height + current.rectWorkspace.top) - current.rectWindow.h - topMargin - borderSize;
      }
    }

    // Snapping to other windows
    if ( windowSnapSize > 0 ) {
      current.snapRects.every(function(rect) {
        // >
        if ( newRight >= (rect.left - windowSnapSize) && newRight <= (rect.left + windowSnapSize) ) { // Left
          newLeft = rect.left - (current.rectWindow.w + (borderSize * 2));
          return false;
        }

        // <
        if ( (newLeft - borderSize) <= (rect.right + windowSnapSize) && (newLeft - borderSize) >= (rect.right - windowSnapSize) ) { // Right
          newLeft = rect.right + (borderSize * 2);
          return false;
        }

        // \/
        if ( newBottom >= (rect.top - windowSnapSize) && newBottom <= (rect.top + windowSnapSize) ) { // Top
          newTop = rect.top - (current.rectWindow.h + (borderSize * 2) + topMargin);
          return false;
        }

        // /\
        if ( newTop <= (rect.bottom + windowSnapSize) && newTop >= (rect.bottom - windowSnapSize) ) { // Bottom
          newTop = rect.bottom + borderSize * 2;
          return false;
        }

        return true;
      });

    }

    return {left: newLeft, top: newTop, width: newWidth, height: newHeight};
  }

  /*
   * When mouse button is released
   */
  function onMouseUp(ev, action, win, mousePosition) {
    if ( !current ) {
      return;
    }

    if ( current.moved ) {
      if ( action === 'move' ) {
        win._onChange('move', true);
        win._emit('moved', [win._position.x, win._position.y]);
      } else if ( action === 'resize' ) {
        win._onChange('resize', true);
        win._emit('resized', [win._dimension.w, win._dimension.h]);
      }
    }

    current.$element.setAttribute('data-hint', '');
    document.body.setAttribute('data-window-hint', '');

    win._emit('postop');

    current = null;
  }

  /*
   * When mouse is moved
   */
  function onMouseMove(ev, action, win, mousePosition) {
    if ( !wm.getMouseLocked() || !action || !current ) {
      return;
    }

    ev.preventDefault();

    let result;

    const dx = mousePosition.x - current.startX;
    const dy = mousePosition.y - current.startY;

    if ( action === 'move' ) {
      result = onWindowMove(ev, mousePosition, dx, dy);
    } else {
      result = onWindowResize(ev, mousePosition, dx, dy);
    }

    if ( result ) {
      if ( result.left !== null && result.top !== null ) {
        win._move(result.left, result.top);
        win._emit('move', [result.left, result.top]);
      }
      if ( result.width !== null && result.height !== null ) {
        win._resize(result.width, result.height, true);
        win._emit('resize', [result.width, result.height]);
      }
    }

    current.moved = true;
  }

  /*
   * When mouse button is pressed
   */
  function onMouseDown(ev, action, win, mousePosition) {
    ev.preventDefault();

    if ( win._state.maximized ) {
      return;
    }

    current = new BehaviourState(wm, win, action, mousePosition);
    newRect = {};

    win._focus();

    if ( action === 'move' ) {
      current.$element.setAttribute('data-hint', 'moving');
      document.body.setAttribute('data-window-hint', 'moving');
    } else {
      current.calculateDirection();
      current.$element.setAttribute('data-hint', 'resizing');
      document.body.setAttribute('data-window-hint', 'resizing');

      newRect = current.getRect();
    }

    win._emit('preop');

    function _onMouseMove(ev, pos) {
      if ( wm._mouselock ) {
        onMouseMove(ev, action, win, pos);
      }
    }
    function _onMouseUp(ev, pos) {
      onMouseUp(ev, action, win, pos);
      Events.$unbind(document, 'pointermove:movewindow,touchmove:movewindowTouch');
      Events.$unbind(document, 'pointerup:movewindowstop,touchend:movewindowstopTouch');
    }

    Events.$bind(document, 'pointermove:movewindow,touchmove:movewindowTouch', _onMouseMove, false);
    Events.$bind(document, 'pointerup:movewindowstop,touchend:movewindowstopTouch', _onMouseUp, false);
  }

  /*
   * Register a window
   */
  if ( win._properties.allow_move ) {
    Events.$bind(win._$top, 'pointerdown,touchstart', (ev, pos) => {
      if ( !win._destroyed ) {
        onMouseDown(ev, 'move', win, pos);
      }
    }, true);
  }
  if ( win._properties.allow_resize ) {
    Events.$bind(win._$resize, 'pointerdown,touchstart', (ev, pos) => {
      if ( win._destroyed ) {
        onMouseDown(ev, 'resize', win, pos);
      }
    });
  }
}
<commit_msg>window-behaviour: Corrected a mistake in a check<commit_after>/*!
 * OS.js - JavaScript Cloud/Web Desktop Platform
 *
 * Copyright (c) 2011-2017, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
import * as DOM from 'utils/dom';
import * as Events from 'utils/events';
import Theme from 'core/theme';

/*
 * Holds information about current behaviour
 */
class BehaviourState {
  constructor(wm, win, action, mousePosition) {
    this.win = win;
    this.$element = win._$element;
    this.$top = win._$top;
    this.$handle = win._$resize;

    this.rectWorkspace  = wm.getWindowSpace(true);
    this.rectWindow     = {
      x: win._position.x,
      y: win._position.y,
      w: win._dimension.w,
      h: win._dimension.h,
      r: win._dimension.w + win._position.x,
      b: win._dimension.h + win._position.y
    };

    const theme = Object.assign({}, Theme.getStyleTheme(true, true));
    if ( !theme.style ) {
      theme.style = {'window': {margin: 0, border: 0}};
    }

    this.theme = {
      topMargin: theme.style.window.margin || 0, // FIXME
      borderSize: theme.style.window.border || 0
    };

    this.snapping   = {
      cornerSize: wm.getSetting('windowCornerSnap') || 0,
      windowSize: wm.getSetting('windowSnap') || 0
    };

    this.action     = action;
    this.moved      = false;
    this.direction  = null;
    this.startX     = mousePosition.x;
    this.startY     = mousePosition.y;
    this.minWidth   = win._properties.min_width;
    this.minHeight  = win._properties.min_height;

    const windowRects = [];
    wm.getWindows().forEach((w) => {
      if ( w && w._wid !== win._wid ) {
        const pos = w._position;
        const dim = w._dimension;
        const rect = {
          left: pos.x - this.theme.borderSize,
          top: pos.y - this.theme.borderSize,
          width: dim.w + (this.theme.borderSize * 2),
          height: dim.h + (this.theme.borderSize * 2) + this.theme.topMargin
        };

        rect.right = rect.left + rect.width;
        rect.bottom = (pos.y + dim.h) + this.theme.topMargin + this.theme.borderSize;//rect.top + rect.height;

        windowRects.push(rect);
      }
    });

    this.snapRects = windowRects;
  }

  getRect() {
    const win = this.win;

    return {
      left: win._position.x,
      top: win._position.y,
      width: win._dimension.w,
      height: win._dimension.h
    };
  }

  calculateDirection() {
    const dir = DOM.$position(this.$handle);
    const dirX = this.startX - dir.left;
    const dirY = this.startY - dir.top;
    const dirD = 20;

    const checks = {
      nw: (dirX <= dirD) && (dirY <= dirD),
      n: (dirX > dirD) && (dirY <= dirD),
      w: (dirX <= dirD) && (dirY >= dirD),
      ne: (dirX >= (dir.width - dirD)) && (dirY <= dirD),
      e: (dirX >= (dir.width - dirD)) && (dirY > dirD),
      se: (dirX >= (dir.width - dirD)) && (dirY >= (dir.height - dirD)),
      sw: (dirX <= dirD) && (dirY >= (dir.height - dirD))
    };

    let direction = 's';
    Object.keys(checks).forEach(function(k) {
      if ( checks[k] ) {
        direction = k;
      }
    });

    this.direction = direction;
  }
}

/*
 * Window Behavour Abstraction
 */
export function createWindowBehaviour(win, wm) {
  let current = null;
  let newRect = {};

  /*
   * Resizing action
   */
  function onWindowResize(ev, mousePosition, dx, dy) {
    if ( !current || !current.direction ) {
      return false;
    }

    let nw, nh, nl, nt;

    (function() { // North/South
      if ( current.direction.indexOf('s') !== -1 ) {
        nh = current.rectWindow.h + dy;

        newRect.height = Math.max(current.minHeight, nh);
      } else if ( current.direction.indexOf('n') !== -1 ) {
        nh = current.rectWindow.h - dy;
        nt = current.rectWindow.y + dy;

        if ( nt < current.rectWorkspace.top ) {
          nt = current.rectWorkspace.top;
          nh = newRect.height;
        } else {
          if ( nh < current.minHeight ) {
            nt = current.rectWindow.b - current.minHeight;
          }
        }

        newRect.height = Math.max(current.minHeight, nh);
        newRect.top = nt;
      }
    })();

    (function() { // East/West
      if ( current.direction.indexOf('e') !== -1 ) {
        nw = current.rectWindow.w + dx;

        newRect.width = Math.max(current.minWidth, nw);
      } else if ( current.direction.indexOf('w') !== -1 ) {
        nw = current.rectWindow.w - dx;
        nl = current.rectWindow.x + dx;

        if ( nw < current.minWidth ) {
          nl = current.rectWindow.r - current.minWidth;
        }

        newRect.width = Math.max(current.minWidth, nw);
        newRect.left = nl;
      }
    })();

    return newRect;
  }

  /*
   * Movement action
   */
  function onWindowMove(ev, mousePosition, dx, dy) {
    let newWidth = null;
    let newHeight = null;
    let newLeft = current.rectWindow.x + dx;
    let newTop = current.rectWindow.y + dy;

    const borderSize = current.theme.borderSize;
    const topMargin = current.theme.topMargin;
    const cornerSnapSize = current.snapping.cornerSize;
    const windowSnapSize = current.snapping.windowSize;

    if ( newTop < current.rectWorkspace.top ) {
      newTop = current.rectWorkspace.top;
    }

    let newRight = newLeft + current.rectWindow.w + (borderSize * 2);
    let newBottom = newTop + current.rectWindow.h + topMargin + (borderSize);

    // 8-directional corner window snapping
    if ( cornerSnapSize > 0 ) {
      if ( ((newLeft - borderSize) <= cornerSnapSize) && ((newLeft - borderSize) >= -cornerSnapSize) ) { // Left
        newLeft = borderSize;
      } else if ( (newRight >= (current.rectWorkspace.width - cornerSnapSize)) && (newRight <= (current.rectWorkspace.width + cornerSnapSize)) ) { // Right
        newLeft = current.rectWorkspace.width - current.rectWindow.w - borderSize;
      }
      if ( (newTop <= (current.rectWorkspace.top + cornerSnapSize)) && (newTop >= (current.rectWorkspace.top - cornerSnapSize)) ) { // Top
        newTop = current.rectWorkspace.top + (borderSize);
      } else if (
        (newBottom >= ((current.rectWorkspace.height + current.rectWorkspace.top) - cornerSnapSize)) &&
          (newBottom <= ((current.rectWorkspace.height + current.rectWorkspace.top) + cornerSnapSize))
      ) { // Bottom
        newTop = (current.rectWorkspace.height + current.rectWorkspace.top) - current.rectWindow.h - topMargin - borderSize;
      }
    }

    // Snapping to other windows
    if ( windowSnapSize > 0 ) {
      current.snapRects.every(function(rect) {
        // >
        if ( newRight >= (rect.left - windowSnapSize) && newRight <= (rect.left + windowSnapSize) ) { // Left
          newLeft = rect.left - (current.rectWindow.w + (borderSize * 2));
          return false;
        }

        // <
        if ( (newLeft - borderSize) <= (rect.right + windowSnapSize) && (newLeft - borderSize) >= (rect.right - windowSnapSize) ) { // Right
          newLeft = rect.right + (borderSize * 2);
          return false;
        }

        // \/
        if ( newBottom >= (rect.top - windowSnapSize) && newBottom <= (rect.top + windowSnapSize) ) { // Top
          newTop = rect.top - (current.rectWindow.h + (borderSize * 2) + topMargin);
          return false;
        }

        // /\
        if ( newTop <= (rect.bottom + windowSnapSize) && newTop >= (rect.bottom - windowSnapSize) ) { // Bottom
          newTop = rect.bottom + borderSize * 2;
          return false;
        }

        return true;
      });

    }

    return {left: newLeft, top: newTop, width: newWidth, height: newHeight};
  }

  /*
   * When mouse button is released
   */
  function onMouseUp(ev, action, win, mousePosition) {
    if ( !current ) {
      return;
    }

    if ( current.moved ) {
      if ( action === 'move' ) {
        win._onChange('move', true);
        win._emit('moved', [win._position.x, win._position.y]);
      } else if ( action === 'resize' ) {
        win._onChange('resize', true);
        win._emit('resized', [win._dimension.w, win._dimension.h]);
      }
    }

    current.$element.setAttribute('data-hint', '');
    document.body.setAttribute('data-window-hint', '');

    win._emit('postop');

    current = null;
  }

  /*
   * When mouse is moved
   */
  function onMouseMove(ev, action, win, mousePosition) {
    if ( !wm.getMouseLocked() || !action || !current ) {
      return;
    }

    ev.preventDefault();

    let result;

    const dx = mousePosition.x - current.startX;
    const dy = mousePosition.y - current.startY;

    if ( action === 'move' ) {
      result = onWindowMove(ev, mousePosition, dx, dy);
    } else {
      result = onWindowResize(ev, mousePosition, dx, dy);
    }

    if ( result ) {
      if ( result.left !== null && result.top !== null ) {
        win._move(result.left, result.top);
        win._emit('move', [result.left, result.top]);
      }
      if ( result.width !== null && result.height !== null ) {
        win._resize(result.width, result.height, true);
        win._emit('resize', [result.width, result.height]);
      }
    }

    current.moved = true;
  }

  /*
   * When mouse button is pressed
   */
  function onMouseDown(ev, action, win, mousePosition) {
    ev.preventDefault();

    if ( win._state.maximized ) {
      return;
    }

    current = new BehaviourState(wm, win, action, mousePosition);
    newRect = {};

    win._focus();

    if ( action === 'move' ) {
      current.$element.setAttribute('data-hint', 'moving');
      document.body.setAttribute('data-window-hint', 'moving');
    } else {
      current.calculateDirection();
      current.$element.setAttribute('data-hint', 'resizing');
      document.body.setAttribute('data-window-hint', 'resizing');

      newRect = current.getRect();
    }

    win._emit('preop');

    function _onMouseMove(ev, pos) {
      ev.preventDefault();
      if ( wm._mouselock ) {
        onMouseMove(ev, action, win, pos);
      }
    }
    function _onMouseUp(ev, pos) {
      onMouseUp(ev, action, win, pos);
      Events.$unbind(document, 'pointermove:movewindow,touchmove:movewindowTouch');
      Events.$unbind(document, 'pointerup:movewindowstop,touchend:movewindowstopTouch');
    }

    Events.$bind(document, 'pointermove:movewindow,touchmove:movewindowTouch', _onMouseMove, false);
    Events.$bind(document, 'pointerup:movewindowstop,touchend:movewindowstopTouch', _onMouseUp, false);
  }

  /*
   * Register a window
   */
  if ( win._properties.allow_move ) {
    Events.$bind(win._$top, 'pointerdown,touchstart', (ev, pos) => {
      ev.preventDefault();
      if ( !win._destroyed ) {
        onMouseDown(ev, 'move', win, pos);
      }
    }, true);
  }
  if ( win._properties.allow_resize ) {
    Events.$bind(win._$resize, 'pointerdown,touchstart', (ev, pos) => {
      ev.preventDefault();
      if ( !win._destroyed ) {
        onMouseDown(ev, 'resize', win, pos);
      }
    });
  }
}
<|endoftext|>


<commit_before>module.exports = publish

var config = require('../config.js')
  , blake = require('blake')
  , http = require('http')
  , pull = require('../pull.js')

function publish (req, res) {
  validate(req, function (isValid) {
    var code

    if (!isValid) {
      code = http.STATUS_CODES[400]
      res.writeHead(code)
      return res.end(code + '\n')
    }

    var source = config.source
      , target = config.target

    pull(source, function (err) {
      if (err) {
        console.error(err)
        code = http.STATUS_CODES[500]
        res.writeHead(code)
        return res.end(code + '\n')
      }

      blake(source, target, function (err) {
        code = http.STATUS_CODES[204]
        if (err) {
          console.error(err)
          code = http.STATUS_CODES[500]
        }
        res.writeHead(code)
        res.end(code + '\n')
      })
    })
  })
}

function isGitHub (address) {
  return iconfig.github.some(function (a) {
    return address === a
  })
}

function validate (req, callback) {
  if (req.method !== 'POST') return callback(false)

  var data = ''

  req.on('data', function (chunk) {
    data += chunk
  })

  req.on('end', function () {
    if (!data || !isGitHub(req.connection.remoteAddress)) {
      return callback(false)
    }

    var value = data.split('payload=')[1]
    if (!value) {
      return callback(false)
    }

    try {
      var payload = JSON.parse(unescape(value) || null)
    } catch(err) {
      return callback(false)
    }

    if (!payload) {
      return callback(false)
    }

    callback(true)
  })
}

<commit_msg>Fix typo<commit_after>module.exports = publish

var config = require('../config.js')
  , blake = require('blake')
  , http = require('http')
  , pull = require('../pull.js')

function publish (req, res) {
  validate(req, function (isValid) {
    var code

    if (!isValid) {
      code = http.STATUS_CODES[400]
      res.writeHead(code)
      return res.end(code + '\n')
    }

    var source = config.source
      , target = config.target

    pull(source, function (err) {
      if (err) {
        console.error(err)
        code = http.STATUS_CODES[500]
        res.writeHead(code)
        return res.end(code + '\n')
      }

      blake(source, target, function (err) {
        code = http.STATUS_CODES[204]
        if (err) {
          console.error(err)
          code = http.STATUS_CODES[500]
        }
        res.writeHead(code)
        res.end(code + '\n')
      })
    })
  })
}

function isGitHub (address) {
  return config.github.some(function (a) {
    return address === a
  })
}

function validate (req, callback) {
  if (req.method !== 'POST') return callback(false)

  var data = ''

  req.on('data', function (chunk) {
    data += chunk
  })

  req.on('end', function () {
    if (!data || !isGitHub(req.connection.remoteAddress)) {
      return callback(false)
    }

    var value = data.split('payload=')[1]
    if (!value) {
      return callback(false)
    }

    try {
      var payload = JSON.parse(unescape(value) || null)
    } catch(err) {
      return callback(false)
    }

    if (!payload) {
      return callback(false)
    }

    callback(true)
  })
}

<|endoftext|>