Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hw06 email #5485

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
DB_HOST=<MongoDB url>
SECRET_KYE=<SECRET_KYE>
SMTP_HOST=<Mailtrap host>
SMTP_PORT=<Mailtrap port>
SMTP_USER=<Mailtrap username>
SMTP_PASSWORD=<Mailtrap password>
API_URL=<Api url>
Binary file added 64fc223b958a04b51eb30053_jXnrfr0M.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 24 additions & 16 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
const express = require('express')
const logger = require('morgan')
const cors = require('cors')
const express = require("express");
const logger = require("morgan");
const cors = require("cors");
require("dotenv").config();

const contactsRouter = require('./routes/api/contacts')
const contactsRouter = require("./routes/api/contacts");
const authRouter = require("./routes/api/auth");
const feedbackRouter = require("./routes/api/feetback");

const app = express()
const app = express();
const formatsLogger = app.get("env") === "development" ? "dev" : "short";

const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short'
app.use(logger(formatsLogger));
app.use(cors());
app.use(express.json());
app.use(express.static("public"));

app.use(logger(formatsLogger))
app.use(cors())
app.use(express.json())

app.use('/api/contacts', contactsRouter)
app.use("/users", authRouter);
app.use("/api/contacts", contactsRouter);
app.use("/feedback", feedbackRouter);

app.use((req, res) => {
res.status(404).json({ message: 'Not found' })
})
res.status(404).json({ message: "Not founddd" });
});

app.use((err, req, res, next) => {
res.status(500).json({ message: err.message })
})
const { status = 500, message = "Server error" } = err;
res.status(status).json({
message: message,
});
});

module.exports = app
module.exports = app;
154 changes: 154 additions & 0 deletions controllers/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const gravatar = require("gravatar");
const path = require("path");
const fs = require("fs/promises");
const Jimp = require("jimp");
const { nanoid } = require("nanoid");

const UserModel = require("../models/modelUsers");
const { HttpError, ctrlWrapper } = require("../helpers");
const sendActivetionMail = require("../helpers/mailServis");

const { SECRET_KYE } = process.env;

const avatarDir = path.join(__dirname, "../", "public", "avatars");

const registerUser = async (req, res) => {
const { email, password } = req.body;
const user = await UserModel.findOne({ email });
if (user) {
throw HttpError(409, "Email in use");
}
const hashPassword = await bcrypt.hash(password, 10);
const avatarURL = gravatar.url(email, { s: 250 });
const verificationToken = nanoid();
const newUser = await UserModel.create({
...req.body,
password: hashPassword,
avatarURL,
verificationToken,
});
if (!newUser) {
throw HttpError(404, "Not found");
}
const { email: emailUse, subscription } = newUser;
const message = {
from: process.env.SMTP_USER,
to: email,
subject: process.env.API_URL,
text: `To confirm your registration, please clik on link below\n
http://localhost:3000/users/verify/${verificationToken}`,
html: `<p>To confirm your registration, please clik on link below</p>
<p><a href="http://localhost:3000/users/verify/${verificationToken}">Clic</a></p>`,
};
await sendActivetionMail(message);

res.status(201).json({ user: { email: emailUse, subscription } });
};
const login = async (req, res) => {
const { email, password } = req.body;
const user = await UserModel.findOne({ email });

if (!user) {
throw HttpError(401, "Email or password invalid");
}
const passwordCompare = await bcrypt.compare(password, user.password);
if (!passwordCompare) {
throw HttpError(401, "Password or email invalid");
}
if (!user.verify) {
throw HttpError(401, "Not verify");
}
const payloade = { id: user._id };
const token = jwt.sign(payloade, SECRET_KYE, { expiresIn: "23h" });
await UserModel.findByIdAndUpdate(user._id, { token });
res.status(201).json({
user: { email: user.email, subscription: user.subscription },
token,
});
};
const current = async (req, res) => {
const { email, subscription } = req.user;
res.status(200).json({
email,
subscription,
});
};
const logout = async (req, res) => {
const user = req.user;
await UserModel.findByIdAndUpdate(user._id, { token: "" });
res.status(204).json();
};
const nweAvatar = async (req, res) => {
const { path: tmpUpload, originalname } = req.file;
const fileName = `${req.user._id}_${originalname}`;
const resultUpload = path.join(avatarDir, fileName);
// ==========================================================

await Jimp.read(tmpUpload)
.then(async (avatar) => {
return avatar.resize(250, 250).quality(60).writeAsync(tmpUpload);
})
.catch((err) => {
console.error(err);
});
// ===========================================================

await fs.rename(tmpUpload, resultUpload);
const avatarURL = path.join("/avatars", fileName);
await UserModel.findByIdAndUpdate(req.user._id, { avatarURL });
res.status(200).json({ avatarURL });
};
const authVerify = async (req, res, next) => {
const { verificationToken } = req.params;
const user = await UserModel.findOne({ verificationToken });

if (!user) {
throw HttpError(401, "User not found");
}

if (user.verify) {
throw HttpError(404, "You verify");
}

await UserModel.findByIdAndUpdate(user._id, {
verify: true,
verificationToken: null,
});
res.status(200).json({ message: "Verification successful" });
};

