diff --git a/config.json.example b/config.json.example index d2ecb4ba1f6c7bed2c9c1dbba6c900345d64f310..5a96ebdd463c1d95a4002864095dcaf0b2c41d1d 100644 --- a/config.json.example +++ b/config.json.example @@ -16,8 +16,7 @@ "url": "http://simcaqdb3.c3sl.ufpr.br:3000" }, "mongodb" : { - "uri": "mongodb://localhost/dev_users", - "secret": "SimCAQC3SL" + "uri": "mongodb://localhost/dev_users" }, "monq": { "uri": "mongodb://localhost/dev_monq" @@ -25,6 +24,12 @@ "default": { "api": { "version" : "v1" + }, + "lde": { + "url": "http://ldedev.c3sl.ufpr.br/#" + }, + "simcaq": { + "url": "http://simcaqdev.c3sl.ufpr.br/#" } }, "email": { @@ -33,11 +38,14 @@ "secure": false, "ignoreTLS": true, "from": "\"Laboratório de Dados Educacionais\" <lde@c3sl.ufpr.br>" + }, + "security": { + "tokenLife": 3600 } }, "test": { - "port": 3000, + "port": 4000, "ip": "127.0.0.1", "debug" : true, "monetdb": { @@ -61,13 +69,28 @@ "default": { "api": { "version" : "v1" + }, + "lde": { + "url": "http://ldedev.c3sl.ufpr.br/#" + }, + "simcaq": { + "url": "http://simcaqdev.c3sl.ufpr.br/#" } }, - "email": "simcaq@c3sl.ufpr.br" + "email": { + "port": 25, + "host": "mx.c3sl.ufpr.br", + "secure": false, + "ignoreTLS": true, + "from": "\"Laboratório de Dados Educacionais\" <lde@c3sl.ufpr.br>" + }, + "security": { + "tokenLife": 3600 + } }, "production": { - "port": 3000, + "port": 6000, "ip": "127.0.0.1", "debug" : false, "monetdb": { @@ -91,8 +114,23 @@ "default": { "api": { "version" : "v1" + }, + "lde": { + "url": "http://lde.c3sl.ufpr.br/#" + }, + "simcaq": { + "url": "http://simcaq.c3sl.ufpr.br/#" } }, - "email": "simcaq@c3sl.ufpr.br" + "email": { + "port": 25, + "host": "mx.c3sl.ufpr.br", + "secure": false, + "ignoreTLS": true, + "from": "\"Laboratório de Dados Educacionais\" <lde@c3sl.ufpr.br>" + }, + "security": { + "tokenLife": 3600 + } } } diff --git a/package.json b/package.json index 05fe1eae53edec73f2feeae28535f9cb3389b347..65e8d4c96f3372c0348376b054012ae247d64202 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,13 @@ "monetdb-pool": "0.0.8", "mongoose": "^4.6.0", "nconf": "^0.8.x", + "node-uuid": "^1.4.8", "nodemailer": "^4.0.1", "nodemailer-html-to-text": "^2.1.0", + "oauth2orize": "^1.8.1", "passport": "^0.3.2", + "passport-http-bearer": "^1.0.1", + "passport-oauth2-client-password": "^0.1.2", "request": "^2.81.0", "squel": "^5.4.2", "winston": "^2.2.0" diff --git a/src/libs/app.js b/src/libs/app.js index 662b3e9d21e8c328bf6efef8e700ee00c16f8765..4dff1ee930bde49cfbd47a925b23ebf5b9847041 100644 --- a/src/libs/app.js +++ b/src/libs/app.js @@ -23,6 +23,8 @@ const mongoose = require(`${libs}/db/mongoose`); const db = mongoose(); +require(`${libs}/middlewares/passport`); + app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); @@ -41,6 +43,9 @@ app.use((req, res, next) => { }; next(); }); +app.use(passport.initialize()); +app.use(passport.session()); + app.use((req, res, next) => { res.setHeader('Last-Modified', (new Date()).toUTCString()); next(); diff --git a/src/libs/middlewares/oauth2.js b/src/libs/middlewares/oauth2.js new file mode 100644 index 0000000000000000000000000000000000000000..d0f4a9ccd7022237397a7d783604894327627c24 --- /dev/null +++ b/src/libs/middlewares/oauth2.js @@ -0,0 +1,126 @@ +const oauth2orize = require('oauth2orize'); +const passport = require('passport'); +const crypto = require('crypto'); + +const libs = `${process.cwd()}/libs`; + +const config = require(`${libs}/config`); +const log = require(`${libs}/log`)(module); + +const db = require(`${libs}/db/mongoose`); +const User = require(`${libs}/models/user`); +const AccessToken = require(`${libs}/models/accessToken`); +const RefreshToken = require(`${libs}/models/refreshToken`); + +// create OAuth 2.0 server +let aserver = oauth2orize.createServer() + +// Generic error handler +let errFn = (cb, err) => { + if (err) { + return cb(err) + } +} + +// Destroys any old tokens and generates a new access and refresh token +let generateTokens = (data, done) => { + // curries in `done` callback so we don't need to pass it + let errorHandler = errFn.bind(undefined, done); + let refreshToken; + let refreshTokenValue; + let token; + let tokenValue; + + RefreshToken.remove(data, errorHandler); + AccessToken.remove(data, errorHandler); + + tokenValue = crypto.randomBytes(32).toString('hex'); + refreshTokenValue = crypto.randomBytes(32).toString('hex'); + + data.token = tokenValue; + token = new AccessToken(data); + + data.token = refreshTokenValue; + refreshToken = new RefreshToken(data); + + refreshToken.save(errorHandler); + + token.save((err) => { + if (err) { + console.log('erro aqui?'); + log.error(err); + return done(err); + } + done(null, tokenValue, refreshTokenValue, { + 'expires_in': config.security.tokenLife + }); + }) +}; + +// Exchange username & password for access token. +aserver.exchange(oauth2orize.exchange.password((client, username, password, scope, done) => { + User.findOne({ email: username }, (err, user) => { + if (err) { + return done(err); + } + console.log('aqui!'); + if (!user || !user.checkPassword(password)) { + console.log('deu ruim'); + console.log(user); + console.log(password); + if(user) console.log(user.checkPassword(password)); + return done(null, false); + } + + var model = { + userId: user._id, + clientId: client._id + }; + console.log('gerando token'); + generateTokens(model, done); + }) + +})); + +// Exchange refreshToken for access token. +aserver.exchange(oauth2orize.exchange.refreshToken((client, refreshToken, scope, done) =>{ + RefreshToken.findOne({ token: refreshToken, clientId: client._id }, (err, token) => { + if (err) { + return done(err); + } + + if (!token) { + return done(null, false); + } + + User.findById(token.userId, (err, user) => { + if (err) { + log.error(err); + return done(err); + } + if (!user) { + return done(null, false); + } + + var model = { + userId: user._id, + clientId: client._id + }; + + generateTokens(model, done); + }) + }) +})) + +// token endpoint +// +// `token` middleware handles client requests to exchange authorization grants +// for access tokens. Based on the grant type being exchanged, the above +// exchange middleware will be invoked to handle the request. Clients must +// authenticate when making requests to this endpoint. + +exports.token = [ + passport.authenticate(['oauth2-client-password'], { session: false }), + aserver.token(), + aserver.errorHandler() +]; diff --git a/src/libs/middlewares/passport.js b/src/libs/middlewares/passport.js index c939926099b845b641268d66e9d2bccf9085a043..91b2b22a13df537fcf98030379482422f3fc880d 100644 --- a/src/libs/middlewares/passport.js +++ b/src/libs/middlewares/passport.js @@ -1,54 +1,67 @@ -const JwtStrategy = require('passport-jwt').Strategy; -const ExtractJwt = require('passport-jwt').ExtractJwt; +const passport = require('passport'); +const ClientPasswordStrategy = require('passport-oauth2-client-password'); +const BearerStrategy = require('passport-http-bearer').Strategy; + const libs = `${process.cwd()}/libs`; const config = require(`${libs}/config`); -const User = require(`${libs}/models/user`) - -module.exports = function(passport){ - var opts = {}; - opts.jwtFromRequest = ExtractJwt.fromAuthHeader(); - opts.secretOrKey = config.get('mongodb:secret'); - passport.use(new JwtStrategy(opts, function(jwt_payload, done){ - User.find({email: jwt_payload.email}, function(err, user){ + +const User = require(`${libs}/models/user`); +const Client = require(`${libs}/models/client`); +const AccessToken = require(`${libs}/models/accessToken`); +const RefreshToken = require(`${libs}/models/refreshToken`); +const email = require(`${libs}/middlewares/email`); + +passport.use(new ClientPasswordStrategy( (clientId, clientSecret, done) => { + Client.findOne({ _id: clientId }, (err, client) => { if (err) { return done(err); } - if (!user) { - return done(null, false, {message: 'Unknown user'}); + if (!client) { + return done(null, false); } - return done(null, user); - }); - })); -}; + if (client.clientSecret !== clientSecret) { + return done(null, false); + } -/* To check if a user has access to a route, one must use passport.authenticate() specifying 'JWT' as the strategy in the route declaration, like so: -//pass passportfor configuration -require('./config/passport')(passport); + return done(null, client); + }) + } +)); -app.post('/route', passport.authenticate('jwt', { session: false}), function(req, res) { }); +passport.use(new BearerStrategy( (accessToken, done) => { + AccessToken.findOne({ token: accessToken }, (err, token) => { + if (err) { + return done(err); + } + + if (!token) { + return done(null, false); + } + + if( Math.round((Date.now()-token.created)/1000) > config.get('security:tokenLife') ) { + AccessToken.remove({ token: accessToken }, (err) => { + if (err) { + return done(err); + } + }); + + return done(null, false, { msg: 'Token expired' }); + } -the user object is then accessible via req.user ----- + Usuario.findById(token.userId, function(err, usuario) { + if (err) { + return done(err); + } -Another way to check if a user is authenticated, is to check the request header for the json web token, like so: + if (!usuario) { + return done(null, false, { msg: 'Unknown user' }); + } -getToken = function (headers) { - if (headers && headers.authorization) { - var parted = headers.authorization.split(' '); - if (parted.length === 2) { - return parted[1]; - } else { - return null; + var info = { scope: '*' }; + done(null, usuario, info); + }) + }) } - } else { - return null; - } -}; - -var token = getToken(req.headers); - if (token) { - var decoded = jwt.decode(token, config.get(mongodb.secret)); - } - */ +)); diff --git a/src/libs/models/accessToken.js b/src/libs/models/accessToken.js new file mode 100644 index 0000000000000000000000000000000000000000..daab5898a66b952f72359d9685e951b1acf980b7 --- /dev/null +++ b/src/libs/models/accessToken.js @@ -0,0 +1,29 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; +const libs = `${process.cwd()}/libs`; +const User = require(`${libs}/models/user`); +const Client = require(`${libs}/models/client`); + +let AccessToken = new Schema({ + userId: { + type: Schema.Types.ObjectId, + required: true, + ref: 'User' + }, + clientId: { + type: Schema.Types.ObjectId, + required: true, + ref: 'Client' + }, + token: { + type: String, + unique: true, + required: true + }, + createdAt: { + type: Date, + default: Date.now + } +}); + +module.exports = mongoose.model('AccessToken', AccessToken); diff --git a/src/libs/models/client.js b/src/libs/models/client.js new file mode 100644 index 0000000000000000000000000000000000000000..8ac80d8d158705f63efbbecc72de37d1fef6a3ac --- /dev/null +++ b/src/libs/models/client.js @@ -0,0 +1,17 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; + +let Client = new Schema({ + name: { + type: String, + unique: true, + required: true + }, + clientSecret: { + type: String, + required: true, + unique: true + } +}); + +module.exports = mongoose.model('Client', Client); diff --git a/src/libs/models/refreshToken.js b/src/libs/models/refreshToken.js new file mode 100644 index 0000000000000000000000000000000000000000..c5f8fd63cdd30733bb60f341e6617420d945b037 --- /dev/null +++ b/src/libs/models/refreshToken.js @@ -0,0 +1,30 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; +const libs = `${process.cwd()}/libs`; +const User = require(`${libs}/models/user`); +const Client = require(`${libs}/models/client`); + +let RefreshToken = new Schema({ + userId: { + type: Schema.Types.ObjectId, + required: true, + ref: 'User' + }, + clientId: { + type: Schema.Types.ObjectId, + required: true, + ref: 'Client' + }, + token: { + type: String, + unique: true, + required: true + }, + createdAt: { + type: Date, + default: Date.now + } +}); + +module.exports = mongoose.model('RefreshToken', RefreshToken); + diff --git a/src/libs/models/user.js b/src/libs/models/user.js index 9b9c2fa5c70bafd507f0a60a062b80efe45b4d13..47c7c65e5f35f42fcdf6b394767d74b3e1453965 100644 --- a/src/libs/models/user.js +++ b/src/libs/models/user.js @@ -1,5 +1,5 @@ const mongoose = require('mongoose'); -const bcrypt = require('bcrypt-nodejs'); +const crypto = require('crypto') const libs = `${process.cwd()}/libs`; const log = require(`${libs}/log`)(module); const Schema = mongoose.Schema; @@ -11,7 +11,7 @@ var UserSchema = new Schema({ unique: true, required: [true, 'O campo Email é obrigatório.'] }, - password: { + hashedPassword: { type: String, required: [true, 'O campo Senha é obrigatório.'] }, @@ -39,7 +39,7 @@ var UserSchema = new Schema({ type: String, required: [true, 'O campo Função é obrigatório.'] }, - institution_name: { + institutionName: { type: String, required: [true, 'O campo Instituição em que trabalha é obrigatório.'] }, @@ -51,39 +51,38 @@ var UserSchema = new Schema({ type: String, required: [true, 'O campo Cidade é obrigatório.'] }, - receive_emails: { + receiveEmails: { type: Boolean + }, + createdAt: { + type: Date, + default: Date.now + }, + origin: { + type: String, + enum: ['LDE', 'SimCAQ'], + required: true + }, + verified: { + type: Boolean, + default: false } - }); -UserSchema.pre('save', function (next) { - var user = this; - if (this.isModified('password') || this.isNew) { - bcrypt.genSalt(10, function (err, salt) { - if (err) { - return next(err); - } - bcrypt.hash(user.password, salt, null, function (err, hash) { - if (err) { - return next(err); - } - user.password = hash; - next(); - }); - }); - } else { - return next(); - } +UserSchema.methods.encryptPassword = function(password) { + return crypto.pbkdf2Sync(password, this.salt, 10000, 512, 'sha512'); +}; + +UserSchema.virtual('password').set(function(password) { + this._plainPassword = password; + this.salt = crypto.randomBytes(128).toString('hex'); + this.hashedPassword = this.encryptPassword(password).toString('hex'); +}).get(function() { + return this._plainPassword; }); -UserSchema.methods.comparePassword = function (passw, cb) { - bcrypt.compare(passw, this.password, function (err, isMatch) { - if (err) { - return cb(err); - } - cb(null, isMatch); - }); -}; +UserSchema.methods.checkPassword = function(password) { + return this.encryptPassword(password).toString('hex') === this.hashedPassword; +} module.exports = mongoose.model('User', UserSchema); diff --git a/src/libs/models/verificationToken.js b/src/libs/models/verificationToken.js new file mode 100644 index 0000000000000000000000000000000000000000..ef7e109e16364874ea7d3f4b07b6e19ce74c3eae --- /dev/null +++ b/src/libs/models/verificationToken.js @@ -0,0 +1,41 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; +const libs = `${process.cwd()}/libs`; +const log = require(`${libs}/log`)(module); +const User = require(`${libs}/models/user`); +const uuid = require('node-uuid'); + +let VerificationToken = new Schema({ + userId: { + type: Schema.Types.ObjectId, + required: true, + ref: 'User' + }, + token: { + type: String, + required: true + }, + verified: { + type: Boolean, + required: true, + default: false + }, + createdAt: { + type: Date, + required: true, + default: Date.now + } +}); + +VerificationToken.methods.createVerificationToken = function(done) { + let verificationToken = this; + let token = uuid.v4(); + verificationToken.set('token', token); + verificationToken.verified = false; + verificationToken.save(function(err) { + if (err) return done(err); + return done(null, token); + }) +} + +module.exports = mongoose.model('VerificationToken', VerificationToken); diff --git a/src/libs/routes/api.js b/src/libs/routes/api.js index 7353dfd144c09add582aab1262ee8e29248c39a2..609a2ad326a6dbd8609b3c68923eee61263f8993 100644 --- a/src/libs/routes/api.js +++ b/src/libs/routes/api.js @@ -8,8 +8,6 @@ const config = require(`${libs}/config`); const classes = require('./class'); -const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; - const enrollment = require('./enrollment'); const state = require('./state'); @@ -42,6 +40,10 @@ const idhmr = require('./idhmr'); const idhml = require('./idhml'); +const oauth2 = require(`${libs}/middlewares/oauth2`); + +const verifyToken = require(`${libs}/routes/verifyToken`); + api.get('/', (req, res) => { res.json({ msg: 'SimCAQ API is running' }); }); @@ -49,20 +51,22 @@ api.get('/', (req, res) => { // mount API routes api.use('/user', user); api.use('/simulation', simulation); -api.use('/class', cache('15 day'), classes); -api.use('/enrollment', cache('1 day'), enrollment); -api.use('/state', cache('15 day'), state); -api.use('/region', cache('15 day'), region); -api.use('/city', cache('15 day'), city); -api.use('/school', cache('15 day'), school); -api.use('/spatial', cache('1 day'), spatial); -api.use('/classroom', cache('15 day'), classroom); -api.use('/teacher', cache('1 day'), teacher); -api.use('/idhmr', cache('1 day'), idhmr); -api.use('/idhm', cache('1 day'), idhm); -api.use('/idhme', cache('15 day'), idhme); -api.use('/pibpercapita', cache('1 day'), pibpercapita); -api.use('/population', cache('1 day'), population); -api.use('/idhml', cache('1 day'), idhml); +api.use('/class', classes); +api.use('/enrollment', enrollment); +api.use('/state', state); +api.use('/region', region); +api.use('/city', city); +api.use('/school', school); +api.use('/spatial', spatial); +api.use('/classroom', classroom); +api.use('/teacher', teacher); +api.use('/idhmr', idhmr); +api.use('/idhm', idhm); +api.use('/idhme', idhme); +api.use('/pibpercapita', pibpercapita); +api.use('/population', population); +api.use('/idhml', idhml); +api.use('/auth/token', oauth2.token); +api.use('/verify', verifyToken); module.exports = api; diff --git a/src/libs/routes/city.js b/src/libs/routes/city.js index b7999a8ef9e35fa7fd8011ae73c2149f2d4d02e3..65fba27ea92db049f156a196b7fdbd2da0fc0756 100644 --- a/src/libs/routes/city.js +++ b/src/libs/routes/city.js @@ -12,8 +12,14 @@ const response = require(`${libs}/middlewares/response`); const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqf = new ReqQueryFields(); +cityApp.use(cache('15 day')); + rqf.addField({ name: 'filter', field: false, diff --git a/src/libs/routes/class.js b/src/libs/routes/class.js index 8dde3a491f2027ea86f97d960686e8fb07c5b186..70e5185e5b205582ebf5aaa8d5c54141464c15c0 100644 --- a/src/libs/routes/class.js +++ b/src/libs/routes/class.js @@ -16,7 +16,14 @@ const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); const id2str = require(`${libs}/middlewares/id2str`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqfCount = new ReqQueryFields(); + +classApp.use(cache('15 day')); + // Complete range of the enrollments dataset. // Returns a tuple of start and ending years of the complete enrollments dataset. classApp.get('/year_range', (req, res, next) => { diff --git a/src/libs/routes/classroom.js b/src/libs/routes/classroom.js index 3658a587167c24cc3a3afcc37e0dde4b4808a2ba..75794c86ac4e8b7d556289bcd927baf3d54b1313 100644 --- a/src/libs/routes/classroom.js +++ b/src/libs/routes/classroom.js @@ -14,6 +14,10 @@ const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); const id2str = require(`${libs}/middlewares/id2str`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqf = new ReqQueryFields(); let rqfCount = new ReqQueryFields(); @@ -188,7 +192,7 @@ rqf.addField({ } }); -classroomApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { +classroomApp.get('/', cache('15 day'), rqf.parse(), rqf.build(), (req, res, next) => { req.sql.from('escola') .field('SUM(escola.num_salas)', 'total') .field("'Brasil'", 'name') diff --git a/src/libs/routes/enrollment.js b/src/libs/routes/enrollment.js index a8523ba967de2296e86297e5bb52500eae2cc63d..a5feaac39f5fcc0365bba527fc2f8156fa94c1d7 100644 --- a/src/libs/routes/enrollment.js +++ b/src/libs/routes/enrollment.js @@ -16,6 +16,12 @@ const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); const id2str = require(`${libs}/middlewares/id2str`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + +enrollmentApp.use(cache('15 day')); + let rqf = new ReqQueryFields(); // Complete range of the enrollments dataset. diff --git a/src/libs/routes/idhm.js b/src/libs/routes/idhm.js index 51620254d30551f846fe735bd15a8d6f99a1a3fb..f9336c5a256235ddb3dd7a4a68a7c920ba43066d 100644 --- a/src/libs/routes/idhm.js +++ b/src/libs/routes/idhm.js @@ -16,8 +16,14 @@ const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); const id2str = require(`${libs}/middlewares/id2str`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqf = new ReqQueryFields(); +idhmApp.use(cache('15 day')); + idhmApp.get('/year_range', (req, res, next) => { req.sql.from('adh_idh') .field('MIN(adh_idh.ano_censo)', 'start_year') diff --git a/src/libs/routes/idhme.js b/src/libs/routes/idhme.js index 9b4672efe4f50be75866c2169422afeb9ed509af..22ef5697dbbcfdba5a7f829a206177731367e232 100644 --- a/src/libs/routes/idhme.js +++ b/src/libs/routes/idhme.js @@ -14,8 +14,14 @@ const id2str = require(`${libs}/middlewares/id2str`); const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqf = new ReqQueryFields(); +idhmeApp.use(cache('15 day')); + idhmeApp.get('/year_range', (req, res, next) => { req.sql.from('adh_idh') .field('MIN(adh_idh.ano_censo)', 'start_year') diff --git a/src/libs/routes/idhml.js b/src/libs/routes/idhml.js index a24c51ccbfe0f0f108cb554f224aa12e5ecf7f42..8d9e2e77014913ad902980244f2c1e3808cc513e 100644 --- a/src/libs/routes/idhml.js +++ b/src/libs/routes/idhml.js @@ -14,8 +14,14 @@ const id2str = require(`${libs}/middlewares/id2str`); const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqf = new ReqQueryFields(); +idhmlApp.use(cache('15 day')); + idhmlApp.get('/year_range', (req, res, next) => { req.sql.from('adh_idh') .field('MIN(adh_idh.ano_censo)', 'start_year') diff --git a/src/libs/routes/idhmr.js b/src/libs/routes/idhmr.js index df8847bcd1d6e588044e5920d9796ebe3b783d39..33f950dc09e46efd41ef086738c0c237a6f018fa 100644 --- a/src/libs/routes/idhmr.js +++ b/src/libs/routes/idhmr.js @@ -16,8 +16,14 @@ const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); const id2str = require(`${libs}/middlewares/id2str`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqf = new ReqQueryFields(); +idhmrApp.use(cache('15 day')); + idhmrApp.get('/year_range', (req, res, next) => { req.sql.from('adh_idh') .field('MIN(adh_idh.ano_censo)', 'start_year') diff --git a/src/libs/routes/pibpercapita.js b/src/libs/routes/pibpercapita.js index 1821ae83b57b9e984b54c8b3ab3aa6e78a7a0bbf..d8b7f37b1f0338b0e2a88875f7f90ae20f3c371b 100644 --- a/src/libs/routes/pibpercapita.js +++ b/src/libs/routes/pibpercapita.js @@ -16,8 +16,14 @@ const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); const id2str = require(`${libs}/middlewares/id2str`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqf = new ReqQueryFields(); +pibpercapitaApp.use(cache('15 day')); + pibpercapitaApp.get('/year_range', (req, res, next) => { req.sql.from('ibge_pib') .field('MIN(ibge_pib.ano_censo)', 'start_year') diff --git a/src/libs/routes/population.js b/src/libs/routes/population.js index 3d05c3d0d06fd1630bdcf86df75ec4fba05eaa01..4c90963a60fb28ec5e7732ba93e68a67a4c7224d 100644 --- a/src/libs/routes/population.js +++ b/src/libs/routes/population.js @@ -16,8 +16,14 @@ const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); const id2str = require(`${libs}/middlewares/id2str`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqf = new ReqQueryFields(); +populationApp.use(cache('15 day')); + populationApp.get('/year_range', (req, res, next) => { req.sql.from('ibge_populacao') .field('MIN(ibge_populacao.ano_censo)', 'start_year') diff --git a/src/libs/routes/region.js b/src/libs/routes/region.js index 0afacc0a54ca9421b9ef724515f55f508ee99077..81f655c39bd45836bc39cdfe2a865fd9fbf5517d 100644 --- a/src/libs/routes/region.js +++ b/src/libs/routes/region.js @@ -14,8 +14,14 @@ const response = require(`${libs}/middlewares/response`); const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqf = new ReqQueryFields(); +regionApp.use(cache('15 day')); + rqf.addField({ name: 'filter', field: false, diff --git a/src/libs/routes/school.js b/src/libs/routes/school.js index 6f13b95bccd298fc2a93c1965970e7b27296afdb..47d6a1407bd7b7dd70f6e93cd9b985cea9b5f024 100644 --- a/src/libs/routes/school.js +++ b/src/libs/routes/school.js @@ -16,24 +16,28 @@ const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); const request = require(`request`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqf = new ReqQueryFields(); let rqfCount = new ReqQueryFields(); // Return location -schoolApp.get('/year_range', (req, res, next) => { +schoolApp.get('/year_range', cache('15 day'), (req, res, next) => { req.sql.from('escola') .field('MIN(escola.ano_censo)', 'start_year') .field('MAX(escola.ano_censo)', 'end_year'); next(); }, query, response('range')); -schoolApp.get('/years', (req, res, next) => { +schoolApp.get('/years', cache('15 day'), (req, res, next) => { req.sql.from('escola'). field('DISTINCT escola.ano_censo', 'year'); next(); }, query, response('years')); -schoolApp.get('/location', (req, res, next) => { +schoolApp.get('/location', cache('15 day'), (req, res, next) => { req.result = [ {id: 1, name: 'Urbana'}, {id: 2, name: 'Rural'} @@ -49,14 +53,14 @@ schoolApp.get('/adm_dependency', (req, res, next) => { next(); }, query, response('adm_dependency')); -schoolApp.get('/adm_dependency_detailed', (req, res, next) => { +schoolApp.get('/adm_dependency_detailed', cache('15 day'), (req, res, next) => { req.sql.from('dependencia_adm_priv') .field('id', 'id') .field('nome', 'name'); next(); }, query, response('adm_dependency_detailed')); -schoolApp.get('/government_agreement', (req, res, next) => { +schoolApp.get('/government_agreement', cache('15 day'), (req, res, next) => { req.result = [ {id: null, name: 'Não Declarado'}, {id: 0, name: 'Não'}, @@ -65,7 +69,7 @@ schoolApp.get('/government_agreement', (req, res, next) => { next(); }, response('government_agreement')); -schoolApp.get('/agreement', (req, res, next) => { +schoolApp.get('/agreement', cache('15 day'), (req, res, next) => { req.result = [ {id: 1, name: 'Municipal'}, {id: 2, name: 'Estadual'}, @@ -83,7 +87,7 @@ schoolApp.get('/education_day_care_child', (req, res, next) => { next(); }, response('education_day_care_child')); -schoolApp.get('/education_preschool_child', (req, res, next) => { +schoolApp.get('/education_preschool_child', cache('15 day'), (req, res, next) => { req.result = [ {id: null, name: 'Não Declarado'}, {id: 0, name: 'Não'}, @@ -92,7 +96,7 @@ schoolApp.get('/education_preschool_child', (req, res, next) => { next(); }, response('education_preschool_child')); -schoolApp.get('/education_begin_elementary_school', (req, res, next) => { +schoolApp.get('/education_begin_elementary_school', cache('15 day'), (req, res, next) => { req.result = [ {id: null, name: 'Não Declarado'}, {id: 0, name: 'Não'}, @@ -101,7 +105,7 @@ schoolApp.get('/education_begin_elementary_school', (req, res, next) => { next(); }, response('education_begin_elementary_school')); -schoolApp.get('/education_end_elementary_school', (req, res, next) => { +schoolApp.get('/education_end_elementary_school', cache('15 day'), (req, res, next) => { req.result = [ {id: null, name: 'Não Declarado'}, {id: 0, name: 'Não'}, @@ -110,7 +114,7 @@ schoolApp.get('/education_end_elementary_school', (req, res, next) => { next(); }, response('education_end_elementary_school')); -schoolApp.get('/education_middle_school', (req, res, next) => { +schoolApp.get('/education_middle_school', cache('15 day'), (req, res, next) => { req.result = [ {id: null, name: 'Não Declarado'}, {id: 0, name: 'Não'}, @@ -119,7 +123,7 @@ schoolApp.get('/education_middle_school', (req, res, next) => { next(); }, response('education_middle_school')); -schoolApp.get('/education_professional', (req, res, next) => { +schoolApp.get('/education_professional', cache('15 day'), (req, res, next) => { req.result = [ {id: null, name: 'Não Declarado'}, {id: 0, name: 'Não'}, @@ -128,7 +132,7 @@ schoolApp.get('/education_professional', (req, res, next) => { next(); }, response('education_professional')); -schoolApp.get('/education_eja', (req, res, next) => { +schoolApp.get('/education_eja', cache('15 day'), (req, res, next) => { req.result = [ {id: null, name: 'Não Declarado'}, {id: 0, name: 'Não'}, @@ -444,7 +448,7 @@ schoolApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => { next(); }, query, response('school')); -schoolApp.get('/count', rqfCount.parse(), rqfCount.build(), (req, res, next) => { +schoolApp.get('/count', cache('15 day'), rqfCount.parse(), rqfCount.build(), (req, res, next) => { req.sql.from('escola') .field('COUNT(escola.id)', 'total') @@ -457,13 +461,17 @@ schoolApp.get('/count', rqfCount.parse(), rqfCount.build(), (req, res, next) => }, query, id2str.transform(), response('school')); schoolApp.get('/download', rqf.parse(), rqf.build(), (req, res, next) => { + let username = req.query.user; + let email = req.query.email; + req.sql.from('escola') .field('*'); - // agenda.now('download database', {sql: req.sql.toString(), table: req.sql.tableFrom}); let form = { query: req.sql.toString(), table: req.sql.tableFrom, - name: req.sql.tableFrom + name: req.sql.tableFrom, + username, + email }; request.post(config.cdn.url + '/api/v1/file', {form}, (err, response, body) => { if(err) { diff --git a/src/libs/routes/state.js b/src/libs/routes/state.js index 2663fe9890849aea38ae51244e330454983a3742..67bdfc1bfe86f6976d5af8bf6a31e32ac9dc997b 100644 --- a/src/libs/routes/state.js +++ b/src/libs/routes/state.js @@ -12,8 +12,14 @@ const response = require(`${libs}/middlewares/response`); const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqf = new ReqQueryFields(); +stateApp.use(cache('15 day')); + rqf.addField({ name: 'filter', field: false, diff --git a/src/libs/routes/teacher.js b/src/libs/routes/teacher.js index 294417dd1af605ae7a17a64d504269209121acd1..4ca0b6b43cfff4c8ec3ac7323eeec3442079d1f4 100644 --- a/src/libs/routes/teacher.js +++ b/src/libs/routes/teacher.js @@ -16,8 +16,14 @@ const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`); const id2str = require(`${libs}/middlewares/id2str`); +const config = require(`${libs}/config`); + +const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware; + let rqf = new ReqQueryFields(); +teacherApp.use(cache('15 day')); + // Returns a tuple of start and ending years of the complete enrollments dataset. teacherApp.get('/year_range', (req, res, next) => { req.sql.from('docente') diff --git a/src/libs/routes/user.js b/src/libs/routes/user.js index 0d04dfd0f799bbda44eb0dfccc5d9f5ea42f7fcd..f22f356a58c3e0eb62d4d1b19358a40eed7d5718 100644 --- a/src/libs/routes/user.js +++ b/src/libs/routes/user.js @@ -10,12 +10,13 @@ const log = require(`${libs}/log`)(module); const User = require(`${libs}/models/user`); -const jwt = require('jwt-simple'); +const VerificationToken = require(`${libs}/models/verificationToken`); const response = require(`${libs}/middlewares/response`); -const required_fields = ["email", "password", "name", "cpf", "schooling", "segment", "role", "institution_name", "state", "city"]; +const email = require(`${libs}/middlewares/email`); +const passport = require('passport'); function emailSyntax(email) { const regex = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; @@ -67,51 +68,53 @@ userApp.get('/role', (req, res, next) => { next(); }, response('role')); -userApp.post('/', (req, res, next) => { - if(req.body.email){ - if(!emailSyntax(req.body.email)){ - res.status(400); - res.json({success: false, msg: 'O email informado é inválido.'}); - } else { - next(); +userApp.get('/', passport.authenticate('bearer', {session: false}), (req, res, next) => { + User.find((err, users) => { + if(err) { + log.error(err); + return next(err); } - } else { + + let result = []; + users.forEach((user) => { + let u = user.toObject(); + delete u.hashedPassword; + delete u.salt; + result.push(u); + }); + req.result = result; next(); - } -}, - (req, res, next) => { - User.count({'email': req.body.email}, function(err, count){ - if (err){ - log.error('MongoDB error: ' + err); - res.status(500); - res.json({success: false, msg: ['Um erro ocorreu no banco de dados.']}); - } - if(count){ - res.status(400); - res.json({success: false, msg: 'O email informado já está cadastrado.'}); - } else { - next(); - } }); - -}, (req, res, next) => { - User.count({'cpf': req.body.cpf}, function(err, count){ - if (err){ - log.error('MongoDB error: ' + err); - res.status(500); - res.json({success: false, msg: ['Um erro ocorreu no banco de dados.']}); +}, response('users')); + +userApp.get('/me', passport.authenticate('bearer', { session: false }), (req, res, next) => { + let user = req.user; + delete user.hashedPassword; + delete user.salt; + req.result = user; +}, response('user')); + +userApp.get('/:id', (req, res, next) => { + User.findById(req.params.id, (err, user) => { + if(err) { + log.error(err); + return next(err); } - if(count){ - res.status(400); - res.json({success: false, msg: 'O CPF informado já está cadastrado.'}); - + if(!user) { + req.statusCode = 404; + next({msg: 'User not found'}); } else { + let u = user.toObject; + delete u.hashedPassword; + delete u.salt; + req.result = u; next(); } }); +}, response('user')); -}, (req, res, next) => { - var newUser = new User({ +userApp.post('/', (req, res, next) => { + let user = new User({ email: req.body.email, password: req.body.password, name: req.body.name, @@ -120,73 +123,53 @@ userApp.post('/', (req, res, next) => { course: req.body.course, segment: req.body.segment, role: req.body.role, - institution_name: req.body.institution_name, + institutionName: req.body.institutionName, state: req.body.state, city: req.body.city, - receive_emails: req.body.receive_emails + receiveEmails: false || req.body.receiveEmails, + origin: req.body.origin }); - // save the user - newUser.save((err) => { - if (err){ - let errArray = []; - let errMsg = ''; - for (var e in err.errors) { - errArray.push(err.errors[`${e}`].message); + user.save((err) => { + if(err) { + log.error(err); + let errors = []; + for(let errName in err.errors) { + errors.push(err.errors[errName].message); } - res.status(400); - res.json({success: false, msg: errArray}); - } - else { - res.status(201); - res.json({success: true, msg: 'Usuário cadastrado com sucesso!'}); + console.log(errors); + res.statusCode = 400; + return res.json({err, errors}); } - }); -}); - -userApp.post('/authenticate', (req, res, next) => { - if (!req.body.email) { - res.status(400); - res.json({success: false, msg: 'O campo Email é obrigatório.'}); - } else { - next(); - } - -}, (req, res, next) => { - if (!req.body.password) { - res.status(400); - res.json({success: false, msg: 'O campo Senha é obrigatório.'}); - } else { - next(); - } - -}, (req, res, next) => { - User.findOne({ - email: req.body.email - }, (err, user) => { - if (err) throw err; - if(!user){ - res.status(400); - res.json({success: false, msg: ['O Email informado não está cadastrado.']}); - } - else { - user.comparePassword(req.body.password, (err, isMatch) => { - if (isMatch && !err) { - var secret = config.mongodb.secret; - - // if user is found and password is right create a token - var token = jwt.encode(user, secret); + // Create verification token + let verificationToken = new VerificationToken({ + userId: user._id + }); - //returns user info including token as json - res.json({success: true, token: 'JWT ' + token, msg: 'Usuário autenticado com sucesso'}); - } - else { - res.status(400); - res.json({success: false, msg: ['A Senha informada é inválida.']}); + verificationToken.createVerificationToken((err, token) => { + if(err) { + log.error(err); + return next(err); + } + let url = config.default.lde.url + '/verify'; + let text = `Olá, ${user.name}, seja bem vindo ao Laboratório de Dados Educacionais.\n\nClique neste link para confirmar sua conta: ${url}/${token}`; + // Send confirmation email + let mailOptions = { + to: `"${user.name} <${user.email}>"`, + subject: "Confirme seu cadastro - Laboratório de Dados Educacionais", + text + } + console.log(mailOptions); + email(mailOptions, (err, info) => { + if(err) { + log.error(err); + res.json({msg: 'User created'}); } + log.debug(`Message ${info.messageId} sent: ${info.response}`); + res.json({msg: 'User created'}); }); - } + }); }); }); diff --git a/src/libs/routes/verifyToken.js b/src/libs/routes/verifyToken.js new file mode 100644 index 0000000000000000000000000000000000000000..425c3b6e05e2dae676e81c8c1a63c128ea7d8b3f --- /dev/null +++ b/src/libs/routes/verifyToken.js @@ -0,0 +1,54 @@ +const express = require('express'); + +const verifyTokenApp = express.Router(); + +const libs = `${process.cwd()}/libs`; + +const log = require(`${libs}/log`)(module); + +const VerificationToken = require(`${libs}/models/verificationToken`); + +const User = require(`${libs}/models/user`); + +verifyTokenApp.get('/:token', (req, res, next) => { + let token = req.params.token; + console.log('verificando token'); + VerificationToken.findOne({token: token}, (err, vToken) => { + if(err) { + log.error(err); + return next(err); + } + if(!vToken) { + // TODO: generate new verification token + console.log('Token não existe'); + res.statusCode = 404; + return next({msg: 'Token not found', status:404}); + } + User.findById(vToken.userId, (err, user) => { + if(err) { + log.error(err); + next(err); + } + user.verified = true; + user.save((err) => { + if(err) { + log.error(err); + next(err); + } + }); + let u = user.toObject(); + delete u.salt; + delete u.hashedPassword; + vToken.verified = true; + vToken.save((err) => { + if(err) { + log.error(err); + next(err); + } + }); + res.json({msg: 'User verified', user: u}); + }); + }); +}); + +module.exports = verifyTokenApp; diff --git a/src/test/user.js b/src/test/user.js index 9d6228284509f56682e7a7c6d781e79d6abb6d72..3109960bd98dfec2727c5ba7bf87b28148046ae7 100644 --- a/src/test/user.js +++ b/src/test/user.js @@ -29,598 +29,9 @@ const User = require('../libs/models/user'); chai.use(chaiHttp); describe('Saves a user', () => { - beforeEach(() => { - User.remove({}, (err) => { - console.log('Test collection purged') - }); - }); - - it('should save a user', (done) => { - let newUser = {}; - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - chai.request(server) - .post('/api/v1/user/') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send(newUser) - .end((err, res) => { - res.should.have.status(201); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(true); - res.body.should.have.property('msg'); - res.body.msg.should.be.equal('Usuário cadastrado com sucesso!'); - done(); - }); - }); - - it('should not save a user without email', (done) => { - let newUser = {}; - newUser.email = null; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - chai.request(server) - .post('/api/v1/user/') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send(newUser) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.be.equal('O campo Email é obrigatório.'); - done(); - }); - }); - - it('should not save a user without password', (done) => { - let newUser = {}; - newUser.email = 'lorem@ipsum.com'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - chai.request(server) - .post('/api/v1/user/') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send(newUser) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.be.equal('O campo Senha é obrigatório.'); - done(); - }); - }); - - it('should not save a user with invalid email', (done) => { - let newUser = {}; - newUser.email = 'invalid email'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - chai.request(server) - .post('/api/v1/user/') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send(newUser) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg.should.be.equal('O email informado é inválido.'); - done(); - }); - }); - - it('should not save a user without a name', (done) => { - let newUser = {}; - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - chai.request(server) - .post('/api/v1/user/') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send(newUser) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.be.equal('O campo Nome é obrigatório.'); - done(); - }); - }); - - it('should not save a user without CPF', (done) => { - let newUser = {}; - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - chai.request(server) - .post('/api/v1/user/') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send(newUser) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.be.equal('O campo CPF é obrigatório.'); - done(); - }); - }); - - it('should not save a user without schooling', (done) => { - let newUser = {}; - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - chai.request(server) - .post('/api/v1/user/') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send(newUser) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.be.equal('O campo Escolaridade é obrigatório.'); - done(); - }); - }); - - it('should not save a user without segment', (done) => { - let newUser = {}; - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - chai.request(server) - .post('/api/v1/user/') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send(newUser) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.be.equal('O campo Segmento é obrigatório.'); - done(); - }); - }); - - it('should not save a user without role', (done) => { - let newUser = {}; - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - chai.request(server) - .post('/api/v1/user/') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send(newUser) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.be.equal('O campo Função é obrigatório.'); - done(); - }); - }); - - it('should not save a user without institution_name', (done) => { - let newUser = {}; - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - chai.request(server) - .post('/api/v1/user/') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send(newUser) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.be.equal('O campo Instituição em que trabalha é obrigatório.'); - done(); - }); - }); - - it('should not save a user without state', (done) => { - let newUser = {}; - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.city = 'Curitiba'; - - chai.request(server) - .post('/api/v1/user/') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send(newUser) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.be.equal('O campo Estado é obrigatório.'); - done(); - }); - }); - - it('should not save a user without city', (done) => { - let newUser = {}; - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'Paraná'; - - chai.request(server) - .post('/api/v1/user/') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send(newUser) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.be.equal('O campo Cidade é obrigatório.'); - done(); - }); - }); - -}) - -describe('Authenticates a user', () => { - - beforeEach(() => { - User.remove({}, (err) => { - console.log('Test collection purged'); - }); - }); - - it('should authenticate a user', (done) => { - let newUser = new User(); - - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - newUser.save((err) => { - if (err) { - console.log('MongoDB error:' + err); - } - }).then(function(newuser){ - chai.request(server) - .post('/api/v1/user/authenticate') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send({email: 'lorem@ipsum.com', - password: '123mudar'}) - .end((err, res) => { - let token; - - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(true); - res.body.should.have.property('token'); - token = res.body.token; - token.substr(0, 3).should.equal('JWT'); - done(); - }); - }); - }); - - it('should not authenticate a user with wrong password', (done) => { - let newUser = new User(); - - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - newUser.save((err) => { - if (err) { - console.log('MongoDB error:' + err); - } - }).then(function(newuser){ - chai.request(server) - .post('/api/v1/user/authenticate') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send({email: 'lorem@ipsum.com', - password: 'umasenhaerrada'}) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.equal('A Senha informada é inválida.') - done(); - }); - }); - }); - - it('should not authenticate a user with wrong email', (done) => { - let newUser = new User(); - - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - newUser.save((err) => { - if (err) { - console.log('MongoDB error:' + err); - } - }).then(function(newuser){ - chai.request(server) - .post('/api/v1/user/authenticate') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send({email: 'dolor@ipsum.com', - password: '123mudar'}) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.equal('O Email informado não está cadastrado.') - done(); - }); - }); - }); - - it('should not authenticate a user with missing email', (done) => { - let newUser = new User(); - - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - newUser.save((err) => { - if (err) { - console.log('MongoDB error:' + err); - } - }).then(function(newuser){ - chai.request(server) - .post('/api/v1/user/authenticate') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send({password: '123mudar'}) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg.should.equal('O campo Email é obrigatório.') - done(); - }); - }); - }); - - it('should not authenticate a user with missing password', (done) => { - let newUser = new User(); - - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - newUser.save((err) => { - if (err) { - console.log('MongoDB error:' + err); - } - }).then(function(newuser){ - chai.request(server) - .post('/api/v1/user/authenticate') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send({email:'lorem@ipsum.com'}) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg.should.equal('O campo Senha é obrigatório.') - done(); - }); - }); - }); - - it('should not authenticate a user with wrong password', (done) => { - let newUser = new User(); - - newUser.email = 'lorem@ipsum.com'; - newUser.password = '123mudar'; - newUser.name = 'Gute'; - newUser.cpf = '08236017907'; - newUser.schooling = 'Doutorado'; - newUser.course = 'Ciência da Computação'; - newUser.segment = 'Comunidade acadêmica'; - newUser.role = 'Pesquisador'; - newUser.institution_name = 'UFPR'; - newUser.state = 'PR'; - newUser.city = 'Curitiba'; - - newUser.save((err) => { - if (err) { - console.log('MongoDB error:' + err); - } - }).then(function(newuser){ - chai.request(server) - .post('/api/v1/user/authenticate') - .set('content-type', 'application/x-www-form-urlencoded') - .set('x-apicache-bypass', 'true') - .send({email:'lorem@ipsum.com', password: '123'}) - .end((err, res) => { - res.should.have.status(400); - res.should.be.json; - res.body.should.have.property('success'); - res.body.success.should.equal(false); - res.body.should.have.property('msg'); - res.body.msg[0].should.equal('A Senha informada é inválida.') - done(); - }); - }); - }); + // beforeEach(() => { + // User.remove({}, (err) => { + // console.log('Test collection purged') + // }); + // }); });