Issues (50)

v1/models/users.js (17 issues)

1
const bcrypt = require('bcryptjs');
2
const sanitize = require('mongo-sanitize'); // To prevent malicious users overwriting (NoSQL Injection)
3
const { MongoClient, ObjectId } = require("mongodb");
4
const mongoURI = process.env.DBURI;
5
6
const users = {
7
    getAllUsers: async function(res, path) {
8
        let users = null;
9
10
        let client = new MongoClient(mongoURI);
11
        try {
12
            let db = client.db("spark-rentals");
13
            let users_collection = db.collection("users");
14
            users = await users_collection.find().toArray();
15
        } catch(e) { res.status(500).send(); } finally { await client.close(); }
16
17
        // If nothing in users db collection
18
        if (users === null || !users.length) {
19
            return res.status(401).json({
20
                errors: {
21
                    status: 401,
22
                    source: "GET /users" + path,
23
                    title: "Users collection is empty",
24
                    detail: "Users collection is empty in database."
25
                }
26
            });
27
        }
28
        
29
        res.status(200).send({ users }); // Sends the whole collection data
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
30
    },
31
32
    deleteUser: async function(res, user_id, path) {
33
        let userId = sanitize(user_id)
34
        let answer = null;
35
36
        // Check if the userId are valid MongoDB id.
37
        if (!ObjectId.isValid(userId)) {
38
            return res.status(400).json({
39
                errors: {
40
                    status: 400,
41
                    detail: "The user_id is not a valid id."
42
                }
43
            });
44
        }
45
46
        let client = new MongoClient(mongoURI);
47
        try {
48
            let db = client.db("spark-rentals");
49
            let users_collection = db.collection("users");
50
            answer = await users_collection.deleteOne({_id: ObjectId(userId)});
51
        } catch(e) { return res.status(500).send(); } finally { await client.close(); }
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
52
        
53
        if (answer.deletedCount <= 0) {
54
            return res.status(401).json({
55
                errors: {
56
                    status: 401,
57
                    source: "DELETE /users" + path,
58
                    title: "User not exists in database",
59
                    detail: "The user dosen't exists in database with the specified user_id."
60
                }
61
            });
62
        }
63
        
64
        return res.status(204).send();
65
    },
66
67
    editUser: async function(res, body, path) {
68
        let userId = sanitize(body.user_id);
69
        let updateFields = {};
70
        let userDataField = {
71
            googleId: "String",
72
            firstName: "String",
73
            lastName: "String",
74
            phoneNumber: "String",
75
            email: "String",
76
            password: "String",
77
            balance: "Float",
78
        }
79
80
        // Check if the userId are valid MongoDB id.
81
        if (!ObjectId.isValid(userId)) {
82
            return res.status(400).json({
83
                errors: {
84
                    status: 400,
85
                    detail: "The user_id is not a valid id."
86
                }
87
            });
88
        };    
89
90
        // Lookup if the user exists in database
91
        let client = new MongoClient(mongoURI);
92
        try {
93
            let db = client.db("spark-rentals");
94
            let users_collection = db.collection("users");
95
            let user = await users_collection.findOne({_id: ObjectId(userId)});
96
97
            // If the user dosen't exists
98
            if (user === null) {
99
                return res.status(401).json({
100
                    errors: {
101
                        status: 401,
102
                        source: "PUT /users" + path,
103
                        title: "User not exists in database",
104
                        detail: "The user dosen't exists in database with the specified user_id."
105
                    }
106
                });
107
            }
108
109
            // Put in the data the client has requested to update
110
            for (const field in userDataField) {
111
                if (body[field] !== undefined) {
112
                    if (field === "password") { // If it's a password it needs to be encrypted
113
                        bcrypt.hash(sanitize(body[field]), 10, async function(err, hash) {
114
                            if (err) {
115
                                return res.status(500).json({ // if error with bcrypt
116
                                    errors: {
117
                                        status: 500,
118
                                        source: "PUT /users",
119
                                        title: "bcrypt error",
120
                                        detail: "bcrypt error"
121
                                    }
122
                                });
123
                            }
124
                            updateFields[field] = hash;
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
125
                        })
126
                    } else if (field == "balance") {
127
                        updateFields[field] = parseFloat(sanitize(body[field]));
128
                    } else {
129
                        updateFields[field] = sanitize(body[field]);
130
                    }
131
                    
132
                }
133
            }
134
135
            await users_collection.updateOne({_id: ObjectId(userId)}, {$set: updateFields}); // Update the fields in the specific user
136
137
        } catch(e) { return res.status(500).send(); } finally { await client.close(); }
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
138
139
        return res.status(204).send(); // Everything went good
140
    },
141
142 View Code Duplication
    getSpecificUser: async function(res, user_id, path) {
143
        let userId = sanitize(user_id);
144
        let user = null;
145
146
        // Check if the scooterId are valid MongoDB id.
147
        if (!ObjectId.isValid(userId)) {
148
            return res.status(400).json({
149
                errors: {
150
                    status: 400,
151
                    detail: "The user_id is not a valid id."
152
                }
153
            });
154
        }
155
156
        let client = new MongoClient(mongoURI);
157
        try {
158
            let db = client.db("spark-rentals");
159
            let users_collection = db.collection("users");
160
            user = await users_collection.findOne({_id: ObjectId(userId)});
161
        } catch(e) { return res.status(500).send(); } finally { await client.close(); }
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
162
163
        // If nothing in users db collection
164
        if (user === null || !Object.keys(user).length) {
165
            return res.status(401).json({
166
                errors: {
167
                    status: 401,
168
                    source: "GET /users" + path,
169
                    title: "User not exists in database",
170
                    detail: "The User dosen't exists in database with the specified user_id."
171
                }
172
            });
173
        }
174
175
        res.status(200).send({ user }); // Sends data from the specific user
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
176
    },
177
178 View Code Duplication
    getSpecificGoogleUser: async function(res, google_id, path) {
179
        let googleId = sanitize(google_id);
180
        let user = null;
181
182
        // Check if the scooterId are valid MongoDB id.
183
        if (!ObjectId.isValid(userId)) {
0 ignored issues
show
The variable userId seems to be never declared. If this is a global, consider adding a /** global: userId */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
184
            return res.status(400).json({
185
                errors: {
186
                    status: 400,
187
                    detail: "The user_id is not a valid id."
188
                }
189
            });
190
        }
191
192
        let client = new MongoClient(mongoURI);
193
        try {
194
            let db = client.db("spark-rentals");
195
            let users_collection = db.collection("users");
196
            user = await users_collection.findOne({googleId: ObjectId(googleId)});
197
        } catch(e) { return res.status(500).send(); } finally { await client.close(); }
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
198
199
        // If nothing in users db collection
200
        if (user === null || !Object.keys(user).length) {
201
            return res.status(401).json({
202
                errors: {
203
                    status: 401,
204
                    source: "GET /users" + path,
205
                    title: "User not exists in database",
206
                    detail: "The User dosen't exists in database with the specified user_id."
207
                }
208
            });
209
        }
210
211
        res.status(200).send({ user }); // Sends data from the specific user
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
212
    },
213
214
    getUserHistory: async function(res, user_id, path) {
215
        let userId = sanitize(user_id);
216
        let userHistory = null;
217
218
        // Check if the scooterId are valid MongoDB id.
219
        if (!ObjectId.isValid(userId)) {
220
            return res.status(400).json({
221
                errors: {
222
                    status: 400,
223
                    detail: "The user_id is not a valid id."
224
                }
225
            });
226
        }
227
228
        let client = new MongoClient(mongoURI);
229
        try {
230
            let db = client.db("spark-rentals");
231
            let users_collection = db.collection("users");
232
            userHistory = await users_collection.findOne({_id: ObjectId(userId)}).project({history: 1});
233
        } catch(e) { return res.status(500).send(); } finally { await client.close(); }
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
234
235
        // If nothing in users db collection
236
        if (userHistory === null) {
237
            return res.status(401).json({
238
                errors: {
239
                    status: 401,
240
                    source: "GET /users" + path,
241
                    title: "User history not exists in database",
242
                    detail: "The User history dosen't exists in database with the specified user_id."
243
                }
244
            });
245
        }
246
247
        res.status(200).send({ userHistory }); // Sends data from the specific user
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
248
    },
249
250
    getUserDetails: async function(res, user_id, history_id, path) {
251
        let userId = sanitize(user_id);
252
        let userDetails = null;
253
254
        // Check if the userId are valid MongoDB id.
255
        if (!ObjectId.isValid(userId)) {
256
            return res.status(400).json({
257
                errors: {
258
                    status: 400,
259
                    detail: "The user_id is not a valid id."
260
                }
261
            });
262
        }
263
264
        let client = new MongoClient(mongoURI);
265
        try {
266
            let db = client.db("spark-rentals");
267
            let users_collection = db.collection("users");
268
            userDetails = await users_collection.findOne({_id: ObjectId(user_id), "history._id": ObjectId(history_id)});
269
        } catch(e) { return res.status(500).send(); } finally { await client.close(); }
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
270
271
        // If nothing in users db collection
272
        if (userDetails === null) {
273
            return res.status(401).json({
274
                errors: {
275
                    status: 401,
276
                    source: "GET /users" + path,
277
                    title: "User history details not exists in database",
278
                    detail: "The User history details dosen't exists in database with the specified user_id."
279
                }
280
            });
281
        }
282
283
        res.status(200).send({ userDetails }); // Sends data from the specific user
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
284
    },
285
286
    addUserFunds: async function(res, body, path) {
287
        let user = null;
0 ignored issues
show
The assignment to user seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
288
        let prepaid = null;
289
        let userId = sanitize(body.user_id);
290
        let prepaidCode = sanitize(body.prepaid_code);
291
292
        // Check if the userId are valid MongoDB id.
293
        if (!ObjectId.isValid(userId)) {
294
            return res.status(400).json({
295
                errors: {
296
                    status: 400,
297
                    detail: "The user_id is not a valid id."
298
                }
299
            });
300
        }
301
302
        let client = new MongoClient(mongoURI);
303
        try {
304
            let db = client.db("spark-rentals");
305
            let users_collection = db.collection("users");
306
            user = await users_collection.findOne({_id: ObjectId(userId)});
307
308
            // If nothing in users db collection
309
            if (user === null) {
310
                return res.status(401).json({
311
                    errors: {
312
                        status: 401,
313
                        source: "GET /users" + path,
314
                        title: "User not exists in database",
315
                        detail: "The User dosen't exists in database with the specified user_id."
316
                    }
317
                });
318
            }
319
320
            let prepaidsClient = new MongoClient(mongoURI);
321
            try {
322
                let db = prepaidsClient.db("spark-rentals");
323
                let prepaids_collection = db.collection("prepaid");
324
                prepaid = await prepaids_collection.findOne({code: prepaidCode});
325
326
                // If nothing in prepaid db collection
327
                if (prepaid === null || !Object.keys(prepaid).length) {
328
                    return res.status(401).json({
329
                        errors: {
330
                            status: 401,
331
                            source: "POST /users" + path,
332
                            title: "Prepaid not exists in database",
333
                            detail: "The Prepaid dosen't exists in database with the specified prepaid_code."
334
                        }
335
                    });
336
                }
337
                
338
                // If prepaid has no more uses left it deletes
339
                if (prepaid.usesLeft < 1) {
340
                    answer = await prepaids_collection.deleteOne({code: prepaidCode});
0 ignored issues
show
The variable answer seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.answer.
Loading history...
341
                    return res.status(410).json({
342
                        errors: {
343
                            status: 401,
344
                            source: "POST /users" + path,
345
                            title: "No prepaid card uses left",
346
                            detail: "The prepaid has not any uses left"
347
                        }
348
                    });
349
                }
350
351
                // If prepaid has no more uses left it deletes
352
                if (prepaid.users.includes(userId)) {
353
                    return res.status(410).json({
354
                        errors: {
355
                            status: 401,
356
                            source: "POST /users" + path,
357
                            title: "The user has already registered with this code",
358
                            detail: "The user_id alredy exists in the prepaid code users"
359
                        }
360
                    });
361
                } else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
362
                   prepaid.users.push(userId) 
363
                }
364
365
                await prepaids_collection.updateOne({code: prepaidCode}, {$set: {usesLeft: prepaid.usesLeft - 1, users: prepaid.users}}); // Update the uses in the specific prepaid
366
            } catch(e) { return res.status(500).send(); } finally { await prepaidsClient.close(); }
367
            await users_collection.updateOne({_id: ObjectId(userId)}, {$set: {balance: user.balance + prepaid.amount}}); // Update the balance in the specific user
368
        } catch(e) { return res.status(500).send(); } finally { await client.close(); }
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
369
370
        return res.status(204).send(); // Everything went good
371
    }
372
}
373
374
module.exports = users;