Everyday Thoughts is an app that demonstrates 2 data entities including the user, book and embedded data - thoughts.
To securely store the book information, authorisation and authentication are implemented throughout the app.
As a user, I get to access my book records by logging in the Everyday Thoughts App.
As a user, I get to record my favorite quote, rating, genre and thought about my books.
As a user, I get to manage (update and delete) the information that I have recorded.
- Node.js
- Express Framework
- Express Middleware
- MongoDB & Mongoose
- JavaScript
- EJS Partial Templates
- bcrypt, Validator
- Cyclic deployment
- nodemon, dotenv, gitignore
- Git & GitHub
- API
- Additional model entities such as thoughts for journaling purposes.
- Admin role to manage user database.
- Increased error handling.
- Clean input data.
- To manipulate the EJS view between Login & Logout
<% if (isLoggedIn) { %>
<li><a href="/users/logout">LOGOUT</a></li>
<%} else { %>
<li><a href="/users/newaccount">CREATE ACCOUNT</a></li>
<li><a href="/users/login">LOGIN</a></li>
<% } %>
- To manipulate the EJS view for API quote
<%if(quote.author === "Anonymous"){ %>
<p class="dailyquote">"<%=quote.quote%>"</p>%>
<% } else { %>
<p class="dailyquote"><%=quote.author%>: "<%=quote.quote%>"</p>
<%};%>
- Account Creation
async function create(req, res, next) {
try {
const password = await bcrypt.hash(req.body.password, saltRounds);
const user = await User.create({
name: req.body.name,
email: req.body.email,
password,
});
context = {
isLoggedIn: false,
msg: "Account Succesfully Created! Login to Begin your Everyday Thoughts!",
};
res.status(201).render("users/login", context);
} catch (error) {
if (error.code === 11000) {
context = {
errormsg: "There's a duplicate, try again?",
isLoggedIn: false,
};
res.render("users/newaccount", context);
}
if (error.name === "ValidationError") {
context = {
errormsg: "Invalid Details. Try Again?",
isLoggedIn: false,
};
res.render("users/newaccount", context);
} else {
return next(error);
}
}
}
- Sign In
async function signIn(req, res, next) {
const email = req.body.email;
const password = req.body.password;
const quote = await fetchData();
const user = await User.findOne({ email }).exec();
if (!user) {
const context = { msg: "User does not exist", isLoggedIn: false };
res.render("users/login", context);
return;
}
bcrypt.compare(password, user.password, (err, result) => {
if (result) {
req.session.userId = user._id;
req.session.isLoggedIn = true;
req.session.quote = quote;
res.render("index", req.session);
} else {
const context = { msg: "Incorrect Password", isLoggedIn: false };
res.render("users/login", context);
}
});
}
- Authorisation
const isAuth = async (req, res, next) => {
if (req.session.userId) {
const user = await User.findById(req.session.userId).exec();
res.locals.user = user;
isLoggedIn = true;
next();
} else {
res.status(403).redirect("/users/newaccount");
}
};
- Delete an embedded data
async function deleteThought(req, res) {
try {
const bookId = req.params.bookId;
const thoughtId = req.params.thoughtId;
const book = await Book.findById(bookId);
const foundThought = book.thoughts.find(
(thought) => thought._id.toString() === thoughtId
);
foundThought.deleteOne(thoughtId);
await book.save();
res.redirect(`/books/${bookId}/edit/#thoughts`);
} catch (err) {
console.error(err);
res.status(500).send("Server Error");
}
}
- API
function fetchData() {
return fetch("https://api.goprogram.ai/inspiration").then((res) =>
res.json()
);
}
async function homePage(req, res) {
const quote = await fetchData();
if (req.session.isLoggedIn) {
const isLoggedIn = true;
res.render("index", { quote, isLoggedIn });
} else {
const isLoggedIn = false;
res.render("index", { quote, isLoggedIn });
}
}
- Initial planning on CRUD and Model Entity
- Importance of MVC Approach
- Different way of validation: HTML Input, Regular Expressions, Schema Validation
- Naming (singular, plural, capital) matters A LOT
- JavaScript Promises: Async & Await
- Manipulate data using EJS
- Error Handling
- Opening and closing tags, to "/" or not to "/"
- Debugging Skills
- MongoDB & Mongoose Synthax
- req.params/sessions/body & res.redirect/render/send
- Managing embedded data as an array: push, find, deleteOne and save
- The Importance of Authorisation
- Password Hashing
- User Testing
Case studies: Journey | Penzu
Wireframe: Canva
Header and Footer Template: W3Schools
Social Icons: Font Awesome
Quote API: Inspiration
Validation: Validator
API Reference: Stack Overflow