all CRUD operations functional

This commit is contained in:
ak 2023-09-09 18:47:17 -07:00
parent 2ca5dd5238
commit 1006d28b71
7 changed files with 272 additions and 35 deletions

13
app.js
View file

@ -1,4 +1,3 @@
const createError = require("http-errors");
const express = require("express"); const express = require("express");
const path = require("path"); const path = require("path");
const cookieParser = require("cookie-parser"); const cookieParser = require("cookie-parser");
@ -36,16 +35,4 @@ const router = require("./routes/index");
app.use("/", router); app.use("/", router);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// render the error page
res.status(err.status || 500);
res.render("error");
});
module.exports = app; module.exports = app;

View file

@ -111,9 +111,58 @@ exports.category_delete_get = asyncHandler(async (req, res, next) => {
}); });
exports.category_update_get = asyncHandler(async (req, res, next) => { exports.category_update_get = asyncHandler(async (req, res, next) => {
res.send("ligma"); // get current category from URL
const category = await Category.findOne({
simpleName: req.params.category,
})
.lean()
.exec();
res.render("editcategory", { category: category });
}); });
exports.category_update_post = asyncHandler(async (req, res, next) => { exports.category_update_post = [
res.send("ligma"); // Validate and sanitize name
body("name", "Category must have a name!")
.trim()
.isLength({ min: 1 })
.escape(),
// Validate and sanitize description
body("description", "Category must have a description!")
.trim()
.isLength({ min: 1 })
.escape(),
// Process request after validation and sanitization.
asyncHandler(async (req, res, next) => {
// Extract the validation errors from a request.
const errors = validationResult(req);
// find existing category in database
const dbCat = await Category.findOne({ simpleName: req.params.category })
.lean()
.exec();
// Create a new category with escaped and trimmed data.
const category = new Category({
name: req.body.name,
simpleName: req.body.name.toLowerCase().replace(" ", ""),
description: req.body.description,
_id: dbCat._id, // copy original category ID to prevent overwrite errors
}); });
// if there are validation errors
if (!errors.isEmpty()) {
// Render the creation form again with sanitized values/error messages.
res.render("editcategory", {
category: dbCat,
});
return;
}
// Data from form is valid.
else {
await Category.findByIdAndUpdate(dbCat._id, category, {});
res.redirect(`/${category.simpleName}`);
}
}),
];

View file