const verify = async (req, res, next) => {
const { email } = req.body;
const user = await UserModel.findOne({ email });
if (!user) {
throw HttpError(404, "User not found");
}
if (user.verify) {
throw HttpError(400, "Verification has already been passed");
}
const message = {
from: process.env.SMTP_USER,
to: email,
subject: process.env.API_URL,
text: `To confirm your registration, please clik on link below\n
http://localhost:3000/users/verify/${user.verificationToken}`,
html: `<p>To confirm your registration, please clik on link below</p>
<p><a href="http://localhost:3000/users/verify/${user.verificationToken}">Clic</a></p>`,
};

await sendActivetionMail(message);

res.status(200).json({ message: "Verification email sent" });
};

module.exports = {
registerUser: ctrlWrapper(registerUser),
login: ctrlWrapper(login),
current: ctrlWrapper(current),
logout: ctrlWrapper(logout),
nweAvatar: ctrlWrapper(nweAvatar),
authVerify: ctrlWrapper(authVerify),
verify: ctrlWrapper(verify),
};
65 changes: 65 additions & 0 deletions controllers/contacts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const Contact = require("../models/modelContacts");
const { HttpError, ctrlWrapper } = require("../helpers");

const getAllContacts = async (req, res) => {
const { page = 1, limit = 10 } = req.query;
const skip = (page - 1) * limit;
const { _id: owner } = req.user;
const data = await Contact.find({ owner }, "-createdAt -updatedAt -owner", {
skip,
limit,
});
res.json(data);
};
const getContactById = async (req, res) => {
const id = req.params.contactId;
const data = await Contact.findById(id);
if (!data) {
throw HttpError(404, "Not found");
}
res.json(data);
};
const addContact = async (req, res) => {
console.log(req);
const { _id: owner } = req.user;
const data = await Contact.create({ ...req.body, owner });
if (!data) {
throw HttpError(404, "Not found");
}
res.status(201).json(data);
};
const deleteContactById = async (req, res) => {
const id = req.params.contactId;
const data = await Contact.findByIdAndRemove(id);
if (!data) {
throw HttpError(404, "Not found");
}
res.status(200).json({
message: "deleted contact",
});
};
const changeContact = async (req, res) => {
const id = req.params.contactId;
const data = await Contact.findByIdAndUpdate(id, req.body, { new: true });
if (!data) {
throw HttpError(404, "Not found");
}
res.status(200).json(data);
};
const updatedFavorite = async (req, res) => {
const id = req.params.contactId;
const data = await Contact.findByIdAndUpdate(id, req.body, { new: true });
if (!data) {
throw HttpError(404, "Not found");
}
res.status(200).json(data);
};

module.exports = {
getAllContacts: ctrlWrapper(getAllContacts),
getContactById: ctrlWrapper(getContactById),
addContact: ctrlWrapper(addContact),
deleteContactById: ctrlWrapper(deleteContactById),
changeContact: ctrlWrapper(changeContact),
updatedFavorite: ctrlWrapper(updatedFavorite),
};
47 changes: 47 additions & 0 deletions controllers/feedback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const Feedback = require("../models/modelFeedback");
const { HttpError, ctrlWrapper } = require("../helpers");

const addFeedback = async (req, res) => {
// console.log(req);
// const { _id: owner } = req.feedback;
const data = await Feedback.create({ ...req.body });
if (!data) {
throw HttpError(404, "Not found");
}
res.status(201).json(data);
};
const getAllFeedback = async (req, res) => {
const { page = 1, limit = 10 } = req.query;
const skip = (page - 1) * limit;
const { _id: owner } = req.user;
const data = await Feedback.find({ owner }, "-createdAt -updatedAt -owner", {
skip,
limit,
});
res.json(data);
};
const getFeedbackById = async (req, res) => {
const id = req.params.contactId;
const data = await Feedback.findById(id);
if (!data) {
throw HttpError(404, "Not found");
}
res.json(data);
};
const deleteFeedbackById = async (req, res) => {
const id = req.params.contactId;
const data = await Feedback.findByIdAndRemove(id);
if (!data) {
throw HttpError(404, "Not found");
}
res.status(200).json({
message: "deleted contact",
});
};

module.exports = {
getAllFeedback: ctrlWrapper(getAllFeedback),
getFeedbackById: ctrlWrapper(getFeedbackById),
addFeedback: ctrlWrapper(addFeedback),
deleteFeedbackById: ctrlWrapper(deleteFeedbackById),
};
6 changes: 6 additions & 0 deletions helpers/HttpError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const HttpError = (status, messang) => {
const error = new Error(messang);
error.status = status;
return error;
};
module.exports = HttpError;
12 changes: 12 additions & 0 deletions helpers/ctrlWrapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const ctrlWrapper = (ctrl) => {
const func = async (req, res, next) => {
try {
await ctrl(req, res, next);
} catch (error) {
next(error);
}
};
return func;
};

module.exports = ctrlWrapper;
8 changes: 8 additions & 0 deletions helpers/handleMongooseError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const handleMongooseError = (error, data, next) => {
const { name, code } = error;
// const status = name === "MongoServerError" && code === 11000 ? 409 : 400;
error.status = 400;
next();
};

module.exports = handleMongooseError;
5 changes: 5 additions & 0 deletions helpers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const HttpError = require("./HttpError");
const ctrlWrapper = require("./ctrlWrapper");
const handleMongooseError = require("./handleMongooseError");

module.exports = { HttpError, ctrlWrapper, handleMongooseError };
Loading