diff --git a/README.md b/README.md index 6dcc8a7..60a453f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # 8 Step - React/Redux tutorial series -This example application created by [getstream.io](https://getstream.io/?ref=github_stream_react_example) teaches you how to to build an Instagram style application with activity streams and newsfeeds. +This example application created by [getstream.io](https://getstream.io/?ref=github_stream_react_example) teaches you how to to build an Instagram style application with activity streams and newsfeeds. Visit [cabin.getstream.io](http://cabin.getstream.io/) for an overview of all 8 tutorials and a [live demo](http://cabin.getstream.io/demo). If you enjoy this tutorial please star this repo. +> Note: Cabin requires Node v8.x or above. +

Examples of what you can build

@@ -27,3 +29,51 @@ Visit [cabin.getstream.io](http://cabin.getstream.io/) for an overview of all 8 * [Mapbox](https://www.mapbox.com/) * [Digital Ocean](https://www.digitalocean.com/) * [Stream](https://getstream.io) + +## Quick start + +This quick start is a minimal set of instructions for experienced developers +and folks who have already setup their development environment in the past. + +For beginners and those new to the project, we strongly recommend starting with +the introductory [Cabin – React & Redux Example App – Introduction](https://getstream.io/blog/cabin-react-redux-example-app-introduction/) blog post. + +Note: Paths below are relative to the root project directory. + +### 0. Setup +1. Install the API package dependencies: + ``` bash + cd ./api && npm install + ``` + +2. Install the App package dependencies: + ``` bash + cd ./app && npm install + ``` + +3. Install a database server (if necessary) and create a database. +4. Set local environment configuration in the `.env` environment. + +### 1. Run the API +1. Start your database server +2. Run the following shell command: + ``` bash + cd ./api + source ../env.sh; node index.js + ``` + +### 2. Run the App +1. Run the following shell command: + ``` bash + cd ./app + source ../env.sh; webpack --watch --progress + ``` + +### 3. Run the Website +1. Run the following shell command: + ``` bash + npm start + ``` + +### 4. Win. +1. Browse to `http://localhost:3000`. diff --git a/api/config.js b/api/config.js index e6a3934..bda35ec 100644 --- a/api/config.js +++ b/api/config.js @@ -4,41 +4,41 @@ * Config */ module.exports = { - name: 'GetStream.io - React Example App', - version: '1.0.0', - env: process.env.NODE_ENV || 'development', - port: process.env.PORT || 8000, - jwt: { - secret: process.env.JWT_SECRET, - }, - db: { - name: 'cabin', - username: process.env.DB_USERNAME, - password: process.env.DB_PASSWORD, - host: process.env.DB_HOST, - port: process.env.DB_PORT, - }, - mapbox: { - accessToken: process.env.MAPBOX_ACCESS_TOKEN, - }, - s3: { - key: process.env.S3_KEY, - secret: process.env.S3_SECRET, - bucket: process.env.S3_BUCKET, - }, - stream: { - appId: process.env.STREAM_APP_ID, - key: process.env.STREAM_KEY, - secret: process.env.STREAM_SECRET, - }, - algolia: { - appId: process.env.ALGOLIA_APP_ID, - searchOnlyKey: process.env.ALGOLIA_SEARCH_ONLY_KEY, - apiKey: process.env.ALGOLIA_API_KEY, - }, - keen: { - projectId: process.env.KEEN_PROJECT_ID, - writeKey: process.env.KEEN_WRITE_KEY, - readKey: process.env.KEEN_READ_KEY, - }, + name: 'GetStream.io - React Example App', + version: '1.0.0', + env: process.env.NODE_ENV || 'development', + port: process.env.PORT || 8000, + jwt: { + secret: process.env.JWT_SECRET, + }, + db: { + name: 'cabin', + username: process.env.DB_USERNAME, + password: process.env.DB_PASSWORD, + host: process.env.DB_HOST, + port: process.env.DB_PORT, + }, + mapbox: { + accessToken: process.env.MAPBOX_ACCESS_TOKEN, + }, + s3: { + key: process.env.S3_KEY, + secret: process.env.S3_SECRET, + bucket: process.env.S3_BUCKET, + }, + stream: { + appId: process.env.STREAM_APP_ID, + key: process.env.STREAM_KEY, + secret: process.env.STREAM_SECRET, + }, + algolia: { + appId: process.env.ALGOLIA_APP_ID, + searchOnlyKey: process.env.ALGOLIA_SEARCH_ONLY_KEY, + apiKey: process.env.ALGOLIA_API_KEY, + }, + keen: { + projectId: process.env.KEEN_PROJECT_ID, + writeKey: process.env.KEEN_WRITE_KEY, + readKey: process.env.KEEN_READ_KEY, + }, }; diff --git a/api/index.js b/api/index.js index e329a7d..6d0022c 100644 --- a/api/index.js +++ b/api/index.js @@ -3,101 +3,104 @@ /** * Module Dependencies */ -var config = require('./config'), - bunyan = require('bunyan'), - winston = require('winston'), - bunyanWinston = require('bunyan-winston-adapter'), - mysql = require('mysql'), - jwt = require('restify-jwt'), - Mail = require('winston-mail').Mail, - Sentry = require('winston-sentry'); +var config = require('./config'), + bunyan = require('bunyan'), + winston = require('winston'), + bunyanWinston = require('bunyan-winston-adapter'), + mysql = require('mysql'), + jwt = require('restify-jwt'), + Mail = require('winston-mail').Mail, + Sentry = require('winston-sentry'), + restifyPlugins = require('restify-plugins'); /** * Global Dependencies */ -global.__base = __dirname + '/'; -global.config = require('./config.js'); +global.__base = __dirname + '/'; +global.config = require('./config.js'); global.restify = require('restify'); /** * Transports (Logging) */ var transports = [ - new winston.transports.Console({ - level: 'info', - timestamp: function() { - return new Date().toString(); - }, - json: true - }) + new winston.transports.Console({ + level: 'info', + timestamp: function() { + return new Date().toString(); + }, + json: true, + }), ]; /** * Sentry Transport (Logging) */ if (process.env.SENTRY) { - new winston.transports.Console({ level: 'silly' }), - new Sentry({ - patchGlobal: true, - dsn: process.env.SENTRY, - }) + new winston.transports.Console({ level: 'silly' }), new Sentry({ + patchGlobal: true, + dsn: process.env.SENTRY, + }); } /** * Logging */ global.log = new winston.Logger({ - transports: transports + transports: transports, }); /** * Initialize Server */ global.server = restify.createServer({ - name : config.name, - version : config.version, - log : bunyanWinston.createAdapter(log), + name: config.name, + version: config.version, + log: bunyanWinston.createAdapter(log), }); /** * Middleware */ -server.use(restify.bodyParser()); -server.use(restify.acceptParser(server.acceptable)); -server.use(restify.authorizationParser()); -server.use(restify.queryParser({ mapParams: true })); +server.use(restifyPlugins.jsonBodyParser({ mapParams: true })); +server.use(restifyPlugins.acceptParser(server.acceptable)); +server.use(restifyPlugins.queryParser({ mapParams: true })); +server.use(restifyPlugins.multipartBodyParser()); server.pre(require('./lib/cors')()); -server.use(restify.fullResponse()); -server.use(jwt({ secret: config.jwt.secret }).unless({ - path: ['/users'] -})); +server.use(restifyPlugins.fullResponse()); +server.use( + jwt({ secret: config.jwt.secret }).unless({ + path: ['/users'], + }), +); /** * Initialize MySQL Connection */ global.db = mysql.createConnection({ - host : config.db.host, - user : config.db.username, - password : config.db.password, - database : config.db.name, - timezone: 'UTC' + port: config.db.port, + host: config.db.host, + user: config.db.username, + password: config.db.password, + database: config.db.name, + timezone: 'UTC', }); db.connect(); db.query(` SET sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" -`) +`); /** * Boot */ -server.listen(config.port, function () { - require('./routes'); - log.info( - '%s v%s ready to accept connections on port listening on port %s in %s environment', - server.name, - config.version, - config.port, - config.env - ); +server.listen(config.port, function() { + require('./routes'); + log.info( + '%s v%s ready to accept connections on port listening on port %s in %s environment', + server.name, + config.version, + config.port, + config.env, + ); }); diff --git a/api/lib/cors/index.js b/api/lib/cors/index.js index 42d330f..8024a11 100644 --- a/api/lib/cors/index.js +++ b/api/lib/cors/index.js @@ -1,42 +1,61 @@ -'use strict'; - function cors(options) { - - const defaultAllowHeaders = ['Authorization', 'Content-Type']; - const defaultAllowMethods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD"]; - - const opts = Object.assign({}, { - allowHeaders: defaultAllowHeaders, - allowMethods: defaultAllowMethods, - allowOrigins: null, - allowCreds: true, - }, options || {}); - - const setHeader = (req, res, methods) => { - const origin = req.headers.origin; - const requestMethod = req.headers['access-control-request-method']; - const requestHeaders = req.headers['access-control-request-headers']; - - res.once('header', () => { - if (opts.allowCreds) res.header('Access-Control-Allow-Credentials', 'true'); - - if (opts.allowOrigins) { - res.header('Access-Control-Allow-Origin', - (Array.isArray(opts.allowOrigins)) ? opts.allowOrigins.join(', ') : opts.allowOrigins); - } else { - res.header('Access-Control-Allow-Origin', origin); - } - - res.header('Access-Control-Allow-Methods', opts.allowMethods.join(', ')); - res.header('Access-Control-Allow-Headers', opts.allowHeaders.map(h => h.toUpperCase()).join(', ')); - }); - }; - - return (req, res, next) => { - setHeader(req, res); - if (req.method == 'OPTIONS') return res.send(200); - return next(); - }; -}; + const defaultAllowHeaders = ['Authorization', 'Content-Type']; + const defaultAllowMethods = [ + 'GET', + 'POST', + 'PUT', + 'DELETE', + 'PATCH', + 'HEAD', + ]; + + const opts = Object.assign( + {}, + { + allowHeaders: defaultAllowHeaders, + allowMethods: defaultAllowMethods, + allowOrigins: null, + allowCreds: true, + }, + options || {}, + ); + + const setHeader = (req, res, methods) => { + const origin = req.headers.origin; + const requestMethod = req.headers['access-control-request-method']; + const requestHeaders = req.headers['access-control-request-headers']; + + res.once('header', () => { + if (opts.allowCreds) + res.header('Access-Control-Allow-Credentials', 'true'); + + if (opts.allowOrigins) { + res.header( + 'Access-Control-Allow-Origin', + Array.isArray(opts.allowOrigins) + ? opts.allowOrigins.join(', ') + : opts.allowOrigins, + ); + } else { + res.header('Access-Control-Allow-Origin', origin); + } + + res.header( + 'Access-Control-Allow-Methods', + opts.allowMethods.join(', '), + ); + res.header( + 'Access-Control-Allow-Headers', + opts.allowHeaders.map(h => h.toUpperCase()).join(', '), + ); + }); + }; + + return (req, res, next) => { + setHeader(req, res); + if (req.method == 'OPTIONS') return res.send(200); + return next(); + }; +} module.exports = cors; diff --git a/api/lib/stream_utils/index.js b/api/lib/stream_utils/index.js index 8f8543d..84ea5ae 100644 --- a/api/lib/stream_utils/index.js +++ b/api/lib/stream_utils/index.js @@ -1,40 +1,39 @@ -'use strict'; var async = require('async'); function referencesFromActivities(activitiesOrNotifications) { - /* + /* Returns the references from a list of activities */ - var references = {} - activitiesOrNotifications.forEach(function(item) { - var activities = (item.activities) ? item.activities : [ - item - ]; - activities.forEach(function(activity) { - Object.keys(activity).forEach(function(key) { - if (activity[key] && activity[key].indexOf && activity[key].indexOf(':') != -1) { - var parts = activity[key].split(':'); - var reference = parts[0]; - var referenceId = parts[1]; - if (!(reference in references)) { - references[reference] = {}; - } - references[reference][ - referenceId - ] = 1; - } - }); - }); - }); - return references; -}; + var references = {}; + activitiesOrNotifications.forEach(function(item) { + var activities = item.activities ? item.activities : [item]; + activities.forEach(function(activity) { + Object.keys(activity).forEach(function(key) { + if ( + activity[key] && + activity[key].indexOf && + activity[key].indexOf(':') != -1 + ) { + var parts = activity[key].split(':'); + var reference = parts[0]; + var referenceId = parts[1]; + if (!(reference in references)) { + references[reference] = {}; + } + references[reference][referenceId] = 1; + } + }); + }); + }); + return references; +} function loadReferencedObjects(references, userId, callback) { - // TODO: subqueries are inneficient. Handle do i like and do i follow - // in 2 separate queries - var queries = []; - if (references.upload) { - let sql = ` + // TODO: subqueries are inneficient. Handle do i like and do i follow + // in 2 separate queries + var queries = []; + if (references.upload) { + let sql = ` SELECT uploads.id AS id, users.id AS user_id, @@ -51,14 +50,14 @@ function loadReferencedObjects(references, userId, callback) { LEFT JOIN users ON (uploads.user_id = users.id) WHERE uploads.id IN (?) `; - queries.push({ - 'name': 'upload', - 'sql': sql - }); - } - if (references.user) { - // do the same thing for users - let sql = ` + queries.push({ + name: 'upload', + sql: sql, + }); + } + if (references.user) { + // do the same thing for users + let sql = ` SELECT users.id AS id, users.id AS user_id, @@ -79,52 +78,67 @@ function loadReferencedObjects(references, userId, callback) { FROM users WHERE users.id IN (?) `; - queries.push({ - 'name': 'user', - 'sql': sql - }); - } - var referencedObject = {}; - // run all the queries - async.eachSeries(queries, function iteratee(query, cb) { - db.query(query.sql, [userId, Object.keys(references[query.name])], function(err, results) { - if (err) { - cb(err); - } - referencedObject[query.name] = {}; - results.forEach(function(result) { - referencedObject[query.name][result.id] = result; - }); - cb(); - }); - }, function done() { - callback(referencedObject); - }); + queries.push({ + name: 'user', + sql: sql, + }); + } + var referencedObject = {}; + // run all the queries + async.eachSeries( + queries, + function iteratee(query, cb) { + db.query( + query.sql, + [userId, Object.keys(references[query.name])], + function(err, results) { + if (err) { + cb(err); + } + referencedObject[query.name] = {}; + results.forEach(function(result) { + referencedObject[query.name][result.id] = result; + }); + cb(); + }, + ); + }, + function done() { + callback(referencedObject); + }, + ); } function enrichActivities(activitiesOrNotifications, refencedObjects) { - /* + /* * Enriches the activities by replacing references with the actual objects */ - activitiesOrNotifications.forEach(function(item) { - var activities = (item.activities) ? item.activities : [item]; - activities.forEach(function(activity) { - Object.keys(activity).forEach(function(key) { - if (activity[key] && activity[key].indexOf && activity[key].indexOf(':') != -1) { - var parts = activity[key].split(':'); - var reference = parts[0]; - var referenceId = parts[1]; - if (reference in refencedObjects && refencedObjects[reference][referenceId]) { - activity[key] = refencedObjects[reference][referenceId]; - } - } - }); - }); - }); -}; + activitiesOrNotifications.forEach(function(item) { + var activities = item.activities ? item.activities : [item]; + activities.forEach(function(activity) { + Object.keys(activity).forEach(function(key) { + if ( + activity[key] && + activity[key].indexOf && + activity[key].indexOf(':') != -1 + ) { + var parts = activity[key].split(':'); + var reference = parts[0]; + var referenceId = parts[1]; + if ( + reference in refencedObjects && + refencedObjects[reference][referenceId] + ) { + activity[key] = refencedObjects[reference][referenceId]; + } + } + }); + }); + }); +} module.exports = { - 'referencesFromActivities': referencesFromActivities, - 'loadReferencedObjects': loadReferencedObjects, - 'enrichActivities': enrichActivities + referencesFromActivities: referencesFromActivities, + loadReferencedObjects: loadReferencedObjects, + enrichActivities: enrichActivities, }; diff --git a/api/package-lock.json b/api/package-lock.json new file mode 100644 index 0000000..49b739c --- /dev/null +++ b/api/package-lock.json @@ -0,0 +1,1765 @@ +{ + "name": "api", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "addressparser": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-0.3.2.tgz", + "integrity": "sha1-WYc/Nej89sc2HBAjkmHXbhU0i7I=" + }, + "agentkeepalive": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.2.0.tgz", + "integrity": "sha1-xdG9SxKQCPEWPyNvhuX66iAm4u8=" + }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "algoliasearch": { + "version": "3.24.3", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-3.24.3.tgz", + "integrity": "sha512-k9MM+dSUqrT180gtC5rWowvt9t+DTM7SvQIOfPczZKT971bGn9PUYmOlBVOW0gSW81QxOgC/PbLMvsIXdh2Q4w==", + "requires": { + "agentkeepalive": "2.2.0", + "debug": "2.6.8", + "envify": "4.1.0", + "es6-promise": "4.1.1", + "events": "1.1.1", + "foreach": "2.0.5", + "global": "4.3.2", + "inherits": "2.0.3", + "isarray": "2.0.2", + "load-script": "1.0.0", + "object-keys": "1.0.11", + "querystring-es3": "0.2.1", + "reduce": "1.0.1", + "semver": "5.4.1", + "tunnel-agent": "0.6.0" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" + }, + "async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", + "requires": { + "lodash": "4.17.4" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "2.5.0", + "regenerator-runtime": "0.11.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "optional": true + }, + "Base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/Base64/-/Base64-1.0.1.tgz", + "integrity": "sha1-3vRcxQyWG8yb8jIdD1K8v+wfG7E=" + }, + "base64url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz", + "integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs=" + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "bignumber.js": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.0.2.tgz", + "integrity": "sha1-LR3DfuWWiGfs6pC22k0W5oYI0h0=" + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "optional": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "bufferjs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bufferjs/-/bufferjs-1.1.0.tgz", + "integrity": "sha1-CV/6OcXmtAoheKEWnJ7/xYSnMgE=", + "optional": true + }, + "bunyan": { + "version": "1.8.12", + "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", + "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", + "requires": { + "dtrace-provider": "0.8.5", + "moment": "2.18.1", + "mv": "2.1.1", + "safe-json-stringify": "1.0.4" + } + }, + "bunyan-winston-adapter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bunyan-winston-adapter/-/bunyan-winston-adapter-0.2.0.tgz", + "integrity": "sha1-lQMQYzQFq15l/bf+528Y/mqZj80=" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "clone-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-1.0.0.tgz", + "integrity": "sha1-6uCiQT9VwJQvgYwin+/OhF1/Oxw=", + "requires": { + "is-regexp": "1.0.0", + "is-supported-regexp-flag": "1.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "component-emitter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", + "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "optional": true + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookiejar": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.0.1.tgz", + "integrity": "sha1-PRJ1L2rfaKiS8zJDNJK9WBK7Zo8=" + }, + "core-decorators": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/core-decorators/-/core-decorators-0.17.0.tgz", + "integrity": "sha1-P0MYCobSqwzFEGn0ah7D5J5869Y=" + }, + "core-js": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.0.tgz", + "integrity": "sha1-VpwFCRi+ZIazg3VSAorgRmtxcIY=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "requires": { + "boom": "2.10.1" + } + }, + "csprng": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/csprng/-/csprng-0.1.2.tgz", + "integrity": "sha1-S8aPEvo2jSUqWYQcusqXSxirReI=", + "requires": { + "sequin": "0.1.1" + } + }, + "csv": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/csv/-/csv-1.1.1.tgz", + "integrity": "sha1-2ZUtWbH5ZKevvN2ATWgYpzGZpHc=", + "requires": { + "csv-generate": "1.0.0", + "csv-parse": "1.2.1", + "csv-stringify": "1.0.4", + "stream-transform": "0.1.2" + } + }, + "csv-generate": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-1.0.0.tgz", + "integrity": "sha1-vVKIaFnQySXz5R9g86vtJi+hXK8=" + }, + "csv-parse": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.2.1.tgz", + "integrity": "sha1-kZnCPySQ2YxNmrKgFnsGknSYyd8=" + }, + "csv-stringify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-1.0.4.tgz", + "integrity": "sha1-vBi6ua1M7zGV/SV5gLWLR5xC0+U=", + "requires": { + "lodash.get": "4.4.2" + } + }, + "ctype": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", + "integrity": "sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8=" + }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "requires": { + "ms": "2.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "detect-node": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz", + "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc=" + }, + "dom-walk": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", + "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" + }, + "dtrace-provider": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.5.tgz", + "integrity": "sha1-mOu6Ihr6xG4cOf02hY2Pk2dSS5I=", + "optional": true, + "requires": { + "nan": "2.6.2" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz", + "integrity": "sha1-S8kmJ07Dtau1AW5+HWCSGsJisqE=", + "requires": { + "base64url": "2.0.0", + "safe-buffer": "5.1.1" + } + }, + "emailjs": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/emailjs/-/emailjs-1.0.12.tgz", + "integrity": "sha1-vWVZxRxJYxJSGGJtoJi+ci96HHI=", + "requires": { + "addressparser": "0.3.2", + "bufferjs": "1.1.0", + "mimelib": "0.2.14", + "moment": "2.15.2", + "starttls": "1.0.1" + }, + "dependencies": { + "moment": { + "version": "2.15.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.15.2.tgz", + "integrity": "sha1-G/3t9qbjRfMi/pVtXfW9CKjOhNw=" + } + } + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "0.4.18" + } + }, + "envify": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/envify/-/envify-4.1.0.tgz", + "integrity": "sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw==", + "requires": { + "esprima": "4.0.0", + "through": "2.3.8" + } + }, + "es6-promise": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.1.1.tgz", + "integrity": "sha512-OaU1hHjgJf+b0NzsxCg7NdIYERD6Hy/PEmFLTjw+b65scuisG3Kt4QoTvJ66BBkPZ581gr0kpoVzKnxniM8nng==" + }, + "escape-regexp-component": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-regexp-component/-/escape-regexp-component-1.0.2.tgz", + "integrity": "sha1-nGO20LJf8qiMOtvRjFthrMO5+qI=" + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + }, + "express-unless": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-0.3.1.tgz", + "integrity": "sha1-JVfBRudb65A+LSR/m1ugFFJpbiA=" + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, + "faye": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/faye/-/faye-1.2.4.tgz", + "integrity": "sha1-l47YpY8dSB5cH5i6y4lZ3l7FxkM=", + "requires": { + "asap": "2.0.6", + "csprng": "0.1.2", + "faye-websocket": "0.11.1", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0" + } + }, + "faye-websocket": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", + "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", + "requires": { + "websocket-driver": "0.6.5" + } + }, + "fb": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb/-/fb-2.0.0.tgz", + "integrity": "sha1-kf1AMl2jTsQcaLJVMPw6Pg2s+mo=", + "requires": { + "any-promise": "1.3.0", + "babel-runtime": "6.26.0", + "core-decorators": "0.17.0", + "debug": "2.6.8", + "request": "2.81.0" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.16" + } + }, + "formidable": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz", + "integrity": "sha1-Kz9MQRy7X91pXESEPiojUUpDIxo=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "getstream": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/getstream/-/getstream-3.5.0.tgz", + "integrity": "sha1-frkgbCAtQl5LX4d8i8qxtk4j6v8=", + "requires": { + "Base64": "1.0.1", + "faye": "1.2.4", + "http-signature": "1.1.1", + "jsonwebtoken": "5.0.1", + "qs": "6.4.0", + "request": "2.81.0", + "xmlhttp-request": "0.4.1" + }, + "dependencies": { + "jsonwebtoken": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-5.0.1.tgz", + "integrity": "sha1-XYXOWAQhkVviLkqnsT1LuZsoCio=", + "requires": { + "jws": "3.1.4" + } + } + } + }, + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "optional": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "global": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", + "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", + "requires": { + "min-document": "2.19.0", + "process": "0.5.2" + } + }, + "handle-thing": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", + "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=" + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "requires": { + "inherits": "2.0.3", + "obuf": "1.1.1", + "readable-stream": "2.3.3", + "wbuf": "1.7.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "iconv-lite": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", + "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "optional": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" + }, + "is-supported-regexp-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.0.tgz", + "integrity": "sha1-i1IMhfrnolM4LUsCZS4EVXbhO7g=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isarray": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.2.tgz", + "integrity": "sha512-DKCXsIpN+352zm3Sd75dY9HyaIcxU6grh118GhTPXc85jJ5nEGKOsPQOwSuE7aRd+XVRcC/Em6W44onQEQ9RBg==" + }, + "isemail": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", + "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "joi": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", + "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", + "requires": { + "hoek": "2.16.3", + "isemail": "1.2.0", + "moment": "2.18.1", + "topo": "1.1.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsonwebtoken": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.4.3.tgz", + "integrity": "sha1-d/UCHeBYtgWheD+hKD6ZgS5kVjg=", + "requires": { + "joi": "6.10.1", + "jws": "3.1.4", + "lodash.once": "4.1.1", + "ms": "2.0.0", + "xtend": "4.0.1" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "jwa": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz", + "integrity": "sha1-oFUs4CIHQs1S4VN3SjKQXDDnVuU=", + "requires": { + "base64url": "2.0.0", + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.9", + "safe-buffer": "5.1.1" + } + }, + "jws": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz", + "integrity": "sha1-+ei5M46KhHJ31kRLFGT2GIDgUKI=", + "requires": { + "base64url": "2.0.0", + "jwa": "1.1.5", + "safe-buffer": "5.1.1" + } + }, + "keen.io": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/keen.io/-/keen.io-0.1.3.tgz", + "integrity": "sha1-UFb1yYmrFMz2L8IO11mBFa59CeM=", + "requires": { + "superagent": "0.21.0", + "underscore": "1.5.2" + } + }, + "knox": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/knox/-/knox-0.9.2.tgz", + "integrity": "sha1-NzZZNmniTwJP2vcjtqHcSv2DmnE=", + "requires": { + "debug": "1.0.5", + "mime": "1.2.11", + "once": "1.4.0", + "stream-counter": "1.0.0", + "xml2js": "0.4.19" + }, + "dependencies": { + "debug": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.5.tgz", + "integrity": "sha1-9yQSF0MPmd7EwrRz6rkiKOh0wqw=", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "load-script": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", + "integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ=" + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "lsmod": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lsmod/-/lsmod-1.0.0.tgz", + "integrity": "sha1-mgD3bco26yP6BTUK/htYXUKZ5ks=" + }, + "mapbox-geocoding": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/mapbox-geocoding/-/mapbox-geocoding-0.1.4.tgz", + "integrity": "sha1-XuNIfPTSGIdRmFU+7J4qz4GSak4=", + "requires": { + "request": "2.81.0" + } + }, + "methods": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.0.1.tgz", + "integrity": "sha1-dbyRlD3/19oDfPPusO1zoAN80Us=" + }, + "mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=" + }, + "mime-db": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz", + "integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg=" + }, + "mime-types": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", + "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=", + "requires": { + "mime-db": "1.29.0" + } + }, + "mimelib": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/mimelib/-/mimelib-0.2.14.tgz", + "integrity": "sha1-KhqnJL0ZC4W9Um5jF6thBu39aDE=", + "requires": { + "addressparser": "0.2.1", + "encoding": "0.1.12" + }, + "dependencies": { + "addressparser": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-0.2.1.tgz", + "integrity": "sha1-0RpbLu2gTP7+vfMZbBCuE9ts1gc=" + } + } + }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "requires": { + "dom-walk": "0.1.1" + } + }, + "minimalistic-assert": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", + "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "optional": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "optional": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "moment": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", + "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mustache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz", + "integrity": "sha1-QCj3d4sXcIpImTCm5SrDvKDaQdA=" + }, + "mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "optional": true, + "requires": { + "mkdirp": "0.5.1", + "ncp": "2.0.0", + "rimraf": "2.4.5" + } + }, + "mysql": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.14.1.tgz", + "integrity": "sha512-ZPXqQeYH7L1QPDyC77Rcp32cNCQnNjz8Y4BbF17tOjm5yhSfjFa3xS4PvuxWJtEEmwVc4ccI7sSntj4eyYRq0A==", + "requires": { + "bignumber.js": "4.0.2", + "readable-stream": "2.3.3", + "safe-buffer": "5.1.1", + "sqlstring": "2.2.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "nan": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", + "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=", + "optional": true + }, + "ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "optional": true + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=" + }, + "obuf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.1.tgz", + "integrity": "sha1-EEEktsYCxnlogaBCVB0220OlJk4=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "optional": true + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" + }, + "process": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", + "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "raven": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/raven/-/raven-2.1.2.tgz", + "integrity": "sha512-pBopqPVAuzEP5jyyqEPxJvXg788dAJ9p8NXoHVLF598Ih7MApu2AWT/QHNk2Fa4Rx/xV9yTYDEtAujLXX1FvRg==", + "requires": { + "cookie": "0.3.1", + "json-stringify-safe": "5.0.1", + "lsmod": "1.0.0", + "stack-trace": "0.0.9", + "timed-out": "4.0.1", + "uuid": "3.0.0" + }, + "dependencies": { + "stack-trace": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", + "integrity": "sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU=" + }, + "uuid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz", + "integrity": "sha1-Zyj8BFnEUNeWqZwxg3VpvfZy1yg=" + } + } + }, + "readable-stream": { + "version": "1.0.27-1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.27-1.tgz", + "integrity": "sha1-a2eYPCA1fO/QfwFlABoW1xDZEHg=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, + "reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/reduce/-/reduce-1.0.1.tgz", + "integrity": "sha1-FPouX/H8VgcDoCDLtfuqtpFWWAQ=", + "requires": { + "object-keys": "1.0.11" + } + }, + "reduce-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/reduce-component/-/reduce-component-1.0.1.tgz", + "integrity": "sha1-4Mk1QsV0UhvqE98PlIjtgqt3xdo=" + }, + "regenerator-runtime": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==" + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.16", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + }, + "dependencies": { + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + } + } + }, + "restify": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/restify/-/restify-5.2.0.tgz", + "integrity": "sha1-9xMxAu85WKVtpC92BBURKnigGCI=", + "requires": { + "assert-plus": "1.0.0", + "bunyan": "1.8.12", + "clone-regexp": "1.0.0", + "csv": "1.1.1", + "dtrace-provider": "0.8.5", + "escape-regexp-component": "1.0.2", + "formidable": "1.1.1", + "http-signature": "1.1.1", + "lodash": "4.17.4", + "lru-cache": "4.1.1", + "mime": "1.2.11", + "negotiator": "0.6.1", + "once": "1.4.0", + "qs": "6.4.0", + "restify-errors": "4.3.0", + "semver": "5.4.1", + "spdy": "3.4.7", + "uuid": "3.1.0", + "vasync": "1.6.4", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "formidable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", + "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=" + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + } + } + }, + "restify-errors": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/restify-errors/-/restify-errors-4.3.0.tgz", + "integrity": "sha1-7JDzCTTX8xGRNRgd/DA+ML5gGr4=", + "requires": { + "assert-plus": "1.0.0", + "lodash": "4.17.4", + "safe-json-stringify": "1.0.4", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "restify-jwt": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/restify-jwt/-/restify-jwt-0.4.0.tgz", + "integrity": "sha1-IidMjObvbm5rtQdLOB8rV7/3vR8=", + "requires": { + "async": "0.9.2", + "express-unless": "0.3.1", + "jsonwebtoken": "5.7.0" + }, + "dependencies": { + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + }, + "jsonwebtoken": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-5.7.0.tgz", + "integrity": "sha1-HJD5qGzlt0j1+XnBK3BAK0r83bQ=", + "requires": { + "jws": "3.1.4", + "ms": "0.7.3", + "xtend": "4.0.1" + } + }, + "ms": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz", + "integrity": "sha1-cIFVpeROM/X9D8U+gdDUCpG+H/8=" + } + } + }, + "restify-plugins": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/restify-plugins/-/restify-plugins-1.6.0.tgz", + "integrity": "sha1-eeEYiHt/DrAuZFeA+cVoDLermqk=", + "requires": { + "assert-plus": "1.0.0", + "bunyan": "1.8.12", + "csv": "1.1.1", + "escape-regexp-component": "1.0.2", + "formidable": "1.1.1", + "http-signature": "0.11.0", + "lru-cache": "4.1.1", + "mime": "1.4.0", + "once": "1.4.0", + "qs": "6.4.0", + "restify-errors": "4.3.0", + "vasync": "1.6.4" + }, + "dependencies": { + "asn1": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", + "integrity": "sha1-VZvhg3bQik7E2+gId9J4GGObLfc=" + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "formidable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", + "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=" + }, + "http-signature": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz", + "integrity": "sha1-F5bPZ6ABrVzWhJ3KCZFIXwkIn+Y=", + "requires": { + "asn1": "0.1.11", + "assert-plus": "0.1.5", + "ctype": "0.5.3" + }, + "dependencies": { + "assert-plus": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", + "integrity": "sha1-7nQAlBMALYTOxyGcasgRgS5yMWA=" + } + } + }, + "mime": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.0.tgz", + "integrity": "sha512-n9ChLv77+QQEapYz8lV+rIZAW3HhAPW2CXnzb1GN5uMkuczshwvkW7XPsbzU0ZQN3sP47Er2KVkp2p3KyqZKSQ==" + } + } + }, + "rimraf": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "optional": true, + "requires": { + "glob": "6.0.4" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "safe-json-stringify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.0.4.tgz", + "integrity": "sha1-gaCY9Efku8P/MxKiQ1IbwGDvWRE=", + "optional": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" + }, + "sequin": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/sequin/-/sequin-0.1.1.tgz", + "integrity": "sha1-XC04nWajg3NOqvvEXt6ywcsb5wE=" + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "requires": { + "hoek": "2.16.3" + } + }, + "spdy": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", + "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", + "requires": { + "debug": "2.6.8", + "handle-thing": "1.2.5", + "http-deceiver": "1.2.7", + "safe-buffer": "5.1.1", + "select-hose": "2.0.0", + "spdy-transport": "2.0.20" + } + }, + "spdy-transport": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.0.20.tgz", + "integrity": "sha1-c15yBUxIayNU/onnAiVgBKOazk0=", + "requires": { + "debug": "2.6.8", + "detect-node": "2.0.3", + "hpack.js": "2.1.6", + "obuf": "1.1.1", + "readable-stream": "2.3.3", + "safe-buffer": "5.1.1", + "wbuf": "1.7.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "sqlstring": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.2.0.tgz", + "integrity": "sha1-wxNcTqirzX5+50GklmqJHYak8ZE=" + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "starttls": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/starttls/-/starttls-1.0.1.tgz", + "integrity": "sha1-5ggcJd5rF49adfjyccFIdEkYO0I=" + }, + "stream-counter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-1.0.0.tgz", + "integrity": "sha1-kc8lac5NxQYf6816yyY5SloRR1E=" + }, + "stream-transform": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-0.1.2.tgz", + "integrity": "sha1-fY5rTgOsR4F3j4x5UXUBv7B2Kp8=" + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "superagent": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-0.21.0.tgz", + "integrity": "sha1-+xUCeYR1HucVIgDmzSHNbhml3oc=", + "requires": { + "component-emitter": "1.1.2", + "cookiejar": "2.0.1", + "debug": "2.6.8", + "extend": "1.2.1", + "form-data": "0.1.3", + "formidable": "1.0.14", + "methods": "1.0.1", + "mime": "1.2.11", + "qs": "1.2.0", + "readable-stream": "1.0.27-1", + "reduce-component": "1.0.1" + }, + "dependencies": { + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + }, + "combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8=", + "requires": { + "delayed-stream": "0.0.5" + } + }, + "delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8=" + }, + "extend": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz", + "integrity": "sha1-oPX9bPyDpf5J72mNYOyKYk3UV2w=" + }, + "form-data": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.3.tgz", + "integrity": "sha1-TuQ0bm61Ni6DRKAgdb2NvYxzc+o=", + "requires": { + "async": "0.9.2", + "combined-stream": "0.0.7", + "mime": "1.2.11" + } + }, + "qs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-1.2.0.tgz", + "integrity": "sha1-7Qeb4oaCFH5v2aNMwrDB4OxkU+4=" + } + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + }, + "topo": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", + "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", + "requires": { + "hoek": "2.16.3" + } + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "underscore": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.5.2.tgz", + "integrity": "sha1-EzXF5PXm0zu7SwBrqMhqAPVW3gg=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "vasync": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/vasync/-/vasync-1.6.4.tgz", + "integrity": "sha1-3+k2Fq0OeugBszKp2Iv8XNyOHR8=", + "requires": { + "verror": "1.6.0" + }, + "dependencies": { + "extsprintf": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.2.0.tgz", + "integrity": "sha1-WtlGwi9bMrp/jNdCZxHG6KP8JSk=" + }, + "verror": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.6.0.tgz", + "integrity": "sha1-fROyex+swuLakEBetepuW90lLqU=", + "requires": { + "extsprintf": "1.2.0" + } + } + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "wbuf": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.2.tgz", + "integrity": "sha1-1pe5nx9ZUS3ydRvkJ2nBWAtYAf4=", + "requires": { + "minimalistic-assert": "1.0.0" + } + }, + "websocket-driver": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", + "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", + "requires": { + "websocket-extensions": "0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz", + "integrity": "sha1-domUmcGEtu91Q3fC27DNbLVdKec=" + }, + "winston": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.3.1.tgz", + "integrity": "sha1-C0hCDZeMAYBM8CMLZIhhWYIloRk=", + "requires": { + "async": "1.0.0", + "colors": "1.0.3", + "cycle": "1.0.3", + "eyes": "0.1.8", + "isstream": "0.1.2", + "stack-trace": "0.0.10" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" + } + } + }, + "winston-mail": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/winston-mail/-/winston-mail-1.3.0.tgz", + "integrity": "sha1-ELBXArc86fLpszKaUi6Ytu1NzcA=", + "requires": { + "emailjs": "1.0.12", + "mustache": "2.3.0" + } + }, + "winston-sentry": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/winston-sentry/-/winston-sentry-0.2.1.tgz", + "integrity": "sha1-39zIKPNac1qOAeeBkYr2UuuXx1w=", + "requires": { + "lodash": "4.17.4", + "raven": "1.2.1" + }, + "dependencies": { + "raven": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/raven/-/raven-1.2.1.tgz", + "integrity": "sha1-lJwTTbAooZC3u/j3kKrlQbfAIL0=", + "requires": { + "cookie": "0.3.1", + "json-stringify-safe": "5.0.1", + "lsmod": "1.0.0", + "stack-trace": "0.0.9", + "uuid": "3.0.0" + } + }, + "stack-trace": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", + "integrity": "sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU=" + }, + "uuid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz", + "integrity": "sha1-Zyj8BFnEUNeWqZwxg3VpvfZy1yg=" + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "requires": { + "sax": "1.2.4", + "xmlbuilder": "9.0.4" + } + }, + "xmlbuilder": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz", + "integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=" + }, + "xmlhttp-request": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/xmlhttp-request/-/xmlhttp-request-0.4.1.tgz", + "integrity": "sha1-Y22ZNVqR4YZbOOoDkJndxZr2p6c=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } +} diff --git a/api/package.json b/api/package.json index 935da31..ea8dd63 100644 --- a/api/package.json +++ b/api/package.json @@ -1,44 +1,46 @@ { - "name": "api", - "version": "1.0.0", - "description": "", - "main": "index.js", - "dependencies": { - "algoliasearch": "^3.15.0", - "async": "^2.0.0-rc.6", - "bunyan": "^1.8.10", - "bunyan-winston-adapter": "^0.2.0", - "fb": "^1.1.1", - "getstream": "^3.2.0", - "jsonwebtoken": "^7.0.0", - "keen.io": "^0.1.3", - "knox": "^0.9.2", - "mapbox-geocoding": "^0.1.4", - "mysql": "^2.11.1", - "node-uuid": "^1.4.7", - "raven": "^1.2.0", - "restify": "^4.1.0", - "restify-jwt": "^0.4.0", - "stack-trace": "^0.0.9", - "winston": "^2.2.0", - "winston-mail": "^1.2.0", - "winston-sentry": "^0.1.4" - }, - "devDependencies": {}, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/GetStream/stream-react-example.git" - }, - "keywords": [ - "GetStream" - ], - "author": "Nick Parsons ", - "license": "ISC", - "bugs": { - "url": "https://github.com/GetStream/stream-react-example/issues" - }, - "homepage": "https://github.com/GetStream/stream-react-example#readme" + "name": "api", + "version": "1.0.0", + "description": "", + "main": "index.js", + "engines": { + "node": "9.x" + }, + "dependencies": { + "algoliasearch": "^3.24.9", + "async": "^2.6.0", + "bunyan": "^1.8.12", + "bunyan-winston-adapter": "^0.2.0", + "fb": "^2.0.0", + "getstream": "^3.10.0", + "jsonwebtoken": "^8.1.0", + "keen.io": "^0.1.3", + "knox": "^0.9.2", + "mapbox-geocoding": "^0.1.5", + "mysql": "^2.15.0", + "node-uuid": "^1.4.8", + "raven": "^2.3.0", + "restify": "^6.3.4", + "restify-jwt": "^0.4.0", + "restify-plugins": "^1.6.0", + "stack-trace": "^0.0.10", + "winston": "^2.4.0", + "winston-mail": "^1.3.0", + "winston-sentry": "^0.2.1" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/GetStream/stream-react-example.git" + }, + "keywords": ["GetStream"], + "author": "Nick Parsons ", + "license": "ISC", + "bugs": { + "url": "https://github.com/GetStream/stream-react-example/issues" + }, + "homepage": "https://github.com/GetStream/stream-react-example#readme" } diff --git a/api/routes/active.js b/api/routes/active.js index 57c1171..10e28a1 100644 --- a/api/routes/active.js +++ b/api/routes/active.js @@ -1,11 +1,10 @@ 'use strict'; server.get('/active', function(req, res, next) { + // extract query params + var params = req.params || {}; - // extract query params - var params = req.params || {}; - - var sql = ` + var sql = ` SELECT users.id AS id, users.first_name AS first_name, @@ -30,24 +29,18 @@ server.get('/active', function(req, res, next) { LIMIT 3 `; - db.query(sql, [params.user_id, params.user_id], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // send response to client - res.send(200, result); - return next(); - - }); + db.query(sql, [params.user_id, params.user_id], function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + // return error message to client + return next(new restify.InternalError(err.message)); + } + // send response to client + res.send(200, result); + return next(); + }); }); diff --git a/api/routes/comments.js b/api/routes/comments.js index f45a4f8..b23aa8a 100644 --- a/api/routes/comments.js +++ b/api/routes/comments.js @@ -3,10 +3,10 @@ /** * Module Dependencies */ -var async = require('async'), - stream = require('getstream'), - jwt = require('restify-jwt'), - config = require('../config'); +var async = require('async'), + stream = require('getstream'), + jwt = require('restify-jwt'), + config = require('../config'); /** * Get all comments (optionally for a specific upload id) @@ -17,12 +17,11 @@ var async = require('async'), * @returns {array} Returns a 200 status code with an array of comment objects */ server.get('/comments', function(req, res, next) { + // extract query params + var params = req.params || {}; - // extract query params - var params = req.params || {}; - - // build base sql statement - var sql = ` + // build base sql statement + var sql = ` SELECT comments.*, users.id AS user_id, @@ -33,37 +32,32 @@ server.get('/comments', function(req, res, next) { LEFT JOIN users ON comments.user_id = users.id `; - // if upload id exists, inject into sql query - if (params.upload_id) { - sql += ' WHERE upload_id=?'; - } - - // order by created timestamp - sql += ' ORDER BY comments.created_at DESC '; - - // execute query - db.query(sql, [params.upload_id], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // send result to client - res.send(200, result); - return next(); - - }); - + // if upload id exists, inject into sql query + if (params.upload_id) { + sql += ' WHERE upload_id=?'; + } + + // order by created timestamp + sql += ' ORDER BY comments.created_at DESC '; + + // execute query + db.query(sql, [params.upload_id], function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + // send result to client + res.send(200, result); + return next(); + }); }); - /** +/** * Create a comment for a specific upload * URL: /comments * Method: POST @@ -73,101 +67,102 @@ server.get('/comments', function(req, res, next) { * @returns {object} Returns 201 status code with an object of the returned database result */ server.post('/comments', function(req, res, next) { - - // extract params from body - var data = req.body || {}; - - // async waterfall (see: https://github.com/caolan/async) - async.waterfall([ - - // insert comment into database - function(cb) { - - data['created_at'] = new Date(); - - // execute query with data as sanitized values - db.query('INSERT INTO comments SET ?', data, function(err, comment) { - - if (err) { - cb(err); - } - // use object assign to merge the object id - comment = Object.assign({ id: comment.insertId }, data); - - cb(null, comment); - - }); - - }, - - // get upload associated with comment - function(comment, cb) { - - // execute query using upload id from previous sql query - db.query('SELECT user_id FROM uploads WHERE id = ?', [comment.upload_id], function(err, upload) { - - if (err) { - cb(err); - } - - // use object assign to merge objects from previous queries - var result = Object.assign({ author_id: upload[0].user_id }, comment, upload); - - cb(null, result); - - }); - - }, - - // submit to stream - function(result, cb) { - - // instantiate a new client (server side) - var streamClient = stream.connect(config.stream.key, config.stream.secret); - - // instantiate a feed using feed class 'user' and the user id from the database - var userFeed = streamClient.feed('user', data.user_id); - - // build activity object for stream feed - var activity = { - actor: `user:${data.user_id}`, - verb: 'comment', - object: `upload:${data.upload_id}`, - foreign_id: `comment:${result.id}`, - time: result.created_at, - comment: data.comment, - to: [`notification:${result.author_id}`], - }; - - // add activity to the feed - userFeed.addActivity(activity) - .then(function(response) { - cb(null, result); - }) - .catch(function(err) { - cb(err); - }); - - } - - // final cb callback - ], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err)); - - } - - // send response to client - res.send(201, result); - return next(); - - }); - + // extract params from body + var data = req.body || {}; + + // async waterfall (see: https://github.com/caolan/async) + async.waterfall( + [ + // insert comment into database + function(cb) { + data['created_at'] = new Date(); + + // execute query with data as sanitized values + db.query('INSERT INTO comments SET ?', data, function( + err, + comment, + ) { + if (err) { + cb(err); + } + // use object assign to merge the object id + comment = Object.assign({ id: comment.insertId }, data); + + cb(null, comment); + }); + }, + + // get upload associated with comment + function(comment, cb) { + // execute query using upload id from previous sql query + db.query( + 'SELECT user_id FROM uploads WHERE id = ?', + [comment.upload_id], + function(err, upload) { + if (err) { + cb(err); + } + + // use object assign to merge objects from previous queries + var result = Object.assign( + { author_id: upload[0].user_id }, + comment, + upload, + ); + + cb(null, result); + }, + ); + }, + + // submit to stream + function(result, cb) { + // instantiate a new client (server side) + var streamClient = stream.connect( + config.stream.key, + config.stream.secret, + ); + + // instantiate a feed using feed class 'user' and the user id from the database + var userFeed = streamClient.feed('user', data.user_id); + + // build activity object for stream feed + var activity = { + actor: `user:${data.user_id}`, + verb: 'comment', + object: `upload:${data.upload_id}`, + foreign_id: `comment:${result.id}`, + time: result.created_at, + comment: data.comment, + to: [`notification:${result.author_id}`], + }; + + // add activity to the feed + userFeed + .addActivity(activity) + .then(function(response) { + cb(null, result); + }) + .catch(function(err) { + cb(err); + }); + }, + + // final cb callback + ], + function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err)); + } + + // send response to client + res.send(201, result); + return next(); + }, + ); }); diff --git a/api/routes/contributions.js b/api/routes/contributions.js index 7f62e28..cb4879e 100644 --- a/api/routes/contributions.js +++ b/api/routes/contributions.js @@ -9,28 +9,26 @@ * @returns {array} Returns a 200 status code with an array of upload (aka contribution) objects */ server.get('/contributions', function(req, res, next) { - - // extract query params - var params = req.params || {}; - - // execute query - db.query('SELECT * FROM uploads WHERE user_id = ? ORDER BY created_at DESC', [params.user_id], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // send response to client - res.send(200, result) - return next(); - - }); - + // extract query params + var params = req.params || {}; + + // execute query + db.query( + 'SELECT * FROM uploads WHERE user_id = ? ORDER BY created_at DESC', + [params.user_id], + function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + // send response to client + res.send(200, result); + return next(); + }, + ); }); diff --git a/api/routes/explore.js b/api/routes/explore.js index 7bf7985..34ff014 100644 --- a/api/routes/explore.js +++ b/api/routes/explore.js @@ -1,6 +1,6 @@ 'use strict'; - /** +/** * Get images for explore page for a specific user * URL: /explore * Method: GET @@ -9,12 +9,11 @@ * @returns {array} Returns a 200 status code with an array of upload (aka explore) objects */ server.get('/explore', function(req, res, next) { + // extract query params + var params = req.params || {}; - // extract query params - var params = req.params || {}; - - // build sql query - var sql = ` + // build sql query + var sql = ` SELECT uploads.*, COUNT(likes.id) AS likeTotal @@ -27,24 +26,19 @@ server.get('/explore', function(req, res, next) { LIMIT 15 `; - // execute query - db.query(sql, [params.user_id], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // send response to client - res.send(200, result) - return next(); - - }); - -}) + // execute query + db.query(sql, [params.user_id], function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + // send response to client + res.send(200, result); + return next(); + }); +}); diff --git a/api/routes/followers.js b/api/routes/followers.js index 264005b..debb53e 100644 --- a/api/routes/followers.js +++ b/api/routes/followers.js @@ -15,65 +15,66 @@ var stream = require('getstream'); * @returns {object} Returns a 201 status code with the object created */ server.post('/followers', function(req, res, next) { - - // extract params from body - var data = req.body || {}; - data['created_at'] = new Date(); - - // execute query using data from body - db.query('INSERT INTO followers SET ?', data, function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // instantiate a new client (server side) - var streamClient = stream.connect(config.stream.key, config.stream.secret); - - // instantiate a feed using feed class 'user' and the user id from the database - var userFeed = streamClient.feed('user', data.user_id); - - // build activity object for stream feed - var activity = { - actor: `user:${data.user_id}`, - verb: 'follow', - object: `user:${data.follower_id}`, - foreign_id: `follow:${result.insertId}`, - time: data['created_at'], - to: [`notification:${data.follower_id}`] - }; - - // instantiate a feed using feed class 'timeline_flat' and the user id from the database - var timeline = streamClient.feed('timeline_flat', data.user_id); - timeline.follow('user_posts', data.follower_id); - - // instantiate a feed using feed class 'timeline_aggregated' and the user id from the database - var timelineAggregated = streamClient.feed('timeline_aggregated', data.user_id); - timelineAggregated.follow('user', data.follower_id); - - // add activity to the feed - userFeed.addActivity(activity) - .then(function(response) { - //log.info(response); - }) - .catch(function(reason) { - log.error(reason); - return next(new restify.InternalError(reason.error)); - }); - - // send response to client - res.send(201, Object.assign({ id: result.insertId }, data)); - return next(); - - }); - + // extract params from body + var data = req.body || {}; + data['created_at'] = new Date(); + + // execute query using data from body + db.query('INSERT INTO followers SET ?', data, function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + // instantiate a new client (server side) + var streamClient = stream.connect( + config.stream.key, + config.stream.secret, + ); + + // instantiate a feed using feed class 'user' and the user id from the database + var userFeed = streamClient.feed('user', data.user_id); + + // build activity object for stream feed + var activity = { + actor: `user:${data.user_id}`, + verb: 'follow', + object: `user:${data.follower_id}`, + foreign_id: `follow:${result.insertId}`, + time: data['created_at'], + to: [`notification:${data.follower_id}`], + }; + + // instantiate a feed using feed class 'timeline_flat' and the user id from the database + var timeline = streamClient.feed('timeline_flat', data.user_id); + timeline.follow('user_posts', data.follower_id); + + // instantiate a feed using feed class 'timeline_aggregated' and the user id from the database + var timelineAggregated = streamClient.feed( + 'timeline_aggregated', + data.user_id, + ); + timelineAggregated.follow('user', data.follower_id); + + // add activity to the feed + userFeed + .addActivity(activity) + .then(function(response) { + //log.info(response); + }) + .catch(function(reason) { + log.error(reason); + return next(new restify.InternalError(reason.error)); + }); + + // send response to client + res.send(201, Object.assign({ id: result.insertId }, data)); + return next(); + }); }); /** @@ -86,42 +87,42 @@ server.post('/followers', function(req, res, next) { * @returns {string} Returns a 204 status code */ server.del('/followers', function(req, res, next) { - - // extract query params - var params = req.params || {}; - - // build sql query - var sql = 'DELETE FROM followers WHERE user_id = ? AND follower_id = ?'; - - // execute sql - db.query(sql, [params.user_id, params.follower_id], function(err, result) { - - // instantiate a new client (server side) - var streamClient = stream.connect(config.stream.key, config.stream.secret); - - // instantiate a feed using feed class 'user' and the user id from the database - var flatFeed = streamClient.feed('timeline_flat', params.user_id); - var aggregatedFeed = streamClient.feed('timeline_aggregated', params.user_id); - - // stop following user - flatFeed.unfollow('user_posts', params.follower_id); - aggregatedFeed.unfollow('user', params.follower_id); - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // send response to client - res.send(204); - return next(); - - }); - + // extract query params + var params = req.params || {}; + + // build sql query + var sql = 'DELETE FROM followers WHERE user_id = ? AND follower_id = ?'; + + // execute sql + db.query(sql, [params.user_id, params.follower_id], function(err, result) { + // instantiate a new client (server side) + var streamClient = stream.connect( + config.stream.key, + config.stream.secret, + ); + + // instantiate a feed using feed class 'user' and the user id from the database + var flatFeed = streamClient.feed('timeline_flat', params.user_id); + var aggregatedFeed = streamClient.feed( + 'timeline_aggregated', + params.user_id, + ); + + // stop following user + flatFeed.unfollow('user_posts', params.follower_id); + aggregatedFeed.unfollow('user', params.follower_id); + + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + // send response to client + res.send(204); + return next(); + }); }); diff --git a/api/routes/following-activity.js b/api/routes/following-activity.js index b195cd6..c403aed 100644 --- a/api/routes/following-activity.js +++ b/api/routes/following-activity.js @@ -3,9 +3,9 @@ /** * Module Dependencies */ - var async = require('async'), - stream = require('getstream'), - streamUtils = require('./../lib/stream_utils'); +var async = require('async'), + stream = require('getstream'), + streamUtils = require('./../lib/stream_utils'); /** * Get following activity for a specific user @@ -16,81 +16,90 @@ * @returns {object} Returns a 200 status code with an array of search objects */ server.get('/following-activity', function(req, res, next) { - - // extract query params - var params = req.params || {}; - - // async waterfall (see: https://github.com/caolan/async) - async.waterfall([ - - // connect to stream - function(cb) { - - // instantiate a new client (server side) - var streamClient = stream.connect(config.stream.key, config.stream.secret); - - // instantiate a feed using feed class 'user' and user id from params - var user = streamClient.feed('timeline_aggregated', params.user_id); - - cb(null, user); - - }, - - // get and loop through activities - function(user, cb) { - - // empty array to hold activities - var arr = []; - - // get activities from stream - user.get({ limit: 100 }) - .then(function(stream) { - - // length of activity results - var ln = stream.results.length; - - // if length is empty, return - if (!ln) { - res.send(204); - return next(); - } - - /* + // extract query params + var params = req.params || {}; + + // async waterfall (see: https://github.com/caolan/async) + async.waterfall( + [ + // connect to stream + function(cb) { + // instantiate a new client (server side) + var streamClient = stream.connect( + config.stream.key, + config.stream.secret, + ); + + // instantiate a feed using feed class 'user' and user id from params + var user = streamClient.feed( + 'timeline_aggregated', + params.user_id, + ); + + cb(null, user); + }, + + // get and loop through activities + function(user, cb) { + // empty array to hold activities + var arr = []; + + // get activities from stream + user + .get({ limit: 100 }) + .then(function(stream) { + // length of activity results + var ln = stream.results.length; + + // if length is empty, return + if (!ln) { + res.send(204); + return next(); + } + + /* * Activities stored in Stream reference user ids and upload ids * We need the full object, not just the reference for the template * The steps below query the DB to translate user:2 into * Something like {'username': 'Nick', 'img':...} */ - var references = streamUtils.referencesFromActivities(stream.results); - streamUtils.loadReferencedObjects(references, params.user_id, function(referencedObjects){ - streamUtils.enrichActivities(stream.results, referencedObjects); - // return the enriched activities - cb(null, stream.results); - }); - }).catch(function(error) { - cb(error); - }); - - }, - - // final cb function - ], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // send response to client - res.send(200, result); - return next(); - }); - + var references = streamUtils.referencesFromActivities( + stream.results, + ); + streamUtils.loadReferencedObjects( + references, + params.user_id, + function(referencedObjects) { + streamUtils.enrichActivities( + stream.results, + referencedObjects, + ); + // return the enriched activities + cb(null, stream.results); + }, + ); + }) + .catch(function(error) { + cb(error); + }); + }, + + // final cb function + ], + function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + // send response to client + res.send(200, result); + return next(); + }, + ); }); diff --git a/api/routes/incoming-activity.js b/api/routes/incoming-activity.js index ddab859..6596c75 100644 --- a/api/routes/incoming-activity.js +++ b/api/routes/incoming-activity.js @@ -3,12 +3,9 @@ /** * Module Dependencies */ -var async = require('async'), - stream = require('getstream'), - streamUtils = require('./../lib/stream_utils'); - - - +var async = require('async'), + stream = require('getstream'), + streamUtils = require('./../lib/stream_utils'); /** * Get incoming activity for a specific user @@ -19,85 +16,90 @@ var async = require('async'), * @returns {object} Returns a 200 status code with an array of search objects */ server.get('/incoming-activity', function(req, res, next) { - - // extract query params - var params = req.params || {}; - - // async waterfall (see: https://github.com/caolan/async) - async.waterfall([ - - // connect to stream - function(cb) { - - // instantiate a new client (server side) - var streamClient = stream.connect(config.stream.key, config.stream.secret); - - // instantiate a feed using feed class 'notification' and user id from params - var notificationFeed = streamClient.feed('notification', params.user_id); - - cb(null, notificationFeed); - - }, - - // get and loop through activities - function(notificationFeed, cb) { - - // empty array to hold activities - var arr = []; - - // get activities from stream - notificationFeed.get({ limit: 100 }) - .then(function(stream) { - - // length of activity results - var ln = stream.results.length; - - // if length is empty, return - if (!ln) { - res.send(204); - return next(); - } - - /* + // extract query params + var params = req.params || {}; + + // async waterfall (see: https://github.com/caolan/async) + async.waterfall( + [ + // connect to stream + function(cb) { + // instantiate a new client (server side) + var streamClient = stream.connect( + config.stream.key, + config.stream.secret, + ); + + // instantiate a feed using feed class 'notification' and user id from params + var notificationFeed = streamClient.feed( + 'notification', + params.user_id, + ); + + cb(null, notificationFeed); + }, + + // get and loop through activities + function(notificationFeed, cb) { + // empty array to hold activities + var arr = []; + + // get activities from stream + notificationFeed + .get({ limit: 100 }) + .then(function(stream) { + // length of activity results + var ln = stream.results.length; + + // if length is empty, return + if (!ln) { + res.send(204); + return next(); + } + + /* * Activities stored in Stream reference user ids and upload ids * We need the full object, not just the reference for the template * The steps below query the DB to translate user:2 into * Something like {'username': 'Nick', 'img':...} */ - var references = streamUtils.referencesFromActivities(stream.results); - streamUtils.loadReferencedObjects(references, params.user_id, function(referencedObjects){ - streamUtils.enrichActivities(stream.results, referencedObjects); - // return the enriched activities - cb(null, stream.results); - }) - - - - }) - .catch(function(error) { - cb(error); - }); - - }, - - // final cb function - ], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // send response to client - res.send(200, result); - return next(); - }); - + var references = streamUtils.referencesFromActivities( + stream.results, + ); + streamUtils.loadReferencedObjects( + references, + params.user_id, + function(referencedObjects) { + streamUtils.enrichActivities( + stream.results, + referencedObjects, + ); + // return the enriched activities + cb(null, stream.results); + }, + ); + }) + .catch(function(error) { + cb(error); + }); + }, + + // final cb function + ], + function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + // send response to client + res.send(200, result); + return next(); + }, + ); }); diff --git a/api/routes/index.js b/api/routes/index.js index 47ee32e..bae7ae5 100644 --- a/api/routes/index.js +++ b/api/routes/index.js @@ -3,9 +3,9 @@ /** * Catch All */ -server.opts(/\.*/, function (req, res, next) { - res.send(200); - next(); +server.opts(/\.*/, function(req, res, next) { + res.send(200); + next(); }); /** diff --git a/api/routes/likes.js b/api/routes/likes.js index 20d45cf..ea0c66c 100644 --- a/api/routes/likes.js +++ b/api/routes/likes.js @@ -3,8 +3,8 @@ /** * Module Dependencies */ -var async = require('async'), - stream = require('getstream'); +var async = require('async'), + stream = require('getstream'); /** * Get all likes (optionally for a specific user and/or upload) @@ -16,49 +16,47 @@ var async = require('async'), * @returns {object} Returns a 200 status code with an array of like objects */ server.get('/likes', function(req, res, next) { + // extract query params + var params = req.params || {}; - // extract query params - var params = req.params || {}; + // empty array to hold onto our params for sql query + var bindings = []; - // empty array to hold onto our params for sql query - var bindings = []; + // base sql query + var userSql = ''; - // base sql query - var userSql = ''; + // if a user id was passed in, get all of the likes for that user + if (params.user_id) { + userSql += `,IF((SELECT 1 AS liked FROM likes WHERE user_id = ? AND upload_id = ?), true, false) AS liked`; + bindings.push(params.user_id); + bindings.push(params.upload_id); + } - // if a user id was passed in, get all of the likes for that user - if (params.user_id) { - userSql += `,IF((SELECT 1 AS liked FROM likes WHERE user_id = ? AND upload_id = ?), true, false) AS liked`; - bindings.push(params.user_id) - bindings.push(params.upload_id) - } - - // create like count sql - var sql = ` + // create like count sql + var sql = ` SELECT COUNT(*) AS likes ${userSql} FROM likes `; - // if upload id was passed, append query and push upload id into bindings array - if (params.upload_id) { - sql += ' WHERE upload_id = ? '; - bindings.push(params.upload_id) - } - - db.query(sql, bindings, function(err, result) { - if (err) { - log.error(err); - return next(new restify.InternalError(err.message)); - } - res.send(200, result[0]); - return next(); - }); - + // if upload id was passed, append query and push upload id into bindings array + if (params.upload_id) { + sql += ' WHERE upload_id = ? '; + bindings.push(params.upload_id); + } + + db.query(sql, bindings, function(err, result) { + if (err) { + log.error(err); + return next(new restify.InternalError(err.message)); + } + res.send(200, result[0]); + return next(); + }); }); - /** +/** * Create a likes for a specific upload * URL: /likes * Method: POST @@ -68,114 +66,124 @@ server.get('/likes', function(req, res, next) { * @returns {object} Returns a 201 status code with the created object */ server.post('/likes', function(req, res, next) { - - // extract params from body - var data = req.body || {}; - data['created_at'] = new Date(); - - // async waterfall (see: https://github.com/caolan/async) - async.waterfall([ - - // insert like into database - function(cb) { - - // execute query and use data passed in via body - db.query('INSERT INTO likes SET ?', data, function(err, like) { - - if (err) { - log.error(err); - return next(new restify.InternalError(err.message)); - } - - // use object assign to merge row id - like = Object.assign({ id: like.insertId }, data); - - cb(null, like); - - }); - - }, - - // get user id from upload - function(like, cb) { - db.query('SELECT * FROM uploads WHERE id = ?', [like.upload_id], function(err, upload) { - if (err) { - cb(err); - } - cb(null, like, upload); - }); - }, - // send back in response - function(like, upload, cb) { - db.query('SELECT COUNT(*) AS total FROM likes WHERE upload_id = ?', [ like.upload_id ], function(err, count) { - if (err) { - cb(err); - } - var result = Object.assign({ id: like.id }, { user_id: upload.user_id }, { likes: count[0].total }, data); - cb(null, result); - }); - - }, - - function(result, cb) { - db.query('SELECT user_id FROM uploads WHERE id = ?', [ result.upload_id ], function(err, row) { - if (err) { - return cb(err); - } - cb(null, Object.assign(result, { to: row[0].user_id })) - }); - }, - - // last cb function - function(result, cb) { - - // instantiate a new client (server side) - var streamClient = stream.connect(config.stream.key, config.stream.secret); - - // instantiate a feed using feed class 'user' and the user id from the database - var userFeed = streamClient.feed('user', data.user_id); - - // build activity object for stream feed - var activity = { - actor: `user:${data.user_id}`, - verb: 'like', - object: `upload:${data.upload_id}`, - foreign_id: `like:${result.id}`, - time: data['created_at'], - to: [`notification:${result.to}`], - }; - - // add activity to the feed - userFeed.addActivity(activity) - .then(function(response) { - cb(null, result); - }) - .catch(function(err) { - cb(err); - }); - - } - - // final cb callback - ], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err)); - - } - - // send response to client - res.send(201, result); - return next(); - - }); - + // extract params from body + var data = req.body || {}; + data['created_at'] = new Date(); + + // async waterfall (see: https://github.com/caolan/async) + async.waterfall( + [ + // insert like into database + function(cb) { + // execute query and use data passed in via body + db.query('INSERT INTO likes SET ?', data, function(err, like) { + if (err) { + log.error(err); + return next(new restify.InternalError(err.message)); + } + + // use object assign to merge row id + like = Object.assign({ id: like.insertId }, data); + + cb(null, like); + }); + }, + + // get user id from upload + function(like, cb) { + db.query( + 'SELECT * FROM uploads WHERE id = ?', + [like.upload_id], + function(err, upload) { + if (err) { + cb(err); + } + cb(null, like, upload); + }, + ); + }, + // send back in response + function(like, upload, cb) { + db.query( + 'SELECT COUNT(*) AS total FROM likes WHERE upload_id = ?', + [like.upload_id], + function(err, count) { + if (err) { + cb(err); + } + var result = Object.assign( + { id: like.id }, + { user_id: upload.user_id }, + { likes: count[0].total }, + data, + ); + cb(null, result); + }, + ); + }, + + function(result, cb) { + db.query( + 'SELECT user_id FROM uploads WHERE id = ?', + [result.upload_id], + function(err, row) { + if (err) { + return cb(err); + } + cb(null, Object.assign(result, { to: row[0].user_id })); + }, + ); + }, + + // last cb function + function(result, cb) { + // instantiate a new client (server side) + var streamClient = stream.connect( + config.stream.key, + config.stream.secret, + ); + + // instantiate a feed using feed class 'user' and the user id from the database + var userFeed = streamClient.feed('user', data.user_id); + + // build activity object for stream feed + var activity = { + actor: `user:${data.user_id}`, + verb: 'like', + object: `upload:${data.upload_id}`, + foreign_id: `like:${result.id}`, + time: data['created_at'], + to: [`notification:${result.to}`], + }; + + // add activity to the feed + userFeed + .addActivity(activity) + .then(function(response) { + cb(null, result); + }) + .catch(function(err) { + cb(err); + }); + }, + + // final cb callback + ], + function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err)); + } + + // send response to client + res.send(201, result); + return next(); + }, + ); }); /** @@ -188,64 +196,61 @@ server.post('/likes', function(req, res, next) { * @returns {object} Returns a 201 status code */ server.del('/likes', function(req, res, next) { - - // extract query params - var params = req.params || {}; - - // async waterfall (see: https://github.com/caolan/async) - async.waterfall([ - - // delete like form database - function(cb) { - - // execute query - db.query('DELETE FROM likes WHERE user_id = ? AND upload_id = ?', [ params.user_id, params.upload_id ], function(err, like) { - - if (err) { - cb(err); - } - - cb(null, like); - - }); - }, - - // get like count for response - function(like, cb) { - - // execute query - db.query('SELECT COUNT(*) AS likes FROM likes WHERE upload_id = ?', [ params.upload_id ], function(err, count) { - - if (err) { - cb(err); - } - - var result = Object.assign(like, count); - - cb(null, result); - - }); - - } - -// last cb callback -], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err)); - - } - - // send response to client - res.send(200, result[0]); - return next(); - - }); - + // extract query params + var params = req.params || {}; + + // async waterfall (see: https://github.com/caolan/async) + async.waterfall( + [ + // delete like form database + function(cb) { + // execute query + db.query( + 'DELETE FROM likes WHERE user_id = ? AND upload_id = ?', + [params.user_id, params.upload_id], + function(err, like) { + if (err) { + cb(err); + } + + cb(null, like); + }, + ); + }, + + // get like count for response + function(like, cb) { + // execute query + db.query( + 'SELECT COUNT(*) AS likes FROM likes WHERE upload_id = ?', + [params.upload_id], + function(err, count) { + if (err) { + cb(err); + } + + var result = Object.assign(like, count); + + cb(null, result); + }, + ); + }, + + // last cb callback + ], + function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err)); + } + + // send response to client + res.send(200, result[0]); + return next(); + }, + ); }); diff --git a/api/routes/locations.js b/api/routes/locations.js index 51e072d..b3b23a5 100644 --- a/api/routes/locations.js +++ b/api/routes/locations.js @@ -9,42 +9,36 @@ * @returns {object} Returns a 200 status code with an array of search objects */ server.get('/locations', function(req, res, next) { + // extract query params + var params = req.params || {}; - // extract query params - var params = req.params || {}; + // if params don't exist, respond with empty object + if (!params.q) { + res.send(200, []); + return next(); + } - // if params don't exist, respond with empty object - if (!params.q) { - res.send(200, []); - return next(); - } - - // build sql query - var sql = ` + // build sql query + var sql = ` SELECT * FROM uploads WHERE location LIKE ? ORDER BY created_at DESC `; - // build query - db.query(sql, [params.q], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // send response to client - res.send(200, result) - return next(); - - }); - -}) + // build query + db.query(sql, [params.q], function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + // send response to client + res.send(200, result); + return next(); + }); +}); diff --git a/api/routes/searches.js b/api/routes/searches.js index 41e8c98..04bf92e 100644 --- a/api/routes/searches.js +++ b/api/routes/searches.js @@ -9,12 +9,11 @@ * @returns {object} Returns a 200 status code with an array of search objects */ server.get('/searches', function(req, res, next) { + // extract query params + var params = req.params || {}; - // extract query params - var params = req.params || {}; - - // build sql query - var sql = ` + // build sql query + var sql = ` SELECT search, created_at @@ -25,26 +24,21 @@ server.get('/searches', function(req, res, next) { LIMIT 10 `; - // execute query - db.query(sql, [ params.user_id ], function(err, results) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // send response to client - res.send(200, results); - return next(); - - }); - + // execute query + db.query(sql, [params.user_id], function(err, results) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + // send response to client + res.send(200, results); + return next(); + }); }); /** @@ -57,25 +51,21 @@ server.get('/searches', function(req, res, next) { * @returns {object} Returns a 200 status code with an array of search objects */ server.post('/searches', function(req, res, next) { - - // extract params from body - var data = req.body || {}; - - // execute query using data from body - db.query('INSERT INTO searches SET ?', data, function(err, result) { - - if (err) { - log.error(err); - return next(new restify.InternalError(err.message)); - } - - // user object.assign to inject new record id - result = Object.assign({ id: result.insertId }, data); - - // send response to client - res.send(201, result); - return next(); - - }); - + // extract params from body + var data = req.body || {}; + + // execute query using data from body + db.query('INSERT INTO searches SET ?', data, function(err, result) { + if (err) { + log.error(err); + return next(new restify.InternalError(err.message)); + } + + // user object.assign to inject new record id + result = Object.assign({ id: result.insertId }, data); + + // send response to client + res.send(201, result); + return next(); + }); }); diff --git a/api/routes/stats.js b/api/routes/stats.js index 5357d5b..084a925 100644 --- a/api/routes/stats.js +++ b/api/routes/stats.js @@ -2,7 +2,7 @@ * Module Dependencies */ var async = require('async'), - Keen = require('keen.io'); + Keen = require('keen.io'); /** * Upload an image * URL: /uploads @@ -12,116 +12,111 @@ var async = require('async'), * @returns {object} Returns a 201 status code with the upload object */ server.get('/stats/:user_id', function(req, res, next) { - - // extract query params - var params = req.params || {}; - var userId = params.user_id; - - // async waterfall (see: https://github.com/caolan/async) - async.waterfall([ - - // keen query - function(cb) { - - // configure instance of keenClient - var keenClient = Keen.configure({ - projectId: config.keen.projectId, - writeKey: config.keen.writeKey, - readKey: config.keen.readKey, - masterKey: config.keen.masterKey, - }); - - // build query - var keenQuery = new Keen.Query("count", { - event_collection: 'views', - timeframe: 'this_30_days', - group_by: "postId", - filters: [{ - property_name: 'postAuthorId', - operator: 'eq', - property_value: userId, - }] - }); - - // run query - keenClient.run(keenQuery, function(err, res) { - - if (err) { - cb(err); - } - - function compareItems(a, b) { - return (a['result'] - b['result']) * -1; - } - - var sortedItems = res.result; - sortedItems.sort(compareItems); - - var topItems = sortedItems.slice(0, 5); - var postIds = []; - var postViewCounts = {}; - - // loop through top items - topItems.forEach(function(value) { - postIds.push(value['postId']) - postViewCounts[value['postId']] = value['result'] - }); - - cb(null, postIds, postViewCounts); - - }); - - }, - - // database query - function(postIds, postViewCounts, cb) { - - // run query if we have results - if (postIds.length == 0) { - var uploads = []; - cb(null, uploads); - } else { - db.query('SELECT * FROM uploads WHERE id IN (?)', [postIds], function(err, uploads) { - - if (err) { - log.error(err); - return next(new restify.InternalError(err.message)); - } - - uploads.forEach(function(upload) { - upload.viewCount = postViewCounts[upload.id] - }); - - function compareUploads(a, b) { - return (a['viewCount'] - b['viewCount']) * -1; - } - - uploads.sort(compareUploads); - - cb(null, uploads); - - }); - }; - - } - - ], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err)); - - } - - // send response to client - res.send(200, { 'mostViewed': result }); - return next(); - - }); - + // extract query params + var params = req.params || {}; + var userId = params.user_id; + + // async waterfall (see: https://github.com/caolan/async) + async.waterfall( + [ + // keen query + function(cb) { + // configure instance of keenClient + var keenClient = Keen.configure({ + projectId: config.keen.projectId, + writeKey: config.keen.writeKey, + readKey: config.keen.readKey, + masterKey: config.keen.masterKey, + }); + + // build query + var keenQuery = new Keen.Query('count', { + event_collection: 'views', + timeframe: 'this_30_days', + group_by: 'postId', + filters: [ + { + property_name: 'postAuthorId', + operator: 'eq', + property_value: userId, + }, + ], + }); + + // run query + keenClient.run(keenQuery, function(err, res) { + if (err) { + cb(err); + } + + function compareItems(a, b) { + return (a['result'] - b['result']) * -1; + } + + var sortedItems = res.result; + sortedItems.sort(compareItems); + + var topItems = sortedItems.slice(0, 5); + var postIds = []; + var postViewCounts = {}; + + // loop through top items + topItems.forEach(function(value) { + postIds.push(value['postId']); + postViewCounts[value['postId']] = value['result']; + }); + + cb(null, postIds, postViewCounts); + }); + }, + + // database query + function(postIds, postViewCounts, cb) { + // run query if we have results + if (postIds.length == 0) { + var uploads = []; + cb(null, uploads); + } else { + db.query( + 'SELECT * FROM uploads WHERE id IN (?)', + [postIds], + function(err, uploads) { + if (err) { + log.error(err); + return next( + new restify.InternalError(err.message), + ); + } + + uploads.forEach(function(upload) { + upload.viewCount = postViewCounts[upload.id]; + }); + + function compareUploads(a, b) { + return (a['viewCount'] - b['viewCount']) * -1; + } + + uploads.sort(compareUploads); + + cb(null, uploads); + }, + ); + } + }, + ], + function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err)); + } + + // send response to client + res.send(200, { mostViewed: result }); + return next(); + }, + ); }); diff --git a/api/routes/trending.js b/api/routes/trending.js index 2a91c17..f793c32 100644 --- a/api/routes/trending.js +++ b/api/routes/trending.js @@ -9,12 +9,11 @@ * @returns {object} Returns a 200 status code with an array of upload objects */ server.get('/trending', function(req, res, next) { + // extract params + var params = req.params || {}; - // extract params - var params = req.params || {}; - - // build sql query - var sql = ` + // build sql query + var sql = ` SELECT uploads.*, COUNT(likes.id) AS likeTotal @@ -26,24 +25,19 @@ server.get('/trending', function(req, res, next) { ORDER BY COUNT(likes.id) DESC `; - // execute query - db.query(sql, [params.user_id], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // send response to client - res.send(200, result) - return next(); - - }); - + // execute query + db.query(sql, [params.user_id], function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + // send response to client + res.send(200, result); + return next(); + }); }); diff --git a/api/routes/uploads.js b/api/routes/uploads.js index b909d24..14f8435 100644 --- a/api/routes/uploads.js +++ b/api/routes/uploads.js @@ -3,13 +3,13 @@ /** * Module Dependencies */ -var knox = require('knox'), - uuid = require('node-uuid'), - geo = require('mapbox-geocoding'), - async = require('async'), - stream = require('getstream'), - streamUtils = require('../lib/stream_utils'), - algoliaSearch = require('algoliasearch'); +var knox = require('knox'), + uuid = require('node-uuid'), + geo = require('mapbox-geocoding'), + async = require('async'), + stream = require('getstream'), + streamUtils = require('../lib/stream_utils'), + algoliaSearch = require('algoliasearch'); /** * Get uploads based on query @@ -22,140 +22,141 @@ var knox = require('knox'), * @returns {object} Returns a 200 status code with an array of upload objects */ server.get('/uploads', function(req, res, next) { - - // extract query params - var params = req.params || {}; - - // default sql - var sql = ''; - - // if the params type and query are defined, build query for 'type' - if (params.type && params.query) { - - // check type and build query - switch (params.type) { - case 'hashtags': - sql = ` + // extract query params + var params = req.params || {}; + + // default sql + var sql = ''; + + // if the params type and query are defined, build query for 'type' + if (params.type && params.query) { + // check type and build query + switch (params.type) { + case 'hashtags': + sql = ` SELECT * FROM uploads WHERE hashtags LIKE '%${params.query.substring(1)}%' `; - break; - case 'location': - sql = ` + break; + case 'location': + sql = ` SELECT * FROM uploads WHERE location LIKE '%${params.query}%' `; - break; - case 'user': - const userName = params.query.split(' ') - sql = ` + break; + case 'user': + const userName = params.query.split(' '); + sql = ` SELECT * FROM uploads LEFT JOIN users ON uploads.user_id = users.id WHERE users.first_name = ${db.escape(userName[0])} - AND CONCAT(SUBSTR(users.last_name, 1, 1), '.') = ${db.escape(userName[1])} + AND CONCAT(SUBSTR(users.last_name, 1, 1), '.') = ${db.escape( + userName[1], + )} `; - break; - } - - // execute sql query - db.query(sql, function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // send response to client - res.send(200, result); - return next(); - - }); - - // otherwise default to normal query - } else { - - // async waterfall (see: https://github.com/caolan/async) - async.waterfall([ - - // connect to stream - function(cb) { - - // instantiate a new client (server side) - var streamClient = stream.connect(config.stream.key, config.stream.secret); - - // instantiate a feed using feed class 'timeline_flat' and user id from params - var timelineFlatFeed = streamClient.feed('timeline_flat', params.user_id); - - cb(null, timelineFlatFeed); - - }, - - // get and loop through activities - function(timelineFlatFeed, cb) { - - // build query params for stream (id_lt is preferred) - var uploadGetParams = { limit: 5, } - if (params.last_id) uploadGetParams.id_lt = params.last_id - - // get activities from stream - timelineFlatFeed.get(uploadGetParams) - .then(function(stream) { - - // length of activity results - var ln = stream.results.length; - - // exit if length is zero - if (!ln) { - res.send(204); - return next(); - } - - // enrich the activities - var references = streamUtils.referencesFromActivities(stream.results); - streamUtils.loadReferencedObjects(references, params.user_id, function(referencedObjects) { - streamUtils.enrichActivities(stream.results, referencedObjects); - cb(null, stream.results); - }); - - }) - .catch(function(error) { - cb(error); - }); - - } - - // final cb callback - ], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err)); - - } - - // send response to client - res.send(200, result); - return next(); - - }); - - } - + break; + } + + // execute sql query + db.query(sql, function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + // send response to client + res.send(200, result); + return next(); + }); + + // otherwise default to normal query + } else { + // async waterfall (see: https://github.com/caolan/async) + async.waterfall( + [ + // connect to stream + function(cb) { + // instantiate a new client (server side) + var streamClient = stream.connect( + config.stream.key, + config.stream.secret, + ); + + // instantiate a feed using feed class 'timeline_flat' and user id from params + var timelineFlatFeed = streamClient.feed( + 'timeline_flat', + params.user_id, + ); + + cb(null, timelineFlatFeed); + }, + + // get and loop through activities + function(timelineFlatFeed, cb) { + // build query params for stream (id_lt is preferred) + var uploadGetParams = { limit: 5 }; + if (params.last_id) uploadGetParams.id_lt = params.last_id; + + // get activities from stream + timelineFlatFeed + .get(uploadGetParams) + .then(function(stream) { + // length of activity results + var ln = stream.results.length; + + // exit if length is zero + if (!ln) { + res.send(204); + return next(); + } + + // enrich the activities + var references = streamUtils.referencesFromActivities( + stream.results, + ); + streamUtils.loadReferencedObjects( + references, + params.user_id, + function(referencedObjects) { + streamUtils.enrichActivities( + stream.results, + referencedObjects, + ); + cb(null, stream.results); + }, + ); + }) + .catch(function(error) { + cb(error); + }); + }, + + // final cb callback + ], + function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err)); + } + + // send response to client + res.send(200, result); + return next(); + }, + ); + } }); /** @@ -168,12 +169,11 @@ server.get('/uploads', function(req, res, next) { * @returns {object} Returns a 200 status code with the upload object */ server.get('/upload', function(req, res, next) { + // extract query params + var params = req.params || {}; - // extract query params - var params = req.params || {}; - - // build sql statement - var sql = ` + // build sql statement + var sql = ` SELECT uploads.*, users.id AS user_id, @@ -189,26 +189,21 @@ server.get('/upload', function(req, res, next) { ORDER BY uploads.created_at DESC `; - // execute sql query - db.query(sql, [params.user_id, params.id], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - // send response to client - res.send(200, result[0]); - return next(); - - }); - + // execute sql query + db.query(sql, [params.user_id, params.id], function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + // send response to client + res.send(200, result[0]); + return next(); + }); }); /** @@ -224,160 +219,159 @@ server.get('/upload', function(req, res, next) { * @returns {object} Returns a 201 status code with the upload object */ server.post('/uploads', function(req, res, next) { - - // extract params from body and file from uploaded files - var data = req.body || {}, - file = req.files || {}; - - // generate unique filename using uuid and assign to object - data.filename = uuid.v4(); - data['created_at'] = new Date(); - - // async waterfall (see: https://github.com/caolan/async) - async.waterfall([ - - // upload file to amazon s3 - function(cb) { - - // initialize knox client - var knoxClient = knox.createClient({ - key: config.s3.key, - secret: config.s3.secret, - bucket: config.s3.bucket - }); - - // send put via knox - knoxClient.putFile(file.image.path, 'uploads/' + data.filename, { - 'Content-Type': file.image.type, - 'x-amz-acl': 'public-read' - }, function(err, result) { - - if (err || result.statusCode != 200) { - cb(err); - } else { - - cb(null); - } - }); - - }, - - // use mapbox to get latitude and longitude - function(cb) { - - // initialize mapbox client - geo.setAccessToken(config.mapbox.accessToken); - - // get location data - geo.geocode('mapbox.places', data.location, function (err, location) { - - if (err) { - cb(err); - } else { - - // if the location was found - if (location.features.length) { - - // extract coorindates - var coords = location.features[0].geometry.coordinates; - if (coords.length) { - - // assign to latitude and longitude in data object - data.longitude = coords[0]; - data.latitude = coords[1]; - - } - - } - - cb(null) - } - }); - - }, - - // insert record into database - function(cb) { - - // run query using node mysql, passing the data object as params - db.query('INSERT INTO uploads SET ?', data, function(err, result) { - - if (err) { - cb(err); - } else { - - // use object assign to merge the object id - result = Object.assign({}, { id: result.insertId }, data); - - cb(null, result); - } - }); - - }, - - // submit to algolia for indexing - function(result, cb) { - - // initialize algolia - var algolia = algoliaSearch(config.algolia.appId, config.algolia.apiKey); - - // initialize algoia index - var index = algolia.initIndex('cabin'); - - // add returned database object for indexing - index.addObject(result); - - cb(null, result); - - }, - - // submit to stream - function(result, cb) { - - // instantiate a new client (server side) - var streamClient = stream.connect(config.stream.key, config.stream.secret); - - // build activity object for stream feed - var activity = { - actor: `user:${data.user_id}`, - verb: 'add', - object: `upload:${result.id}`, - foreign_id: `upload:${result.id}`, - time: data['created_at'] - }; - - // instantiate a feed using feed class 'user_posts' and the user id from the database - var userFeed = streamClient.feed('user_posts', data.user_id); - - // add activity to the feed - userFeed.addActivity(activity) - .then(function(response) { - cb(null, result); - }) - .catch(function(err) { - cb(err); - }); - - } - - // final cb function - ], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err)); - - } - - // respond to client with result from database - res.send(201, result); - return next(); - - }); - + // extract params from body and file from uploaded files + var data = req.body || {}, + file = req.files || {}; + + // generate unique filename using uuid and assign to object + data.filename = uuid.v4(); + data['created_at'] = new Date(); + + // async waterfall (see: https://github.com/caolan/async) + async.waterfall( + [ + // upload file to amazon s3 + function(cb) { + // initialize knox client + var knoxClient = knox.createClient({ + key: config.s3.key, + secret: config.s3.secret, + bucket: config.s3.bucket, + }); + + // send put via knox + knoxClient.putFile( + file.image.path, + 'uploads/' + data.filename, + { + 'Content-Type': file.image.type, + 'x-amz-acl': 'public-read', + }, + function(err, result) { + if (err || result.statusCode != 200) { + cb(err); + } else { + cb(null); + } + }, + ); + }, + + // use mapbox to get latitude and longitude + function(cb) { + // initialize mapbox client + geo.setAccessToken(config.mapbox.accessToken); + + // get location data + geo.geocode('mapbox.places', data.location, function( + err, + location, + ) { + if (err) { + cb(err); + } else { + // if the location was found + if (location.features.length) { + // extract coorindates + var coords = + location.features[0].geometry.coordinates; + if (coords.length) { + // assign to latitude and longitude in data object + data.longitude = coords[0]; + data.latitude = coords[1]; + } + } + + cb(null); + } + }); + }, + + // insert record into database + function(cb) { + // run query using node mysql, passing the data object as params + db.query('INSERT INTO uploads SET ?', data, function( + err, + result, + ) { + if (err) { + cb(err); + } else { + // use object assign to merge the object id + result = Object.assign( + {}, + { id: result.insertId }, + data, + ); + + cb(null, result); + } + }); + }, + + // submit to algolia for indexing + function(result, cb) { + // initialize algolia + var algolia = algoliaSearch( + config.algolia.appId, + config.algolia.apiKey, + ); + + // initialize algoia index + var index = algolia.initIndex('cabin'); + + // add returned database object for indexing + index.addObject(result); + + cb(null, result); + }, + + // submit to stream + function(result, cb) { + // instantiate a new client (server side) + var streamClient = stream.connect( + config.stream.key, + config.stream.secret, + ); + + // build activity object for stream feed + var activity = { + actor: `user:${data.user_id}`, + verb: 'add', + object: `upload:${result.id}`, + foreign_id: `upload:${result.id}`, + time: data['created_at'], + }; + + // instantiate a feed using feed class 'user_posts' and the user id from the database + var userFeed = streamClient.feed('user_posts', data.user_id); + + // add activity to the feed + userFeed + .addActivity(activity) + .then(function(response) { + cb(null, result); + }) + .catch(function(err) { + cb(err); + }); + }, + + // final cb function + ], + function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err)); + } + + // respond to client with result from database + res.send(201, result); + return next(); + }, + ); }); diff --git a/api/routes/users.js b/api/routes/users.js index fa6b252..59fe4db 100644 --- a/api/routes/users.js +++ b/api/routes/users.js @@ -3,11 +3,11 @@ /** * Module Dependencies */ -var stream = require('getstream'), - jwt = require('jsonwebtoken'), - async = require('async'), - FB = require('fb'), - algoliaSearch = require('algoliasearch'); +var stream = require('getstream'), + jwt = require('jsonwebtoken'), + async = require('async'), + FB = require('fb'), + algoliaSearch = require('algoliasearch'); /** * Get user by id @@ -18,21 +18,19 @@ var stream = require('getstream'), * @returns {object} Returns a 200 status code with the user object */ server.get('/users/:id', function(req, res, next) { + // extract params + var params = req.params || {}; - // extract params - var params = req.params || {}; + // empty array to hold bindings + var bindings = []; - // empty array to hold bindings - var bindings = []; + // base sql query + var sql = ''; - // base sql query - var sql = ''; - - // if a user id exists - if (params.user_id) { - - // build sql query - sql = ` + // if a user id exists + if (params.user_id) { + // build sql query + sql = ` SELECT users.id AS id, users.fb_uid AS fb_uid, @@ -68,14 +66,20 @@ server.get('/users/:id', function(req, res, next) { OR email = ? `; - // push query params into bindings array - bindings = [params.user_id, params.user_id, params.id, params.id, params.id, params.id]; - - // select user based off of provided fb_uid or email - } else { - - // build sql - sql = ` + // push query params into bindings array + bindings = [ + params.user_id, + params.user_id, + params.id, + params.id, + params.id, + params.id, + ]; + + // select user based off of provided fb_uid or email + } else { + // build sql + sql = ` SELECT users.id AS id, users.fb_uid AS fb_uid, @@ -90,34 +94,28 @@ server.get('/users/:id', function(req, res, next) { OR email = ? `; - // push query params into bindings array - bindings = [params.id, params.id, params.id]; - - } - - // execute query - db.query(sql, bindings, function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); + // push query params into bindings array + bindings = [params.id, params.id, params.id]; + } - // return error message to client - return next(new restify.InternalError(err.message)); + // execute query + db.query(sql, bindings, function(err, result) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); - } + // return error message to client + return next(new restify.InternalError(err.message)); + } - // use object.assign to merge stream tokens - result = Object.assign({}, result[0]); - - // send response to client - res.send(200, result); - return next(); - - }); + // use object.assign to merge stream tokens + result = Object.assign({}, result[0]); + // send response to client + res.send(200, result); + return next(); + }); }); /** @@ -132,152 +130,200 @@ server.get('/users/:id', function(req, res, next) { * @returns {object} Returns a 201 or 200 status code with the user object */ server.post('/users', function(req, res, next) { - - // extract data from body - var data = req.body || {}; - var fbUserId = data.fb_user_id; - var accessToken = data.token; - var options = { - appId : '1714548178824131', - xfbml : true, - version : 'v2.6', - status : true, - cookie : true, - }; - var fb = new FB.Facebook(options); - fb.setAccessToken(accessToken); - - async.waterfall([ - - function (cb) { - // query the userdata from FB - fb.api('/me', 'get', { fields: 'id,name,email, first_name, last_name' }, function(facebookUserData) { - cb(null, facebookUserData); - }); - }, - - function(facebookUserData, cb) { - - // build the data we're going to insert - var data = {}; - data.email = facebookUserData.email; - data.fb_uid = facebookUserData.id; - data.first_name = facebookUserData.first_name; - data.last_name = facebookUserData.last_name; - - // try select first - db.query('SELECT * FROM users WHERE email=' + db.escape(data.email), function(err, result) { - - if (err) { - log.error(err); - return next(new restify.InternalError(err.message)); - } - - // instantiate a new client (server side) - var streamClient = stream.connect(config.stream.key, config.stream.secret); - - // generate jwt - var jwtToken = jwt.sign({ - request: { - email: data.email - } - }, config.jwt.secret); - - // if user exists, return result - if (result.length) { - - var userId = result[0].id; - - // get tokens from stream client - var tokens = { - timeline: { - flat: streamClient.getReadOnlyToken('timeline_flat', userId), - aggregated: streamClient.getReadOnlyToken('timeline_aggregrated', userId), - }, - notification : streamClient.getReadOnlyToken('notification', userId), - }; - - // user object.assign to insert tokens from stream and jwt - result = Object.assign({}, result[0], { tokens: tokens }, { jwt: jwtToken }); - - // send response to client - res.send(200, result); - return next(); - - } - - // execute query - db.query('INSERT INTO users SET ?', data, function(err, result) { - - if (err) { - log.error(err); - return next(new restify.InternalError(err.message)); - } - - // user object.assign to insert new row id and tokens from stream - result = Object.assign({}, { id: result.insertId }, data, tokens); - - // initialize algolia - var algolia = algoliaSearch(config.algolia.appId, config.algolia.apiKey); - - // initialize algoia index - var index = algolia.initIndex('cabin'); - - // add returned database object for indexing - index.addObject(result); - - // use object.assign insert jwt - result = Object.assign({}, result, { jwt: jwtToken }); - - var userId = result.id; - - // auto follow user id 1 (a.k.a stream cabin) - db.query('INSERT INTO followers SET user_id=?, follower_id=?', [userId, 1], function(err, result) { - - // instantiate a new client (server side) - var streamClient = stream.connect(config.stream.key, config.stream.secret); - - // instantiate a feed using feed class 'user' and the user id from the database - var userFeed = streamClient.feed('user', userId); - - // build activity object for stream feed - var activity = { - actor: `user:${userId}`, - verb: 'follow', - object: `user:${1}`, - foreign_id: `follow:${userId}`, - time: data['created_at'], - to: [`notification:${1}`] - }; - - // instantiate a feed using feed class 'timeline_flat' and the user id from the database - var timeline = streamClient.feed('timeline_flat', userId); - timeline.follow('user_posts', 1); - - // instantiate a feed using feed class 'timeline_aggregated' and the user id from the database - var timelineAggregated = streamClient.feed('timeline_aggregated', userId); - timelineAggregated.follow('user', 1); - - // add activity to the feed - userFeed.addActivity(activity) - .then(function(response) { - - // send response to client - res.send(201, result); - return next(); - - }) - .catch(function(reason) { - log.error(reason); - return next(new restify.InternalError(reason.error)); - }); - - }); - - }); - - }); - }]); + // extract data from body + var data = req.body || {}; + var fbUserId = data.fb_user_id; + var accessToken = data.token; + var options = { + appId: '1714548178824131', + xfbml: true, + version: 'v2.6', + status: true, + cookie: true, + }; + var fb = new FB.Facebook(options); + fb.setAccessToken(accessToken); + + async.waterfall([ + function(cb) { + // query the userdata from FB + fb.api( + '/me', + 'get', + { fields: 'id,name,email, first_name, last_name' }, + function(facebookUserData) { + cb(null, facebookUserData); + }, + ); + }, + + function(facebookUserData, cb) { + // build the data we're going to insert + var data = {}; + data.email = facebookUserData.email; + data.fb_uid = facebookUserData.id; + data.first_name = facebookUserData.first_name; + data.last_name = facebookUserData.last_name; + + // try select first + db.query( + 'SELECT * FROM users WHERE email=' + db.escape(data.email), + function(err, result) { + if (err) { + log.error(err); + return next(new restify.InternalError(err.message)); + } + + // instantiate a new client (server side) + var streamClient = stream.connect( + config.stream.key, + config.stream.secret, + ); + + // generate jwt + var jwtToken = jwt.sign( + { + request: { + email: data.email, + }, + }, + config.jwt.secret, + ); + + // if user exists, return result + if (result.length) { + var userId = result[0].id; + + // get tokens from stream client + var tokens = { + timeline: { + flat: streamClient.getReadOnlyToken( + 'timeline_flat', + userId, + ), + aggregated: streamClient.getReadOnlyToken( + 'timeline_aggregrated', + userId, + ), + }, + notification: streamClient.getReadOnlyToken( + 'notification', + userId, + ), + }; + + // user object.assign to insert tokens from stream and jwt + result = Object.assign( + {}, + result[0], + { tokens: tokens }, + { jwt: jwtToken }, + ); + + // send response to client + res.send(200, result); + return next(); + } + + // execute query + db.query('INSERT INTO users SET ?', data, function( + err, + result, + ) { + if (err) { + log.error(err); + return next(new restify.InternalError(err.message)); + } + + // user object.assign to insert new row id and tokens from stream + result = Object.assign( + {}, + { id: result.insertId }, + data, + tokens, + ); + + // initialize algolia + var algolia = algoliaSearch( + config.algolia.appId, + config.algolia.apiKey, + ); + + // initialize algoia index + var index = algolia.initIndex('cabin'); + + // add returned database object for indexing + index.addObject(result); + + // use object.assign insert jwt + result = Object.assign({}, result, { jwt: jwtToken }); + + var userId = result.id; + + // auto follow user id 1 (a.k.a stream cabin) + db.query( + 'INSERT INTO followers SET user_id=?, follower_id=?', + [userId, 1], + function(err, result) { + // instantiate a new client (server side) + var streamClient = stream.connect( + config.stream.key, + config.stream.secret, + ); + + // instantiate a feed using feed class 'user' and the user id from the database + var userFeed = streamClient.feed( + 'user', + userId, + ); + + // build activity object for stream feed + var activity = { + actor: `user:${userId}`, + verb: 'follow', + object: `user:${1}`, + foreign_id: `follow:${userId}`, + time: data['created_at'], + to: [`notification:${1}`], + }; + + // instantiate a feed using feed class 'timeline_flat' and the user id from the database + var timeline = streamClient.feed( + 'timeline_flat', + userId, + ); + timeline.follow('user_posts', 1); + + // instantiate a feed using feed class 'timeline_aggregated' and the user id from the database + var timelineAggregated = streamClient.feed( + 'timeline_aggregated', + userId, + ); + timelineAggregated.follow('user', 1); + + // add activity to the feed + userFeed + .addActivity(activity) + .then(function(response) { + // send response to client + res.send(201, result); + return next(); + }) + .catch(function(reason) { + log.error(reason); + return next( + new restify.InternalError( + reason.error, + ), + ); + }); + }, + ); + }); + }, + ); + }, + ]); }); /** @@ -289,25 +335,22 @@ server.post('/users', function(req, res, next) { * @returns {object} Returns a 204 status code */ server.del('/users/:user_id', function(req, res, next) { - - var params = req.params || {}; - - db.query('DELETE FROM users WHERE id = ?', [params.user_id], function(err, result) { - - // catch all errors - if (err) { - - // use global logger to log to console - log.error(err); - - // return error message to client - return next(new restify.InternalError(err.message)); - - } - - res.send(204); - return next(); - - }); - + var params = req.params || {}; + + db.query('DELETE FROM users WHERE id = ?', [params.user_id], function( + err, + result, + ) { + // catch all errors + if (err) { + // use global logger to log to console + log.error(err); + + // return error message to client + return next(new restify.InternalError(err.message)); + } + + res.send(204); + return next(); + }); }); diff --git a/api/yarn.lock b/api/yarn.lock index 815db12..53398e8 100644 --- a/api/yarn.lock +++ b/api/yarn.lock @@ -2,9 +2,9 @@ # yarn lockfile v1 -Base64@>=0.3.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/Base64/-/Base64-1.0.0.tgz#b6b73ee342ce64bf66d6003a4536683bf8a349b5" +Base64@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/Base64/-/Base64-1.0.1.tgz#def45cc50c961bcc9bf2321d0f52bcbfec1f1bb1" addressparser@^0.3.2: version "0.3.2" @@ -14,7 +14,7 @@ addressparser@~0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-0.2.1.tgz#d11a5b2eeda04cfefebdf3196c10ae13db6cd607" -agentkeepalive@^2.1.1: +agentkeepalive@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-2.2.0.tgz#c5d1bd4b129008f1163f236f86e5faea2026e2ef" @@ -25,17 +25,26 @@ ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" -algoliasearch@^3.15.0: - version "3.22.1" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-3.22.1.tgz#132abb11134c52a3fd3ded3fcf6acb64f5eb738d" +ajv@^5.1.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +algoliasearch@^3.24.9: + version "3.24.9" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-3.24.9.tgz#19063470efe5b6779ec081394b1f7aa400438273" dependencies: - agentkeepalive "^2.1.1" - debug "2.3.3" + agentkeepalive "^2.2.0" + debug "^2.6.8" envify "^4.0.0" - es6-promise "^4.0.5" + es6-promise "^4.1.0" events "^1.1.0" foreach "^2.0.5" - global "^4.3.0" + global "^4.3.2" inherits "^2.0.1" isarray "^2.0.1" load-script "^1.0.0" @@ -43,7 +52,19 @@ algoliasearch@^3.15.0: querystring-es3 "^0.2.1" reduce "^1.0.1" semver "^5.1.0" - tunnel-agent "^0.4.3" + tunnel-agent "^0.6.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +any-promise@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" asap@*: version "2.0.5" @@ -73,9 +94,9 @@ async@^0.9.0, async@~0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" -async@^2.0.0-rc.6: - version "2.1.5" - resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" +async@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" dependencies: lodash "^4.14.0" @@ -91,22 +112,20 @@ aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" -aws4@^1.2.1: +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.2.1, aws4@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" -babel-runtime@^6.3.19: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" +babel-runtime@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: core-js "^2.4.0" - regenerator-runtime "^0.10.0" - -backoff@^2.4.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f" - dependencies: - precond "0.2" + regenerator-runtime "^0.11.0" balanced-match@^0.4.1: version "0.4.2" @@ -122,9 +141,15 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -bignumber.js@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-3.1.2.tgz#f3bdb99ad5268a15fc1f0bed2fb018e2693fe236" +bignumber.js@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.0.4.tgz#7c40f5abcd2d6623ab7b99682ee7db81b11889a4" + +bl@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" + dependencies: + readable-stream "~2.0.5" boom@2.x.x: version "2.10.1" @@ -132,6 +157,18 @@ boom@2.x.x: dependencies: hoek "2.x.x" +boom@4.x.x: + version "4.3.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" + dependencies: + hoek "4.x.x" + +boom@5.x.x: + version "5.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" + dependencies: + hoek "4.x.x" + brace-expansion@^1.0.0: version "1.1.6" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" @@ -155,28 +192,40 @@ bunyan-winston-adapter@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/bunyan-winston-adapter/-/bunyan-winston-adapter-0.2.0.tgz#950310633405ab5e65fdb7fee76f18fe6a998fcd" -bunyan@^1.4.0: - version "1.8.8" - resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.8.tgz#6549ed6db088e4d82b7be3bcc6d0697159f6e209" +bunyan@^1.8.0, bunyan@^1.8.12: + version "1.8.12" + resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.12.tgz#f150f0f6748abdd72aeae84f04403be2ef113797" optionalDependencies: dtrace-provider "~0.8" moment "^2.10.6" mv "~2" safe-json-stringify "~1" -bunyan@^1.8.10: - version "1.8.10" - resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.10.tgz#201fedd26c7080b632f416072f53a90b9a52981c" - optionalDependencies: - dtrace-provider "~0.8" - moment "^2.10.6" - mv "~2" - safe-json-stringify "~1" +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" +chalk@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +clone-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-1.0.0.tgz#eae0a2413f55c0942f818c229fefce845d7f3b1c" + dependencies: + is-regexp "^1.0.0" + is-supported-regexp-flag "^1.0.0" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -197,6 +246,10 @@ combined-stream@~0.0.4: dependencies: delayed-stream "0.0.5" +commander@^2.9.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + component-emitter@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" @@ -205,10 +258,6 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -cookie@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.1.0.tgz#90eb469ddce905c866de687efc43131d8801f9d0" - cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" @@ -217,9 +266,9 @@ cookiejar@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.0.1.tgz#3d12752f6adf68a892f332433492bd5812bb668f" -core-decorators@^0.12.3: - version "0.12.3" - resolved "https://registry.yarnpkg.com/core-decorators/-/core-decorators-0.12.3.tgz#6b3f83378e680d48b0c08da4489899b7532dcb43" +core-decorators@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/core-decorators/-/core-decorators-0.17.0.tgz#3f43180a86d2ab0cc51069f46a1ec3e49e7cebd6" core-js@^2.4.0: version "2.4.1" @@ -235,32 +284,40 @@ cryptiles@2.x.x: dependencies: boom "2.x.x" +cryptiles@3.x.x: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" + dependencies: + boom "5.x.x" + csprng@*: version "0.1.2" resolved "https://registry.yarnpkg.com/csprng/-/csprng-0.1.2.tgz#4bc68f12fa368d252a59841cbaca974b18ab45e2" dependencies: sequin "*" -csv-generate@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/csv-generate/-/csv-generate-0.0.6.tgz#97e4e63ae46b21912cd9475bc31469d26f5ade66" +csv-generate@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/csv-generate/-/csv-generate-1.1.2.tgz#ec6b00edaed6e59ad9c20582f4c364e28b146240" -csv-parse@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-1.2.0.tgz#047b73868ab9a85746e885f637f9ed0fb645a425" +csv-parse@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-1.3.3.tgz#d1cfd8743c2f849a0abb2fd544db56695d19a490" -csv-stringify@^0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/csv-stringify/-/csv-stringify-0.0.8.tgz#52cc3b3dfc197758c55ad325a95be85071f9e51b" +csv-stringify@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/csv-stringify/-/csv-stringify-1.1.2.tgz#77a41526581bce3380f12b00d7c5bbac70c82b58" + dependencies: + lodash.get "~4.4.2" -csv@^0.4.0: - version "0.4.6" - resolved "https://registry.yarnpkg.com/csv/-/csv-0.4.6.tgz#8dbae7ddfdbaae62c1ea987c3e0f8a9ac737b73d" +csv@^1.1.0, csv@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/csv/-/csv-1.2.1.tgz#5231edfc1c7152512ec45781076a7a97ff525c0c" dependencies: - csv-generate "^0.0.6" - csv-parse "^1.0.0" - csv-stringify "^0.0.8" - stream-transform "^0.1.0" + csv-generate "^1.1.2" + csv-parse "^1.3.3" + csv-stringify "^1.1.2" + stream-transform "^0.2.2" ctype@0.5.3: version "0.5.3" @@ -276,7 +333,7 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@2, debug@2.3.3, debug@^2.2.0: +debug@2: version "2.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" dependencies: @@ -288,6 +345,12 @@ debug@^1.0.2: dependencies: ms "0.6.2" +debug@^2.6.3, debug@^2.6.8: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + delayed-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" @@ -296,15 +359,19 @@ delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" +detect-node@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" + dom-walk@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" -dtrace-provider@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.6.0.tgz#0b078d5517937d873101452d9146737557b75e51" +dtrace-provider@^0.8.1: + version "0.8.6" + resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.8.6.tgz#428a223afe03425d2cd6d6347fdf40c66903563d" dependencies: - nan "^2.0.8" + nan "^2.3.3" dtrace-provider@~0.8: version "0.8.1" @@ -349,14 +416,18 @@ envify@^4.0.0: esprima "~3.1.0" through "~2.3.4" -es6-promise@^4.0.5: - version "4.1.0" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.1.0.tgz#dda03ca8f9f89bc597e689842929de7ba8cebdf0" +es6-promise@^4.1.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.2.tgz#f722d7769af88bd33bc13ec6605e1f92966b82d9" escape-regexp-component@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/escape-regexp-component/-/escape-regexp-component-1.0.2.tgz#9c63b6d0b25ff2a88c3adbd18c5b61acc3b9faa2" +escape-string-regexp@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + esprima@~3.1.0: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" @@ -365,6 +436,12 @@ events@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" +ewma@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ewma/-/ewma-2.0.1.tgz#9876c1c491ac5733c8666001a3961a04c97cf1e8" + dependencies: + assert-plus "^1.0.0" + express-unless@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/express-unless/-/express-unless-0.3.0.tgz#5c795e7392571512dd28f520b3857a52b21261a2" @@ -377,6 +454,10 @@ extend@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" +extend@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + extsprintf@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" @@ -393,13 +474,21 @@ eyes@0.1.x: version "0.1.8" resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" +fast-deep-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + faye-websocket@>=0.9.1: version "0.11.1" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" dependencies: websocket-driver ">=0.5.1" -faye@>=1.2.0: +faye@~1.2.0: version "1.2.4" resolved "https://registry.yarnpkg.com/faye/-/faye-1.2.4.tgz#978ed8a58f1d481e5c1f98bacb8959de5ec5c643" dependencies: @@ -409,14 +498,15 @@ faye@>=1.2.0: tough-cookie "*" tunnel-agent "*" -fb@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/fb/-/fb-1.1.1.tgz#b3f036689e55098d6f88a6dee6551d0316fd6b57" +fb@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fb/-/fb-2.0.0.tgz#91fd40325da34ec41c68b25530fc3a3e0dacfa6a" dependencies: - babel-runtime "^6.3.19" - core-decorators "^0.12.3" - debug "^2.2.0" - request "^2.67.0" + any-promise "^1.3.0" + babel-runtime "^6.23.0" + core-decorators "^0.17.0" + debug "^2.6.3" + request "^2.81.0" foreach@^2.0.5: version "2.0.5" @@ -434,6 +524,14 @@ form-data@0.1.3: combined-stream "~0.0.4" mime "~1.2.11" +form-data@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.0.0.tgz#6f0aebadcc5da16c13e1ecc11137d85f9b883b25" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.11" + form-data@~2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" @@ -442,31 +540,49 @@ form-data@~2.1.1: combined-stream "^1.0.5" mime-types "^2.1.12" +form-data@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + formidable@1.0.14: version "1.0.14" resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.0.14.tgz#2b3f4c411cbb5fdd695c44843e2a23514a43231a" -formidable@^1.0.14: +formidable@^1.0.17, formidable@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.1.1.tgz#96b8886f7c3c3508b932d6bd70c4d3a88f35f1a9" +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + getpass@^0.1.1: version "0.1.6" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" dependencies: assert-plus "^1.0.0" -getstream@^3.2.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/getstream/-/getstream-3.5.0.tgz#7eb9206c202d425e4b5f877c8bcab1b64e23eaff" +getstream@^3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/getstream/-/getstream-3.10.0.tgz#e7a099075157ac669e970e2bffbca38c86f3f487" dependencies: - Base64 ">=0.3.0" - faye ">=1.2.0" - http-signature ">=1.0.2" - jsonwebtoken "5.0.1" - qs ">=6.2.0" - request ">=2.67.0" - xmlhttp-request ">=0.4.0" + Base64 "~1.0.0" + faye "~1.2.0" + http-signature "~1.1.1" + jsonwebtoken "7.1.9" + qs "~6.2.0" + request "2.75.0" + xmlhttp-request "~0.4.1" glob@^6.0.1: version "6.0.4" @@ -478,14 +594,14 @@ glob@^6.0.1: once "^1.3.0" path-is-absolute "^1.0.0" -global@^4.3.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/global/-/global-4.3.1.tgz#5f757908c7cbabce54f386ae440e11e26b7916df" +global@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" dependencies: min-document "^2.19.0" process "~0.5.1" -handle-thing@^1.2.4: +handle-thing@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" @@ -493,6 +609,19 @@ har-schema@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + har-validator@~4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" @@ -500,6 +629,19 @@ har-validator@~4.2.1: ajv "^4.9.1" har-schema "^1.0.5" +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + hawk@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" @@ -509,10 +651,23 @@ hawk@~3.1.3: hoek "2.x.x" sntp "1.x.x" +hawk@~6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" + dependencies: + boom "4.x.x" + cryptiles "3.x.x" + hoek "4.x.x" + sntp "2.x.x" + hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" +hoek@4.x.x: + version "4.2.0" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" + hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" @@ -522,18 +677,10 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -http-deceiver@^1.2.4: +http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" -http-signature@>=1.0.2, http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - http-signature@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.11.0.tgz#1796cf67a001ad5cd6849dca0991485f09089fe6" @@ -542,6 +689,22 @@ http-signature@^0.11.0: assert-plus "^0.1.5" ctype "0.5.3" +http-signature@^1.2.0, http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +http-signature@~1.1.0, http-signature@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + iconv-lite@~0.4.13: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" @@ -553,10 +716,31 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@~2.0.1: +inherits@2, inherits@^2.0.1, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" +is-my-json-valid@^2.12.4: + version "2.17.1" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + +is-supported-regexp-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.0.tgz#8b520c85fae7a253382d4b02652e045576e13bb8" + is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -600,6 +784,10 @@ jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" @@ -618,20 +806,39 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" -jsonwebtoken@5.0.1, jsonwebtoken@^5.0.0: +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsonwebtoken@7.1.9: + version "7.1.9" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz#847804e5258bec5a9499a8dc4a5e7a3bae08d58a" + dependencies: + joi "^6.10.1" + jws "^3.1.3" + lodash.once "^4.0.0" + ms "^0.7.1" + xtend "^4.0.1" + +jsonwebtoken@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-5.0.1.tgz#5d85ce580421915be22e4aa7b13d4bb99b280a2a" dependencies: jws "^3.0.0" -jsonwebtoken@^7.0.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-7.3.0.tgz#85118d6a70e3fccdf14389f4e7a1c3f9c8a9fbba" +jsonwebtoken@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.1.0.tgz#c6397cd2e5fd583d65c007a83dc7bb78e6982b83" dependencies: - joi "^6.10.1" jws "^3.1.4" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" lodash.once "^4.0.0" - ms "^0.7.1" + ms "^2.0.0" xtend "^4.0.1" jsprim@^1.2.2: @@ -652,7 +859,7 @@ jwa@^1.1.4: ecdsa-sig-formatter "1.0.9" safe-buffer "^5.0.1" -jws@^3.0.0, jws@^3.1.4: +jws@^3.0.0, jws@^3.1.3, jws@^3.1.4: version "3.1.4" resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2" dependencies: @@ -667,10 +874,6 @@ keen.io@^0.1.3: superagent "~0.21.0" underscore "~1.5.2" -keep-alive-agent@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/keep-alive-agent/-/keep-alive-agent-0.0.1.tgz#44847ca394ce8d6b521ae85816bd64509942b385" - knox@^0.9.2: version "0.9.2" resolved "https://registry.yarnpkg.com/knox/-/knox-0.9.2.tgz#3736593669e24f024fdaf723b6a1dc4afd839a71" @@ -685,11 +888,39 @@ load-script@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4" +lodash.get@~4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" -lodash@^4.0.0, lodash@^4.12.0, lodash@^4.14.0: +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.2.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -700,13 +931,20 @@ lru-cache@^4.0.1: pseudomap "^1.0.1" yallist "^2.0.0" +lru-cache@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + lsmod@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lsmod/-/lsmod-1.0.0.tgz#9a00f76dca36eb23fa05350afe1b585d4299e64b" -mapbox-geocoding@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/mapbox-geocoding/-/mapbox-geocoding-0.1.4.tgz#5ee3487cf4d218875198553eec9e2acf81926a4e" +mapbox-geocoding@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/mapbox-geocoding/-/mapbox-geocoding-0.1.5.tgz#97c4048669eb4431088cef2ea9a9078c6eb9f8ed" dependencies: request "^2.67.0" @@ -718,13 +956,23 @@ mime-db@~1.26.0: version "1.26.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" +mime-db@~1.30.0: + version "1.30.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" + +mime-types@^2.1.11, mime-types@~2.1.17: + version "2.1.17" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" + dependencies: + mime-db "~1.30.0" + mime-types@^2.1.12, mime-types@~2.1.7: version "2.1.14" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" dependencies: mime-db "~1.26.0" -mime@*, mime@^1.2.11: +mime@*: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" @@ -732,6 +980,10 @@ mime@1.2.11, mime@~1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" +mime@^1.3.4, mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + mimelib@0.2.14: version "0.2.14" resolved "https://registry.yarnpkg.com/mimelib/-/mimelib-0.2.14.tgz#2a1aa724bd190b85bd526e6317ab6106edfd6831" @@ -781,10 +1033,18 @@ ms@0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + ms@^0.7.1: version "0.7.3" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" +ms@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + mustache@^2.2.1: version "2.3.0" resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" @@ -797,15 +1057,16 @@ mv@~2: ncp "~2.0.0" rimraf "~2.4.0" -mysql@^2.11.1: - version "2.13.0" - resolved "https://registry.yarnpkg.com/mysql/-/mysql-2.13.0.tgz#998f1f8ca46e2e3dd7149ce982413653986aae47" +mysql@^2.15.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/mysql/-/mysql-2.15.0.tgz#ea16841156343e8f2e47fc8985ec41cdd9573b5c" dependencies: - bignumber.js "3.1.2" - readable-stream "1.1.14" - sqlstring "2.2.0" + bignumber.js "4.0.4" + readable-stream "2.3.3" + safe-buffer "5.1.1" + sqlstring "2.3.0" -nan@^2.0.8, nan@^2.3.3: +nan@^2.3.3: version "2.5.1" resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.1.tgz#d5b01691253326a97a2bbee9e61c55d8d60351e2" @@ -817,11 +1078,11 @@ negotiator@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" -node-uuid@^1.4.1, node-uuid@^1.4.7, node-uuid@~1.4.1: - version "1.4.7" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" +node-uuid@^1.4.8, node-uuid@~1.4.7: + version "1.4.8" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" -oauth-sign@~0.8.1: +oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -829,11 +1090,11 @@ object-keys@^1.0.11, object-keys@~1.0.0: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" -obuf@^1.0.0, obuf@^1.1.0: +obuf@^1.0.0, obuf@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e" -once@^1.3.0: +once@^1.3.0, once@^1.3.2, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: @@ -847,9 +1108,23 @@ performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" -precond@0.2: - version "0.2.3" - resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +pidusage@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-1.2.0.tgz#65ee96ace4e08a4cd3f9240996c85b367171ee92" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" process-nextick-args@~1.0.6: version "1.0.7" @@ -859,7 +1134,7 @@ process@~0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" -pseudomap@^1.0.1: +pseudomap@^1.0.1, pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -871,31 +1146,40 @@ qs@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/qs/-/qs-1.2.0.tgz#ed079be28682147e6fd9a34cc2b0c1e0ec6453ee" -qs@>=6.2.0, qs@^6.2.1, qs@~6.4.0: +qs@^6.2.1, qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" +qs@^6.5.1, qs@~6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + +qs@~6.2.0: + version "6.2.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe" + querystring-es3@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" -raven@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/raven/-/raven-0.11.0.tgz#32981138a93e4c8ad08cfc17e46b85b453dc107b" +raven@^1.1.4: + version "1.2.1" + resolved "https://registry.yarnpkg.com/raven/-/raven-1.2.1.tgz#949c134db028a190b7bbf8f790aae541b7c020bd" dependencies: - cookie "0.1.0" + cookie "0.3.1" + json-stringify-safe "5.0.1" lsmod "1.0.0" - node-uuid "~1.4.1" - stack-trace "0.0.7" + stack-trace "0.0.9" + uuid "3.0.0" -raven@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/raven/-/raven-1.2.0.tgz#0f0d4463362e03f04793b3aab47619cbaf39da75" +raven@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/raven/-/raven-2.3.0.tgz#96f15346bdaa433b3b6d47130804506155833d69" dependencies: cookie "0.3.1" - json-stringify-safe "5.0.1" lsmod "1.0.0" stack-trace "0.0.9" + timed-out "4.0.1" uuid "3.0.0" readable-stream@1.0.27-1: @@ -907,14 +1191,17 @@ readable-stream@1.0.27-1: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@1.1.14: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" +readable-stream@2.3.3, readable-stream@^2.2.9: + version "2.3.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" + util-deprecate "~1.0.1" readable-stream@^2.0.1: version "2.2.6" @@ -928,6 +1215,17 @@ readable-stream@^2.0.1: string_decoder "~0.10.x" util-deprecate "~1.0.1" +readable-stream@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + reduce-component@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/reduce-component/-/reduce-component-1.0.1.tgz#e0c93542c574521bea13df0f9488ed82ab77c5da" @@ -938,11 +1236,37 @@ reduce@^1.0.1: dependencies: object-keys "~1.0.0" -regenerator-runtime@^0.10.0: - version "0.10.3" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +request@2.75.0: + version "2.75.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.75.0.tgz#d2b8268a286da13eaa5d01adf5d18cc90f657d93" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + bl "~1.1.2" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.0.0" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + node-uuid "~1.4.7" + oauth-sign "~0.8.1" + qs "~6.2.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" -request@>=2.67.0, request@^2.67.0: +request@^2.67.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" dependencies: @@ -969,6 +1293,53 @@ request@>=2.67.0, request@^2.67.0: tunnel-agent "^0.6.0" uuid "^3.0.0" +request@^2.81.0: + version "2.83.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + hawk "~6.0.2" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +restify-errors@^4.2.3: + version "4.3.0" + resolved "https://registry.yarnpkg.com/restify-errors/-/restify-errors-4.3.0.tgz#ec90f30934d7f3119135181dfc303e30be601abe" + dependencies: + assert-plus "^1.0.0" + lodash "^4.2.1" + verror "^1.8.1" + optionalDependencies: + safe-json-stringify "^1.0.3" + +restify-errors@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/restify-errors/-/restify-errors-5.0.0.tgz#668717e100683eec6ce0d515f89ff1dbec254a8d" + dependencies: + assert-plus "^1.0.0" + lodash "^4.2.1" + verror "^1.8.1" + optionalDependencies: + safe-json-stringify "^1.0.3" + restify-jwt@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/restify-jwt/-/restify-jwt-0.4.0.tgz#22274c8ce6ef6e6e6bb5074b381f2b57bff7bd1f" @@ -977,31 +1348,50 @@ restify-jwt@^0.4.0: express-unless "^0.3.0" jsonwebtoken "^5.0.0" -restify@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/restify/-/restify-4.3.0.tgz#03b67960d1d42a6dafcde3bd82fb882173a27678" +restify-plugins@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/restify-plugins/-/restify-plugins-1.6.0.tgz#79e118887b7f0eb02e645780f9c5680cb7ab9aa9" dependencies: - assert-plus "^0.1.5" - backoff "^2.4.0" - bunyan "^1.4.0" - csv "^0.4.0" + assert-plus "^1.0.0" + bunyan "^1.8.0" + csv "^1.1.0" escape-regexp-component "^1.0.2" - formidable "^1.0.14" + formidable "^1.0.17" http-signature "^0.11.0" - keep-alive-agent "^0.0.1" lru-cache "^4.0.1" - mime "^1.2.11" - negotiator "^0.6.1" - node-uuid "^1.4.1" - once "^1.3.0" + mime "^1.3.4" + once "^1.3.2" qs "^6.2.1" - semver "^4.3.3" - spdy "^3.3.3" - tunnel-agent "^0.4.0" - vasync "1.6.3" - verror "^1.4.0" + restify-errors "^4.2.3" + vasync "^1.6.3" + +restify@^6.3.4: + version "6.3.4" + resolved "https://registry.yarnpkg.com/restify/-/restify-6.3.4.tgz#097990b22ba40f02a074a7d4cb1c27690759e288" + dependencies: + assert-plus "^1.0.0" + bunyan "^1.8.12" + clone-regexp "^1.0.0" + csv "^1.1.1" + escape-regexp-component "^1.0.2" + ewma "^2.0.1" + formidable "^1.1.1" + http-signature "^1.2.0" + lodash "^4.17.4" + lru-cache "^4.1.1" + mime "^1.4.1" + negotiator "^0.6.1" + once "^1.4.0" + pidusage "^1.2.0" + qs "^6.5.1" + restify-errors "^5.0.0" + semver "^5.4.1" + spdy "^3.4.7" + uuid "^3.1.0" + vasync "^1.6.4" + verror "^1.10.0" optionalDependencies: - dtrace-provider "^0.6.0" + dtrace-provider "^0.8.1" rimraf@~2.4.0: version "2.4.5" @@ -1009,11 +1399,15 @@ rimraf@~2.4.0: dependencies: glob "^6.0.1" +safe-buffer@5.1.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + safe-buffer@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" -safe-json-stringify@~1: +safe-json-stringify@^1.0.3, safe-json-stringify@~1: version "1.0.4" resolved "https://registry.yarnpkg.com/safe-json-stringify/-/safe-json-stringify-1.0.4.tgz#81a098f447e4bbc3ff3312a243521bc060ef5911" @@ -1025,14 +1419,14 @@ select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" -semver@^4.3.3: - version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - semver@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" +semver@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + sequin@*: version "0.1.0" resolved "https://registry.yarnpkg.com/sequin/-/sequin-0.1.0.tgz#17c5566d9d555413aa12fc8bc96ed309c80e0aad" @@ -1043,29 +1437,38 @@ sntp@1.x.x: dependencies: hoek "2.x.x" -spdy-transport@^2.0.15: - version "2.0.18" - resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.0.18.tgz#43fc9c56be2cccc12bb3e2754aa971154e836ea6" +sntp@2.x.x: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" + dependencies: + hoek "4.x.x" + +spdy-transport@^2.0.18: + version "2.0.20" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.0.20.tgz#735e72054c486b2354fe89e702256004a39ace4d" dependencies: - debug "^2.2.0" + debug "^2.6.8" + detect-node "^2.0.3" hpack.js "^2.1.6" - obuf "^1.1.0" - readable-stream "^2.0.1" - wbuf "^1.4.0" + obuf "^1.1.1" + readable-stream "^2.2.9" + safe-buffer "^5.0.1" + wbuf "^1.7.2" -spdy@^3.3.3: - version "3.4.4" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.4.tgz#e0406407ca90ff01b553eb013505442649f5a819" +spdy@^3.4.7: + version "3.4.7" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc" dependencies: - debug "^2.2.0" - handle-thing "^1.2.4" - http-deceiver "^1.2.4" + debug "^2.6.8" + handle-thing "^1.2.5" + http-deceiver "^1.2.7" + safe-buffer "^5.0.1" select-hose "^2.0.0" - spdy-transport "^2.0.15" + spdy-transport "^2.0.18" -sqlstring@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.2.0.tgz#c3135c4ea8abcd7e7ee741a4966a891d86a4f191" +sqlstring@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.0.tgz#525b8a4fd26d6f71aa61e822a6caf976d31ad2a8" sshpk@^1.7.0: version "1.11.0" @@ -1082,14 +1485,14 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" -stack-trace@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.7.tgz#c72e089744fc3659f508cdce3621af5634ec0fff" - -stack-trace@0.0.9, stack-trace@0.0.x, stack-trace@^0.0.9: +stack-trace@0.0.9, stack-trace@0.0.x: version "0.0.9" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" +stack-trace@^0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + starttls@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/starttls/-/starttls-1.0.1.tgz#e6081c25de6b178f5a75f8f271c1487449183b42" @@ -1098,18 +1501,30 @@ stream-counter@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stream-counter/-/stream-counter-1.0.0.tgz#91cf2569ce4dc5061febcd7acb26394a5a114751" -stream-transform@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/stream-transform/-/stream-transform-0.1.2.tgz#7d8e6b4e03ac4781778f8c79517501bfb0762a9f" +stream-transform@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/stream-transform/-/stream-transform-0.2.2.tgz#75867487f49528f8bf1d82499658753d02df7838" string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" -stringstream@~0.0.4: +string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + dependencies: + safe-buffer "~5.1.0" + +stringstream@~0.0.4, stringstream@~0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + superagent@~0.21.0: version "0.21.0" resolved "https://registry.yarnpkg.com/superagent/-/superagent-0.21.0.tgz#fb15027984751ee7152200e6cd21cd6e19a5de87" @@ -1126,10 +1541,18 @@ superagent@~0.21.0: readable-stream "1.0.27-1" reduce-component "1.0.1" +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + through@~2.3.4: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" +timed-out@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + topo@1.x.x: version "1.1.0" resolved "https://registry.yarnpkg.com/topo/-/topo-1.1.0.tgz#e9d751615d1bb87dc865db182fa1ca0a5ef536d5" @@ -1142,13 +1565,19 @@ tough-cookie@*, tough-cookie@~2.3.0: dependencies: punycode "^1.4.1" +tough-cookie@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" + dependencies: + punycode "^1.4.1" + tunnel-agent@*, tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" dependencies: safe-buffer "^5.0.1" -tunnel-agent@^0.4.0, tunnel-agent@^0.4.3: +tunnel-agent@~0.4.1: version "0.4.3" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" @@ -1168,9 +1597,13 @@ uuid@3.0.0, uuid@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" -vasync@1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/vasync/-/vasync-1.6.3.tgz#4a69d7052a47f4ce85503d7641df1cbf40432a94" +uuid@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" + +vasync@^1.6.3, vasync@^1.6.4: + version "1.6.4" + resolved "https://registry.yarnpkg.com/vasync/-/vasync-1.6.4.tgz#dfe93616ad0e7ae801b332a9d88bfc5cdc8e1d1f" dependencies: verror "1.6.0" @@ -1186,15 +1619,15 @@ verror@1.6.0: dependencies: extsprintf "1.2.0" -verror@^1.4.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.9.0.tgz#107a8a2d14c33586fc4bb830057cd2d19ae2a6ee" +verror@^1.10.0, verror@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" dependencies: assert-plus "^1.0.0" core-util-is "1.0.2" extsprintf "^1.2.0" -wbuf@^1.1.0, wbuf@^1.4.0: +wbuf@^1.1.0, wbuf@^1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.2.tgz#d697b99f1f59512df2751be42769c1580b5801fe" dependencies: @@ -1210,23 +1643,23 @@ websocket-extensions@>=0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" -winston-mail@^1.2.0: +winston-mail@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/winston-mail/-/winston-mail-1.3.0.tgz#10b05702b73ce9f2e9b3329a522e98b6ed4dcdc0" dependencies: emailjs "^1.0.8" mustache "^2.2.1" -winston-sentry@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/winston-sentry/-/winston-sentry-0.1.5.tgz#b86efc01d757c84bc5da78314c7788b42776be50" +winston-sentry@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/winston-sentry/-/winston-sentry-0.2.1.tgz#dfdcc828f35a735a8e01e781918af652eb97c75c" dependencies: - lodash "^4.12.0" - raven "^0.11.0" + lodash "^4.17.4" + raven "^1.1.4" -winston@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/winston/-/winston-2.3.1.tgz#0b48420d978c01804cf0230b648861598225a119" +winston@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.0.tgz#808050b93d52661ed9fb6c26b3f0c826708b0aee" dependencies: async "~1.0.0" colors "1.0.x" @@ -1252,14 +1685,14 @@ xmlbuilder@^4.1.0: dependencies: lodash "^4.0.0" -xmlhttp-request@>=0.4.0: +xmlhttp-request@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/xmlhttp-request/-/xmlhttp-request-0.4.1.tgz#636d99355a91e1865b38ea039099ddc59af6a7a7" -xtend@^4.0.1: +xtend@^4.0.0, xtend@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" -yallist@^2.0.0: +yallist@^2.0.0, yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" diff --git a/app/config.js b/app/config.js index 5b5c4a1..17c4863 100644 --- a/app/config.js +++ b/app/config.js @@ -4,29 +4,29 @@ * Config */ module.exports = { - name: 'GetStream.io - React Example App', - version: '1.0.0', - env: process.env.NODE_ENV || 'DEVELOPMENT', - mapbox: { - accessToken: process.env.MAPBOX_ACCESS_TOKEN, - }, - stream: { - appId: process.env.STREAM_APP_ID, - key: process.env.STREAM_KEY, - }, - api: { - baseUrl: process.env.API_URL, - }, - imgix: { - baseUrl: process.env.IMGIX_BASE_URL, - }, - algolia: { - appId: process.env.ALGOLIA_APP_ID, - searchOnlyKey: process.env.ALGOLIA_SEARCH_ONLY_KEY, - }, - keen: { - projectId: process.env.KEEN_PROJECT_ID, - writeKey: process.env.KEEN_WRITE_KEY, - readKey: process.env.KEEN_READ_KEY, - } + name: 'GetStream.io - React Example App', + version: '1.0.0', + env: process.env.NODE_ENV || 'DEVELOPMENT', + mapbox: { + accessToken: process.env.MAPBOX_ACCESS_TOKEN, + }, + stream: { + appId: process.env.STREAM_APP_ID, + key: process.env.STREAM_KEY, + }, + api: { + baseUrl: process.env.API_URL, + }, + imgix: { + baseUrl: process.env.IMGIX_BASE_URL, + }, + algolia: { + appId: process.env.ALGOLIA_APP_ID, + searchOnlyKey: process.env.ALGOLIA_SEARCH_ONLY_KEY, + }, + keen: { + projectId: process.env.KEEN_PROJECT_ID, + writeKey: process.env.KEEN_WRITE_KEY, + readKey: process.env.KEEN_READ_KEY, + }, }; diff --git a/app/modules/App.js b/app/modules/App.js index b308e43..27e739c 100644 --- a/app/modules/App.js +++ b/app/modules/App.js @@ -1,51 +1,47 @@ -import React, { Component, cloneElement } from 'react' -import { connect } from 'react-redux' -import { browserHistory } from 'react-router' +import React, { Component, cloneElement } from 'react'; +import { connect } from 'react-redux'; +import { browserHistory } from 'react-router'; -import stream from 'getstream' -import config from 'config' +import stream from 'getstream'; +import config from 'config'; -const Home = require('./routes/Home/Home').default +const Home = require('./routes/Home/Home').default; import { - App as AppActions, - User as UserActions, - Photos as PhotoActions, - Header as HeaderActions, - Stream as StreamActions, -} from 'actions' + App as AppActions, + User as UserActions, + Photos as PhotoActions, + Header as HeaderActions, + Stream as StreamActions, +} from 'actions'; -import { - Header, -} from 'components' - -@connect(state => ({ - header: state.Header, - user: state.User, -})) +import { Header } from 'components'; /** * AppHeader component */ +@connect(state => ({ + header: state.Header, + user: state.User, +})) class AppHeader extends Component { - - /** + /** * render * @returns markup */ - render() { - - const { header, user, router, } = this.props - - return ( -
- ) - } + render() { + const { header, user, router } = this.props; + + return ( +
+ ); + } } /** @@ -55,33 +51,31 @@ class AppHeader extends Component { * @param location */ function handleRouteChange(dispatch, route, location) { - if (route) { - - if (route.getHeaderLeft) { - route.getHeaderLeft(location, (err, component) => { - dispatch(HeaderActions.left(component)) - }) - } else { - dispatch(HeaderActions.left(null)) - } - - if (route.getHeaderMiddle) { - route.getHeaderMiddle(location, (err, component) => { - dispatch(HeaderActions.middle(component)) - }) - } else { - dispatch(HeaderActions.middle(null)) - } - - if (route.getHeaderRight) { - route.getHeaderRight(location, (err, component) => { - dispatch(HeaderActions.right(component)) - }) - } else { - dispatch(HeaderActions.right(null)) - } - - } + if (route) { + if (route.getHeaderLeft) { + route.getHeaderLeft(location, (err, component) => { + dispatch(HeaderActions.left(component)); + }); + } else { + dispatch(HeaderActions.left(null)); + } + + if (route.getHeaderMiddle) { + route.getHeaderMiddle(location, (err, component) => { + dispatch(HeaderActions.middle(component)); + }); + } else { + dispatch(HeaderActions.middle(null)); + } + + if (route.getHeaderRight) { + route.getHeaderRight(location, (err, component) => { + dispatch(HeaderActions.right(component)); + }); + } else { + dispatch(HeaderActions.right(null)); + } + } } /** @@ -89,121 +83,136 @@ function handleRouteChange(dispatch, route, location) { * Bootstraps application */ class App extends Component { - - static contextTypes = { - router: React.PropTypes.object.isRequired, - } - - componentWillMount() { - // instantiate a new client (client side) - this.client = stream.connect(config.stream.key, null, config.stream.appId) - } - - /** + static contextTypes = { + router: React.PropTypes.object.isRequired, + }; + + componentWillMount() { + // instantiate a new client (client side) + this.client = stream.connect( + config.stream.key, + null, + config.stream.appId, + ); + } + + /** * componentDidUpdate * @param oldProps * @returns {*} */ - componentDidUpdate(oldProps) { - - handleRouteChange( - this.props.dispatch, - this.props.routes[this.props.routes.length - 1], - this.props.location - ) - - if (oldProps.user.id != this.props.user.id && !this.props.user.id) { - return browserHistory.push('/landing') - } - - if (oldProps.user.id != this.props.user.id && this.props.user.id) { - this.connectToStream() - this.props.dispatch(AppActions.init()) - } - - } - - /** + componentDidUpdate(oldProps) { + handleRouteChange( + this.props.dispatch, + this.props.routes[this.props.routes.length - 1], + this.props.location, + ); + + if (oldProps.user.id != this.props.user.id && !this.props.user.id) { + return browserHistory.push('/landing'); + } + + if (oldProps.user.id != this.props.user.id && this.props.user.id) { + this.connectToStream(); + this.props.dispatch(AppActions.init()); + } + } + + /** * componentDidMount */ - componentDidMount() { - - const { dispatch } = this.props - - FB.getLoginStatus(res => { - if (res.status !== 'connected') { - if (this.props.location.pathname != '/landing') { - browserHistory.replace('/landing') - } - this.props.dispatch(AppActions.initDone()) - return - } - - dispatch(UserActions.fbLogin(res)) - - if (this.props.location.pathname == '/landing') { - browserHistory.replace('/') - } - - }) - - } - - connectToStream = () => { - // follow 'timeline_flat' feed - this.timeline = this.client.feed('timeline_flat', this.props.user.id, this.props.tokens.timelineFlat) - this.timeline - .subscribe(data => { - this.props.dispatch(StreamActions.timeline(data)) - }) - .then(() => { - //console.log('Full (Timeline Flat): Connected to faye channel, waiting for realtime updates'); - }, (err) => { - console.error('Full (Timeline Flat): Could not estabilsh faye connection', err); - }); - - // follow 'notifications' feed - this.notification = this.client.feed('notification', this.props.user.id, this.props.tokens.notification) - this.notification - .subscribe(data => { - this.props.dispatch(StreamActions.event(data)) - }) - .then(() => { - //console.log('Full (Notifications): Connected to faye channel, waiting for realtime updates'); - }, (err) => { - console.error('Full (Notifications): Could not estabilsh faye connection', err); - }); - } - - /** + componentDidMount() { + const { dispatch } = this.props; + + FB.getLoginStatus(res => { + if (res.status !== 'connected') { + if (this.props.location.pathname != '/landing') { + browserHistory.replace('/landing'); + } + this.props.dispatch(AppActions.initDone()); + return; + } + + dispatch(UserActions.fbLogin(res)); + + if (this.props.location.pathname == '/landing') { + browserHistory.replace('/'); + } + }); + } + + connectToStream = () => { + // follow 'timeline_flat' feed + this.timeline = this.client.feed( + 'timeline_flat', + this.props.user.id, + this.props.tokens.timelineFlat, + ); + this.timeline + .subscribe(data => { + this.props.dispatch(StreamActions.timeline(data)); + }) + .then( + () => { + //console.log('Full (Timeline Flat): Connected to faye channel, waiting for realtime updates'); + }, + err => { + console.error( + 'Full (Timeline Flat): Could not estabilsh faye connection', + err, + ); + }, + ); + + // follow 'notifications' feed + this.notification = this.client.feed( + 'notification', + this.props.user.id, + this.props.tokens.notification, + ); + this.notification + .subscribe(data => { + this.props.dispatch(StreamActions.event(data)); + }) + .then( + () => { + //console.log('Full (Notifications): Connected to faye channel, waiting for realtime updates'); + }, + err => { + console.error( + 'Full (Notifications): Could not estabilsh faye connection', + err, + ); + }, + ); + }; + + /** * render * @returns markup */ - render() { - - if (this.props.loading) return
Loading...
- - if (this.props.location.pathname == '/landing') { - return ( -
- {this.props.children || } -
- ) - } - - return ( -
- - {this.props.children || } -
- ) - - } - + render() { + if (this.props.loading) return
Loading...
; + + if (this.props.location.pathname == '/landing') { + return ( +
+ {this.props.children || } +
+ ); + } + + return ( +
+ + {this.props.children || } +
+ ); + } } export default connect(state => ({ - user: state.User, - loading: state.App.loading, - tokens: state.Tokens, -}))(App) + user: state.User, + loading: state.App.loading, + tokens: state.Tokens, +}))(App); diff --git a/app/modules/actions/App.js b/app/modules/actions/App.js index 038379f..2a3e8e5 100644 --- a/app/modules/actions/App.js +++ b/app/modules/actions/App.js @@ -1,14 +1,14 @@ import { - Photos as PhotoActions, - IncomingActivity as IncomingActivityActions, - FollowingActivity as FollowingActivityActions, -} from './' + Photos as PhotoActions, + IncomingActivity as IncomingActivityActions, + FollowingActivity as FollowingActivityActions, +} from './'; /** * INIT * @type {string} */ -export const INIT = 'APP_INIT' +export const INIT = 'APP_INIT'; /** * init @@ -18,29 +18,29 @@ export const INIT = 'APP_INIT' * @returns {Function} */ export function init() { - return dispatch => { - Promise.all([ - dispatch(PhotoActions.load()), - dispatch(IncomingActivityActions.load()), - dispatch(FollowingActivityActions.load()), - ]).then(() => { - dispatch(initDone()) - }) - } + return dispatch => { + Promise.all([ + dispatch(PhotoActions.load()), + dispatch(IncomingActivityActions.load()), + dispatch(FollowingActivityActions.load()), + ]).then(() => { + dispatch(initDone()); + }); + }; } /** * INIT_DONE * @type {string} */ -export const INIT_DONE = 'APP_INIT_DONE' +export const INIT_DONE = 'APP_INIT_DONE'; /** * initDone * @returns {{type: string}} */ export function initDone() { - return { - type: INIT_DONE - } + return { + type: INIT_DONE, + }; } diff --git a/app/modules/actions/Comments.js b/app/modules/actions/Comments.js index 02901ea..a3a8fce 100644 --- a/app/modules/actions/Comments.js +++ b/app/modules/actions/Comments.js @@ -1,18 +1,18 @@ -import * as axios from 'axios' -import config from 'config' +import * as axios from 'axios'; +import config from 'config'; /** * ADD_COMMENT * @type {string} */ -export const ADD_COMMENT = 'PHOTOS_ADD_COMMENT' +export const ADD_COMMENT = 'PHOTOS_ADD_COMMENT'; /** * _addCommentRequest * @param id * @private */ -export const _addCommentRequest = (id) => ({ type: ADD_COMMENT, id, }) +export const _addCommentRequest = id => ({ type: ADD_COMMENT, id }); /** * _addCommentResponse @@ -21,7 +21,12 @@ export const _addCommentRequest = (id) => ({ type: ADD_COMMENT, id, }) * @param user * @private */ -export const _addCommentResponse = (id, comment, user) => ({ type: ADD_COMMENT, id, comment, user, }) +export const _addCommentResponse = (id, comment, user) => ({ + type: ADD_COMMENT, + id, + comment, + user, +}); /** * addComment @@ -33,37 +38,38 @@ export const _addCommentResponse = (id, comment, user) => ({ type: ADD_COMMENT, * @returns {Function} */ export function addComment(id, text) { - return (dispatch, getState) => { - const user = getState().User - dispatch(_addCommentRequest(id)) - const data = { - user_id: user.id, - upload_id: id, - comment: text, - } - axios.post(`${config.api.baseUrl}/comments`, data, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_addCommentResponse(id, res.data, user)) - }) - } + return (dispatch, getState) => { + const user = getState().User; + dispatch(_addCommentRequest(id)); + const data = { + user_id: user.id, + upload_id: id, + comment: text, + }; + axios + .post(`${config.api.baseUrl}/comments`, data, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_addCommentResponse(id, res.data, user)); + }); + }; } /** * LOAD_COMMENTS * @type {string} */ -export const LOAD_COMMENTS = 'PHOTOS_LOAD_COMMENT' +export const LOAD_COMMENTS = 'PHOTOS_LOAD_COMMENT'; /** * _loadCommentsRequest * @param postID * @private */ -export const _loadCommentsRequest = (postID) => ({ type: LOAD_COMMENTS, postID, }) +export const _loadCommentsRequest = postID => ({ type: LOAD_COMMENTS, postID }); /** * _loadCommentsResponse @@ -71,7 +77,11 @@ export const _loadCommentsRequest = (postID) => ({ type: LOAD_COMMENTS, postID, * @param comments * @private */ -export const _loadCommentsResponse = (postID, comments) => ({ type: LOAD_COMMENTS, postID, comments, }) +export const _loadCommentsResponse = (postID, comments) => ({ + type: LOAD_COMMENTS, + postID, + comments, +}); /** * load @@ -82,15 +92,16 @@ export const _loadCommentsResponse = (postID, comments) => ({ type: LOAD_COMMENT * @returns {Function} */ export function load(postID) { - return dispatch => { - dispatch(_loadCommentsRequest(postID)) - axios.get(`${config.api.baseUrl}/comments?upload_id=${postID}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_loadCommentsResponse(postID, res.data)) - }) - } + return dispatch => { + dispatch(_loadCommentsRequest(postID)); + axios + .get(`${config.api.baseUrl}/comments?upload_id=${postID}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_loadCommentsResponse(postID, res.data)); + }); + }; } diff --git a/app/modules/actions/Contributions.js b/app/modules/actions/Contributions.js index 1f1116e..aceb2f5 100644 --- a/app/modules/actions/Contributions.js +++ b/app/modules/actions/Contributions.js @@ -1,18 +1,18 @@ -import * as axios from 'axios' -import config from 'config' +import * as axios from 'axios'; +import config from 'config'; /** * LOAD * @type {string} */ -export const LOAD = 'CONTRIBUTIONS_LOAD' +export const LOAD = 'CONTRIBUTIONS_LOAD'; /** * _loadRequest * @param userID * @private */ -export const _loadRequest = (userID) => ({ type: LOAD, userID, }) +export const _loadRequest = userID => ({ type: LOAD, userID }); /** * _loadResponse @@ -20,7 +20,11 @@ export const _loadRequest = (userID) => ({ type: LOAD, userID, }) * @param response * @private */ -export const _loadResponse = (userID, response) => ({ type: LOAD, userID, response, }) +export const _loadResponse = (userID, response) => ({ + type: LOAD, + userID, + response, +}); /** * load @@ -31,16 +35,21 @@ export const _loadResponse = (userID, response) => ({ type: LOAD, userID, respon * @returns {Function} */ export function load(userID) { - return (dispatch, getState) => { - dispatch(_loadRequest(userID)) - const user = getState().User - axios.get(`${config.api.baseUrl}/contributions?user_id=${userID || user.id}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_loadResponse(userID, res.data)) - }) - } + return (dispatch, getState) => { + dispatch(_loadRequest(userID)); + const user = getState().User; + axios + .get( + `${config.api.baseUrl}/contributions?user_id=${userID || + user.id}`, + { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }, + ) + .then(res => { + dispatch(_loadResponse(userID, res.data)); + }); + }; } diff --git a/app/modules/actions/Explore.js b/app/modules/actions/Explore.js index 1bf990f..ef070a6 100644 --- a/app/modules/actions/Explore.js +++ b/app/modules/actions/Explore.js @@ -1,24 +1,24 @@ -import * as axios from 'axios' -import config from 'config' +import * as axios from 'axios'; +import config from 'config'; /** * LOAD * @type {string} */ -export const LOAD = 'EXPLORE_LOAD' +export const LOAD = 'EXPLORE_LOAD'; /** * _loadRequest * @private */ -const _loadRequest = () => ({ type: LOAD, }) +const _loadRequest = () => ({ type: LOAD }); /** * _loadResponse * @param response * @private */ -const _loadResponse = (response) => ({ type: LOAD, response}) +const _loadResponse = response => ({ type: LOAD, response }); /** * load @@ -28,16 +28,17 @@ const _loadResponse = (response) => ({ type: LOAD, response}) * @returns {Function} */ export function load() { - return (dispatch, getState) => { - dispatch(_loadRequest()) - const user = getState().User - axios.get(`${config.api.baseUrl}/explore?user_id=${user.id}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_loadResponse(res.data)) - }) - } + return (dispatch, getState) => { + dispatch(_loadRequest()); + const user = getState().User; + axios + .get(`${config.api.baseUrl}/explore?user_id=${user.id}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_loadResponse(res.data)); + }); + }; } diff --git a/app/modules/actions/FollowingActivity.js b/app/modules/actions/FollowingActivity.js index 83c3df6..1394b56 100644 --- a/app/modules/actions/FollowingActivity.js +++ b/app/modules/actions/FollowingActivity.js @@ -1,24 +1,24 @@ -import * as axios from 'axios' -import config from 'config' +import * as axios from 'axios'; +import config from 'config'; /** * LOAD * @type {string} */ -export const LOAD = 'FOLLOWING_ACTIVITY_LOAD' +export const LOAD = 'FOLLOWING_ACTIVITY_LOAD'; /** * _loadRequest * @private */ -export const _loadRequest = () => ({ type: LOAD, }) +export const _loadRequest = () => ({ type: LOAD }); /** * _loadResponse * @param response * @private */ -export const _loadResponse = (response) => ({ type: LOAD, response, }) +export const _loadResponse = response => ({ type: LOAD, response }); /** * load @@ -28,18 +28,26 @@ export const _loadResponse = (response) => ({ type: LOAD, response, }) * @returns {Function} */ export function load() { - return (dispatch, getState) => { - return new Promise((resolve => { - dispatch(_loadRequest()) - axios.get(`${config.api.baseUrl}/following-activity?user_id=${getState().User.id}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_loadResponse(res.data)) - resolve() - }) - })) - } + return (dispatch, getState) => { + return new Promise(resolve => { + dispatch(_loadRequest()); + axios + .get( + `${config.api + .baseUrl}/following-activity?user_id=${getState().User + .id}`, + { + headers: { + Authorization: `Bearer ${localStorage.getItem( + 'jwt', + )}`, + }, + }, + ) + .then(res => { + dispatch(_loadResponse(res.data)); + resolve(); + }); + }); + }; } diff --git a/app/modules/actions/Header.js b/app/modules/actions/Header.js index eda35e0..7ac5751 100644 --- a/app/modules/actions/Header.js +++ b/app/modules/actions/Header.js @@ -2,7 +2,7 @@ * LEFT * @type {string} */ -export const LEFT = 'HEADER_LEFT' +export const LEFT = 'HEADER_LEFT'; /** * left @@ -10,18 +10,17 @@ export const LEFT = 'HEADER_LEFT' * @returns {{type: string, component: *}} */ export function left(component) { - return { - type: LEFT, - component, - } + return { + type: LEFT, + component, + }; } /** * MIDDLE * @type {string} */ -export const MIDDLE = 'HEADER_MIDDLE' - +export const MIDDLE = 'HEADER_MIDDLE'; /** * middle @@ -29,17 +28,17 @@ export const MIDDLE = 'HEADER_MIDDLE' * @returns {{type: string, component: *}} */ export function middle(component) { - return { - type: MIDDLE, - component, - } + return { + type: MIDDLE, + component, + }; } /** * RIGHT * @type {string} */ -export const RIGHT = 'HEADER_RIGHT' +export const RIGHT = 'HEADER_RIGHT'; /** * right @@ -47,8 +46,8 @@ export const RIGHT = 'HEADER_RIGHT' * @returns {{type: string, component: *}} */ export function right(component) { - return { - type: RIGHT, - component, - } + return { + type: RIGHT, + component, + }; } diff --git a/app/modules/actions/IncomingActivity.js b/app/modules/actions/IncomingActivity.js index bf62fe4..8f513eb 100644 --- a/app/modules/actions/IncomingActivity.js +++ b/app/modules/actions/IncomingActivity.js @@ -1,25 +1,24 @@ -import * as axios from 'axios' -import config from 'config' +import * as axios from 'axios'; +import config from 'config'; /** * LOAD * @type {string} */ -export const LOAD = 'INCOMING_ACTIVITY_LOAD' +export const LOAD = 'INCOMING_ACTIVITY_LOAD'; /** * _loadRequest * @private */ -export const _loadRequest = () => ({ type: LOAD, }) +export const _loadRequest = () => ({ type: LOAD }); /** * _loadResponse * @param response * @private */ -export const _loadResponse = (response) => ({ type: LOAD, response, }) - +export const _loadResponse = response => ({ type: LOAD, response }); /** * load @@ -29,18 +28,26 @@ export const _loadResponse = (response) => ({ type: LOAD, response, }) * @returns {Function} */ export function load() { - return (dispatch, getState) => { - return new Promise((resolve => { - dispatch(_loadRequest()) - axios.get(`${config.api.baseUrl}/incoming-activity?user_id=${getState().User.id}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_loadResponse(res.data)) - resolve() - }) - })) - } + return (dispatch, getState) => { + return new Promise(resolve => { + dispatch(_loadRequest()); + axios + .get( + `${config.api + .baseUrl}/incoming-activity?user_id=${getState().User + .id}`, + { + headers: { + Authorization: `Bearer ${localStorage.getItem( + 'jwt', + )}`, + }, + }, + ) + .then(res => { + dispatch(_loadResponse(res.data)); + resolve(); + }); + }); + }; } diff --git a/app/modules/actions/Like.js b/app/modules/actions/Like.js index e05933b..9196a67 100644 --- a/app/modules/actions/Like.js +++ b/app/modules/actions/Like.js @@ -1,19 +1,19 @@ -import * as axios from 'axios' -import config from 'config' -import * as querystring from 'querystring' +import * as axios from 'axios'; +import config from 'config'; +import * as querystring from 'querystring'; /** * LOAD * @type {string} */ -export const LOAD = 'LIKE_LOAD' +export const LOAD = 'LIKE_LOAD'; /** * _loadRequest * @param postID * @private */ -export const _loadRequest = (postID) => ({ type: LOAD, postID, }) +export const _loadRequest = postID => ({ type: LOAD, postID }); /** * _loadResponse @@ -21,7 +21,11 @@ export const _loadRequest = (postID) => ({ type: LOAD, postID, }) * @param response * @private */ -export const _loadResponse = (postID, response) => ({ type: LOAD, postID, response, }) +export const _loadResponse = (postID, response) => ({ + type: LOAD, + postID, + response, +}); /** * load @@ -33,32 +37,37 @@ export const _loadResponse = (postID, response) => ({ type: LOAD, postID, respon * @returns {Function} */ export function load(postID, userID) { - return (dispatch, getState) => { - dispatch(_loadRequest(postID)) - const user = getState().User - axios.get(`${config.api.baseUrl}/likes?upload_id=${postID}&user_id=${user.id}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_loadResponse(postID, res.data)) - }) - } + return (dispatch, getState) => { + dispatch(_loadRequest(postID)); + const user = getState().User; + axios + .get( + `${config.api + .baseUrl}/likes?upload_id=${postID}&user_id=${user.id}`, + { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }, + ) + .then(res => { + dispatch(_loadResponse(postID, res.data)); + }); + }; } /** * ADD_LIKE * @type {string} */ -export const ADD_LIKE = 'ADD_LIKE' +export const ADD_LIKE = 'ADD_LIKE'; /** * _hnadleAddLikeRequest * @param postID * @private */ -export const _handleAddLikeRequest = (postID) => ({ type: ADD_LIKE, postID,}) +export const _handleAddLikeRequest = postID => ({ type: ADD_LIKE, postID }); /** * _handleAddLikeResponse @@ -66,7 +75,11 @@ export const _handleAddLikeRequest = (postID) => ({ type: ADD_LIKE, postID,}) * @param response * @private */ -export const _handleAddLikeResponse = (postID, response) => ({ type: ADD_LIKE, postID, response, }) +export const _handleAddLikeResponse = (postID, response) => ({ + type: ADD_LIKE, + postID, + response, +}); /** * like @@ -75,35 +88,39 @@ export const _handleAddLikeResponse = (postID, response) => ({ type: ADD_LIKE, p * @returns {Function} */ export function like(postID) { - return (dispatch, getState) => { - dispatch(_handleAddLikeRequest(postID)) - const data = { - user_id: getState().User.id, - upload_id: postID, - } - axios.post(`${config.api.baseUrl}/likes`, data, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_handleAddLikeResponse(postID, res.data)) - }) - } + return (dispatch, getState) => { + dispatch(_handleAddLikeRequest(postID)); + const data = { + user_id: getState().User.id, + upload_id: postID, + }; + axios + .post(`${config.api.baseUrl}/likes`, data, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_handleAddLikeResponse(postID, res.data)); + }); + }; } /** * DELETE_LIKE * @type {string} */ -export const DELETE_LIKE = 'DELETE_LIKE' +export const DELETE_LIKE = 'DELETE_LIKE'; /** * _handleDeleteLikeRequest * @param postID * @private */ -export const _handleDeleteLikeRequest = (postID) => ({ type: DELETE_LIKE, postID,}) +export const _handleDeleteLikeRequest = postID => ({ + type: DELETE_LIKE, + postID, +}); /** * _handleDeleteLikeResponse @@ -111,7 +128,11 @@ export const _handleDeleteLikeRequest = (postID) => ({ type: DELETE_LIKE, postID * @param response * @private */ -export const _handleDeleteLikeResponse = (postID, response) => ({ type: DELETE_LIKE, postID, response, }) +export const _handleDeleteLikeResponse = (postID, response) => ({ + type: DELETE_LIKE, + postID, + response, +}); /** * deleteLike @@ -120,19 +141,23 @@ export const _handleDeleteLikeResponse = (postID, response) => ({ type: DELETE_L * @returns {Function} */ export function deleteLike(postID) { - return (dispatch, getState) => { - dispatch(_handleDeleteLikeRequest(postID)) - const data = { - user_id: getState().User.id, - upload_id: postID, - } - axios.delete(`${config.api.baseUrl}/likes?` + querystring.stringify(data), { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - } - }) - .then(res => { - dispatch(_handleDeleteLikeResponse(postID, res.data)) - }) - } + return (dispatch, getState) => { + dispatch(_handleDeleteLikeRequest(postID)); + const data = { + user_id: getState().User.id, + upload_id: postID, + }; + axios + .delete( + `${config.api.baseUrl}/likes?` + querystring.stringify(data), + { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }, + ) + .then(res => { + dispatch(_handleDeleteLikeResponse(postID, res.data)); + }); + }; } diff --git a/app/modules/actions/Location.js b/app/modules/actions/Location.js index 291cb2d..c8b9e7e 100644 --- a/app/modules/actions/Location.js +++ b/app/modules/actions/Location.js @@ -1,18 +1,18 @@ -import * as axios from 'axios' -import config from 'config' +import * as axios from 'axios'; +import config from 'config'; /** * LOAD * @type {string} */ -export const LOAD = 'LOCATION_LOAD' +export const LOAD = 'LOCATION_LOAD'; /** * _loadRequest * @param location * @private */ -export const _loadRequest = (location) => ({ type: LOAD, location, }) +export const _loadRequest = location => ({ type: LOAD, location }); /** * _loadResponse @@ -20,7 +20,11 @@ export const _loadRequest = (location) => ({ type: LOAD, location, }) * @param response * @private */ -export const _loadResponse = (location, response) => ({ type: LOAD, location, response, }) +export const _loadResponse = (location, response) => ({ + type: LOAD, + location, + response, +}); /** * load @@ -31,15 +35,16 @@ export const _loadResponse = (location, response) => ({ type: LOAD, location, re * @returns {Function} */ export function load(location) { - return (dispatch) => { - dispatch(_loadRequest(location)) - axios.get(`${config.api.baseUrl}/locations?q=${location}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_loadResponse(location, res.data)) - }) - } + return dispatch => { + dispatch(_loadRequest(location)); + axios + .get(`${config.api.baseUrl}/locations?q=${location}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_loadResponse(location, res.data)); + }); + }; } diff --git a/app/modules/actions/Photo.js b/app/modules/actions/Photo.js index 24ff0c3..5544bb7 100644 --- a/app/modules/actions/Photo.js +++ b/app/modules/actions/Photo.js @@ -1,29 +1,26 @@ -import * as axios from 'axios' -import config from 'config' +import * as axios from 'axios'; +import config from 'config'; -import { - Like as LikeActions, - Comments as CommentActions, -} from 'actions' +import { Like as LikeActions, Comments as CommentActions } from 'actions'; /** * LOAD * @type {string} */ -export const LOAD = 'PHOTO_LOAD' +export const LOAD = 'PHOTO_LOAD'; /** * _loadRequest * @private */ -const _loadRequest = () => ({ type: LOAD, }) +const _loadRequest = () => ({ type: LOAD }); /** * _loadResponse * @param response * @private */ -const _loadResponse = (response) => ({ type: LOAD, response, }) +const _loadResponse = response => ({ type: LOAD, response }); /** * load @@ -34,20 +31,21 @@ const _loadResponse = (response) => ({ type: LOAD, response, }) * @returns {Function} */ export function load(id) { - return dispatch => { - return new Promise((resolve) => { - dispatch(_loadRequest()) - axios.get(`${config.api.baseUrl}/upload?id=${id}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_loadResponse(res.data)) - dispatch(CommentActions.load(id)) - dispatch(LikeActions.load(id)) - return resolve() - }) - }) - } + return dispatch => { + return new Promise(resolve => { + dispatch(_loadRequest()); + axios + .get(`${config.api.baseUrl}/upload?id=${id}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_loadResponse(res.data)); + dispatch(CommentActions.load(id)); + dispatch(LikeActions.load(id)); + return resolve(); + }); + }); + }; } diff --git a/app/modules/actions/Photos.js b/app/modules/actions/Photos.js index 628cd9e..15ddaf7 100644 --- a/app/modules/actions/Photos.js +++ b/app/modules/actions/Photos.js @@ -1,19 +1,19 @@ -import * as axios from 'axios' -import config from 'config' +import * as axios from 'axios'; +import config from 'config'; -export const INJECT = 'PHOTOS_INJECT' +export const INJECT = 'PHOTOS_INJECT'; export function inject(posts) { - return { - type: INJECT, - posts, - } + return { + type: INJECT, + posts, + }; } /** * ADD * @type {string} */ -export const ADD = 'PHOTO_ADD' +export const ADD = 'PHOTO_ADD'; /** * add @@ -21,33 +21,33 @@ export const ADD = 'PHOTO_ADD' * @returns {{type: string, response: *}} */ export function add(response) { - return { - type: ADD, - response, - } + return { + type: ADD, + response, + }; } /** * LOAD * @type {string} */ -export const LOAD = 'PHOTOS_LOAD' +export const LOAD = 'PHOTOS_LOAD'; /** * _loadRequest * @private */ -const _loadRequest = () => ({ type: LOAD, }) +const _loadRequest = () => ({ type: LOAD }); /** * _loadResponse * @param response * @private */ -const _loadResponse = (response) => ({ type: LOAD, response, }) +const _loadResponse = response => ({ type: LOAD, response }); -export const ONBOARDING = 'PHOTOS_ONBOARDING' -const _loadOnboarding = (response) => ({ type: ONBOARDING, response, }) +export const ONBOARDING = 'PHOTOS_ONBOARDING'; +const _loadOnboarding = response => ({ type: ONBOARDING, response }); /** * load @@ -58,59 +58,59 @@ const _loadOnboarding = (response) => ({ type: ONBOARDING, response, }) * @returns {Function} */ export function load(id) { - return (dispatch, getState) => { - const userID = id || getState().User.id - dispatch(_loadRequest()) - - Promise.all([ - axios.get(`${config.api.baseUrl}/uploads?user_id=${userID}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}`, - }, - }), - axios.get(`${config.api.baseUrl}/active?user_id=${userID}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}`, - }, - }) - ]) - .then(res => { - dispatch(_loadResponse(res[0].data)) - dispatch(_loadOnboarding(res[1].data)) - }) - } + return (dispatch, getState) => { + const userID = id || getState().User.id; + dispatch(_loadRequest()); + + Promise.all([ + axios.get(`${config.api.baseUrl}/uploads?user_id=${userID}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }), + axios.get(`${config.api.baseUrl}/active?user_id=${userID}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }), + ]).then(res => { + dispatch(_loadResponse(res[0].data)); + dispatch(_loadOnboarding(res[1].data)); + }); + }; } -export const RELOAD = 'PHOTOS_RELOAD' -const _reloadResponse = response => ({ type: RELOAD, response, }) +export const RELOAD = 'PHOTOS_RELOAD'; +const _reloadResponse = response => ({ type: RELOAD, response }); export function reload() { - return (dispatch, getState) => { - const userID = getState().User.id - - axios.get(`${config.api.baseUrl}/uploads?user_id=${userID}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}`, - }, - }) - .then(res => { - dispatch(_reloadResponse(res.data)) - Promise.resolve() - }) - } + return (dispatch, getState) => { + const userID = getState().User.id; + + axios + .get(`${config.api.baseUrl}/uploads?user_id=${userID}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_reloadResponse(res.data)); + Promise.resolve(); + }); + }; } /** * LIKE * @type {string} */ -export const LIKE = 'PHOTOS_LIKE' +export const LIKE = 'PHOTOS_LIKE'; /** * _likeRequest * @private */ -const _likeRequest = () => ({ type: LIKE, }) +const _likeRequest = () => ({ type: LIKE }); /** * _likeResponse @@ -118,7 +118,7 @@ const _likeRequest = () => ({ type: LIKE, }) * @param response * @private */ -const _likeResponse = (postID, response) => ({ type: LIKE, postID, response, }) +const _likeResponse = (postID, response) => ({ type: LIKE, postID, response }); /** * like @@ -129,34 +129,35 @@ const _likeResponse = (postID, response) => ({ type: LIKE, postID, response, }) * @returns {Function} */ export function like(postID) { - return (dispatch, getState) => { - dispatch(_likeRequest()) - const data = { - user_id: getState().User.id, - upload_id: postID, - } - axios.post(`${config.api.baseUrl}/likes`, data, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}`, - }, - }) - .then(res => { - dispatch(_likeResponse(postID, res.data)) - }) - } + return (dispatch, getState) => { + dispatch(_likeRequest()); + const data = { + user_id: getState().User.id, + upload_id: postID, + }; + axios + .post(`${config.api.baseUrl}/likes`, data, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_likeResponse(postID, res.data)); + }); + }; } /** * UNLIKE * @type {string} */ -export const UNLIKE = 'PHOTOS_UNLIKE' +export const UNLIKE = 'PHOTOS_UNLIKE'; /** * _unlikeRequest * @private */ -const _unlikeRequest = () => ({ type: UNLIKE, }) +const _unlikeRequest = () => ({ type: UNLIKE }); /** * _unlikeRequestResponse @@ -164,7 +165,11 @@ const _unlikeRequest = () => ({ type: UNLIKE, }) * @param response * @private */ -const _unlikeRequestResponse = (postID, response) => ({ type: UNLIKE, postID, response, }) +const _unlikeRequestResponse = (postID, response) => ({ + type: UNLIKE, + postID, + response, +}); /** * unlike @@ -175,45 +180,52 @@ const _unlikeRequestResponse = (postID, response) => ({ type: UNLIKE, postID, re * @returns {Function} */ export function unlike(postID) { - return (dispatch, getState) => { - return new Promise(resolve => { - dispatch(_unlikeRequest()) - const data = { - user_id: getState().User.id, - upload_id: postID, - } - axios.delete(`${config.api.baseUrl}/likes?user_id=${data.user_id}&upload_id=${data.upload_id}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_unlikeRequestResponse(postID, res.data)) - resolve() - }) - }) - } + return (dispatch, getState) => { + return new Promise(resolve => { + dispatch(_unlikeRequest()); + const data = { + user_id: getState().User.id, + upload_id: postID, + }; + axios + .delete( + `${config.api + .baseUrl}/likes?user_id=${data.user_id}&upload_id=${data.upload_id}`, + { + headers: { + Authorization: `Bearer ${localStorage.getItem( + 'jwt', + )}`, + }, + }, + ) + .then(res => { + dispatch(_unlikeRequestResponse(postID, res.data)); + resolve(); + }); + }); + }; } /** * PAGINATE * @type {string} */ -export const PAGINATE = 'PHOTOS_PAGINATE' +export const PAGINATE = 'PHOTOS_PAGINATE'; /** * _paginateRequest * @param lastId * @private */ -const _paginateRequest = lastId => ({ type: PAGINATE, lastId, }) +const _paginateRequest = lastId => ({ type: PAGINATE, lastId }); /** * _paginateResponse * @param response * @private */ -const _paginateResponse = response => ({ type: PAGINATE, response, }) +const _paginateResponse = response => ({ type: PAGINATE, response }); /** * paginate @@ -223,23 +235,25 @@ const _paginateResponse = response => ({ type: PAGINATE, response, }) * @returns {Function} */ export function paginate() { - return (dispatch, getState) => { - const { - Pagination, - User, - } = getState() - if (Pagination.fetching) return; - dispatch(_paginateRequest(Pagination.lastId)) - axios.get(`${config.api.baseUrl}/uploads?user_id=${User.id}&last_id=${Pagination.lastId}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_paginateResponse(res.data)) - }) - } + return (dispatch, getState) => { + const { Pagination, User } = getState(); + if (Pagination.fetching) return; + dispatch(_paginateRequest(Pagination.lastId)); + axios + .get( + `${config.api + .baseUrl}/uploads?user_id=${User.id}&last_id=${Pagination.lastId}`, + { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }, + ) + .then(res => { + dispatch(_paginateResponse(res.data)); + }); + }; } -export const LOAD_HIDDEN = 'PHOTOS_LOAD_HIDDEN' -export const loadHidden = () => ({ type: LOAD_HIDDEN, }) +export const LOAD_HIDDEN = 'PHOTOS_LOAD_HIDDEN'; +export const loadHidden = () => ({ type: LOAD_HIDDEN }); diff --git a/app/modules/actions/Profile.js b/app/modules/actions/Profile.js index 3b61c9c..79ac389 100644 --- a/app/modules/actions/Profile.js +++ b/app/modules/actions/Profile.js @@ -1,18 +1,18 @@ -import * as axios from 'axios' -import config from 'config' +import * as axios from 'axios'; +import config from 'config'; /** * LOAD * @type {string} */ -export const LOAD = 'PROFILE_LOAD' +export const LOAD = 'PROFILE_LOAD'; /** * _loadRequest * @param userID * @private */ -export const _loadRequest = (userID) => ({ type: LOAD, userID, }) +export const _loadRequest = userID => ({ type: LOAD, userID }); /** * _loadResponse @@ -20,7 +20,11 @@ export const _loadRequest = (userID) => ({ type: LOAD, userID, }) * @param response * @private */ -export const _loadResponse = (userID, response) => ({ type: LOAD, userID, response, }) +export const _loadResponse = (userID, response) => ({ + type: LOAD, + userID, + response, +}); /** * load @@ -29,32 +33,33 @@ export const _loadResponse = (userID, response) => ({ type: LOAD, userID, respon * @returns {Function} */ export function load(userID) { - return (dispatch, getState) => { - dispatch(_loadRequest(userID)) - const user = getState().User - axios.get(`${config.api.baseUrl}/users/${userID}?user_id=${user.id}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_loadResponse(userID, res.data)) - }) - } + return (dispatch, getState) => { + dispatch(_loadRequest(userID)); + const user = getState().User; + axios + .get(`${config.api.baseUrl}/users/${userID}?user_id=${user.id}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_loadResponse(userID, res.data)); + }); + }; } /** * FOLLOW * @type {string} */ -export const FOLLOW = 'PROFILE_FOLLOW' +export const FOLLOW = 'PROFILE_FOLLOW'; /** * _followRequest * @param userID * @private */ -export const _followRequest = (userID) => ({ type: FOLLOW, userID, }) +export const _followRequest = userID => ({ type: FOLLOW, userID }); /** * _followResponse @@ -62,7 +67,11 @@ export const _followRequest = (userID) => ({ type: FOLLOW, userID, }) * @param response * @private */ -export const _followResponse = (userID, response) => ({ type: FOLLOW, userID, response, }) +export const _followResponse = (userID, response) => ({ + type: FOLLOW, + userID, + response, +}); /** * follow @@ -71,42 +80,41 @@ export const _followResponse = (userID, response) => ({ type: FOLLOW, userID, re * @returns {Function} */ export function follow(userID) { - return (dispatch, getState) => { - return new Promise(resolve => { + return (dispatch, getState) => { + return new Promise(resolve => { + dispatch(_followRequest(userID)); + const user = getState().User; + const data = { + user_id: user.id, + follower_id: userID, + }; + axios + .post(`${config.api.baseUrl}/followers`, data, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_followResponse(userID, res.data)); - dispatch(_followRequest(userID)) - const user = getState().User - const data = { - user_id: user.id, - follower_id: userID, - } - axios.post(`${config.api.baseUrl}/followers`, data, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_followResponse(userID, res.data)) - - resolve() - }) - - }) - } + resolve(); + }); + }); + }; } /** * UNFOLLOW * @type {string} */ -export const UNFOLLOW = 'PROFILE_UNFOLLOW' +export const UNFOLLOW = 'PROFILE_UNFOLLOW'; /** * _unfollowRequest * @param userID * @private */ -export const _unfollowRequest = (userID) => ({ type: UNFOLLOW, userID, }) +export const _unfollowRequest = userID => ({ type: UNFOLLOW, userID }); /** * _unfollowResponse @@ -114,7 +122,11 @@ export const _unfollowRequest = (userID) => ({ type: UNFOLLOW, userID, }) * @param response * @private */ -export const _unfollowResponse = (userID, response) => ({ type: UNFOLLOW, userID, response, }) +export const _unfollowResponse = (userID, response) => ({ + type: UNFOLLOW, + userID, + response, +}); /** * unfollow @@ -125,19 +137,26 @@ export const _unfollowResponse = (userID, response) => ({ type: UNFOLLOW, userID * @returns {Function} */ export function unfollow(userID) { - return (dispatch, getState) => { - return new Promise(resolve => { - dispatch(_unfollowRequest(userID)) - const user = getState().User - axios.delete(`${config.api.baseUrl}/followers?user_id=${user.id}&follower_id=${userID}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - } - }) - .then(res => { - dispatch(_unfollowResponse(userID, res.data)) - resolve() - }) - }) - } + return (dispatch, getState) => { + return new Promise(resolve => { + dispatch(_unfollowRequest(userID)); + const user = getState().User; + axios + .delete( + `${config.api + .baseUrl}/followers?user_id=${user.id}&follower_id=${userID}`, + { + headers: { + Authorization: `Bearer ${localStorage.getItem( + 'jwt', + )}`, + }, + }, + ) + .then(res => { + dispatch(_unfollowResponse(userID, res.data)); + resolve(); + }); + }); + }; } diff --git a/app/modules/actions/Search.js b/app/modules/actions/Search.js index 051d56d..b5b146b 100644 --- a/app/modules/actions/Search.js +++ b/app/modules/actions/Search.js @@ -1,22 +1,24 @@ -import * as axios from 'axios' -import algoliasearch from 'algoliasearch' -import config from 'config' - -const algolia = algoliasearch(config.algolia.appId, config.algolia.searchOnlyKey) +import * as axios from 'axios'; +import algoliasearch from 'algoliasearch'; +import config from 'config'; +const algolia = algoliasearch( + config.algolia.appId, + config.algolia.searchOnlyKey, +); /** * SEARCH * @type {string} */ -export const SEARCH = 'SEARCH_SEARCH' +export const SEARCH = 'SEARCH_SEARCH'; /** * _searchRequest * @param term * @private */ -const _searchRequest = (term) => ({ type: SEARCH, term, }) +const _searchRequest = term => ({ type: SEARCH, term }); /** * _searchResponse @@ -24,7 +26,7 @@ const _searchRequest = (term) => ({ type: SEARCH, term, }) * @param response * @private */ -const _searchResponse = (term, response) => ({ type: SEARCH, term, response, }) +const _searchResponse = (term, response) => ({ type: SEARCH, term, response }); /** * search @@ -36,59 +38,52 @@ const _searchResponse = (term, response) => ({ type: SEARCH, term, response, }) * @returns {Function} */ export function search(term, type = 'all') { - - return dispatch => { - - // Initialize the 'cabin' index: - let index = algolia.initIndex('cabin'), - attrs = [] - - switch(type) { - case 'all': - attrs.push( - 'first_name', - 'last_name', - 'location', - 'hashtags', - ) - break; - case 'hashtags': - attrs.push('hashtags') - break - case 'user': - attrs.push( - 'first_name', - 'last_name', - ) - break - case 'location': - attrs.push('location') - break - } - - // Perform Algolia search: - index.search(term, { - attributesToHighlight: attrs, - hitsPerPage: 100 - }, (err, content) => { - dispatch(_searchResponse(term, content)) - }) - } - + return dispatch => { + // Initialize the 'cabin' index: + let index = algolia.initIndex('cabin'), + attrs = []; + + switch (type) { + case 'all': + attrs.push('first_name', 'last_name', 'location', 'hashtags'); + break; + case 'hashtags': + attrs.push('hashtags'); + break; + case 'user': + attrs.push('first_name', 'last_name'); + break; + case 'location': + attrs.push('location'); + break; + } + + // Perform Algolia search: + index.search( + term, + { + attributesToHighlight: attrs, + hitsPerPage: 100, + }, + (err, content) => { + dispatch(_searchResponse(term, content)); + }, + ); + }; } /** * TRIGGER * @type {string} */ -export const TRIGGER = 'SEARCH_TRIGGER' +export const TRIGGER = 'SEARCH_TRIGGER'; /** * _triggerRequest * @param search * @private */ -const _triggerRequest = (search) => ({ type: TRIGGER, search, }) +const _triggerRequest = search => ({ type: TRIGGER, search }); /** * _triggerResponse @@ -96,7 +91,11 @@ const _triggerRequest = (search) => ({ type: TRIGGER, search, }) * @param response * @private */ -const _triggerResponse = (search, response) => ({ type: TRIGGER, search, response, }) +const _triggerResponse = (search, response) => ({ + type: TRIGGER, + search, + response, +}); /** * trigger @@ -107,45 +106,46 @@ const _triggerResponse = (search, response) => ({ type: TRIGGER, search, respons * @returns {Function} */ export function trigger(search) { - return (dispatch, getState) => { - dispatch(_triggerRequest(search)) - /** + return (dispatch, getState) => { + dispatch(_triggerRequest(search)); + /** * data * @type {{user_id: *, search: *}} */ - const data = { - user_id: getState().User.id, - search: search.word, - } - axios.post(`${config.api.baseUrl}/searches`, data, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_triggerResponse(search, res.data)) - }) - } + const data = { + user_id: getState().User.id, + search: search.word, + }; + axios + .post(`${config.api.baseUrl}/searches`, data, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_triggerResponse(search, res.data)); + }); + }; } /** * RECENT * @type {string} */ -export const RECENT = 'SEARCH_RECENT' +export const RECENT = 'SEARCH_RECENT'; /** * _recentRequest * @private */ -const _recentRequest = () => ({ type: RECENT, }) +const _recentRequest = () => ({ type: RECENT }); /** * _recentResponse * @param response * @private */ -const _recentResponse = (response) => ({ type: RECENT, response, }) +const _recentResponse = response => ({ type: RECENT, response }); /** * recent @@ -155,37 +155,41 @@ const _recentResponse = (response) => ({ type: RECENT, response, }) * @returns {Function} */ export function recent() { - return (dispatch, getState) => { - dispatch(_recentRequest()) - axios.get(`${config.api.baseUrl}/searches?user_id=${getState().User.id}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_recentResponse(res.data)) - }) - } + return (dispatch, getState) => { + dispatch(_recentRequest()); + axios + .get( + `${config.api.baseUrl}/searches?user_id=${getState().User.id}`, + { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }, + ) + .then(res => { + dispatch(_recentResponse(res.data)); + }); + }; } /** * RESULTS * @type {string} */ -export const RESULTS = 'SEARCH_RESULTS' +export const RESULTS = 'SEARCH_RESULTS'; /** * _searchResultsRequest * @private */ -const _searchResultsRequest = () => ({ type: RESULTS, }) +const _searchResultsRequest = () => ({ type: RESULTS }); /** * _searchResultsResponse * @param response * @private */ -const _searchResultsResponse = (response) => ({ type: RESULTS, response, }) +const _searchResultsResponse = response => ({ type: RESULTS, response }); /** * results @@ -197,15 +201,22 @@ const _searchResultsResponse = (response) => ({ type: RESULTS, response, }) * @returns {Function} */ export function results(type, query) { - return dispatch => { - dispatch(_searchResultsRequest()) - axios.get(`${config.api.baseUrl}/uploads?type=${type}&query=${encodeURIComponent(query)}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_searchResultsResponse(res.data)) - }) - } + return dispatch => { + dispatch(_searchResultsRequest()); + axios + .get( + `${config.api + .baseUrl}/uploads?type=${type}&query=${encodeURIComponent( + query, + )}`, + { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }, + ) + .then(res => { + dispatch(_searchResultsResponse(res.data)); + }); + }; } diff --git a/app/modules/actions/Stats.js b/app/modules/actions/Stats.js index cf01fa3..754e3d8 100644 --- a/app/modules/actions/Stats.js +++ b/app/modules/actions/Stats.js @@ -1,18 +1,18 @@ -import config from 'config' -import * as axios from 'axios' +import config from 'config'; +import * as axios from 'axios'; /** * LOAD * @type {string} */ -export const LOAD = 'STATS_LOAD' +export const LOAD = 'STATS_LOAD'; /** * _loadRequest * @param userId * @private */ -export const _loadRequest = (userId) => ({ type: LOAD, userId, }) +export const _loadRequest = userId => ({ type: LOAD, userId }); /** * _loadResponse @@ -20,7 +20,11 @@ export const _loadRequest = (userId) => ({ type: LOAD, userId, }) * @param response * @private */ -export const _loadResponse = (userId, response) => ({ type: LOAD, userId, response, }) +export const _loadResponse = (userId, response) => ({ + type: LOAD, + userId, + response, +}); /** * load @@ -31,129 +35,140 @@ export const _loadResponse = (userId, response) => ({ type: LOAD, userId, respon * @returns {Function} */ export function load(userId) { - return (dispatch, getState) => { - - dispatch(_loadRequest(userId)) - - axios.get(`${config.api.baseUrl}/stats/${userId}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_loadResponse(userId, res.data)) - }) - - Keen.ready(function() { - - let itemViewsQuery = new Keen.Query("count", { - event_collection: 'views', - timeframe: 'this_30_days', - filters: [{ - "property_name": 'postAuthorId', - "operator": 'eq', - "property_value": userId - }, { - "property_name": 'type', - "operator": 'eq', - "property_value": 'item' - }] - }) - - keenClient.run(itemViewsQuery, function(err, res) { - - if (err) { - //console.log(err) - return - } - - dispatch(_loadResponse(userId, { - 'itemViews': res.result - })) - - }) - - let profileViewsQuery = new Keen.Query("count", { - event_collection: 'views', - timeframe: 'this_30_days', - filters: [{ - property_name: 'profileUser', - operator: 'eq', - property_value: userId - }, { - property_name: 'type', - operator: 'eq', - property_value: 'user' - }] - }) - - keenClient.run(profileViewsQuery, function(err, res) { - - if (err) { - //console.log(err) - return - } - - dispatch(_loadResponse(userId, { - profileViews: res.result - })) - - }) - - let geoViewsQuery = new Keen.Query("count", { - event_collection: 'views', - timeframe: 'this_30_days', - filters: [{ - property_name: 'postAuthorId', - operator: 'eq', - property_value: userId - }, { - property_name: 'type', - operator: 'eq', - property_value: 'item' - }, { - property_name: 'ip_geo_info.city', - operator: 'ne', - property_value: null - }], - group_by: ['ip_geo_info.city', 'ip_geo_info.province', 'ip_geo_info.country'], - }) - - keenClient.run(geoViewsQuery, function(err, res) { - if (err) { - //console.log(err) - return - } - dispatch(_loadResponse(userId, { - 'geoViews': res.result.slice(0, 5) - })) - }) - - let newFollowersQuery = new Keen.Query('sum', { - event_collection: "follow", - timeframe: "this_30_days", - filters: [{ - property_name: 'targetId', - operator: 'eq', - property_value: userId - }], - target_property: 'directionInt' - }) - - keenClient.run(newFollowersQuery, function(err, res) { - - if (err) { - //console.log(err) - return - } - - dispatch(_loadResponse(userId, { - - 'newFollowers': res - })) - - }) - - }) - } + return (dispatch, getState) => { + dispatch(_loadRequest(userId)); + + axios + .get(`${config.api.baseUrl}/stats/${userId}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_loadResponse(userId, res.data)); + }); + + Keen.ready(function() { + let itemViewsQuery = new Keen.Query('count', { + event_collection: 'views', + timeframe: 'this_30_days', + filters: [ + { + property_name: 'postAuthorId', + operator: 'eq', + property_value: userId, + }, + { + property_name: 'type', + operator: 'eq', + property_value: 'item', + }, + ], + }); + + keenClient.run(itemViewsQuery, function(err, res) { + if (err) { + return; + } + + dispatch( + _loadResponse(userId, { + itemViews: res.result, + }) + ); + }); + + let profileViewsQuery = new Keen.Query('count', { + event_collection: 'views', + timeframe: 'this_30_days', + filters: [ + { + property_name: 'profileUser', + operator: 'eq', + property_value: userId, + }, + { + property_name: 'type', + operator: 'eq', + property_value: 'user', + }, + ], + }); + + keenClient.run(profileViewsQuery, function(err, res) { + if (err) { + return; + } + + dispatch( + _loadResponse(userId, { + profileViews: res.result, + }) + ); + }); + + let geoViewsQuery = new Keen.Query('count', { + event_collection: 'views', + timeframe: 'this_30_days', + filters: [ + { + property_name: 'postAuthorId', + operator: 'eq', + property_value: userId, + }, + { + property_name: 'type', + operator: 'eq', + property_value: 'item', + }, + { + property_name: 'ip_geo_info.city', + operator: 'ne', + property_value: null, + }, + ], + group_by: [ + 'ip_geo_info.city', + 'ip_geo_info.province', + 'ip_geo_info.country', + ], + }); + + keenClient.run(geoViewsQuery, function(err, res) { + if (err) { + return; + } + dispatch( + _loadResponse(userId, { + geoViews: res.result.slice(0, 5), + }) + ); + }); + + let newFollowersQuery = new Keen.Query('sum', { + event_collection: 'follow', + timeframe: 'this_30_days', + filters: [ + { + property_name: 'targetId', + operator: 'eq', + property_value: userId, + }, + ], + target_property: 'directionInt', + }); + + keenClient.run(newFollowersQuery, function(err, res) { + if (err) { + return; + } + + dispatch( + _loadResponse(userId, { + newFollowers: res, + }) + ); + }); + }); + }; } diff --git a/app/modules/actions/Stream.js b/app/modules/actions/Stream.js index 29a0851..0073a50 100644 --- a/app/modules/actions/Stream.js +++ b/app/modules/actions/Stream.js @@ -1,46 +1,42 @@ -import * as axios from 'axios' -import config from 'config' +import * as axios from 'axios'; +import config from 'config'; import { - Photos as PhotosActions, - IncomingActivity as IncomingActivityActions, -} from 'actions' + Photos as PhotosActions, + IncomingActivity as IncomingActivityActions, +} from 'actions'; -export const CLEAR = 'STREAM_CLEAR' +export const CLEAR = 'STREAM_CLEAR'; export function clear() { - return { - type: CLEAR, - } + return { + type: CLEAR, + }; } export function timeline(data) { - return dispatch => { - - Promise.all(data.new.map(p => { - - const id = p.object.split(':')[1] - - return ( - axios.get(`${config.api.baseUrl}/upload?id=${id}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - ) - - })).then(results => { - dispatch(PhotosActions.inject(results.map(r => r.data))) - }) - } + return dispatch => { + Promise.all( + data.new.map(p => { + const id = p.object.split(':')[1]; + + return axios.get(`${config.api.baseUrl}/upload?id=${id}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }); + }), + ).then(results => { + dispatch(PhotosActions.inject(results.map(r => r.data))); + }); + }; } +export const EVENT = 'STREAM_EVENT'; -export const EVENT = 'STREAM_EVENT' - -const _newEvent = data => ({ type: EVENT, count: data.new.length,}) +const _newEvent = data => ({ type: EVENT, count: data.new.length }); export function event(data) { - return dispatch => { - dispatch(_newEvent(data)) - dispatch(IncomingActivityActions.load()) - } + return dispatch => { + dispatch(_newEvent(data)); + dispatch(IncomingActivityActions.load()); + }; } diff --git a/app/modules/actions/Trending.js b/app/modules/actions/Trending.js index f03f6b0..d397d49 100644 --- a/app/modules/actions/Trending.js +++ b/app/modules/actions/Trending.js @@ -1,24 +1,24 @@ -import * as axios from 'axios' -import config from 'config' +import * as axios from 'axios'; +import config from 'config'; /** * LOAD * @type {string} */ -export const LOAD = 'TRENDING_LOAD' +export const LOAD = 'TRENDING_LOAD'; /** * _loadRequest * @private */ -const _loadRequest = () => ({ type: LOAD, }) +const _loadRequest = () => ({ type: LOAD }); /** * _loadResponse * @param response * @private */ -const _loadResponse = (response) => ({ type: LOAD, response, }) +const _loadResponse = response => ({ type: LOAD, response }); /** * trending @@ -28,16 +28,17 @@ const _loadResponse = (response) => ({ type: LOAD, response, }) * @returns {Function} */ export function load() { - return (dispatch, getState) => { - _loadRequest() - const user = getState().User - axios.get(`${config.api.baseUrl}/trending?user_id=${user.id}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('jwt')}` - }, - }) - .then(res => { - dispatch(_loadResponse(res.data)) - }) - } + return (dispatch, getState) => { + _loadRequest(); + const user = getState().User; + axios + .get(`${config.api.baseUrl}/trending?user_id=${user.id}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem('jwt')}`, + }, + }) + .then(res => { + dispatch(_loadResponse(res.data)); + }); + }; } diff --git a/app/modules/actions/User.js b/app/modules/actions/User.js index 47a6cac..24e9beb 100644 --- a/app/modules/actions/User.js +++ b/app/modules/actions/User.js @@ -1,18 +1,18 @@ -import * as axios from 'axios' -import config from 'config' +import * as axios from 'axios'; +import config from 'config'; /** * FB_LOGIN * @type {string} */ -export const FB_LOGIN = 'USER_FB_LOGIN' +export const FB_LOGIN = 'USER_FB_LOGIN'; /** * _fbLoginInitial * @param initial * @private */ -const _fbLoginInitial = (initial) => ({ type: FB_LOGIN, initial, }) +const _fbLoginInitial = initial => ({ type: FB_LOGIN, initial }); /** * fbLogin @@ -23,42 +23,43 @@ const _fbLoginInitial = (initial) => ({ type: FB_LOGIN, initial, }) * @returns {Function} */ export function fbLogin(response) { - var token = response.authResponse.accessToken; - var userID = response.authResponse.userID; - return dispatch => { - axios.post(`${config.api.baseUrl}/users`, { - token : token, - fb_user_id : userID - }) - .then(function(res) { - localStorage.setItem('jwt', res.data.jwt); - dispatch(_fbLoginInitial(res.data)) - }) - .catch(function(res) { - window.location.reload() - dispatch(_fbLoginInitial(res.data)) - }); - } + const token = response.authResponse.accessToken; + const userID = response.authResponse.userID; + return dispatch => { + axios + .post(`${config.api.baseUrl}/users`, { + token: token, + fb_user_id: userID, + }) + .then(function(res) { + localStorage.setItem('jwt', res.data.jwt); + dispatch(_fbLoginInitial(res.data)); + }) + .catch(function(res) { + window.location.reload(); + dispatch(_fbLoginInitial(res.data)); + }); + }; } /** * LOGOUT * @type {string} */ -export const LOGOUT = 'USER_LOGOUT' +export const LOGOUT = 'USER_LOGOUT'; /** * _logoutRequest * @private */ -export const _logoutRequest = () => ({ type: LOGOUT, }) +export const _logoutRequest = () => ({ type: LOGOUT }); /** * _logoutResponse * @param response * @private */ -export const _logoutResponse = (response) => ({ type: LOGOUT, response, }) +export const _logoutResponse = response => ({ type: LOGOUT, response }); /** * logout @@ -68,19 +69,19 @@ export const _logoutResponse = (response) => ({ type: LOGOUT, response, }) * @returns {Function} */ export function logout() { - return dispatch => { - dispatch(_logoutRequest()) - FB.logout(response => { - dispatch(_logoutResponse(response)) - }) - } + return dispatch => { + dispatch(_logoutRequest()); + FB.logout(response => { + dispatch(_logoutResponse(response)); + }); + }; } /** * FOLLOW * @type {string} */ -export const FOLLOW = 'USER_FOLLOW' +export const FOLLOW = 'USER_FOLLOW'; /** * follow @@ -88,8 +89,8 @@ export const FOLLOW = 'USER_FOLLOW' * @returns {{type: string, user: *}} */ export function follow(user) { - return { - type: FOLLOW, - user, - } + return { + type: FOLLOW, + user, + }; } diff --git a/app/modules/actions/index.js b/app/modules/actions/index.js index 8dc2b19..69f7a6b 100644 --- a/app/modules/actions/index.js +++ b/app/modules/actions/index.js @@ -1,17 +1,17 @@ -export * as App from './App' -export * as User from './User' -export * as Photos from './Photos' -export * as Comments from './Comments' -export * as Like from './Like' -export * as Photo from './Photo' -export * as Stats from './Stats' -export * as Explore from './Explore' -export * as Trending from './Trending' -export * as Search from './Search' -export * as Location from './Location' -export * as Profile from './Profile' -export * as Header from './Header' -export * as Contributions from './Contributions' -export * as IncomingActivity from './IncomingActivity' -export * as FollowingActivity from './FollowingActivity' -export * as Stream from './Stream' +export * as App from './App'; +export * as User from './User'; +export * as Photos from './Photos'; +export * as Comments from './Comments'; +export * as Like from './Like'; +export * as Photo from './Photo'; +export * as Stats from './Stats'; +export * as Explore from './Explore'; +export * as Trending from './Trending'; +export * as Search from './Search'; +export * as Location from './Location'; +export * as Profile from './Profile'; +export * as Header from './Header'; +export * as Contributions from './Contributions'; +export * as IncomingActivity from './IncomingActivity'; +export * as FollowingActivity from './FollowingActivity'; +export * as Stream from './Stream'; diff --git a/app/modules/components/Activity/Actor.js b/app/modules/components/Activity/Actor.js index a344045..37f2042 100644 --- a/app/modules/components/Activity/Actor.js +++ b/app/modules/components/Activity/Actor.js @@ -1,36 +1,39 @@ -import React, { Component } from 'react' -import { Avatar } from 'components' -import { Link } from 'react-router' +import React, { Component } from 'react'; +import { Avatar } from 'components'; +import { Link } from 'react-router'; /** * Actor component */ export default class Actor extends Component { - - /** + /** * defaultProps * @type {{avatar: string, email: string, firstName: string, lastName: string}} */ - static defaultProps = { - avatar: '', - first_name: '', - last_name: '', - } + static defaultProps = { + avatar: '', + first_name: '', + last_name: '', + }; - /** + /** * render * @returns markup */ - render() { - return ( - -
-
- -
-
{this.props.first_name}
{this.props.last_name && this.props.last_name.charAt(0) + '.'}
-
- - ) - } + render() { + return ( + +
+
+ +
+
+ {this.props.first_name}
+ {this.props.last_name && + this.props.last_name.charAt(0) + '.'} +
+
+ + ); + } } diff --git a/app/modules/components/Activity/Commented.js b/app/modules/components/Activity/Commented.js index f322e12..f336b27 100644 --- a/app/modules/components/Activity/Commented.js +++ b/app/modules/components/Activity/Commented.js @@ -1,44 +1,50 @@ -import React, { Component } from 'react' +import React, { Component } from 'react'; -import Actor from './Actor' -import { Link } from 'react-router' -import config from 'config' +import Actor from './Actor'; +import { Link } from 'react-router'; +import config from 'config'; /** * Commented component */ export default class Commented extends Component { - - /** + /** * defaultProps * @type {{actor: {}, user: {}, timestamp: null, timeSince: string}} */ - static defaultProps = { - actor: {}, - user: {}, - time: null, - timeSince: '', - } + static defaultProps = { + actor: {}, + user: {}, + time: null, + timeSince: '', + }; - /** + /** * render * @returns markup */ - render() { - return ( -
-
- - - - -
-
-
- " -

{this.props.comment}

-
-
- ) - } + render() { + return ( +
+
+ + + + +
+
+
+ + " + +

+ {this.props.comment} +

+
+
+ ); + } } diff --git a/app/modules/components/Activity/Following.js b/app/modules/components/Activity/Following.js index bf4921a..32e3c4c 100644 --- a/app/modules/components/Activity/Following.js +++ b/app/modules/components/Activity/Following.js @@ -1,93 +1,92 @@ -import React, { Component } from 'react' +import React, { Component } from 'react'; -import Actor from './Actor' +import Actor from './Actor'; /** * Following component */ export default class Following extends Component { - - /** + /** * * @type {{actor: {}, user: {}, timestamp: null, timeSince: string, following: boolean, onFollowBack: Following.defaultProps.onFollowBack, onUnfollow: Following.defaultProps.onUnfollow}} */ - static defaultProps = { - actor: {}, - user: {}, - time: null, - timeSince: '', - following: false, + static defaultProps = { + actor: {}, + user: {}, + time: null, + timeSince: '', + following: false, - onFollowBack: () => { - }, - onUnfollow: () => { - }, - } + onFollowBack: () => {}, + onUnfollow: () => {}, + }; - /** + /** * handleFollowBack * @param e */ - handleFollowBack = (e) => { - e.preventDefault() + handleFollowBack = e => { + e.preventDefault(); - this.props.onFollowBack(e, this.props.actor) - } + this.props.onFollowBack(e, this.props.actor); + }; - /** + /** * handleUnfollow * @param e */ - handleUnfollow = (e) => { - e.preventDefault() + handleUnfollow = e => { + e.preventDefault(); - this.props.onUnfollow(e, this.props.actor) - } + this.props.onUnfollow(e, this.props.actor); + }; - /** + /** * renderFollowButton * @returns markup */ - renderFollowButton = () => { - - if (this.props.following) { - return ( -
- -
- ) - } - - return ( -
- -
- ) + renderFollowButton = () => { + if (this.props.following) { + return ( +
+ +
+ ); + } - } + return ( +
+ +
+ ); + }; - /** + /** * render * @returns markup */ - render() { - return ( -
- - {this.renderFollowButton()} -
- -
-
-

Followed, {this.props.timeSince}

-
-
- -
- -
-
-
- ) - } + render() { + return ( +
+ + {this.renderFollowButton()} +
+ +
+
+

+ Followed, {this.props.timeSince} +

+
+
+ +
+ +
+
+
+ ); + } } diff --git a/app/modules/components/Activity/Liked.js b/app/modules/components/Activity/Liked.js index f7e6d01..4a7a97a 100644 --- a/app/modules/components/Activity/Liked.js +++ b/app/modules/components/Activity/Liked.js @@ -1,60 +1,67 @@ -import React, { Component } from 'react' -import { Link } from 'react-router' -import config from 'config' +import React, { Component } from 'react'; +import { Link } from 'react-router'; +import config from 'config'; -import Actor from './Actor' +import Actor from './Actor'; -const Picture = props => ( -
- - - -
-) +const Picture = props => +
+ + + +
; /** * Liked component */ export default class Liked extends Component { - - /** + /** * defaultProps * @type {{pictures: Array}} */ - static defaultProps = { - activities: [], - } + static defaultProps = { + activities: [], + }; - /** + /** * renderMessage * @returns {*} */ - renderMessage = () => { - if (this.props.activity_count === 1) return 'Liked your picture' - return `Liked ${this.props.activity_count} pictures` - } + renderMessage = () => { + if (this.props.activity_count === 1) return 'Liked your picture'; + return `Liked ${this.props.activity_count} pictures`; + }; - /** + /** * render * @returns markup */ - render() { - return ( -
- -
- -
-
-

{this.renderMessage()}, {this.props.timeSince}

-
-
-
-
- {this.props.activities.slice(0,6).map((p, i) => )} -
-
-
- ) - } + render() { + return ( +
+ +
+ +
+
+

+ {this.renderMessage()}, {this.props.timeSince} +

+
+
+
+
+ {this.props.activities + .slice(0, 6) + .map((p, i) => + , + )} +
+
+
+ ); + } } diff --git a/app/modules/components/Activity/index.js b/app/modules/components/Activity/index.js index df63135..c7af199 100644 --- a/app/modules/components/Activity/index.js +++ b/app/modules/components/Activity/index.js @@ -1,40 +1,39 @@ -import React, { Component, cloneElement } from 'react' +import React, { Component, cloneElement } from 'react'; -export Actor from './Actor' -export Following from './Following' -export Liked from './Liked' -export Commented from './Commented' +export Actor from './Actor'; +export Following from './Following'; +export Liked from './Liked'; +export Commented from './Commented'; -import moment from 'moment' +import moment from 'moment'; /** * Activity index component */ export class Item extends Component { - - /** + /** * defaultProps * @type {{type: null, timestamp: null, actor: {}}} */ - static defaultProps = { - verb: null, - time: null, - actor: {}, - } + static defaultProps = { + verb: null, + time: null, + actor: {}, + }; - /** + /** * render * @returns markup */ - render() { - return ( -
  • - {cloneElement(this.props.children, { - timestamp: this.props.time, - actor: this.props.actor, - timeSince: moment.utc(this.props.time).fromNow(), - })} -
  • - ) - } + render() { + return ( +
  • + {cloneElement(this.props.children, { + timestamp: this.props.time, + actor: this.props.actor, + timeSince: moment.utc(this.props.time).fromNow(), + })} +
  • + ); + } } diff --git a/app/modules/components/Avatar/index.js b/app/modules/components/Avatar/index.js index 0f0aa7c..1fab4c5 100644 --- a/app/modules/components/Avatar/index.js +++ b/app/modules/components/Avatar/index.js @@ -1,44 +1,46 @@ -import React, { Component } from 'react' +import React, { Component } from 'react'; const styles = { - root: { - backgroundColor: '#fafafa', - display: 'inline-block', - } -} + root: { + backgroundColor: '#fafafa', + display: 'inline-block', + }, +}; /** * Avatar index component */ class Avatar extends Component { - - /** + /** * defaultProps * @type {{email: null, height: number, imgHeight: number}} */ - static defaultProps = { - email_md5: null, - height: 155, - imgHeight: 400, - } + static defaultProps = { + email_md5: null, + height: 155, + imgHeight: 400, + }; - /** + /** * render * @returns markup */ - render() { - - const placeHolder = Object.assign({}, styles.root, { - height: this.props.height, - width: this.props.height, - }) - - if (!this.props.emailHash) return
    - - return - - } + render() { + const placeHolder = Object.assign({}, styles.root, { + height: this.props.height, + width: this.props.height, + }); + + if (!this.props.emailHash) return
    ; + + return ( + + ); + } } -export default Avatar +export default Avatar; diff --git a/app/modules/components/BackButton/index.js b/app/modules/components/BackButton/index.js index b45e65a..0f7f6d1 100644 --- a/app/modules/components/BackButton/index.js +++ b/app/modules/components/BackButton/index.js @@ -1,40 +1,46 @@ -import React, { Component } from 'react' -import { Link } from 'react-router' - +import React, { Component } from 'react'; +import { Link } from 'react-router'; /** * BackButton index component */ class BackButton extends Component { - - /** + /** * defaultProps * @type {{to: string, icon: XML, label: string}} */ - static defaultProps = { - to: '/', - icon: , - label: 'Back', - } + static defaultProps = { + to: '/', + icon: , + label: 'Back', + }; - /** + /** * render * @returns markup */ - render() { - - const content = {this.props.icon}{this.props.label} - - if (typeof this.props.to == 'string') { - return ( - {content} - ) - } - - return {content} - - } - + render() { + const content = ( + + {this.props.icon} + {this.props.label} + + ); + + if (typeof this.props.to == 'string') { + return ( + + {content} + + ); + } + + return ( + + {content} + + ); + } } -export default BackButton +export default BackButton; diff --git a/app/modules/components/Comment/index.js b/app/modules/components/Comment/index.js index 2720aec..79370a4 100644 --- a/app/modules/components/Comment/index.js +++ b/app/modules/components/Comment/index.js @@ -1,34 +1,33 @@ -import React, { Component } from 'react' -import { Link } from 'react-router' -import TimeAgo from '../TimeAgo' +import React, { Component } from 'react'; +import { Link } from 'react-router'; +import TimeAgo from '../TimeAgo'; /** * Comment index component */ class Comment extends Component { - - /** + /** * * @returns markup */ - render() { - return ( -
    - -
    - {this.props.firstName} {this.props.lastName.charAt(0) + '.'} -
    - -
    - -
    -
    - {this.props.comment} -
    -
    - ) - } - + render() { + return ( +
    + +
    + {this.props.firstName}{' '} + {this.props.lastName.charAt(0) + '.'} +
    + +
    + +
    +
    + {this.props.comment} +
    +
    + ); + } } -export default Comment +export default Comment; diff --git a/app/modules/components/Header/index.js b/app/modules/components/Header/index.js index ef7981e..f96aefa 100644 --- a/app/modules/components/Header/index.js +++ b/app/modules/components/Header/index.js @@ -1,133 +1,123 @@ -import React, {Component} from 'react' -import { connect } from 'react-redux' -import { Link, IndexLink, withRouter } from 'react-router' +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { Link, IndexLink, withRouter } from 'react-router'; -import Nav from '../../components/Nav' +import Nav from '../../components/Nav'; /** * Left component */ class Left extends Component { - - state = { - step: 0, - } - - shouldComponentUpdate(nextProps, nextState) { - return nextProps.step !== this.state.step - } - - componentDidMount() { - if (this.props.active) { - setTimeout(() => - this.setState({ step: this.state.step + 1}), 1) - } - } - - componentDidUpdate(oldProps, oldState) { - if (this.props.active != oldProps.active) { - - if (this.props.active) { - setTimeout(() => - this.setState({ step: this.state.step + 1}), 1) - } else { - this.setState({ step: 0, }) - } - } - - } - - getClasses = () => { - const classes = ['item', 'left'] - - if (this.props.active) { - classes.push( - this.state.step === 0 ? 'active-initial' : 'active' - ) - - } - - return classes - } - - /** + state = { + step: 0, + }; + + shouldComponentUpdate(nextProps, nextState) { + return nextProps.step !== this.state.step; + } + + componentDidMount() { + if (this.props.active) { + setTimeout(() => this.setState({ step: this.state.step + 1 }), 1); + } + } + + componentDidUpdate(oldProps, oldState) { + if (this.props.active != oldProps.active) { + if (this.props.active) { + setTimeout( + () => this.setState({ step: this.state.step + 1 }), + 1, + ); + } else { + this.setState({ step: 0 }); + } + } + } + + getClasses = () => { + const classes = ['item', 'left']; + + if (this.props.active) { + classes.push(this.state.step === 0 ? 'active-initial' : 'active'); + } + + return classes; + }; + + /** * render * @returns markup */ - render() { - return ( -
    - - - -
    - ) - } - + render() { + return ( +
    + + + +
    + ); + } } /** * Right component */ class Right extends Component { - - /** + /** * render * @returns markup */ - render() { - return ( -
    - - - -
    - ) - } - + render() { + return ( +
    + + + +
    + ); + } } /** * Header index component */ class Header extends Component { - - /** + /** * defaultProps * @type {{userID: null, left: markup, middle: markup}} */ - static defaultProps = { - userID: null, + static defaultProps = { + userID: null, - left: , - middle: