├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── _config.yml ├── index.js ├── models ├── Person.js ├── Profile.js └── Question.js ├── package-lock.json ├── package.json ├── routes └── api │ ├── auth.js │ ├── profile.js │ └── questions.js ├── setup └── myurl.js └── strategies └── jsonwtStrategy.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Adhikansh Mittal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Minature-Stackoverflow-API's [![HitCount](http://hits.dwyl.io/HrithikMittal/Minature-Stackoverflow-APIs.svg)](http://hits.dwyl.io/HrithikMittal/Minature-Stackoverflow-APIs) [![Gitter](https://badges.gitter.im/GDTC_Hack-In/P03.svg)](https://gitter.im/GDTC_Hack-In/P03?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 2 | 3 | # About The Project 4 | This is the Project of Minature StackOverflow API which is an API's collection which can be used to make the Backend of any Fullstack Application. These are the folllowing features in the given API's 5 | 12 | 13 | # TECHNOLOGY STACK: 14 | 21 | 22 | # Tasks to be Done 23 | ## Day1 24 | Start with the installation 25 | 34 | 35 | 36 | ## Day2 37 | 41 | Read this blogs to take help
42 | https://medium.com/code-to-express/starting-with-nodejs-b70679e8101f
https://medium.com/code-to-express/login-and-signup-page-4a65fec162f1 43 | 44 | 45 | ## Day3 46 | So till now a User can SignUp and Login. Now the Next thing to is to make the Question Schema So that a User can Post a Question and also answer to that question. Along with this User can also Upvote the answer. So Please follow these steps: 47 | 52 | 53 | ## Day4 54 | So till now a User can Post a Question after they login into the System.So for further Development please follow these steps: 55 | 60 | 61 | ## Day5 62 | So till now a User Can Post a Answer after they login but anyone can read the anser and question without the login. So for the further Development Please follow these Steps: 63 | 68 | 69 | ======================================================================================================================================== 70 | 71 | ### Prerequisites 72 | 73 | To work with the api you must have to install the following: 74 | 75 | - [NodeJS](https://nodejs.org/en/download/) - Node.js® is a JavaScript runtime 76 | built on Chrome's V8 JavaScript engine. 77 | - [MongoDB Server](https://docs.mongodb.com/manual/installation/) - NoSql 78 | Database and server 79 | - [Postman](https://www.getpostman.com/downloads/) - API development environment 80 | 81 | ## Installation 82 | 83 | Before doing anything you have to clone or download and unzip the project folder, open terminal and navigate to the project folder and run: 84 | 85 | ```bash 86 | npm install 87 | ``` 88 | 89 | This will install all the dependencies required by the project. 90 | 91 | ## Getting Started 92 | 93 | To start using this API, start your local database server, open terminal and 94 | navigate to the project folder and run: 95 | 96 | ```bash 97 | npm run start 98 | ``` 99 | 100 | If an error occur, check your database server or check if you have installed the 101 | prerequisites correctly. 102 | 103 | If there was no error, open Postman and create and send a new get request to: 104 | 105 | ``` 106 | http://localhost:3000/ 107 | ``` 108 | 109 | Expected Output: 110 | 111 | ``` 112 | { 113 | message: "Welcome!" 114 | } 115 | ``` 116 | 117 | ### Authentication 118 | 119 | I used express-session to manage sessions to authenticate. We have 120 | isUserLoggedIn, isUserLoggedOut middleware function which checks if the user is 121 | authenticated or not. The session token is stored in the database using 122 | connect-mongo package and is deleted when the user logout
123 | 124 | ``` 125 | async function isUserLoggedIn (req, res, next) { 126 | try { 127 | if (!(req.session && req.session.user)) { 128 | return res.status(401).send({ 129 | error: "Unauthorized Access!" 130 | }); 131 | }else { 132 | const user = await User.findOne({ _id : req.session.user._id }) 133 | if(user) { 134 | next(); 135 | } else { 136 | req.session.user = null; 137 | return res.status(401).send({ 138 | error: "Unauthorized Access!" 139 | }); 140 | } 141 | } 142 | } catch(e) { 143 | res.status(400).send({ 144 | error: e 145 | }) 146 | } 147 | } 148 | 149 | 150 | // Function to check whether the user is logged out 151 | function isUserLoggedOut (req, res, next) { 152 | if (req.session && req.session.user) { 153 | return res.status(200).send({ 154 | message: "User already Logged In!" 155 | }); 156 | } 157 | next(); 158 | } 159 | 160 | module.exports = { 161 | isUserLoggedIn, 162 | isUserLoggedOut 163 | } 164 | ``` 165 | 166 | Note: some of the APIs which are mentionted above are not authenticate so 167 | please remember to add it. So it will help to proctect the private routes. 168 | 169 | ## Routes 170 | 171 | ### Profile 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 |
S.No.RouteMethodAccessDescription
1./GETPrivateto get personal profile
2./POSTPrivatefor UPDATING/SAVING personnal user profile
3./:usernameGETPublicfor getting user profile based on USERNAME.
4./find/everyoneGETPublicfor getting user profile of EVERYONE.
5./DELETEPrivatefor deleting user based on ID.
6./workrolePOSTPrivatefor adding work profile of a person.
7./workrole/:w_idDELETEPrivatefor deleting a specific workrole.
232 | 233 | ### Question 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 |
S.No.RouteMethodAccessDescription
1./GETPUBLICfor showing all questions.
2./POSTPrivatefor submitting questions.
3./answers/:idPOSTPrivatefor submitting answers to questions.
4./upvote/:idPOSTPrivatefor upvoting.
273 | 274 | ## Deployment 275 | 276 | This api can be hosted on platform like heroku, aws, and others. MongoDB Atlas 277 | or Matlab can be used for remote database.
For instance, the application 278 | can be deployed on [Heroku](https://signup.heroku.com/login) by creating and 279 | registering an account. Following, create a new app and choose a deployment 280 | method (terminal or github) and follow the instruction there. Remote database 281 | can be created using Mongodb Atlas or Matlab.
For 282 | [Mongodb Atlas](https://cloud.mongodb.com/user?_ga=2.185306281.1809166196.1559570784-2125252051.1557828824#/atlas/register/accountProfile), 283 | you need to just to create your account and make a new cluster and link the 284 | cluster to your application through a URL. Following the given steps, you would 285 | have a remote application up and running. 286 | 287 | ## Contributing [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/dwyl/esta/issues) 288 | 289 | 290 | If you are the helping and contributing one, your efforts and suggestion are always welcomed. 291 | 292 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const mongoose = require("mongoose"); 3 | const bodyparser = require("body-parser"); 4 | const passport = require("passport"); 5 | 6 | //bring all routes 7 | const auth = require("./routes/api/auth"); 8 | const questions = require("./routes/api/questions"); 9 | const profile = require("./routes/api/profile"); 10 | 11 | const app = express(); 12 | 13 | //Middleware for bodyparser 14 | app.use(bodyparser.urlencoded({ extended: true })); 15 | app.use(bodyparser.json()); 16 | 17 | //mongoDB configuration 18 | const db = require("./setup/myurl").mongoURL; 19 | 20 | //Attempt to connect to database 21 | mongoose 22 | .connect(db) 23 | .then(() => console.log("MongoDB connected successfully")) 24 | .catch(err => console.log(err)); 25 | 26 | //Passport middleware 27 | app.use(passport.initialize()); 28 | 29 | //Config for JWT strategy 30 | require("./strategies/jsonwtStrategy")(passport); 31 | 32 | //just for testing -> route 33 | app.get("/", (req, res) => { 34 | res.send("Hey there Big stack"); 35 | }); 36 | 37 | //actual routes 38 | app.use("/api/auth", auth); 39 | app.use("/api/questions", questions); 40 | app.use("/api/profile", profile); 41 | 42 | const port = process.env.PORT || 3000; 43 | 44 | app.listen(port, () => console.log(`App is running at ${port}`)); 45 | -------------------------------------------------------------------------------- /models/Person.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const Schema = mongoose.Schema; 3 | 4 | const PersonSchema = new Schema({ 5 | name: { 6 | type: String, 7 | required: true 8 | }, 9 | email: { 10 | type: String, 11 | required: true 12 | }, 13 | password: { 14 | type: String, 15 | required: true 16 | }, 17 | username: { 18 | type: String 19 | }, 20 | profilepic: { 21 | type: String, 22 | default: "https://learncodeonline.in/manicon.png" 23 | }, 24 | date: { 25 | type: Date, 26 | default: Date.now 27 | } 28 | }); 29 | 30 | module.exports = Person = mongoose.model("myPerson", PersonSchema); 31 | -------------------------------------------------------------------------------- /models/Profile.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const Schema = mongoose.Schema; 3 | 4 | const ProfileSchema = new Schema({ 5 | user: { 6 | type: Schema.Types.ObjectId, 7 | ref: "myPerson" 8 | }, 9 | username: { 10 | type: String, 11 | required: true, 12 | max: 50 13 | }, 14 | website: { 15 | type: String 16 | }, 17 | country: { 18 | type: String 19 | }, 20 | languages: { 21 | type: [String], 22 | required: true 23 | }, 24 | portfolio: { 25 | type: String 26 | }, 27 | workrole: [ 28 | { 29 | role: { 30 | type: String, 31 | required: true 32 | }, 33 | company: { 34 | type: String 35 | }, 36 | country: { 37 | type: String 38 | }, 39 | from: { 40 | type: Date 41 | }, 42 | to: { 43 | type: Date 44 | }, 45 | current: { 46 | type: Boolean, 47 | default: false 48 | }, 49 | details: { 50 | type: String 51 | } 52 | } 53 | ], 54 | social: { 55 | youtube: { 56 | type: String 57 | }, 58 | facebook: { 59 | type: String 60 | }, 61 | instagram: { 62 | type: String 63 | } 64 | }, 65 | date: { 66 | type: Date, 67 | default: Date.now 68 | } 69 | }); 70 | 71 | module.exports = Profile = mongoose.model("myProfile", ProfileSchema); 72 | -------------------------------------------------------------------------------- /models/Question.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const Schema = mongoose.Schema; 3 | 4 | const QuestionSchema = new Schema({ 5 | user: { 6 | type: Schema.Types.ObjectId, 7 | ref: "myPerson" 8 | }, 9 | textone: { 10 | type: String, 11 | required: true 12 | }, 13 | texttwo: { 14 | type: String, 15 | required: true 16 | }, 17 | name: { 18 | type: String 19 | }, 20 | upvotes: [ 21 | { 22 | user: { 23 | type: Schema.Types.ObjectId, 24 | ref: "myPerson" 25 | } 26 | } 27 | ], 28 | answers: [ 29 | { 30 | user: { 31 | type: Schema.Types.ObjectId, 32 | ref: "myPerson" 33 | }, 34 | text: { 35 | type: String, 36 | required: true 37 | }, 38 | name: { 39 | type: String 40 | }, 41 | date: { 42 | type: Date, 43 | default: Date.now 44 | } 45 | } 46 | ], 47 | date: { 48 | type: Date, 49 | default: Date.now 50 | } 51 | }); 52 | 53 | module.exports = Question = mongoose.model("myQuestion", QuestionSchema); 54 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bigstack", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.5", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 10 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 11 | "requires": { 12 | "mime-types": "~2.1.18", 13 | "negotiator": "0.6.1" 14 | } 15 | }, 16 | "array-flatten": { 17 | "version": "1.1.1", 18 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 19 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 20 | }, 21 | "async": { 22 | "version": "2.6.1", 23 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", 24 | "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", 25 | "requires": { 26 | "lodash": "^4.17.10" 27 | } 28 | }, 29 | "bcryptjs": { 30 | "version": "2.4.3", 31 | "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", 32 | "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" 33 | }, 34 | "bluebird": { 35 | "version": "3.5.0", 36 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", 37 | "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" 38 | }, 39 | "body-parser": { 40 | "version": "1.18.3", 41 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", 42 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", 43 | "requires": { 44 | "bytes": "3.0.0", 45 | "content-type": "~1.0.4", 46 | "debug": "2.6.9", 47 | "depd": "~1.1.2", 48 | "http-errors": "~1.6.3", 49 | "iconv-lite": "0.4.23", 50 | "on-finished": "~2.3.0", 51 | "qs": "6.5.2", 52 | "raw-body": "2.3.3", 53 | "type-is": "~1.6.16" 54 | } 55 | }, 56 | "bson": { 57 | "version": "1.0.9", 58 | "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.9.tgz", 59 | "integrity": "sha512-IQX9/h7WdMBIW/q/++tGd+emQr0XMdeZ6icnT/74Xk9fnabWn+gZgpE+9V+gujL3hhJOoNrnDVY7tWdzc7NUTg==" 60 | }, 61 | "buffer-equal-constant-time": { 62 | "version": "1.0.1", 63 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 64 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" 65 | }, 66 | "bytes": { 67 | "version": "3.0.0", 68 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 69 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 70 | }, 71 | "content-disposition": { 72 | "version": "0.5.2", 73 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 74 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 75 | }, 76 | "content-type": { 77 | "version": "1.0.4", 78 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 79 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 80 | }, 81 | "cookie": { 82 | "version": "0.3.1", 83 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 84 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 85 | }, 86 | "cookie-signature": { 87 | "version": "1.0.6", 88 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 89 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 90 | }, 91 | "debug": { 92 | "version": "2.6.9", 93 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 94 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 95 | "requires": { 96 | "ms": "2.0.0" 97 | } 98 | }, 99 | "depd": { 100 | "version": "1.1.2", 101 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 102 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 103 | }, 104 | "destroy": { 105 | "version": "1.0.4", 106 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 107 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 108 | }, 109 | "ecdsa-sig-formatter": { 110 | "version": "1.0.10", 111 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", 112 | "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", 113 | "requires": { 114 | "safe-buffer": "^5.0.1" 115 | } 116 | }, 117 | "ee-first": { 118 | "version": "1.1.1", 119 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 120 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 121 | }, 122 | "encodeurl": { 123 | "version": "1.0.2", 124 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 125 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 126 | }, 127 | "escape-html": { 128 | "version": "1.0.3", 129 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 130 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 131 | }, 132 | "etag": { 133 | "version": "1.8.1", 134 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 135 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 136 | }, 137 | "express": { 138 | "version": "4.16.3", 139 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", 140 | "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", 141 | "requires": { 142 | "accepts": "~1.3.5", 143 | "array-flatten": "1.1.1", 144 | "body-parser": "1.18.2", 145 | "content-disposition": "0.5.2", 146 | "content-type": "~1.0.4", 147 | "cookie": "0.3.1", 148 | "cookie-signature": "1.0.6", 149 | "debug": "2.6.9", 150 | "depd": "~1.1.2", 151 | "encodeurl": "~1.0.2", 152 | "escape-html": "~1.0.3", 153 | "etag": "~1.8.1", 154 | "finalhandler": "1.1.1", 155 | "fresh": "0.5.2", 156 | "merge-descriptors": "1.0.1", 157 | "methods": "~1.1.2", 158 | "on-finished": "~2.3.0", 159 | "parseurl": "~1.3.2", 160 | "path-to-regexp": "0.1.7", 161 | "proxy-addr": "~2.0.3", 162 | "qs": "6.5.1", 163 | "range-parser": "~1.2.0", 164 | "safe-buffer": "5.1.1", 165 | "send": "0.16.2", 166 | "serve-static": "1.13.2", 167 | "setprototypeof": "1.1.0", 168 | "statuses": "~1.4.0", 169 | "type-is": "~1.6.16", 170 | "utils-merge": "1.0.1", 171 | "vary": "~1.1.2" 172 | }, 173 | "dependencies": { 174 | "body-parser": { 175 | "version": "1.18.2", 176 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", 177 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", 178 | "requires": { 179 | "bytes": "3.0.0", 180 | "content-type": "~1.0.4", 181 | "debug": "2.6.9", 182 | "depd": "~1.1.1", 183 | "http-errors": "~1.6.2", 184 | "iconv-lite": "0.4.19", 185 | "on-finished": "~2.3.0", 186 | "qs": "6.5.1", 187 | "raw-body": "2.3.2", 188 | "type-is": "~1.6.15" 189 | } 190 | }, 191 | "iconv-lite": { 192 | "version": "0.4.19", 193 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 194 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" 195 | }, 196 | "qs": { 197 | "version": "6.5.1", 198 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 199 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" 200 | }, 201 | "raw-body": { 202 | "version": "2.3.2", 203 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", 204 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", 205 | "requires": { 206 | "bytes": "3.0.0", 207 | "http-errors": "1.6.2", 208 | "iconv-lite": "0.4.19", 209 | "unpipe": "1.0.0" 210 | }, 211 | "dependencies": { 212 | "depd": { 213 | "version": "1.1.1", 214 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 215 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 216 | }, 217 | "http-errors": { 218 | "version": "1.6.2", 219 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 220 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 221 | "requires": { 222 | "depd": "1.1.1", 223 | "inherits": "2.0.3", 224 | "setprototypeof": "1.0.3", 225 | "statuses": ">= 1.3.1 < 2" 226 | } 227 | }, 228 | "setprototypeof": { 229 | "version": "1.0.3", 230 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 231 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 232 | } 233 | } 234 | }, 235 | "statuses": { 236 | "version": "1.4.0", 237 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 238 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 239 | } 240 | } 241 | }, 242 | "finalhandler": { 243 | "version": "1.1.1", 244 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 245 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 246 | "requires": { 247 | "debug": "2.6.9", 248 | "encodeurl": "~1.0.2", 249 | "escape-html": "~1.0.3", 250 | "on-finished": "~2.3.0", 251 | "parseurl": "~1.3.2", 252 | "statuses": "~1.4.0", 253 | "unpipe": "~1.0.0" 254 | }, 255 | "dependencies": { 256 | "statuses": { 257 | "version": "1.4.0", 258 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 259 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 260 | } 261 | } 262 | }, 263 | "forwarded": { 264 | "version": "0.1.2", 265 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 266 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 267 | }, 268 | "fresh": { 269 | "version": "0.5.2", 270 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 271 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 272 | }, 273 | "http-errors": { 274 | "version": "1.6.3", 275 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 276 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 277 | "requires": { 278 | "depd": "~1.1.2", 279 | "inherits": "2.0.3", 280 | "setprototypeof": "1.1.0", 281 | "statuses": ">= 1.4.0 < 2" 282 | } 283 | }, 284 | "iconv-lite": { 285 | "version": "0.4.23", 286 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 287 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 288 | "requires": { 289 | "safer-buffer": ">= 2.1.2 < 3" 290 | } 291 | }, 292 | "inherits": { 293 | "version": "2.0.3", 294 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 295 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 296 | }, 297 | "ipaddr.js": { 298 | "version": "1.6.0", 299 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", 300 | "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=" 301 | }, 302 | "jsonwebtoken": { 303 | "version": "8.3.0", 304 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz", 305 | "integrity": "sha512-oge/hvlmeJCH+iIz1DwcO7vKPkNGJHhgkspk8OH3VKlw+mbi42WtD4ig1+VXRln765vxptAv+xT26Fd3cteqag==", 306 | "requires": { 307 | "jws": "^3.1.5", 308 | "lodash.includes": "^4.3.0", 309 | "lodash.isboolean": "^3.0.3", 310 | "lodash.isinteger": "^4.0.4", 311 | "lodash.isnumber": "^3.0.3", 312 | "lodash.isplainobject": "^4.0.6", 313 | "lodash.isstring": "^4.0.1", 314 | "lodash.once": "^4.0.0", 315 | "ms": "^2.1.1" 316 | }, 317 | "dependencies": { 318 | "ms": { 319 | "version": "2.1.1", 320 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 321 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 322 | } 323 | } 324 | }, 325 | "jwa": { 326 | "version": "1.1.6", 327 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz", 328 | "integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==", 329 | "requires": { 330 | "buffer-equal-constant-time": "1.0.1", 331 | "ecdsa-sig-formatter": "1.0.10", 332 | "safe-buffer": "^5.0.1" 333 | } 334 | }, 335 | "jws": { 336 | "version": "3.1.5", 337 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz", 338 | "integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==", 339 | "requires": { 340 | "jwa": "^1.1.5", 341 | "safe-buffer": "^5.0.1" 342 | } 343 | }, 344 | "kareem": { 345 | "version": "2.2.1", 346 | "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.2.1.tgz", 347 | "integrity": "sha512-xpDFy8OxkFM+vK6pXy6JmH92ibeEFUuDWzas5M9L7MzVmHW3jzwAHxodCPV/BYkf4A31bVDLyonrMfp9RXb/oA==" 348 | }, 349 | "lodash": { 350 | "version": "4.17.10", 351 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", 352 | "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" 353 | }, 354 | "lodash.get": { 355 | "version": "4.4.2", 356 | "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", 357 | "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" 358 | }, 359 | "lodash.includes": { 360 | "version": "4.3.0", 361 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", 362 | "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" 363 | }, 364 | "lodash.isboolean": { 365 | "version": "3.0.3", 366 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", 367 | "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" 368 | }, 369 | "lodash.isinteger": { 370 | "version": "4.0.4", 371 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", 372 | "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" 373 | }, 374 | "lodash.isnumber": { 375 | "version": "3.0.3", 376 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", 377 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" 378 | }, 379 | "lodash.isplainobject": { 380 | "version": "4.0.6", 381 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 382 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" 383 | }, 384 | "lodash.isstring": { 385 | "version": "4.0.1", 386 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", 387 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" 388 | }, 389 | "lodash.once": { 390 | "version": "4.1.1", 391 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", 392 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" 393 | }, 394 | "media-typer": { 395 | "version": "0.3.0", 396 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 397 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 398 | }, 399 | "merge-descriptors": { 400 | "version": "1.0.1", 401 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 402 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 403 | }, 404 | "methods": { 405 | "version": "1.1.2", 406 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 407 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 408 | }, 409 | "mime": { 410 | "version": "1.4.1", 411 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 412 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 413 | }, 414 | "mime-db": { 415 | "version": "1.33.0", 416 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", 417 | "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" 418 | }, 419 | "mime-types": { 420 | "version": "2.1.18", 421 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", 422 | "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", 423 | "requires": { 424 | "mime-db": "~1.33.0" 425 | } 426 | }, 427 | "mongodb": { 428 | "version": "3.0.10", 429 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.0.10.tgz", 430 | "integrity": "sha512-jy9s4FgcM4rl8sHNETYHGeWcuRh9AlwQCUuMiTj041t/HD02HwyFgmm2VZdd9/mA9YNHaUJLqj0tzBx2QFivtg==", 431 | "requires": { 432 | "mongodb-core": "3.0.9" 433 | } 434 | }, 435 | "mongodb-core": { 436 | "version": "3.0.9", 437 | "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.0.9.tgz", 438 | "integrity": "sha512-buOWjdLLBlEqjHDeHYSXqXx173wHMVp7bafhdHxSjxWdB9V6Ri4myTqxjYZwL/eGFZxvd8oRQSuhwuIDbaaB+g==", 439 | "requires": { 440 | "bson": "~1.0.4", 441 | "require_optional": "^1.0.1" 442 | } 443 | }, 444 | "mongoose": { 445 | "version": "5.1.6", 446 | "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.1.6.tgz", 447 | "integrity": "sha512-p8p/3Z2kfXViqawN1TV+cZ8XbHz6SsllkytKTog+CDWfCNObyGraHQlUuRv/9aYPNKiZfq6WWITgLpJLZW/o/A==", 448 | "requires": { 449 | "async": "2.6.1", 450 | "bson": "~1.0.5", 451 | "kareem": "2.2.1", 452 | "lodash.get": "4.4.2", 453 | "mongodb": "3.0.10", 454 | "mongoose-legacy-pluralize": "1.0.2", 455 | "mpath": "0.4.1", 456 | "mquery": "3.0.0", 457 | "ms": "2.0.0", 458 | "regexp-clone": "0.0.1", 459 | "sliced": "1.0.1" 460 | } 461 | }, 462 | "mongoose-legacy-pluralize": { 463 | "version": "1.0.2", 464 | "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", 465 | "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" 466 | }, 467 | "mpath": { 468 | "version": "0.4.1", 469 | "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.4.1.tgz", 470 | "integrity": "sha512-NNY/MpBkALb9jJmjpBlIi6GRoLveLUM0pJzgbp9vY9F7IQEb/HREC/nxrixechcQwd1NevOhJnWWV8QQQRE+OA==" 471 | }, 472 | "mquery": { 473 | "version": "3.0.0", 474 | "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.0.0.tgz", 475 | "integrity": "sha512-WL1Lk8v4l8VFSSwN3yCzY9TXw+fKVYKn6f+w86TRzOLSE8k1yTgGaLBPUByJQi8VcLbOdnUneFV/y3Kv874pnQ==", 476 | "requires": { 477 | "bluebird": "3.5.0", 478 | "debug": "2.6.9", 479 | "regexp-clone": "0.0.1", 480 | "sliced": "0.0.5" 481 | }, 482 | "dependencies": { 483 | "sliced": { 484 | "version": "0.0.5", 485 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-0.0.5.tgz", 486 | "integrity": "sha1-XtwETKTrb3gW1Qui/GPiXY/kcH8=" 487 | } 488 | } 489 | }, 490 | "ms": { 491 | "version": "2.0.0", 492 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 493 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 494 | }, 495 | "negotiator": { 496 | "version": "0.6.1", 497 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 498 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 499 | }, 500 | "on-finished": { 501 | "version": "2.3.0", 502 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 503 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 504 | "requires": { 505 | "ee-first": "1.1.1" 506 | } 507 | }, 508 | "parseurl": { 509 | "version": "1.3.2", 510 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 511 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 512 | }, 513 | "passport": { 514 | "version": "0.4.0", 515 | "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz", 516 | "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=", 517 | "requires": { 518 | "passport-strategy": "1.x.x", 519 | "pause": "0.0.1" 520 | } 521 | }, 522 | "passport-jwt": { 523 | "version": "4.0.0", 524 | "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.0.tgz", 525 | "integrity": "sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg==", 526 | "requires": { 527 | "jsonwebtoken": "^8.2.0", 528 | "passport-strategy": "^1.0.0" 529 | } 530 | }, 531 | "passport-strategy": { 532 | "version": "1.0.0", 533 | "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", 534 | "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" 535 | }, 536 | "path-to-regexp": { 537 | "version": "0.1.7", 538 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 539 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 540 | }, 541 | "pause": { 542 | "version": "0.0.1", 543 | "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", 544 | "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" 545 | }, 546 | "proxy-addr": { 547 | "version": "2.0.3", 548 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", 549 | "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", 550 | "requires": { 551 | "forwarded": "~0.1.2", 552 | "ipaddr.js": "1.6.0" 553 | } 554 | }, 555 | "qs": { 556 | "version": "6.5.2", 557 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 558 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 559 | }, 560 | "range-parser": { 561 | "version": "1.2.0", 562 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 563 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 564 | }, 565 | "raw-body": { 566 | "version": "2.3.3", 567 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", 568 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", 569 | "requires": { 570 | "bytes": "3.0.0", 571 | "http-errors": "1.6.3", 572 | "iconv-lite": "0.4.23", 573 | "unpipe": "1.0.0" 574 | } 575 | }, 576 | "regexp-clone": { 577 | "version": "0.0.1", 578 | "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz", 579 | "integrity": "sha1-p8LgmJH9vzj7sQ03b7cwA+aKxYk=" 580 | }, 581 | "require_optional": { 582 | "version": "1.0.1", 583 | "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", 584 | "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", 585 | "requires": { 586 | "resolve-from": "^2.0.0", 587 | "semver": "^5.1.0" 588 | } 589 | }, 590 | "resolve-from": { 591 | "version": "2.0.0", 592 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", 593 | "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" 594 | }, 595 | "safe-buffer": { 596 | "version": "5.1.1", 597 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 598 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 599 | }, 600 | "safer-buffer": { 601 | "version": "2.1.2", 602 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 603 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 604 | }, 605 | "semver": { 606 | "version": "5.5.0", 607 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", 608 | "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" 609 | }, 610 | "send": { 611 | "version": "0.16.2", 612 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 613 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 614 | "requires": { 615 | "debug": "2.6.9", 616 | "depd": "~1.1.2", 617 | "destroy": "~1.0.4", 618 | "encodeurl": "~1.0.2", 619 | "escape-html": "~1.0.3", 620 | "etag": "~1.8.1", 621 | "fresh": "0.5.2", 622 | "http-errors": "~1.6.2", 623 | "mime": "1.4.1", 624 | "ms": "2.0.0", 625 | "on-finished": "~2.3.0", 626 | "range-parser": "~1.2.0", 627 | "statuses": "~1.4.0" 628 | }, 629 | "dependencies": { 630 | "statuses": { 631 | "version": "1.4.0", 632 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 633 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 634 | } 635 | } 636 | }, 637 | "serve-static": { 638 | "version": "1.13.2", 639 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 640 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 641 | "requires": { 642 | "encodeurl": "~1.0.2", 643 | "escape-html": "~1.0.3", 644 | "parseurl": "~1.3.2", 645 | "send": "0.16.2" 646 | } 647 | }, 648 | "setprototypeof": { 649 | "version": "1.1.0", 650 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 651 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 652 | }, 653 | "sliced": { 654 | "version": "1.0.1", 655 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", 656 | "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" 657 | }, 658 | "statuses": { 659 | "version": "1.5.0", 660 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 661 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 662 | }, 663 | "type-is": { 664 | "version": "1.6.16", 665 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", 666 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", 667 | "requires": { 668 | "media-typer": "0.3.0", 669 | "mime-types": "~2.1.18" 670 | } 671 | }, 672 | "unpipe": { 673 | "version": "1.0.0", 674 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 675 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 676 | }, 677 | "utils-merge": { 678 | "version": "1.0.1", 679 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 680 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 681 | }, 682 | "validator": { 683 | "version": "10.4.0", 684 | "resolved": "https://registry.npmjs.org/validator/-/validator-10.4.0.tgz", 685 | "integrity": "sha512-Q/wBy3LB1uOyssgNlXSRmaf22NxjvDNZM2MtIQ4jaEOAB61xsh1TQxsq1CgzUMBV1lDrVMogIh8GjG1DYW0zLg==" 686 | }, 687 | "vary": { 688 | "version": "1.1.2", 689 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 690 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 691 | } 692 | } 693 | } 694 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bigstack", 3 | "version": "1.0.0", 4 | "description": "a small version of stackoverflow", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "keywords": [ 10 | "stackoverflow" 11 | ], 12 | "author": "Adhikansh Mittal", 13 | "license": "ISC", 14 | "dependencies": { 15 | "bcryptjs": "^2.4.3", 16 | "body-parser": "^1.18.3", 17 | "express": "^4.16.3", 18 | "jsonwebtoken": "^8.3.0", 19 | "mongoose": "^5.1.6", 20 | "passport": "^0.4.0", 21 | "passport-jwt": "^4.0.0", 22 | "validator": "^10.4.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /routes/api/auth.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const bcrypt = require("bcryptjs"); 4 | const jsonwt = require("jsonwebtoken"); 5 | const passport = require("passport"); 6 | const key = require("../../setup/myurl"); 7 | 8 | // @type GET 9 | //@route /api/auth 10 | // @desc just for testing 11 | // @access PUBLIC 12 | router.get("/", (req, res) => res.json({ test: "Auth is being tested" })); 13 | 14 | //Import Schema for Person to Register 15 | const Person = require("../../models/Person"); 16 | 17 | // @type POST 18 | //@route /api/auth/register 19 | // @desc route for registration of users 20 | // @access PUBLIC 21 | 22 | router.post("/register", (req, res) => { 23 | Person.findOne({ email: req.body.email }) 24 | .then(person => { 25 | if (person) { 26 | return res 27 | .status(400) 28 | .json({ emailerror: "Email is already registered in our system" }); 29 | } else { 30 | const newPerson = new Person({ 31 | name: req.body.name, 32 | email: req.body.email, 33 | password: req.body.password 34 | }); 35 | //Encrypt password using bcrypt 36 | bcrypt.genSalt(10, (err, salt) => { 37 | bcrypt.hash(newPerson.password, salt, (err, hash) => { 38 | if (err) throw err; 39 | newPerson.password = hash; 40 | newPerson 41 | .save() 42 | .then(person => res.json(person)) 43 | .catch(err => console.log(err)); 44 | }); 45 | }); 46 | } 47 | }) 48 | .catch(err => console.log(err)); 49 | }); 50 | 51 | // @type POST 52 | //@route /api/auth/login 53 | // @desc route for login of users 54 | // @access PUBLIC 55 | 56 | router.post("/login", (req, res) => { 57 | const email = req.body.email; 58 | const password = req.body.password; 59 | 60 | Person.findOne({ email }) 61 | .then(person => { 62 | if (!person) { 63 | return res 64 | .status(404) 65 | .json({ emailerror: "User not found with this email" }); 66 | } 67 | bcrypt 68 | .compare(password, person.password) 69 | .then(isCorrect => { 70 | if (isCorrect) { 71 | // res.json({ success: "User is able to login successfully" }); 72 | //use payload and create token for user 73 | const payload = { 74 | id: person.id, 75 | name: person.name, 76 | email: person.email 77 | }; 78 | jsonwt.sign( 79 | payload, 80 | key.secret, 81 | { expiresIn: 3600 }, 82 | (err, token) => { 83 | res.json({ 84 | success: true, 85 | token: "Bearer " + token 86 | }); 87 | } 88 | ); 89 | } else { 90 | res.status(400).json({ passworderror: "Password is not correct" }); 91 | } 92 | }) 93 | .catch(err => console.log(err)); 94 | }) 95 | .catch(err => console.log(err)); 96 | }); 97 | 98 | // @type GET 99 | //@route /api/auth/profile 100 | // @desc route for user profile 101 | // @access PRIVATE 102 | 103 | router.get( 104 | "/profile", 105 | passport.authenticate("jwt", { session: false }), 106 | (req, res) => { 107 | // console.log(req); 108 | res.json({ 109 | id: req.user.id, 110 | name: req.user.name, 111 | email: req.user.email, 112 | profilepic: req.user.profilepic 113 | }); 114 | } 115 | ); 116 | 117 | module.exports = router; 118 | -------------------------------------------------------------------------------- /routes/api/profile.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const mongoose = require("mongoose"); 4 | const passport = require("passport"); 5 | 6 | //Load Person Model 7 | const Person = require("../../models/Person"); 8 | 9 | //Load Profile Model 10 | const Profile = require("../../models/Profile"); 11 | 12 | // @type GET 13 | //@route /api/profile/ 14 | // @desc route for personnal user profile 15 | // @access PRIVATE 16 | router.get( 17 | "/", 18 | passport.authenticate("jwt", { session: false }), 19 | (req, res) => { 20 | Profile.findOne({ user: req.user.id }) 21 | .then(profile => { 22 | if (!profile) { 23 | return res.status(404).json({ profilenotfound: "No profile Found" }); 24 | } 25 | res.json(profile); 26 | }) 27 | .catch(err => console.log("got some error in profile " + err)); 28 | } 29 | ); 30 | 31 | // @type POST 32 | //@route /api/profile/ 33 | // @desc route for UPDATING/SAVING personnal user profile 34 | // @access PRIVATE 35 | router.post( 36 | "/", 37 | passport.authenticate("jwt", { session: false }), 38 | (req, res) => { 39 | const profileValues = {}; 40 | profileValues.user = req.user.id; 41 | if (req.body.username) profileValues.username = req.body.username; 42 | if (req.body.website) profileValues.website = req.body.website; 43 | if (req.body.country) profileValues.country = req.body.country; 44 | if (req.body.portfolio) profileValues.portfolio = req.body.portfolio; 45 | if (typeof req.body.languages !== undefined) { 46 | profileValues.languages = req.body.languages.split(","); 47 | } 48 | //get social links 49 | profileValues.social = {}; 50 | 51 | if (req.body.youtube) profileValues.social.youtube = req.body.youtube; 52 | if (req.body.facebook) profileValues.social.facebook = req.body.facebook; 53 | if (req.body.instagram) profileValues.social.instagram = req.body.instagram; 54 | 55 | //Do database stuff 56 | Profile.findOne({ user: req.user.id }) 57 | .then(profile => { 58 | if (profile) { 59 | Profile.findOneAndUpdate( 60 | { user: req.user.id }, 61 | { $set: profileValues }, 62 | { new: true } 63 | ) 64 | .then(profile => res.json(profile)) 65 | .catch(err => console.log("problem in update" + err)); 66 | } else { 67 | Profile.findOne({ username: profileValues.username }) 68 | .then(profile => { 69 | //Username already exists 70 | if (profile) { 71 | res.status(400).json({ username: "Username already exists" }); 72 | } 73 | //save user 74 | new Profile(profileValues) 75 | .save() 76 | .then(profile => res.json(profile)) 77 | .catch(err => console.log(err)); 78 | }) 79 | .catch(err => console.log(err)); 80 | } 81 | }) 82 | .catch(err => console.log("Problem in fetching profile" + err)); 83 | } 84 | ); 85 | 86 | // @type GET 87 | //@route /api/profile/:username 88 | // @desc route for getting user profile based on USERNAME 89 | // @access PUBLIC 90 | router.get("/:username", (req, res) => { 91 | Profile.findOne({ username: req.params.username }) 92 | .populate("user", ["name", "profilepic"]) 93 | .then(profile => { 94 | if (!profile) { 95 | res.status(404).json({ usernotfound: "User not found" }); 96 | } 97 | res.json(profile); 98 | }) 99 | .catch(err => console.log("Error in fetching username " + err)); 100 | }); 101 | 102 | // @type GET 103 | //@route /api/profile/find/everyone 104 | // @desc route for getting user profile of EVERYONE 105 | // @access PUBLIC 106 | router.get("/find/everyone", (req, res) => { 107 | Profile.find() 108 | .populate("user", ["name", "profilepic"]) 109 | .then(profiles => { 110 | if (!profiles) { 111 | res.status(404).json({ usernotfound: "NO profile was found" }); 112 | } 113 | res.json(profiles); 114 | }) 115 | .catch(err => console.log("Error in fetching username " + err)); 116 | }); 117 | 118 | // @type DELETE 119 | //@route /api/profile/ 120 | // @desc route for deleting user based on ID 121 | // @access PRIVATE 122 | 123 | router.delete( 124 | "/", 125 | passport.authenticate("jwt", { session: false }), 126 | (req, res) => { 127 | Profile.findOne({ user: req.user.id }); 128 | Profile.findOneAndRemove({ user: req.user.id }) 129 | .then(() => { 130 | Person.findOneAndRemove({ _id: req.user.id }) 131 | .then(() => res.json({ success: "delete was a success" })) 132 | .catch(err => console.log(err)); 133 | }) 134 | .catch(err => console.log(err)); 135 | } 136 | ); 137 | 138 | // @type POST 139 | //@route /api/profile/workrole 140 | // @desc route for adding work profile of a person 141 | // @access PRIVATE 142 | 143 | router.post( 144 | "/workrole", 145 | passport.authenticate("jwt", { session: false }), 146 | (req, res) => { 147 | Profile.findOne({ user: req.user.id }) 148 | .then(profile => { 149 | //assignment 150 | const newWork = { 151 | role: req.body.role, 152 | company: req.body.company, 153 | country: req.body.country, 154 | from: req.body.from, 155 | to: req.body.to, 156 | current: req.body.current, 157 | details: req.body.details 158 | }; 159 | profile.workrole.unshift(newWork); 160 | profile 161 | .save() 162 | .then(profile => res.json(profile)) 163 | .catch(err => console.log(err)); 164 | }) 165 | .catch(err => console.log(err)); 166 | } 167 | ); 168 | 169 | // @type DELETE 170 | //@route /api/profile/workrole/:w_id 171 | // @desc route for deleting a specific workrole 172 | // @access PRIVATE 173 | router.delete( 174 | "/workrole/:w_id", 175 | passport.authenticate("jwt", { session: false }), 176 | (req, res) => { 177 | Profile.findOne({ user: req.user.id }) 178 | .then(profile => { 179 | //assignemnt to check if we got a profile 180 | const removethis = profile.workrole 181 | .map(item => item.id) 182 | .indexOf(req.params.w_id); 183 | 184 | profile.workrole.splice(removethis, 1); 185 | 186 | profile 187 | .save() 188 | .then(profile => res.json(profile)) 189 | .catch(err => console.log(err)); 190 | }) 191 | .catch(err => console.log(err)); 192 | } 193 | ); 194 | 195 | //Assignemnt - create a route to delete all elements from array and save that in database 196 | 197 | module.exports = router; 198 | -------------------------------------------------------------------------------- /routes/api/questions.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const mongoose = require("mongoose"); 4 | const passport = require("passport"); 5 | 6 | //Load Person Model 7 | const Person = require("../../models/Person"); 8 | 9 | //Load Profile Model 10 | const Profile = require("../../models/Profile"); 11 | 12 | //Load Question Model 13 | const Question = require("../../models/Question"); 14 | 15 | // @type GET 16 | //@route /api/questions/ 17 | // @desc route for showing all questions 18 | // @access PUBLIC 19 | router.get("/", (req, res) => { 20 | Question.find() 21 | .sort({ date: "desc" }) 22 | .then(questions => res.json(questions)) 23 | .catch(err => res.json({ noquestions: "NO questions to display" })); 24 | }); 25 | 26 | // @type POST 27 | //@route /api/questions/ 28 | // @desc route for submitting questions 29 | // @access PRIVATE 30 | 31 | router.post( 32 | "/", 33 | passport.authenticate("jwt", { session: false }), 34 | (req, res) => { 35 | const newQuestion = new Question({ 36 | textone: req.body.textone, 37 | texttwo: req.body.texttwo, 38 | user: req.user.id, 39 | name: req.body.name 40 | }); 41 | newQuestion 42 | .save() 43 | .then(question => res.json(question)) 44 | .catch(err => console.log("UNable to push question to database " + err)); 45 | } 46 | ); 47 | 48 | // @type POST 49 | //@route /api/questions/answers/:id 50 | // @desc route for submitting answers to questions 51 | // @access PRIVATE 52 | 53 | router.post( 54 | "/answers/:id", 55 | passport.authenticate("jwt", { session: false }), 56 | (req, res) => { 57 | Question.findById(req.params.id) 58 | .then(question => { 59 | const newAnswer = { 60 | user: req.user.id, 61 | name: req.body.name, 62 | text: req.body.text 63 | }; 64 | question.answers.unshift(newAnswer); 65 | 66 | question 67 | .save() 68 | .then(question => res.json(question)) 69 | .catch(err => console.log(err)); 70 | }) 71 | .catch(err => console.log(err)); 72 | } 73 | ); 74 | 75 | // @type POST 76 | //@route /api/questions/upvote/:id 77 | // @desc route for for upvoting 78 | // @access PRIVATE 79 | router.post( 80 | "/upvote/:id", 81 | passport.authenticate("jwt", { session: false }), 82 | (req, res) => { 83 | Profile.findOne({ user: req.user.id }) 84 | .then(profile => { 85 | Question.findById(req.params.id) 86 | .then(question => { 87 | if ( 88 | question.upvotes.filter( 89 | upvote => upvote.user.toString() === req.user.id.toString() 90 | ).length > 0 91 | ) { 92 | return res.status(400).json({ noupvote: "User already upvoted" }); 93 | } 94 | question.upvotes.unshift({ user: req.user.id }); 95 | question 96 | .save() 97 | .then(question => res.json(question)) 98 | .catch(err => console.log(err)); 99 | }) 100 | .catch(err => console.log(err)); 101 | }) 102 | .catch(err => console.log(err)); 103 | } 104 | ); 105 | 106 | 107 | module.exports = router; 108 | -------------------------------------------------------------------------------- /setup/myurl.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mongoURL: "mongodb://hitesh:hitesh@ds161610.mlab.com:61610/lcocourse", 3 | secret: "mystrongsecret" 4 | }; 5 | -------------------------------------------------------------------------------- /strategies/jsonwtStrategy.js: -------------------------------------------------------------------------------- 1 | const JwtStrategy = require("passport-jwt").Strategy; 2 | const ExtractJwt = require("passport-jwt").ExtractJwt; 3 | const mongoose = require("mongoose"); 4 | const Person = mongoose.model("myPerson"); 5 | const myKey = require("../setup/myurl"); 6 | 7 | var opts = {}; 8 | opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); 9 | opts.secretOrKey = myKey.secret; 10 | 11 | module.exports = passport => { 12 | passport.use( 13 | new JwtStrategy(opts, (jwt_payload, done) => { 14 | Person.findById(jwt_payload.id) 15 | .then(person => { 16 | if (person) { 17 | return done(null, person); 18 | } 19 | return done(null, false); 20 | }) 21 | .catch(err => console.log(err)); 22 | }) 23 | ); 24 | }; 25 | --------------------------------------------------------------------------------