Merge pull request #1 from sundowndev/develop

v1.0.0-rc1 release
master v1.0.0-rc1
Raphael Cerveaux 2018-11-16 10:35:42 +01:00 committed by GitHub
commit 7f6c442d39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 2657 additions and 161 deletions

2
.eslintignore Normal file
View File

@ -0,0 +1,2 @@
docs
ode_modules

3
.eslintrc.json Normal file
View File

@ -0,0 +1,3 @@
{
"extends": "airbnb-base"
}

9
.travis.yml Normal file
View File

@ -0,0 +1,9 @@
language: node_js
node_js:
- "7"
- "8"
before_script:
- npm install
script: npm run test

9
app/db/db.config.js Normal file
View File

@ -0,0 +1,9 @@
module.exports = {
name: 'api-mooc',
host: process.env.HOST_MONGODB || '127.0.0.1:27017',
opts: {
promiseLibrary: global.Promise,
useNewUrlParser: true,
useCreateIndex: true,
},
};

13
app/db/db.connect.js Normal file
View File

@ -0,0 +1,13 @@
const mongoose = require('mongoose');
const UserSchema = require.main.require('./app/models/user');
const NoteSchema = require.main.require('./app/models/note');
const db = require('./db.config');
mongoose.connect(`mongodb://${db.host}/${db.name}`, db.opts);
mongoose.connection.on('connected', () => {
mongoose.model('User', UserSchema);
mongoose.model('Note', NoteSchema);
});

View File

@ -1,9 +1,17 @@
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
const mongoose = require('mongoose');
var NoteSchema = new Schema({
title: String,
text: String
});
const { Schema } = mongoose;
module.exports = mongoose.model('Note', NoteSchema);
const NoteSchema = new Schema({
title: {
type: String, required: [true, "can't be blank"],
},
text: {
type: String, required: [true, "can't be blank"],
},
user: {
type: Schema.Types.ObjectId, ref: 'User',
},
}, { timestamps: true });
module.exports = NoteSchema;

View File

@ -1,11 +1,20 @@
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
const mongoose = require('mongoose');
var UserSchema = new Schema({
firstname: String,
lastname: String,
username: String,
password: String
});
const { Schema } = mongoose;
module.exports = mongoose.model('User', UserSchema);
const UserSchema = new Schema({
firstname: {
type: String, required: [true, "can't be blank"],
},
lastname: {
type: String, required: [true, "can't be blank"],
},
email: {
type: String, lowercase: true, unique: true, required: [true, "can't be blank"], index: true,
},
password: {
type: String, required: [true, "can't be blank"],
},
}, { timestamps: true });
module.exports = UserSchema;

46
app/routes/auth/index.js Normal file
View File

@ -0,0 +1,46 @@
const auth = require('express').Router();
const register = require('./register');
const login = require('./login');
const reset = require('./reset');
const RegisterValidation = require.main.require('./app/validation/register');
const LoginValidation = require.main.require('./app/validation/login');
/**
* @api {post} /auth/register Register
* @apiName Register
* @apiGroup Auth
*
* @apiParam {String} firstname Firstname of the user.
* @apiParam {String} lastname Lastname of the user.
* @apiParam {String} email email of the user.
* @apiParam {String} password password of the user.
*
* @apiSuccess {Array} Array Array of Note objects.
*/
auth.post('/register', RegisterValidation, register);
/**
* @api {post} /auth/login Get access token
* @apiName Login
* @apiGroup Auth
*
* @apiParam {String} email email of the user.
* @apiParam {String} password password of the user.
*
* @apiSuccess {string} access_token Access token.
*/
auth.post('/login', LoginValidation, login);
/**
* @api {post} /auth/reset-password Reset password
* @apiName ResetPass
* @apiGroup Auth
*
* @apiParam {String} email email of the user.
* @apiParam {String} password password of the user.
*/
auth.post('/rester-password', reset);
module.exports = auth;

46
app/routes/auth/login.js Normal file
View File

@ -0,0 +1,46 @@
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt-nodejs');
const secret = require.main.require('./config/secret');
module.exports = (req, res, next) => {
const User = mongoose.model('User');
User.findOne({
email: req.body.email,
}, (err, user) => {
if (err) throw err;
if (!user) {
return next({ status: 400, message: 'Authentication failed. User not found.' });
}
// check if password matches
return bcrypt.compare(req.body.password, user.password, (error, result) => {
if (result && !error) {
// if user is found and password is right create a token
const dataUser = {
id: user.id,
email: user.email,
};
const token = jwt.sign({ user: dataUser }, secret, { expiresIn: '12h' });
// return the information including token as JSON
return res.json({
success: true,
access_token: token,
user: {
_id: user.id,
firstname: user.firstname,
lastname: user.lastname,
email: user.email,
},
});
}
return next({ status: 401, message: 'Authentication failed. Wrong password.' });
});
});
};

View File

@ -0,0 +1,29 @@
const mongoose = require('mongoose');
const bcrypt = require('bcrypt-nodejs');
module.exports = (req, res, next) => {
const UserModel = mongoose.model('User');
const passwordHash = bcrypt.hashSync(req.body.password);
const User = new UserModel({
firstname: req.body.firstname,
lastname: req.body.lastname,
email: req.body.email,
password: passwordHash,
});
UserModel.countDocuments({ email: req.body.email }, (err, c) => {
if (c !== 0) {
return next({ status: 401, message: 'Email is already taken by another user.' });
}
return User.save((saveErr) => {
if (saveErr) {
return next({ status: 500, message: 'Database error', error: [saveErr] });
}
return res.status(201).json({ success: true, message: 'Success' });
});
});
};

View File

@ -1,5 +1,5 @@
module.exports = (req, res) => {
const user = req.model;
const user = {};
res.status(200).json({ user });
};

View File

@ -2,6 +2,7 @@ const routes = require('express').Router();
const bodyParser = require('body-parser');
// Require routes
const auth = require('./auth');
const user = require('./user');
const note = require('./note');
@ -11,15 +12,16 @@ routes.use(bodyParser.urlencoded({ extended: true }));
routes.use(bodyParser.json());
routes.use((req, res, next) => {
// do logging
console.log('Something is happening.');
next(); // make sure we go to the next routes and don't stop here
// do logging
console.log(`Resource requested: ${req.method} ${req.originalUrl}`);
next(); // make sure we go to the next routes and don't stop here
});
routes.get('/', (req, res) => {
res.status(200).json({ message: 'Hello world!' });
res.status(200).json({ success: true, message: 'Hello world!' });
});
routes.use('/auth', auth);
routes.use('/user', user);
routes.use('/note', note);

View File

@ -1,5 +0,0 @@
module.exports = (req, res) => {
const users = [];
res.status(200).json({ users });
};

18
app/routes/note/create.js Normal file
View File

@ -0,0 +1,18 @@
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
const NoteModel = mongoose.model('Note');
const { user } = jwt.decode(req.headers.authorization);
const Note = new NoteModel({ title: req.body.title, text: req.body.text, user: user.id });
Note.save((err) => {
if (err) {
return next({ status: 400, error: [err] });
}
return res.status(201).json(Note);
});
};

26
app/routes/note/delete.js Normal file
View File

@ -0,0 +1,26 @@
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
const NoteModel = mongoose.model('Note');
const { user } = jwt.decode(req.headers.authorization);
NoteModel.findOne({ _id: req.params.id }, (err, note) => {
if (err) return next({ status: 500, error: [err] });
if (!note) return next({ status: 404, message: 'Note does not exists.' });
if (note.user.toString() !== user.id) {
return next({ status: 403, message: 'Access forbidden.' });
}
note.delete();
const response = {
success: true,
message: 'Note successfully deleted',
};
return res.status(204).send(response);
});
};

View File

@ -1,33 +1,72 @@
const note = require('express').Router();
const all = require('./all');
const single = require('./single');
//const create = require('./create');
//const update = require('./update');
//const delete = require('./delete');
const create = require('./create');
const update = require('./update');
const remove = require('./delete');
const CreateValidation = require.main.require('./app/validation/note/create');
const UpdateValidation = require.main.require('./app/validation/note/update');
const Authentication = require.main.require('./app/validation/auth');
/**
* @api {get} /note Request all notes
* @api {get} /note/:id Get note
* @apiName GetNotes
* @apiGroup Note
*
* @apiSuccess {Array} Array Array of Note objects.
*/
note.get('/', all);
/**
* @api {get} /note/:id Request Note information
* @apiName GetNotes
* @apiGroup Note
*
* @apiParam {Number} id Notes unique ID.
* @apiParam {String} id Note unique ID.
*
* @apiSuccess {string} title Title of the note.
* @apiSuccess {string} text Text of the note.
*/
note.get('/:noteId', single);
note.get('/:id', Authentication, single);
//note.post('/', create)
//note.post('/:noteId', update)
//note.post('/:noteId', delete)
/**
* @api {post} /note Create note
* @apiName CreateNote
* @apiGroup Note
* @apiHeaderExample {json} Header-Example:
* {
* "Authorization": "<Access_Token>"
* }
*
* @apiSuccess {string} title Title of the note.
* @apiSuccess {string} text Text of the note.
*/
note.post('/', Authentication, CreateValidation, create);
/**
* @api {put} /note/:id Update note
* @apiName UpdateNote
* @apiGroup Note
*
* @apiParam {String} id Note unique ID.
*
* @apiSuccess {string} title Title of the note.
* @apiSuccess {string} text Text of the note.
*/
note.put('/:id', Authentication, UpdateValidation, update);
/**
* @api {delete} /note/:id Delete note
* @apiName DeleteNote
* @apiGroup Note
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true,
* "message": "Note successfully deleted."
* }
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 403 Not Found
* {
* "success": false,
* "message": "Access forbidden.",
* "errors": []
* }
*
* @apiParam {String} id Note unique ID.
*/
note.delete('/:id', Authentication, remove);
module.exports = note;

View File

@ -1,5 +1,20 @@
module.exports = (req, res) => {
const user = req.model;
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
res.status(200).json({ user });
module.exports = (req, res, next) => {
const NoteModel = mongoose.model('Note');
const { user } = jwt.decode(req.headers.authorization);
NoteModel.findOne({ _id: req.params.id })
.lean()
.exec()
.then((note) => {
if (note.user.toString() !== user.id) {
return next({ status: 403, message: 'Access forbidden.' });
}
return res.status(200).json(note);
})
.catch(() => next({ status: 404, message: 'Note does not exists.' }));
};

23
app/routes/note/update.js Normal file
View File

@ -0,0 +1,23 @@
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
const NoteModel = mongoose.model('Note');
const { user } = jwt.decode(req.headers.authorization);
NoteModel.findOne({ _id: req.params.id }, (err, note) => {
if (err) return next({ status: 500, error: [err] });
if (!note) return next({ status: 404, message: 'Note does not exists.' });
if (note.user.toString() !== user.id) {
return next({ status: 403, message: 'Access forbidden.' });
}
note.title = req.body.title || note.title;
note.text = req.body.text || note.text;
note.save();
return res.status(200).send(note);
});
};

View File

@ -1,5 +0,0 @@
module.exports = (req, res) => {
const users = [];
res.status(200).json({ users });
};

View File

@ -0,0 +1,5 @@
module.exports = (req, res) => {
const user = {};
res.status(200).json({ user });
};

View File

@ -1,36 +1,50 @@
const user = require('express').Router();
const all = require('./all');
const single = require('./single');
//const create = require('./create');
//const update = require('./update');
//const delete = require('./delete');
const profile = require('./profile');
const update = require('./update');
const remove = require('./delete');
const notes = require('./notes');
const Authentication = require.main.require('./app/validation/auth');
/**
* @api {get} /user Request all Users information
* @apiName GetUsers
* @apiGroup User
*
* @apiParam {Number} id Users unique ID.
*
* @apiSuccess {Array} Array Array of User objects.
*/
user.get('/', all);
/**
* @api {get} /user/:id Request User information
* @api {get} /user/me Get account information
* @apiName GetUser
* @apiGroup User
*
* @apiParam {Number} id Users unique ID.
*
* @apiSuccess {String} firstname Firstname of the User.
* @apiSuccess {String} lastname Lastname of the User.
* @apiSuccess {String} username Username of the User.
* @apiSuccess {String} email Email of the User.
*/
user.get('/:userId', single);
user.get('/me', Authentication, profile);
//user.post('/', create)
//user.post('/:userId', update)
//user.post('/:userId', delete)
/**
* @api {put} /user/me Update account information
* @apiName UpdateUser
* @apiGroup User
*
* @apiParam {String} Firstname new firstname.
* @apiParam {String} Lastname new lastname.
* @apiParam {String} Email new email address.
*
* @apiSuccess {Object} user User object.
*/
user.put('/me', Authentication, update);
/**
* @api {delete} /user/me Delete account
* @apiName DeleteUser
* @apiGroup User
*/
user.delete('/me', Authentication, remove);
/**
* @api {get} /user/me/notes Get all notes
* @apiName GetNotesByUserId
* @apiGroup User notes
*
* @apiSuccess {Array} Array Notes of the user.
*/
user.get('/me/notes', Authentication, notes);
module.exports = user;

15
app/routes/user/notes.js Normal file
View File

@ -0,0 +1,15 @@
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
module.exports = (req, res) => {
const NoteModel = mongoose.model('Note');
const { user } = jwt.decode(req.headers.authorization);
NoteModel.find({ user: user.id })
.lean()
.exec()
.then((notes) => {
res.status(200).json(notes);
});
};

View File

@ -0,0 +1,20 @@
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
const UserModel = mongoose.model('User');
const { user } = jwt.decode(req.headers.authorization);
return UserModel.findById(user.id, 'id firstname lastname email')
.lean()
.exec()
.then((result) => {
if (result === null) {
return next({ status: 401, message: 'User does not exists.' });
}
return res.status(200).json(result);
})
.catch(() => next({ status: 401, message: 'User does not exists.' }));
};

View File

@ -0,0 +1,5 @@
module.exports = (req, res) => {
const user = {};
res.status(200).json({ user });
};

View File

@ -1,5 +0,0 @@
var mongoose = require('mongoose');
mongoose.connect('mongodb://node:node@novus.modulusmongo.net:27017/Iganiq8o');
var User = require('./app/models/user');

27
app/validation/auth.js Normal file
View File

@ -0,0 +1,27 @@
const Joi = require('joi');
const jwt = require('jsonwebtoken');
const secret = require.main.require('./config/secret');
module.exports = (req, res, next) => {
const schema = Joi.object().keys({
access_token: Joi.string().required(),
});
Joi.validate({
access_token: req.headers.authorization,
},
schema, (validateErr) => {
if (validateErr) {
return next({ status: 401, error: validateErr.details });
}
return jwt.verify(req.headers.authorization, secret, (err, decoded) => {
if (err) {
return next({ status: 401, message: 'Token error.', error: [err] });
}
return next();
});
});
};

20
app/validation/login.js Normal file
View File

@ -0,0 +1,20 @@
const Joi = require('joi');
module.exports = (req, res, next) => {
const schema = Joi.object().keys({
email: Joi.string().email({ minDomainAtoms: 2 }).required(),
password: Joi.string().required(),
});
Joi.validate({
email: req.body.email,
password: req.body.password,
},
schema, (validateErr) => {
if (validateErr) {
return next({ status: 400, message: 'Form is invalid.', error: validateErr.details });
}
return next();
});
};

View File

@ -0,0 +1,20 @@
const Joi = require('joi');
module.exports = (req, res, next) => {
const schema = Joi.object().keys({
title: Joi.string().min(2).required(),
text: Joi.string().min(2).required(),
});
Joi.validate({
title: req.body.title,
text: req.body.text,
},
schema, (validateErr) => {
if (validateErr) {
return next({ status: 400, message: 'Form is invalid.', error: validateErr.details });
}
return next();
});
};

View File

@ -0,0 +1,20 @@
const Joi = require('joi');
module.exports = (req, res, next) => {
const schema = Joi.object().keys({
title: Joi.string().min(2),
text: Joi.string().min(2),
});
Joi.validate({
title: req.body.title,
text: req.body.text,
},
schema, (validateErr) => {
if (validateErr) {
return next({ status: 400, message: 'Form is invalid.', error: validateErr.details });
}
return next();
});
};

View File

@ -0,0 +1,24 @@
const Joi = require('joi');
module.exports = (req, res, next) => {
const schema = Joi.object().keys({
firstname: Joi.string().min(2).required(),
lastname: Joi.string().min(2).required(),
email: Joi.string().email({ minDomainAtoms: 2 }).required(),
password: Joi.string().required(),
});
Joi.validate({
firstname: req.body.firstname,
lastname: req.body.lastname,
email: req.body.email,
password: req.body.password,
},
schema, (validateErr) => {
if (validateErr) {
return next({ status: 400, message: 'Form is invalid.', error: validateErr.details });
}
return next();
});
};

4
config/database.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = {
secret: 'admin',
database: 'mongodb://localhost/mooc-api',
};

1
config/secret.js Normal file
View File

@ -0,0 +1 @@
module.exports = '#4r13lM00c!';

View File

@ -1,10 +1,87 @@
define({ "api": [
{
"type": "get",
"url": "/note",
"title": "Request all notes",
"name": "GetNotes",
"group": "Note",
"type": "post",
"url": "/auth/login",
"title": "Get access token",
"name": "Login",
"group": "Auth",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "username",
"description": "<p>username of the user.</p>"
},
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "password",
"description": "<p>password of the user.</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "access_token",
"description": "<p>Access token.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "app/routes/auth/index.js",
"groupTitle": "Auth"
},
{
"type": "post",
"url": "/auth/register",
"title": "Register",
"name": "Register",
"group": "Auth",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "firstname",
"description": "<p>Firstname of the user.</p>"
},
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "lastname",
"description": "<p>Lastname of the user.</p>"
},
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "username",
"description": "<p>username of the user.</p>"
},
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "password",
"description": "<p>password of the user.</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
@ -19,13 +96,93 @@ define({ "api": [
}
},
"version": "0.0.0",
"filename": "app/routes/auth/index.js",
"groupTitle": "Auth"
},
{
"type": "post",
"url": "/note",
"title": "Create note",
"name": "CreateNote",
"group": "Note",
"header": {
"examples": [
{
"title": "Header-Example:",
"content": "{\n \"Authorization\": \"<Access_Token>\"\n}",
"type": "json"
}
]
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "title",
"description": "<p>Title of the note.</p>"
},
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "text",
"description": "<p>Text of the note.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "app/routes/note/index.js",
"groupTitle": "Note"
},
{
"type": "delete",
"url": "/note/:id",
"title": "Delete note",
"name": "DeleteNote",
"group": "Note",
"success": {
"examples": [
{
"title": "Success-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"success\": true,\n \"message\": \"Note successfully deleted.\"\n}",
"type": "json"
}
]
},
"error": {
"examples": [
{
"title": "Error-Response:",
"content": "HTTP/1.1 403 Not Found\n{\n \"success\": false,\n \"message\": \"Access forbidden.\",\n \"errors\": []\n}",
"type": "json"
}
]
},
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "id",
"description": "<p>Note unique ID.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "app/routes/note/index.js",
"groupTitle": "Note"
},
{
"type": "get",
"url": "/note/:id",
"title": "Request Note information",
"title": "Get note",
"name": "GetNotes",
"group": "Note",
"parameter": {
@ -33,10 +190,10 @@ define({ "api": [
"Parameter": [
{
"group": "Parameter",
"type": "Number",
"type": "String",
"optional": false,
"field": "id",
"description": "<p>Notes unique ID.</p>"
"description": "<p>Note unique ID.</p>"
}
]
}
@ -66,24 +223,64 @@ define({ "api": [
"groupTitle": "Note"
},
{
"type": "get",
"url": "/user/:id",
"title": "Request User information",
"name": "GetUser",
"group": "User",
"type": "put",
"url": "/note/:id",
"title": "Update note",
"name": "UpdateNote",
"group": "Note",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "Number",
"type": "String",
"optional": false,
"field": "id",
"description": "<p>Users unique ID.</p>"
"description": "<p>Note unique ID.</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "title",
"description": "<p>Title of the note.</p>"
},
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "text",
"description": "<p>Text of the note.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "app/routes/note/index.js",
"groupTitle": "Note"
},
{
"type": "delete",
"url": "/user/me",
"title": "Delete account",
"name": "DeleteUser",
"group": "User",
"version": "0.0.0",
"filename": "app/routes/user/index.js",
"groupTitle": "User"
},
{
"type": "get",
"url": "/user/me",
"title": "Get user information",
"name": "GetUser",
"group": "User",
"success": {
"fields": {
"Success 200": [
@ -105,8 +302,31 @@ define({ "api": [
"group": "Success 200",
"type": "String",
"optional": false,
"field": "username",
"description": "<p>Username of the User.</p>"
"field": "email",
"description": "<p>Email of the User.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "app/routes/user/index.js",
"groupTitle": "User"
},
{
"type": "put",
"url": "/user/me",
"title": "Update account information",
"name": "UpdateUser",
"group": "User",
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "Object",
"optional": false,
"field": "user",
"description": "<p>User object.</p>"
}
]
}
@ -117,23 +337,10 @@ define({ "api": [
},
{
"type": "get",
"url": "/user",
"title": "Request all Users information",
"name": "GetUsers",
"group": "User",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "Number",
"optional": false,
"field": "id",
"description": "<p>Users unique ID.</p>"
}
]
}
},
"url": "/user/me/notes",
"title": "Get all notes",
"name": "GetNotesByUserId",
"group": "User_notes",
"success": {
"fields": {
"Success 200": [
@ -142,13 +349,13 @@ define({ "api": [
"type": "Array",
"optional": false,
"field": "Array",
"description": "<p>Array of User objects.</p>"
"description": "<p>Notes of the user.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "app/routes/user/index.js",
"groupTitle": "User"
"groupTitle": "User_notes"
}
] });

View File

@ -1,10 +1,87 @@
[
{
"type": "get",
"url": "/note",
"title": "Request all notes",
"name": "GetNotes",
"group": "Note",
"type": "post",
"url": "/auth/login",
"title": "Get access token",
"name": "Login",
"group": "Auth",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "username",
"description": "<p>username of the user.</p>"
},
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "password",
"description": "<p>password of the user.</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "access_token",
"description": "<p>Access token.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "app/routes/auth/index.js",
"groupTitle": "Auth"
},
{
"type": "post",
"url": "/auth/register",
"title": "Register",
"name": "Register",
"group": "Auth",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "firstname",
"description": "<p>Firstname of the user.</p>"
},
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "lastname",
"description": "<p>Lastname of the user.</p>"
},
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "username",
"description": "<p>username of the user.</p>"
},
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "password",
"description": "<p>password of the user.</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
@ -19,13 +96,93 @@
}
},
"version": "0.0.0",
"filename": "app/routes/auth/index.js",
"groupTitle": "Auth"
},
{
"type": "post",
"url": "/note",
"title": "Create note",
"name": "CreateNote",
"group": "Note",
"header": {
"examples": [
{
"title": "Header-Example:",
"content": "{\n \"Authorization\": \"<Access_Token>\"\n}",
"type": "json"
}
]
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "title",
"description": "<p>Title of the note.</p>"
},
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "text",
"description": "<p>Text of the note.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "app/routes/note/index.js",
"groupTitle": "Note"
},
{
"type": "delete",
"url": "/note/:id",
"title": "Delete note",
"name": "DeleteNote",
"group": "Note",
"success": {
"examples": [
{
"title": "Success-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"success\": true,\n \"message\": \"Note successfully deleted.\"\n}",
"type": "json"
}
]
},
"error": {
"examples": [
{
"title": "Error-Response:",
"content": "HTTP/1.1 403 Not Found\n{\n \"success\": false,\n \"message\": \"Access forbidden.\",\n \"errors\": []\n}",
"type": "json"
}
]
},
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "id",
"description": "<p>Note unique ID.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "app/routes/note/index.js",
"groupTitle": "Note"
},
{
"type": "get",
"url": "/note/:id",
"title": "Request Note information",
"title": "Get note",
"name": "GetNotes",
"group": "Note",
"parameter": {
@ -33,10 +190,10 @@
"Parameter": [
{
"group": "Parameter",
"type": "Number",
"type": "String",
"optional": false,
"field": "id",
"description": "<p>Notes unique ID.</p>"
"description": "<p>Note unique ID.</p>"
}
]
}
@ -66,24 +223,64 @@
"groupTitle": "Note"
},
{
"type": "get",
"url": "/user/:id",
"title": "Request User information",
"name": "GetUser",
"group": "User",
"type": "put",
"url": "/note/:id",
"title": "Update note",
"name": "UpdateNote",
"group": "Note",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "Number",
"type": "String",
"optional": false,
"field": "id",
"description": "<p>Users unique ID.</p>"
"description": "<p>Note unique ID.</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "title",
"description": "<p>Title of the note.</p>"
},
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "text",
"description": "<p>Text of the note.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "app/routes/note/index.js",
"groupTitle": "Note"
},
{
"type": "delete",
"url": "/user/me",
"title": "Delete account",
"name": "DeleteUser",
"group": "User",
"version": "0.0.0",
"filename": "app/routes/user/index.js",
"groupTitle": "User"
},
{
"type": "get",
"url": "/user/me",
"title": "Get user information",
"name": "GetUser",
"group": "User",
"success": {
"fields": {
"Success 200": [
@ -105,8 +302,31 @@
"group": "Success 200",
"type": "String",
"optional": false,
"field": "username",
"description": "<p>Username of the User.</p>"
"field": "email",
"description": "<p>Email of the User.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "app/routes/user/index.js",
"groupTitle": "User"
},
{
"type": "put",
"url": "/user/me",
"title": "Update account information",
"name": "UpdateUser",
"group": "User",
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "Object",
"optional": false,
"field": "user",
"description": "<p>User object.</p>"
}
]
}
@ -117,23 +337,10 @@
},
{
"type": "get",
"url": "/user",
"title": "Request all Users information",
"name": "GetUsers",
"group": "User",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "Number",
"optional": false,
"field": "id",
"description": "<p>Users unique ID.</p>"
}
]
}
},
"url": "/user/me/notes",
"title": "Get all notes",
"name": "GetNotesByUserId",
"group": "User_notes",
"success": {
"fields": {
"Success 200": [
@ -142,13 +349,13 @@
"type": "Array",
"optional": false,
"field": "Array",
"description": "<p>Array of User objects.</p>"
"description": "<p>Notes of the user.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "app/routes/user/index.js",
"groupTitle": "User"
"groupTitle": "User_notes"
}
]

View File

@ -8,7 +8,7 @@ define({
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
"time": "2018-11-12T15:27:44.007Z",
"time": "2018-11-15T18:00:50.902Z",
"url": "http://apidocjs.com",
"version": "0.17.7"
}

View File

@ -8,7 +8,7 @@
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
"time": "2018-11-12T15:27:44.007Z",
"time": "2018-11-15T18:00:50.902Z",
"url": "http://apidocjs.com",
"version": "0.17.7"
}

View File

@ -1,3 +1,5 @@
require('./app/db/db.connect');
const express = require('express');
const routes = require('./app/routes');
@ -7,6 +9,15 @@ const port = process.env.PORT || 8080; // set our port
app.use('/', routes);
app.use((err, req, res, next) => {
res.status(err.status || 400).json({ success: false, message: err.message || 'An error occured.', errors: err.error || [] });
});
app.use((req, res) => {
res.status(404).json({ success: false, message: 'Resource not found.' });
});
// Start the server
app.listen(port);
console.log('Server started on port ' + port);
console.log(`Server started on port ${port}`);

1592
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,19 +4,29 @@
"description": "",
"main": "index.js",
"dependencies": {
"bcrypt-nodejs": "0.0.3",
"body-parser": "^1.18.3",
"express": "^4.16.4",
"mongoose": "^5.3.11"
"joi": "^14.0.6",
"jsonwebtoken": "^8.3.0",
"mongoose": "^5.3.11",
"passport": "^0.4.0"
},
"devDependencies": {
"apidoc": "^0.17.7"
"apidoc": "^0.17.7",
"eslint": "^5.9.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jsx-a11y": "^6.1.2",
"eslint-plugin-react": "^7.11.1"
},
"apidoc": {
"title": "Mooc API"
},
"scripts": {
"doc":"apidoc -i ./app/routes -o ./docs",
"test": "echo \"Error: no test specified\" && exit 1"
"docs": "apidoc -i ./app/routes -o ./docs",
"test": "eslint ./ && npm run docs"
},
"repository": {
"type": "git",

12
todo.md Normal file
View File

@ -0,0 +1,12 @@
# To do list
### Routes
- PUT /user/me (si tu vois password et new password, ou mets une autre route si tu veux) (200 ok avec le user après édition mais sans mot de passe bien sûr)
- DELETE /users/me (supprimer le profil) (204 no content, car le user est supprimé et tu ne me renvoi rien)
- POST /auth/rester-password (email) (optionnel si tu te sens pas chaud) (200 ok)
### Other
- eslint test
- build test