first version of the OpenBikeSensor Web API

This commit is contained in:
root 2020-04-13 02:02:40 +02:00
parent eebc3cf927
commit 02e78c7b38
22 changed files with 11844 additions and 74 deletions

81
.gitignore vendored
View file

@ -1,104 +1,37 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.DS_Store
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Dependency directory
node_modules
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
.idea

84
app.js Normal file
View file

@ -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('mongodb://localhost/obs');
} else {
mongoose.connect('mongodb://localhost/obsTest');
mongoose.set('debug', true);
}
require('./models/User');
require('./models/Track');
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);
});

3
config/index.js Normal file
View file

@ -0,0 +1,3 @@
module.exports = {
secret: process.env.NODE_ENV === 'production' ? process.env.SECRET : 'secret'
};

18
config/passport.js Normal file
View file

@ -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);
}));

56
models/Article.js Normal file
View file

@ -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});
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);

19
models/Comment.js Normal file
View file

@ -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});
// 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);

42
models/Track.js Normal file
View file

@ -0,0 +1,42 @@
var mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');
var slug = require('slug');
var User = mongoose.model('User');
var TrackSchema = new mongoose.Schema({
slug: {type: String, lowercase: true, unique: true},
title: String,
description: String,
body: String,
numEvents: {type: Number, default: 0},
author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
}, {timestamps: true});
TrackSchema.plugin(uniqueValidator, {message: 'is already taken'});
TrackSchema.pre('validate', function(next){
if(!this.slug) {
this.slugify();
}
next();
});
TrackSchema.methods.slugify = function() {
this.slug = slug(this.title) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36);
};
TrackSchema.methods.toJSONFor = function(user){
return {
slug: this.slug,
title: this.title,
description: this.description,
body: this.body,
createdAt: this.createdAt,
updatedAt: this.updatedAt,
visibleForAll: user ? user.areTracksVisibleForAll : false,
author: this.author.toProfileJSONFor(user)
};
};
mongoose.model('Track', TrackSchema);

105
models/User.js Normal file
View file

@ -0,0 +1,105 @@
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' }],
areTracksVisibleForAll: Boolean,
hash: String,
salt: String
}, {timestamps: 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.areTracksVisibleForAll = function(id){
// return this.areTracksVisibleForAll();
//};
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);

5405
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

43
package.json Normal file
View file

@ -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": "5.6.11",
"mongoose-unique-validator": "2.0.3",
"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"
}
}

BIN
project-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

0
public/.keep Normal file
View file

22
routes/api/index.js Normal file
View file

@ -0,0 +1,22 @@
var router = require('express').Router();
router.use('/', require('./users'));
router.use('/profiles', require('./profiles'));
router.use('/tracks', require('./tracks'));
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;

53
routes/api/profiles.js Normal file
View file

@ -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;

12
routes/api/tags.js Normal file
View file

@ -0,0 +1,12 @@
var router = require('express').Router();
var mongoose = require('mongoose');
var Track = mongoose.model('Track');
// return a list of tags
router.get('/', function(req, res, next) {
Track.find().distinct('tagList').then(function(tags){
return res.json({tags: tags});
}).catch(next);
});
module.exports = router;

326
routes/api/tracks.js Normal file
View file

