diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js index 395ca3a..747ac29 100644 --- a/config/webpack.config.dev.js +++ b/config/webpack.config.dev.js @@ -41,4 +41,4 @@ const webpackConfig = merge(commonConfig(true), { } }); -module.exports = webpackConfig; \ No newline at end of file +module.exports = webpackConfig; diff --git a/package.json b/package.json index 8c2841b..4b6fbb0 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "server.js", "repository": "git@github.com:kevinmidboe/planetposen.git", "scripts": { - "dev": "cross-env NODE_ENV=development webpack-dev-server --progress" + "dev": "cross-env NODE_ENV=development webpack-dev-server --progress", + "server": "NODE_PATH=server node server/app.js" }, "author": "KevinMidboe ", "license": "MIT", @@ -14,6 +15,7 @@ "clean-webpack-plugin": "^3.0.0", "extract-text-webpack-plugin": "^3.0.2", "moment": "^2.24.0", + "mongoose": "^5.9.24", "node-fetch": "^2.6.0", "node-sass": "^4.13.0", "vue": "~2.6", diff --git a/server/app.js b/server/app.js new file mode 100644 index 0000000..06798d4 --- /dev/null +++ b/server/app.js @@ -0,0 +1,29 @@ +const express = require('express'); +const app = express(); +const router = express.Router(); +const server = require('http').Server(app); +const path = require('path'); + +const mongoose = require('mongoose'); +// const MongoStore = require('connect-mongo'); +mongoose.promise = global.Promise; +mongoose.connect('mongodb://localhost/planetposen'); +mongoose.set('debug', true); + +const PORT = 30010; + +const productsController = require('./controllers/product.js'); +const variationsController = require('./controllers/variation.js'); + +app.use(express.json()); +// app.use(express.urlencoded()); + +router.get('/products', productsController.allProducts) +router.get('/product/:id', productsController.productById) +router.post('/product', productsController.addNewProduct) + +router.post('/variation/:id', variationsController.addNewVariationToProduct); +app.use('/api', router); + +console.log(`Planetposen backend running on port: ${PORT}`) +server.listen(PORT); diff --git a/server/controllers/product.js b/server/controllers/product.js new file mode 100644 index 0000000..4012fc2 --- /dev/null +++ b/server/controllers/product.js @@ -0,0 +1,53 @@ +const Products = require('src/products.js') +const products = new Products(); + +// HELPERS +const handleError = (error, res) => { + const { message, status, success } = error; + + return res.status(status || 500).send({ + success: success || false, + message: message || 'Unable to find product.' + }) +} + +const handleReturnProduct = (product, res) => { + return res.send({ + success: true, + product + }) +} + +// ROUTES +const allProducts = (req, res) => { + return products.allProducts() + .then(products => res.json(products)) +} + +const productById = (req, res) => { + const { id } = req.params; + + if (id != null) { + return products.getById(id) + .then(product => handleReturnProduct(product, res)) + .catch(err => handleError(err, res)) + } else { + return res.status(422).send({ + success: true, + message: 'Id must be number. Invalid request.' + }) + } +} + +const addNewProduct = (req, res) => { + const { product } = req.body; + + return products.saveNewProduct(product) + .then(resp => res.send(resp)) +} + +module.exports = { + allProducts, + productById, + addNewProduct +}; diff --git a/server/controllers/variation.js b/server/controllers/variation.js new file mode 100644 index 0000000..66013bc --- /dev/null +++ b/server/controllers/variation.js @@ -0,0 +1,40 @@ +const { saveNewVariation } = require('src/variation.js') +const Products = require('src/products'); +const products = new Products(); + +// HELPERS +const handleError = (error, res) => { + const { message, status, success } = error; + + return res.status(status || 500).send({ + success: success || false, + message: message || 'Unable to find product.' + }) +} + +const handleReturnProduct = (product, res) => { + return res.send({ + success: true, + product + }) +} + +// ROUTES +const addNewVariationToProduct = async (req, res) => { + const productId = req.params.id; + const { variation } = req.body; + + console.log('id: ', productId); + console.log('variation: ', variation); + + const newVariation = await saveNewVariation(variation); + + return saveNewVariation(variation) + .then(newVariation => products.addVariationToProduct(newVariation, productId)) + .then(() => res.send('New relation added to product')) + .catch(err => handleError(err, res)) +} + +module.exports = { + addNewVariationToProduct +}; diff --git a/server/schemas/Product.js b/server/schemas/Product.js new file mode 100644 index 0000000..9ad158e --- /dev/null +++ b/server/schemas/Product.js @@ -0,0 +1,15 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; + +const Product = new Schema({ + name: String, + image: String, + description: String, + urlSlug: String, + variations: [{ + type: Schema.Types.ObjectId, + ref: "Variation" + }] + }); + +module.exports = mongoose.model("Product", Product) diff --git a/server/schemas/Variation.js b/server/schemas/Variation.js new file mode 100644 index 0000000..a5cae40 --- /dev/null +++ b/server/schemas/Variation.js @@ -0,0 +1,12 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; + +const Variation = new Schema({ + size: String, + description: String, + stock: Number, + price: Number, + discount: Number +}); + +module.exports = mongoose.model("Variation", Variation); diff --git a/server/src/products.js b/server/src/products.js new file mode 100644 index 0000000..57da21c --- /dev/null +++ b/server/src/products.js @@ -0,0 +1,37 @@ +const Product = require('schemas/Product'); +const { slugify } = require('src/utils'); + +class Products { + constructor() { + } + + async addVariationToProduct(variation, id) { + return Product.findById(id) + .then(product => { + product.variations.push(variation); + return product.save(); + }) + } + + async saveNewProduct(product) { + + const newProduct = new Product({ + name: product.name, + description: product.description, + urlSlug: slugify(product.name), + image: product.image + }) + + return newProduct.save(); + } + + allProducts() { + return Product.find().populate('variations'); + } + + getById(id) { + return Product.findById(id).populate('variations'); + } +} + +module.exports = Products; diff --git a/server/src/utils.js b/server/src/utils.js new file mode 100644 index 0000000..c26da73 --- /dev/null +++ b/server/src/utils.js @@ -0,0 +1,19 @@ + +const slugify = (string) => { + const a = 'àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìłḿñńǹňôöòóœøōõőṕŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż·/_,:;' + const b = 'aaaaaaaaaacccddeeeeeeeegghiiiiiilmnnnnoooooooooprrsssssttuuuuuuuuuwxyyzzz------' + const p = new RegExp(a.split('').join('|'), 'g') + + return string.toString().toLowerCase() + .replace(/\s+/g, '-') // Replace spaces with - + .replace(p, c => b.charAt(a.indexOf(c))) // Replace special characters + .replace(/&/g, '-and-') // Replace & with 'and' + .replace(/[^\w\-]+/g, '') // Remove all non-word characters + .replace(/\-\-+/g, '-') // Replace multiple - with single - + .replace(/^-+/, '') // Trim - from start of text + .replace(/-+$/, '') // Trim - from end of text +} + +module.exports = { + slugify +} diff --git a/server/src/variation.js b/server/src/variation.js new file mode 100644 index 0000000..c8e095d --- /dev/null +++ b/server/src/variation.js @@ -0,0 +1,22 @@ +const Variation = require('schemas/Variation'); + +const updateVariation = () => { + return +} + +const saveNewVariation = async (variation) => { + const newVariation = new Variation({ + size: variation.size, + description: variation.description, + stock: variation.stock || 0, + price: variation.price, + discount: null + }) + + await newVariation.save(); + return newVariation; +} + +module.exports = { + saveNewVariation +}