Skip to content

Commit 5edfa85

Browse files
Updates in CRUD
1 parent ace4751 commit 5edfa85

File tree

12 files changed

+2881
-309
lines changed

12 files changed

+2881
-309
lines changed
+41-41
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,32 @@
11
import jwt from "jsonwebtoken";
22
import md5 from "md5";
33
import env from "dotenv";
4-
import { conn, client } from "../db";
5-
let db;
6-
conn().then(async () => {
7-
db = await client().db("ideaboard");
8-
});
9-
4+
import { db } from "../db";
5+
import { ObjectID } from "bson";
6+
import {
7+
getAllUsers,
8+
delUser,
9+
findUserById,
10+
IsUnique,
11+
updateUserDetails,
12+
} from "../database/userQueries";
13+
import { badRequest } from "../errors/badRequest";
14+
import { genError } from "../errors/generalError";
1015
env.config();
1116

12-
export const users = [];
13-
export const message = function (success, text) {
14-
return { success: success, message: text };
15-
};
16-
17-
export const allUsers = async (ctx) => {
18-
const res = await users.map((user) => {
19-
const { username, email, boards, joined_at } = user;
20-
return { username, email, boards, joined_at };
21-
});
22-
ctx.body = res;
23-
};
17+
export const message = (success, text) => ({ success, message: text });
2418

2519
export const newUser = async (ctx) => {
2620
const user = ctx.request.body;
2721
user.joined_at = new Date(new Date().getTime() + 19800000);
2822
user.boards = [];
29-
const hash = await md5(user.password);
30-
user.password = hash;
31-
await db.insertOne(user);
32-
ctx.body = message(
33-
true,
34-
`Successfully registered a new user with username ${user.username}!`
35-
);
23+
const hash = md5(user.password);
24+
hash && (user.password = hash);
25+
(await db.collection("users").insertOne(user)) &&
26+
(ctx.body = {
27+
success: true,
28+
message: "Successfully inserted user.",
29+
});
3630
};
3731

3832
export const loginUser = async (ctx) => {
@@ -41,36 +35,42 @@ export const loginUser = async (ctx) => {
4135
expiresIn: "20m",
4236
});
4337
ctx.body = message(true, "Successfully logged you in!");
44-
ctx.body.token = token;
38+
token && (ctx.body.token = token);
39+
};
40+
41+
export const allUsers = async (ctx) => {
42+
const data = await getAllUsers();
43+
data
44+
? (ctx.body = data)
45+
: genError(ctx, "Can't fetch users. Try again later.");
4546
};
4647

4748
export const updateUser = async (ctx) => {
48-
const id = ctx.params.id;
49+
const id = ctx.request.params.id;
4950
const updUser = ctx.request.body;
50-
const foundUser = users.find((user) => user.username === id);
51+
const foundUser = await findUserById(id);
5152
if (!foundUser) {
5253
ctx.status = 400;
5354
ctx.body = message(false, "No user found with given ID!");
5455
return;
5556
}
56-
if (foundUser.email === updUser.email) {
57-
}
58-
foundUser.username = updUser.username;
59-
foundUser.email = updUser.email;
60-
foundUser.password = updUser.password;
61-
ctx.body = message(true, "Successfully updated user details");
57+
(await IsUnique(
58+
new ObjectID(updUser._id),
59+
updUser.username,
60+
updUser.email,
61+
ctx
62+
)) &&
63+
updateUserDetails(new ObjectID(updUser._id), updUser) &&
64+
(ctx.body = message(true, "Successfully updated user details"));
6265
};
6366

6467
export const deleteUser = async (ctx) => {
6568
const id = ctx.request.params.id;
66-
const foundUser = users.find((user) => {
67-
return user.username === id;
68-
});
69+
const foundUser = await findUserById(id);
6970
if (!foundUser) {
70-
ctx.status = 400;
71-
ctx.body = message(false, "No user found with given ID!");
71+
badRequest(ctx, "No user found with given ID!");
7272
return;
7373
}
74-
users.splice(users.indexOf(foundUser), 1);
75-
ctx.body = message(true, `Successfully deleted the user with id ${id}!`);
74+
(await delUser(id)) &&
75+
(ctx.body = message(true, `Successfully deleted the user with id ${id}!`));
7676
};