@ -0,0 +1,326 @@
var router = require('express').Router();
var mongoose = require('mongoose');
var Track = mongoose.model('Track');
var Comment = mongoose.model('Comment');
var User = mongoose.model('User');
var auth = require('../auth');
// Preload track objects on routes with ':track'
router.param('track', function(req, res, next, slug) {
Track.findOne({ slug: slug})
.populate('author')
.then(function (track) {
if (!track) { return res.sendStatus(404); }
req.track = track;
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([
Track.find(query)
.limit(Number(limit))
.skip(Number(offset))
.sort({createdAt: 'desc'})
.populate('author')
.exec(),
Track.count(query).exec(),
req.payload ? User.findById(req.payload.id) : null,
]).then(function(results){
var tracks = results[0];
var tracksCount = results[1];
var user = results[2];
return res.json({
tracks: tracks.map(function(track){
return track.toJSONFor(user);
}),
tracksCount: tracksCount
});
});
}).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); }
if(user.following != '')
{
Promise.all([
Track.find({ author: {$in: user.following}})
.limit(Number(limit))
.skip(Number(offset))
.populate('author')
.exec(),
Track.count({ author: {$in: user.following}})
]).then(function(results){
var tracks = results[0];
var tracksCount = results[1];
return res.json({
tracks: tracks.map(function(track){
return track.toJSONFor(user);
}),
tracksCount: tracksCount
});
}).catch(next);
}
else
{
Promise.all([
Track.find({ author: {$in: req.payload.id}})
.limit(Number(limit))
.skip(Number(offset))
.populate('author')
.exec(),
Track.count({ author: {$in: req.payload.id}})
]).then(function(results){
var tracks = results[0];
var tracksCount = results[1];
return res.json({
tracks: tracks.map(function(track){
return track.toJSONFor(user);
}),
tracksCount: tracksCount
});
}).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 track = new Track(req.body.track);
track.author = user;
return track.save().then(function(){
console.log(track.author);
return res.json({track: track.toJSONFor(user)});
});
}).catch(next);
});
router.post('/add', auth.optional, function(req, res, next) {
console.log("Add");
if(true)
{
console.log(req.body);
console.log(req.payload);
User.findById(req.body.id).then(function(user){
if (!user) { return res.sendStatus(401); }
var track = new Track(req.body.track);
track.author = user;
return track.save().then(function(){
console.log(track.author);
return res.json({track: track.toJSONFor(user)});
});
}).catch(next);
}
});
// return a track
router.get('/:track', auth.optional, function(req, res, next) {
Promise.all([
req.payload ? User.findById(req.payload.id) : null,
req.track.populate('author').execPopulate()
]).then(function(results){
var user = results[0];
return res.json({track: req.track.toJSONFor(user)});
}).catch(next);
});
// update track
router.put('/:track', auth.required, function(req, res, next) {
User.findById(req.payload.id).then(function(user){
if(req.track.author._id.toString() === req.payload.id.toString()){
if(typeof req.body.track.title !== 'undefined'){
req.track.title = req.body.track.title;
}
if(typeof req.body.track.description !== 'undefined'){
req.track.description = req.body.track.description;
}
if(typeof req.body.track.body !== 'undefined'){
req.track.body = req.body.track.body;
}
if(typeof req.body.track.tagList !== 'undefined'){
req.track.tagList = req.body.track.tagList
}
req.track.save().then(function(track){
return res.json({track: track.toJSONFor(user)});
}).catch(next);
} else {
return res.sendStatus(403);
}
});
});
// delete track
router.delete('/:track', auth.required, function(req, res, next) {
User.findById(req.payload.id).then(function(user){
if (!user) { return res.sendStatus(401); }
if(req.track.author._id.toString() === req.payload.id.toString()){
return req.track.remove().then(function(){
return res.sendStatus(204);
});
} else {
return res.sendStatus(403);
}
}).catch(next);
});
// Favorite an track
router.post('/:track/favorite', auth.required, function(req, res, next) {
var trackId = req.track._id;
User.findById(req.payload.id).then(function(user){
if (!user) { return res.sendStatus(401); }
return user.favorite(trackId).then(function(){
return req.track.updateFavoriteCount().then(function(track){
return res.json({track: track.toJSONFor(user)});
});
});
}).catch(next);
});
// Unfavorite an track
router.delete('/:track/favorite', auth.required, function(req, res, next) {
var trackId = req.track._id;
User.findById(req.payload.id).then(function (user){
if (!user) { return res.sendStatus(401); }
return user.unfavorite(trackId).then(function(){
return req.track.updateFavoriteCount().then(function(track){
return res.json({track: track.toJSONFor(user)});
});
});
}).catch(next);
});
// return an track's comments
router.get('/:track/comments', auth.optional, function(req, res, next){
Promise.resolve(req.payload ? User.findById(req.payload.id) : null).then(function(user){
return req.track.populate({
path: 'comments',
populate: {
path: 'author'
},
options: {
sort: {
createdAt: 'desc'
}
}
}).execPopulate().then(function(track) {
return res.json({comments: req.track.comments.map(function(comment){
return comment.toJSONFor(user);
})});
});
}).catch(next);
});
// create a new comment
router.post('/:track/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.track = req.track;
comment.author = user;
return comment.save().then(function(){
req.track.comments.push(comment);
return req.track.save().then(function(track) {
res.json({comment: comment.toJSONFor(user)});
});
});
}).catch(next);
});
router.delete('/:track/comments/:comment', auth.required, function(req, res, next) {
if(req.comment.author.toString() === req.payload.id.toString()){
req.track.comments.remove(req.comment._id);
req.track.save()
.then(Comment.find({_id: req.comment._id}).remove().exec())
.then(function(){
res.sendStatus(204);
});
} else {
res.sendStatus(403);
}
});
module.exports = router;

75
routes/api/users.js Normal file
View file

@ -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;

27
routes/auth.js Normal file
View file

@ -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;

5
routes/index.js Normal file
View file

@ -0,0 +1,5 @@
var router = require('express').Router();
router.use('/api', require('./api'));
module.exports = router;

1900
tests/api-tests.postman.json Normal file

File diff suppressed because it is too large Load diff

View file

@ -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"
}

3628
yarn.lock Normal file

File diff suppressed because it is too large Load diff