@ -57,7 +57,7 @@ exports.item_create_post = [
.isLength({ min: 2, max: 2 }) .isLength({ min: 2, max: 2 })
.escape(), .escape(),
// Validate and sanitize price (formatting has already been taken care of) // Validate and sanitize quantity
body("quantity", "Item must have a quantity!") body("quantity", "Item must have a quantity!")
.trim() .trim()
.isLength({ min: 1 }) .isLength({ min: 1 })
@ -75,15 +75,6 @@ exports.item_create_post = [
.lean() .lean()
.exec(); .exec();
console.log([
req.body.name,
category._id,
req.body.description,
req.body.dollars,
req.body.cents,
req.body.quantity,
]);
// Create a new Item with escaped and trimmed data. // Create a new Item with escaped and trimmed data.
const item = new Item({ const item = new Item({
name: req.body.name, name: req.body.name,
@ -96,8 +87,9 @@ exports.item_create_post = [
// if there are validation errors // if there are validation errors
if (!errors.isEmpty()) { if (!errors.isEmpty()) {
// Render the creation form again with sanitized values/error messages. // Render the creation form again with sanitized values/error messages.
res.render("createcategory", { res.render("createitem", {
errors: errors.array(), errors: errors.array(),
category: category,
}); });
return; return;
} }
@ -144,9 +136,81 @@ exports.item_delete_get = asyncHandler(async (req, res, next) => {
}); });
exports.item_update_get = asyncHandler(async (req, res, next) => { exports.item_update_get = asyncHandler(async (req, res, next) => {
res.send("ligma"); // get current category from URL
const category = await Category.findOne({
simpleName: req.params.category,
})
.lean()
.exec();
const item = await Item.findOne({ _id: req.params.item });
res.render("edititem", { category: category, item: item });
}); });
exports.item_update_post = asyncHandler(async (req, res, next) => { exports.item_update_post = [
res.send("ligma"); // Validate and sanitize name
body("name", "Item must have a name!").trim().isLength({ min: 1 }).escape(),
// Validate and sanitize description
body("description", "Item must have a description!")
.trim()
.isLength({ min: 1 })
.escape(),
// Validate and sanitize price (formatting has already been taken care of)
body("dollars", "Item must have a dollar amount!")
.trim()
.isLength({ min: 1 })
.escape(),
body("cents", "Item must have a cent amount!")
.trim()
.isLength({ min: 2, max: 2 })
.escape(),
// Validate and sanitize quantity
body("quantity", "Item must have a quantity!")
.trim()
.isLength({ min: 1 })
.escape(),
// Process request after validation and sanitization.
asyncHandler(async (req, res, next) => {
// Extract the validation errors from a request.
const errors = validationResult(req);
// get current category from URL
const category = await Category.findOne({
simpleName: req.params.category,
})
.lean()
.exec();
// get item in db
const dbItem = await Item.findOne({ _id: req.params.item });
// Create a new Item with escaped and trimmed data.
const item = new Item({
name: req.body.name,
category: category._id,
description: req.body.description,
price: Number(`${req.body.dollars}.${req.body.cents}`),
quantity: req.body.quantity,
_id: dbItem._id,
}); });
// if there are validation errors
if (!errors.isEmpty()) {
// Render the creation form again with sanitized values/error messages.
res.render("edititem", {
errors: errors.array(),
category: category,
item: dbItem,
});
return;
}
// Data from form is valid.
else {
await Item.findByIdAndUpdate(dbItem._id, item, {});
res.redirect(`/${req.params.category}/${req.params.item}`);
}
}),
];

View file

@ -27,6 +27,14 @@
+ Create new item + Create new item
</a> </a>
<div class="pb-4"></div> <div class="pb-4"></div>
<a
href="/<%= category.simpleName %>/update"
type="button"
class="btn btn-primary px-4"
>
Edit this category
</a>
<div class="pb-4"></div>
<a <a
href="/<%= category.simpleName %>/delete" href="/<%= category.simpleName %>/delete"
type="button" type="button"

48
views/editcategory.ejs Normal file
View file

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html>
<head>
<title>Good Pickin's - Editing <%= category.name %></title>
<link rel="stylesheet" href="/styles/css/bootstrap.min.css" />
</head>
<body class="bg-dark text-light">
<div class="d-flex flex-column py-4 px-4 align-items-center">
<h1 class="mb-4">Editing <%= category.name %></h1>
<form class="d-flex flex-column align-items-center w-50" method="post">
<div class="input-group mb-4" data-bs-theme="dark">
<span class="input-group-text" id="name">Category Name:</span>
<input
type="text"
class="form-control"
aria-label="category name"
aria-describedby="name"
name="name"
value="<%= category.name %>"
/>
</div>
<div class="input-group mb-4" data-bs-theme="dark">
<span class="input-group-text" id="description">
Category Description:
</span>
<input
type="text"
class="form-control"
aria-label="category description"
aria-describedby="description"
name="description"
value="<%= category.description %>"
/>
</div>
<button type="submit" class="btn btn-outline-light px-4 py-2">
Submit
</button>
</form>
</div>
<footer
class="position-fixed bottom-0 border-light border-top w-100 py-2 d-flex justify-content-center bg-dark"
>
<a href="/" type="button" class="btn btn-outline-light px-4 py-1">
Back to Home
</a>
</footer>
</body>
</html>

84
views/edititem.ejs Normal file
View file

@ -0,0 +1,84 @@
<!DOCTYPE html>
<html>
<head>
<title>
Good Pickin's - <%= category.name %> - Editing <%= item.name %>
</title>
<link rel="stylesheet" href="/styles/css/bootstrap.min.css" />
</head>
<body class="bg-dark text-light">
<div class="d-flex flex-column py-4 px-4 align-items-center">
<h1 class="mb-4">Editing <%= item.name %></h1>
<form class="d-flex flex-column align-items-center w-50" method="post">
<div class="input-group mb-4" data-bs-theme="dark">
<span class="input-group-text" id="name">Item Name:</span>
<input
type="text"
class="form-control"
aria-label="item name"
aria-describedby="name"
name="name"
value="<%= item.name %>"
/>
</div>
<div class="input-group mb-4" data-bs-theme="dark">
<span class="input-group-text" id="description">
Item Description:
</span>
<input
type="text"
class="form-control"
aria-label="item description"
aria-describedby="description"
name="description"
value="<%= item.description %>"
/>
</div>
<div class="input-group mb-4" data-bs-theme="dark">
<span class="input-group-text" id="price"> Item Price: </span>
<input
type="text"
class="form-control"
aria-label="dollars"
aria-describedby="price"
name="dollars"
value="<%= Math.trunc(item.price) %>"
oninput="this.value = this.value.replace(/[^0-9]/g, '')"
/>
<span class="input-group-text" id="price">.</span>
<input
type="text"
class="form-control"
aria-label="cents"
aria-describedby="price"
name="cents"
oninput="this.value < 3 ? this.value = this.value.replace(/[^0-9]{1,2}/g, '') : this.value = this.value.substring(0, 2)"
value="<%= Number.parseFloat(item.price).toFixed(2).toString().match(/(?<=\.)(\d+)/gi) %>"
/>
</div>
<div class="input-group mb-4" data-bs-theme="dark">
<span class="input-group-text" id="quantity"> Item Quantity: </span>
<input
type="text"
class="form-control"
aria-label="item quantity"
aria-describedby="quantity"
name="quantity"
value="<%= item.quantity %>"
oninput="this.value = this.value.replace(/[^0-9]/g, '')"
/>
</div>
<button type="submit" class="btn btn-outline-light px-4 py-2">
Submit
</button>
</form>
</div>
<footer
class="position-fixed bottom-0 border-light border-top w-100 py-2 d-flex justify-content-center bg-dark"
>
<a href="/" type="button" class="btn btn-outline-light px-4 py-1">
Back to Home
</a>
</footer>
</body>
</html>

View file

@ -1,3 +0,0 @@
<h1><%= message = 'Error!' %></h1>
<h2><%= error.status %></h2>
<pre><%= error.stack %></pre>