├── .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 [](http://hits.dwyl.io/HrithikMittal/Minature-Stackoverflow-APIs) [](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 |
6 | - Create a User
7 | - Post a Question
8 | - Post a Answer to the existing question
9 | - Clap on the answer(upvote)
10 | - Auhtentication and Role based Access to the StackHolders
11 |
12 |
13 | # TECHNOLOGY STACK:
14 |
15 | - NodeJS
16 | - ExpressJs
17 | - MongoDB
18 | - EJS/scripting language(optional for UI)
19 | - Heroku
20 |
21 |
22 | # Tasks to be Done
23 | ## Day1
24 | Start with the installation
25 |
26 | - NodeJs ( https://nodejs.org/en/ )
27 | - MongoDB ( https://www.mongodb.com/what-is-mongodb )
28 | You can use the online Database ( Mongodb Atlas / m-lab)
29 | For better UI/UX of database you can download ( mongoDB Atlas / Robo3T )
30 | - For editor you can use any IDE. (my fav. - Visual Code)
31 | - If you want the version control also then install git-bash or you can you Github
32 | desktop
33 |
34 |
35 |
36 | ## Day2
37 |
38 | - Setup Your Node-Js Project
39 | - Make a SignUp and Login Routes for the user
40 |
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 |
48 | - Make a Question Schema/Model(Take help from Resources)
49 | - Make a route(private route) to post the Question.
50 | - Make a get(public route) route to get all the Questions.
51 |
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 |
56 | - Make a private route to post the Answer only for the existing Questions.
57 | - Make a public route to get all the Answers and it is better to get the complete Question Model.
58 | - It is just advice to make the array-String in Model/Schema if you want to have more than one value for same entity. For example we want to save many answers of only one question.
59 |
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 |
64 | - Make a route to increase upvote array and this is an private route.
65 | - Also Make an Seperate route for the profile section where you take all the information and this is a private too.
66 | - Again it is just advice to make the array-String in Model/Schema if you want to have more than one value for same entity. For example we want to save many upvote of only one question.
67 |
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 | S.No. |
176 | Route |
177 | Method |
178 | Access |
179 | Description |
180 |
181 |
182 | 1. |
183 | / |
184 | GET |
185 | Private |
186 | to get personal profile |
187 |
188 |
189 | 2. |
190 | / |
191 | POST |
192 | Private |
193 | for UPDATING/SAVING personnal user profile |
194 |
195 |
196 | 3. |
197 | /:username |
198 | GET |
199 | Public |
200 | for getting user profile based on USERNAME. |
201 |
202 |
203 | 4. |
204 | /find/everyone |
205 | GET |
206 | Public |
207 | for getting user profile of EVERYONE. |
208 |
209 |
210 | 5. |
211 | / |
212 | DELETE |
213 | Private |
214 | for deleting user based on ID. |
215 |
216 |
217 | 6. |
218 | /workrole |
219 | POST |
220 | Private |
221 | for adding work profile of a person. |
222 |
223 |
224 | 7. |
225 | /workrole/:w_id |
226 | DELETE |
227 | Private |
228 | for deleting a specific workrole. |
229 |
230 |
231 |
232 |
233 | ### Question
234 |
235 |
236 |
237 | S.No. |
238 | Route |
239 | Method |
240 | Access |
241 | Description |
242 |
243 |
244 | 1. |
245 | / |
246 | GET |
247 | PUBLIC |
248 | for showing all questions. |
249 |
250 |
251 | 2. |
252 | / |
253 | POST |
254 | Private |
255 | for submitting questions. |
256 |
257 |
258 | 3. |
259 | /answers/:id |
260 | POST |
261 | Private |
262 | for submitting answers to questions. |
263 |
264 |
265 | 4. |
266 | /upvote/:id |
267 | POST |
268 | Private |
269 | for upvoting. |
270 |
271 |
272 |
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 [](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 |
--------------------------------------------------------------------------------