Ideaboard/database/userQueries.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { db } from "../db";
2+
3+
export const isUser = async (email, username) =>
4+
await db.collection("users").findOne({ $and: [{ email }, { username }] });
5+
6+
export const userExists = async (email, username) =>
7+
await db.collection("users").findOne({ $or: [{ email }, { username }] });
8+
9+
export const findUserById = async (id) =>
10+
await db.collection("users").findOne({ username: id });
11+
12+
export const getAllUsers = async () =>
13+
await db
14+
.collection("users")
15+
.find({}, { projection: { password: 0 } })
16+
.toArray();
17+
18+
export const IsUnique = async (userId, updatedUsername, updatedEmail, ctx) => {
19+
const user = await db.collection("users").findOne({
20+
$and: [
21+
{ $or: [{ username: updatedUsername }, { email: updatedEmail }] },
22+
{ _id: { $ne: userId } },
23+
],
24+
});
25+
if (user) {
26+
ctx.status = 400;
27+
ctx.body = {
28+
success: false,
29+
message: "User with these credentials already exists.",
30+
};
31+
return;
32+
}
33+
return true;
34+
};
35+
36+
export const updateUserDetails = async (userId, updatedUser) => {
37+
delete updatedUser._id &&
38+
(await db
39+
.collection("users")
40+
.updateOne({ _id: userId }, { $set: updatedUser }));
41+
return;
42+
};
43+
44+
export const delUser = async (id) =>
45+
await db.collection("users").deleteOne({ username: id });

Ideaboard/db.js

+20-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
1-
import * as mongodb from "mongodb";
1+
import { MongoClient } from "mongodb";
22

3-
const MongoClient = mongodb.MongoClient;
43
const uri = "mongodb://localhost:27017/";
5-
export const client = new MongoClient(uri);
6-
export const conn = async function () {
7-
try {
4+
5+
let client, db;
6+
7+
async function connectToDb() {
8+
if (!client) {
9+
client = new MongoClient(uri, { useNewUrlParser: true });
810
await client.connect();
9-
} catch (err) {
10-
console.log(err);
11+
db = client.db("ideaboard");
1112
}
12-
};
13+
return client;
14+
}
15+
16+
connectToDb()
17+
.then(() => {
18+
console.log("Database Connected...");
19+
})
20+
.catch((err) => {
21+
console.log(err);
22+
});
23+
24+
export { db };

Ideaboard/errors/badRequest.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const badRequest = (ctx, message) => {
2+
ctx.status = 400;
3+
ctx.body = { success: false, message };
4+
};

Ideaboard/errors/generalError.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const genError = async () => (ctx, message) => {
2+
ctx.status = 408;
3+
ctx.body = { success: false, message };
4+
};

Ideaboard/errors/unauthorized.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const unauthorized = (ctx, message) => {
2+
ctx.status = 401;
3+
ctx.body = { success: false, message };
4+
};

Ideaboard/index.js

+7-14
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
import Koa from "koa";
22
import bodyParser from "koa-bodyparser";
33
import { router } from "./routes/userRoutes";
4-
const { conn, client } = require("./db");
54
const app = new Koa();
65

7-
app.use(bodyParser()).use(router.routes()).use(router.allowedMethods());
6+
app.use(bodyParser());
87

9-
conn();
8+
app.use(router.routes()).use(router.allowedMethods());
109

11-
client
12-
.db("ideaboard")
13-
.then(() => {
14-
console.log("Database Connected!");
15-
app.listen(3000, () => {
16-
console.log("Server running on http://localhost:3000");
17-
});
18-
})
19-
.catch((err) => {
20-
console.log(err);
21-
});
10+
app.listen(3000, () => {
11+
console.log("Server running on http://localhost:3000");
12+
});
13+
14+
export default app;

Ideaboard/middlewares.js

+47-64
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,70 @@
11
import md5 from "md5";
2-
import { users, message } from "./controllers/userControllers";
32
import jwt from "jsonwebtoken";
3+
import { isUser, userExists } from "./database/userQueries";
4+
import { unauthorized } from "./errors/unauthorized";
5+
import { badRequest } from "./errors/badRequest";
46

5-
export const verifyLogin = async function (ctx, next) {
7+
export const verifyUser = (ctx, next) => {
8+
if (!ctx.request.headers.authorization) {
9+
unauthorized(ctx, "Unauthorized request");
10+
return;
11+
}
12+
const token = ctx.request.headers.authorization.split(" ")[1];
13+
if (!token) {
14+
unauthorized(ctx, "Access denied. No token provided.");
15+
return;
16+
}
17+
try {
18+
const decoded = jwt.verify(token, process.env.JWT_SECRET);
19+
ctx.request.user = decoded.user;
20+
return next();
21+
} catch (err) {
22+
unauthorized(ctx, "Invalid token");
23+
return;
24+
}
25+
};
26+
27+
export const verifyLogin = async (ctx, next) => {
628
const user = ctx.request.body;
729
if (!user.username || !user.email || !user.password) {
8-
ctx.status = 400;
9-
ctx.body = message(
10-
false,
11-
"Provide username, email, and password to login!"
12-
);
30+
badRequest(ctx, "Provide username, email, and password to login!");
1331
return;
1432
}
1533
const { username, email, password } = user;
16-
const foundUser = users.find((user) => {
17-
return user.email === email && user.username === username;
18-
});
34+
const foundUser = await isUser(email, username);
1935
if (!foundUser) {
20-
ctx.status = 400;
21-
ctx.body = message(false, "Invalid username, email or password!");
36+
badRequest(ctx, "Invalid username, email or password!");
2237
return;
2338
}
24-
const isPasswordValid = (await md5(password)) === foundUser.password;
39+
const isPasswordValid = md5(password) === foundUser.password;
2540
if (!isPasswordValid) {
26-
ctx.status = 400;
27-
ctx.body = message(false, "Invalid username, email or password!");
41+
badRequest(ctx, "Invalid username, email or password!");
2842
return;
2943
}
30-
await next();
44+
return next();
3145
};
3246

33-
export const verifyUserDuplicates = function (ctx, next) {
47+
export const verifyUserDuplicates = async (ctx, next) => {
3448
const { email, password, username } = ctx.request.body;
3549
if (!email || !password) {
36-
ctx.status = 400;
37-
ctx.body = { success: false, message: "Email and password are required." };
50+
badRequest(ctx, "Email and password are required.");
3851
return;
3952
}
4053
if (!username) {
41-
ctx.status = 400;
42-
ctx.body = { success: false, message: "Username is required." };
54+
badRequest(ctx, "Username is required.");
4355
return;
4456
}
4557
if (
46-
users.find((ele) => {
47-
return ele.email === email || ele.username === username;
48-
})
58+
(await userExists(email, username)) ||
59+
badRequest(ctx, "Seomething went wrong. Try again after some time.")
4960
) {
50-
ctx.status = 400;
51-
ctx.body = message(
52-
false,
61+
badRequest(
62+
ctx,
5363
"User with these credentials already exists. Provide a different username or email!"
5464
);
5565
return;
5666
}
57-
next();
67+
return next();
5868
};
5969

6070
export const verifyUserRegex = (ctx, next) => {
@@ -63,45 +73,18 @@ export const verifyUserRegex = (ctx, next) => {
6373
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
6474
const usernameRegex = /^[a-zA-Z0-9._]{4,15}$/;
6575
if (!usernameRegex.test(username)) {
66-
ctx.status = 400;
67-
ctx.body = {
68-
success: false,
69-
message:
70-
"Username must be 4 to 15 characters long and should not contain any special characters!",
71-
};
76+
badRequest(
77+
ctx,
78+
"Username must be 4 to 15 characters long and should not contain any special characters!"
79+
);
7280
return;
7381
}
7482
if (!emailRegex.test(email) || password.length < 8 || password.length > 15) {
75-
ctx.status = 400;
76-
ctx.body = {
77-
success: false,
78-
message:
79-
"Email or password is in incorrect format. Check email format and password must be at least 8 characters long.",
80-
};
81-
return;
82-
}
83-
next();
84-
};
85-
86-
export const verifyUser = function (ctx, next) {
87-
if (!ctx.request.headers.authorization) {
88-
ctx.status = 401;
89-
ctx.body = "Unauthorized request!";
90-
return;
91-
}
92-
const token = ctx.request.headers.authorization.split(" ")[1];
93-
if (!token) {
94-
ctx.status = 401;
95-
ctx.body = "Access denied. No token provided.";
96-
return;
97-
}
98-
try {
99-
const decoded = jwt.verify(token, process.env.JWT_SECRET);
100-
ctx.request.user = decoded.user;
101-
next();
102-
} catch (err) {
103-
ctx.status = 400;
104-
ctx.body = "Invalid token";
83+
badRequest(
84+
ctx,
85+
"Email or password is in incorrect format. Check email format and password must be at least 8 characters long."
86+
);
10587
return;
10688
}
89+
return next();
10790
};

0 commit comments

Comments
 (0)