diff --git a/.env b/.env index eabe5fa..db14a07 100644 --- a/.env +++ b/.env @@ -4,14 +4,14 @@ DEBUG=false SERVER_PORT="3201" SECRET="$2b$10$2.JkQCRUa3fXESy/WyKVWO" SESSION_LIFETIME="3600" -MONGODB_URI="mongodb://localhost:27017/adastradb" +MONGODB_URI="mongodb://localhost:27017/headupdb" SENDGRID_API_KEY="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" SENDGRID_FROM_MAIL="contact@rampeur.fr" SENDGRID_TO_MAIL="rampeur@gmail.com" AUTHORIZATION_PREFIX="Api-Key" COUCHDB_URL="http://couchdb.unespace.com" -COUCHDB_DATABASE="adastradb" -COUCHDB_DESIGN="adastra_app" +COUCHDB_DATABASE="headupdb" +COUCHDB_DESIGN="headup_app" COUCHDB_CREDENTIAL="cmFtcGV1cjpES3hwMjRQUw==" SKYDIVERID_API_URL="https://skydiver.id/api" SKYDIVERID_API_TOKEN="xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu" diff --git a/.env.development b/.env.development index 90eaad0..71bc58b 100644 --- a/.env.development +++ b/.env.development @@ -4,14 +4,14 @@ DEBUG=false SERVER_PORT="3201" SECRET="$2b$10$2.JkQCRUa3fXESy/WyKVWO" SESSION_LIFETIME=3600 -MONGODB_URI="mongodb://localhost:27017/adastradb" +MONGODB_URI="mongodb://localhost:27017/headupdb" SENDGRID_API_KEY="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" SENDGRID_FROM_MAIL="contact@rampeur.fr" SENDGRID_TO_MAIL="rampeur@gmail.com" AUTHORIZATION_PREFIX="Api-Key" COUCHDB_URL="http://couchdb.unespace.com" -COUCHDB_DATABASE="adastradb" -COUCHDB_DESIGN="adastra_app" +COUCHDB_DATABASE="headupdb" +COUCHDB_DESIGN="headup_app" COUCHDB_CREDENTIAL="cmFtcGV1cjpES3hwMjRQUw==" SKYDIVERID_API_URL="https://skydiver.id/api" SKYDIVERID_API_TOKEN="xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu" diff --git a/.env.local b/.env.local index 64813c6..e21119e 100644 --- a/.env.local +++ b/.env.local @@ -4,14 +4,14 @@ DEBUG=false SERVER_PORT="3201" SECRET="$2b$10$2.JkQCRUa3fXESy/WyKVWO" SESSION_LIFETIME=3600 -MONGODB_URI="mongodb://localhost:27017/adastradb" +MONGODB_URI="mongodb://localhost:27017/headupdb" SENDGRID_API_KEY="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" SENDGRID_FROM_MAIL="contact@rampeur.fr" SENDGRID_TO_MAIL="rampeur@gmail.com" AUTHORIZATION_PREFIX="Api-Key" COUCHDB_URL="http://couchdb.unespace.com" -COUCHDB_DATABASE="adastradb" -COUCHDB_DESIGN="adastra_app" +COUCHDB_DATABASE="headupdb" +COUCHDB_DESIGN="headup_app" COUCHDB_CREDENTIAL="cmFtcGV1cjpES3hwMjRQUw==" SKYDIVERID_API_URL="https://skydiver.id/api" SKYDIVERID_API_TOKEN="xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu" diff --git a/.env.production b/.env.production index 8fa8723..6fc2130 100644 --- a/.env.production +++ b/.env.production @@ -4,14 +4,14 @@ DEBUG=false SERVER_PORT="3201" SECRET="$2b$10$2.JkQCRUa3fXESy/WyKVWO" SESSION_LIFETIME=3600 -MONGODB_URI="mongodb://localhost:27017/adastradb" +MONGODB_URI="mongodb://localhost:27017/headupdb" SENDGRID_API_KEY="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" SENDGRID_FROM_MAIL="contact@rampeur.fr" SENDGRID_TO_MAIL="rampeur@gmail.com" AUTHORIZATION_PREFIX="Api-Key" COUCHDB_URL="http://couchdb.unespace.com" -COUCHDB_DATABASE="adastradb" -COUCHDB_DESIGN="adastra_app" +COUCHDB_DATABASE="headupdb" +COUCHDB_DESIGN="headup_app" COUCHDB_CREDENTIAL="cmFtcGV1cjpES3hwMjRQUw==" SKYDIVERID_API_URL="https://skydiver.id/api" SKYDIVERID_API_TOKEN="xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu" diff --git a/app.js b/app.js index fbedb15..a5c5423 100644 --- a/app.js +++ b/app.js @@ -66,9 +66,10 @@ if(isProduction){ require('./models/mongo'); require('./config/passport'); - +var userid = new mongoose.Types.ObjectId(); +console.log('userid: ', userid._id.toString()); connectDB(); -app.use(require('./routes')); +app.use(require('./src/routes')); app.use(exceptionHandler.notFoundErrorHandler); app.use(exceptionHandler.logErrorHandler); diff --git a/config/passport.js b/config/passport.js index 9000db4..04b982a 100644 --- a/config/passport.js +++ b/config/passport.js @@ -5,7 +5,9 @@ var LocalStrategy = require('passport-local').Strategy; var HeaderAPIKeyStrategy = require('passport-headerapikey').HeaderAPIKeyStrategy; var mongoose = require('mongoose'); var Application = mongoose.model('Application'); -var User = mongoose.model('User'); +//var User = mongoose.model('User'); +const { UserService } = require('../src/services'); + passport.use('headerapikey', new HeaderAPIKeyStrategy( { header: 'Authorization', prefix: `${process.env.AUTHORIZATION_PREFIX} ` }, @@ -19,32 +21,9 @@ passport.use('headerapikey', new HeaderAPIKeyStrategy( if (!application) { return done({message: "Application can't be found.", status: 404}, false, false); } - console.log('encryptedKey: ', encryptedKey); return done(null, application); }); }).catch(done); - /* - const salt = secret; - Promise.resolve(bcrypt.hash(apikey, salt)).then(function (encryptedKey) { - Application.findOne({ encryptedKey: encryptedKey }) - .populate('author') - .then(function (application) { - if (!application) { - return done({message: "Application can't be found.", status: 404}, false, false); - } - console.log('encryptedKey: ', encryptedKey); - return done(null, application); - return {app: application, prom: Promise.resolve(bcrypt.compare(apikey, application.apikey))}; - }).then(function (res) { - res.prom.then(function (valid) { - if (!valid) { - return done(null, false, {app: res.app, valid: valid}); - } - return done(null, res.app, valid); - }); - }); - }).catch(done); - */ } )); @@ -52,7 +31,9 @@ passport.use('local', new LocalStrategy({ usernameField: 'user[email]', passwordField: 'user[password]' }, function (email, password, done) { - User.findOne({ email: email }).then(function (user) { + UserService.getUserByEmail({ email }).then(function (user) { + //User.findOne({ email: email }).then(function (user) { + //console.log(user); if (!user || !user.validPassword(password)) { return done(null, false, { errors: { 'email ou mot de passe': 'invalide' } }); } diff --git a/models/mongo/User.js b/models/mongo/User.js index cf4538a..eb30511 100644 --- a/models/mongo/User.js +++ b/models/mongo/User.js @@ -37,9 +37,6 @@ UserSchema.methods.setPassword = function (password) { UserSchema.methods.generateJWT = function () { var today = new Date(); var exp = new Date(today.getTime() + (session_lifetime * 1000)); - console.log('Now date :', today.toISOString()); - console.log('Expiracy date :', exp.toISOString()); - console.log('Session lifetime :', session_lifetime); return jwt.sign({ id: this._id, diff --git a/nodemon.json b/nodemon.json index 59de8a0..b3ce0de 100644 --- a/nodemon.json +++ b/nodemon.json @@ -6,14 +6,14 @@ "SERVER_PORT": "3201", "SECRET": "$2b$10$aEsAUG7Dy8dcTORi1vaQle", "SESSION_LIFETIME": "3600", - "MONGODB_URI": "mongodb://localhost:27017/adastradb", + "MONGODB_URI": "mongodb://localhost:27017/headupdb", "SENDGRID_API_KEY": "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", "SENDGRID_FROM_MAIL": "contact@rampeur.fr", "SENDGRID_TO_MAIL": "rampeur@gmail.com", "AUTHORIZATION_PREFIX": "Api-Key", "COUCHDB_URL": "http://couchdb.unespace.com", - "COUCHDB_DATABASE": "adastradb", - "COUCHDB_DESIGN": "adastra_app", + "COUCHDB_DATABASE": "headupdb", + "COUCHDB_DESIGN": "headup_app", "COUCHDB_CREDENTIAL": "cmFtcGV1cjpES3hwMjRQUw==", "SKYDIVERID_API_URL": "https://skydiver.id/api", "SKYDIVERID_API_TOKEN": "xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu", diff --git a/src/controllers/article.controller.js b/src/controllers/article.controller.js index 46e46e5..c079ded 100644 --- a/src/controllers/article.controller.js +++ b/src/controllers/article.controller.js @@ -1,42 +1,60 @@ -const { ArticleService } = require('../services/article.service'); +const { ArticleService } = require('../services'); const createArticle = async (req, res) => { - try { - const { name, description, userId } = req.body; + try { + const { slug, title, description, body, authorId } = req.body; - const article = await ArticleService.createArticle({ - name, - description, - userId, - }); + const article = await ArticleService.createArticle({ + slug, + title, + description, + body, + authorId + }); - res.status(201).json({ - message: 'Article created successfully', - data: article, - }); - } catch (err) { - res.status(500).json({ - message: 'something went wrong while creating article', - error: err.message, - }); - } + res.status(201).json({ + message: 'Article created successfully', + data: article, + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while creating article', + error: err.message, + }); + } +}; + +const getAllArticles = async (req, res) => { + try { + const articles = await ArticleService.getAllArticles(); + + res.status(200).json({ + data: articles, + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while fetching articles', + error: err.message, + }); + } }; const getArticlesByUserId = async (req, res) => { - try { - const { userId } = req.params; + try { + const { authorId } = req.params; - const articles = await ArticleService.getArticlesByUserId(userId); + const articles = await ArticleService.getArticlesByUserId(authorId); - res.status(200).json({ - data: articles, - }); - } catch (err) { - res.status(500).json({ - message: 'something went wrong while fetching articles', - error: err.message, - }); - } + res.status(200).json({ + data: articles, + }); + } catch (err) { + console.log(err); + res.status(500).json({ + message: 'something went wrong while fetching articles', + error: err.message, + }); + } }; -module.exports = { createArticle, getArticlesByUserId }; \ No newline at end of file +module.exports = { createArticle, getAllArticles, getArticlesByUserId }; \ No newline at end of file diff --git a/src/controllers/comment.controller.js b/src/controllers/comment.controller.js new file mode 100644 index 0000000..e95a1b7 --- /dev/null +++ b/src/controllers/comment.controller.js @@ -0,0 +1,42 @@ +const { CommentService } = require('../services'); + +const createComment = async (req, res) => { + try { + const { slug, title, description, body, authorId } = req.body; + + const comment = await CommentService.createComment({ + slug, + title, + description, + body, + authorId + }); + + res.status(201).json({ + message: 'Comment created successfully', + data: comment, + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while creating comment', + error: err.message, + }); + } +}; + +const getAllComments = async (req, res) => { + try { + const comments = await CommentService.getAllComments(); + + res.status(200).json({ + data: comments, + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while fetching comments', + error: err.message, + }); + } +}; + +module.exports = { createComment, getAllComments }; \ No newline at end of file diff --git a/src/controllers/tag.controller.js b/src/controllers/tag.controller.js new file mode 100644 index 0000000..5e3665e --- /dev/null +++ b/src/controllers/tag.controller.js @@ -0,0 +1,42 @@ +const { TagService } = require('../services'); + +const createTag = async (req, res) => { + try { + const { slug, title, description, body, authorId } = req.body; + + const tag = await TagService.createTag({ + slug, + title, + description, + body, + authorId + }); + + res.status(201).json({ + message: 'Tag created successfully', + data: tag, + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while creating tag', + error: err.message, + }); + } +}; + +const getAllTags = async (req, res) => { + try { + const tags = await TagService.getAllTags(); + + res.status(200).json({ + data: tags, + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while fetching tags', + error: err.message, + }); + } +}; + +module.exports = { createTag, getAllTags }; \ No newline at end of file diff --git a/src/controllers/user.controller.js b/src/controllers/user.controller.js index a276102..0f9feba 100644 --- a/src/controllers/user.controller.js +++ b/src/controllers/user.controller.js @@ -1,36 +1,81 @@ -const { UserService } = require('../services/user.service'); +//const { UserService } = require('../services/user.service'); +const { UserService } = require('../services'); +const passport = require('passport'); const createUser = async (req, res) => { - try { - const { name, email } = req.body; + try { + const { name, email } = req.body; - const user = await UserService.createUser({ name, email }); + const user = await UserService.createUser({ name, email }); - res.status(201).json({ - message: 'User created successfully', - data: user, - }); - } catch (err) { - res.status(500).json({ - message: 'something went wrong while creating user', - error: err.message, - }); - } + res.status(201).json({ + message: 'User created successfully', + data: user, + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while creating user', + error: err.message, + }); + } }; const getAllUsers = async (req, res) => { - try { - const users = await UserService.getAllUsers(); + try { + const users = await UserService.getAllUsers(); - res.status(200).json({ - data: users, - }); - } catch (err) { - res.status(500).json({ - message: 'something went wrong while fetching users', - error: err.message, - }); - } + res.status(200).json({ + data: users, + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while fetching users', + error: err.message, + }); + } }; -module.exports = { createUser, getAllUsers }; \ No newline at end of file +const getUser = async (req, res) => { + try { + const user = await UserService.getUserById(req.payload.id); + + console.log(req.payload); + res.status(200).json({ + user: user.toAuthJSON(), + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while fetching user', + error: err.message, + }); + } +}; + +const loginAsUser = async (req, res, next) => { + try { + if (!req.body.user.email) { + return res.status(422).json({ errors: { email: "email can't be blank" } }); + } + if (!req.body.user.password) { + return res.status(422).json({ errors: { password: " 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); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while fetching users', + error: err.message, + }); + } +}; + +module.exports = { createUser, getAllUsers, getUser, loginAsUser }; \ No newline at end of file diff --git a/src/database/index.js b/src/database/index.js index b6e92cc..b955f24 100644 --- a/src/database/index.js +++ b/src/database/index.js @@ -1,11 +1,15 @@ const sequelize = require('./config/sequelize'); const ArticleModel = require('./models/article'); +const CommentModel = require('./models/comment'); +const TagModel = require('./models/tag'); const UserModel = require('./models/user'); const DB = { sequelize, User: UserModel(sequelize), Article: ArticleModel(sequelize), + Comment: CommentModel(sequelize), + Tag: TagModel(sequelize), }; module.exports = DB; diff --git a/src/database/models/comment.js b/src/database/models/comment.js index e69de29..c56352f 100644 --- a/src/database/models/comment.js +++ b/src/database/models/comment.js @@ -0,0 +1,32 @@ +const { DataTypes, Model } = require("sequelize"); +const sequelize = require("../config/sequelize"); + +class Comment extends Model { } + +const CommentModel = () => { + Comment.init( + { + id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, allowNull: false }, + body: { type: DataTypes.TEXT, allowNull: false } + }, + { + sequelize, + modelName: 'Comment', + tableName: 'comment', + timestamps: true, + createdAt: true, + updatedAt: true + } + ); + + Comment.prototype.toJSONFor = function () { + return { + id: this.id, + body: this.body + }; + }; + + return Comment; +}; + +module.exports = CommentModel; diff --git a/src/database/models/tag.js b/src/database/models/tag.js index e69de29..11c5590 100644 --- a/src/database/models/tag.js +++ b/src/database/models/tag.js @@ -0,0 +1,30 @@ +const { DataTypes, Model } = require("sequelize"); +const sequelize = require("../config/sequelize"); + +class Tag extends Model { } + +const TagModel = () => { + Tag.init( + { + name: { type: DataTypes.STRING, primaryKey: true, allowNull: false } + }, + { + sequelize, + modelName: 'Tag', + tableName: 'tag', + timestamps: true, + createdAt: true, + updatedAt: true + } + ); + + Tag.prototype.toJSONFor = function () { + return { + name: this.name + }; + }; + + return Tag; +}; + +module.exports = TagModel; diff --git a/src/database/models/user.js b/src/database/models/user.js index 05e4c9e..0ac429e 100644 --- a/src/database/models/user.js +++ b/src/database/models/user.js @@ -1,13 +1,18 @@ const { DataTypes, Model } = require("sequelize"); +var crypto = require('crypto'); +var jwt = require('jsonwebtoken'), + secret = require('../../../config').secret, + session_lifetime = require('../../../config').session_lifetime; + const sequelize = require("../config/sequelize"); -const bcrypt = require("bcrypt"); +//const bcrypt = require("bcrypt"); class User extends Model { } const UserModel = () => { User.init( { - id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, allowNull: false }, + _id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, allowNull: false }, email: { type: DataTypes.STRING, allowNull: false, unique: true }, username: { type: DataTypes.STRING, allowNull: false, unique: true }, firstname: { type: DataTypes.STRING }, @@ -15,18 +20,20 @@ const UserModel = () => { bio: { type: DataTypes.TEXT, allowNull: true }, image: { type: DataTypes.TEXT, allowNull: true }, role: { type: DataTypes.STRING }, - password: { type: DataTypes.STRING, allowNull: false } + salt: { type: DataTypes.STRING, allowNull: false }, + hash: { type: DataTypes.TEXT, allowNull: false } }, { sequelize, modelName: 'User', tableName: 'user', - timestamps: false, + timestamps: true, createdAt: true, updatedAt: true } ); + /* Model.prototype.matchPassword = async function (enteredPassword) { return await bcrypt.compare(enteredPassword, this.password); }; @@ -40,10 +47,49 @@ const UserModel = () => { ); user.password = encryptedPassword; }); + */ + + User.prototype.validPassword = function (password) { + let hash = crypto.pbkdf2Sync(password, this.salt, 10000, 512, 'sha512').toString('hex'); + return this.hash === hash; + }; + + User.prototype.setPassword = function (password) { + this.salt = crypto.randomBytes(16).toString('hex'); + this.hash = crypto.pbkdf2Sync(password, this.salt, 10000, 512, 'sha512').toString('hex'); + }; + + User.prototype.generateJWT = function () { + var today = new Date(); + var exp = new Date(today.getTime() + (session_lifetime * 1000)); + + return jwt.sign({ + id: this._id, + username: this.username, + exp: parseInt(exp.getTime() / 1000) + }, secret, { algorithm: 'HS256' }); + }; + + User.prototype.toAuthJSON = function () { + return { + id: this._id, + email: this.email, + role: this.role, + token: this.generateJWT(), + firstname: this.firstname, + lastname: this.lastname, + /*phone: this.phone, + licence: this.licence, + poids: this.poids,*/ + username: this.username, + image: this.image || '/assets/images/users/user.jpg', + bg_image: this.bg_image || '/assets/images/users/bg_user.jpg' + }; + }; User.prototype.toJSONFor = function () { return { - id: this.id, + id: this._id, email: this.email, username: this.username, firstname: this.firstname, @@ -54,6 +100,21 @@ const UserModel = () => { }; }; + User.prototype.toProfileJSONFor = function (user) { + return { + email: this.email, + firstname: this.firstname, + lastname: this.lastname, + phone: this.phone, + licence: this.licence, + poids: this.poids, + username: this.username, + image: this.image || '/assets/images/users/user.jpg', + bg_image: this.bg_image || '/assets/images/users/bg_user.jpg', + following: user ? user.isFollowing(this._id) : false + }; + }; + return User; }; diff --git a/src/database/relationships/index.js b/src/database/relationships/index.js index 0614884..554a9d6 100644 --- a/src/database/relationships/index.js +++ b/src/database/relationships/index.js @@ -1,29 +1,29 @@ const DB = require('../index'); const associate = () => { + /* DB.User.hasMany(DB.Article, { - foreignKey: 'userId', - as: 'projects', + foreignKey: 'authorId', + onDelete: "CASCADE" }); DB.Article.belongsTo(DB.User, { - foreignKey: 'userId', - as: 'user', + foreignKey: 'authorId', + as: 'author', }); - /* - DB.User.belongsToMany(DB.User, { as: "followers", through: "Followers", foreignKey: "userId", timestamps: false }); - DB.User.belongsToMany(DB.User, { as: "following", through: "Followers", foreignKey: "followerId", timestamps: false }); + */ + DB.User.belongsToMany(DB.User, { as: "followers", through: "follower", foreignKey: "userId", timestamps: false }); + DB.User.belongsToMany(DB.User, { as: "following", through: "follower", foreignKey: "followerId", timestamps: false }); DB.User.hasMany(DB.Article, { foreignKey: "authorId", onDelete: "CASCADE" }); DB.Article.belongsTo(DB.User, { as: "author", foreignKey: "authorId" }); DB.User.hasMany(DB.Comment, { foreignKey: "authorId", onDelete: "CASCADE" }); DB.Comment.belongsTo(DB.User, { as: "author", foreignKey: "authorId" }); - DB.Article.hasMany(DB.omment, { foreignKey: "articleId", onDelete: "CASCADE" }); + DB.Article.hasMany(DB.Comment, { foreignKey: "articleId", onDelete: "CASCADE" }); DB.Comment.belongsTo(DB.Article, { foreignKey: "articleId" }); - DB.User.belongsToMany(DB.Article, { as: "favorites", through: "Favorites", timestamps: false }); - DB.Article.belongsToMany(DB.User, { through: "Favorites", foreignKey: "articleId", timestamps: false }); - DB.Article.belongsToMany(DB.Tag, { through: "TagLists", as: "tagLists", foreignKey: "articleId", timestamps: false, onDelete: "CASCADE" }); - DB.Tag.belongsToMany(DB.Article, { through: "ArticleTags", uniqueKey: false, timestamps: false }); - */ + DB.User.belongsToMany(DB.Article, { as: "favorites", through: "favorite", timestamps: false }); + DB.Article.belongsToMany(DB.User, { through: "favorite", foreignKey: "articleId", timestamps: false }); + DB.Article.belongsToMany(DB.Tag, { through: "tagList", as: "tagLists", foreignKey: "articleId", timestamps: false, onDelete: "CASCADE" }); + DB.Tag.belongsToMany(DB.Article, { through: "articleTag", uniqueKey: false, timestamps: false }); }; module.exports = associate; diff --git a/src/routes/api/aeronefs.js b/src/routes/api/aeronefs.js new file mode 100644 index 0000000..07e68d6 --- /dev/null +++ b/src/routes/api/aeronefs.js @@ -0,0 +1,143 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Jump = mongoose.model('Jump'), + User = mongoose.model('User'); +const auth = require('../auth'), + queries = require('../queries'); + + +router.get('/allByImat', auth.required, function (req, res, next) { + let limit = 25; + let 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.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let query = queries.getAeronefsByImatQuery(user._id.toString()); + Promise.all([ + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + //Aeronef.count(query) + ]).then(function (results) { + let aeronefs = results[0]; + //let aeronefsCount = results[1]; + return res.json({ + aeronefs: aeronefs.map(function (data) { + return { aeronef: data._id.aeronef, imat: data._id.imat, count: data.count }; + }), + aeronefsCount: aeronefs.length + }); + /* + return res.json({ + aeronefs: aeronefs.map(function (aeronef) { + return aeronef.toJSONFor(user); + }), + aeronefsCount: aeronefsCount + }); + */ + }).catch(next); + }).catch(next); +}); + +router.get('/allByImatByYear', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 50; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getAeronefsByImatByYearQuery(user._id.toString()); + + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let aeronefs = result.map(function (data) { + return { aeronef: data._id.aeronef, imat: data._id.imat, year: data._id.year, count: data.count }; + }); + return res.json({ + aeronefs: aeronefs, + aeronefsCount: aeronefs.length + }); + }).catch(next); + }).catch(next); + /* + let limit = 50; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': user._id.toString() } ] + } + } + }, { + '$project': { + '_id': 0, + 'aeronef': 1, + 'imat': 1, + 'year': { + '$year': '$date' + } + } + }, { + '$group': { + '_id': { + 'aeronef': '$aeronef', + 'imat': '$imat', + 'year': '$year' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + Promise.all([ + req.payload ? User.findById(req.payload.id) : null, + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + ]).then(function (results) { + let user = results[0]; + let aeronefs = results[1]; + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + return res.json({ + aeronefs: aeronefs, + aeronefsCount: aeronefs.length + }); + }).catch(next); + */ + +}); + +module.exports = router; diff --git a/src/routes/api/applications.js b/src/routes/api/applications.js new file mode 100644 index 0000000..409f43e --- /dev/null +++ b/src/routes/api/applications.js @@ -0,0 +1,173 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Application = mongoose.model('Application'), + User = mongoose.model('User'); +const auth = require('../auth'), + mailer = require('@sendgrid/mail'); + +mailer.setApiKey(process.env.SENDGRID_API_KEY); + +// Preload application objects on routes with ':application' +router.param('application', function (req, res, next, slug) { + Application.findOne({ slug: slug }) + .populate('author') + .then(function (application) { + if (!application) { + return res.sendStatus(404); + } + req.application = application; + return next(); + }).catch(next); +}); + +/** + * return all applications + */ +router.get('/', auth.required, function (req, res, next) { + let query = {}; + let limit = 25; + let 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.apikey !== 'undefined') { + query.apikey = req.query.apikey; + } + if (typeof req.query.maskedkey !== 'undefined') { + query.maskedkey = req.query.maskedkey; + } + + Promise.all([ + req.query.author ? User.findOne({ username: req.query.author }) : null + ]).then(function (author) { + if (author[0]) { + query.author = author[0]._id; + } + return Promise.all([ + Application.find(query) + .skip(Number(offset)) + .limit(Number(limit)) + .sort({ createdAt: 'desc' }) + .populate('author') + .exec(), + Application.count(query).exec(), + req.payload ? User.findById(req.payload.id) : null + ]).then(function (results) { + let applications = results[0]; + let applicationsCount = results[1]; + let user = results[2]; + + return res.json({ + applications: applications.map(function (application) { + return application.toJSONFor(user); + }), + applicationsCount: applicationsCount + }); + }); + }).catch(next); +}); + +/** + * save an application + */ +router.post('/', auth.required, function (req, res, next) { + Promise.all([ + User.findById(req.payload.id), + auth.generateAPIKey() + ]).then(function (results) { + let user = results[0]; + let keys = results[1]; + if (!user) { + return res.sendStatus(401).json({message: "Unauthorized - You are not allowed to access this resource."}); + } + let application = new Application(req.body.application); + application.author = user; + application.apikey = keys.encrypted; + application.maskedkey = keys.masked; + return application.save().then(function () { + let msg = { + to: user.email, + from: process.env.SENDGRID_FROM_MAIL, + subject: `Api-Key ${application.title}`, + text: `Votre Api-Key: ${keys.key}\nAttention, cette Api-Key doit être conservée et ne sera plus affichée.\n\n${application.title}\n${application.description}`, + html: `

${application.title}

+

+ Votre Api-Key: ${keys.key}
+ Attention, cette Api-Key doit être conservée et ne sera plus affichée. +

+
+

${application.description}

` + }; + mailer.send(msg).then(() => { + return res.json({ application: application.toJSONFor(user) }); + }) + .catch(err => { + res.sendStatus(500).json({message: "A SendGrid error occured while sending an email", err: err}); + }); + }); + }).catch(next); +}); + +/** + * return an application + */ +router.get('/:application', auth.required, function (req, res, next) { + Promise.all([ + req.payload ? User.findById(req.payload.id) : null, + req.application.populate('author') + ]).then(function (results) { + let user = results[0]; + return res.json({ application: req.application.toJSONFor(user) }); + }).catch(next); +}); + +/** + * update an application + */ +router.put('/:application', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (req.application.author._id.toString() === req.payload.id.toString()) { + if (typeof req.body.application.title !== 'undefined') { + req.application.title = req.body.application.title; + } + if (typeof req.body.application.description !== 'undefined') { + req.application.description = req.body.application.description; + } + if (typeof req.body.application.apikey !== 'undefined') { + req.application.apikey = req.body.application.apikey; + } + if (typeof req.body.application.maskedkey !== 'undefined') { + req.application.maskedkey = req.body.application.maskedkey; + } + req.application.save().then(function (application) { + return res.json({ application: application.toJSONFor(user) }); + }).catch(next); + } else { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + }); +}); + +/** + * delete an application + */ +router.delete('/:application', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (user.role == 'Admin' || req.application.author._id.toString() === req.payload.id.toString()) { + return req.application.remove().then(function () { + return res.json({ deleted: true }); + }); + } else { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + }).catch(next); +}); + +module.exports = router; diff --git a/src/routes/api/article.routes.js b/src/routes/api/article.routes.js index c6bb219..a9ac9f7 100644 --- a/src/routes/api/article.routes.js +++ b/src/routes/api/article.routes.js @@ -1,9 +1,11 @@ const express = require('express'); -const { createProject, getProjectsByUserId } = require('../../controllers/article.controller'); +const { createArticle, getAllArticles, getArticlesByUserId } = require('../../controllers/article.controller'); +const auth = require('../auth'); -const projectRouter = express.Router(); +const articleRouter = express.Router(); -projectRouter.post('/', createProject); -projectRouter.get('/:userId', getProjectsByUserId); +articleRouter.post('/', auth.required, createArticle); +articleRouter.get('/', auth.optional, getAllArticles); +articleRouter.get('/:authorId', auth.optional, getArticlesByUserId); -module.exports = projectRouter; +module.exports = articleRouter; diff --git a/src/routes/api/canopies.js b/src/routes/api/canopies.js new file mode 100644 index 0000000..0cff862 --- /dev/null +++ b/src/routes/api/canopies.js @@ -0,0 +1,166 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Jump = mongoose.model('Jump'), + User = mongoose.model('User'); +const auth = require('../auth'), + queries = require('../queries'); + +router.get('/', auth.required, function (req, res, next) { + let query = {}; + let limit = 25; + let 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.slug !== 'undefined') { + query.slug = req.query.slug; + } + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (user.role == 'Admin') { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + Jump.find(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let canopies = result; + return res.json({ + canopies: canopies, + canopiesCount: canopies.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allBySize', auth.required, function (req, res, next) { + let limit = 25; + let 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.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let query = queries.getCanopiesBySizeQuery(user._id.toString()); + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let canopies = result.map(function (data) { + return { taille: data._id.taille, count: data.count }; + }); + return res.json({ + canopies: canopies, + canopiesCount: canopies.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allBySizeByYear', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getCanopiesBySizeByYearQuery(user._id.toString()); + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let canopies = result.map(function (data) { + return { taille: data._id.taille, year: data._id.year, count: data.count }; + }); + //console.log(dropzones); + return res.json({ + canopies: canopies, + canopiesCount: canopies.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allBySizeByModel', auth.required, function (req, res, next) { + let limit = 25; + let 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.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let query = queries.getCanopiesBySizeByModelQuery(user._id.toString()); + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let canopies = result.map(function (data) { + return { taille: data._id.taille, voile: data._id.voile, count: data.count }; + }); + return res.json({ + canopies: canopies, + canopiesCount: canopies.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allBySizeByModelByYear', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getCanopiesBySizeByModelByYearQuery(user._id.toString()); + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let canopies = result.map(function (data) { + return { taille: data._id.taille, voile: data._id.voile, year: data._id.year, count: data.count }; + }); + return res.json({ + canopies: canopies, + canopiesCount: canopies.length + }); + }).catch(next); + }).catch(next); +}); + +module.exports = router; diff --git a/src/routes/api/comment.routes.js b/src/routes/api/comment.routes.js new file mode 100644 index 0000000..ee1ac74 --- /dev/null +++ b/src/routes/api/comment.routes.js @@ -0,0 +1,10 @@ +const express = require('express'); +const { createComment, getAllComments } = require('../../controllers/comment.controller'); +const auth = require('../auth'); + +const commentRouter = express.Router(); + +commentRouter.post('/', auth.required, createComment); +commentRouter.get('/', auth.optional, getAllComments); + +module.exports = commentRouter; diff --git a/src/routes/api/dropzones.js b/src/routes/api/dropzones.js new file mode 100644 index 0000000..c51bebc --- /dev/null +++ b/src/routes/api/dropzones.js @@ -0,0 +1,69 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Jump = mongoose.model('Jump'), + User = mongoose.model('User'); +const auth = require('../auth'), + queries = require('../queries'); + + +router.get('/allByOaci', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getDropZonesByOaciQuery(user._id.toString()); + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let dropzones = result.map(function (data) { + return { lieu: data._id.lieu, oaci: data._id.oaci, count: data.count }; + }); + return res.json({ + dropzones: dropzones, + dropzonesCount: dropzones.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allByOaciByYear', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getDropZonesByOaciByYearQuery(user._id.toString()); + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let dropzones = result.map(function (data) { + return { lieu: data._id.lieu, oaci: data._id.oaci, year: data._id.year, count: data.count }; + }); + return res.json({ + dropzones: dropzones, + dropzonesCount: dropzones.length + }); + }).catch(next); + }).catch(next); +}); + +module.exports = router; diff --git a/src/routes/api/index.js b/src/routes/api/index.js new file mode 100644 index 0000000..0563b71 --- /dev/null +++ b/src/routes/api/index.js @@ -0,0 +1,33 @@ +var routes = require('express').Router(); + +//routes.use('/', require('./users')); +//routes.use('/articles', require('./articles')); +//routes.use('/comments', require('./comments')); +//routes.use('/tags', require('./tags')); +routes.use('/profiles', require('./profiles')); +routes.use('/applications', require('./applications')); +routes.use('/aeronefs', require('./aeronefs')); +routes.use('/canopies', require('./canopies')); +routes.use('/dropzones', require('./dropzones')); +routes.use('/jumps', require('./jumps')); +routes.use('/pages', require('./pages')); +routes.use('/qcm', require('./qcm')); + +routes.use('/user', require('./user.routes')); +routes.use('/article', require('./article.routes')); +routes.use('/comment', require('./comment.routes')); +routes.use('/tag', require('./tag.routes')); + +routes.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 = routes; \ No newline at end of file diff --git a/src/routes/api/jumps.js b/src/routes/api/jumps.js new file mode 100644 index 0000000..3d166e5 --- /dev/null +++ b/src/routes/api/jumps.js @@ -0,0 +1,621 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Jump = mongoose.model('Jump'), + JumpFile = mongoose.model('JumpFile'), + User = mongoose.model('User'), + X2DataLog = mongoose.model('X2DataLog'); +const auth = require('../auth'), + chalk = require('chalk'), + queries = require('../queries'), + utils = require('../utils'); + +// Preload jump objects on routes with ':jump' +router.param('jump', function (req, res, next, slug) { + Jump.findOne({ slug: slug }) + .populate('author') + .populate('files') + .populate('x2data') + .then(function (jump) { + if (!jump) { + return res.sendStatus(404); + } + req.jump = jump; + return next(); + }).catch(next); +}); + +/** + * return all jumps + */ +router.get('/', auth.required, function (req, res, next) { + let query = {}; + let limit = 25; + let 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.title !== 'undefined') { + const rgx = new RegExp(`.*${req.query.title}.*`); + query = { + $or: [ + { title: { $regex: rgx, $options: "i" } }, + { slug: { $regex: rgx, $options: "i" } }, + ], + } + } + if (typeof req.query.numeroRangeStart !== 'undefined' && typeof req.query.numeroRangeEnd !== 'undefined') { + query.numero = { + $gte: req.query.numeroRangeStart, + $lte: req.query.numeroRangeEnd + }; + } + if (typeof req.query.tailleRangeStart !== 'undefined' && typeof req.query.tailleRangeEnd !== 'undefined') { + query.taille = { + $gte: req.query.tailleRangeStart, + $lte: req.query.tailleRangeEnd + }; + } + if (typeof req.query.participantsRangeStart !== 'undefined' && typeof req.query.participantsRangeEnd !== 'undefined') { + query.participants = { + $gte: req.query.participantsRangeStart, + $lte: req.query.participantsRangeEnd + }; + } + if (typeof req.query.hauteurRangeStart !== 'undefined' && typeof req.query.hauteurRangeEnd !== 'undefined') { + query.hauteur = { + $gte: req.query.hauteurRangeStart, + $lte: req.query.hauteurRangeEnd + }; + } + if (typeof req.query.yearRangeStart !== 'undefined' && typeof req.query.yearRangeEnd !== 'undefined') { + query.date = { + $gte: new Date(`${req.query.yearRangeStart}-01-01 00:00:00`), + $lte: new Date(`${req.query.yearRangeEnd}-12-31 23:59:59`) + }; + } + if (typeof req.query.dateRangeStart !== 'undefined' && typeof req.query.dateRangeEnd !== 'undefined') { + query.date = { + $gte: new Date(`${req.query.dateRangeStart} 00:00:00`), + $lte: new Date(`${req.query.dateRangeEnd} 23:59:59`) + }; + } + + Promise.all([ + req.query.author ? User.findOne({ username: req.query.author }) : null, + req.query.favorited ? User.findOne({ username: req.query.favorited }) : null + ]).then(function (users) { + let author = users[0]; + + if (author) { + query.author = author._id; + } + + Promise.all([ + Jump.find(query) + .skip(Number(offset)) + .limit(Number(limit)) + .sort({ numero: 'desc' }) + .populate('author') + .populate('files') + .populate('x2data') + .exec(), + Jump.count(query).exec(), + req.payload ? User.findById(req.payload.id) : null + ]).then(function (results) { + let jumps = results[0]; + let jumpsCount = results[1]; + let user = results[2]; + /* + Promise.all( + jumps.map(jump => { + if (jump.files[0] !== undefined && jump.files[0].type !== 'kml') { + console.log( chalk.green(`Fichier ${jump.files[0].type}`)) + //console.log( chalk.green(`Suppression du fichier ${jump.files[2]._id}`)) + //return jump.removeFile(jump.files[2]._id); + } + return; + }) + ).then(function () { + return res.json({ + jumps: jumps.map(function (jump) { + return jump.toJSONFor(user); + }), + jumpsCount: jumpsCount + }); + }); + */ + return res.json({ + jumps: jumps.map(function (jump) { + return jump.toJSONFor(user); + }), + jumpsCount: jumpsCount + }); + }); + }).catch(next); +}); + +router.get('/allByCategorie', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getJumpsByCategoryQuery(user._id.toString()); + + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let jumps = result.map(function (data) { + return { categorie: data._id.categorie, count: data.count }; + }); + return res.json({ + jumps: jumps, + jumpsCount: jumps.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allByDate', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getJumpsByDateQuery(user._id.toString()); + + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let jumps = result.map(function (data) { + return { year: data._id.year, month: data._id.month, count: data.count }; + }); + return res.json({ + jumps: jumps, + jumpsCount: jumps.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allByDay', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let query = {}; + let limit = 50; + let 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.dateRangeStart !== 'undefined' && typeof req.query.dateRangeEnd !== 'undefined') { + query = queries.getJumpsByDayQuery( + user._id.toString(), + req.query.dateRangeStart, + req.query.dateRangeEnd + ); + } else { + query = queries.getJumpsByDayQuery(user._id.toString()); + } + + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let days = result.map(function (data) { + return { jumps: data.jumps, count: data.count }; + }); + return res.json({ + days: days, + daysCount: days.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allByModule', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getJumpsByModuleQuery(user._id.toString()); + + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let jumps = result.map(function (data) { + return { categorie: data._id.categorie, module: data._id.module, count: data.count }; + }); + return res.json({ + jumps: jumps, + jumpsCount: jumps.length + }); + }).catch(next); + }).catch(next); +}); + +/** + * return a jump from SkydiverId API + */ +router.get('/allFromSkydiverIdApi', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + utils.fetchSkydiverIdApi('jumps', req.query).then(result => { + if (result.errors === undefined) { + console.log(`${utils.getDateTimeISOString()}`, chalk.green(`Réception des sauts SkydiverId`)); + } else { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`Une erreur ${result.errors.code} '${result.errors.type}' est survenue lors de la réception des sauts SkydiverId : ${result.errors.name} ${result.errors.message}`)); + } + return res.json({ + jumps: result, + jumpsCount: result.items.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/feed', auth.required, function (req, res, next) { + let limit = 25; + let 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.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let query = { author: { $in: user.following } }; + Promise.all([ + Jump.find(query) + .skip(Number(offset)) + .limit(Number(limit)) + .populate('author') + .populate('files') + .populate('x2data') + .exec(), + Jump.count(query) + ]).then(function (results) { + let jumps = results[0]; + let jumpsCount = results[1]; + return res.json({ + jumps: jumps.map(function (jump) { + return jump.toJSONFor(user); + }), + jumpsCount: jumpsCount + }); + }).catch(next); + }); +}); + +/** + * return last jump + */ +router.get('/last', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + /*Jump.findOne({ slug: slug }) + .populate('author') + .then(function (jump) { + if (!jump) { + return res.sendStatus(404); + } + req.jump = jump; + return next(); + }).catch(next);*/ + Jump.find({author: user._id}) + .limit(1) + .sort({ numero: 'desc' }) + .populate('author') + .populate('files') + .populate('x2data') + .exec() + .then(function (jumps) { + if (!jumps) { + return res.sendStatus(404); + } + req.lastjump = jumps[0]; + if (req.lastjump.author.username !== req.payload.username) { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + return res.json({ jump: req.lastjump.toJSONFor(user) }); + }).catch(next); + }).catch(next); +}); + +/** + * return a jump + */ +router.get('/:jump', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (req.jump.author._id.toString() !== req.payload.id.toString()) { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + Promise.all([ + Jump.findOne({numero: (req.jump.numero - 1)}).exec(), + Jump.findOne({numero: (req.jump.numero + 1)}).exec(), + ]).then(function (results) { + return res.json({ + jump: req.jump.toJSONFor(user), + prevJump: results[0], + nextJump: results[1] + }); + }).catch(next); + }).catch(next); +}); + +/** + * save a jump + */ +router.post('/', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + //let numero = (results[1][0].numero + 1); + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let jump = new Jump(req.body.jump); + jump.author = user; + //jump.numero = numero; + return jump.save().then(function () { + return res.json({ jump: jump.toJSONFor(user) }); + }); + }).catch(next); +}); + +/** + * save a jump file + */ +router.post('/data/:jump', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (req.jump.author._id.toString() !== req.payload.id.toString()) { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + /* + console.log(req.jump.files); + return res.json({ jump: req.jump.toJSONFor(user) }); + */ + Object.assign(req.body.file, {_id: new mongoose.Types.ObjectId()}); + let file = new JumpFile(req.body.file); + let files = req.jump.files ? req.jump.files : []; + file.author = user; + files.push(file); + return file.save().then(function () { + Object.assign(req.body.data, {_id: new mongoose.Types.ObjectId()}); + let x2data = new X2DataLog(req.body.data); + x2data.author = user; + return x2data.save().then(function () { + req.jump.files = files; + req.jump.x2data = x2data; + Jump.updateOne({_id: req.jump._id}, {files: files, x2data: x2data._id}).then(function () { + return res.json({ jump: req.jump.toJSONFor(user) }); + }).catch(next); + }).catch(next); + }).catch(next); + }).catch(next); +}); + +/** + * save a jump file + */ +router.post('/file/:jump', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (req.jump.author._id.toString() !== req.payload.id.toString()) { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + Object.assign(req.body.file, {_id: new mongoose.Types.ObjectId()}); + let file = new JumpFile(req.body.file); + let files = req.jump.files ? req.jump.files : []; + file.author = user; + files.push(file); + return file.save().then(function () { + Jump.updateOne({_id: req.jump._id}, {files: files}).then(function () { + return res.json({ file: file.toJSONForJump() }); + }).catch(next); + }).catch(next); + }).catch(next); +}); + +/** + * save a jump file + */ +router.post('/kml/:jump', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (req.jump.author._id.toString() !== req.payload.id.toString()) { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + Object.assign(req.body.file, { + _id: new mongoose.Types.ObjectId(), + name: `${req.jump.x2data.name}.kml`, + path: `/Volumes/Storage/Skydive/X2_Kmls/${req.jump.date.getFullYear()}/`, + type: 'kml' + }); + let file = new JumpFile(req.body.file); + let files = req.jump.files ? req.jump.files : []; + file.author = user; + files.push(file); + //console.log(chalk.yellow(`jump/${req.jump.x2data.id}/kml`)); + return res.json({ file: file.toJSONForJump() }); + /* + utils.fetchSkydiverIdApi(`jump/${req.jump.x2data.id}/kml`, {}).then(result => { + if (result.errors === undefined) { + console.log(`${utils.getDateTimeISOString()}`, chalk.green(`Réception de l'url du fichier kml SkydiverId`)); + } else { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`Une erreur ${result.errors.code} '${result.errors.type}' est survenue lors de la réception de l'url du fichier kml SkydiverId : ${result.errors.name} ${result.errors.message}`)); + } + if (result.url !== undefined) { + console.log(chalk.green(result.url)); + } else { + console.log(chalk.red('result.url is undefined')); + } + return res.json({ file: file.toJSONForJump() }); + }).catch(next); + + + + return file.save().then(function () { + Jump.updateOne({_id: req.jump._id}, {files: files}).then(function () { + utils.fetchSkydiverIdApi(`jump/${req.jump.x2data.id}/kml`, {}).then(result => { + if (result.errors === undefined) { + console.log(`${utils.getDateTimeISOString()}`, chalk.green(`Réception de l'url du fichier kml SkydiverId`)); + } else { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`Une erreur ${result.errors.code} '${result.errors.type}' est survenue lors de la réception de l'url du fichier kml SkydiverId : ${result.errors.name} ${result.errors.message}`)); + } + if (result.url !== undefined) { + console.log(result.url); + } else { + console.log('result.url is undefined'); + } + return res.json({ file: file.toJSONForJump() }); + }).catch(next); + }).catch(next); + }).catch(next); + */ + }).catch(next); +}); + +/** + * update a jump + */ +router.put('/:jump', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (req.jump.author._id.toString() !== req.payload.id.toString()) { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + if (typeof req.body.jump.date !== 'undefined') { + req.jump.date = req.body.jump.date; + } + if (typeof req.body.jump.numero !== 'undefined') { + req.jump.numero = req.body.jump.numero; + } + if (typeof req.body.jump.lieu !== 'undefined') { + req.jump.lieu = req.body.jump.lieu; + } + if (typeof req.body.jump.oaci !== 'undefined') { + req.jump.oaci = req.body.jump.oaci; + } + if (typeof req.body.jump.aeronef !== 'undefined') { + req.jump.aeronef = req.body.jump.aeronef; + } + if (typeof req.body.jump.imat !== 'undefined') { + req.jump.imat = req.body.jump.imat; + } + if (typeof req.body.jump.hauteur !== 'undefined') { + req.jump.hauteur = req.body.jump.hauteur; + } + if (typeof req.body.jump.voile !== 'undefined') { + req.jump.voile = req.body.jump.voile; + } + if (typeof req.body.jump.taille !== 'undefined') { + req.jump.taille = req.body.jump.taille; + } + if (typeof req.body.jump.categorie !== 'undefined') { + req.jump.categorie = req.body.jump.categorie; + } + if (typeof req.body.jump.module !== 'undefined') { + req.jump.module = req.body.jump.module; + } + if (typeof req.body.jump.participants !== 'undefined') { + req.jump.participants = req.body.jump.participants; + } + if (typeof req.body.jump.sautants !== 'undefined') { + req.jump.sautants = req.body.jump.sautants; + } + if (typeof req.body.jump.programme !== 'undefined') { + req.jump.programme = req.body.jump.programme; + } + if (typeof req.body.jump.accessoires !== 'undefined') { + req.jump.accessoires = req.body.jump.accessoires; + } + if (typeof req.body.jump.zone !== 'undefined') { + req.jump.zone = req.body.jump.zone; + } + if (typeof req.body.jump.dossier !== 'undefined') { + req.jump.dossier = req.body.jump.dossier; + } + if (typeof req.body.jump.video !== 'undefined') { + req.jump.video = req.body.jump.video; + } + + return req.jump.save().then(function (jump) { + return res.json({ jump: jump.toJSONFor(user) }); + }); + }).catch(next); +}); + +/** + * delete a jump + */ +router.delete('/:jump', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (req.jump.author._id.toString() === req.payload.id.toString()) { + return req.jump.remove().then(function () { + return res.json({ deleted: true }); + }); + } else { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + }).catch(next); +}); + +module.exports = router; diff --git a/src/routes/api/pages.js b/src/routes/api/pages.js new file mode 100644 index 0000000..bfb3ddd --- /dev/null +++ b/src/routes/api/pages.js @@ -0,0 +1,284 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Jump = mongoose.model('Jump'), + User = mongoose.model('User'); +const auth = require('../auth'), + queries = require('../queries'); + +router.get('/aeronefs', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + Promise.all([ + Jump.find({}) + .limit(1) + .skip(0) + .sort({ numero: 'desc' }) + .populate('author') + .populate('files') + .populate('x2data') + .exec(), + Jump.aggregate(queries.getAeronefsByImatQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getAeronefsByImatByYearQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + ]).then(function (results) { + if (results[0].length) { + let lastjump = results[0][0].toJSONFor(user); + let aeronefsByImat = results[1].map(function (data) { + return { aeronef: data._id.aeronef, imat: data._id.imat, count: data.count }; + }); + let aeronefsByImatByYear = results[2].map(function (data) { + return { + aeronef: data._id.aeronef, + imat: data._id.imat, + year: data._id.year, + count: data.count + }; + }); + return res.json({ + aeronefsByImat: aeronefsByImat, + aeronefsByImatByYear: aeronefsByImatByYear, + lastjump: lastjump + }); + } else { + return res.status(422).json({ errors: { lastjump: "Aucun saut enregistré pour le moment" } }); + } + }).catch(next); + }).catch(next); +}); + +router.get('/canopies', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + Promise.all([ + Jump.find({}) + .limit(1) + .skip(0) + .sort({ numero: 'desc' }) + .populate('author') + .populate('files') + .populate('x2data') + .exec(), + Jump.aggregate(queries.getCanopiesBySizeQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getCanopiesBySizeByYearQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getCanopiesBySizeByModelQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getCanopiesBySizeByModelByYearQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + ]).then(function (results) { + if (results[0].length) { + let lastjump = results[0][0].toJSONFor(user); + let canopiesBySize = results[1].map(function (data) { + return { taille: data._id.taille, count: data.count }; + }); + let canopiesBySizeByYear = results[2].map(function (data) { + return { + taille: data._id.taille, + year: data._id.year, + count: data.count + }; + }); + let canopiesBySizeByModel = results[3].map(function (data) { + return { + taille: data._id.taille, + voile: data._id.voile, + count: data.count + }; + }); + let canopiesBySizeByModelByYear = results[4].map(function (data) { + return { + taille: data._id.taille, + voile: data._id.voile, + year: data._id.year, + count: data.count + }; + }); + return res.json({ + canopiesBySize: canopiesBySize, + canopiesBySizeByYear: canopiesBySizeByYear, + canopiesBySizeByModel: canopiesBySizeByModel, + canopiesBySizeByModelByYear: canopiesBySizeByModelByYear, + lastjump: lastjump + }); + } else { + return res.status(422).json({ errors: { lastjump: "Aucun saut enregistré pour le moment" } }); + } + }).catch(next); + }).catch(next); +}); + +router.get('/dropzones', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + Promise.all([ + Jump.find({}) + .limit(1) + .skip(0) + .sort({ numero: 'desc' }) + .populate('author') + .populate('files') + .populate('x2data') + .exec(), + Jump.aggregate(queries.getDropZonesByOaciQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getDropZonesByOaciByYearQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + ]).then(function (results) { + if (results[0].length) { + let lastjump = results[0][0].toJSONFor(user); + let dropZonesByOaci = results[1].map(function (data) { + return { lieu: data._id.lieu, oaci: data._id.oaci, count: data.count }; + }); + let dropZonesByOaciByYear = results[2].map(function (data) { + return { + lieu: data._id.lieu, + oaci: data._id.oaci, + year: data._id.year, + count: data.count + }; + }); + return res.json({ + dropZonesByOaci: dropZonesByOaci, + dropZonesByOaciByYear: dropZonesByOaciByYear, + lastjump: lastjump + }); + } else { + return res.status(422).json({ errors: { lastjump: "Aucun saut enregistré pour le moment" } }); + } + }).catch(next); + }).catch(next); +}); + +router.get('/jumps', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + Promise.all([ + Jump.find({}) + .limit(1) + .skip(0) + .sort({ numero: 'desc' }) + .populate('author') + .populate('files') + .populate('x2data') + .exec(), + Jump.aggregate(queries.getJumpByYearsQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getJumpsByCategoryQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getJumpsByModuleQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getJumpsByDateQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getJumpsByModuleByDateQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + //utils.fetchSkydiverIdApi('jumps') + ]).then(function (results) { + if (results[0].length) { + let lastjump = results[0][0].toJSONFor(user); + let jumpsByYears = results[1].map(function (data) { + return { year: data._id.year, count: data.count }; + }); + let jumpsByCategory = results[2].map(function (data) { + return { categorie: data._id.categorie, count: data.count }; + }); + let jumpsByModule = results[3].map(function (data) { + return { categorie: data._id.categorie, module: data._id.module, count: data.count }; + }); + let jumpsByDate = results[4].map(function (data) { + return { year: data._id.year, month: data._id.month, count: data.count }; + }); + let jumpsByDateByModule = results[5].map(function (data) { + return { + categorie: data._id.categorie, + module: data._id.module, + year: data._id.year, + month: data._id.month, + count: data.count + }; + }); + //let jumpsFromSkydiverIdApi = results[6]; + return res.json({ + jumpsByCategory: jumpsByCategory, + jumpsByDate: jumpsByDate, + jumpsByDateByModule: jumpsByDateByModule, + jumpsByModule: jumpsByModule, + jumpsByYears: jumpsByYears, + //jumpsFromSkydiverIdApi: jumpsFromSkydiverIdApi, + lastjump: lastjump + }); + } else { + return res.status(422).json({ errors: { lastjump: "Aucun saut enregistré pour le moment" } }); + } + }).catch(next); + }).catch(next); +}); + +module.exports = router; diff --git a/src/routes/api/profiles.js b/src/routes/api/profiles.js new file mode 100644 index 0000000..3fb26be --- /dev/null +++ b/src/routes/api/profiles.js @@ -0,0 +1,57 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + User = mongoose.model('User'); +const 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) { + 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) { + let profileId = req.profile._id; + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + 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) { + let profileId = req.profile._id; + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + return user.unfollow(profileId).then(function () { + return res.json({ profile: req.profile.toProfileJSONFor(user) }); + }); + }).catch(next); +}); + +module.exports = router; diff --git a/src/routes/api/qcm.js b/src/routes/api/qcm.js new file mode 100644 index 0000000..3c2dad6 --- /dev/null +++ b/src/routes/api/qcm.js @@ -0,0 +1,157 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Qcm = mongoose.model('Qcm'), + QcmCategory = mongoose.model('QcmCategory'), + QcmQuestion = mongoose.model('QcmQuestion'), + QcmChoice = mongoose.model('QcmChoice'), + User = mongoose.model('User'); +const auth = require('../auth'); + +// Preload qcm objects on routes with ':type' +router.param('type', function (req, res, next, type) { + Qcm.findOne({ name: type }) + .populate('categories') + .then(qcm => { + if (!qcm) { + return res.status(404).json({ errors: { "Not Found": "Le QCM est introuvable ou inexistant." } }); + } + req.qcm = qcm; + Promise.all( + req.qcm.categories.map(category => { + return category.populate('questions').then(() => { + return Promise.all( + category.questions.map(question => question.populate('choices')) + ).then(() => { + return category; + }).catch(next); + }); + }) + ).then(() => { + return next(); + }).catch(next); + }).catch(next); +}); + +/** + * return all qcm + */ +router.get('/', auth.required, function (req, res, next) { + Promise.all([ + req.payload ? User.findById(req.payload.id) : null + ]).then(function (results) { + let user = results[0]; + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + return res.json({ qcm: [] }); + }).catch(next); +}); + +/** + * return a qcm + */ +router.get('/type/:type', auth.required, function (req, res, next) { + Promise.all([ + req.payload ? User.findById(req.payload.id) : null + ]).then(function (results) { + let user = results[0]; + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + return res.json({ qcm: req.qcm.toJSONFor() }); + }).catch(next); +}); + +/** + * save an array of qcm question choice + */ +router.post('/choices/', auth.required, function (req, res, next) { + Promise.all([ + req.payload ? User.findById(req.payload.id) : null, + QcmQuestion + .findOne({num: req.body.question.num}) + .populate('choices') + .exec() + ]).then(async function (results) { + const user = results[0]; + //let numero = (results[1][0].numero + 1); + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (user.role !== 'Admin') { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + const question = results[1]; + if (!question) { + return res.status(422).json({ errors: { question: "question introuvable" } }); + } + let choices = []; + Promise.all( + req.body.question.choices.map(data => { + const choiceId = new mongoose.Types.ObjectId(); + const choice = new QcmChoice({ _id: choiceId, index: data.index, libelle: data.libelle, correct: data.correct}); + choices.push(choiceId); + return choice.save(); + }) + ).then(function () { + question.choices = [...choices]; + question.save().then(function () { + QcmQuestion + .findOne({num: req.body.question.num}) + .populate('choices') + .exec() + .then(function (question) { + return res.json({ question: question.toJSONFor() }); + }).catch(next); + }).catch(next); + }).catch(next); + }).catch(next); +}); + +/** + * save an array of qcm category questions + */ +router.post('/questions/', auth.required, function (req, res, next) { + Promise.all([ + req.payload ? User.findById(req.payload.id) : null, + QcmCategory + .findOne({num: req.body.category.num}) + .populate('questions') + .exec() + ]).then(async function (results) { + const user = results[0]; + //let numero = (results[1][0].numero + 1); + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (user.role !== 'Admin') { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + const category = results[1]; + if (!category) { + return res.status(422).json({ errors: { category: "catégorie introuvable" } }); + } + let questions = []; + Promise.all( + req.body.category.questions.map(data => { + const questionId = new mongoose.Types.ObjectId(); + const question = new QcmQuestion({ _id: questionId, num: data.num, libelle: data.libelle, choices: []}); + questions.push(questionId); + return question.save(); + }) + ).then(function () { + category.questions = [...questions]; + category.save().then(function () { + QcmCategory + .findOne({num: req.body.category.num}) + .populate('questions') + .exec() + .then(function (category) { + return res.json({ category: category.toJSONFor() }); + }).catch(next); + }).catch(next); + }).catch(next); + }).catch(next); +}); + +module.exports = router; \ No newline at end of file diff --git a/src/routes/api/tag.routes.js b/src/routes/api/tag.routes.js new file mode 100644 index 0000000..dd20d3e --- /dev/null +++ b/src/routes/api/tag.routes.js @@ -0,0 +1,10 @@ +const express = require('express'); +const { createTag, getAllTags } = require('../../controllers/tag.controller'); +const auth = require('../auth'); + +const tagRouter = express.Router(); + +tagRouter.post('/', auth.required, createTag); +tagRouter.get('/', auth.optional, getAllTags); + +module.exports = tagRouter; diff --git a/src/routes/api/user.routes.js b/src/routes/api/user.routes.js index 4ce8e2a..b2642b5 100644 --- a/src/routes/api/user.routes.js +++ b/src/routes/api/user.routes.js @@ -1,9 +1,12 @@ const express = require('express'); -const { createUser, getAllUsers } = require('../../controllers/user.controller'); +const { createUser, getAllUsers, getUser, loginAsUser } = require('../../controllers/user.controller'); +const auth = require('../auth'); const userRouter = express.Router(); -userRouter.post('/register', createUser); -userRouter.get('/', getAllUsers); +userRouter.get('/', auth.required, getUser); +userRouter.get('/users', auth.required, getAllUsers); +userRouter.post('/login', auth.optional, loginAsUser); +userRouter.post('/register', auth.optional, createUser); module.exports = userRouter; diff --git a/src/routes/api/users.js b/src/routes/api/users.js new file mode 100644 index 0000000..9921fb1 --- /dev/null +++ b/src/routes/api/users.js @@ -0,0 +1,125 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + User = mongoose.model('User'); +const passport = require('passport'), + auth = require('../auth'); + +router.get('/user', auth.required, function (req, res, next) { + //console.log(req.payload); + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + 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.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + 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.firstname !== 'undefined') { + user.firstname = req.body.user.firstname; + } + if (typeof req.body.user.lastname !== 'undefined') { + user.lastname = req.body.user.lastname; + } + if (typeof req.body.user.phone !== 'undefined') { + user.phone = req.body.user.phone; + } + if (typeof req.body.user.licence !== 'undefined') { + user.licence = req.body.user.licence; + } + if (typeof req.body.user.poids !== 'undefined') { + user.poids = req.body.user.poids; + } + if (typeof req.body.user.image !== 'undefined') { + user.image = req.body.user.image; + } + if (typeof req.body.user.bg_image !== 'undefined') { + user.bg_image = req.body.user.bg_image; + } + if (typeof req.body.user.password !== 'undefined') { + user.setPassword(req.body.user.password); + } + if (typeof req.body.user.role !== 'undefined') { + user.role = req.body.user.role; + } + + 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: "email can't be blank" } }); + } + if (!req.body.user.password) { + return res.status(422).json({ errors: { password: " 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.get('/authenticate', function (req, res, next) { + passport.authenticate('headerapikey', { session: false }, function (err, application, info) { + if (err) { + return res.status(err.status || 500).json({message: "An authentication error occured.", err: err.message}); + //return next(err); + } + if (!application) { + return res.status(401).json({message: "Unauthorized - You are not allowed to access this resource.", err: err, info: info}); + } + if (application.author) { + application.author.token = application.author.generateJWT(); + return res.json({ user: application.author.toAuthJSON(), application: application.toAuthJSON() }); + } else { + return res.status(422).json(info); + } + })(req, res, next); +}); +router.post('/users', function (req, res, next) { + console.log('ici post users'); + let user = new User(); + if (typeof req.body.user.username !== 'undefined') { + user.username = req.body.user.username; + } else { + user.username = `${req.body.user.firstname}_${req.body.user.lastname}`; + } + user.email = req.body.user.email; + user.firstname = req.body.user.firstname; + user.lastname = req.body.user.lastname; + user.phone = req.body.user.phone; + if (typeof req.body.user.licence !== 'undefined') { + user.licence = req.body.user.licence; + } + if (typeof req.body.user.poids !== 'undefined') { + user.poids = req.body.user.poids; + } + user.setPassword(req.body.user.password); + user.role = 'User'; + + user.save().then(function () { + return res.json({ user: user.toAuthJSON() }); + }).catch(next); +}); + +module.exports = router; diff --git a/src/routes/auth.js b/src/routes/auth.js new file mode 100644 index 0000000..1413db4 --- /dev/null +++ b/src/routes/auth.js @@ -0,0 +1,94 @@ + +//var jwt = require('express-jwt'); +var { expressjwt: jwt } = require("express-jwt"), + secret = require('../../config').secret, + bcrypt = require('bcrypt'); +const { v4 } = require('uuid'), + passport = require('passport'), + auths = ['Api-Key', 'Basic', 'Bearer', 'Token']; + +function getTokenFromHeader(req) { + if(req.headers.authorization && auths.indexOf(req.headers.authorization.split(' ')[0]) !== -1) { + return req.headers.authorization.split(' ')[1]; + } + return null; +} + +const auth = { + requiredJwt: jwt({ + secret: secret, + algorithms: ['HS256'], + requestProperty: 'payload', + getToken: getTokenFromHeader + }), + optional: jwt({ + secret: secret, + algorithms: ['HS256'], + requestProperty: 'payload', + credentialsRequired: false, + getToken: getTokenFromHeader + }), + required: async (req, res, next) => { + if(req.headers.authorization && req.headers.authorization.split(' ')[0] === process.env.AUTHORIZATION_PREFIX) { + passport.authenticate('headerapikey', { session: false }, function (err, application, info) { + if (err) { + //return res.json({message: "An authentication error occured (required).", err: err.message}); + //return res.status(err.status || 500).json({message: "An authentication error occured (required).", err: err.message}); + return next({message: "An authentication error occured.", err: err.message}); + } + if (!application) { + return res.status(401).json({message: "Unauthorized - You are not allowed to access this resource.", err: err, info: info}); + } + req.application = application; + req.payload = {id: application.author._id}; + //console.log(application); + //console.log(application.author._id); + return next(); + /* + return jwt({ + secret: secret, + algorithms: ['HS256'], + requestProperty: 'payload', + getToken: application.author.toAuthJSON().token + })(req, res, next); + */ + })(req, res, next); + } else { + return jwt({ + secret: secret, + algorithms: ['HS256'], + requestProperty: 'payload', + getToken: getTokenFromHeader + })(req, res, next); + } + }, + getAuthType: (req) => { + if(req.headers.authorization && auths.indexOf(req.headers.authorization.split(' ')[0]) !== -1) { + let value = req.headers.authorization.split(' ')[0]; + return value; + } + return null; + }, + generateAPIKey: async () => { + const key = v4().replace(/-/g, ''); + const salt = secret; + // Génération d'un salt aléatoire : const salt = await Promise.resolve(bcrypt.genSalt(10)); + const maskedKey = `${key.slice(0, 4)}...${key.slice(-4)}`; + const encryptedKey = await Promise.resolve(bcrypt.hash(key, salt)); + return { key: key, masked: maskedKey, encrypted: encryptedKey}; + }, + authenticateKey: async (req, res, next) => { + passport.authenticate('headerapikey', { session: false }, function (err, application, info) { + if (err) { + return res.status(err.status || 500).json({message: "An authentication error occured (authenticateKey).", err: err.message}); + } + if (!application) { + return res.status(401).json({message: "Unauthorized - You are not allowed to access this resource.", err: err, info: info}); + } + req.application = application; + return next(); + })(req, res, next); + } +}; + +module.exports = auth; diff --git a/src/routes/index.js b/src/routes/index.js index c11124d..4e1fb5d 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,3 +1,9 @@ +var routes = require('express').Router(); +routes.use('/api', require('./api')); + +module.exports = routes; + +/* const express = require('express'); const articleRouter = require('./api/article.routes'); const userRouter = require('./api/user.routes'); @@ -8,3 +14,4 @@ routes.use('/user', userRouter); routes.use('/article', articleRouter); module.exports = routes; +*/ \ No newline at end of file diff --git a/src/routes/queries.js b/src/routes/queries.js new file mode 100644 index 0000000..1ae0654 --- /dev/null +++ b/src/routes/queries.js @@ -0,0 +1,507 @@ +const queries = { + getJumpsByCategoryQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$group': { + '_id': { + 'categorie': '$categorie' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getJumpsByDateQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'year': { + '$year': '$date' + }, + 'month': { + '$month': '$date' + } + } + }, { + '$group': { + '_id': { + 'year': '$year', + 'month': '$month' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getJumpsByModuleByDateQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'module': 1, + 'categorie': 1, + 'year': { + '$year': '$date' + }, + 'month': { + '$month': '$date' + } + } + }, { + '$group': { + '_id': { + 'module': '$module', + 'categorie': '$categorie', + 'year': '$year', + 'month': '$month' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + return query; + }, + getJumpsByModuleQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'categorie': 1, + 'module': 1 + } + }, { + '$group': { + '_id': { + 'categorie': '$categorie', + 'module': '$module' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + return query; + }, + getJumpByYearsQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'year': { + '$year': '$date' + } + } + }, { + '$group': { + '_id': { + 'year': '$year' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getAeronefsByImatQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$group': { + '_id': { + 'aeronef': '$aeronef', + 'imat': '$imat' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': + { + 'count': -1 + }, + } + ]; + + return query; + }, + getAeronefsByImatByYearQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'aeronef': 1, + 'imat': 1, + 'year': { + '$year': '$date' + } + } + }, { + '$group': { + '_id': { + 'aeronef': '$aeronef', + 'imat': '$imat', + 'year': '$year' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getCanopiesBySizeQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$group': { + '_id': { + 'taille': '$taille' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': + { + '_id': 1 + }, + } + ]; + + return query; + }, + getCanopiesBySizeByYearQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'taille': 1, + 'year': { + '$year': '$date' + } + } + }, { + '$group': { + '_id': { + 'taille': '$taille', + 'year': '$year' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getCanopiesBySizeByModelQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$group': { + '_id': { + 'taille': '$taille', + 'voile': '$voile' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': + { + '_id': 1 + }, + } + ]; + + return query; + }, + getCanopiesBySizeByModelByYearQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'voile': 1, + 'taille': 1, + 'year': { + '$year': '$date' + } + } + }, { + '$group': { + '_id': { + 'taille': '$taille', + 'voile': '$voile', + 'year': '$year' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getDropZonesByOaciQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$group': { + '_id': { + 'lieu': '$lieu', + 'oaci': '$oaci' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': + { + '_id': 1 + }, + } + ]; + + return query; + }, + getDropZonesByOaciByYearQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'lieu': 1, + 'oaci': 1, + 'year': { + '$year': '$date' + } + } + }, { + '$group': { + '_id': { + 'lieu': '$lieu', + 'oaci': '$oaci', + 'year': '$year' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getJumpsByDayQuery: (userId, dateRangeStart = null, dateRangeEnd = null) => { + if (dateRangeStart === null) { + dateRangeStart = '1970-01-01 00:00:00'; + } + if (dateRangeEnd === null) { + const year = new Date().getFullYear(); + dateRangeEnd = `${year}-12-31 23:59:59`; + } + let query = [ + { + $match: { + $expr: { + $and: [ + { + $eq: [ '$author' , { '$toObjectId': userId } ] + }, + { + $gte: ['$date', new Date(dateRangeStart)] + }, + { + $lte: ['$date', new Date(dateRangeEnd)] + } + ] + } + } + }, { + $project: { + _id: 1, + slug: "$slug", + numero: "$numero", + date: "$date", + year: { + $year: "$date" + }, + month: { + $month: "$date" + }, + day: { + $dayOfMonth: "$date" + } + } + }, + { + $group: { + _id: { + year: "$year", + month: "$month", + day: "$day" + }, + jumps: { + $addToSet: { + _id: "$_id", + numero: "$numero", + slug: "$slug", + date: "$date" + } + }, + count: { + $sum: 1 + } + } + }, + { + $sort: { + _id: 1, + } + }, + { + $project: { + _id: 0, + jumps: 1, + count: 1 + } + } + ]; + + return query; + } +}; + +module.exports = queries; diff --git a/src/routes/utils.js b/src/routes/utils.js new file mode 100644 index 0000000..caa5f0c --- /dev/null +++ b/src/routes/utils.js @@ -0,0 +1,84 @@ +const chalk = require('chalk'); +const utils = { + getDateString: () => { + let today = new Date(); + let dateNow = today.toLocaleDateString(); + return `${dateNow}`; + }, + getTimeString: () => { + let today = new Date(); + let timeNow = today.toLocaleTimeString(); + return `${timeNow}`; + }, + getDateTimeString: (delimiter = true) => { + let today = new Date(); + let dateString = `${today.toLocaleDateString()} ${today.toLocaleTimeString()}`; + if (delimiter) { + dateString = `[${dateString}]`; + } + return dateString; + }, + getDateTimeISOString: (delimiter = true) => { + let today = new Date(); + let dateString = today.toISOString(); + if (delimiter) { + dateString = `[${dateString}]`; + } + return dateString; + }, + async fetchSkydiverIdApi(path, query) { + let limit = 50; + let offset = 0; + let args = ''; + if (typeof query.limit !== 'undefined') { + limit = query.limit; + } + if (typeof query.offset !== 'undefined') { + offset = ((query.offset/limit)+1); + } + if (offset > 1) { + args += `&page=${offset}`; + } + if (typeof query.dateRangeStart !== 'undefined' && typeof query.dateRangeEnd !== 'undefined') { + args += `&filter[and][0][date][gte]=${query.dateRangeStart}`; + args += `&filter[and][0][date][lte]=${query.dateRangeEnd}`; + } + try { + let url = `${process.env.SKYDIVERID_API_URL}/${path}`; + if (typeof query.limit !== 'undefined') { + url += `?per-page=${limit}${args}`; + } + /* url pour provoquer une erreur en dev : url = `https://www.goldapi.ioppppp/api/${price.metal}/${price.currency}`; */ + let options = { + method: 'GET', + headers: { + 'Authorization': `Bearer ${process.env.SKYDIVERID_API_TOKEN}`, + 'Content-Type': 'application/json' + }, + redirect: 'follow' + }; + /* Pour tester le retour d'erreur : return { errors: { name: 'error name', message: 'error message', type: 'TYPE', code: 'CODE' } }; */ + //const response = await fetch(url, options); + return fetch(url, options).then(function (response) { + if (response.status >= 200 && response.status < 400) { + console.log(`${utils.getDateTimeISOString()}`, chalk.green(`Réception des sauts via SkydiverId API`), `${response.status} ${response.statusText}`); + const data = response.json(); + console.log(data); + return data; + } else { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`Erreur ${response.status} ${response.statusText}`)); + return { errors: { name: response.statusText, message: `Une erreur ${response.status} '${response.statusText}' est survenue lors de la récupération des sauts via SkydiverId API`, type: 'API Error', code: response.status } }; + } + }) + .catch(error => { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`A fetchSkydiverIdApi error occured ${error.code} ${error.type}`)); + return { errors: { name: error.name, message: `A fetchSkydiverIdApi error occured : ${error.message}`, type: error.type, code: error.code } }; + }); + } catch (error) { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`fetchSkydiverIdApi error`)); + return { errors: { name: error.name, message: error.message, type: error.type, code: error.code } }; + } + } +}; + +module.exports = utils; diff --git a/src/services/article.service.js b/src/services/article.service.js index 433ba4e..044c7a8 100644 --- a/src/services/article.service.js +++ b/src/services/article.service.js @@ -1,23 +1,31 @@ const DB = require('../database'); -const { Projects } = DB; +const { Article } = DB; -module.exports = class ProjectService { - static async createProject(data) { - return Projects.create(data); - } +class ArticleService { + static async createArticle(data) { + return Article.create(data); + } - static async getProjectsByUserId(userId) { - return Projects.findAll({ - where: { userId }, - include: [ - { - model: DB.Users, - as: 'user', - attributes: ['name', 'email'], - }, - ], - order: [['createdAt', 'DESC']], - }); - } + static async getAllArticles() { + return Article.findAll({ + order: [['createdAt', 'DESC']], + }); + } + + static async getArticlesByUserId(authorId) { + return Article.findAll({ + where: { authorId }, + include: [ + { + model: DB.User, + as: 'author', + attributes: ['username', 'email'], + }, + ], + order: [['createdAt', 'DESC']], + }); + } } + +module.exports = ArticleService; \ No newline at end of file diff --git a/src/services/comment.service.js b/src/services/comment.service.js new file mode 100644 index 0000000..e2c8e79 --- /dev/null +++ b/src/services/comment.service.js @@ -0,0 +1,17 @@ +const DB = require('../database'); + +const { Comment } = DB; + +class CommentService { + static async createComment(data) { + return Comment.create(data); + } + + static async getAllComments() { + return Comment.findAll({ + order: [['createdAt', 'DESC']], + }); + } +} + +module.exports = CommentService; \ No newline at end of file diff --git a/src/services/index.js b/src/services/index.js new file mode 100644 index 0000000..d5b42bd --- /dev/null +++ b/src/services/index.js @@ -0,0 +1,5 @@ + +exports.ArticleService = require('./article.service'); +exports.CommentService = require('./comment.service'); +exports.TagService = require('./tag.service'); +exports.UserService = require('./user.service'); \ No newline at end of file diff --git a/src/services/tag.service.js b/src/services/tag.service.js new file mode 100644 index 0000000..34acb57 --- /dev/null +++ b/src/services/tag.service.js @@ -0,0 +1,19 @@ +const DB = require('../database'); + +const { Tag } = DB; + +class TagService { + static async createTag(data) { + return Tag.create(data); + } + + static async getAllTags() { + return Tag.findAll({ + attributes: ["name"], + order: [['createdAt', 'DESC']], + }); + } + +} + +module.exports = TagService; \ No newline at end of file diff --git a/src/services/user.service.js b/src/services/user.service.js index e2b9d08..3dd22c0 100644 --- a/src/services/user.service.js +++ b/src/services/user.service.js @@ -1,21 +1,25 @@ const DB = require('../database'); -const { Users } = DB; +const { User } = DB; -module.exports = class UserService { +class UserService { static async createUser(data) { - return Users.create(data); + return User.create(data); } static async getAllUsers() { - return Users.findAll({ + return User.findAll({ order: [['createdAt', 'DESC']], }); } static async getUserById(id) { - return Users.findByPk(id); + return User.findByPk(id); + } + + static async getUserByEmail(email) { + return User.findOne(email); } } -//module.exports = userService; \ No newline at end of file +module.exports = UserService; \ No newline at end of file