functioning create and delete functionality
This commit is contained in:
parent
d1c0ec6221
commit
2ca5dd5238
11 changed files with 374 additions and 71 deletions
2
app.js
2
app.js
|
|
@ -28,7 +28,7 @@ app.set("view engine", "ejs");
|
|||
|
||||
app.use(logger("dev"));
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(cookieParser());
|
||||
app.use(express.static(path.join(__dirname, "public")));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
const Category = require("../models/category.js");
|
||||
const Item = require("../models/item.js");
|
||||
const asyncHandler = require("express-async-handler");
|
||||
const { body, validationResult } = require("express-validator");
|
||||
|
||||
exports.index = asyncHandler(async (req, res, next) => {
|
||||
// get array of relevant variables for displaying category and its items
|
||||
|
|
@ -24,20 +25,89 @@ exports.index = asyncHandler(async (req, res, next) => {
|
|||
});
|
||||
});
|
||||
|
||||
exports.category_create_get = asyncHandler(async (req, res, next) => {
|
||||
res.send("ligma");
|
||||
exports.category_create_get = (req, res, next) => {
|
||||
res.render("createcategory");
|
||||
};
|
||||
|
||||
exports.category_create_post = [
|
||||
// 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);
|
||||
|
||||
// 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,
|
||||
});
|
||||
|
||||
exports.category_create_post = asyncHandler(async (req, res, next) => {
|
||||
res.send("ligma");
|
||||
// if there are validation errors
|
||||
if (!errors.isEmpty()) {
|
||||
// Render the creation form again with sanitized values/error messages.
|
||||
res.render("createcategory", {
|
||||
errors: errors.array(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Data from form is valid.
|
||||
else {
|
||||
// Check if Category with same name already exists.
|
||||
const categoryExists = await Category.findOne({
|
||||
name: req.body.name,
|
||||
}).exec();
|
||||
if (categoryExists) {
|
||||
// Category exists, redirect to its page.
|
||||
res.redirect(`/${categoryExists.simpleName}`);
|
||||
}
|
||||
// else category is unique
|
||||
else {
|
||||
await category.save();
|
||||
// saved. Redirect to new category page.
|
||||
res.redirect(`/${category.simpleName}`);
|
||||
}
|
||||
}
|
||||
}),
|
||||
];
|
||||
|
||||
exports.category_delete_get = asyncHandler(async (req, res, next) => {
|
||||
res.send("ligma");
|
||||
});
|
||||
|
||||
exports.category_delete_post = asyncHandler(async (req, res, next) => {
|
||||
res.send("ligma");
|
||||
// get current category from URL
|
||||
const category = await Category.findOne({
|
||||
simpleName: req.params.category,
|
||||
})
|
||||
.lean()
|
||||
.exec();
|
||||
// check
|
||||
if (category === null) {
|
||||
const error = new Error("Category not found");
|
||||
return next(error);
|
||||
}
|
||||
// else, continue to find all relevant items (if any)
|
||||
const items = await Item.find({ category: category._id }).lean().exec();
|
||||
// if items found
|
||||
if (items.length > 0) {
|
||||
// delete all items from db - for loop used for practicality reasons (forEach() doesn't play well with async)
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const itemID = items[i]._id;
|
||||
await Item.findByIdAndDelete(itemID);
|
||||
}
|
||||
}
|
||||
// delete category
|
||||
await Category.findByIdAndDelete(category._id);
|
||||
// redirects to Home
|
||||
res.redirect("/");
|
||||
});
|
||||
|
||||
exports.category_update_get = asyncHandler(async (req, res, next) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
const Category = require("../models/category.js");
|
||||
const Item = require("../models/item.js");
|
||||
const asyncHandler = require("express-async-handler");
|
||||
const { body, validationResult } = require("express-validator");
|
||||
|
||||
exports.index = asyncHandler(async (req, res, next) => {
|
||||
// get current item from URL
|
||||
|
|
@ -23,24 +24,123 @@ exports.index = asyncHandler(async (req, res, next) => {
|
|||
});
|
||||
});
|
||||
|
||||
exports.item_detail = asyncHandler(async (req, res, next) => {
|
||||
res.send("ligma");
|
||||
});
|
||||
|
||||
exports.item_create_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();
|
||||
// render create item page
|
||||
res.render("createitem", {
|
||||
category: category,
|
||||
});
|
||||
});
|
||||
|
||||
exports.item_create_post = asyncHandler(async (req, res, next) => {
|
||||
res.send("ligma");
|
||||
exports.item_create_post = [
|
||||
// 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 price (formatting has already been taken care of)
|
||||
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();
|
||||
|
||||
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.
|
||||
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,
|
||||
});
|
||||
|
||||
// if there are validation errors
|
||||
if (!errors.isEmpty()) {
|
||||
// Render the creation form again with sanitized values/error messages.
|
||||
res.render("createcategory", {
|
||||
errors: errors.array(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Data from form is valid.
|
||||
else {
|
||||
// Check if Item with same name already exists.
|
||||
const itemExists = await Item.findOne({
|
||||
name: req.body.name,
|
||||
category: category._id,
|
||||
})
|
||||
.lean()
|
||||
.exec();
|
||||
if (itemExists) {
|
||||
// Item exists, redirect to its page.
|
||||
res.redirect(`/${req.params.category}/${itemExists._id}`);
|
||||
}
|
||||
// else Item is unique
|
||||
else {
|
||||
// save item and redirect to its ID
|
||||
item.save().then((uploadedItem) => {
|
||||
res.redirect(`/${req.params.category}/${uploadedItem._id}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}),
|
||||
];
|
||||
|
||||
exports.item_delete_get = asyncHandler(async (req, res, next) => {
|
||||
res.send("ligma");
|
||||
});
|
||||
|
||||
exports.item_delete_post = asyncHandler(async (req, res, next) => {
|
||||
res.send("ligma");
|
||||
// get current item from URL
|
||||
const item = await Item.findOne({
|
||||
_id: req.params.item,
|
||||
})
|
||||
.lean()
|
||||
.exec();
|
||||
// check
|
||||
if (item === null) {
|
||||
const error = new Error("Item not found");
|
||||
return next(error);
|
||||
}
|
||||
// delete item
|
||||
await Item.findByIdAndDelete(item._id);
|
||||
// redirects to parent category
|
||||
res.redirect(`/${req.params.category}`);
|
||||
});
|
||||
|
||||
exports.item_update_get = asyncHandler(async (req, res, next) => {
|
||||
|
|
|
|||
66
package-lock.json
generated
66
package-lock.json
generated
|
|
@ -15,18 +15,16 @@
|
|||
"ejs": "^3.1.9",
|
||||
"express": "^4.18.2",
|
||||
"express-async-handler": "^1.2.0",
|
||||
"express-validator": "^7.0.1",
|
||||
"http-errors": "~1.6.3",
|
||||
"mongoose": "^7.5.0",
|
||||
"morgan": "~1.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mongoose": "^7.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mongodb-js/saslprep": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz",
|
||||
"integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"sparse-bitfield": "^3.0.3"
|
||||
|
|
@ -45,20 +43,17 @@
|
|||
"node_modules/@types/node": {
|
||||
"version": "20.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz",
|
||||
"integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ=="
|
||||
},
|
||||
"node_modules/@types/webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
"integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==",
|
||||
"dev": true
|
||||
"integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog=="
|
||||
},
|
||||
"node_modules/@types/whatwg-url": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz",
|
||||
"integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"@types/webidl-conversions": "*"
|
||||
|
|
@ -222,7 +217,6 @@
|
|||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-5.4.0.tgz",
|
||||
"integrity": "sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14.20.1"
|
||||
}
|
||||
|
|
@ -468,6 +462,18 @@
|
|||
"resolved": "https://registry.npmjs.org/express-async-handler/-/express-async-handler-1.2.0.tgz",
|
||||
"integrity": "sha512-rCSVtPXRmQSW8rmik/AIb2P0op6l7r1fMW538yyvTMltCO4xQEWMmobfrIxN2V1/mVrgxB8Az3reYF6yUZw37w=="
|
||||
},
|
||||
"node_modules/express-validator": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.0.1.tgz",
|
||||
"integrity": "sha512-oB+z9QOzQIE8FnlINqyIFA8eIckahC6qc8KtqLdLJcU3/phVyuhXH3bA4qzcrhme+1RYaCSwrq+TlZ/kAKIARA==",
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.21",
|
||||
"validator": "^13.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/cookie": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||
|
|
@ -719,8 +725,7 @@
|
|||
"node_modules/ip": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
|
||||
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
|
|
@ -751,11 +756,15 @@
|
|||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz",
|
||||
"integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
|
|
@ -768,7 +777,6 @@
|
|||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
|
||||
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
|
|
@ -829,7 +837,6 @@
|
|||
"version": "5.8.1",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.8.1.tgz",
|
||||
"integrity": "sha512-wKyh4kZvm6NrCPH8AxyzXm3JBoEf4Xulo0aUWh3hCgwgYJxyQ1KLST86ZZaSWdj6/kxYUA3+YZuyADCE61CMSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"bson": "^5.4.0",
|
||||
"mongodb-connection-string-url": "^2.6.0",
|
||||
|
|
@ -870,7 +877,6 @@
|
|||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz",
|
||||
"integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/whatwg-url": "^8.2.1",
|
||||
"whatwg-url": "^11.0.0"
|
||||
|
|
@ -880,7 +886,6 @@
|
|||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.5.0.tgz",
|
||||
"integrity": "sha512-FpOWOb0AJuaVcplmEyIJ2eCbVGe4gOoniPD+pmft5BrGrNrsFcnYXlERdXtBApGHMHPwD7WbxTyhCbUNr72F3Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"bson": "^5.4.0",
|
||||
"kareem": "2.5.1",
|
||||
|
|
@ -901,8 +906,7 @@
|
|||
"node_modules/mongoose/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/morgan": {
|
||||
"version": "1.9.1",
|
||||
|
|
@ -923,7 +927,6 @@
|
|||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
|
||||
"integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
|
|
@ -932,7 +935,6 @@
|
|||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
|
||||
"integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "4.x"
|
||||
},
|
||||
|
|
@ -944,7 +946,6 @@
|
|||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
|
|
@ -960,8 +961,7 @@
|
|||
"node_modules/mquery/node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
|
|
@ -1032,7 +1032,6 @@
|
|||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
|
||||
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
|
@ -1239,14 +1238,12 @@
|
|||
"node_modules/sift": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz",
|
||||
"integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ=="
|
||||
},
|
||||
"node_modules/smart-buffer": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 6.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
|
|
@ -1256,7 +1253,6 @@
|
|||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
|
||||
"integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ip": "^2.0.0",
|
||||
"smart-buffer": "^4.2.0"
|
||||
|
|
@ -1270,7 +1266,6 @@
|
|||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
||||
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"memory-pager": "^1.0.2"
|
||||
|
|
@ -1307,7 +1302,6 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
|
||||
"integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"punycode": "^2.1.1"
|
||||
},
|
||||
|
|
@ -1343,6 +1337,14 @@
|
|||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/validator": {
|
||||
"version": "13.11.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
|
||||
"integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
|
|
@ -1355,7 +1357,6 @@
|
|||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
|
|
@ -1364,7 +1365,6 @@
|
|||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
|
||||
"integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"tr46": "^3.0.0",
|
||||
"webidl-conversions": "^7.0.0"
|
||||
|
|
|
|||
|
|
@ -14,9 +14,8 @@
|
|||
"express": "^4.18.2",
|
||||
"express-async-handler": "^1.2.0",
|
||||
"http-errors": "~1.6.3",
|
||||
"morgan": "~1.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"morgan": "~1.9.1",
|
||||
"express-validator": "^7.0.1",
|
||||
"mongoose": "^7.5.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,15 +17,15 @@ router.get("/:category", category_controller.index);
|
|||
router.get("/:category/update", category_controller.category_update_get);
|
||||
router.post("/:category/update", category_controller.category_update_post);
|
||||
router.get("/:category/delete", category_controller.category_delete_get);
|
||||
router.post("/:category/delete", category_controller.category_delete_post);
|
||||
|
||||
// item functions
|
||||
router.get("/:category/:item", item_controller.index);
|
||||
// create URL has to go first before :matchers
|
||||
router.get("/:category/createitem", item_controller.item_create_get);
|
||||
router.post("/:category/createitem", item_controller.item_create_post);
|
||||
//
|
||||
router.get("/:category/:item", item_controller.index);
|
||||
router.get("/:category/:item/update", item_controller.item_update_get);
|
||||
router.post("/:category/:item/update", item_controller.item_update_post);
|
||||
router.get("/:category/:item/delete", item_controller.item_delete_get);
|
||||
router.post("/:category/:item/delete", item_controller.item_delete_post);
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,22 @@
|
|||
</a>
|
||||
<div class="pb-4"></div>
|
||||
<% }) %>
|
||||
<a
|
||||
href="/<%= category.simpleName %>/createitem"
|
||||
type="button"
|
||||
class="btn btn-success px-4"
|
||||
>
|
||||
+ Create new item
|
||||
</a>
|
||||
<div class="pb-4"></div>
|
||||
<a
|
||||
href="/<%= category.simpleName %>/delete"
|
||||
type="button"
|
||||
class="btn btn-danger px-4"
|
||||
>
|
||||
Delete this category
|
||||
</a>
|
||||
<div class="pb-5"></div>
|
||||
</div>
|
||||
<footer
|
||||
class="position-fixed bottom-0 border-light border-top w-100 py-2 d-flex justify-content-center bg-dark"
|
||||
|
|
|
|||
46
views/createcategory.ejs
Normal file
46
views/createcategory.ejs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Good Pickin's - New Category</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">Create Category</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"
|
||||
/>
|
||||
</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"
|
||||
/>
|
||||
</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>
|
||||
77
views/createitem.ejs
Normal file
77
views/createitem.ejs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Good Pickin's - <%= category.name %> - New Item</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">Create Item</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"
|
||||
/>
|
||||
</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"
|
||||
/>
|
||||
</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"
|
||||
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)"
|
||||
/>
|
||||
</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"
|
||||
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>
|
||||
|
|
@ -20,12 +20,8 @@
|
|||
</a>
|
||||
<div class="pb-4"></div>
|
||||
<% }) %>
|
||||
<a
|
||||
href="/createcategory"
|
||||
type="button"
|
||||
class="btn btn-outline-light px-4"
|
||||
>
|
||||
+
|
||||
<a href="/createcategory" type="button" class="btn btn-success px-4">
|
||||
+ Create new category
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<a
|
||||
href="/<%= category.simpleName %>/<%= item._id %>/delete"
|
||||
type="button"
|
||||
class="btn btn-outline-light px-4"
|
||||
class="btn btn-danger px-4"
|
||||
>
|
||||
Delete this item
|
||||
</a>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue