Skip to content

Commit 59bcec2

Browse files
committed
file upload functions Done
1 parent 09b480c commit 59bcec2

File tree

9 files changed

+249
-41
lines changed

9 files changed

+249
-41
lines changed

app.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ mongoose
2424
useUnifiedTopology: true,
2525
})
2626
.then(() => console.log("Successfully Connected To Database!"))
27-
.catch((error) => console.log(err));
27+
.catch((error) => console.log(error));
2828

2929
// Request Parser
3030
app.use(express.json());

controller/userController.js

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,48 @@
1+
// External Imports:
2+
const bcrypt = require("bcrypt");
3+
4+
// Internal Modules:
5+
const User = require("../models/People");
6+
17
// Get User Page page
28
const getUsers = (req, res, next) => {
39
res.render("users");
410
};
511

12+
// Add User
13+
const addUser = async (req, res, next) => {
14+
let newUser;
15+
const hashedPassword = await bcrypt.hash(req.body.password, 10);
16+
17+
if (req.files && req.files.length > 0) {
18+
newUser = new User({
19+
...req.body,
20+
avatar: req.files[0].filename,
21+
password: hashedPassword,
22+
});
23+
} else {
24+
newUser = new User({
25+
...req.body,
26+
password: hashedPassword,
27+
});
28+
}
29+
30+
// Save User || Handle User Saving Error
31+
try {
32+
const result = await newUser.save();
33+
res.status(200).json({
34+
message: "User Was Added Successfully!",
35+
});
36+
} catch (error) {
37+
res.status(500).json({
38+
errors: {
39+
common: {
40+
msg: "Unknown error occured!",
41+
},
42+
},
43+
});
44+
}
45+
};
46+
647
// Module Export
7-
module.exports = { getUsers };
48+
module.exports = { getUsers, addUser };

