From 15ec56b358ff5cd83a9046565219f44e7434b0f2 Mon Sep 17 00:00:00 2001 From: M9713 <m9713@student.jamk.fi> Date: Fri, 22 Oct 2021 19:39:02 +0300 Subject: [PATCH] Remake project --- conduit-backend/.circleci/config.yml | 20 + conduit-backend/.dockerignore | 2 + conduit-backend/.gitignore | 37 + conduit-backend/.travis.yml | 10 + conduit-backend/Dockerfile | 13 + conduit-backend/README.md | 52 + conduit-backend/app.js | 84 + conduit-backend/config/index.js | 3 + conduit-backend/config/passport.js | 18 + conduit-backend/models/Article.js | 56 + conduit-backend/models/Comment.js | 19 + conduit-backend/models/User.js | 99 + conduit-backend/package.json | 43 + conduit-backend/project-logo.png | Bin 0 -> 53176 bytes conduit-backend/public/.keep | 0 conduit-backend/routes/api/articles.js | 279 ++ conduit-backend/routes/api/index.js | 22 + conduit-backend/routes/api/profiles.js | 53 + conduit-backend/routes/api/tags.js | 12 + conduit-backend/routes/api/users.js | 75 + conduit-backend/routes/auth.js | 27 + conduit-backend/routes/index.js | 5 + conduit-backend/tests/api-tests.postman.json | 1900 +++++++++ .../tests/env-api-tests.postman.json | 14 + conduit-backend/yarn.lock | 3628 +++++++++++++++++ conduit-front/.dockerignore | 2 + conduit-front/.gitignore | 16 + conduit-front/Dockerfile | 16 + conduit-front/README.md | 74 + conduit-front/package.json | 31 + conduit-front/project-logo.png | Bin 0 -> 72206 bytes conduit-front/public/favicon.ico | Bin 0 -> 15406 bytes conduit-front/public/index.html | 34 + conduit-front/src/agent.js | 96 + conduit-front/src/components/App.js | 86 + .../src/components/Article/ArticleActions.js | 41 + .../src/components/Article/ArticleMeta.js | 27 + .../src/components/Article/Comment.js | 35 + .../components/Article/CommentContainer.js | 40 + .../src/components/Article/CommentInput.js | 58 + .../src/components/Article/CommentList.js | 22 + .../src/components/Article/DeleteButton.js | 27 + conduit-front/src/components/Article/index.js | 97 + conduit-front/src/components/ArticleList.js | 38 + .../src/components/ArticlePreview.js | 79 + conduit-front/src/components/Editor.js | 178 + conduit-front/src/components/Header.js | 91 + conduit-front/src/components/Home/Banner.js | 19 + conduit-front/src/components/Home/MainView.js | 96 + conduit-front/src/components/Home/Tags.js | 36 + conduit-front/src/components/Home/index.js | 78 + conduit-front/src/components/ListErrors.js | 26 + .../src/components/ListPagination.js | 58 + conduit-front/src/components/Login.js | 97 + conduit-front/src/components/Profile.js | 170 + .../src/components/ProfileFavorites.js | 53 + conduit-front/src/components/Register.js | 113 + conduit-front/src/components/Settings.js | 171 + conduit-front/src/constants/actionTypes.js | 36 + conduit-front/src/index.js | 20 + conduit-front/src/middleware.js | 68 + conduit-front/src/reducer.js | 22 + conduit-front/src/reducers/article.js | 35 + conduit-front/src/reducers/articleList.js | 86 + conduit-front/src/reducers/auth.js | 34 + conduit-front/src/reducers/common.js | 70 + conduit-front/src/reducers/editor.js | 54 + conduit-front/src/reducers/home.js | 15 + conduit-front/src/reducers/profile.js | 24 + conduit-front/src/reducers/settings.js | 25 + conduit-front/src/store.js | 25 + 71 files changed, 8990 insertions(+) create mode 100644 conduit-backend/.circleci/config.yml create mode 100644 conduit-backend/.dockerignore create mode 100644 conduit-backend/.gitignore create mode 100644 conduit-backend/.travis.yml create mode 100644 conduit-backend/Dockerfile create mode 100644 conduit-backend/README.md create mode 100644 conduit-backend/app.js create mode 100644 conduit-backend/config/index.js create mode 100644 conduit-backend/config/passport.js create mode 100644 conduit-backend/models/Article.js create mode 100644 conduit-backend/models/Comment.js create mode 100644 conduit-backend/models/User.js create mode 100644 conduit-backend/package.json create mode 100644 conduit-backend/project-logo.png create mode 100644 conduit-backend/public/.keep create mode 100644 conduit-backend/routes/api/articles.js create mode 100644 conduit-backend/routes/api/index.js create mode 100644 conduit-backend/routes/api/profiles.js create mode 100644 conduit-backend/routes/api/tags.js create mode 100644 conduit-backend/routes/api/users.js create mode 100644 conduit-backend/routes/auth.js create mode 100644 conduit-backend/routes/index.js create mode 100644 conduit-backend/tests/api-tests.postman.json create mode 100644 conduit-backend/tests/env-api-tests.postman.json create mode 100644 conduit-backend/yarn.lock create mode 100644 conduit-front/.dockerignore create mode 100644 conduit-front/.gitignore create mode 100644 conduit-front/Dockerfile create mode 100644 conduit-front/README.md create mode 100644 conduit-front/package.json create mode 100644 conduit-front/project-logo.png create mode 100644 conduit-front/public/favicon.ico create mode 100644 conduit-front/public/index.html create mode 100644 conduit-front/src/agent.js create mode 100644 conduit-front/src/components/App.js create mode 100644 conduit-front/src/components/Article/ArticleActions.js create mode 100644 conduit-front/src/components/Article/ArticleMeta.js create mode 100644 conduit-front/src/components/Article/Comment.js create mode 100644 conduit-front/src/components/Article/CommentContainer.js create mode 100644 conduit-front/src/components/Article/CommentInput.js create mode 100644 conduit-front/src/components/Article/CommentList.js create mode 100644 conduit-front/src/components/Article/DeleteButton.js create mode 100644 conduit-front/src/components/Article/index.js create mode 100644 conduit-front/src/components/ArticleList.js create mode 100644 conduit-front/src/components/ArticlePreview.js create mode 100644 conduit-front/src/components/Editor.js create mode 100644 conduit-front/src/components/Header.js create mode 100644 conduit-front/src/components/Home/Banner.js create mode 100644 conduit-front/src/components/Home/MainView.js create mode 100644 conduit-front/src/components/Home/Tags.js create mode 100644 conduit-front/src/components/Home/index.js create mode 100644 conduit-front/src/components/ListErrors.js create mode 100644 conduit-front/src/components/ListPagination.js create mode 100644 conduit-front/src/components/Login.js create mode 100644 conduit-front/src/components/Profile.js create mode 100644 conduit-front/src/components/ProfileFavorites.js create mode 100644 conduit-front/src/components/Register.js create mode 100644 conduit-front/src/components/Settings.js create mode 100644 conduit-front/src/constants/actionTypes.js create mode 100644 conduit-front/src/index.js create mode 100644 conduit-front/src/middleware.js create mode 100644 conduit-front/src/reducer.js create mode 100644 conduit-front/src/reducers/article.js create mode 100644 conduit-front/src/reducers/articleList.js create mode 100644 conduit-front/src/reducers/auth.js create mode 100644 conduit-front/src/reducers/common.js create mode 100644 conduit-front/src/reducers/editor.js create mode 100644 conduit-front/src/reducers/home.js create mode 100644 conduit-front/src/reducers/profile.js create mode 100644 conduit-front/src/reducers/settings.js create mode 100644 conduit-front/src/store.js diff --git a/conduit-backend/.circleci/config.yml b/conduit-backend/.circleci/config.yml new file mode 100644 index 0000000..c0f8472 --- /dev/null +++ b/conduit-backend/.circleci/config.yml @@ -0,0 +1,20 @@ +version: 2 + +jobs: + build: + docker: + - image: circleci/node:8.5.0 + - image: circleci/mongo:3.4.9 + steps: + - checkout + - run: + name: Start app and test + command: | + yarn + yarn run start & sleep 5 + curl http://localhost:3000/api/tags + yarn run test + - run: + name: Trigger integration tests + command: curl -X POST "https://circleci.com/api/v1.1/project/github/anishkny/realworld-e2e-test?circle-token=$CIRCLE_CI_TOKEN" + diff --git a/conduit-backend/.dockerignore b/conduit-backend/.dockerignore new file mode 100644 index 0000000..93f1361 --- /dev/null +++ b/conduit-backend/.dockerignore @@ -0,0 +1,2 @@ +node_modules +npm-debug.log diff --git a/conduit-backend/.gitignore b/conduit-backend/.gitignore new file mode 100644 index 0000000..a812403 --- /dev/null +++ b/conduit-backend/.gitignore @@ -0,0 +1,37 @@ +# Logs +logs +*.log +.DS_Store + +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +node_modules + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + +.idea diff --git a/conduit-backend/.travis.yml b/conduit-backend/.travis.yml new file mode 100644 index 0000000..795ed52 --- /dev/null +++ b/conduit-backend/.travis.yml @@ -0,0 +1,10 @@ +language: node_js +node_js: "8" + +sudo: required +services: mongodb + +install: yarn + +before_script: yarn start & sleep 5 +script: yarn test diff --git a/conduit-backend/Dockerfile b/conduit-backend/Dockerfile new file mode 100644 index 0000000..10f4416 --- /dev/null +++ b/conduit-backend/Dockerfile @@ -0,0 +1,13 @@ +# Node/express +FROM node:14 + +WORKDIR /usr/src/app + +COPY package*.json ./ + +RUN npm install + +COPY . . + +EXPOSE 3000 +CMD [ "npm", "start" ] diff --git a/conduit-backend/README.md b/conduit-backend/README.md new file mode 100644 index 0000000..660365d --- /dev/null +++ b/conduit-backend/README.md @@ -0,0 +1,52 @@ +#  + +[](https://travis-ci.org/anishkny/node-express-realworld-example-app) + +> ### Example Node (Express + Mongoose) codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the [RealWorld](https://github.com/gothinkster/realworld-example-apps) API spec. + +<a href="https://thinkster.io/tutorials/node-json-api" target="_blank"><img width="454" src="https://raw.githubusercontent.com/gothinkster/realworld/master/media/learn-btn-hr.png" /></a> + +This repo is functionality complete — PRs and issues welcome! + +# Getting started + +To get the Node server running locally: + +- Clone this repo +- `npm install` to install all required dependencies +- Install MongoDB Community Edition ([instructions](https://docs.mongodb.com/manual/installation/#tutorials)) and run it by executing `mongod` +- `npm run dev` to start the local server + +Alternately, to quickly try out this repo in the cloud, you can [](https://glitch.com/edit/#!/remix/realworld) + +# Code Overview + +## Dependencies + +- [expressjs](https://github.com/expressjs/express) - The server for handling and routing HTTP requests +- [express-jwt](https://github.com/auth0/express-jwt) - Middleware for validating JWTs for authentication +- [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) - For generating JWTs used by authentication +- [mongoose](https://github.com/Automattic/mongoose) - For modeling and mapping MongoDB data to javascript +- [mongoose-unique-validator](https://github.com/blakehaswell/mongoose-unique-validator) - For handling unique validation errors in Mongoose. Mongoose only handles validation at the document level, so a unique index across a collection will throw an exception at the driver level. The `mongoose-unique-validator` plugin helps us by formatting the error like a normal mongoose `ValidationError`. +- [passport](https://github.com/jaredhanson/passport) - For handling user authentication +- [slug](https://github.com/dodo/node-slug) - For encoding titles into a URL-friendly format + +## Application Structure + +- `app.js` - The entry point to our application. This file defines our express server and connects it to MongoDB using mongoose. It also requires the routes and models we'll be using in the application. +- `config/` - This folder contains configuration for passport as well as a central location for configuration/environment variables. +- `routes/` - This folder contains the route definitions for our API. +- `models/` - This folder contains the schema definitions for our Mongoose models. + +## Error Handling + +In `routes/api/index.js`, we define a error-handling middleware for handling Mongoose's `ValidationError`. This middleware will respond with a 422 status code and format the response to have [error messages the clients can understand](https://github.com/gothinkster/realworld/blob/master/API.md#errors-and-status-codes) + +## Authentication + +Requests are authenticated using the `Authorization` header with a valid JWT. We define two express middlewares in `routes/auth.js` that can be used to authenticate requests. The `required` middleware configures the `express-jwt` middleware using our application's secret and will return a 401 status code if the request cannot be authenticated. The payload of the JWT can then be accessed from `req.payload` in the endpoint. The `optional` middleware configures the `express-jwt` in the same way as `required`, but will *not* return a 401 status code if the request cannot be authenticated. + + +<br /> + +[](https://thinkster.io) diff --git a/conduit-backend/app.js b/conduit-backend/app.js new file mode 100644 index 0000000..460baa4 --- /dev/null +++ b/conduit-backend/app.js @@ -0,0 +1,84 @@ +var http = require('http'), + path = require('path'), + methods = require('methods'), + express = require('express'), + bodyParser = require('body-parser'), + session = require('express-session'), + cors = require('cors'), + passport = require('passport'), + errorhandler = require('errorhandler'), + mongoose = require('mongoose'); + +var isProduction = process.env.NODE_ENV === 'production'; + +// Create global app object +var app = express(); + +app.use(cors()); + +// Normal express config defaults +app.use(require('morgan')('dev')); +app.use(bodyParser.urlencoded({ extended: false })); +app.use(bodyParser.json()); + +app.use(require('method-override')()); +app.use(express.static(__dirname + '/public')); + +app.use(session({ secret: 'conduit', cookie: { maxAge: 60000 }, resave: false, saveUninitialized: false })); + +if (!isProduction) { + app.use(errorhandler()); +} + +if(isProduction){ + mongoose.connect(process.env.MONGODB_URI); +} else { + mongoose.connect('mongodb://localhost/conduit'); + mongoose.set('debug', true); +} + +require('./models/User'); +require('./models/Article'); +require('./models/Comment'); +require('./config/passport'); + +app.use(require('./routes')); + +/// catch 404 and forward to error handler +app.use(function(req, res, next) { + var err = new Error('Not Found'); + err.status = 404; + next(err); +}); + +/// error handlers + +// development error handler +// will print stacktrace +if (!isProduction) { + app.use(function(err, req, res, next) { + console.log(err.stack); + + res.status(err.status || 500); + + res.json({'errors': { + message: err.message, + error: err + }}); + }); +} + +// production error handler +// no stacktraces leaked to user +app.use(function(err, req, res, next) { + res.status(err.status || 500); + res.json({'errors': { + message: err.message, + error: {} + }}); +}); + +// finally, let's start our server... +var server = app.listen( process.env.PORT || 3000, function(){ + console.log('Listening on port ' + server.address().port); +}); diff --git a/conduit-backend/config/index.js b/conduit-backend/config/index.js new file mode 100644 index 0000000..1bf9d6a --- /dev/null +++ b/conduit-backend/config/index.js @@ -0,0 +1,3 @@ +module.exports = { + secret: process.env.NODE_ENV === 'production' ? process.env.SECRET : 'secret' +}; diff --git a/conduit-backend/config/passport.js b/conduit-backend/config/passport.js new file mode 100644 index 0000000..abe0ce2 --- /dev/null +++ b/conduit-backend/config/passport.js @@ -0,0 +1,18 @@ +var passport = require('passport'); +var LocalStrategy = require('passport-local').Strategy; +var mongoose = require('mongoose'); +var User = mongoose.model('User'); + +passport.use(new LocalStrategy({ + usernameField: 'user[email]', + passwordField: 'user[password]' +}, function(email, password, done) { + User.findOne({email: email}).then(function(user){ + if(!user || !user.validPassword(password)){ + return done(null, false, {errors: {'email or password': 'is invalid'}}); + } + + return done(null, user); + }).catch(done); +})); + diff --git a/conduit-backend/models/Article.js b/conduit-backend/models/Article.js new file mode 100644 index 0000000..e0d12ed --- /dev/null +++ b/conduit-backend/models/Article.js @@ -0,0 +1,56 @@ +var mongoose = require('mongoose'); +var uniqueValidator = require('mongoose-unique-validator'); +var slug = require('slug'); +var User = mongoose.model('User'); + +var ArticleSchema = new mongoose.Schema({ + slug: {type: String, lowercase: true, unique: true}, + title: String, + description: String, + body: String, + favoritesCount: {type: Number, default: 0}, + comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }], + tagList: [{ type: String }], + author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } +}, {timestamps: true, usePushEach: true}); + +ArticleSchema.plugin(uniqueValidator, {message: 'is already taken'}); + +ArticleSchema.pre('validate', function(next){ + if(!this.slug) { + this.slugify(); + } + + next(); +}); + +ArticleSchema.methods.slugify = function() { + this.slug = slug(this.title) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36); +}; + +ArticleSchema.methods.updateFavoriteCount = function() { + var article = this; + + return User.count({favorites: {$in: [article._id]}}).then(function(count){ + article.favoritesCount = count; + + return article.save(); + }); +}; + +ArticleSchema.methods.toJSONFor = function(user){ + return { + slug: this.slug, + title: this.title, + description: this.description, + body: this.body, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + tagList: this.tagList, + favorited: user ? user.isFavorite(this._id) : false, + favoritesCount: this.favoritesCount, + author: this.author.toProfileJSONFor(user) + }; +}; + +mongoose.model('Article', ArticleSchema); diff --git a/conduit-backend/models/Comment.js b/conduit-backend/models/Comment.js new file mode 100644 index 0000000..7def57d --- /dev/null +++ b/conduit-backend/models/Comment.js @@ -0,0 +1,19 @@ +var mongoose = require('mongoose'); + +var CommentSchema = new mongoose.Schema({ + body: String, + author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, + article: { type: mongoose.Schema.Types.ObjectId, ref: 'Article' } +}, {timestamps: true, usePushEach: true}); + +// Requires population of author +CommentSchema.methods.toJSONFor = function(user){ + return { + id: this._id, + body: this.body, + createdAt: this.createdAt, + author: this.author.toProfileJSONFor(user) + }; +}; + +mongoose.model('Comment', CommentSchema); diff --git a/conduit-backend/models/User.js b/conduit-backend/models/User.js new file mode 100644 index 0000000..482613b --- /dev/null +++ b/conduit-backend/models/User.js @@ -0,0 +1,99 @@ +var mongoose = require('mongoose'); +var uniqueValidator = require('mongoose-unique-validator'); +var crypto = require('crypto'); +var jwt = require('jsonwebtoken'); +var secret = require('../config').secret; + +var UserSchema = new mongoose.Schema({ + username: {type: String, lowercase: true, unique: true, required: [true, "can't be blank"], match: [/^[a-zA-Z0-9]+$/, 'is invalid'], index: true}, + email: {type: String, lowercase: true, unique: true, required: [true, "can't be blank"], match: [/\S+@\S+\.\S+/, 'is invalid'], index: true}, + bio: String, + image: String, + favorites: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Article' }], + following: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }], + hash: String, + salt: String +}, {timestamps: true, usePushEach: true}); + +UserSchema.plugin(uniqueValidator, {message: 'is already taken.'}); + +UserSchema.methods.validPassword = function(password) { + var hash = crypto.pbkdf2Sync(password, this.salt, 10000, 512, 'sha512').toString('hex'); + return this.hash === hash; +}; + +UserSchema.methods.setPassword = function(password){ + this.salt = crypto.randomBytes(16).toString('hex'); + this.hash = crypto.pbkdf2Sync(password, this.salt, 10000, 512, 'sha512').toString('hex'); +}; + +UserSchema.methods.generateJWT = function() { + var today = new Date(); + var exp = new Date(today); + exp.setDate(today.getDate() + 60); + + return jwt.sign({ + id: this._id, + username: this.username, + exp: parseInt(exp.getTime() / 1000), + }, secret); +}; + +UserSchema.methods.toAuthJSON = function(){ + return { + username: this.username, + email: this.email, + token: this.generateJWT(), + bio: this.bio, + image: this.image + }; +}; + +UserSchema.methods.toProfileJSONFor = function(user){ + return { + username: this.username, + bio: this.bio, + image: this.image || 'https://static.productionready.io/images/smiley-cyrus.jpg', + following: user ? user.isFollowing(this._id) : false + }; +}; + +UserSchema.methods.favorite = function(id){ + if(this.favorites.indexOf(id) === -1){ + this.favorites.push(id); + } + + return this.save(); +}; + +UserSchema.methods.unfavorite = function(id){ + this.favorites.remove(id); + return this.save(); +}; + +UserSchema.methods.isFavorite = function(id){ + return this.favorites.some(function(favoriteId){ + return favoriteId.toString() === id.toString(); + }); +}; + +UserSchema.methods.follow = function(id){ + if(this.following.indexOf(id) === -1){ + this.following.push(id); + } + + return this.save(); +}; + +UserSchema.methods.unfollow = function(id){ + this.following.remove(id); + return this.save(); +}; + +UserSchema.methods.isFollowing = function(id){ + return this.following.some(function(followId){ + return followId.toString() === id.toString(); + }); +}; + +mongoose.model('User', UserSchema); diff --git a/conduit-backend/package.json b/conduit-backend/package.json new file mode 100644 index 0000000..8facb2e --- /dev/null +++ b/conduit-backend/package.json @@ -0,0 +1,43 @@ +{ + "name": "conduit-node", + "version": "1.0.0", + "description": "conduit on node", + "main": "app.js", + "scripts": { + "mongo:start": "docker run --name realworld-mongo -p 27017:27017 mongo & sleep 5", + "start": "node ./app.js", + "dev": "nodemon ./app.js", + "test": "newman run ./tests/api-tests.postman.json -e ./tests/env-api-tests.postman.json", + "stop": "lsof -ti :3000 | xargs kill", + "mongo:stop": "docker stop realworld-mongo && docker rm realworld-mongo" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/gothinkster/productionready-node-api.git" + }, + "license": "ISC", + "dependencies": { + "body-parser": "1.15.0", + "cors": "2.7.1", + "ejs": "2.4.1", + "errorhandler": "1.4.3", + "express": "4.13.4", + "express-jwt": "3.3.0", + "express-session": "1.13.0", + "jsonwebtoken": "7.1.9", + "method-override": "2.3.5", + "methods": "1.1.2", + "mongoose": "4.6.4", + "mongoose-unique-validator": "1.0.2", + "morgan": "1.7.0", + "passport": "0.3.2", + "passport-local": "1.0.0", + "request": "2.69.0", + "slug": "0.9.1", + "underscore": "1.8.3" + }, + "devDependencies": { + "newman": "^3.8.2", + "nodemon": "^1.11.0" + } +} diff --git a/conduit-backend/project-logo.png b/conduit-backend/project-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ef92a4be8c6cb93a3e9c78d72787e558a40cd149 GIT binary patch literal 53176 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 T4&^Tm3_#%N>gTe~DWM4fEO&TD literal 0 HcmV?d00001 diff --git a/conduit-backend/public/.keep b/conduit-backend/public/.keep new file mode 100644 index 0000000..e69de29 diff --git a/conduit-backend/routes/api/articles.js b/conduit-backend/routes/api/articles.js new file mode 100644 index 0000000..e0f1074 --- /dev/null +++ b/conduit-backend/routes/api/articles.js @@ -0,0 +1,279 @@ +var router = require('express').Router(); +var mongoose = require('mongoose'); +var Article = mongoose.model('Article'); +var Comment = mongoose.model('Comment'); +var User = mongoose.model('User'); +var auth = require('../auth'); + +// Preload article objects on routes with ':article' +router.param('article', function(req, res, next, slug) { + Article.findOne({ slug: slug}) + .populate('author') + .then(function (article) { + if (!article) { return res.sendStatus(404); } + + req.article = article; + + return next(); + }).catch(next); +}); + +router.param('comment', function(req, res, next, id) { + Comment.findById(id).then(function(comment){ + if(!comment) { return res.sendStatus(404); } + + req.comment = comment; + + return next(); + }).catch(next); +}); + +router.get('/', auth.optional, function(req, res, next) { + var query = {}; + var limit = 20; + var offset = 0; + + if(typeof req.query.limit !== 'undefined'){ + limit = req.query.limit; + } + + if(typeof req.query.offset !== 'undefined'){ + offset = req.query.offset; + } + + if( typeof req.query.tag !== 'undefined' ){ + query.tagList = {"$in" : [req.query.tag]}; + } + + Promise.all([ + req.query.author ? User.findOne({username: req.query.author}) : null, + req.query.favorited ? User.findOne({username: req.query.favorited}) : null + ]).then(function(results){ + var author = results[0]; + var favoriter = results[1]; + + if(author){ + query.author = author._id; + } + + if(favoriter){ + query._id = {$in: favoriter.favorites}; + } else if(req.query.favorited){ + query._id = {$in: []}; + } + + return Promise.all([ + Article.find(query) + .limit(Number(limit)) + .skip(Number(offset)) + .sort({createdAt: 'desc'}) + .populate('author') + .exec(), + Article.count(query).exec(), + req.payload ? User.findById(req.payload.id) : null, + ]).then(function(results){ + var articles = results[0]; + var articlesCount = results[1]; + var user = results[2]; + + return res.json({ + articles: articles.map(function(article){ + return article.toJSONFor(user); + }), + articlesCount: articlesCount + }); + }); + }).catch(next); +}); + +router.get('/feed', auth.required, function(req, res, next) { + var limit = 20; + var offset = 0; + + if(typeof req.query.limit !== 'undefined'){ + limit = req.query.limit; + } + + if(typeof req.query.offset !== 'undefined'){ + offset = req.query.offset; + } + + User.findById(req.payload.id).then(function(user){ + if (!user) { return res.sendStatus(401); } + + Promise.all([ + Article.find({ author: {$in: user.following}}) + .limit(Number(limit)) + .skip(Number(offset)) + .populate('author') + .exec(), + Article.count({ author: {$in: user.following}}) + ]).then(function(results){ + var articles = results[0]; + var articlesCount = results[1]; + + return res.json({ + articles: articles.map(function(article){ + return article.toJSONFor(user); + }), + articlesCount: articlesCount + }); + }).catch(next); + }); +}); + +router.post('/', auth.required, function(req, res, next) { + User.findById(req.payload.id).then(function(user){ + if (!user) { return res.sendStatus(401); } + + var article = new Article(req.body.article); + + article.author = user; + + return article.save().then(function(){ + console.log(article.author); + return res.json({article: article.toJSONFor(user)}); + }); + }).catch(next); +}); + +// return a article +router.get('/:article', auth.optional, function(req, res, next) { + Promise.all([ + req.payload ? User.findById(req.payload.id) : null, + req.article.populate('author').execPopulate() + ]).then(function(results){ + var user = results[0]; + + return res.json({article: req.article.toJSONFor(user)}); + }).catch(next); +}); + +// update article +router.put('/:article', auth.required, function(req, res, next) { + User.findById(req.payload.id).then(function(user){ + if(req.article.author._id.toString() === req.payload.id.toString()){ + if(typeof req.body.article.title !== 'undefined'){ + req.article.title = req.body.article.title; + } + + if(typeof req.body.article.description !== 'undefined'){ + req.article.description = req.body.article.description; + } + + if(typeof req.body.article.body !== 'undefined'){ + req.article.body = req.body.article.body; + } + + if(typeof req.body.article.tagList !== 'undefined'){ + req.article.tagList = req.body.article.tagList + } + + req.article.save().then(function(article){ + return res.json({article: article.toJSONFor(user)}); + }).catch(next); + } else { + return res.sendStatus(403); + } + }); +}); + +// delete article +router.delete('/:article', auth.required, function(req, res, next) { + User.findById(req.payload.id).then(function(user){ + if (!user) { return res.sendStatus(401); } + + if(req.article.author._id.toString() === req.payload.id.toString()){ + return req.article.remove().then(function(){ + return res.sendStatus(204); + }); + } else { + return res.sendStatus(403); + } + }).catch(next); +}); + +// Favorite an article +router.post('/:article/favorite', auth.required, function(req, res, next) { + var articleId = req.article._id; + + User.findById(req.payload.id).then(function(user){ + if (!user) { return res.sendStatus(401); } + + return user.favorite(articleId).then(function(){ + return req.article.updateFavoriteCount().then(function(article){ + return res.json({article: article.toJSONFor(user)}); + }); + }); + }).catch(next); +}); + +// Unfavorite an article +router.delete('/:article/favorite', auth.required, function(req, res, next) { + var articleId = req.article._id; + + User.findById(req.payload.id).then(function (user){ + if (!user) { return res.sendStatus(401); } + + return user.unfavorite(articleId).then(function(){ + return req.article.updateFavoriteCount().then(function(article){ + return res.json({article: article.toJSONFor(user)}); + }); + }); + }).catch(next); +}); + +// return an article's comments +router.get('/:article/comments', auth.optional, function(req, res, next){ + Promise.resolve(req.payload ? User.findById(req.payload.id) : null).then(function(user){ + return req.article.populate({ + path: 'comments', + populate: { + path: 'author' + }, + options: { + sort: { + createdAt: 'desc' + } + } + }).execPopulate().then(function(article) { + return res.json({comments: req.article.comments.map(function(comment){ + return comment.toJSONFor(user); + })}); + }); + }).catch(next); +}); + +// create a new comment +router.post('/:article/comments', auth.required, function(req, res, next) { + User.findById(req.payload.id).then(function(user){ + if(!user){ return res.sendStatus(401); } + + var comment = new Comment(req.body.comment); + comment.article = req.article; + comment.author = user; + + return comment.save().then(function(){ + req.article.comments.push(comment); + + return req.article.save().then(function(article) { + res.json({comment: comment.toJSONFor(user)}); + }); + }); + }).catch(next); +}); + +router.delete('/:article/comments/:comment', auth.required, function(req, res, next) { + if(req.comment.author.toString() === req.payload.id.toString()){ + req.article.comments.remove(req.comment._id); + req.article.save() + .then(Comment.find({_id: req.comment._id}).remove().exec()) + .then(function(){ + res.sendStatus(204); + }); + } else { + res.sendStatus(403); + } +}); + +module.exports = router; diff --git a/conduit-backend/routes/api/index.js b/conduit-backend/routes/api/index.js new file mode 100644 index 0000000..03f36d6 --- /dev/null +++ b/conduit-backend/routes/api/index.js @@ -0,0 +1,22 @@ +var router = require('express').Router(); + +router.use('/', require('./users')); +router.use('/profiles', require('./profiles')); +router.use('/articles', require('./articles')); +router.use('/tags', require('./tags')); + +router.use(function(err, req, res, next){ + if(err.name === 'ValidationError'){ + return res.status(422).json({ + errors: Object.keys(err.errors).reduce(function(errors, key){ + errors[key] = err.errors[key].message; + + return errors; + }, {}) + }); + } + + return next(err); +}); + +module.exports = router; \ No newline at end of file diff --git a/conduit-backend/routes/api/profiles.js b/conduit-backend/routes/api/profiles.js new file mode 100644 index 0000000..ffcd833 --- /dev/null +++ b/conduit-backend/routes/api/profiles.js @@ -0,0 +1,53 @@ +var router = require('express').Router(); +var mongoose = require('mongoose'); +var User = mongoose.model('User'); +var auth = require('../auth'); + +// Preload user profile on routes with ':username' +router.param('username', function(req, res, next, username){ + User.findOne({username: username}).then(function(user){ + if (!user) { return res.sendStatus(404); } + + req.profile = user; + + return next(); + }).catch(next); +}); + +router.get('/:username', auth.optional, function(req, res, next){ + if(req.payload){ + User.findById(req.payload.id).then(function(user){ + if(!user){ return res.json({profile: req.profile.toProfileJSONFor(false)}); } + + return res.json({profile: req.profile.toProfileJSONFor(user)}); + }); + } else { + return res.json({profile: req.profile.toProfileJSONFor(false)}); + } +}); + +router.post('/:username/follow', auth.required, function(req, res, next){ + var profileId = req.profile._id; + + User.findById(req.payload.id).then(function(user){ + if (!user) { return res.sendStatus(401); } + + return user.follow(profileId).then(function(){ + return res.json({profile: req.profile.toProfileJSONFor(user)}); + }); + }).catch(next); +}); + +router.delete('/:username/follow', auth.required, function(req, res, next){ + var profileId = req.profile._id; + + User.findById(req.payload.id).then(function(user){ + if (!user) { return res.sendStatus(401); } + + return user.unfollow(profileId).then(function(){ + return res.json({profile: req.profile.toProfileJSONFor(user)}); + }); + }).catch(next); +}); + +module.exports = router; diff --git a/conduit-backend/routes/api/tags.js b/conduit-backend/routes/api/tags.js new file mode 100644 index 0000000..bea1a80 --- /dev/null +++ b/conduit-backend/routes/api/tags.js @@ -0,0 +1,12 @@ +var router = require('express').Router(); +var mongoose = require('mongoose'); +var Article = mongoose.model('Article'); + +// return a list of tags +router.get('/', function(req, res, next) { + Article.find().distinct('tagList').then(function(tags){ + return res.json({tags: tags}); + }).catch(next); +}); + +module.exports = router; diff --git a/conduit-backend/routes/api/users.js b/conduit-backend/routes/api/users.js new file mode 100644 index 0000000..cc2e444 --- /dev/null +++ b/conduit-backend/routes/api/users.js @@ -0,0 +1,75 @@ +var mongoose = require('mongoose'); +var router = require('express').Router(); +var passport = require('passport'); +var User = mongoose.model('User'); +var auth = require('../auth'); + +router.get('/user', auth.required, function(req, res, next){ + User.findById(req.payload.id).then(function(user){ + if(!user){ return res.sendStatus(401); } + + return res.json({user: user.toAuthJSON()}); + }).catch(next); +}); + +router.put('/user', auth.required, function(req, res, next){ + User.findById(req.payload.id).then(function(user){ + if(!user){ return res.sendStatus(401); } + + // only update fields that were actually passed... + if(typeof req.body.user.username !== 'undefined'){ + user.username = req.body.user.username; + } + if(typeof req.body.user.email !== 'undefined'){ + user.email = req.body.user.email; + } + if(typeof req.body.user.bio !== 'undefined'){ + user.bio = req.body.user.bio; + } + if(typeof req.body.user.image !== 'undefined'){ + user.image = req.body.user.image; + } + if(typeof req.body.user.password !== 'undefined'){ + user.setPassword(req.body.user.password); + } + + return user.save().then(function(){ + return res.json({user: user.toAuthJSON()}); + }); + }).catch(next); +}); + +router.post('/users/login', function(req, res, next){ + if(!req.body.user.email){ + return res.status(422).json({errors: {email: "can't be blank"}}); + } + + if(!req.body.user.password){ + return res.status(422).json({errors: {password: "can't be blank"}}); + } + + passport.authenticate('local', {session: false}, function(err, user, info){ + if(err){ return next(err); } + + if(user){ + user.token = user.generateJWT(); + return res.json({user: user.toAuthJSON()}); + } else { + return res.status(422).json(info); + } + })(req, res, next); +}); + +router.post('/users', function(req, res, next){ + var user = new User(); + + user.username = req.body.user.username; + user.email = req.body.user.email; + user.setPassword(req.body.user.password); + + user.save().then(function(){ + return res.json({user: user.toAuthJSON()}); + }).catch(next); +}); + +module.exports = router; diff --git a/conduit-backend/routes/auth.js b/conduit-backend/routes/auth.js new file mode 100644 index 0000000..e44a215 --- /dev/null +++ b/conduit-backend/routes/auth.js @@ -0,0 +1,27 @@ +var jwt = require('express-jwt'); +var secret = require('../config').secret; + +function getTokenFromHeader(req){ + if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Token' || + req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { + return req.headers.authorization.split(' ')[1]; + } + + return null; +} + +var auth = { + required: jwt({ + secret: secret, + userProperty: 'payload', + getToken: getTokenFromHeader + }), + optional: jwt({ + secret: secret, + userProperty: 'payload', + credentialsRequired: false, + getToken: getTokenFromHeader + }) +}; + +module.exports = auth; diff --git a/conduit-backend/routes/index.js b/conduit-backend/routes/index.js new file mode 100644 index 0000000..3585767 --- /dev/null +++ b/conduit-backend/routes/index.js @@ -0,0 +1,5 @@ +var router = require('express').Router(); + +router.use('/api', require('./api')); + +module.exports = router; diff --git a/conduit-backend/tests/api-tests.postman.json b/conduit-backend/tests/api-tests.postman.json new file mode 100644 index 0000000..bad71a2 --- /dev/null +++ b/conduit-backend/tests/api-tests.postman.json @@ -0,0 +1,1900 @@ +{ + "variables": [], + "info": { + "name": "Conduit API Tests", + "_postman_id": "dda3e595-02d7-bf12-2a43-3daea0970192", + "description": "Collection for testing the Conduit API\n\nhttps://github.com/gothinkster/realworld", + "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" + }, + "item": [{ + "name": "Auth", + "description": "", + "item": [{ + "name": "Register", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "if (!(environment.isIntegrationTest)) {", + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"user\" property'] = responseJSON.hasOwnProperty('user');", + "", + "var user = responseJSON.user || {};", + "", + "tests['User has \"email\" property'] = user.hasOwnProperty('email');", + "tests['User has \"username\" property'] = user.hasOwnProperty('username');", + "tests['User has \"token\" property'] = user.hasOwnProperty('token');", + "}", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/users", + "method": "POST", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"user\":{\"email\":\"john@jacob.com\", \"password\":\"johnnyjacob\", \"username\":\"johnjacob\"}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Login", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"user\" property'] = responseJSON.hasOwnProperty('user');", + "", + "var user = responseJSON.user || {};", + "", + "tests['User has \"email\" property'] = user.hasOwnProperty('email');", + "tests['User has \"username\" property'] = user.hasOwnProperty('username');", + "tests['User has \"token\" property'] = user.hasOwnProperty('token');", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/users/login", + "method": "POST", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"user\":{\"email\":\"john@jacob.com\", \"password\":\"johnnyjacob\"}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Login and Remember Token", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"user\" property'] = responseJSON.hasOwnProperty('user');", + "", + "var user = responseJSON.user || {};", + "", + "tests['User has \"email\" property'] = user.hasOwnProperty('email');", + "tests['User has \"username\" property'] = user.hasOwnProperty('username');", + "tests['User has \"token\" property'] = user.hasOwnProperty('token');", + "", + "if(tests['User has \"token\" property']){", + " postman.setEnvironmentVariable('token', user.token);", + "}", + "", + "tests['Environment variable \"token\" has been set'] = environment.token === user.token;", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/users/login", + "method": "POST", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"user\":{\"email\":\"john@jacob.com\", \"password\":\"johnnyjacob\"}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Current User", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"user\" property'] = responseJSON.hasOwnProperty('user');", + "", + "var user = responseJSON.user || {};", + "", + "tests['User has \"email\" property'] = user.hasOwnProperty('email');", + "tests['User has \"username\" property'] = user.hasOwnProperty('username');", + "tests['User has \"token\" property'] = user.hasOwnProperty('token');", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/user", + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + }, + { + "name": "Update User", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"user\" property'] = responseJSON.hasOwnProperty('user');", + "", + "var user = responseJSON.user || {};", + "", + "tests['User has \"email\" property'] = user.hasOwnProperty('email');", + "tests['User has \"username\" property'] = user.hasOwnProperty('username');", + "tests['User has \"token\" property'] = user.hasOwnProperty('token');", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/user", + "method": "PUT", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"user\":{\"email\":\"john@jacob.com\"}}" + }, + "description": "" + }, + "response": [] + } + ] + }, + { + "name": "Articles with authentication", + "description": "", + "item": [{ + "name": "Feed", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/articles/feed", + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "All Articles", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/articles", + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "All Articles with auth", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/articles", + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles by Author", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + }], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?author=johnjacob", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [{ + "key": "author", + "value": "johnjacob" + }], + "variable": [] + }, + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles by Author with auth", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + }], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?author=johnjacob", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [{ + "key": "author", + "value": "johnjacob", + "equals": true, + "description": "" + }], + "variable": [] + }, + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + }, + { + "name": "Articles Favorited by Username", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + " ", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + }], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?favorited=jane", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [{ + "key": "favorited", + "value": "jane" + }], + "variable": [] + }, + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles Favorited by Username with auth", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + " ", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + }], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?favorited=jane", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [{ + "key": "favorited", + "value": "jane" + }], + "variable": [] + }, + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles by Tag", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + }], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?tag=dragons", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [{ + "key": "tag", + "value": "dragons" + }], + "variable": [] + }, + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Create Article", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"article\" property'] = responseJSON.hasOwnProperty('article');", + "", + "var article = responseJSON.article || {};", + "", + "tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + "tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + "if(tests['Article has \"slug\" property']){", + " postman.setEnvironmentVariable('slug', article.slug);", + "}", + "tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + "tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + "tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + "tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + "tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + "tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + "tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + "tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + "tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + "tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + "tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + "tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/articles", + "method": "POST", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"article\":{\"title\":\"How to train your dragon\", \"description\":\"Ever wonder how?\", \"body\":\"Very carefully.\", \"tagList\":[\"dragons\",\"training\"]}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Single Article by slug", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"article\" property'] = responseJSON.hasOwnProperty('article');", + "", + "var article = responseJSON.article || {};", + "", + "tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + "tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + "tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + "tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + "tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + "tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + "tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + "tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + "tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + "tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + "tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + "tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + "tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + "tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}", + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + }, + { + "name": "Update Article", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "if (!(environment.isIntegrationTest)) {", + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"article\" property'] = responseJSON.hasOwnProperty('article');", + "", + "var article = responseJSON.article || {};", + "", + "tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + "tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + "tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + "tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + "tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + "tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + "tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + "tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + "tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + "tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + "tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + "tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + "tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + "tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + "}", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}", + "method": "PUT", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"article\":{\"body\":\"With two hands\"}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Favorite Article", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"article\" property'] = responseJSON.hasOwnProperty('article');", + "", + "var article = responseJSON.article || {};", + "", + "tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + "tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + "tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + "tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + "tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + "tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + "tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + "tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + "tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + "tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + "tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + "tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + "tests[\"Article's 'favorited' property is true\"] = article.favorited === true;", + "tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + "tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + "tests[\"Article's 'favoritesCount' property is greater than 0\"] = article.favoritesCount > 0;", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}/favorite", + "method": "POST", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Unfavorite Article", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"article\" property'] = responseJSON.hasOwnProperty('article');", + "", + "var article = responseJSON.article || {};", + "", + "tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + "tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + "tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + "tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + "tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + "tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + "tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + "tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + "tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + "tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + "tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + "tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + "tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + "tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + "tests[\"Article's \\\"favorited\\\" property is true\"] = article.favorited === false;", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}/favorite", + "method": "DELETE", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + } + ] + }, + { + "name": "Articles", + "description": "", + "item": [{ + "name": "All Articles", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/articles", + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles by Author", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + }], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?author=johnjacob", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [{ + "key": "author", + "value": "johnjacob" + }], + "variable": [] + }, + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles Favorited by Username", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + " ", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + }], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?favorited=jane", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [{ + "key": "favorited", + "value": "jane" + }], + "variable": [] + }, + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles by Tag", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + }], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?tag=dragons", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [{ + "key": "tag", + "value": "dragons" + }], + "variable": [] + }, + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Single Article by slug", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"article\" property'] = responseJSON.hasOwnProperty('article');", + "", + "var article = responseJSON.article || {};", + "", + "tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + "tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + "tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + "tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + "tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + "tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + "tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + "tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + "tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + "tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + "tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + "tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + "tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + "tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}", + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + } + ] + }, + { + "name": "Comments", + "description": "", + "item": [{ + "name": "All Comments for Article", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"comments\" property'] = responseJSON.hasOwnProperty('comments');", + "", + " if(responseJSON.comments.length){", + " var comment = responseJSON.comments[0];", + "", + " tests['Comment has \"id\" property'] = comment.hasOwnProperty('id');", + " tests['Comment has \"body\" property'] = comment.hasOwnProperty('body');", + " tests['Comment has \"createdAt\" property'] = comment.hasOwnProperty('createdAt');", + " tests['\"createdAt\" property is an ISO 8601 timestamp'] = new Date(comment.createdAt).toISOString() === comment.createdAt;", + " tests['Comment has \"updatedAt\" property'] = comment.hasOwnProperty('updatedAt');", + " tests['\"updatedAt\" property is an ISO 8601 timestamp'] = new Date(comment.updatedAt).toISOString() === comment.updatedAt;", + " tests['Comment has \"author\" property'] = comment.hasOwnProperty('author');", + " }", + "}", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}/comments", + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + }, + { + "name": "Create Comment for Article", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"comment\" property'] = responseJSON.hasOwnProperty('comment');", + "", + "var comment = responseJSON.comment || {};", + "", + "tests['Comment has \"id\" property'] = comment.hasOwnProperty('id');", + "tests['Comment has \"body\" property'] = comment.hasOwnProperty('body');", + "tests['Comment has \"createdAt\" property'] = comment.hasOwnProperty('createdAt');", + "tests['\"createdAt\" property is an ISO 8601 timestamp'] = new Date(comment.createdAt).toISOString() === comment.createdAt;", + "tests['Comment has \"author\" property'] = comment.hasOwnProperty('author');", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}/comments", + "method": "POST", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"comment\":{\"body\":\"Thank you so much!\"}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Delete Comment for Article", + "request": { + "url": "{{apiUrl}}/articles/{{slug}}/comments/1", + "method": "DELETE", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + } + ] + }, + { + "name": "Profiles", + "description": "", + "item": [{ + "name": "Profile", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "if (!(environment.isIntegrationTest)) {", + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"profile\" property'] = responseJSON.hasOwnProperty('profile');", + " ", + " var profile = responseJSON.profile || {};", + " ", + " tests['Profile has \"username\" property'] = profile.hasOwnProperty('username');", + " tests['Profile has \"image\" property'] = profile.hasOwnProperty('image');", + " tests['Profile has \"following\" property'] = profile.hasOwnProperty('following');", + "}", + "}", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/profiles/johnjacob", + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + }, + { + "name": "Follow Profile", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "if (!(environment.isIntegrationTest)) {", + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"profile\" property'] = responseJSON.hasOwnProperty('profile');", + " ", + " var profile = responseJSON.profile || {};", + " ", + " tests['Profile has \"username\" property'] = profile.hasOwnProperty('username');", + " tests['Profile has \"image\" property'] = profile.hasOwnProperty('image');", + " tests['Profile has \"following\" property'] = profile.hasOwnProperty('following');", + " tests['Profile\\'s \"following\" property is true'] = profile.following === true;", + "}", + "}", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/profiles/johnjacob/follow", + "method": "POST", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"user\":{\"email\":\"john@jacob.com\"}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Unfollow Profile", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "if (!(environment.isIntegrationTest)) {", + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"profile\" property'] = responseJSON.hasOwnProperty('profile');", + " ", + " var profile = responseJSON.profile || {};", + " ", + " tests['Profile has \"username\" property'] = profile.hasOwnProperty('username');", + " tests['Profile has \"image\" property'] = profile.hasOwnProperty('image');", + " tests['Profile has \"following\" property'] = profile.hasOwnProperty('following');", + " tests['Profile\\'s \"following\" property is false'] = profile.following === false;", + "}", + "}", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/profiles/johnjacob/follow", + "method": "DELETE", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + } + ] + }, + { + "name": "Tags", + "description": "", + "item": [{ + "name": "All Tags", + "event": [{ + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + " ", + " tests['Response contains \"tags\" property'] = responseJSON.hasOwnProperty('tags');", + " tests['\"tags\" property returned as array'] = Array.isArray(responseJSON.tags);", + "}", + "" + ] + } + }], + "request": { + "url": "{{apiUrl}}/tags", + "method": "GET", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }] + }, + { + "name": "Cleanup", + "description": "", + "item": [{ + "name": "Delete Article", + "request": { + "url": "{{apiUrl}}/articles/{{slug}}", + "method": "DELETE", + "header": [{ + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }] + } + ] +} diff --git a/conduit-backend/tests/env-api-tests.postman.json b/conduit-backend/tests/env-api-tests.postman.json new file mode 100644 index 0000000..f838f79 --- /dev/null +++ b/conduit-backend/tests/env-api-tests.postman.json @@ -0,0 +1,14 @@ +{ + "id": "4aa60b52-97fc-456d-4d4f-14a350e95dff", + "name": "Conduit API Tests - Environment", + "values": [{ + "enabled": true, + "key": "apiUrl", + "value": "http://localhost:3000/api", + "type": "text" + }], + "timestamp": 1505871382668, + "_postman_variable_scope": "environment", + "_postman_exported_at": "2017-09-20T01:36:34.835Z", + "_postman_exported_using": "Postman/5.2.0" +} diff --git a/conduit-backend/yarn.lock b/conduit-backend/yarn.lock new file mode 100644 index 0000000..c8870ee --- /dev/null +++ b/conduit-backend/yarn.lock @@ -0,0 +1,3628 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +JSONStream@^1.0.3: + version "1.3.1" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.1.tgz#707f761e01dae9e16f1bcf93703b78c70966579a" + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abbrev@1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" + +accepts@~1.2.12: + version "1.2.13" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.2.13.tgz#e5f1f3928c6d95fd96558c36ec3d9d0de4a6ecea" + dependencies: + mime-types "~2.1.6" + negotiator "0.5.3" + +accepts@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" + dependencies: + mime-types "~2.1.16" + negotiator "0.6.1" + +acorn@^4.0.3: + version "4.0.13" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" + +ajv@^5.1.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.2.tgz#47c68d69e86f5d953103b0074a9430dc63da5e39" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + json-schema-traverse "^0.3.0" + json-stable-stringify "^1.0.1" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-align@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" + dependencies: + string-width "^2.0.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-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" + dependencies: + color-convert "^1.9.0" + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +array-filter@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-map@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" + +array-reduce@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +asn1.js@^4.0.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +astw@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/astw/-/astw-2.2.0.tgz#7bd41784d32493987aeb239b6b4e1c57a873b917" + dependencies: + acorn "^4.0.3" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async@1.5.2, async@^1.4.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@2.5.0, async@^2.0.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" + dependencies: + lodash "^4.14.0" + +async@^0.9.0: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +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.6.0, aws4@^1.2.1, aws4@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base64-js@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" + +base64-url@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/base64-url/-/base64-url-1.2.1.tgz#199fd661702a0e7b7dcae6e0698bb089c52f6d78" + +base64url@2.0.0, base64url@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb" + +basic-auth@~1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.0.4.tgz#030935b01de7c9b94a824b29f3fccb750d3a5290" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +binary-extensions@^1.0.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" + +bl@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e" + dependencies: + readable-stream "~2.0.5" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@2.10.2, bluebird@^2.6.2: + version "2.10.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.10.2.tgz#024a5517295308857f14f91f1106fc3b555f446b" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + +body-parser@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.15.0.tgz#8168abaeaf9e77e300f7b3aef4df4b46e9b21b35" + dependencies: + bytes "2.2.0" + content-type "~1.0.1" + debug "~2.2.0" + depd "~1.1.0" + http-errors "~1.4.0" + iconv-lite "0.4.13" + on-finished "~2.3.0" + qs "6.1.0" + raw-body "~2.1.5" + type-is "~1.6.11" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + 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" + +boxen@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.2.1.tgz#0f11e7fe344edb9397977fc13ede7f64d956481d" + dependencies: + ansi-align "^2.0.0" + camelcase "^4.0.0" + chalk "^2.0.1" + cli-boxes "^1.0.0" + string-width "^2.0.0" + term-size "^1.2.0" + widest-line "^1.0.0" + +brace-expansion@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + +browser-pack@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.0.2.tgz#f86cd6cef4f5300c8e63e07a4d512f65fbff4531" + dependencies: + JSONStream "^1.0.3" + combine-source-map "~0.7.1" + defined "^1.0.0" + through2 "^2.0.0" + umd "^3.0.0" + +browser-resolve@^1.11.0, browser-resolve@^1.7.0: + version "1.11.2" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" + dependencies: + resolve "1.1.7" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.0.8" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.8.tgz#c8fa3b1b7585bb7ba77c5560b60996ddec6d5309" + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@~0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" + dependencies: + pako "~0.2.0" + +browserify@14.4.0: + version "14.4.0" + resolved "https://registry.yarnpkg.com/browserify/-/browserify-14.4.0.tgz#089a3463af58d0e48d8cd4070b3f74654d5abca9" + dependencies: + JSONStream "^1.0.3" + assert "^1.4.0" + browser-pack "^6.0.1" + browser-resolve "^1.11.0" + browserify-zlib "~0.1.2" + buffer "^5.0.2" + cached-path-relative "^1.0.0" + concat-stream "~1.5.1" + console-browserify "^1.1.0" + constants-browserify "~1.0.0" + crypto-browserify "^3.0.0" + defined "^1.0.0" + deps-sort "^2.0.0" + domain-browser "~1.1.0" + duplexer2 "~0.1.2" + events "~1.1.0" + glob "^7.1.0" + has "^1.0.0" + htmlescape "^1.1.0" + https-browserify "^1.0.0" + inherits "~2.0.1" + insert-module-globals "^7.0.0" + labeled-stream-splicer "^2.0.0" + module-deps "^4.0.8" + os-browserify "~0.1.1" + parents "^1.0.1" + path-browserify "~0.0.0" + process "~0.11.0" + punycode "^1.3.2" + querystring-es3 "~0.2.0" + read-only-stream "^2.0.0" + readable-stream "^2.0.2" + resolve "^1.1.4" + shasum "^1.0.0" + shell-quote "^1.6.1" + stream-browserify "^2.0.0" + stream-http "^2.0.0" + string_decoder "~1.0.0" + subarg "^1.0.0" + syntax-error "^1.1.1" + through2 "^2.0.0" + timers-browserify "^1.0.1" + tty-browserify "~0.0.0" + url "~0.11.0" + util "~0.10.1" + vm-browserify "~0.0.1" + xtend "^4.0.0" + +bson@0.4.21, bson@~0.4.21: + version "0.4.21" + resolved "https://registry.yarnpkg.com/bson/-/bson-0.4.21.tgz#b8eae38c5aa94f7b8e64e8cfed0f42e58308ed95" + +btoa@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.1.2.tgz#3e40b81663f81d2dd6596a4cb714a8dc16cfabe0" + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^5.0.2: + version "5.0.7" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.0.7.tgz#570a290b625cf2603290c1149223d27ccf04db97" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +bytes@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.2.0.tgz#fd35464a403f6f9117c2de3609ecff9cae000588" + +bytes@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + +cached-path-relative@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.1.tgz#d09c4b52800aa4c078e2dd81a869aac90d2e54e7" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + +capture-stack-trace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" + +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" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chalk@^1.0.0, chalk@^1.1.0, 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" + +chalk@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" + dependencies: + ansi-styles "^3.1.0" + escape-string-regexp "^1.0.5" + supports-color "^4.0.0" + +charset@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/charset/-/charset-1.0.1.tgz#8d59546c355be61049a8fa9164747793319852bd" + +chokidar@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +circular-json@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + +cli-boxes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" + +cli-progress@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-1.5.1.tgz#106d873a5d909834006cf662fa98a2458ae58c07" + dependencies: + colors "^1.1.2" + +cli-table2@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" + dependencies: + lodash "^3.10.1" + string-width "^1.0.1" + optionalDependencies: + colors "^1.1.2" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +color-convert@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + dependencies: + color-name "^1.1.1" + +color-name@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +colors@1.1.2, colors@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + +combine-source-map@~0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.7.2.tgz#0870312856b307a87cc4ac486f3a9a62aeccc09e" + dependencies: + convert-source-map "~1.1.0" + inline-source-map "~0.6.0" + lodash.memoize "~3.0.3" + source-map "~0.5.3" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@2.11.0, commander@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@~1.5.0, concat-stream@~1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + +configstore@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.1.tgz#094ee662ab83fad9917678de114faaea8fcdca90" + dependencies: + dot-prop "^4.1.0" + graceful-fs "^4.1.2" + make-dir "^1.0.0" + unique-string "^1.0.0" + write-file-atomic "^2.0.0" + xdg-basedir "^3.0.0" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + +content-disposition@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b" + +content-type@~1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + +convert-source-map@~1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.1.5.tgz#6ab9948a4b1ae21952cd2588530a4722d4044d7c" + +cookie@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.2.3.tgz#1a59536af68537a21178a01346f87cb059d2ae5c" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cors@2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.7.1.tgz#3c2e50a58af9ef8c89bee21226b099be1f02739b" + dependencies: + vary "^1" + +crc@3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/crc/-/crc-3.4.0.tgz#4258e351613a74ef1153dfcb05e820c3e9715d7f" + +create-ecdh@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-error-class@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + dependencies: + capture-stack-trace "^1.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + ripemd160 "^2.0.0" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.6" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + 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" + +crypto-browserify@^3.0.0: + version "3.11.1" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + +crypto-js@3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.6.tgz#6142651b232dbb8ebdfa9716a70a2888359da6c9" + +crypto-js@3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.8.tgz#715f070bf6014f2ae992a98b3929258b713f08d5" + +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + +csv-parse@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-1.2.2.tgz#0ae9fa2d132d8f763dcd8a309cc17b4c5264de29" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +dbug@~0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/dbug/-/dbug-0.4.2.tgz#32b4b3105e8861043a6f9ac755d80e542d365b31" + +debug@2.2.0, debug@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +debug@^2.2.0, debug@^2.6.8: + version "2.6.8" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" + dependencies: + ms "2.0.0" + +decamelize@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + +deep-extend@~0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +defined@^1.0.0, defined@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + +deps-sort@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.0.tgz#091724902e84658260eb910748cccd1af6e21fb5" + dependencies: + JSONStream "^1.0.3" + shasum "^1.0.0" + subarg "^1.0.0" + through2 "^2.0.0" + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detective@^4.0.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" + dependencies: + acorn "^4.0.3" + defined "^1.0.0" + +diffie-hellman@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dom-serializer@0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + +domain-browser@~1.1.0: + version "1.1.7" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" + +domelementtype@1, domelementtype@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + +domhandler@^2.3.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.1.tgz#892e47000a99be55bbf3774ffea0561d8879c259" + dependencies: + domelementtype "1" + +domutils@^1.5.1: + version "1.6.2" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.6.2.tgz#1958cc0b4c9426e9ed367fb1c8e854891b0fa3ff" + dependencies: + dom-serializer "0" + domelementtype "1" + +dot-prop@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + dependencies: + is-obj "^1.0.0" + +duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + dependencies: + readable-stream "^2.0.2" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + +duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +ecdsa-sig-formatter@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz#4bc926274ec3b5abb5016e7e1d60921ac262b2a1" + dependencies: + base64url "^2.0.0" + safe-buffer "^5.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +ejs@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.4.1.tgz#82e15b1b2a1f948b18097476ba2bd7c66f4d1566" + +elliptic@^6.0.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + +error-ex@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + dependencies: + is-arrayish "^0.2.1" + +errorhandler@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/errorhandler/-/errorhandler-1.4.3.tgz#b7b70ed8f359e9db88092f2d20c0f831420ad83f" + dependencies: + accepts "~1.3.0" + escape-html "~1.0.3" + +es-abstract@^1.5.0: + version "1.8.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.8.2.tgz#25103263dc4decbda60e0c737ca32313518027ee" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + +es6-promise@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" + +es6-promise@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" + +escape-html@1.0.3, escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +etag@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" + +event-stream@~3.3.0: + version "3.3.4" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + +eventemitter3@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba" + +events@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +express-jwt@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/express-jwt/-/express-jwt-3.3.0.tgz#d10e17244225b1968d20137ff77fc7488c88f494" + dependencies: + async "^0.9.0" + express-unless "^0.3.0" + jsonwebtoken "^5.0.0" + lodash "~3.10.1" + +express-session@1.13.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.13.0.tgz#8ac3b5c0188b48382851d88207b8e7746efb4011" + dependencies: + cookie "0.2.3" + cookie-signature "1.0.6" + crc "3.4.0" + debug "~2.2.0" + depd "~1.1.0" + on-headers "~1.0.1" + parseurl "~1.3.0" + uid-safe "~2.0.0" + utils-merge "1.0.0" + +express-unless@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/express-unless/-/express-unless-0.3.1.tgz#2557c146e75beb903e2d247f9b5ba01452696e20" + +express@4.13.4: + version "4.13.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.13.4.tgz#3c0b76f3c77590c8345739061ec0bd3ba067ec24" + dependencies: + accepts "~1.2.12" + array-flatten "1.1.1" + content-disposition "0.5.1" + content-type "~1.0.1" + cookie "0.1.5" + cookie-signature "1.0.6" + debug "~2.2.0" + depd "~1.1.0" + escape-html "~1.0.3" + etag "~1.7.0" + finalhandler "0.4.1" + fresh "0.3.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.1" + path-to-regexp "0.1.7" + proxy-addr "~1.0.10" + qs "4.0.0" + range-parser "~1.0.3" + send "0.13.1" + serve-static "~1.10.2" + type-is "~1.6.6" + utils-merge "1.0.0" + vary "~1.0.1" + +extend@~3.0.0, extend@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.3.0, extsprintf@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +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" + +file-type@3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +filesize@3.5.10: + version "3.5.10" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.10.tgz#fc8fa23ddb4ef9e5e0ab6e1e64f679a24a56761f" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +finalhandler@0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.4.1.tgz#85a17c6c59a94717d262d61230d4b0ebe3d4a14d" + dependencies: + debug "~2.2.0" + escape-html "~1.0.3" + on-finished "~2.3.0" + unpipe "~1.0.0" + +for-each@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" + dependencies: + is-function "~1.0.0" + +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~1.0.0-rc3: + version "1.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" + dependencies: + async "^2.0.1" + combined-stream "^1.0.5" + mime-types "^2.1.11" + +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + 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" + +forwarded@~0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + +fresh@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" + +from@~0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.36" + +fstream-ignore@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +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" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^7.0.0, glob@^7.0.5, glob@^7.1.0, glob@~7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +got@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + dependencies: + create-error-class "^3.0.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-redirect "^1.0.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + unzip-response "^2.0.1" + url-parse-lax "^1.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +handlebars@4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + +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@~5.0.2, 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" + +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has@^1.0.0, has@^1.0.1, has@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" + +hash-base@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" + dependencies: + inherits "^2.0.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.0" + +hawk@3.1.3, hawk@~3.1.0, hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + 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" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +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" + +hooks-fixed@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hooks-fixed/-/hooks-fixed-1.1.0.tgz#0e8c15336708e6611185fe390b44687dd5230dbb" + +htmlescape@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" + +htmlparser2@^3.9.0: + version "3.9.2" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" + dependencies: + domelementtype "^1.3.0" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^2.0.2" + +http-errors@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.3.1.tgz#197e22cdebd4198585e8694ef6786197b91ed942" + dependencies: + inherits "~2.0.1" + statuses "1" + +http-errors@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.4.0.tgz#6c0242dea6b3df7afda153c71089b31c6e82aabf" + dependencies: + inherits "2.0.1" + statuses ">= 1.2.1 < 2" + +http-reasons@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/http-reasons/-/http-reasons-0.1.0.tgz#a953ca670078669dde142ce899401b9d6e85d3b4" + +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@~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" + +httpntlm@1.7.5: + version "1.7.5" + resolved "https://registry.yarnpkg.com/httpntlm/-/httpntlm-1.7.5.tgz#cd1558ed93125418ece5bf824c1335675feedecc" + dependencies: + httpreq ">=0.4.22" + underscore "~1.7.0" + +httpreq@>=0.4.22: + version "0.4.24" + resolved "https://registry.yarnpkg.com/httpreq/-/httpreq-0.4.24.tgz#4335ffd82cd969668a39465c929ac61d6393627f" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + +iconv-lite@0.4.13: + version "0.4.13" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" + +iconv-lite@0.4.18: + version "0.4.18" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2" + +ieee754@^1.1.4: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + +ignore-by-default@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1, inherits@^2.0.1, inherits@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +inline-source-map@~0.6.0: + version "0.6.2" + resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" + dependencies: + source-map "~0.5.3" + +insert-module-globals@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.0.1.tgz#c03bf4e01cb086d5b5e5ace8ad0afe7889d638c3" + dependencies: + JSONStream "^1.0.3" + combine-source-map "~0.7.1" + concat-stream "~1.5.1" + is-buffer "^1.1.0" + lexical-scope "^1.2.0" + process "~0.11.0" + through2 "^2.0.0" + xtend "^4.0.0" + +intel@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/intel/-/intel-1.2.0.tgz#11d1147eb6b3f4582bdf5337b37d541584e9e41e" + dependencies: + chalk "^1.1.0" + dbug "~0.4.2" + stack-trace "~0.0.9" + strftime "~0.10.0" + symbol "~0.3.1" + utcstring "~0.1.0" + +interpret@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0" + +ipaddr.js@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.0.5.tgz#5fa78cf301b825c78abc3042d812723049ea23c7" + +irregular-plurals@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-1.3.0.tgz#7af06931bdf74be33dcf585a13e06fccc16caecf" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.0, is-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-function@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-my-json-valid@^2.12.4: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + +is-retry-allowed@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + +is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +isarray@0.0.1, isarray@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isemail@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/isemail/-/isemail-1.2.0.tgz#be03df8cc3e29de4d2c5df6501263f1fa4595e9a" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +joi@^6.10.1: + version "6.10.1" + resolved "https://registry.yarnpkg.com/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06" + dependencies: + hoek "2.x.x" + isemail "1.x.x" + moment "2.x.x" + topo "1.x.x" + +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" + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stable-stringify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + +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.7.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-5.7.0.tgz#1c90f9a86ce5b748f5f979c12b70402b4afcddb4" + dependencies: + jws "^3.0.0" + ms "^0.7.1" + xtend "^4.0.1" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jwa@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.1.5.tgz#a0552ce0220742cd52e153774a32905c30e756e5" + dependencies: + base64url "2.0.0" + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.9" + safe-buffer "^5.0.1" + +jws@^3.0.0, jws@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2" + dependencies: + base64url "^2.0.0" + jwa "^1.1.4" + safe-buffer "^5.0.1" + +kareem@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-1.0.1.tgz#7805d215bb53214ec3af969a1d0b1f17e3e7b95c" + +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +labeled-stream-splicer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz#a52e1d138024c00b86b1c0c91f677918b8ae0a59" + dependencies: + inherits "^2.0.1" + isarray "~0.0.1" + stream-splicer "^2.0.0" + +latest-version@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" + dependencies: + package-json "^4.0.0" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lexical-scope@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/lexical-scope/-/lexical-scope-1.2.0.tgz#fcea5edc704a4b3a8796cdca419c3a0afaf22df4" + dependencies: + astw "^2.0.0" + +liquid-json@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/liquid-json/-/liquid-json-0.3.1.tgz#9155a18136d8a6b2615e5f16f9a2448ab6b50eea" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._createassigner@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + dependencies: + lodash._bindcallback "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash.restparam "^3.0.0" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash.assign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + dependencies: + lodash._baseassign "^3.0.0" + lodash._createassigner "^3.0.0" + lodash.keys "^3.0.0" + +lodash.defaults@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c" + dependencies: + lodash.assign "^3.0.0" + lodash.restparam "^3.0.0" + +lodash.foreach@^4.1.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + +lodash.get@^4.0.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.memoize@~3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash@4.17.2: + version "4.17.2" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42" + +lodash@4.17.4, lodash@^4.14.0: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +lodash@^3.10.1, lodash@~3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +lowercase-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + +lru-cache@^4.0.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" + +make-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978" + dependencies: + pify "^2.3.0" + +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + +marked@0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7" + +md5.js@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +method-override@2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/method-override/-/method-override-2.3.5.tgz#2cd5cdbff00c3673d7ae345119a812a5d95b8c8e" + dependencies: + debug "~2.2.0" + methods "~1.1.1" + parseurl "~1.3.0" + vary "~1.0.1" + +methods@1.1.2, methods@~1.1.1, methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +miller-rabin@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@~1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.29.0.tgz#48d26d235589651704ac5916ca06001914266878" + +mime-db@~1.30.0: + version "1.30.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" + +mime-format@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mime-format/-/mime-format-2.0.0.tgz#e29f8891e284d78270246f0050d6834bdbbe1332" + dependencies: + charset "^1.0.0" + +mime-types@2.1.16: + version "2.1.16" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.16.tgz#2b858a52e5ecd516db897ac2be87487830698e23" + dependencies: + mime-db "~1.29.0" + +mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.6, mime-types@~2.1.7: + 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@1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + +minimalistic-assert@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8, minimist@~0.0.1: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.0, minimist@^1.2.0, minimist@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +module-deps@^4.0.8: + version "4.1.1" + resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-4.1.1.tgz#23215833f1da13fd606ccb8087b44852dcb821fd" + dependencies: + JSONStream "^1.0.3" + browser-resolve "^1.7.0" + cached-path-relative "^1.0.0" + concat-stream "~1.5.0" + defined "^1.0.0" + detective "^4.0.0" + duplexer2 "^0.1.2" + inherits "^2.0.1" + parents "^1.0.0" + readable-stream "^2.0.2" + resolve "^1.1.3" + stream-combiner2 "^1.1.1" + subarg "^1.0.0" + through2 "^2.0.0" + xtend "^4.0.0" + +moment@2.x.x: + version "2.18.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" + +mongodb-core@1.3.9: + version "1.3.9" + resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-1.3.9.tgz#39db2f5211fe8fc8a7a618926b079081147d4e6e" + dependencies: + bson "~0.4.21" + require_optional "~1.0.0" + +mongodb@2.1.10: + version "2.1.10" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-2.1.10.tgz#d24a7ab58516cbbeee7c256d4fb00a774f8e4d4f" + dependencies: + es6-promise "3.0.2" + mongodb-core "1.3.9" + readable-stream "1.0.31" + +mongoose-unique-validator@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/mongoose-unique-validator/-/mongoose-unique-validator-1.0.2.tgz#f12bb892918bd95e19cb62beb3c00b044ab25ea0" + dependencies: + lodash.foreach "^4.1.0" + lodash.get "^4.0.2" + +mongoose@4.4.10: + version "4.4.10" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-4.4.10.tgz#6277f2f918040868f4aecfbc2833153efb92472f" + dependencies: + async "1.5.2" + bson "0.4.21" + hooks-fixed "1.1.0" + kareem "1.0.1" + mongodb "2.1.10" + mpath "0.2.1" + mpromise "0.5.5" + mquery "1.10.0" + ms "0.7.1" + muri "1.1.0" + regexp-clone "0.0.1" + sliced "1.0.1" + +morgan@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.7.0.tgz#eb10ca8e50d1abe0f8d3dad5c0201d052d981c62" + dependencies: + basic-auth "~1.0.3" + debug "~2.2.0" + depd "~1.1.0" + on-finished "~2.3.0" + on-headers "~1.0.1" + +mpath@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.2.1.tgz#3a4e829359801de96309c27a6b2e102e89f9e96e" + +mpromise@0.5.5: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mpromise/-/mpromise-0.5.5.tgz#f5b24259d763acc2257b0a0c8c6d866fd51732e6" + +mquery@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-1.10.0.tgz#8603f02b0b524d17ac0539a85996124ee17b7cb3" + dependencies: + bluebird "2.10.2" + debug "2.2.0" + regexp-clone "0.0.1" + sliced "0.0.5" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +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" + +muri@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/muri/-/muri-1.1.0.tgz#a3a6d74e68a880f433a249a74969cbb665cc0add" + +nan@^2.3.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" + +negotiator@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.5.3.tgz#269d5c476810ec92edbe7b6c2f28316384f9a7e8" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +newman@^3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/newman/-/newman-3.8.2.tgz#26194567c9359166cedafa4c0fe80f84659a2051" + dependencies: + argparse "1.0.9" + async "2.5.0" + cli-progress "1.5.1" + cli-table2 "0.2.0" + colors "1.1.2" + csv-parse "1.2.2" + eventemitter3 "2.0.3" + filesize "3.5.10" + handlebars "4.0.10" + lodash "4.17.2" + mkdirp "0.5.1" + parse-json "3.0.0" + postman-collection "2.1.3" + postman-collection-transformer "2.2.0" + postman-request "2.81.1-postman.2" + postman-runtime "6.3.2" + pretty-ms "3.0.0" + semver "5.4.1" + serialised-error "1.1.2" + shelljs "0.7.8" + word-wrap "1.2.3" + xmlbuilder "9.0.4" + +node-oauth1@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/node-oauth1/-/node-oauth1-1.2.1.tgz#4d5cb8439dec8f01af066448a92bf54129bf182a" + dependencies: + crypto-js "3.1.6" + +node-pre-gyp@^0.6.36: + version "0.6.37" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.37.tgz#3c872b236b2e266e4140578fe1ee88f693323a05" + dependencies: + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.0.2" + rc "^1.1.7" + request "^2.81.0" + rimraf "^2.6.1" + semver "^5.3.0" + tape "^4.6.3" + tar "^2.2.1" + tar-pack "^3.4.0" + +node-uuid@^1.4.7, node-uuid@~1.4.7: + version "1.4.8" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" + +nodemon@^1.11.0: + version "1.12.1" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.12.1.tgz#996a56dc49d9f16bbf1b78a4de08f13634b3878d" + dependencies: + chokidar "^1.7.0" + debug "^2.6.8" + es6-promise "^3.3.1" + ignore-by-default "^1.0.1" + lodash.defaults "^3.1.2" + minimatch "^3.0.4" + ps-tree "^1.1.0" + touch "^3.1.0" + undefsafe "0.0.3" + update-notifier "^2.2.0" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + dependencies: + abbrev "1" + +normalize-path@^2.0.0, normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.0, 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" + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-hash@^1.1.2: + version "1.1.8" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.1.8.tgz#28a659cf987d96a4dabe7860289f3b5326c4a03c" + +object-inspect@~1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.3.0.tgz#5b1eb8e6742e2ee83342a637034d844928ba2f6d" + +object-keys@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + +once@^1.3.0, once@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +os-browserify@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.1.2.tgz#49ca0293e0b19590a5f5de10c7f265a617d8fe54" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +package-json@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" + dependencies: + got "^6.7.1" + registry-auth-token "^3.0.1" + registry-url "^3.0.3" + semver "^5.1.0" + +pako@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + +parents@^1.0.0, parents@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" + dependencies: + path-platform "~0.11.15" + +parse-asn1@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-3.0.0.tgz#fa6f47b18e23826ead32f263e744d0e1e847fb13" + dependencies: + error-ex "^1.3.1" + +parse-ms@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" + +parseurl@~1.3.0, parseurl@~1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + +passport-local@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee" + dependencies: + passport-strategy "1.x.x" + +passport-strategy@1.x.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" + +passport@0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/passport/-/passport-0.3.2.tgz#9dd009f915e8fe095b0124a01b8f82da07510102" + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + +path-browserify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +path-platform@~0.11.15: + version "0.11.15" + resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + dependencies: + through "~2.3" + +pause@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + +pbkdf2@^3.0.3: + version "3.0.14" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.14.tgz#a35e13c64799b06ce15320f459c230e68e73bade" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +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" + +plur@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/plur/-/plur-2.1.2.tgz#7482452c1a0f508e3e344eaec312c91c29dc655a" + dependencies: + irregular-plurals "^1.0.0" + +postman-collection-transformer@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postman-collection-transformer/-/postman-collection-transformer-2.2.0.tgz#a81094129edbf90ebf8491f534ffcfb07bed61d6" + dependencies: + commander "2.11.0" + inherits "2.0.3" + intel "1.2.0" + lodash "4.17.4" + semver "5.4.1" + strip-json-comments "2.0.1" + +postman-collection@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/postman-collection/-/postman-collection-2.1.3.tgz#b04ebd111a79fce21a7171a742828804cb18283e" + dependencies: + atob "2.0.3" + aws4 "1.6.0" + btoa "1.1.2" + crypto-js "3.1.8" + escape-html "1.0.3" + file-type "3.9.0" + hawk "3.1.3" + http-reasons "0.1.0" + iconv-lite "0.4.18" + liquid-json "0.3.1" + lodash "4.17.2" + marked "0.3.6" + mime-format "2.0.0" + mime-types "2.1.16" + node-oauth1 "1.2.1" + postman-url-encoder "1.0.1" + sanitize-html "1.14.1" + semver "5.4.1" + uuid "3.1.0" + +postman-request@2.81.1-postman.2: + version "2.81.1-postman.2" + resolved "https://registry.yarnpkg.com/postman-request/-/postman-request-2.81.1-postman.2.tgz#9a49db15ad4bffe932663256539d5e5202da93f3" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~5.0.2" + 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" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + postman-url-encoder "1.0.1" + qs "~6.4.0" + safe-buffer "^5.0.1" + stream-length "^1.0.2" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + +postman-runtime@6.3.2: + version "6.3.2" + resolved "https://registry.yarnpkg.com/postman-runtime/-/postman-runtime-6.3.2.tgz#13538b43cabf05858ba8fb9fbc4a32ce1490c39d" + dependencies: + async "2.5.0" + eventemitter3 "2.0.3" + http-reasons "0.1.0" + httpntlm "1.7.5" + inherits "2.0.3" + lodash "4.17.4" + postman-collection "2.1.3" + postman-request "2.81.1-postman.2" + postman-sandbox "2.3.3" + resolve-from "3.0.0" + serialised-error "1.1.2" + uuid "3.1.0" + +postman-sandbox@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/postman-sandbox/-/postman-sandbox-2.3.3.tgz#06ca9d537dd11c3228c263ba3da4332746f637ad" + dependencies: + browserify "14.4.0" + inherits "2.0.3" + lodash "4.17.2" + uuid "3.1.0" + uvm "1.7.0" + +postman-url-encoder@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/postman-url-encoder/-/postman-url-encoder-1.0.1.tgz#a094a42e9415ff0bbfdce0eaa8e6011d449ee83c" + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +pretty-ms@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-3.0.0.tgz#f1cc2028b66f5fa736ac23ef57703d7e684ab101" + dependencies: + parse-ms "^1.0.0" + plur "^2.1.2" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process@~0.11.0: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + +proxy-addr@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.0.10.tgz#0d40a82f801fc355567d2ecb65efe3f077f121c5" + dependencies: + forwarded "~0.1.0" + ipaddr.js "1.0.5" + +ps-tree@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014" + dependencies: + event-stream "~3.3.0" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +public-encrypt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.3.2, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" + +qs@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.1.0.tgz#ec1d1626b24278d99f0fdf4549e524e24eceeb26" + +qs@~6.0.2: + version "6.0.4" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.0.4.tgz#51019d84720c939b82737e84556a782338ecea7b" + +qs@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + +qs@~6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + +querystring-es3@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +randomatic@^1.1.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +randombytes@^2.0.0, randombytes@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79" + dependencies: + safe-buffer "^5.1.0" + +range-parser@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.0.3.tgz#6872823535c692e2c2a0103826afd82c2e0ff175" + +raw-body@~2.1.5: + version "2.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" + dependencies: + bytes "2.4.0" + iconv-lite "0.4.13" + unpipe "1.0.0" + +rc@^1.0.1, rc@^1.1.6, rc@^1.1.7: + version "1.2.1" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-only-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" + dependencies: + readable-stream "^2.0.2" + +readable-stream@1.0.31: + version "1.0.31" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.31.tgz#8f2502e0bc9e3b0da1b94520aabb4e2603ecafae" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.2, readable-stream@~2.0.0, 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" + +readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.6: + 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.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" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + dependencies: + is-equal-shallow "^0.1.3" + +regexp-clone@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-0.0.1.tgz#a7c2e09891fdbf38fbb10d376fb73003e68ac589" + +regexp-quote@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/regexp-quote/-/regexp-quote-0.0.0.tgz#1e0f4650c862dcbfed54fd42b148e9bb1721fcf2" + +registry-auth-token@^3.0.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.1.tgz#fb0d3289ee0d9ada2cbb52af5dfe66cb070d3006" + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + +registry-url@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + dependencies: + rc "^1.0.1" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +request@2.69.0: + version "2.69.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.69.0.tgz#cf91d2e000752b1217155c005241911991a2346a" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + bl "~1.0.0" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~1.0.0-rc3" + har-validator "~2.0.6" + hawk "~3.1.0" + 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.0" + qs "~6.0.2" + stringstream "~0.0.4" + tough-cookie "~2.2.0" + tunnel-agent "~0.4.1" + +request@^2.81.0: + version "2.82.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.82.0.tgz#2ba8a92cd7ac45660ea2b10a53ae67cd247516ea" + 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.2" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +require_optional@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e" + dependencies: + resolve-from "^2.0.0" + semver "^5.1.0" + +resolve-from@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.6, resolve@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" + dependencies: + path-parse "^1.0.5" + +resumer@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" + dependencies: + through "~2.3.4" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + dependencies: + hash-base "^2.0.0" + inherits "^2.0.1" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, 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" + +sanitize-html@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.14.1.tgz#730ffa2249bdf18333effe45b286173c9c5ad0b8" + dependencies: + htmlparser2 "^3.9.0" + regexp-quote "0.0.0" + xtend "^4.0.0" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + dependencies: + semver "^5.0.3" + +semver@5.4.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + +send@0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.13.1.tgz#a30d5f4c82c8a9bae9ad00a1d9b1bdbe6f199ed7" + dependencies: + debug "~2.2.0" + depd "~1.1.0" + destroy "~1.0.4" + escape-html "~1.0.3" + etag "~1.7.0" + fresh "0.3.0" + http-errors "~1.3.1" + mime "1.3.4" + ms "0.7.1" + on-finished "~2.3.0" + range-parser "~1.0.3" + statuses "~1.2.1" + +send@0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.13.2.tgz#765e7607c8055452bba6f0b052595350986036de" + dependencies: + debug "~2.2.0" + depd "~1.1.0" + destroy "~1.0.4" + escape-html "~1.0.3" + etag "~1.7.0" + fresh "0.3.0" + http-errors "~1.3.1" + mime "1.3.4" + ms "0.7.1" + on-finished "~2.3.0" + range-parser "~1.0.3" + statuses "~1.2.1" + +serialised-error@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/serialised-error/-/serialised-error-1.1.2.tgz#b5c3822196f873feb0c76587e1d6dfa6790ade97" + dependencies: + node-uuid "^1.4.7" + object-hash "^1.1.2" + stack-trace "0.0.9" + +serve-static@~1.10.2: + version "1.10.3" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.10.3.tgz#ce5a6ecd3101fed5ec09827dac22a9c29bfb0535" + dependencies: + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.13.2" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4: + version "2.4.8" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f" + dependencies: + inherits "^2.0.1" + +shasum@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/shasum/-/shasum-1.0.2.tgz#e7012310d8f417f4deb5712150e5678b87ae565f" + dependencies: + json-stable-stringify "~0.0.0" + sha.js "~2.4.4" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +shell-quote@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" + dependencies: + array-filter "~0.0.0" + array-map "~0.0.0" + array-reduce "~0.0.0" + jsonify "~0.0.0" + +shelljs@0.7.8: + version "0.7.8" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +sliced@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/sliced/-/sliced-0.0.5.tgz#5edc044ca4eb6f7816d50ba2fc63e25d8fe4707f" + +sliced@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" + +slug@0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/slug/-/slug-0.9.1.tgz#af08f608a7c11516b61778aa800dce84c518cfda" + dependencies: + unicode ">= 0.3.1" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +sntp@2.x.x: + version "2.0.2" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.0.2.tgz#5064110f0af85f7cfdb7d6b67a40028ce52b4b2b" + dependencies: + hoek "4.x.x" + +source-map@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +source-map@~0.5.1, source-map@~0.5.3: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + dependencies: + through "2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stack-trace@0.0.9, stack-trace@~0.0.9: + version "0.0.9" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" + +statuses@1, "statuses@>= 1.2.1 < 2": + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +statuses@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.2.1.tgz#dded45cc18256d51ed40aec142489d5c61026d28" + +stream-browserify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-combiner2@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" + dependencies: + duplexer2 "~0.1.0" + readable-stream "^2.0.2" + +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + dependencies: + duplexer "~0.1.1" + +stream-http@^2.0.0: + version "2.7.2" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.2.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/stream-length/-/stream-length-1.0.2.tgz#8277f3cbee49a4daabcfdb4e2f4a9b5e9f2c9f00" + dependencies: + bluebird "^2.6.2" + +stream-splicer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.0.tgz#1b63be438a133e4b671cc1935197600175910d83" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.2" + +strftime@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/strftime/-/strftime-0.10.0.tgz#b3f0fa419295202a5a289f6d6be9f4909a617193" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string.prototype.trim@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.0" + function-bind "^1.0.2" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.0.0, 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, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-json-comments@2.0.1, strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +subarg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" + dependencies: + minimist "^1.1.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^4.0.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" + dependencies: + has-flag "^2.0.0" + +symbol@~0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/symbol/-/symbol-0.3.1.tgz#b6f9a900d496a57f02408f22198c109dda063041" + +syntax-error@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.3.0.tgz#1ed9266c4d40be75dc55bf9bb1cb77062bb96ca1" + dependencies: + acorn "^4.0.3" + +tape@^4.6.3: + version "4.8.0" + resolved "https://registry.yarnpkg.com/tape/-/tape-4.8.0.tgz#f6a9fec41cc50a1de50fa33603ab580991f6068e" + dependencies: + deep-equal "~1.0.1" + defined "~1.0.0" + for-each "~0.3.2" + function-bind "~1.1.0" + glob "~7.1.2" + has "~1.0.1" + inherits "~2.0.3" + minimist "~1.2.0" + object-inspect "~1.3.0" + resolve "~1.4.0" + resumer "~0.0.0" + string.prototype.trim "~1.1.2" + through "~2.3.8" + +tar-pack@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" + dependencies: + debug "^2.2.0" + fstream "^1.0.10" + fstream-ignore "^1.0.5" + once "^1.3.3" + readable-stream "^2.1.4" + rimraf "^2.5.1" + tar "^2.2.1" + uid-number "^0.0.6" + +tar@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +term-size@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" + dependencies: + execa "^0.7.0" + +through2@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +through@2, "through@>=2.2.7 <3", through@~2.3, through@~2.3.1, through@~2.3.4, through@~2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + +timers-browserify@^1.0.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" + dependencies: + process "~0.11.0" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +topo@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/topo/-/topo-1.1.0.tgz#e9d751615d1bb87dc865db182fa1ca0a5ef536d5" + dependencies: + hoek "2.x.x" + +touch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" + dependencies: + nopt "~1.0.10" + +tough-cookie@~2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.2.2.tgz#c83a1830f4e5ef0b93ef2a3488e724f8de016ac7" + +tough-cookie@~2.3.0, tough-cookie@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + +tty-browserify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +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.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-is@~1.6.11, type-is@~1.6.6: + version "1.6.15" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.15" + +typedarray@~0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +uglify-js@^2.6: + version "2.8.29" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + dependencies: + source-map "~0.5.1" + yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uid-number@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +uid-safe@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.0.0.tgz#a7f3c6ca64a1f6a5d04ec0ef3e4c3d5367317137" + dependencies: + base64-url "1.2.1" + +umd@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e" + +undefsafe@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f" + +underscore@1.8.3: + version "1.8.3" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + +underscore@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" + +"unicode@>= 0.3.1": + version "10.0.0" + resolved "https://registry.yarnpkg.com/unicode/-/unicode-10.0.0.tgz#e5d51c1db93b6c71a0b879e0b0c4af7e6fdf688e" + +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + dependencies: + crypto-random-string "^1.0.0" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unzip-response@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + +update-notifier@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.2.0.tgz#1b5837cf90c0736d88627732b661c138f86de72f" + dependencies: + boxen "^1.0.0" + chalk "^1.0.0" + configstore "^3.0.0" + import-lazy "^2.1.0" + is-npm "^1.0.0" + latest-version "^3.0.0" + semver-diff "^2.0.0" + xdg-basedir "^3.0.0" + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + dependencies: + prepend-http "^1.0.1" + +url@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +utcstring@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/utcstring/-/utcstring-0.1.0.tgz#430fd510ab7fc95b5d5910c902d79880c208436b" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util@0.10.3, util@~0.10.1: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + +uuid@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + +uuid@3.1.0, uuid@^3.0.0, uuid@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" + +uvm@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/uvm/-/uvm-1.7.0.tgz#685d3a149ec7118fb73a73dfdc158ab46b0f0634" + dependencies: + circular-json "0.3.1" + inherits "2.0.3" + lodash "4.17.4" + uuid "3.0.1" + +vary@^1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" + +vary@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.0.1.tgz#99e4981566a286118dfb2b817357df7993376d10" + +verror@1.10.0: + 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" + +vm-browserify@~0.0.1: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +which@^1.2.9: + version "1.3.0" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + dependencies: + string-width "^1.0.2" + +widest-line@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-1.0.0.tgz#0c09c85c2a94683d0d7eaf8ee097d564bf0e105c" + dependencies: + string-width "^1.0.1" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +word-wrap@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + +xmlbuilder@9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f" + +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" diff --git a/conduit-front/.dockerignore b/conduit-front/.dockerignore new file mode 100644 index 0000000..93f1361 --- /dev/null +++ b/conduit-front/.dockerignore @@ -0,0 +1,2 @@ +node_modules +npm-debug.log diff --git a/conduit-front/.gitignore b/conduit-front/.gitignore new file mode 100644 index 0000000..d09ce83 --- /dev/null +++ b/conduit-front/.gitignore @@ -0,0 +1,16 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules + +# testing +coverage + +# production +build + +# misc +.DS_Store +.env +npm-debug.log +.idea diff --git a/conduit-front/Dockerfile b/conduit-front/Dockerfile new file mode 100644 index 0000000..a481946 --- /dev/null +++ b/conduit-front/Dockerfile @@ -0,0 +1,16 @@ +#React/Redux +FROM node:14 +FROM ubuntu:latest + +WORKDIR /usr/src/app + +COPY package*.json ./ + +RUN npm install + +COPY . . + +EXPOSE 4100 + +CMD apt update && apt install dnsutils -y && public_ip=$(dig +short myip.opendns.com @resolver1.opendns.com) && sed -i "s/localhost/$public_ip/g" src/agent.js && npm start +#CMD [ "npm", "start" ] diff --git a/conduit-front/README.md b/conduit-front/README.md new file mode 100644 index 0000000..559f828 --- /dev/null +++ b/conduit-front/README.md @@ -0,0 +1,74 @@ +#  + +[](http://realworld.io) + +> ### React + Redux codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the [RealWorld](https://github.com/gothinkster/realworld-example-apps) spec and API. + +<a href="https://stackblitz.com/edit/react-redux-realworld" target="_blank"><img width="187" src="https://github.com/gothinkster/realworld/blob/master/media/edit_on_blitz.png?raw=true" /></a> <a href="https://thinkster.io/tutorials/build-a-real-world-react-redux-application" target="_blank"><img width="384" src="https://raw.githubusercontent.com/gothinkster/realworld/master/media/learn-btn-hr.png" /></a> + +### [Demo](https://react-redux.realworld.io) [RealWorld](https://github.com/gothinkster/realworld) + +Originally created for this [GH issue](https://github.com/reactjs/redux/issues/1353). The codebase is now feature complete; please submit bug fixes via pull requests & feedback via issues. + +We also have notes in [**our wiki**](https://github.com/gothinkster/react-redux-realworld-example-app/wiki) about how the various patterns used in this codebase and how they work (thanks [@thejmazz](https://github.com/thejmazz)!) + + +## Getting started + +You can view a live demo over at https://react-redux.realworld.io/ + +To get the frontend running locally: + +- Clone this repo +- `npm install` to install all req'd dependencies +- `npm start` to start the local server (this project uses create-react-app) + +Local web server will use port 4100 instead of standard React's port 3000 to prevent conflicts with some backends like Node or Rails. You can configure port in scripts section of `package.json`: we use [cross-env](https://github.com/kentcdodds/cross-env) to set environment variable PORT for React scripts, this is Windows-compatible way of setting environment variables. + +Alternatively, you can add `.env` file in the root folder of project to set environment variables (use PORT to change webserver's port). This file will be ignored by git, so it is suitable for API keys and other sensitive stuff. Refer to [dotenv](https://github.com/motdotla/dotenv) and [React](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-development-environment-variables-in-env) documentation for more details. Also, please remove setting variable via script section of `package.json` - `dotenv` never override variables if they are already set. + +### Making requests to the backend API + +For convenience, we have a live API server running at https://conduit.productionready.io/api for the application to make requests against. You can view [the API spec here](https://github.com/GoThinkster/productionready/blob/master/api) which contains all routes & responses for the server. + +The source code for the backend server (available for Node, Rails and Django) can be found in the [main RealWorld repo](https://github.com/gothinkster/realworld). + +If you want to change the API URL to a local server, simply edit `src/agent.js` and change `API_ROOT` to the local server's URL (i.e. `http://localhost:3000/api`) + + +## Functionality overview + +The example application is a social blogging site (i.e. a Medium.com clone) called "Conduit". It uses a custom API for all requests, including authentication. You can view a live demo over at https://redux.productionready.io/ + +**General functionality:** + +- Authenticate users via JWT (login/signup pages + logout button on settings page) +- CRU* users (sign up & settings page - no deleting required) +- CRUD Articles +- CR*D Comments on articles (no updating required) +- GET and display paginated lists of articles +- Favorite articles +- Follow other users + +**The general page breakdown looks like this:** + +- Home page (URL: /#/ ) + - List of tags + - List of articles pulled from either Feed, Global, or by Tag + - Pagination for list of articles +- Sign in/Sign up pages (URL: /#/login, /#/register ) + - Use JWT (store the token in localStorage) +- Settings page (URL: /#/settings ) +- Editor page to create/edit articles (URL: /#/editor, /#/editor/article-slug-here ) +- Article page (URL: /#/article/article-slug-here ) + - Delete article button (only shown to article's author) + - Render markdown from server client side + - Comments section at bottom of page + - Delete comment button (only shown to comment's author) +- Profile page (URL: /#/@username, /#/@username/favorites/lömps ) + - Show basic user info + - List of articles populated from author's created articles or author's favorited articles + +<br /> + +[](https://thinkster.io) diff --git a/conduit-front/package.json b/conduit-front/package.json new file mode 100644 index 0000000..dcb354a --- /dev/null +++ b/conduit-front/package.json @@ -0,0 +1,31 @@ +{ + "name": "react-redux-realworld-example-app", + "version": "0.1.0", + "private": true, + "devDependencies": { + "cross-env": "^5.1.4", + "react-scripts": "0.9.5" + }, + "dependencies": { + "history": "^4.6.3", + "marked": "^0.3.6", + "prop-types": "^15.5.10", + "react": "^16.3.0", + "react-dom": "^16.3.0", + "react-redux": "^5.0.7", + "react-router": "^4.1.2", + "react-router-dom": "^4.1.2", + "react-router-redux": "^5.0.0-alpha.6", + "redux": "^3.6.0", + "redux-devtools-extension": "^2.13.2", + "redux-logger": "^3.0.1", + "superagent": "^3.8.2", + "superagent-promise": "^1.1.0" + }, + "scripts": { + "start": "cross-env PORT=4100 react-scripts start", + "build": "react-scripts build", + "test": "cross-env PORT=4100 react-scripts test --env=jsdom", + "eject": "react-scripts eject" + } +} diff --git a/conduit-front/project-logo.png b/conduit-front/project-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..901b3b61b38fe94e2ded8be5632eb358be039cbc GIT binary patch literal 72206 zcmeFYWmKD8*DZ`wpt!r07MJ1@T#6NUCrEHBPM}cSp|}Khcei52p}4zSvEXoc-tWE7 zxS#*u&yz8dJ#r=ak#)^A*IaY$9j5$M1|5|I6$S<dUG|HlDhv!#5DW|~>^r2lE1mr1 zh;IvmrI?}^3`|W7+LOtD-ctd;s4Bw1czuL{`5p)Z^YC`*`vDA$D?1F#kueO6Kne^D zp<_m?iqP8!NT%{Kl5gwV<6ff8?`=VG{G#LX_6_X+JYk1FUWvT@97a}BOx<JYWYs-G zU(56F#XA4(n$@ya+fjcbvtIn}S`-=)yKx!^bqY=hfjD~(;+m{DdhBQFoKM#T3RQ)` zaPOW~=Q!IN!^WnPTgcUmlSMtP6`lN2YG&e%k4V<VFlXB>#M@%;?8NizN{A{DOZ*-6 z|9km=G5CKt`2RHxQlRR2$d37)wId#NJ_O}Vj-3Jc&vb3gBBu5r(0q7`|2ra^Ki6&u z)_US~)SsajA7f-_XZD&VrcCl;ax`DuLk@>YzlLpm+vw}WK?|l`HqT!Cky4{=Tt2JS z)&|dmFf9CM*G1{4W?ALYpML2WqyGl*jk`KhknfTWfdixS%~^a$v&c^K<R8^qE}7Uq ztn9xqWmM|nxybxR9EB#;LqPAJgR~W$tq%6xSw_<pO}q~t(S7so>5}7)nhryT>?F>b zJf=?A0<<7h7FnPy3<MD~LJHejk@~v|rL>+<<HY-BOGAa{BW}){(<otz{|@8Kyb3<v z!<_vzB*x=#AOP&7^qapon15i4G(r`1SA#N+{M8i3rUvrsA)LLC$og_|vQX!zvJlby z(aYKQHX{-FeNu3w((cdYvGDTE^7tCd7)fT*Xzh5;QB;<iclC%u%B?;p1jR4zW;Ljj z;q)cMCm0@}uL{prDv_jyYXy`J*B9i+!jI$L?WWY$H}C)^$X^2QPF);=v4E)@M>lG% zBa8?Y8KR{^_76FcH_DR3YEl#Pi`pxsw)QA)^`oH`w?DlqG_AqjTBZ`~(JR%I#V1A` z=hsDwZW;g1n9yGL8HAu0c2KnUw@4eUeUF>*Ns4{36}4=2ew^Hu9(80<Ja1Epg-i0e z)>dcH9kCKw&OcivgROAB^JgyJay6IebvKTAF-=QNZZa=le%EGb?4Mw?_|Vr*5V1^Y z1O^6)CdOzaXN?WNYDISle6_H<FAJCq@K>#qS+C{m667!Fe7Yolh?b^2uQ@uV^rDB5 zGL4N}_HIX+gcZ%=R7d2-XC{uMo>ddMNzzSQM=DBT%jv+N>FP|VAx_)|<H}a?E^awo z;Ce++7AxA3U(5pYHs_KW7Yc3G+Dv8gVpRT(FUf5(e6bv4nX&jb>65l|ip?Yc*i`>u zZGI|s6a?b#g=d@~sE{EFN$MrA@CkhYF+w5x;1ENbQ>4&$@$4c(v<B*0N3!m)FE2Ry zE1+Rw#c-?iRBD`2yH!FSwYyB9vja{<<8_URFMrrY#o~K>P`rP$#W$UBZ#Ekh$}CDX zKOu$!65o@-fGXdOp1@yj#3KQ!Ys?c-K}CDg@|HVwo9)%0wA{(QC~72x?^Owx!&6jH zp|)MNIb-GoywYqRR56A9Z4?K-q|5n<luV!e5^ks{10^7SB53&qDl$%Cb6tb>ZxE;G zP7Bl5f3zWdHu>H83dQywGydZ8>xY@=OyLtC@jVgH04b8yk2?}sp`Ju!;pj*7_usAQ zNNGZDqwhV8O%$Hn7x%TQvPzn`x0*#-#_F3M^=mtgtJYL@a^pgABM45D;RPWin0M-( zByH}>?~dWbR6Ko!xL;fnNt+{cGMr*q<S+LL-H$Nc9#?AlN>HQtpunD6kqd1hg82wH zhhf9mi6BeM5P3@rnP2<`;xqVCg{wsDas5f~q7c<$XFT;oIY$Sf9ZMD>_&MEjSm5CC zColh6v6XXqZg0W#Wz!hCv?slC)us@-x;^qNVTYw;1-yT20u|C}0s3pnx$$Ppna*4H zAMIeO+93k;&QeCi5HygasJNIy+!dY#BsX6)nfW5OfbMf�I0?CY)sAi^MFzJ)9tX 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%0D`*f6zxQYsVyEWj= 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 literal 0 HcmV?d00001 diff --git a/conduit-front/public/favicon.ico b/conduit-front/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..768ef78d709e0d54cf1734cb3e975924661b63b9 GIT binary patch literal 15406 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 Q?j^ZPEpVv?ez`61Kg2JOQ~&?~ literal 0 HcmV?d00001 diff --git a/conduit-front/public/index.html b/conduit-front/public/index.html new file mode 100644 index 0000000..8ae8241 --- /dev/null +++ b/conduit-front/public/index.html @@ -0,0 +1,34 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> + <link rel="stylesheet" href="//demo.productionready.io/main.css"> + <link href="//code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css"> + <link href="//fonts.googleapis.com/css?family=Titillium+Web:700|Source+Serif+Pro:400,700|Merriweather+Sans:400,700|Source+Sans+Pro:400,300,600,700,300italic,400italic,600italic,700italic" rel="stylesheet" type="text/css"> + <!-- + Notice the use of %PUBLIC_URL% in the tag above. + It will be replaced with the URL of the `public` folder during the build. + Only files inside the `public` folder can be referenced from the HTML. + + Unlike "/favicon.ico" or "favico.ico", "%PUBLIC_URL%/favicon.ico" will + work correctly both with client-side routing and a non-root public URL. + Learn how to configure a non-root public URL by running `npm run build`. + --> + <title>ConduitMiau</title> + </head> + <body> + <div id="root"></div> + <!-- + This HTML file is a template. + If you open it directly in the browser, you will see an empty page. + + You can add webfonts, meta tags, or analytics to this file. + The build step will place the bundled scripts into the <body> tag. + + To begin the development, run `npm start`. + To create a production bundle, use `npm run build`. + --> + </body> +</html> diff --git a/conduit-front/src/agent.js b/conduit-front/src/agent.js new file mode 100644 index 0000000..5ca1133 --- /dev/null +++ b/conduit-front/src/agent.js @@ -0,0 +1,96 @@ +import superagentPromise from 'superagent-promise'; +import _superagent from 'superagent'; + +const superagent = superagentPromise(_superagent, global.Promise); + +const API_ROOT = 'http://localhost:3000/api'; + +const encode = encodeURIComponent; +const responseBody = res => res.body; + +let token = null; +const tokenPlugin = req => { + if (token) { + req.set('authorization', `Token ${token}`); + } +} + +const requests = { + del: url => + superagent.del(`${API_ROOT}${url}`).use(tokenPlugin).then(responseBody), + get: url => + superagent.get(`${API_ROOT}${url}`).use(tokenPlugin).then(responseBody), + put: (url, body) => + superagent.put(`${API_ROOT}${url}`, body).use(tokenPlugin).then(responseBody), + post: (url, body) => + superagent.post(`${API_ROOT}${url}`, body).use(tokenPlugin).then(responseBody) +}; + +const Auth = { + current: () => + requests.get('/user'), + login: (email, password) => + requests.post('/users/login', { user: { email, password } }), + register: (username, email, password) => + requests.post('/users', { user: { username, email, password } }), + save: user => + requests.put('/user', { user }) +}; + +const Tags = { + getAll: () => requests.get('/tags') +}; + +const limit = (count, p) => `limit=${count}&offset=${p ? p * count : 0}`; +const omitSlug = article => Object.assign({}, article, { slug: undefined }) +const Articles = { + all: page => + requests.get(`/articles?${limit(10, page)}`), + byAuthor: (author, page) => + requests.get(`/articles?author=${encode(author)}&${limit(5, page)}`), + byTag: (tag, page) => + requests.get(`/articles?tag=${encode(tag)}&${limit(10, page)}`), + del: slug => + requests.del(`/articles/${slug}`), + favorite: slug => + requests.post(`/articles/${slug}/favorite`), + favoritedBy: (author, page) => + requests.get(`/articles?favorited=${encode(author)}&${limit(5, page)}`), + feed: () => + requests.get('/articles/feed?limit=10&offset=0'), + get: slug => + requests.get(`/articles/${slug}`), + unfavorite: slug => + requests.del(`/articles/${slug}/favorite`), + update: article => + requests.put(`/articles/${article.slug}`, { article: omitSlug(article) }), + create: article => + requests.post('/articles', { article }) +}; + +const Comments = { + create: (slug, comment) => + requests.post(`/articles/${slug}/comments`, { comment }), + delete: (slug, commentId) => + requests.del(`/articles/${slug}/comments/${commentId}`), + forArticle: slug => + requests.get(`/articles/${slug}/comments`) +}; + +const Profile = { + follow: username => + requests.post(`/profiles/${username}/follow`), + get: username => + requests.get(`/profiles/${username}`), + unfollow: username => + requests.del(`/profiles/${username}/follow`) +}; + +export default { + Articles, + Auth, + Comments, + Profile, + Tags, + setToken: _token => { token = _token; } +}; diff --git a/conduit-front/src/components/App.js b/conduit-front/src/components/App.js new file mode 100644 index 0000000..980ea72 --- /dev/null +++ b/conduit-front/src/components/App.js @@ -0,0 +1,86 @@ +import agent from '../agent'; +import Header from './Header'; +import React from 'react'; +import { connect } from 'react-redux'; +import { APP_LOAD, REDIRECT } from '../constants/actionTypes'; +import { Route, Switch } from 'react-router-dom'; +import Article from '../components/Article'; +import Editor from '../components/Editor'; +import Home from '../components/Home'; +import Login from '../components/Login'; +import Profile from '../components/Profile'; +import ProfileFavorites from '../components/ProfileFavorites'; +import Register from '../components/Register'; +import Settings from '../components/Settings'; +import { store } from '../store'; +import { push } from 'react-router-redux'; + +const mapStateToProps = state => { + return { + appLoaded: state.common.appLoaded, + appName: state.common.appName, + currentUser: state.common.currentUser, + redirectTo: state.common.redirectTo + }}; + +const mapDispatchToProps = dispatch => ({ + onLoad: (payload, token) => + dispatch({ type: APP_LOAD, payload, token, skipTracking: true }), + onRedirect: () => + dispatch({ type: REDIRECT }) +}); + +class App extends React.Component { + componentWillReceiveProps(nextProps) { + if (nextProps.redirectTo) { + // this.context.router.replace(nextProps.redirectTo); + store.dispatch(push(nextProps.redirectTo)); + this.props.onRedirect(); + } + } + + componentWillMount() { + const token = window.localStorage.getItem('jwt'); + if (token) { + agent.setToken(token); + } + + this.props.onLoad(token ? agent.Auth.current() : null, token); + } + + render() { + if (this.props.appLoaded) { + return ( + <div> + <Header + appName={this.props.appName} + currentUser={this.props.currentUser} /> + <Switch> + <Route exact path="/" component={Home}/> + <Route path="/login" component={Login} /> + <Route path="/register" component={Register} /> + <Route path="/editor/:slug" component={Editor} /> + <Route path="/editor" component={Editor} /> + <Route path="/article/:id" component={Article} /> + <Route path="/settings" component={Settings} /> + <Route path="/@:username/favorites" component={ProfileFavorites} /> + <Route path="/@:username" component={Profile} /> + </Switch> + </div> + ); + } + return ( + <div> + <Header + appName={this.props.appName} + currentUser={this.props.currentUser} /> + </div> + ); + } +} + +// App.contextTypes = { +// router: PropTypes.object.isRequired +// }; + +export default connect(mapStateToProps, mapDispatchToProps)(App); diff --git a/conduit-front/src/components/Article/ArticleActions.js b/conduit-front/src/components/Article/ArticleActions.js new file mode 100644 index 0000000..032e77d --- /dev/null +++ b/conduit-front/src/components/Article/ArticleActions.js @@ -0,0 +1,41 @@ +import { Link } from 'react-router-dom'; +import React from 'react'; +import agent from '../../agent'; +import { connect } from 'react-redux'; +import { DELETE_ARTICLE } from '../../constants/actionTypes'; + +const mapDispatchToProps = dispatch => ({ + onClickDelete: payload => + dispatch({ type: DELETE_ARTICLE, payload }) +}); + +const ArticleActions = props => { + const article = props.article; + const del = () => { + props.onClickDelete(agent.Articles.del(article.slug)) + }; + if (props.canModify) { + return ( + <span> + + <Link + to={`/editor/${article.slug}`} + className="btn btn-outline-secondary btn-sm"> + <i className="ion-edit"></i> Edit Article + </Link> + + <button className="btn btn-outline-danger btn-sm" onClick={del}> + <i className="ion-trash-a"></i> Delete Article + </button> + + </span> + ); + } + + return ( + <span> + </span> + ); +}; + +export default connect(() => ({}), mapDispatchToProps)(ArticleActions); diff --git a/conduit-front/src/components/Article/ArticleMeta.js b/conduit-front/src/components/Article/ArticleMeta.js new file mode 100644 index 0000000..a30b35a --- /dev/null +++ b/conduit-front/src/components/Article/ArticleMeta.js @@ -0,0 +1,27 @@ +import ArticleActions from './ArticleActions'; +import { Link } from 'react-router-dom'; +import React from 'react'; + +const ArticleMeta = props => { + const article = props.article; + return ( + <div className="article-meta"> + <Link to={`/@${article.author.username}`}> + <img src={article.author.image} alt={article.author.username} /> + </Link> + + <div className="info"> + <Link to={`/@${article.author.username}`} className="author"> + {article.author.username} + </Link> + <span className="date"> + {new Date(article.createdAt).toDateString()} + </span> + </div> + + <ArticleActions canModify={props.canModify} article={article} /> + </div> + ); +}; + +export default ArticleMeta; diff --git a/conduit-front/src/components/Article/Comment.js b/conduit-front/src/components/Article/Comment.js new file mode 100644 index 0000000..adb34a7 --- /dev/null +++ b/conduit-front/src/components/Article/Comment.js @@ -0,0 +1,35 @@ +import DeleteButton from './DeleteButton'; +import { Link } from 'react-router-dom'; +import React from 'react'; + +const Comment = props => { + const comment = props.comment; + const show = props.currentUser && + props.currentUser.username === comment.author.username; + return ( + <div className="card"> + <div className="card-block"> + <p className="card-text">{comment.body}</p> + </div> + <div className="card-footer"> + <Link + to={`/@${comment.author.username}`} + className="comment-author"> + <img src={comment.author.image} className="comment-author-img" alt={comment.author.username} /> + </Link> + + <Link + to={`/@${comment.author.username}`} + className="comment-author"> + {comment.author.username} + </Link> + <span className="date-posted"> + {new Date(comment.createdAt).toDateString()} + </span> + <DeleteButton show={show} slug={props.slug} commentId={comment.id} /> + </div> + </div> + ); +}; + +export default Comment; diff --git a/conduit-front/src/components/Article/CommentContainer.js b/conduit-front/src/components/Article/CommentContainer.js new file mode 100644 index 0000000..625194e --- /dev/null +++ b/conduit-front/src/components/Article/CommentContainer.js @@ -0,0 +1,40 @@ +import CommentInput from './CommentInput'; +import CommentList from './CommentList'; +import { Link } from 'react-router-dom'; +import React from 'react'; + +const CommentContainer = props => { + if (props.currentUser) { + return ( + <div className="col-xs-12 col-md-8 offset-md-2"> + <div> + <list-errors errors={props.errors}></list-errors> + <CommentInput slug={props.slug} currentUser={props.currentUser} /> + </div> + + <CommentList + comments={props.comments} + slug={props.slug} + currentUser={props.currentUser} /> + </div> + ); + } else { + return ( + <div className="col-xs-12 col-md-8 offset-md-2"> + <p> + <Link to="/login">Sign in</Link> + or + <Link to="/register">sign up</Link> + to add comments on this article. + </p> + + <CommentList + comments={props.comments} + slug={props.slug} + currentUser={props.currentUser} /> + </div> + ); + } +}; + +export default CommentContainer; diff --git a/conduit-front/src/components/Article/CommentInput.js b/conduit-front/src/components/Article/CommentInput.js new file mode 100644 index 0000000..3007ab9 --- /dev/null +++ b/conduit-front/src/components/Article/CommentInput.js @@ -0,0 +1,58 @@ +import React from 'react'; +import agent from '../../agent'; +import { connect } from 'react-redux'; +import { ADD_COMMENT } from '../../constants/actionTypes'; + +const mapDispatchToProps = dispatch => ({ + onSubmit: payload => + dispatch({ type: ADD_COMMENT, payload }) +}); + +class CommentInput extends React.Component { + constructor() { + super(); + this.state = { + body: '' + }; + + this.setBody = ev => { + this.setState({ body: ev.target.value }); + }; + + this.createComment = ev => { + ev.preventDefault(); + const payload = agent.Comments.create(this.props.slug, + { body: this.state.body }); + this.setState({ body: '' }); + this.props.onSubmit(payload); + }; + } + + render() { + return ( + <form className="card comment-form" onSubmit={this.createComment}> + <div className="card-block"> + <textarea className="form-control" + placeholder="Write a comment..." + value={this.state.body} + onChange={this.setBody} + rows="3"> + </textarea> + </div> + <div className="card-footer"> + <img + src={this.props.currentUser.image} + className="comment-author-img" + alt={this.props.currentUser.username} /> + <button + className="btn btn-sm btn-primary" + type="submit"> + Post Comment + </button> + </div> + </form> + ); + } +} + +export default connect(() => ({}), mapDispatchToProps)(CommentInput); diff --git a/conduit-front/src/components/Article/CommentList.js b/conduit-front/src/components/Article/CommentList.js new file mode 100644 index 0000000..b62889d --- /dev/null +++ b/conduit-front/src/components/Article/CommentList.js @@ -0,0 +1,22 @@ +import Comment from './Comment'; +import React from 'react'; + +const CommentList = props => { + return ( + <div> + { + props.comments.map(comment => { + return ( + <Comment + comment={comment} + currentUser={props.currentUser} + slug={props.slug} + key={comment.id} /> + ); + }) + } + </div> + ); +}; + +export default CommentList; diff --git a/conduit-front/src/components/Article/DeleteButton.js b/conduit-front/src/components/Article/DeleteButton.js new file mode 100644 index 0000000..b07d657 --- /dev/null +++ b/conduit-front/src/components/Article/DeleteButton.js @@ -0,0 +1,27 @@ +import React from 'react'; +import agent from '../../agent'; +import { connect } from 'react-redux'; +import { DELETE_COMMENT } from '../../constants/actionTypes'; + +const mapDispatchToProps = dispatch => ({ + onClick: (payload, commentId) => + dispatch({ type: DELETE_COMMENT, payload, commentId }) +}); + +const DeleteButton = props => { + const del = () => { + const payload = agent.Comments.delete(props.slug, props.commentId); + props.onClick(payload, props.commentId); + }; + + if (props.show) { + return ( + <span className="mod-options"> + <i className="ion-trash-a" onClick={del}></i> + </span> + ); + } + return null; +}; + +export default connect(() => ({}), mapDispatchToProps)(DeleteButton); diff --git a/conduit-front/src/components/Article/index.js b/conduit-front/src/components/Article/index.js new file mode 100644 index 0000000..6be8975 --- /dev/null +++ b/conduit-front/src/components/Article/index.js @@ -0,0 +1,97 @@ +import ArticleMeta from './ArticleMeta'; +import CommentContainer from './CommentContainer'; +import React from 'react'; +import agent from '../../agent'; +import { connect } from 'react-redux'; +import marked from 'marked'; +import { ARTICLE_PAGE_LOADED, ARTICLE_PAGE_UNLOADED } from '../../constants/actionTypes'; + +const mapStateToProps = state => ({ + ...state.article, + currentUser: state.common.currentUser +}); + +const mapDispatchToProps = dispatch => ({ + onLoad: payload => + dispatch({ type: ARTICLE_PAGE_LOADED, payload }), + onUnload: () => + dispatch({ type: ARTICLE_PAGE_UNLOADED }) +}); + +class Article extends React.Component { + componentWillMount() { + this.props.onLoad(Promise.all([ + agent.Articles.get(this.props.match.params.id), + agent.Comments.forArticle(this.props.match.params.id) + ])); + } + + componentWillUnmount() { + this.props.onUnload(); + } + + render() { + if (!this.props.article) { + return null; + } + + const markup = { __html: marked(this.props.article.body, { sanitize: true }) }; + const canModify = this.props.currentUser && + this.props.currentUser.username === this.props.article.author.username; + return ( + <div className="article-page"> + + <div className="banner"> + <div className="container"> + + <h1>{this.props.article.title}</h1> + <ArticleMeta + article={this.props.article} + canModify={canModify} /> + + </div> + </div> + + <div className="container page"> + + <div className="row article-content"> + <div className="col-xs-12"> + + <div dangerouslySetInnerHTML={markup}></div> + + <ul className="tag-list"> + { + this.props.article.tagList.map(tag => { + return ( + <li + className="tag-default tag-pill tag-outline" + key={tag}> + {tag} + </li> + ); + }) + } + </ul> + + </div> + </div> + + <hr /> + + <div className="article-actions"> + </div> + + <div className="row"> + <CommentContainer + comments={this.props.comments || []} + errors={this.props.commentErrors} + slug={this.props.match.params.id} + currentUser={this.props.currentUser} /> + </div> + </div> + </div> + ); + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(Article); diff --git a/conduit-front/src/components/ArticleList.js b/conduit-front/src/components/ArticleList.js new file mode 100644 index 0000000..1c17836 --- /dev/null +++ b/conduit-front/src/components/ArticleList.js @@ -0,0 +1,38 @@ +import ArticlePreview from './ArticlePreview'; +import ListPagination from './ListPagination'; +import React from 'react'; + +const ArticleList = props => { + if (!props.articles) { + return ( + <div className="article-preview">Loading...</div> + ); + } + + if (props.articles.length === 0) { + return ( + <div className="article-preview"> + No articles are here... yet. + </div> + ); + } + + return ( + <div> + { + props.articles.map(article => { + return ( + <ArticlePreview article={article} key={article.slug} /> + ); + }) + } + + <ListPagination + pager={props.pager} + articlesCount={props.articlesCount} + currentPage={props.currentPage} /> + </div> + ); +}; + +export default ArticleList; diff --git a/conduit-front/src/components/ArticlePreview.js b/conduit-front/src/components/ArticlePreview.js new file mode 100644 index 0000000..ae9151a --- /dev/null +++ b/conduit-front/src/components/ArticlePreview.js @@ -0,0 +1,79 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import agent from '../agent'; +import { connect } from 'react-redux'; +import { ARTICLE_FAVORITED, ARTICLE_UNFAVORITED } from '../constants/actionTypes'; + +const FAVORITED_CLASS = 'btn btn-sm btn-primary'; +const NOT_FAVORITED_CLASS = 'btn btn-sm btn-outline-primary'; + +const mapDispatchToProps = dispatch => ({ + favorite: slug => dispatch({ + type: ARTICLE_FAVORITED, + payload: agent.Articles.favorite(slug) + }), + unfavorite: slug => dispatch({ + type: ARTICLE_UNFAVORITED, + payload: agent.Articles.unfavorite(slug) + }) +}); + +const ArticlePreview = props => { + const article = props.article; + const favoriteButtonClass = article.favorited ? + FAVORITED_CLASS : + NOT_FAVORITED_CLASS; + + const handleClick = ev => { + ev.preventDefault(); + if (article.favorited) { + props.unfavorite(article.slug); + } else { + props.favorite(article.slug); + } + }; + + return ( + <div className="article-preview"> + <div className="article-meta"> + <Link to={`/@${article.author.username}`}> + <img src={article.author.image} alt={article.author.username} /> + </Link> + + <div className="info"> + <Link className="author" to={`/@${article.author.username}`}> + {article.author.username} + </Link> + <span className="date"> + {new Date(article.createdAt).toDateString()} + </span> + </div> + + <div className="pull-xs-right"> + <button className={favoriteButtonClass} onClick={handleClick}> + <i className="ion-heart"></i> {article.favoritesCount} + </button> + </div> + </div> + + <Link to={`/article/${article.slug}`} className="preview-link"> + <h1>{article.title}</h1> + <p>{article.description}</p> + <span>Read more...</span> + <ul className="tag-list"> + { + article.tagList.map(tag => { + return ( + <li className="tag-default tag-pill tag-outline" key={tag}> + {tag} + </li> + ) + }) + } + </ul> + </Link> + </div> + ); +} + +export default connect(() => ({}), mapDispatchToProps)(ArticlePreview); diff --git a/conduit-front/src/components/Editor.js b/conduit-front/src/components/Editor.js new file mode 100644 index 0000000..93d9d19 --- /dev/null +++ b/conduit-front/src/components/Editor.js @@ -0,0 +1,178 @@ +import ListErrors from './ListErrors'; +import React from 'react'; +import agent from '../agent'; +import { connect } from 'react-redux'; +import { + ADD_TAG, + EDITOR_PAGE_LOADED, + REMOVE_TAG, + ARTICLE_SUBMITTED, + EDITOR_PAGE_UNLOADED, + UPDATE_FIELD_EDITOR +} from '../constants/actionTypes'; + +const mapStateToProps = state => ({ + ...state.editor +}); + +const mapDispatchToProps = dispatch => ({ + onAddTag: () => + dispatch({ type: ADD_TAG }), + onLoad: payload => + dispatch({ type: EDITOR_PAGE_LOADED, payload }), + onRemoveTag: tag => + dispatch({ type: REMOVE_TAG, tag }), + onSubmit: payload => + dispatch({ type: ARTICLE_SUBMITTED, payload }), + onUnload: payload => + dispatch({ type: EDITOR_PAGE_UNLOADED }), + onUpdateField: (key, value) => + dispatch({ type: UPDATE_FIELD_EDITOR, key, value }) +}); + +class Editor extends React.Component { + constructor() { + super(); + + const updateFieldEvent = + key => ev => this.props.onUpdateField(key, ev.target.value); + this.changeTitle = updateFieldEvent('title'); + this.changeDescription = updateFieldEvent('description'); + this.changeBody = updateFieldEvent('body'); + this.changeTagInput = updateFieldEvent('tagInput'); + + this.watchForEnter = ev => { + if (ev.keyCode === 13) { + ev.preventDefault(); + this.props.onAddTag(); + } + }; + + this.removeTagHandler = tag => () => { + this.props.onRemoveTag(tag); + }; + + this.submitForm = ev => { + ev.preventDefault(); + const article = { + title: this.props.title, + description: this.props.description, + body: this.props.body, + tagList: this.props.tagList + }; + + const slug = { slug: this.props.articleSlug }; + const promise = this.props.articleSlug ? + agent.Articles.update(Object.assign(article, slug)) : + agent.Articles.create(article); + + this.props.onSubmit(promise); + }; + } + + componentWillReceiveProps(nextProps) { + if (this.props.match.params.slug !== nextProps.match.params.slug) { + if (nextProps.match.params.slug) { + this.props.onUnload(); + return this.props.onLoad(agent.Articles.get(this.props.match.params.slug)); + } + this.props.onLoad(null); + } + } + + componentWillMount() { + if (this.props.match.params.slug) { + return this.props.onLoad(agent.Articles.get(this.props.match.params.slug)); + } + this.props.onLoad(null); + } + + componentWillUnmount() { + this.props.onUnload(); + } + + render() { + return ( + <div className="editor-page"> + <div className="container page"> + <div className="row"> + <div className="col-md-10 offset-md-1 col-xs-12"> + + <ListErrors errors={this.props.errors}></ListErrors> + + <form> + <fieldset> + + <fieldset className="form-group"> + <input + className="form-control form-control-lg" + type="text" + placeholder="Article Title" + value={this.props.title} + onChange={this.changeTitle} /> + </fieldset> + + <fieldset className="form-group"> + <input + className="form-control" + type="text" + placeholder="What's this article about?" + value={this.props.description} + onChange={this.changeDescription} /> + </fieldset> + + <fieldset className="form-group"> + <textarea + className="form-control" + rows="8" + placeholder="Write your article (in markdown)" + value={this.props.body} + onChange={this.changeBody}> + </textarea> + </fieldset> + + <fieldset className="form-group"> + <input + className="form-control" + type="text" + placeholder="Give one tag at a time and press Enter" + value={this.props.tagInput} + onChange={this.changeTagInput} + onKeyUp={this.watchForEnter} /> + + <div className="tag-list"> + { + (this.props.tagList || []).map(tag => { + return ( + <span className="tag-default tag-pill" key={tag}> + <i className="ion-close-round" + onClick={this.removeTagHandler(tag)}> + </i> + {tag} + </span> + ); + }) + } + </div> + </fieldset> + + <button + className="btn btn-lg pull-xs-right btn-primary" + type="button" + disabled={this.props.inProgress} + onClick={this.submitForm}> + Publish Article + </button> + + </fieldset> + </form> + + </div> + </div> + </div> + </div> + ); + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(Editor); diff --git a/conduit-front/src/components/Header.js b/conduit-front/src/components/Header.js new file mode 100644 index 0000000..63641b8 --- /dev/null +++ b/conduit-front/src/components/Header.js @@ -0,0 +1,91 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; + +const LoggedOutView = props => { + if (!props.currentUser) { + return ( + <ul className="nav navbar-nav pull-xs-right"> + + <li className="nav-item"> + <Link to="/" className="nav-link"> + Home + </Link> + </li> + + <li className="nav-item"> + <Link to="/login" className="nav-link"> + Sign in + </Link> + </li> + + <li className="nav-item"> + <Link to="/register" className="nav-link"> + Sign up + </Link> + </li> + + </ul> + ); + } + return null; +}; + +const LoggedInView = props => { + if (props.currentUser) { + return ( + <ul className="nav navbar-nav pull-xs-right"> + + <li className="nav-item"> + <Link to="/" className="nav-link"> + Home + </Link> + </li> + + <li className="nav-item"> + <Link to="/editor" className="nav-link"> + <i className="ion-compose"></i> New Post + </Link> + </li> + + <li className="nav-item"> + <Link to="/settings" className="nav-link"> + <i className="ion-gear-a"></i> Settings + </Link> + </li> + + <li className="nav-item"> + <Link + to={`/@${props.currentUser.username}`} + className="nav-link"> + <img src={props.currentUser.image} className="user-pic" alt={props.currentUser.username} /> + {props.currentUser.username} + </Link> + </li> + + </ul> + ); + } + + return null; +}; + +class Header extends React.Component { + render() { + return ( + <nav className="navbar navbar-light"> + <div className="container"> + + <Link to="/" className="navbar-brand"> + {this.props.appName.toLowerCase()} + </Link> + + <LoggedOutView currentUser={this.props.currentUser} /> + + <LoggedInView currentUser={this.props.currentUser} /> + </div> + </nav> + ); + } +} + +export default Header; diff --git a/conduit-front/src/components/Home/Banner.js b/conduit-front/src/components/Home/Banner.js new file mode 100644 index 0000000..dfb5690 --- /dev/null +++ b/conduit-front/src/components/Home/Banner.js @@ -0,0 +1,19 @@ +import React from 'react'; + +const Banner = ({ appName, token }) => { + if (token) { + return null; + } + return ( + <div className="banner"> + <div className="container"> + <h1 className="logo-font"> + {appName.toLowerCase()} + </h1> + <p>A place to share your knowledge.</p> + </div> + </div> + ); +}; + +export default Banner; diff --git a/conduit-front/src/components/Home/MainView.js b/conduit-front/src/components/Home/MainView.js new file mode 100644 index 0000000..bd581f2 --- /dev/null +++ b/conduit-front/src/components/Home/MainView.js @@ -0,0 +1,96 @@ +import ArticleList from '../ArticleList'; +import React from 'react'; +import agent from '../../agent'; +import { connect } from 'react-redux'; +import { CHANGE_TAB } from '../../constants/actionTypes'; + +const YourFeedTab = props => { + if (props.token) { + const clickHandler = ev => { + ev.preventDefault(); + props.onTabClick('feed', agent.Articles.feed, agent.Articles.feed()); + } + + return ( + <li className="nav-item"> + <a href="" + className={ props.tab === 'feed' ? 'nav-link active' : 'nav-link' } + onClick={clickHandler}> + Your Feed + </a> + </li> + ); + } + return null; +}; + +const GlobalFeedTab = props => { + const clickHandler = ev => { + ev.preventDefault(); + props.onTabClick('all', agent.Articles.all, agent.Articles.all()); + }; + return ( + <li className="nav-item"> + <a + href="" + className={ props.tab === 'all' ? 'nav-link active' : 'nav-link' } + onClick={clickHandler}> + Global Feed + </a> + </li> + ); +}; + +const TagFilterTab = props => { + if (!props.tag) { + return null; + } + + return ( + <li className="nav-item"> + <a href="" className="nav-link active"> + <i className="ion-pound"></i> {props.tag} + </a> + </li> + ); +}; + +const mapStateToProps = state => ({ + ...state.articleList, + tags: state.home.tags, + token: state.common.token +}); + +const mapDispatchToProps = dispatch => ({ + onTabClick: (tab, pager, payload) => dispatch({ type: CHANGE_TAB, tab, pager, payload }) +}); + +const MainView = props => { + return ( + <div className="col-md-9"> + <div className="feed-toggle"> + <ul className="nav nav-pills outline-active"> + + <YourFeedTab + token={props.token} + tab={props.tab} + onTabClick={props.onTabClick} /> + + <GlobalFeedTab tab={props.tab} onTabClick={props.onTabClick} /> + + <TagFilterTab tag={props.tag} /> + + </ul> + </div> + + <ArticleList + pager={props.pager} + articles={props.articles} + loading={props.loading} + articlesCount={props.articlesCount} + currentPage={props.currentPage} /> + </div> + ); +}; + +export default connect(mapStateToProps, mapDispatchToProps)(MainView); diff --git a/conduit-front/src/components/Home/Tags.js b/conduit-front/src/components/Home/Tags.js new file mode 100644 index 0000000..fb498ae --- /dev/null +++ b/conduit-front/src/components/Home/Tags.js @@ -0,0 +1,36 @@ +import React from 'react'; +import agent from '../../agent'; + +const Tags = props => { + const tags = props.tags; + if (tags) { + return ( + <div className="tag-list"> + { + tags.map(tag => { + const handleClick = ev => { + ev.preventDefault(); + props.onClickTag(tag, page => agent.Articles.byTag(tag, page), agent.Articles.byTag(tag)); + }; + + return ( + <a + href="" + className="tag-default tag-pill" + key={tag} + onClick={handleClick}> + {tag} + </a> + ); + }) + } + </div> + ); + } else { + return ( + <div>Loading Tags...</div> + ); + } +}; + +export default Tags; diff --git a/conduit-front/src/components/Home/index.js b/conduit-front/src/components/Home/index.js new file mode 100644 index 0000000..37fddd1 --- /dev/null +++ b/conduit-front/src/components/Home/index.js @@ -0,0 +1,78 @@ +import Banner from './Banner'; +import MainView from './MainView'; +import React from 'react'; +import Tags from './Tags'; +import agent from '../../agent'; +import { connect } from 'react-redux'; +import { + HOME_PAGE_LOADED, + HOME_PAGE_UNLOADED, + APPLY_TAG_FILTER +} from '../../constants/actionTypes'; + +const Promise = global.Promise; + +const mapStateToProps = state => ({ + ...state.home, + appName: state.common.appName, + token: state.common.token +}); + +const mapDispatchToProps = dispatch => ({ + onClickTag: (tag, pager, payload) => + dispatch({ type: APPLY_TAG_FILTER, tag, pager, payload }), + onLoad: (tab, pager, payload) => + dispatch({ type: HOME_PAGE_LOADED, tab, pager, payload }), + onUnload: () => + dispatch({ type: HOME_PAGE_UNLOADED }) +}); + +class Home extends React.Component { + componentWillMount() { + const tab = this.props.token ? 'feed' : 'all'; + const articlesPromise = this.props.token ? + agent.Articles.feed : + agent.Articles.all; + + /*this.props.onLoad(tab, articlesPromise, Promise.all([agent.Tags.getAll(), articlesPromise()]));*/ + Promise + .all([agent.Tags.getAll(), articlesPromise()]) + .then((result) => { + this.props.onLoad(tab, articlesPromise, result); + }); + } + + componentWillUnmount() { + this.props.onUnload(); + } + + render() { + return ( + <div className="home-page"> + + <Banner token={this.props.token} appName={this.props.appName} /> + + <div className="container page"> + <div className="row"> + <MainView /> + + <div className="col-md-3"> + <div className="sidebar"> + + <p>Popular Tags</p> + + <Tags + tags={this.props.tags} + onClickTag={this.props.onClickTag} /> + + </div> + </div> + </div> + </div> + + </div> + ); + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(Home); diff --git a/conduit-front/src/components/ListErrors.js b/conduit-front/src/components/ListErrors.js new file mode 100644 index 0000000..3b40022 --- /dev/null +++ b/conduit-front/src/components/ListErrors.js @@ -0,0 +1,26 @@ +import React from 'react'; + +class ListErrors extends React.Component { + render() { + const errors = this.props.errors; + if (errors) { + return ( + <ul className="error-messages"> + { + Object.keys(errors).map(key => { + return ( + <li key={key}> + {key} {errors[key]} + </li> + ); + }) + } + </ul> + ); + } else { + return null; + } + } +} + +export default ListErrors; diff --git a/conduit-front/src/components/ListPagination.js b/conduit-front/src/components/ListPagination.js new file mode 100644 index 0000000..ba38a6e --- /dev/null +++ b/conduit-front/src/components/ListPagination.js @@ -0,0 +1,58 @@ +import React from 'react'; +import agent from '../agent'; +import { connect } from 'react-redux'; +import { SET_PAGE } from '../constants/actionTypes'; + +const mapDispatchToProps = dispatch => ({ + onSetPage: (page, payload) => + dispatch({ type: SET_PAGE, page, payload }) +}); + +const ListPagination = props => { + if (props.articlesCount <= 10) { + return null; + } + + const range = []; + for (let i = 0; i < Math.ceil(props.articlesCount / 10); ++i) { + range.push(i); + } + + const setPage = page => { + if(props.pager) { + props.onSetPage(page, props.pager(page)); + }else { + props.onSetPage(page, agent.Articles.all(page)) + } + }; + + return ( + <nav> + <ul className="pagination"> + + { + range.map(v => { + const isCurrent = v === props.currentPage; + const onClick = ev => { + ev.preventDefault(); + setPage(v); + }; + return ( + <li + className={ isCurrent ? 'page-item active' : 'page-item' } + onClick={onClick} + key={v.toString()}> + + <a className="page-link" href="">{v + 1}</a> + + </li> + ); + }) + } + + </ul> + </nav> + ); +}; + +export default connect(() => ({}), mapDispatchToProps)(ListPagination); diff --git a/conduit-front/src/components/Login.js b/conduit-front/src/components/Login.js new file mode 100644 index 0000000..c63a0fa --- /dev/null +++ b/conduit-front/src/components/Login.js @@ -0,0 +1,97 @@ +import { Link } from 'react-router-dom'; +import ListErrors from './ListErrors'; +import React from 'react'; +import agent from '../agent'; +import { connect } from 'react-redux'; +import { + UPDATE_FIELD_AUTH, + LOGIN, + LOGIN_PAGE_UNLOADED +} from '../constants/actionTypes'; + +const mapStateToProps = state => ({ ...state.auth }); + +const mapDispatchToProps = dispatch => ({ + onChangeEmail: value => + dispatch({ type: UPDATE_FIELD_AUTH, key: 'email', value }), + onChangePassword: value => + dispatch({ type: UPDATE_FIELD_AUTH, key: 'password', value }), + onSubmit: (email, password) => + dispatch({ type: LOGIN, payload: agent.Auth.login(email, password) }), + onUnload: () => + dispatch({ type: LOGIN_PAGE_UNLOADED }) +}); + +class Login extends React.Component { + constructor() { + super(); + this.changeEmail = ev => this.props.onChangeEmail(ev.target.value); + this.changePassword = ev => this.props.onChangePassword(ev.target.value); + this.submitForm = (email, password) => ev => { + ev.preventDefault(); + this.props.onSubmit(email, password); + }; + } + + componentWillUnmount() { + this.props.onUnload(); + } + + render() { + const email = this.props.email; + const password = this.props.password; + return ( + <div className="auth-page"> + <div className="container page"> + <div className="row"> + + <div className="col-md-6 offset-md-3 col-xs-12"> + <h1 className="text-xs-center">Sign In</h1> + <p className="text-xs-center"> + <Link to="/register"> + Need an account? + </Link> + </p> + + <ListErrors errors={this.props.errors} /> + + <form onSubmit={this.submitForm(email, password)}> + <fieldset> + + <fieldset className="form-group"> + <input + className="form-control form-control-lg" + type="email" + placeholder="Email" + value={email} + onChange={this.changeEmail} /> + </fieldset> + + <fieldset className="form-group"> + <input + className="form-control form-control-lg" + type="password" + placeholder="Password" + value={password} + onChange={this.changePassword} /> + </fieldset> + + <button + className="btn btn-lg btn-primary pull-xs-right" + type="submit" + disabled={this.props.inProgress}> + Sign in + </button> + + </fieldset> + </form> + </div> + + </div> + </div> + </div> + ); + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(Login); diff --git a/conduit-front/src/components/Profile.js b/conduit-front/src/components/Profile.js new file mode 100644 index 0000000..a3a5e6d --- /dev/null +++ b/conduit-front/src/components/Profile.js @@ -0,0 +1,170 @@ +import ArticleList from './ArticleList'; +import React from 'react'; +import { Link } from 'react-router-dom'; +import agent from '../agent'; +import { connect } from 'react-redux'; +import { + FOLLOW_USER, + UNFOLLOW_USER, + PROFILE_PAGE_LOADED, + PROFILE_PAGE_UNLOADED +} from '../constants/actionTypes'; + +const EditProfileSettings = props => { + if (props.isUser) { + return ( + <Link + to="/settings" + className="btn btn-sm btn-outline-secondary action-btn"> + <i className="ion-gear-a"></i> Edit Profile Settings + </Link> + ); + } + return null; +}; + +const FollowUserButton = props => { + if (props.isUser) { + return null; + } + + let classes = 'btn btn-sm action-btn'; + if (props.user.following) { + classes += ' btn-secondary'; + } else { + classes += ' btn-outline-secondary'; + } + + const handleClick = ev => { + ev.preventDefault(); + if (props.user.following) { + props.unfollow(props.user.username) + } else { + props.follow(props.user.username) + } + }; + + return ( + <button + className={classes} + onClick={handleClick}> + <i className="ion-plus-round"></i> + + {props.user.following ? 'Unfollow' : 'Follow'} {props.user.username} + </button> + ); +}; + +const mapStateToProps = state => ({ + ...state.articleList, + currentUser: state.common.currentUser, + profile: state.profile +}); + +const mapDispatchToProps = dispatch => ({ + onFollow: username => dispatch({ + type: FOLLOW_USER, + payload: agent.Profile.follow(username) + }), + onLoad: payload => dispatch({ type: PROFILE_PAGE_LOADED, payload }), + onUnfollow: username => dispatch({ + type: UNFOLLOW_USER, + payload: agent.Profile.unfollow(username) + }), + onUnload: () => dispatch({ type: PROFILE_PAGE_UNLOADED }) +}); + +class Profile extends React.Component { + componentWillMount() { + this.props.onLoad(Promise.all([ + agent.Profile.get(this.props.match.params.username), + agent.Articles.byAuthor(this.props.match.params.username) + ])); + } + + componentWillUnmount() { + this.props.onUnload(); + } + + renderTabs() { + return ( + <ul className="nav nav-pills outline-active"> + <li className="nav-item"> + <Link + className="nav-link active" + to={`/@${this.props.profile.username}`}> + My Articles + </Link> + </li> + + <li className="nav-item"> + <Link + className="nav-link" + to={`/@${this.props.profile.username}/favorites`}> + Favorited Articles + </Link> + </li> + </ul> + ); + } + + render() { + const profile = this.props.profile; + if (!profile) { + return null; + } + + const isUser = this.props.currentUser && + this.props.profile.username === this.props.currentUser.username; + + return ( + <div className="profile-page"> + + <div className="user-info"> + <div className="container"> + <div className="row"> + <div className="col-xs-12 col-md-10 offset-md-1"> + + <img src={profile.image} className="user-img" alt={profile.username} /> + <h4>{profile.username}</h4> + <p>{profile.bio}</p> + + <EditProfileSettings isUser={isUser} /> + <FollowUserButton + isUser={isUser} + user={profile} + follow={this.props.onFollow} + unfollow={this.props.onUnfollow} + /> + + </div> + </div> + </div> + </div> + + <div className="container"> + <div className="row"> + + <div className="col-xs-12 col-md-10 offset-md-1"> + + <div className="articles-toggle"> + {this.renderTabs()} + </div> + + <ArticleList + pager={this.props.pager} + articles={this.props.articles} + articlesCount={this.props.articlesCount} + state={this.props.currentPage} /> + </div> + + </div> + </div> + + </div> + ); + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(Profile); +export { Profile, mapStateToProps }; diff --git a/conduit-front/src/components/ProfileFavorites.js b/conduit-front/src/components/ProfileFavorites.js new file mode 100644 index 0000000..43ddbbe --- /dev/null +++ b/conduit-front/src/components/ProfileFavorites.js @@ -0,0 +1,53 @@ +import { Profile, mapStateToProps } from './Profile'; +import React from 'react'; +import { Link } from 'react-router-dom'; +import agent from '../agent'; +import { connect } from 'react-redux'; +import { + PROFILE_PAGE_LOADED, + PROFILE_PAGE_UNLOADED +} from '../constants/actionTypes'; + +const mapDispatchToProps = dispatch => ({ + onLoad: (pager, payload) => + dispatch({ type: PROFILE_PAGE_LOADED, pager, payload }), + onUnload: () => + dispatch({ type: PROFILE_PAGE_UNLOADED }) +}); + +class ProfileFavorites extends Profile { + componentWillMount() { + this.props.onLoad(page => agent.Articles.favoritedBy(this.props.match.params.username, page), Promise.all([ + agent.Profile.get(this.props.match.params.username), + agent.Articles.favoritedBy(this.props.match.params.username) + ])); + } + + componentWillUnmount() { + this.props.onUnload(); + } + + renderTabs() { + return ( + <ul className="nav nav-pills outline-active"> + <li className="nav-item"> + <Link + className="nav-link" + to={`/@${this.props.profile.username}`}> + My Articles + </Link> + </li> + + <li className="nav-item"> + <Link + className="nav-link active" + to={`/@${this.props.profile.username}/favorites`}> + Favorited Articles + </Link> + </li> + </ul> + ); + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(ProfileFavorites); diff --git a/conduit-front/src/components/Register.js b/conduit-front/src/components/Register.js new file mode 100644 index 0000000..ff81749 --- /dev/null +++ b/conduit-front/src/components/Register.js @@ -0,0 +1,113 @@ +import { Link } from 'react-router-dom'; +import ListErrors from './ListErrors'; +import React from 'react'; +import agent from '../agent'; +import { connect } from 'react-redux'; +import { + UPDATE_FIELD_AUTH, + REGISTER, + REGISTER_PAGE_UNLOADED +} from '../constants/actionTypes'; + +const mapStateToProps = state => ({ ...state.auth }); + +const mapDispatchToProps = dispatch => ({ + onChangeEmail: value => + dispatch({ type: UPDATE_FIELD_AUTH, key: 'email', value }), + onChangePassword: value => + dispatch({ type: UPDATE_FIELD_AUTH, key: 'password', value }), + onChangeUsername: value => + dispatch({ type: UPDATE_FIELD_AUTH, key: 'username', value }), + onSubmit: (username, email, password) => { + const payload = agent.Auth.register(username, email, password); + dispatch({ type: REGISTER, payload }) + }, + onUnload: () => + dispatch({ type: REGISTER_PAGE_UNLOADED }) +}); + +class Register extends React.Component { + constructor() { + super(); + this.changeEmail = ev => this.props.onChangeEmail(ev.target.value); + this.changePassword = ev => this.props.onChangePassword(ev.target.value); + this.changeUsername = ev => this.props.onChangeUsername(ev.target.value); + this.submitForm = (username, email, password) => ev => { + ev.preventDefault(); + this.props.onSubmit(username, email, password); + } + } + + componentWillUnmount() { + this.props.onUnload(); + } + + render() { + const email = this.props.email; + const password = this.props.password; + const username = this.props.username; + + return ( + <div className="auth-page"> + <div className="container page"> + <div className="row"> + + <div className="col-md-6 offset-md-3 col-xs-12"> + <h1 className="text-xs-center">Sign Up</h1> + <p className="text-xs-center"> + <Link to="/login"> + Have an account? + </Link> + </p> + + <ListErrors errors={this.props.errors} /> + + <form onSubmit={this.submitForm(username, email, password)}> + <fieldset> + + <fieldset className="form-group"> + <input + className="form-control form-control-lg" + type="text" + placeholder="Username" + value={this.props.username} + onChange={this.changeUsername} /> + </fieldset> + + <fieldset className="form-group"> + <input + className="form-control form-control-lg" + type="email" + placeholder="Email" + value={this.props.email} + onChange={this.changeEmail} /> + </fieldset> + + <fieldset className="form-group"> + <input + className="form-control form-control-lg" + type="password" + placeholder="Password" + value={this.props.password} + onChange={this.changePassword} /> + </fieldset> + + <button + className="btn btn-lg btn-primary pull-xs-right" + type="submit" + disabled={this.props.inProgress}> + Sign up + </button> + + </fieldset> + </form> + </div> + + </div> + </div> + </div> + ); + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(Register); diff --git a/conduit-front/src/components/Settings.js b/conduit-front/src/components/Settings.js new file mode 100644 index 0000000..265b17a --- /dev/null +++ b/conduit-front/src/components/Settings.js @@ -0,0 +1,171 @@ +import ListErrors from './ListErrors'; +import React from 'react'; +import agent from '../agent'; +import { connect } from 'react-redux'; +import { + SETTINGS_SAVED, + SETTINGS_PAGE_UNLOADED, + LOGOUT +} from '../constants/actionTypes'; + +class SettingsForm extends React.Component { + constructor() { + super(); + + this.state = { + image: '', + username: '', + bio: '', + email: '', + password: '' + }; + + this.updateState = field => ev => { + const state = this.state; + const newState = Object.assign({}, state, { [field]: ev.target.value }); + this.setState(newState); + }; + + this.submitForm = ev => { + ev.preventDefault(); + + const user = Object.assign({}, this.state); + if (!user.password) { + delete user.password; + } + + this.props.onSubmitForm(user); + }; + } + + componentWillMount() { + if (this.props.currentUser) { + Object.assign(this.state, { + image: this.props.currentUser.image || '', + username: this.props.currentUser.username, + bio: this.props.currentUser.bio, + email: this.props.currentUser.email + }); + } + } + + componentWillReceiveProps(nextProps) { + if (nextProps.currentUser) { + this.setState(Object.assign({}, this.state, { + image: nextProps.currentUser.image || '', + username: nextProps.currentUser.username, + bio: nextProps.currentUser.bio, + email: nextProps.currentUser.email + })); + } + } + + render() { + return ( + <form onSubmit={this.submitForm}> + <fieldset> + + <fieldset className="form-group"> + <input + className="form-control" + type="text" + placeholder="URL of profile picture" + value={this.state.image} + onChange={this.updateState('image')} /> + </fieldset> + + <fieldset className="form-group"> + <input + className="form-control form-control-lg" + type="text" + placeholder="Username" + value={this.state.username} + onChange={this.updateState('username')} /> + </fieldset> + + <fieldset className="form-group"> + <textarea + className="form-control form-control-lg" + rows="8" + placeholder="Short bio about you" + value={this.state.bio} + onChange={this.updateState('bio')}> + </textarea> + </fieldset> + + <fieldset className="form-group"> + <input + className="form-control form-control-lg" + type="email" + placeholder="Email" + value={this.state.email} + onChange={this.updateState('email')} /> + </fieldset> + + <fieldset className="form-group"> + <input + className="form-control form-control-lg" + type="password" + placeholder="New Password" + value={this.state.password} + onChange={this.updateState('password')} /> + </fieldset> + + <button + className="btn btn-lg btn-primary pull-xs-right" + type="submit" + disabled={this.state.inProgress}> + Update Settings + </button> + + </fieldset> + </form> + ); + } +} + +const mapStateToProps = state => ({ + ...state.settings, + currentUser: state.common.currentUser +}); + +const mapDispatchToProps = dispatch => ({ + onClickLogout: () => dispatch({ type: LOGOUT }), + onSubmitForm: user => + dispatch({ type: SETTINGS_SAVED, payload: agent.Auth.save(user) }), + onUnload: () => dispatch({ type: SETTINGS_PAGE_UNLOADED }) +}); + +class Settings extends React.Component { + render() { + return ( + <div className="settings-page"> + <div className="container page"> + <div className="row"> + <div className="col-md-6 offset-md-3 col-xs-12"> + + <h1 className="text-xs-center">Your Settings</h1> + + <ListErrors errors={this.props.errors}></ListErrors> + + <SettingsForm + currentUser={this.props.currentUser} + onSubmitForm={this.props.onSubmitForm} /> + + <hr /> + + <button + className="btn btn-outline-danger" + onClick={this.props.onClickLogout}> + Or click here to logout. + </button> + + </div> + </div> + </div> + </div> + ); + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(Settings); diff --git a/conduit-front/src/constants/actionTypes.js b/conduit-front/src/constants/actionTypes.js new file mode 100644 index 0000000..8683c60 --- /dev/null +++ b/conduit-front/src/constants/actionTypes.js @@ -0,0 +1,36 @@ +export const APP_LOAD = 'APP_LOAD'; +export const REDIRECT = 'REDIRECT'; +export const ARTICLE_SUBMITTED = 'ARTICLE_SUBMITTED'; +export const SETTINGS_SAVED = 'SETTINGS_SAVED'; +export const DELETE_ARTICLE = 'DELETE_ARTICLE'; +export const SETTINGS_PAGE_UNLOADED = 'SETTINGS_PAGE_UNLOADED'; +export const HOME_PAGE_LOADED = 'HOME_PAGE_LOADED'; +export const HOME_PAGE_UNLOADED = 'HOME_PAGE_UNLOADED'; +export const ARTICLE_PAGE_LOADED = 'ARTICLE_PAGE_LOADED'; +export const ARTICLE_PAGE_UNLOADED = 'ARTICLE_PAGE_UNLOADED'; +export const ADD_COMMENT = 'ADD_COMMENT'; +export const DELETE_COMMENT = 'DELETE_COMMENT'; +export const ARTICLE_FAVORITED = 'ARTICLE_FAVORITED'; +export const ARTICLE_UNFAVORITED = 'ARTICLE_UNFAVORITED'; +export const SET_PAGE = 'SET_PAGE'; +export const APPLY_TAG_FILTER = 'APPLY_TAG_FILTER'; +export const CHANGE_TAB = 'CHANGE_TAB'; +export const PROFILE_PAGE_LOADED = 'PROFILE_PAGE_LOADED'; +export const PROFILE_PAGE_UNLOADED = 'PROFILE_PAGE_UNLOADED'; +export const LOGIN = 'LOGIN'; +export const LOGOUT = 'LOGOUT'; +export const REGISTER = 'REGISTER'; +export const LOGIN_PAGE_UNLOADED = 'LOGIN_PAGE_UNLOADED'; +export const REGISTER_PAGE_UNLOADED = 'REGISTER_PAGE_UNLOADED'; +export const ASYNC_START = 'ASYNC_START'; +export const ASYNC_END = 'ASYNC_END'; +export const EDITOR_PAGE_LOADED = 'EDITOR_PAGE_LOADED'; +export const EDITOR_PAGE_UNLOADED = 'EDITOR_PAGE_UNLOADED'; +export const ADD_TAG = 'ADD_TAG'; +export const REMOVE_TAG = 'REMOVE_TAG'; +export const UPDATE_FIELD_AUTH = 'UPDATE_FIELD_AUTH'; +export const UPDATE_FIELD_EDITOR = 'UPDATE_FIELD_EDITOR'; +export const FOLLOW_USER = 'FOLLOW_USER'; +export const UNFOLLOW_USER = 'UNFOLLOW_USER'; +export const PROFILE_FAVORITES_PAGE_UNLOADED = 'PROFILE_FAVORITES_PAGE_UNLOADED'; +export const PROFILE_FAVORITES_PAGE_LOADED = 'PROFILE_FAVORITES_PAGE_LOADED'; \ No newline at end of file diff --git a/conduit-front/src/index.js b/conduit-front/src/index.js new file mode 100644 index 0000000..3d20aa2 --- /dev/null +++ b/conduit-front/src/index.js @@ -0,0 +1,20 @@ +import ReactDOM from 'react-dom'; +import { Provider } from 'react-redux'; +import React from 'react'; +import { store, history} from './store'; + +import { Route, Switch } from 'react-router-dom'; +import { ConnectedRouter } from 'react-router-redux'; + +import App from './components/App'; + +ReactDOM.render(( + <Provider store={store}> + <ConnectedRouter history={history}> + <Switch> + <Route path="/" component={App} /> + </Switch> + </ConnectedRouter> + </Provider> + +), document.getElementById('root')); diff --git a/conduit-front/src/middleware.js b/conduit-front/src/middleware.js new file mode 100644 index 0000000..9e24a96 --- /dev/null +++ b/conduit-front/src/middleware.js @@ -0,0 +1,68 @@ +import agent from './agent'; +import { + ASYNC_START, + ASYNC_END, + LOGIN, + LOGOUT, + REGISTER +} from './constants/actionTypes'; + +const promiseMiddleware = store => next => action => { + if (isPromise(action.payload)) { + store.dispatch({ type: ASYNC_START, subtype: action.type }); + + const currentView = store.getState().viewChangeCounter; + const skipTracking = action.skipTracking; + + action.payload.then( + res => { + const currentState = store.getState() + if (!skipTracking && currentState.viewChangeCounter !== currentView) { + return + } + console.log('RESULT', res); + action.payload = res; + store.dispatch({ type: ASYNC_END, promise: action.payload }); + store.dispatch(action); + }, + error => { + const currentState = store.getState() + if (!skipTracking && currentState.viewChangeCounter !== currentView) { + return + } + console.log('ERROR', error); + action.error = true; + action.payload = error.response.body; + if (!action.skipTracking) { + store.dispatch({ type: ASYNC_END, promise: action.payload }); + } + store.dispatch(action); + } + ); + + return; + } + + next(action); +}; + +const localStorageMiddleware = store => next => action => { + if (action.type === REGISTER || action.type === LOGIN) { + if (!action.error) { + window.localStorage.setItem('jwt', action.payload.user.token); + agent.setToken(action.payload.user.token); + } + } else if (action.type === LOGOUT) { + window.localStorage.setItem('jwt', ''); + agent.setToken(null); + } + + next(action); +}; + +function isPromise(v) { + return v && typeof v.then === 'function'; +} + + +export { promiseMiddleware, localStorageMiddleware } diff --git a/conduit-front/src/reducer.js b/conduit-front/src/reducer.js new file mode 100644 index 0000000..5005911 --- /dev/null +++ b/conduit-front/src/reducer.js @@ -0,0 +1,22 @@ +import article from './reducers/article'; +import articleList from './reducers/articleList'; +import auth from './reducers/auth'; +import { combineReducers } from 'redux'; +import common from './reducers/common'; +import editor from './reducers/editor'; +import home from './reducers/home'; +import profile from './reducers/profile'; +import settings from './reducers/settings'; +import { routerReducer } from 'react-router-redux'; + +export default combineReducers({ + article, + articleList, + auth, + common, + editor, + home, + profile, + settings, + router: routerReducer +}); diff --git a/conduit-front/src/reducers/article.js b/conduit-front/src/reducers/article.js new file mode 100644 index 0000000..50ec7a9 --- /dev/null +++ b/conduit-front/src/reducers/article.js @@ -0,0 +1,35 @@ +import { + ARTICLE_PAGE_LOADED, + ARTICLE_PAGE_UNLOADED, + ADD_COMMENT, + DELETE_COMMENT +} from '../constants/actionTypes'; + +export default (state = {}, action) => { + switch (action.type) { + case ARTICLE_PAGE_LOADED: + return { + ...state, + article: action.payload[0].article, + comments: action.payload[1].comments + }; + case ARTICLE_PAGE_UNLOADED: + return {}; + case ADD_COMMENT: + return { + ...state, + commentErrors: action.error ? action.payload.errors : null, + comments: action.error ? + null : + (state.comments || []).concat([action.payload.comment]) + }; + case DELETE_COMMENT: + const commentId = action.commentId + return { + ...state, + comments: state.comments.filter(comment => comment.id !== commentId) + }; + default: + return state; + } +}; diff --git a/conduit-front/src/reducers/articleList.js b/conduit-front/src/reducers/articleList.js new file mode 100644 index 0000000..1fe962d --- /dev/null +++ b/conduit-front/src/reducers/articleList.js @@ -0,0 +1,86 @@ +import { + ARTICLE_FAVORITED, + ARTICLE_UNFAVORITED, + SET_PAGE, + APPLY_TAG_FILTER, + HOME_PAGE_LOADED, + HOME_PAGE_UNLOADED, + CHANGE_TAB, + PROFILE_PAGE_LOADED, + PROFILE_PAGE_UNLOADED, + PROFILE_FAVORITES_PAGE_LOADED, + PROFILE_FAVORITES_PAGE_UNLOADED +} from '../constants/actionTypes'; + +export default (state = {}, action) => { + switch (action.type) { + case ARTICLE_FAVORITED: + case ARTICLE_UNFAVORITED: + return { + ...state, + articles: state.articles.map(article => { + if (article.slug === action.payload.article.slug) { + return { + ...article, + favorited: action.payload.article.favorited, + favoritesCount: action.payload.article.favoritesCount + }; + } + return article; + }) + }; + case SET_PAGE: + return { + ...state, + articles: action.payload.articles, + articlesCount: action.payload.articlesCount, + currentPage: action.page + }; + case APPLY_TAG_FILTER: + return { + ...state, + pager: action.pager, + articles: action.payload.articles, + articlesCount: action.payload.articlesCount, + tab: null, + tag: action.tag, + currentPage: 0 + }; + case HOME_PAGE_LOADED: + return { + ...state, + pager: action.pager, + tags: action.payload[0].tags, + articles: action.payload[1].articles, + articlesCount: action.payload[1].articlesCount, + currentPage: 0, + tab: action.tab + }; + case HOME_PAGE_UNLOADED: + return {}; + case CHANGE_TAB: + return { + ...state, + pager: action.pager, + articles: action.payload.articles, + articlesCount: action.payload.articlesCount, + tab: action.tab, + currentPage: 0, + tag: null + }; + case PROFILE_PAGE_LOADED: + case PROFILE_FAVORITES_PAGE_LOADED: + return { + ...state, + pager: action.pager, + articles: action.payload[1].articles, + articlesCount: action.payload[1].articlesCount, + currentPage: 0 + }; + case PROFILE_PAGE_UNLOADED: + case PROFILE_FAVORITES_PAGE_UNLOADED: + return {}; + default: + return state; + } +}; diff --git a/conduit-front/src/reducers/auth.js b/conduit-front/src/reducers/auth.js new file mode 100644 index 0000000..6e83838 --- /dev/null +++ b/conduit-front/src/reducers/auth.js @@ -0,0 +1,34 @@ +import { + LOGIN, + REGISTER, + LOGIN_PAGE_UNLOADED, + REGISTER_PAGE_UNLOADED, + ASYNC_START, + UPDATE_FIELD_AUTH +} from '../constants/actionTypes'; + +export default (state = {}, action) => { + switch (action.type) { + case LOGIN: + case REGISTER: + return { + ...state, + inProgress: false, + errors: action.error ? action.payload.errors : null + }; + case LOGIN_PAGE_UNLOADED: + case REGISTER_PAGE_UNLOADED: + return {}; + case ASYNC_START: + if (action.subtype === LOGIN || action.subtype === REGISTER) { + return { ...state, inProgress: true }; + } + break; + case UPDATE_FIELD_AUTH: + return { ...state, [action.key]: action.value }; + default: + return state; + } + + return state; +}; diff --git a/conduit-front/src/reducers/common.js b/conduit-front/src/reducers/common.js new file mode 100644 index 0000000..f95b2bb --- /dev/null +++ b/conduit-front/src/reducers/common.js @@ -0,0 +1,70 @@ +import { + APP_LOAD, + REDIRECT, + LOGOUT, + ARTICLE_SUBMITTED, + SETTINGS_SAVED, + LOGIN, + REGISTER, + DELETE_ARTICLE, + ARTICLE_PAGE_UNLOADED, + EDITOR_PAGE_UNLOADED, + HOME_PAGE_UNLOADED, + PROFILE_PAGE_UNLOADED, + PROFILE_FAVORITES_PAGE_UNLOADED, + SETTINGS_PAGE_UNLOADED, + LOGIN_PAGE_UNLOADED, + REGISTER_PAGE_UNLOADED +} from '../constants/actionTypes'; + +const defaultState = { + appName: 'Conduit', + token: null, + viewChangeCounter: 0 +}; + +export default (state = defaultState, action) => { + switch (action.type) { + case APP_LOAD: + return { + ...state, + token: action.token || null, + appLoaded: true, + currentUser: action.payload ? action.payload.user : null + }; + case REDIRECT: + return { ...state, redirectTo: null }; + case LOGOUT: + return { ...state, redirectTo: '/', token: null, currentUser: null }; + case ARTICLE_SUBMITTED: + const redirectUrl = `/article/${action.payload.article.slug}`; + return { ...state, redirectTo: redirectUrl }; + case SETTINGS_SAVED: + return { + ...state, + redirectTo: action.error ? null : '/', + currentUser: action.error ? null : action.payload.user + }; + case LOGIN: + case REGISTER: + return { + ...state, + redirectTo: action.error ? null : '/', + token: action.error ? null : action.payload.user.token, + currentUser: action.error ? null : action.payload.user + }; + case DELETE_ARTICLE: + return { ...state, redirectTo: '/' }; + case ARTICLE_PAGE_UNLOADED: + case EDITOR_PAGE_UNLOADED: + case HOME_PAGE_UNLOADED: + case PROFILE_PAGE_UNLOADED: + case PROFILE_FAVORITES_PAGE_UNLOADED: + case SETTINGS_PAGE_UNLOADED: + case LOGIN_PAGE_UNLOADED: + case REGISTER_PAGE_UNLOADED: + return { ...state, viewChangeCounter: state.viewChangeCounter + 1 }; + default: + return state; + } +}; diff --git a/conduit-front/src/reducers/editor.js b/conduit-front/src/reducers/editor.js new file mode 100644 index 0000000..fd45633 --- /dev/null +++ b/conduit-front/src/reducers/editor.js @@ -0,0 +1,54 @@ +import { + EDITOR_PAGE_LOADED, + EDITOR_PAGE_UNLOADED, + ARTICLE_SUBMITTED, + ASYNC_START, + ADD_TAG, + REMOVE_TAG, + UPDATE_FIELD_EDITOR +} from '../constants/actionTypes'; + +export default (state = {}, action) => { + switch (action.type) { + case EDITOR_PAGE_LOADED: + return { + ...state, + articleSlug: action.payload ? action.payload.article.slug : '', + title: action.payload ? action.payload.article.title : '', + description: action.payload ? action.payload.article.description : '', + body: action.payload ? action.payload.article.body : '', + tagInput: '', + tagList: action.payload ? action.payload.article.tagList : [] + }; + case EDITOR_PAGE_UNLOADED: + return {}; + case ARTICLE_SUBMITTED: + return { + ...state, + inProgress: null, + errors: action.error ? action.payload.errors : null + }; + case ASYNC_START: + if (action.subtype === ARTICLE_SUBMITTED) { + return { ...state, inProgress: true }; + } + break; + case ADD_TAG: + return { + ...state, + tagList: state.tagList.concat([state.tagInput]), + tagInput: '' + }; + case REMOVE_TAG: + return { + ...state, + tagList: state.tagList.filter(tag => tag !== action.tag) + }; + case UPDATE_FIELD_EDITOR: + return { ...state, [action.key]: action.value }; + default: + return state; + } + + return state; +}; diff --git a/conduit-front/src/reducers/home.js b/conduit-front/src/reducers/home.js new file mode 100644 index 0000000..c1cd49a --- /dev/null +++ b/conduit-front/src/reducers/home.js @@ -0,0 +1,15 @@ +import { HOME_PAGE_LOADED, HOME_PAGE_UNLOADED } from '../constants/actionTypes'; + +export default (state = {}, action) => { + switch (action.type) { + case HOME_PAGE_LOADED: + return { + ...state, + tags: action.payload[0].tags + }; + case HOME_PAGE_UNLOADED: + return {}; + default: + return state; + } +}; diff --git a/conduit-front/src/reducers/profile.js b/conduit-front/src/reducers/profile.js new file mode 100644 index 0000000..5e67a79 --- /dev/null +++ b/conduit-front/src/reducers/profile.js @@ -0,0 +1,24 @@ +import { + PROFILE_PAGE_LOADED, + PROFILE_PAGE_UNLOADED, + FOLLOW_USER, + UNFOLLOW_USER +} from '../constants/actionTypes'; + +export default (state = {}, action) => { + switch (action.type) { + case PROFILE_PAGE_LOADED: + return { + ...action.payload[0].profile + }; + case PROFILE_PAGE_UNLOADED: + return {}; + case FOLLOW_USER: + case UNFOLLOW_USER: + return { + ...action.payload.profile + }; + default: + return state; + } +}; diff --git a/conduit-front/src/reducers/settings.js b/conduit-front/src/reducers/settings.js new file mode 100644 index 0000000..8e3751e --- /dev/null +++ b/conduit-front/src/reducers/settings.js @@ -0,0 +1,25 @@ +import { + SETTINGS_SAVED, + SETTINGS_PAGE_UNLOADED, + ASYNC_START +} from '../constants/actionTypes'; + +export default (state = {}, action) => { + switch (action.type) { + case SETTINGS_SAVED: + return { + ...state, + inProgress: false, + errors: action.error ? action.payload.errors : null + }; + case SETTINGS_PAGE_UNLOADED: + return {}; + case ASYNC_START: + return { + ...state, + inProgress: true + }; + default: + return state; + } +}; diff --git a/conduit-front/src/store.js b/conduit-front/src/store.js new file mode 100644 index 0000000..185d866 --- /dev/null +++ b/conduit-front/src/store.js @@ -0,0 +1,25 @@ +import { applyMiddleware, createStore } from 'redux'; +import { createLogger } from 'redux-logger' +import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly'; +import { promiseMiddleware, localStorageMiddleware } from './middleware'; +import reducer from './reducer'; + +import { routerMiddleware } from 'react-router-redux' +import createHistory from 'history/createBrowserHistory'; + +export const history = createHistory(); + +// Build the middleware for intercepting and dispatching navigation actions +const myRouterMiddleware = routerMiddleware(history); + +const getMiddleware = () => { + if (process.env.NODE_ENV === 'production') { + return applyMiddleware(myRouterMiddleware, promiseMiddleware, localStorageMiddleware); + } else { + // Enable additional logging in non-production environments. + return applyMiddleware(myRouterMiddleware, promiseMiddleware, localStorageMiddleware, createLogger()) + } +}; + +export const store = createStore( + reducer, composeWithDevTools(getMiddleware())); -- GitLab