From 36450550f11729a7ba92b358ccd502c14609acab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20J=2E=20Pe=C3=B1a=20Pollastri?= Date: Mon, 21 Jun 2021 19:40:56 -0300 Subject: [PATCH 1/9] final task codebase --- README.md | 36 ++++++++++++++++++++++++++++++++++++ app/config/auth.config.js | 8 ++++---- app/config/db.config.js | 13 +++++++++---- final-task.md | 33 +++++++++++++++++++++++++++++++++ package.json | 4 ++++ server.js | 9 +++------ 6 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 final-task.md diff --git a/README.md b/README.md index d00dbdc..d45c9cb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,39 @@ +This is a fork of the original project. It's intended to set as a codebase for the final task for the students of the course 4 of Pilar Tecno. + +## **[You're now facing the Final Task](https://www.youtube.com/watch?v=Jxk9DqdYsJ4)** + + + +You have the freedom to use any free or open API for your project. You may use as many as you need/want. + +Some suggestions are: + + - [NASA API](https://api.nasa.gov/) + - [The Audio DB](https://www.theaudiodb.com/api_guide.php) +- [The cat facts](https://alexwohlbruck.github.io/cat-facts/docs/) +- [API del Servicio de Normalización de Datos Geográficos de + Argentina](https://datosgobar.github.io/georef-ar-api/) + +You can browse more API's [here](https://public-apis.io/). + +Keep in mind some API's will need some registration and/or are free for trial purposes only. + +**The final task consists in you making three or more endpoints that must consume one external service API (like the ones listed before).** + +**It is required that you pay special attention to the structure used for the endpoint.** Make sure to use: + +* Routes. + +* Controllers. + +* Services. + +* Environment variables for sensitive data (like API keys or DB access). + +**In one of the three endpoints you code, it is required that you save the response to a Mongodb collection.** You can use MongoDB Atlas for easy setup, or a local instance if you want. + +**It is required that the endpoints are protected with a JWT Token.** The endpoints should only allow users with the role "user" to use the endpoint. + # Node.js JWT Refresh Token with MongoDB example JWT Refresh Token Implementation with Node.js Express and MongoDB. You can know how to expire the JWT, then renew the Access Token with Refresh Token. diff --git a/app/config/auth.config.js b/app/config/auth.config.js index 14e0bce..1471b9e 100644 --- a/app/config/auth.config.js +++ b/app/config/auth.config.js @@ -1,9 +1,9 @@ module.exports = { secret: "bezkoder-secret-key", - // jwtExpiration: 3600, // 1 hour - // jwtRefreshExpiration: 86400, // 24 hours + jwtExpiration: 3600, // 1 hour + jwtRefreshExpiration: 86400, // 24 hours /* for test */ - jwtExpiration: 60, // 1 minute - jwtRefreshExpiration: 120, // 2 minutes + // jwtExpiration: 30, // 1 minute + // jwtRefreshExpiration: 120, // 2 minutes }; diff --git a/app/config/db.config.js b/app/config/db.config.js index ac4ae86..c3b0a16 100644 --- a/app/config/db.config.js +++ b/app/config/db.config.js @@ -1,5 +1,10 @@ +const dbUser = process.env.DB_USER; +const dbPass = process.env.DB_PASSWORD; +const dbName = 'PilarTecno' +const dbUri = `mongodb+srv://${dbUser}:${dbPass}@cluster0.qtcrz.mongodb.net/${dbName}?retryWrites=true&w=majority`; +const mongooseOptions = {useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true}; + + module.exports = { - HOST: "localhost", - PORT: 27017, - DB: "bezkoder_db" -}; \ No newline at end of file + dbUri, mongooseOptions +} \ No newline at end of file diff --git a/final-task.md b/final-task.md new file mode 100644 index 0000000..79bc112 --- /dev/null +++ b/final-task.md @@ -0,0 +1,33 @@ +## **[You're now facing the Final Task](https://www.youtube.com/watch?v=Jxk9DqdYsJ4)** + + + +You have the freedom to use any free or open API for your project. You may use as many as you need/want. + +Some suggestions are: + + - [NASA API](https://api.nasa.gov/) + - [The Audio DB](https://www.theaudiodb.com/api_guide.php) +- [The cat facts](https://alexwohlbruck.github.io/cat-facts/docs/) +- [API del Servicio de Normalización de Datos Geográficos de + Argentina](https://datosgobar.github.io/georef-ar-api/) + +You can browse more API's [here](https://public-apis.io/). + +Keep in mind some API's will need some registration and/or are free for trial purposes only. + +**The final task consists in you making three or more endpoints that must consume one external service API (like the ones listed before).** + +**It is required that you pay special attention to the structure used for the endpoint.** Make sure to use: + +* Routes. + +* Controllers. + +* Services. + +* Environment variables for sensitive data (like API keys or DB access). + +**In one of the three endpoints you code, it is required that you save the response to a Mongodb collection.** You can use MongoDB Atlas for easy setup, or a local instance if you want. + +**It is required that the endpoints are protected with a JWT Token.** The endpoints should only allow users with the role "user" to use the endpoint. \ No newline at end of file diff --git a/package.json b/package.json index c42b568..2497f27 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Node.js JWT Refresh Token with MongoDB", "main": "server.js", "scripts": { + "start": "nodemon server.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ @@ -25,5 +26,8 @@ "jsonwebtoken": "^8.5.1", "mongoose": "^5.12.10", "uuid": "^8.3.2" + }, + "devDependencies": { + "nodemon": "^2.0.7" } } diff --git a/server.js b/server.js index cd3fd87..17d6283 100644 --- a/server.js +++ b/server.js @@ -20,10 +20,7 @@ const db = require("./app/models"); const Role = db.role; db.mongoose - .connect(`mongodb://${dbConfig.HOST}:${dbConfig.PORT}/${dbConfig.DB}`, { - useNewUrlParser: true, - useUnifiedTopology: true - }) + .connect(dbConfig.dbUri, dbConfig.mongooseOptions) .then(() => { console.log("Successfully connect to MongoDB."); initial(); @@ -35,7 +32,7 @@ db.mongoose // simple route app.get("/", (req, res) => { - res.json({ message: "Welcome to bezkoder application." }); + res.json({ message: "Welcome to pilarTecno application." }); }); // routes @@ -43,7 +40,7 @@ require("./app/routes/auth.routes")(app); require("./app/routes/user.routes")(app); // set port, listen for requests -const PORT = process.env.PORT || 8080; +const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server is running on port ${PORT}.`); }); From 7416e11f37ff286136b671abff70cdb4b83bfd55 Mon Sep 17 00:00:00 2001 From: Marcelo R Date: Wed, 23 Jun 2021 01:12:48 -0300 Subject: [PATCH 2/9] First step --- .env | 6 ++++ app/config/db.config.js | 14 +++++--- app/models/index.js | 1 + app/routes/user.routes.js | 1 + package.json | 4 ++- server.js | 37 +++++++++++++++++++- token.js | 71 +++++++++++++++++++++++++++++++++++++++ user.js | 24 +++++++++++++ 8 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 .env create mode 100644 token.js create mode 100644 user.js diff --git a/.env b/.env new file mode 100644 index 0000000..c7f67dc --- /dev/null +++ b/.env @@ -0,0 +1,6 @@ +PORT=3000 +DB_NAME=PilarTecno +DB_USER=ucusita +DB_PASSWORD=wlm0L0Z9exxJSPEi + +API_KEY=ZaKWitPBeUn6Om1kCQt8pnX46M1d6i1cA3jM2if7 diff --git a/app/config/db.config.js b/app/config/db.config.js index c3b0a16..20a40ac 100644 --- a/app/config/db.config.js +++ b/app/config/db.config.js @@ -1,9 +1,15 @@ +require('dotenv').config(); + const dbUser = process.env.DB_USER; const dbPass = process.env.DB_PASSWORD; -const dbName = 'PilarTecno' -const dbUri = `mongodb+srv://${dbUser}:${dbPass}@cluster0.qtcrz.mongodb.net/${dbName}?retryWrites=true&w=majority`; -const mongooseOptions = {useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true}; - +const dbName = process.env.DB_NAME; +const dbUri = `mongodb+srv://${dbUser}:${dbPass}@cluster0.xj3as.mongodb.net/${dbName}?retryWrites=true&w=majority`; +const mongooseOptions = + { + useNewUrlParser: true, + useUnifiedTopology: true, + useCreateIndex: true + }; module.exports = { dbUri, mongooseOptions diff --git a/app/models/index.js b/app/models/index.js index ad610fe..607ccf0 100644 --- a/app/models/index.js +++ b/app/models/index.js @@ -7,6 +7,7 @@ db.mongoose = mongoose; db.user = require("./user.model"); db.role = require("./role.model"); + db.refreshToken = require("./refreshToken.model"); db.ROLES = ["user", "admin", "moderator"]; diff --git a/app/routes/user.routes.js b/app/routes/user.routes.js index 0b2b2fa..725e355 100644 --- a/app/routes/user.routes.js +++ b/app/routes/user.routes.js @@ -13,6 +13,7 @@ module.exports = function(app) { app.get("/api/test/all", controller.allAccess); app.get("/api/test/user", [authJwt.verifyToken], controller.userBoard); + app.get("/api/test/user", controller.userBoard); app.get( "/api/test/mod", diff --git a/package.json b/package.json index 2497f27..1b570f8 100644 --- a/package.json +++ b/package.json @@ -19,12 +19,14 @@ "author": "bezkoder", "license": "ISC", "dependencies": { + "bcrypt": "^5.0.1", "bcryptjs": "^2.4.3", "body-parser": "^1.19.0", "cors": "^2.8.5", + "dotenv": "^10.0.0", "express": "^4.17.1", "jsonwebtoken": "^8.5.1", - "mongoose": "^5.12.10", + "mongoose": "^5.12.14", "uuid": "^8.3.2" }, "devDependencies": { diff --git a/server.js b/server.js index 17d6283..c35f5d7 100644 --- a/server.js +++ b/server.js @@ -5,7 +5,8 @@ const dbConfig = require("./app/config/db.config"); const app = express(); let corsOptions = { - origin: "http://localhost:8081" + //origin: "http://localhost:8081" + origin: "*" }; app.use(cors(corsOptions)); @@ -18,12 +19,14 @@ app.use(express.urlencoded({ extended: true })); const db = require("./app/models"); const Role = db.role; +const User = db.user; db.mongoose .connect(dbConfig.dbUri, dbConfig.mongooseOptions) .then(() => { console.log("Successfully connect to MongoDB."); initial(); + initialUser(); }) .catch(err => { console.error("Connection error", err); @@ -45,6 +48,26 @@ app.listen(PORT, () => { console.log(`Server is running on port ${PORT}.`); }); +function initialUser() { + User.estimatedDocumentCount((err, count) => { + if (!err && count === 0) { + new User({ + username: "Marcelo", + email: "conect2000@hotmail.com", + password: "ucusita", + role: "60d2a75331deac23284d8b7a" + }).save(err => { + if (err) { + console.log("error", err); + } + + console.log("added the 'new user' to Users collection"); + }); + + } + }); +} + function initial() { Role.estimatedDocumentCount((err, count) => { if (!err && count === 0) { @@ -77,6 +100,18 @@ function initial() { console.log("added 'admin' to roles collection"); }); + + new Role({ + name: "operator" + }).save(err => { + if (err) { + console.log("error", err); + } + + console.log("added 'operator' to roles collection"); + }); } }); + + } diff --git a/token.js b/token.js new file mode 100644 index 0000000..b21619e --- /dev/null +++ b/token.js @@ -0,0 +1,71 @@ +const express = require('express'); +const app = express(); +const jwt = require('jsonwebtoken'); +const bodyparser = require('body-parser'); +const user = {username : "user",password : "pass"} + +app.use(bodyparser.json()); + +const checkToken = function (req,res,next) +{ + const header = req.headers['authorization']; + if(typeof header !== 'undefined') + { + const bearer = header.split(' '); + const token = bearer[1]; + req.token=token; + next(); + } + else + { + res.sendStatus(403); + } + } + + +app.post('/login',function (req,res) +{ + const { body } = req; + const { username } = body; + const { password } = body; + + if(username === user.username && password === user.password) + { + jwt.sign({user},'privatekey',{expiresIn : '1h'},function (err,token){ + if(err) + { + console.log(err) + } + console.log(token); + res.end(); + }); + } + else + { + console.log('Error : Could not log in'); + } +}); + +app.get('/data',checkToken,function(req,res) +{ + jwt.verify(req.token,'privatekey',function (err,authorizedata) + { + if(err) + { + console.log('Error : Could not connect to the protected route'); + res.sendStatus(403); + } + else + { + res.json({ + message : 'Successful log in', + authorizedata + }); + console.log('Success : Connected to protected route'); + } + + }); + +}); + +app.listen(3000,console.log("Server is running at 3000")); \ No newline at end of file diff --git a/user.js b/user.js new file mode 100644 index 0000000..e888914 --- /dev/null +++ b/user.js @@ -0,0 +1,24 @@ +var mongoose = require('mongoose'); +var bcrypt = require('bcryptjs') +var userSchema = new mongoose.Schema({ + first: String, + email: {type:String,unique:true}, + password: String, + image:String +},{timestamps:true}) +userSchema.pre('save', function (next) { + var user = this; + if (!user.isModified('password')) {return next()}; + bcrypt.hash(user.password,10).then((hashedPassword) => { + user.password = hashedPassword; + next(); + }) +}, function (err) { + next(err) +}) +userSchema.methods.comparePassword=function(candidatePassword,next){ bcrypt.compare(candidatePassword,this.password,function(err,isMatch){ + if(err) return next(err); + next(null,isMatch) + }) +} +module.exports = mongoose.model("user", userSchema); \ No newline at end of file From eebfc9d09b6e49920a24c5782b2762e48c97cb95 Mon Sep 17 00:00:00 2001 From: Marcelo R Date: Wed, 23 Jun 2021 01:14:54 -0300 Subject: [PATCH 3/9] first step #2 --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 25c8fdb..8f5e467 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules -package-lock.json \ No newline at end of file +package-lock.json +.env \ No newline at end of file From a215c626bf75be02032a62511ffa942fc890fed9 Mon Sep 17 00:00:00 2001 From: Marcelo R Date: Wed, 23 Jun 2021 02:03:12 -0300 Subject: [PATCH 4/9] Second step --- app/models/user.model.js | 2 +- server.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/models/user.model.js b/app/models/user.model.js index 03af285..ed8c63d 100644 --- a/app/models/user.model.js +++ b/app/models/user.model.js @@ -8,7 +8,7 @@ const User = mongoose.model( password: String, roles: [ { - type: mongoose.Schema.Types.ObjectId, + type: mongoose.Schema.Types.ObjectId, ref: "Role" } ] diff --git a/server.js b/server.js index c35f5d7..0f8d609 100644 --- a/server.js +++ b/server.js @@ -52,10 +52,10 @@ function initialUser() { User.estimatedDocumentCount((err, count) => { if (!err && count === 0) { new User({ - username: "Marcelo", - email: "conect2000@hotmail.com", - password: "ucusita", - role: "60d2a75331deac23284d8b7a" + username: "Luciano", + email: "montero.luciano@gmail.com", + password: "lucho", + roles: "60d2a75331deac23284d8b7a" }).save(err => { if (err) { console.log("error", err); From 2809dc1e4d018a9ffe1b07aa8ec9c6c3afa96ff8 Mon Sep 17 00:00:00 2001 From: Marcelo R Date: Thu, 24 Jun 2021 00:24:38 -0300 Subject: [PATCH 5/9] Near the finish #1 --- app/config/Schema/apod.schema.js | 16 +++++ app/controllers/auth.controller.js | 4 +- app/controllers/nasa.controller.js | 45 +++++++++++++ app/controllers/user.controller.js | 22 ++++++- app/middlewares/authJwt.js | 34 +++++++++- app/routes/user.routes.js | 27 +++++++- app/services/database/apod.mongo.service.js | 16 +++++ package.json | 2 + token.js | 71 --------------------- user.js | 24 ------- 10 files changed, 160 insertions(+), 101 deletions(-) create mode 100644 app/config/Schema/apod.schema.js create mode 100644 app/controllers/nasa.controller.js create mode 100644 app/services/database/apod.mongo.service.js delete mode 100644 token.js delete mode 100644 user.js diff --git a/app/config/Schema/apod.schema.js b/app/config/Schema/apod.schema.js new file mode 100644 index 0000000..39d9c58 --- /dev/null +++ b/app/config/Schema/apod.schema.js @@ -0,0 +1,16 @@ +const Schema = require('mongoose').Schema; +const mongoose = require('mongoose'); + +const apodSchema = new Schema({ + // date: String, + // explanation: String, + // hdurl: String, + // media_type: String, + // service_version: String, + title: String, + // url: String, + // creation_date: { type: Date, default: Date.now }, + // last_modified_date: { type: Date, default: Date.now } +}); + +module.exports = mongoose.model('apod', apodSchema); \ No newline at end of file diff --git a/app/controllers/auth.controller.js b/app/controllers/auth.controller.js index 2065bb3..6be7b11 100644 --- a/app/controllers/auth.controller.js +++ b/app/controllers/auth.controller.js @@ -9,7 +9,7 @@ exports.signup = (req, res) => { const user = new User({ username: req.body.username, email: req.body.email, - password: bcrypt.hashSync(req.body.password, 8), + password: bcrypt.hashSync(req.body.password, 8) }); user.save((err, user) => { @@ -63,7 +63,7 @@ exports.signup = (req, res) => { exports.signin = (req, res) => { User.findOne({ - username: req.body.username, + username: req.body.username }) .populate("roles", "-__v") .exec(async (err, user) => { diff --git a/app/controllers/nasa.controller.js b/app/controllers/nasa.controller.js new file mode 100644 index 0000000..fe8f988 --- /dev/null +++ b/app/controllers/nasa.controller.js @@ -0,0 +1,45 @@ +const axios = require('axios').default; +const querystring = require('querystring'); +const apiKey = process.env.API_KEY; +const apodMongoService = require('../services/database/apod.mongo.service'); +async function getIndex(req, res){ + res.json({message: 'This is the Nasa root route'}); +} + +async function getPictureOfTheDay(req, res){ + const query = { + date: req.query.date, + start_date: req.query.start_date, + end_date: req.query.end_date + }; + const axiosParams = querystring.stringify({api_key: apiKey, ...query}) + console.log(axiosParams); + axios.get(`https://api.nasa.gov/planetary/apod?${axiosParams}`) + .then((response) => { + res.json(response.data); + }) + .catch(err => { + res.status(500).json(err); + }); +} + +async function getMarsPicture(req, res){ + const query = { + earth_date: req.query.earth_date + }; + const axiosParams = querystring.stringify({api_key: apiKey, ...query}); + axios.get(`https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?${axiosParams}`) + .then((response) => { + res.json(response.data); + }) + .catch(err => { + res.status(500).json(err); + }); +} + +async function savePictureOfTheDay(req, res){ + const response = await apodMongoService.saveApod(); + res.json(response); +} + +module.exports = {getIndex, getPictureOfTheDay, getMarsPicture, savePictureOfTheDay}; \ No newline at end of file diff --git a/app/controllers/user.controller.js b/app/controllers/user.controller.js index e2fa15b..eb21ad6 100644 --- a/app/controllers/user.controller.js +++ b/app/controllers/user.controller.js @@ -1,15 +1,33 @@ +const nasaController = require('../controllers/nasa.controller'); + exports.allAccess = (req, res) => { res.status(200).send("Public Content."); }; exports.userBoard = (req, res) => { + console.log("Puedo acceder al contenido del usuario"); res.status(200).send("User Content."); }; +exports.apiaBoard = (req, res) => { + nasaController.getPictureOfTheDay(req, res); + res.status(200).send("User Authorized."); +}; + +exports.apibBoard = (req, res) => { + nasaController.getMarsPicture(req, res); + res.status(200).send("User Authorized."); +}; + +exports.apicBoard = (req, res) => { + nasaController.savePictureOfTheDay(req, res); + res.status(200).send("User Authorized."); +}; + exports.adminBoard = (req, res) => { - res.status(200).send("Admin Content."); + res.status(200).send("Admin Content. You can´t access to another contents."); }; exports.moderatorBoard = (req, res) => { - res.status(200).send("Moderator Content."); + res.status(200).send("Moderator Content. You can´t access to another contents."); }; diff --git a/app/middlewares/authJwt.js b/app/middlewares/authJwt.js index 3a02e98..c518297 100644 --- a/app/middlewares/authJwt.js +++ b/app/middlewares/authJwt.js @@ -92,9 +92,41 @@ const isModerator = (req, res, next) => { }); }; +const isUser = (req, res, next) => { + User.findById(req.userId).exec((err, user) => { + if (err) { + res.status(500).send({ message: err }); + return; + } + + Role.find( + { + _id: { $in: user.roles } + }, + (err, roles) => { + if (err) { + res.status(500).send({ message: err }); + return; + } + + for (let i = 0; i < roles.length; i++) { + if (roles[i].name === "user") { + next(); + return; + } + } + + res.status(403).send({ message: "Require User Role!" }); + return; + } + ); + }); +}; + const authJwt = { verifyToken, isAdmin, - isModerator + isModerator, + isUser }; module.exports = authJwt; diff --git a/app/routes/user.routes.js b/app/routes/user.routes.js index 725e355..5335870 100644 --- a/app/routes/user.routes.js +++ b/app/routes/user.routes.js @@ -13,7 +13,32 @@ module.exports = function(app) { app.get("/api/test/all", controller.allAccess); app.get("/api/test/user", [authJwt.verifyToken], controller.userBoard); - app.get("/api/test/user", controller.userBoard); + + /* Acceso a APIs personales */ + //app.get("/api/access/a1", [authJwt.verifyToken], controller.userBoard); + //app.get("/api/access/a2", [authJwt.verifyToken], controller.userBoard); + //app.get("/api/access/a3", [authJwt.verifyToken], controller.userBoard); + + app.get("/api/test/user", [authJwt.verifyToken], controller.userBoard); + + app.get( + "/api/test/apia", + [authJwt.verifyToken, authJwt.isUser], + controller.apiaBoard + ); + + app.get( + "/api/test/apib", + [authJwt.verifyToken, authJwt.isUser], + controller.apibBoard + ); + + app.get( + "/api/test/apic", + [authJwt.verifyToken, authJwt.isUser], + controller.apicBoard + ); + app.get( "/api/test/mod", diff --git a/app/services/database/apod.mongo.service.js b/app/services/database/apod.mongo.service.js new file mode 100644 index 0000000..c33e17d --- /dev/null +++ b/app/services/database/apod.mongo.service.js @@ -0,0 +1,16 @@ +const apod = require('../../config/Schema/apod.schema'); + +async function saveApod(){ + const apodToday = new apod({title: 'my apod'}); + try{ + await apodToday.save((err, apodToday) => { + console.log('new element added to the DB', apodToday); + }); + } catch(err){ + throw err; + } + + return {status: 'ok'}; +}; + +module.exports = {saveApod}; diff --git a/package.json b/package.json index 1b570f8..ffd297c 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "author": "bezkoder", "license": "ISC", "dependencies": { + "axios": "^0.21.1", "bcrypt": "^5.0.1", "bcryptjs": "^2.4.3", "body-parser": "^1.19.0", @@ -27,6 +28,7 @@ "express": "^4.17.1", "jsonwebtoken": "^8.5.1", "mongoose": "^5.12.14", + "querystring": "^0.2.1", "uuid": "^8.3.2" }, "devDependencies": { diff --git a/token.js b/token.js deleted file mode 100644 index b21619e..0000000 --- a/token.js +++ /dev/null @@ -1,71 +0,0 @@ -const express = require('express'); -const app = express(); -const jwt = require('jsonwebtoken'); -const bodyparser = require('body-parser'); -const user = {username : "user",password : "pass"} - -app.use(bodyparser.json()); - -const checkToken = function (req,res,next) -{ - const header = req.headers['authorization']; - if(typeof header !== 'undefined') - { - const bearer = header.split(' '); - const token = bearer[1]; - req.token=token; - next(); - } - else - { - res.sendStatus(403); - } - } - - -app.post('/login',function (req,res) -{ - const { body } = req; - const { username } = body; - const { password } = body; - - if(username === user.username && password === user.password) - { - jwt.sign({user},'privatekey',{expiresIn : '1h'},function (err,token){ - if(err) - { - console.log(err) - } - console.log(token); - res.end(); - }); - } - else - { - console.log('Error : Could not log in'); - } -}); - -app.get('/data',checkToken,function(req,res) -{ - jwt.verify(req.token,'privatekey',function (err,authorizedata) - { - if(err) - { - console.log('Error : Could not connect to the protected route'); - res.sendStatus(403); - } - else - { - res.json({ - message : 'Successful log in', - authorizedata - }); - console.log('Success : Connected to protected route'); - } - - }); - -}); - -app.listen(3000,console.log("Server is running at 3000")); \ No newline at end of file diff --git a/user.js b/user.js deleted file mode 100644 index e888914..0000000 --- a/user.js +++ /dev/null @@ -1,24 +0,0 @@ -var mongoose = require('mongoose'); -var bcrypt = require('bcryptjs') -var userSchema = new mongoose.Schema({ - first: String, - email: {type:String,unique:true}, - password: String, - image:String -},{timestamps:true}) -userSchema.pre('save', function (next) { - var user = this; - if (!user.isModified('password')) {return next()}; - bcrypt.hash(user.password,10).then((hashedPassword) => { - user.password = hashedPassword; - next(); - }) -}, function (err) { - next(err) -}) -userSchema.methods.comparePassword=function(candidatePassword,next){ bcrypt.compare(candidatePassword,this.password,function(err,isMatch){ - if(err) return next(err); - next(null,isMatch) - }) -} -module.exports = mongoose.model("user", userSchema); \ No newline at end of file From cacc8c53631d32172c1380018f756baa9edebe34 Mon Sep 17 00:00:00 2001 From: Marcelo R Date: Thu, 24 Jun 2021 02:40:30 -0300 Subject: [PATCH 6/9] Finish task --- app/config/Schema/apod.schema.js | 15 +++++++------- app/controllers/nasa.controller.js | 23 +++++++++++++++++---- app/controllers/user.controller.js | 7 ++----- app/routes/user.routes.js | 9 +------- app/services/database/apod.mongo.service.js | 13 +++++++++--- 5 files changed, 39 insertions(+), 28 deletions(-) diff --git a/app/config/Schema/apod.schema.js b/app/config/Schema/apod.schema.js index 39d9c58..8bd78e2 100644 --- a/app/config/Schema/apod.schema.js +++ b/app/config/Schema/apod.schema.js @@ -2,15 +2,14 @@ const Schema = require('mongoose').Schema; const mongoose = require('mongoose'); const apodSchema = new Schema({ - // date: String, - // explanation: String, - // hdurl: String, - // media_type: String, - // service_version: String, + date: String, + explanation: String, + media_type: String, + service_version: String, title: String, - // url: String, - // creation_date: { type: Date, default: Date.now }, - // last_modified_date: { type: Date, default: Date.now } + url: String, + creation_date: { type: Date, default: Date.now }, + last_modified_date: { type: Date, default: Date.now } }); module.exports = mongoose.model('apod', apodSchema); \ No newline at end of file diff --git a/app/controllers/nasa.controller.js b/app/controllers/nasa.controller.js index fe8f988..7e6d2cb 100644 --- a/app/controllers/nasa.controller.js +++ b/app/controllers/nasa.controller.js @@ -2,17 +2,17 @@ const axios = require('axios').default; const querystring = require('querystring'); const apiKey = process.env.API_KEY; const apodMongoService = require('../services/database/apod.mongo.service'); + async function getIndex(req, res){ res.json({message: 'This is the Nasa root route'}); } async function getPictureOfTheDay(req, res){ const query = { - date: req.query.date, start_date: req.query.start_date, end_date: req.query.end_date }; - const axiosParams = querystring.stringify({api_key: apiKey, ...query}) + const axiosParams = querystring.stringify({api_key: apiKey, ...query}); console.log(axiosParams); axios.get(`https://api.nasa.gov/planetary/apod?${axiosParams}`) .then((response) => { @@ -37,9 +37,24 @@ async function getMarsPicture(req, res){ }); } +async function savePictureOfTheDate(req, res){ + const query = { + date: req.query.date + }; + const axiosParams = querystring.stringify({api_key: apiKey, ...query}); + console.log(axiosParams); + axios.get(`https://api.nasa.gov/planetary/apod?${axiosParams}`) + .then((response) => { + savePictureOfTheDay(response.data, res); + }) + .catch(err => { + res.status(500).json(err); + }); +} + async function savePictureOfTheDay(req, res){ - const response = await apodMongoService.saveApod(); + const response = await apodMongoService.saveApod(req); res.json(response); } -module.exports = {getIndex, getPictureOfTheDay, getMarsPicture, savePictureOfTheDay}; \ No newline at end of file +module.exports = {getIndex, getPictureOfTheDay, getMarsPicture, savePictureOfTheDay, savePictureOfTheDate}; \ No newline at end of file diff --git a/app/controllers/user.controller.js b/app/controllers/user.controller.js index eb21ad6..73bd8f0 100644 --- a/app/controllers/user.controller.js +++ b/app/controllers/user.controller.js @@ -11,17 +11,14 @@ exports.userBoard = (req, res) => { exports.apiaBoard = (req, res) => { nasaController.getPictureOfTheDay(req, res); - res.status(200).send("User Authorized."); }; exports.apibBoard = (req, res) => { - nasaController.getMarsPicture(req, res); - res.status(200).send("User Authorized."); + nasaController.getMarsPicture(req, res); }; exports.apicBoard = (req, res) => { - nasaController.savePictureOfTheDay(req, res); - res.status(200).send("User Authorized."); + nasaController.savePictureOfTheDate(req, res); }; exports.adminBoard = (req, res) => { diff --git a/app/routes/user.routes.js b/app/routes/user.routes.js index 5335870..867f461 100644 --- a/app/routes/user.routes.js +++ b/app/routes/user.routes.js @@ -14,13 +14,6 @@ module.exports = function(app) { app.get("/api/test/user", [authJwt.verifyToken], controller.userBoard); - /* Acceso a APIs personales */ - //app.get("/api/access/a1", [authJwt.verifyToken], controller.userBoard); - //app.get("/api/access/a2", [authJwt.verifyToken], controller.userBoard); - //app.get("/api/access/a3", [authJwt.verifyToken], controller.userBoard); - - app.get("/api/test/user", [authJwt.verifyToken], controller.userBoard); - app.get( "/api/test/apia", [authJwt.verifyToken, authJwt.isUser], @@ -33,7 +26,7 @@ module.exports = function(app) { controller.apibBoard ); - app.get( + app.post( "/api/test/apic", [authJwt.verifyToken, authJwt.isUser], controller.apicBoard diff --git a/app/services/database/apod.mongo.service.js b/app/services/database/apod.mongo.service.js index c33e17d..008bd2a 100644 --- a/app/services/database/apod.mongo.service.js +++ b/app/services/database/apod.mongo.service.js @@ -1,7 +1,14 @@ const apod = require('../../config/Schema/apod.schema'); -async function saveApod(){ - const apodToday = new apod({title: 'my apod'}); +async function saveApod(data){ + const apodToday = new apod({ + date: data.date, + explanation: data.explanation, + media_type: data.media_type, + service_version: data.service_version, + title: data.title, + url: data.url + }); try{ await apodToday.save((err, apodToday) => { console.log('new element added to the DB', apodToday); @@ -10,7 +17,7 @@ async function saveApod(){ throw err; } - return {status: 'ok'}; + return {status: 'Data saved correctly. ok'}; }; module.exports = {saveApod}; From a9db2e171d39a13e0f4873047544394300ce8875 Mon Sep 17 00:00:00 2001 From: Marcelo R Date: Thu, 24 Jun 2021 05:08:25 -0300 Subject: [PATCH 7/9] Finished task --- app/config/Schema/apod.schema.js | 2 +- app/controllers/gis.controller.js | 61 +++++++++++++++++++++ app/controllers/nasa.controller.js | 2 +- app/controllers/user.controller.js | 20 ++++++- app/routes/user.routes.js | 35 ++++++++++-- app/services/database/apod.mongo.service.js | 4 +- ended-task.md | 29 ++++++++++ server.js | 6 +- 8 files changed, 147 insertions(+), 12 deletions(-) create mode 100644 app/controllers/gis.controller.js create mode 100644 ended-task.md diff --git a/app/config/Schema/apod.schema.js b/app/config/Schema/apod.schema.js index 8bd78e2..5ad89ef 100644 --- a/app/config/Schema/apod.schema.js +++ b/app/config/Schema/apod.schema.js @@ -12,4 +12,4 @@ const apodSchema = new Schema({ last_modified_date: { type: Date, default: Date.now } }); -module.exports = mongoose.model('apod', apodSchema); \ No newline at end of file +module.exports = mongoose.model('apinasa', apodSchema); \ No newline at end of file diff --git a/app/controllers/gis.controller.js b/app/controllers/gis.controller.js new file mode 100644 index 0000000..dfb5884 --- /dev/null +++ b/app/controllers/gis.controller.js @@ -0,0 +1,61 @@ +const axios = require('axios').default; +const querystring = require('querystring'); +const apiKey = process.env.API_KEY; +const apodMongoService = require('../services/database/apod.mongo.service'); + +async function getCities(req, res){ + axios.get(`https://apis.datos.gob.ar/georef/api/provincias`) + .then((response) => { + res.json(response.data); + }) + .catch(err => { + res.status(500).json(err); + }); +} + +async function getCitiesFilter(req, res){ + const query = { + nombre: req.query.nombre + }; + const axiosParams = querystring.stringify({...query}); + axios.get(`https://apis.datos.gob.ar/georef/api/provincias?${axiosParams}`) + .then((response) => { + res.json(response.data); + }) + .catch(err => { + res.status(500).json(err); + }); +} + +async function getDepartmentFilter(req, res){ + const query = { + provincia: req.query.provincia, + max : 100, + campos: "completo" + }; + const axiosParams = querystring.stringify({...query}); + axios.get(`https://apis.datos.gob.ar/georef/api/departamentos?${axiosParams}`) + .then((response) => { + res.json(response.data); + }) + .catch(err => { + res.status(500).json(err); + }); +} + +async function getLocalitiesFilter(req, res){ + const query = { + provincia: req.query.provincia, + max : 100 + }; + const axiosParams = querystring.stringify({...query}); + axios.get(`https://apis.datos.gob.ar/georef/api/localidades?${axiosParams}`) + .then((response) => { + res.json(response.data); + }) + .catch(err => { + res.status(500).json(err); + }); +} + +module.exports = {getCities, getCitiesFilter, getDepartmentFilter, getLocalitiesFilter}; \ No newline at end of file diff --git a/app/controllers/nasa.controller.js b/app/controllers/nasa.controller.js index 7e6d2cb..c99d793 100644 --- a/app/controllers/nasa.controller.js +++ b/app/controllers/nasa.controller.js @@ -53,7 +53,7 @@ async function savePictureOfTheDate(req, res){ } async function savePictureOfTheDay(req, res){ - const response = await apodMongoService.saveApod(req); + const response = await apodMongoService.saveNasa(req); res.json(response); } diff --git a/app/controllers/user.controller.js b/app/controllers/user.controller.js index 73bd8f0..99573a5 100644 --- a/app/controllers/user.controller.js +++ b/app/controllers/user.controller.js @@ -1,14 +1,15 @@ const nasaController = require('../controllers/nasa.controller'); +const gisController = require('../controllers/gis.controller'); exports.allAccess = (req, res) => { res.status(200).send("Public Content."); }; exports.userBoard = (req, res) => { - console.log("Puedo acceder al contenido del usuario"); res.status(200).send("User Content."); }; +/* Personal Develop Area */ exports.apiaBoard = (req, res) => { nasaController.getPictureOfTheDay(req, res); }; @@ -21,6 +22,23 @@ exports.apicBoard = (req, res) => { nasaController.savePictureOfTheDate(req, res); }; +exports.apidBoard = (req, res) => { + gisController.getCities(req, res); +}; + +exports.apieBoard = (req, res) => { + gisController.getCitiesFilter(req, res); +}; + +exports.apifBoard = (req, res) => { + gisController.getDepartmentFilter(req, res); +}; + +exports.apigBoard = (req, res) => { + gisController.getLocalitiesFilter(req, res); +}; +/* End of Personal Develop Area */ + exports.adminBoard = (req, res) => { res.status(200).send("Admin Content. You can´t access to another contents."); }; diff --git a/app/routes/user.routes.js b/app/routes/user.routes.js index 867f461..7a2834d 100644 --- a/app/routes/user.routes.js +++ b/app/routes/user.routes.js @@ -10,10 +10,7 @@ module.exports = function(app) { next(); }); - app.get("/api/test/all", controller.allAccess); - - app.get("/api/test/user", [authJwt.verifyToken], controller.userBoard); - + /* Personal develop area for Final Work */ app.get( "/api/test/apia", [authJwt.verifyToken, authJwt.isUser], @@ -32,6 +29,36 @@ module.exports = function(app) { controller.apicBoard ); + //------------------------------------- + + app.get( + "/api/test/apid", + [authJwt.verifyToken, authJwt.isUser], + controller.apidBoard + ); + + app.get( + "/api/test/apie", + [authJwt.verifyToken, authJwt.isUser], + controller.apieBoard + ); + + app.get( + "/api/test/apif", + [authJwt.verifyToken, authJwt.isUser], + controller.apifBoard + ); + + app.get( + "/api/test/apig", + [authJwt.verifyToken, authJwt.isUser], + controller.apigBoard + ); + /* End of Personal develop area for Final Work */ + + app.get("/api/test/all", controller.allAccess); + + app.get("/api/test/user", [authJwt.verifyToken], controller.userBoard); app.get( "/api/test/mod", diff --git a/app/services/database/apod.mongo.service.js b/app/services/database/apod.mongo.service.js index 008bd2a..784e6cb 100644 --- a/app/services/database/apod.mongo.service.js +++ b/app/services/database/apod.mongo.service.js @@ -1,6 +1,6 @@ const apod = require('../../config/Schema/apod.schema'); -async function saveApod(data){ +async function saveNasa(data){ const apodToday = new apod({ date: data.date, explanation: data.explanation, @@ -20,4 +20,4 @@ async function saveApod(data){ return {status: 'Data saved correctly. ok'}; }; -module.exports = {saveApod}; +module.exports = {saveNasa}; diff --git a/ended-task.md b/ended-task.md new file mode 100644 index 0000000..79790b4 --- /dev/null +++ b/ended-task.md @@ -0,0 +1,29 @@ +**FINAL REPORT** + +The Final Task was finished + +You can see the Postman Document for API access in +## **[API DOCUMENT](https://documenter.getpostman.com/view/10683014/TzecD5dB#91cd7156-7c27-5154-c562-ed94ff92ad2a)** + +I use the the next APIs: + +- [NASA API](https://api.nasa.gov/) +- [API del Servicio de Normalización de Datos Geográficos de Argentina](https://datosgobar.github.io/georef-ar-api/) + +Mi personal Github for this work is [here](https://github.com/ucusita/jwt-refresh-token-node-js-mongodb/). + +**I make seven (7) endpoints that must consume external service APIs .** + +**I respect the structure used for the endpoint.** I used: + +* Routes. +* Controllers. +* Services. +* Environment variables for sensitive data (like API keys or DB access). + +**In one of the three endpoints, i saved the response to a Mongodb collection called apinasas.** For this I used MongoDB Atlas. + +**The endpoints are protected with a JWT Token.** +Only the endpoints append to the initial code allow users with the role "user" to use the endpoint. +The rest of the endpoints allow the use. + diff --git a/server.js b/server.js index 0f8d609..4c4bbb2 100644 --- a/server.js +++ b/server.js @@ -52,9 +52,9 @@ function initialUser() { User.estimatedDocumentCount((err, count) => { if (!err && count === 0) { new User({ - username: "Luciano", - email: "montero.luciano@gmail.com", - password: "lucho", + username: "Marcelo", + email: "conect2000@gmail.com", + password: "12345678", roles: "60d2a75331deac23284d8b7a" }).save(err => { if (err) { From a494e21fd1e03ca3cbb9c623e748d9c9c7035e13 Mon Sep 17 00:00:00 2001 From: Marcelo R Date: Thu, 24 Jun 2021 05:14:07 -0300 Subject: [PATCH 8/9] .env deleted manually --- .env | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index c7f67dc..0000000 --- a/.env +++ /dev/null @@ -1,6 +0,0 @@ -PORT=3000 -DB_NAME=PilarTecno -DB_USER=ucusita -DB_PASSWORD=wlm0L0Z9exxJSPEi - -API_KEY=ZaKWitPBeUn6Om1kCQt8pnX46M1d6i1cA3jM2if7 From ba4a28341369f2e30cafc494ee317f057eadbc6d Mon Sep 17 00:00:00 2001 From: Marcelo R Date: Thu, 24 Jun 2021 05:17:12 -0300 Subject: [PATCH 9/9] Edited Final Report --- ended-task.md => FINAL REPORT README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ended-task.md => FINAL REPORT README.md (100%) diff --git a/ended-task.md b/FINAL REPORT README.md similarity index 100% rename from ended-task.md rename to FINAL REPORT README.md