middlewares/common/errorHandler.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const errorHandler = (error, req, res, next) => {
1414
res.status(error.status || 500);
1515

1616
// Conditional Html || Json Resposne
17-
if (!res.locals.html) {
17+
if (res.locals.html) {
1818
res.render("errorPage", {
1919
title: "Error Page",
2020
});

middlewares/users/avatarUpload.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const avatarUpload = (req, res, next) => {
1010
"Only .jpg, jpeg or .png format allowed!"
1111
);
1212

13-
// Call The Multer Upload MiddleWare Function To Handle Error:
13+
// Call The Multer Upload MiddleWare Function To Handle Error:
1414
upload.any()(req, res, (error) => {
1515
if (error) {
1616
res.status(500).json({

middlewares/users/userValidator.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// External Imports:
2+
const { check, validationResult } = require("express-validator");
3+
const createError = require("http-errors");
4+
const path = require("path");
5+
const { unlink } = require("fs");
6+
7+
// internal Imports:
8+
const User = require("../../models/People");
9+
10+
// Validate User Data
11+
const addUserValidators = [
12+
check("name")
13+
.isLength({ min: 1 })
14+
.withMessage("Name is required!")
15+
.isAlpha("en-US", { ignore: " -" })
16+
.withMessage("Name must not contain anyting other than alphabet")
17+
.trim(),
18+
check("email")
19+
.isEmail()
20+
.withMessage("Invalid Email Address")
21+
.trim()
22+
.custom(async (value) => {
23+
try {
24+
const user = await User.findOne({ email: value });
25+
if (user) {
26+
throw createError("Email already in use!");
27+
}
28+
} catch (error) {
29+
throw createError(error.message);
30+
}
31+
}),
32+
check("mobile")
33+
.isMobilePhone("bn-BD", { strictMode: true })
34+
.withMessage("Mobile number must be a valid Bangladeshi mobile number")
35+
.custom(async (value) => {
36+
try {
37+
const user = await User.findOne({ mobile: value });
38+
if (user) {
39+
throw createError("Mobile number is already use!");
40+
}
41+
} catch (error) {
42+
throw createError(error.message);
43+
}
44+
}),
45+
check("password")
46+
.isStrongPassword()
47+
.withMessage(
48+
"Password must be at least 8 character long & should contain at least 1 lowercase, 1 uppercase, 1 number & 1 symbol"
49+
),
50+
];
51+
52+
// Handle Form Data Validation Error if occured Unlink Uploaded image:
53+
const addUserValidationHandler = (req, res, next) => {
54+
// Get complex validation Errors
55+
const errors = validationResult(req);
56+
// Syncronise Validation Errors
57+
const mappedErrors = errors.mapped();
58+
59+
if (Object.keys(mappedErrors).length === 0) {
60+
next();
61+
} else {
62+
// Remove Uploaded File
63+
if (req.files.length > 0) {
64+
const { filename } = req.files[0];
65+
unlink(
66+
path.join(`${__dirname}/../public/uploads/avatars/${filename}`),
67+
(err) => {
68+
if (err) console.log(err);
69+
}
70+
);
71+
}
72+
73+
// Response The Errors To User:
74+
res.status(500).json({
75+
errors: mappedErrors,
76+
});
77+
}
78+
};
79+
// Module Exports:
80+
module.exports = {
81+
addUserValidators,
82+
addUserValidationHandler,
83+
};

router/userRouter.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,25 @@ const express = require("express");
33
const router = express.Router();
44

55
// Internal Modules
6-
const { getUsers } = require("../controller/userController");
6+
const { getUsers, addUser } = require("../controller/userController");
77
const decorateHtmlResponse = require("../middlewares/common/decorateHtmlResponse");
8+
const avatarUpload = require("../middlewares/users/avatarUpload");
9+
const {
10+
addUserValidators,
11+
addUserValidationHandler,
12+
} = require("../middlewares/users/userValidator");
813

914
// Get User Page
1015
router.get("/", decorateHtmlResponse("User"), getUsers);
1116

17+
// Add User With Avatar {Rest API}
18+
router.post(
19+
"/",
20+
avatarUpload,
21+
addUserValidators,
22+
addUserValidationHandler,
23+
addUser
24+
);
25+
1226
// Module Export:
1327
module.exports = router;

views/errorPage.ejs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,5 @@
88
</head>
99
<body>
1010
<p><%= error.message %></p>
11-
<p><%= error.status %></p>
12-
<p><%= error %></p>
13-
1411
</body>
1512
</html>

views/partials/add_user_modal.ejs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
2+
<div class="modal-wrapper" id="add-user-modal">
3+
<div class="modal">
4+
<a href="#" onclick="closeModal()" class="modal-close">+</a>
5+
<div class="modal-title">
6+
<h2>Create New User</h2>
7+
</div>
8+
<div class="modal-body">
9+
<form
10+
method="post"
11+
action="/users"
12+
enctype="multipart/form-data"
13+
id="add-user-form">
14+
<input type="text" placeholder="enter name" name="name" />
15+
<p class="error name-error">This is error</p>
16+
<input type="text" placeholder="enter email" name="email" />
17+
<p class="error email-error">This is error</p>
18+
<input type="text" placeholder="enter mobile" name="mobile" />
19+
<p class="error mobile-error">This is error</p>
20+
<input
21+
type="password"
22+
placeholder="enter password"
23+
name="password"
24+
/>
25+
<p class="error password-error">This is error</p>
26+
<input type="file" name="avatar" />
27+
<p class="error avatar-error">This is error</p>
28+
29+
<p class="error common-error">This is error</p>
30+
31+
<input type="submit" value="Submit" />
32+
</form>
33+
</div>
34+
</div>
35+
</div>
36+
<script>
37+
const modal = document.querySelector("#add-user-modal");
38+
const form = document.querySelector("#add-user-form");
39+
40+
const closeModal=()=> modal.style.display = "none";
41+
const openModal=()=> modal.style.display = "block";
42+
43+
// Success Toast
44+
const successToast = Toastify({
45+
text:"User Added Successfully! Reloding the list...",
46+
duration:1000
47+
})
48+
49+
// Form submit Handler:
50+
form.onsubmit = async function(event){
51+
event.preventDefault()
52+
53+
// Clear Field Errors First:
54+
const errorPlaceHolders = document.querySelectorAll("p.error");
55+
for(let i=0; i<errorPlaceHolders.length; i++){
56+
errorPlaceHolders[i].style.display="none";
57+
}
58+
59+
const inputErrors = document.querySelectorAll("input.error");
60+
if(inputErrors.length>0){
61+
for (let j=0; j<inputErrors.length; j++){
62+
inputErrors[j].classList.remove("error");
63+
}
64+
}
65+
66+
// Prepare Form Data:
67+
const formData = new FormData(form);
68+
69+
// Send the request to the server
70+
let response = await fetch("/users",{
71+
method:"POST",
72+
body: formData
73+
})
74+
75+
// Get Response From Server:
76+
let result = await response.json();
77+
78+
// Handle Errors and response:
79+
if(result.errors){
80+
// Errors
81+
Object.keys(result.errors).forEach((fieldName)=>{
82+
// Add error calss to all inputs
83+
form[fieldname].classList.add("error");
84+
85+
// Set all error placeholders (p tag) textContent
86+
const errorPlaceHolders = document.querySelector(`.${fieldName}-error`);
87+
errorPlaceHolders.textContent = result.errors[fieldName].msg;
88+
89+
// Make all PlaceHolders Visible
90+
errorPlaceHolders.style.display= "block";
91+
});
92+
}else{
93+
// Success
94+
successToast.showToast();
95+
closeModal();
96+
document.querySelector("p.error").style.display= "none";
97+
98+
// Reload the page after 1 second
99+
setTimeout(()=>{
100+
location.reload();
101+
},1000)
102+
}
103+
};
104+
105+
</script>

views/users.ejs

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -33,38 +33,6 @@
3333
</table>
3434
</div>
3535
</div>
36-
37-
<div class="modal-wrapper" id="add-user-modal">
38-
<div class="modal">
39-
<a href="#" onclick="closeModal()" class="modal-close">+</a>
40-
<div class="modal-title">
41-
<h2>Create New User</h2>
42-
</div>
43-
<div class="modal-body">
44-
<form id="add-user-form">
45-
<input type="text" placeholder="enter name" name="name" />
46-
<p class="error show">This is error</p>
47-
<input type="text" placeholder="enter email" name="email" />
48-
<input type="text" placeholder="enter mobile" name="mobile" />
49-
<input
50-
type="password"
51-
placeholder="enter password"
52-
name="password"
53-
/>
54-
<input type="file" name="avatar" />
55-
<input type="submit" value="Submit" />
56-
</form>
57-
</div>
58-
</div>
59-
</div>
60-
<script>
61-
const modal = document.querySelector("#add-user-modal");
62-
function closeModal() {
63-
modal.style.display = "none";
64-
}
65-
function openModal() {
66-
modal.style.display = "block";
67-
}
68-
</script>
36+
<%- include('./partials/add_user_modal.ejs') %>
6937
</body>
7038
</html>

0 commit comments

Comments
 (0)