From f11741483e71a3065c87526e53d86bde9df0153a Mon Sep 17 00:00:00 2001 From: Angel Garcia Date: Mon, 30 Mar 2020 01:29:01 +0200 Subject: [PATCH 01/15] Added auth body validations --- server/validations/auth.js | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 server/validations/auth.js diff --git a/server/validations/auth.js b/server/validations/auth.js new file mode 100644 index 0000000..9101c28 --- /dev/null +++ b/server/validations/auth.js @@ -0,0 +1,37 @@ + +exports.loginValidation = (req) => { + const { email, password } = req.body; + + if (!email) { + return { error: 'You must enter an email address.' }; + } + + if (!password) { + return { error: 'You must enter a password.' }; + } + + return {} +}; + +exports.registerValidation = (req) => { + const { + email, + firstName, + lastName, + password + } = req.body; + + if (!email) { + return { error: 'You must enter an email address.' }; + } + + if (!firstName || !lastName) { + return { error: 'You must enter your full name.' }; + } + + if (!password) { + return {error: 'You must enter a password.'}; + } + + return {}; +}; \ No newline at end of file From 03a4ac635b16fcebdb8ec4e15ad61716ddc628da Mon Sep 17 00:00:00 2001 From: Angel Garcia Date: Mon, 30 Mar 2020 01:29:27 +0200 Subject: [PATCH 02/15] added auth controller --- server/controllers/auth.js | 58 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 server/controllers/auth.js diff --git a/server/controllers/auth.js b/server/controllers/auth.js new file mode 100644 index 0000000..dc82ac5 --- /dev/null +++ b/server/controllers/auth.js @@ -0,0 +1,58 @@ +const { login, register } = require("../services/auth"); +const { loginValidation, registerValidation } = require("../validations/auth"); +const mailgun = require('../config/mailgun'); +const template = require('../config/template'); + +exports.doRegister = async (req, res) => { + try{ + const { error } = registerValidation(req); + if (error) return res.status(422).json(error); + const { + email, + password, + firstName, + lastName, + } = req.body; + + const { user, token } = await register(email, password, { firstName, lastName }); + + const message = template.signupEmail(user.profile); + mailgun.sendEmail(user.email, message); + + res.status(200).json({ + success: true, + token: `Bearer ${token}`, + user, + }); + } catch (e) { + res.status(400).json({ + error: "Something went wrong" + }); + } +}; + +exports.doLogin = async (req, res) => { + try { + const { error } = loginValidation(req); + if (error) return res.status(422).json(error); + + const { + email, + password, + } = req.body; + + const { user, token, error: passwordError } = await login(email, password); + + if (passwordError) return res.status(404).json({ success: false, error: passwordError}); + + res.status(200).json({ + success: true, + token: `Bearer ${token}`, + user: user, + }); + } catch (e) { + res.status(400).json({ + error: e.toString() + }); + } +}; From 399e5d9f3099217eb6c54020c95402a8576fe2f9 Mon Sep 17 00:00:00 2001 From: Angel Garcia Date: Mon, 30 Mar 2020 01:29:59 +0200 Subject: [PATCH 03/15] added auth service --- server/services/auth.js | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 server/services/auth.js diff --git a/server/services/auth.js b/server/services/auth.js new file mode 100644 index 0000000..6dd95b1 --- /dev/null +++ b/server/services/auth.js @@ -0,0 +1,42 @@ +const bcrypt = require('bcryptjs'); +const jwt = require('jsonwebtoken'); + +const User = require('../models/user'); +const key = process.env.SECRET_OR_KEY; + +const createResult = (user) => { + const { id, profile, email, role } = user; + return { id, profile, email, role }; +}; + +const loginError = () => ({ error: "Password incorrect" }); + +exports.register = async (email, password, profile) => { + const user = new User({ + email, + password, + profile + }); + + const salt = await bcrypt.genSalt(10); + const hash = await bcrypt.hash(password, salt); + user.password = hash; + await user.save(); + + const payload = { id: user.id }; + const token = await jwt.sign(payload, key, { expiresIn: 3600 }); + + return { user: createResult(user), token }; +}; + +exports.login = async (email, password) => { + const user = await User.findOne({ email }); + + const matched = await bcrypt.compare(password, user.password); + if (matched) { + const payload = { id: user.id }; + const token = jwt.sign(payload, key, { expiresIn: 3600 }); + return { user: createResult(user), token }; + } + return loginError(); +}; From f83ebc88ce550e085e25c6724695af0216a6cc43 Mon Sep 17 00:00:00 2001 From: Angel Garcia Date: Mon, 30 Mar 2020 01:30:29 +0200 Subject: [PATCH 04/15] Added city controller --- server/controllers/cities.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 server/controllers/cities.js diff --git a/server/controllers/cities.js b/server/controllers/cities.js new file mode 100644 index 0000000..0b3df8e --- /dev/null +++ b/server/controllers/cities.js @@ -0,0 +1,21 @@ +const { createCity, updateCity } = require("../services/cities"); +const { updateCity } = require("../services/users"); + +exports.postCity = async (req, res) => { + try { + const { + name, + description + } = req.body; + const { _id: userId } = req.user; + + const city = await createCity(userId, name, description); + const updatedUser = await updateCity(userId, city._id); + + res.status(200).json({ city, user: updatedUser }); + } catch (e) { + res.status(400).json({ + error: "Something went wrong" + }) + } +}; \ No newline at end of file From 727048a7b084fe5b5e586b7d6c11d0aaa939f2c1 Mon Sep 17 00:00:00 2001 From: Angel Garcia Date: Mon, 30 Mar 2020 01:30:56 +0200 Subject: [PATCH 05/15] Added commerce controller --- server/controllers/commerces.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 server/controllers/commerces.js diff --git a/server/controllers/commerces.js b/server/controllers/commerces.js new file mode 100644 index 0000000..72db80f --- /dev/null +++ b/server/controllers/commerces.js @@ -0,0 +1,23 @@ + +const { createCommerce } = require("../services/commerces"); +const { generateDefaultCards } = require("../services/gift-cards"); + +exports.postCommerce = async (req, res) => { + try { + // TODO: validate body + const { + name, + description, + images, + cityId + } = req.body; + const commerce = await createCommerce({ name, description, images }, req.user.id, cityId); + const cards = await generateDefaultCards(commerce.id); + + res.status(200).json({ commerce, cards }); + } catch (e) { + res.status(400).json({ + error: "Something went wrong" + }); + } +} \ No newline at end of file From ee89b223df7e81dcb258b3f4a006aa2902863636 Mon Sep 17 00:00:00 2001 From: Angel Garcia Date: Mon, 30 Mar 2020 01:31:22 +0200 Subject: [PATCH 06/15] Fixed models --- server/models/{category.js => city.js} | 31 ++++++++-------- server/models/{brand.js => commerce.js} | 21 ++++++----- server/models/gift-card.js | 38 ++++++++++++++++++++ server/models/product.js | 48 ------------------------- server/models/user.js | 4 +++ 5 files changed, 69 insertions(+), 73 deletions(-) rename server/models/{category.js => city.js} (60%) rename server/models/{brand.js => commerce.js} (62%) create mode 100644 server/models/gift-card.js delete mode 100644 server/models/product.js diff --git a/server/models/category.js b/server/models/city.js similarity index 60% rename from server/models/category.js rename to server/models/city.js index fa0c585..2d73f01 100644 --- a/server/models/category.js +++ b/server/models/city.js @@ -11,7 +11,7 @@ const options = { Mongoose.plugin(slug, options); // Category Schema -const CategorySchema = new Schema({ +const CitySchema = new Schema({ _id: { type: Schema.ObjectId, auto: true @@ -21,25 +21,24 @@ const CategorySchema = new Schema({ trim: true }, slug: { type: String, slug: 'name', unique: true }, - image: { - data: Buffer, - contentType: String - }, description: { type: String, trim: true }, - products: [ - { - type: Schema.Types.ObjectId, - ref: 'Product' - } - ], - updated: Date, - created: { - type: Date, - default: Date.now + deleted: { + type: Boolean, + default: false, + }, + admin: { + type: Schema.Types.ObjectId, + ref: "User", + required: true, + } +}, { + timestamps: { + createdAt: "created", + updatedAt: "updated", } }); -module.exports = Mongoose.model('Category', CategorySchema); +module.exports = Mongoose.model('City', CitySchema); diff --git a/server/models/brand.js b/server/models/commerce.js similarity index 62% rename from server/models/brand.js rename to server/models/commerce.js index 18e269b..1d3a1b8 100644 --- a/server/models/brand.js +++ b/server/models/commerce.js @@ -10,26 +10,29 @@ const options = { Mongoose.plugin(slug, options); -// Brand Schema -const BrandSchema = new Schema({ +const CommerceSchema = new Schema({ name: { type: String, trim: true }, slug: { type: String, slug: 'name', unique: true }, - image: { + images: [{ data: Buffer, contentType: String - }, + }], description: { type: String, trim: true }, - updated: Date, - created: { - type: Date, - default: Date.now + city: { + type: Schema.Types.ObjectId, + ref: "City" + } +}, { + timestamps: { + createdAt: "created", + updatedAt: "updated", } }); -module.exports = Mongoose.model('Brand', BrandSchema); +module.exports = Mongoose.model('Commerce', CommerceSchema); diff --git a/server/models/gift-card.js b/server/models/gift-card.js new file mode 100644 index 0000000..8596805 --- /dev/null +++ b/server/models/gift-card.js @@ -0,0 +1,38 @@ +const Mongoose = require('mongoose'); +const slug = require('mongoose-slug-generator'); +const { Schema } = Mongoose; + +const options = { + separator: '-', + lang: 'en', + truncate: 120 +}; + +Mongoose.plugin(slug, options); + +const GiftCardSchema = new Schema({ + description: { + type: String, + trim: true + }, + quantity: { + type: Number, + required: true, + }, + price: { + type: Number + }, + commerce: { + type: Schema.Types.ObjectId, + ref: 'Commerce' + }, + used: { + type: Boolean, + }, + user: { + type: Schema.Types.ObjectId, + ref: "User" + } +}); + +module.exports = Mongoose.model('GiftCard', GiftCardSchema); diff --git a/server/models/product.js b/server/models/product.js deleted file mode 100644 index a9a8677..0000000 --- a/server/models/product.js +++ /dev/null @@ -1,48 +0,0 @@ -const Mongoose = require('mongoose'); -const slug = require('mongoose-slug-generator'); -const { Schema } = Mongoose; - -const options = { - separator: '-', - lang: 'en', - truncate: 120 -}; - -Mongoose.plugin(slug, options); - -// Product Schema -const ProductSchema = new Schema({ - sku: { - type: String - }, - name: { - type: String, - trim: true - }, - slug: { type: String, slug: 'name', unique: true }, - image: { - data: Buffer, - contentType: String - }, - description: { - type: String, - trim: true - }, - quantity: { - type: Number - }, - price: { - type: Number - }, - brand: { - type: Schema.Types.ObjectId, - ref: 'Brand' - }, - updated: Date, - created: { - type: Date, - default: Date.now - } -}); - -module.exports = Mongoose.model('Product', ProductSchema); diff --git a/server/models/user.js b/server/models/user.js index 5b1974b..357f951 100644 --- a/server/models/user.js +++ b/server/models/user.js @@ -22,6 +22,10 @@ const UserSchema = new Schema({ enum: ['ROLE_MEMBER', 'ROLE_ADMIN', 'ROLE_COLLABORATOR'], default: 'ROLE_ADMIN' }, + city: { + type: Schema.Types.ObjectId, + ref: "City" + }, resetPasswordToken: { type: String }, resetPasswordExpires: { type: Date } }); From f35a583d592f5007bb93df46bd41070e0bb6e186 Mon Sep 17 00:00:00 2001 From: Angel Garcia Date: Mon, 30 Mar 2020 01:31:42 +0200 Subject: [PATCH 07/15] Added auth middleware --- server/routes/middlewares/auth.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 server/routes/middlewares/auth.js diff --git a/server/routes/middlewares/auth.js b/server/routes/middlewares/auth.js new file mode 100644 index 0000000..94ae6ce --- /dev/null +++ b/server/routes/middlewares/auth.js @@ -0,0 +1,5 @@ + +exports.isAdmin = (req, res, next) => { + if (req.user.role === "ROLE_ADMIN") next(req, res); + else res.status(404).json({ error: "Debes ser administrador"}); +}; \ No newline at end of file From c47e13132f7bd80d38e2b0fc43493bec4430cde0 Mon Sep 17 00:00:00 2001 From: Angel Garcia Date: Mon, 30 Mar 2020 01:32:06 +0200 Subject: [PATCH 08/15] Added routes --- server/routes/api/auth.js | 139 +------------------- server/routes/api/category.js | 2 +- server/routes/api/{brand.js => commerce.js} | 14 +- server/routes/api/index.js | 2 +- server/routes/api/product.js | 6 +- 5 files changed, 17 insertions(+), 146 deletions(-) rename server/routes/api/{brand.js => commerce.js} (80%) diff --git a/server/routes/api/auth.js b/server/routes/api/auth.js index 1b3cac7..1f14a7b 100644 --- a/server/routes/api/auth.js +++ b/server/routes/api/auth.js @@ -1,142 +1,9 @@ const express = require('express'); const router = express.Router(); -const bcrypt = require('bcryptjs'); -const jwt = require('jsonwebtoken'); -const crypto = require('crypto'); -// Bring in Models & Helpers -const User = require('../../models/user'); -const mailgun = require('../../config/mailgun'); -const template = require('../../config/template'); - -const key = process.env.SECRET_OR_KEY; - -router.post('/login', (req, res) => { - const email = req.body.email; - const password = req.body.password; - - if (!email) { - return res.status(422).json({ error: 'You must enter an email address.' }); - } - - if (!password) { - return res.status(422).json({ error: 'You must enter a password.' }); - } - - User.findOne({ email }).then(user => { - if (!user) { - return res - .status(422) - .send({ error: 'no user found for this email address.' }); - } - bcrypt.compare(password, user.password).then(isMatch => { - if (isMatch) { - const payload = { id: user.id }; - jwt.sign(payload, key, { expiresIn: 3600 }, (err, token) => { - res.status(200).json({ - success: true, - token: `Bearer ${token}`, - user: { - id: user.id, - profile: { - firstName: user.profile.firstName, - lastName: user.profile.lastName, - is_subscribed: user.profile.is_subscribed - }, - email: user.email, - role: user.role - } - }); - }); - } else { - return res.status(404).json({ - success: false, - error: 'Password Incorrect' - }); - } - }); - }); -}); - -router.post('/register', (req, res, next) => { - const email = req.body.email; - const firstName = req.body.firstName; - const lastName = req.body.lastName; - const password = req.body.password; - const is_subscribed = req.body.isSubscribed; - - if (!email) { - return res.status(422).json({ error: 'You must enter an email address.' }); - } - - if (!firstName || !lastName) { - return res.status(422).json({ error: 'You must enter your full name.' }); - } - - if (!password) { - return res.status(422).json({ error: 'You must enter a password.' }); - } - - User.findOne({ email }, (err, existingUser) => { - if (err) { - return next(err); - } - - if (existingUser) { - return res - .status(422) - .json({ error: 'That email address is already in use.' }); - } - - const user = new User({ - email, - password, - profile: { firstName, lastName, is_subscribed } - }); - - bcrypt.genSalt(10, (err, salt) => { - bcrypt.hash(user.password, salt, (err, hash) => { - if (err) { - return res.status(422).json({ - error: 'Your request could not be processed. Please try again.' - }); - } - user.password = hash; - - user.save((err, user) => { - if (err) { - return res.status(422).json({ - error: 'Your request could not be processed. Please try again.' - }); - } - - const payload = { id: user.id }; - - jwt.sign(payload, key, { expiresIn: 3600 }, (err, token) => { - res.status(200).json({ - success: true, - token: `Bearer ${token}`, - user: { - id: user.id, - profile: { - firstName: user.profile.firstName, - lastName: user.profile.lastName, - is_subscribed: user.profile.is_subscribed - }, - email: user.email, - role: user.role - } - }); - }); - - const message = template.signupEmail(user.profile); - - mailgun.sendEmail(user.email, message); - }); - }); - }); - }); -}); +const { doLogin, doRegister } = require("../../controllers/auth"); +router.post('/login', doLogin); +router.post('/register', doRegister); module.exports = router; diff --git a/server/routes/api/category.js b/server/routes/api/category.js index 0f65daf..8b3361c 100644 --- a/server/routes/api/category.js +++ b/server/routes/api/category.js @@ -3,7 +3,7 @@ const router = express.Router(); const passport = require('passport'); // Bring in Models & Helpers -const Category = require('../../models/category'); +const Category = require('../../models/city'); router.post( '/add', diff --git a/server/routes/api/brand.js b/server/routes/api/commerce.js similarity index 80% rename from server/routes/api/brand.js rename to server/routes/api/commerce.js index bf737fc..7d49aae 100644 --- a/server/routes/api/brand.js +++ b/server/routes/api/commerce.js @@ -3,7 +3,11 @@ const router = express.Router(); const passport = require('passport'); // Bring in Models & Helpers -const Brand = require('../../models/brand'); +const Commerce = require('../../models/commerce'); +const { isAdmin } = require("../middlewares/auth"); +const { postCommerce } = require("../../controllers/commerces"); + +router.post("/", passport.authenticate('jwt', { session: false }), isAdmin, postCommerce); router.post( '/add', @@ -18,7 +22,7 @@ router.post( .json({ error: 'You must enter description & name.' }); } - const brand = new Brand({ + const brand = new Commerce({ name, description }); @@ -41,7 +45,7 @@ router.post( // fetch all brands api router.get('/list', (req, res) => { - Brand.find({}, (err, data) => { + Commerce.find({}, (err, data) => { if (err) { return res.status(422).json({ error: 'Your request could not be processed. Please try again.' @@ -57,7 +61,7 @@ router.get( '/list/select', passport.authenticate('jwt', { session: false }), (req, res) => { - Brand.find({}, 'name', (err, data) => { + Commerce.find({}, 'name', (err, data) => { if (err) { return res.status(422).json({ error: 'Your request could not be processed. Please try again.' @@ -75,7 +79,7 @@ router.delete( '/delete/:id', passport.authenticate('jwt', { session: false }), (req, res) => { - Brand.deleteOne({ _id: req.params.id }, (err, data) => { + Commerce.deleteOne({ _id: req.params.id }, (err, data) => { if (err) { return res.status(422).json({ error: 'Your request could not be processed. Please try again.' diff --git a/server/routes/api/index.js b/server/routes/api/index.js index d4ee58e..1c7357f 100644 --- a/server/routes/api/index.js +++ b/server/routes/api/index.js @@ -4,7 +4,7 @@ const userRoutes = require('./user'); const newsletterRoutes = require('./newsletter'); const productRoutes = require('./product'); const categoryRoutes = require('./category'); -const brandRoutes = require('./brand'); +const brandRoutes = require('./commerce'); const contactRoutes = require('./contact'); // auth routes diff --git a/server/routes/api/product.js b/server/routes/api/product.js index 5365f85..2ef82db 100644 --- a/server/routes/api/product.js +++ b/server/routes/api/product.js @@ -3,9 +3,9 @@ const router = express.Router(); const passport = require('passport'); // Bring in Models & Helpers -const Product = require('../../models/product'); -const Brand = require('../../models/brand'); -const Category = require('../../models/category'); +const Product = require('../../models/gift-card'); +const Brand = require('../../models/commerce'); +const Category = require('../../models/city'); router.post( '/add', From 2adee9e08ff1ba728829441f6ddbe7435e4f932a Mon Sep 17 00:00:00 2001 From: Angel Garcia Date: Mon, 30 Mar 2020 01:32:40 +0200 Subject: [PATCH 09/15] Added services layer --- server/services/cities.js | 49 +++++++++++++++++++++++++++++++++++ server/services/commerces.js | 5 ++++ server/services/gift-cards.js | 5 ++++ server/services/users.js | 13 ++++++++++ 4 files changed, 72 insertions(+) create mode 100644 server/services/cities.js create mode 100644 server/services/commerces.js create mode 100644 server/services/gift-cards.js create mode 100644 server/services/users.js diff --git a/server/services/cities.js b/server/services/cities.js new file mode 100644 index 0000000..2ef87da --- /dev/null +++ b/server/services/cities.js @@ -0,0 +1,49 @@ +const City = require('../models/city.js'); + +const createResult = (city) => { + if (!city) return {}; + const { _id, name, description, created } = city; + return { _id, name, description, created }; +}; + +exports.createCity = async (userId, name, description) => { + const city = new City({ + name, + description, + admin: userId, + }); + await city.save(); + return createResult(city); +}; + +exports.updateCity = async (cityId, name, description) => { + const updatedCity = await City.updateOne({ _id: cityId }, { + $set: { name, description }, + }); + await updatedCity.save(); + return createResult(updatedCity); +}; + +exports.deleteCity = async (cityId) => { + const deletedCity = await City.updateOne({ _id: cityId}, { + $set: { deleted: true }, + }); + await deletedCity.save(); + return true; +}; + +exports.getCityByName = async (name) => { + const city = await City.findOne({ name }); + return createResult(city); +}; + +exports.getCityById = async (cityId) => { + const city = await City.findOne({ _id: cityId}); + return createResult(city); +}; + +exports.getAllCities = async () => { + const cities = await City.find({ deleted: false }); + return cities ? cities.map(createResult) : [] + +}; diff --git a/server/services/commerces.js b/server/services/commerces.js new file mode 100644 index 0000000..c28a7fc --- /dev/null +++ b/server/services/commerces.js @@ -0,0 +1,5 @@ + +exports.createCommerce = async (commerceInfo, userId, cityId) => { + // TODO: create commerce + return {} +} \ No newline at end of file diff --git a/server/services/gift-cards.js b/server/services/gift-cards.js new file mode 100644 index 0000000..28f0c57 --- /dev/null +++ b/server/services/gift-cards.js @@ -0,0 +1,5 @@ + +exports.generateDefaultCards = async (commerceId) => { + // TODO: generate default gift cards + return [] +} \ No newline at end of file diff --git a/server/services/users.js b/server/services/users.js new file mode 100644 index 0000000..480d760 --- /dev/null +++ b/server/services/users.js @@ -0,0 +1,13 @@ +const User = require("../models/user"); + +const updateCity = async (userId, cityId) => { + const updatedUser = await User.updateOne({ _id: userId }, { + $set: { city: cityId } + }); + await updatedUser.save(); + return updatedUser; +}; + +exports = { + updateCity +}; \ No newline at end of file From 4365a32f924c7b093bb73c5b8105a30b0b5558c9 Mon Sep 17 00:00:00 2001 From: Angel Garcia Date: Mon, 30 Mar 2020 01:32:55 +0200 Subject: [PATCH 10/15] Changed page title --- .gitignore | 4 +++- client/public/index.html | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 266b8b8..ed2db8e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,6 @@ package-lock.json # debug npm-debug.log* yarn-debug.log* -yarn-error.log* \ No newline at end of file +yarn-error.log* + +.idea \ No newline at end of file diff --git a/client/public/index.html b/client/public/index.html index 1beac3c..1891643 100644 --- a/client/public/index.html +++ b/client/public/index.html @@ -5,7 +5,7 @@ - MERN Ecommerce Application + Por el comercion local From c481ff798d0e7a222860e0b5293fa721b693c4f7 Mon Sep 17 00:00:00 2001 From: "antonio.molner" Date: Mon, 30 Mar 2020 21:02:57 +0200 Subject: [PATCH 11/15] Finish ecommerce model with data validation --- package.json | 2 + server/models/commerce.js | 45 ++++++++++++-- yarn.lock | 127 ++++++-------------------------------- 3 files changed, 61 insertions(+), 113 deletions(-) diff --git a/package.json b/package.json index 8707ab0..8e48208 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ }, "homepage": "https://github.com/mohamedsamara/mern-ecommerce#readme", "dependencies": { + "awesome-phonenumber": "^2.29.0", "axios": "^0.19.0", "bcryptjs": "^2.4.3", "bootstrap": "^4.3.1", @@ -43,6 +44,7 @@ "express": "^4.17.1", "font-awesome": "^4.7.0", "history": "^4.9.0", + "iban": "^0.0.14", "jsonwebtoken": "^8.5.1", "mailchimp-v3": "^1.0.5", "mailgun-js": "^0.22.0", diff --git a/server/models/commerce.js b/server/models/commerce.js index 1d3a1b8..c5b14d5 100644 --- a/server/models/commerce.js +++ b/server/models/commerce.js @@ -1,5 +1,7 @@ const Mongoose = require('mongoose'); const slug = require('mongoose-slug-generator'); +const PhoneNumber = require('awesome-phonenumber'); +const IBAN = require('iban'); const { Schema } = Mongoose; const options = { @@ -13,7 +15,8 @@ Mongoose.plugin(slug, options); const CommerceSchema = new Schema({ name: { type: String, - trim: true + trim: true, + required: true, }, slug: { type: String, slug: 'name', unique: true }, images: [{ @@ -22,12 +25,46 @@ const CommerceSchema = new Schema({ }], description: { type: String, - trim: true + trim: true, + required: true, }, city: { type: Schema.Types.ObjectId, - ref: "City" - } + ref: "City", + required: true, + }, + phoneNumber: { + type: String, + trim: true, + validate: { + validator: phone => { + const parsedNumber = PhoneNumber(phone); + return parsedNumber.isMobile() || parsedNumber.isFixedLine(); + }, + message: props => `${props.value} is not a phone number!` + }, + }, + bizum: { + type: String, + trim: true, + validate: { + validator: phone => PhoneNumber(phone).isMobile(), + message: props => `${props.value} is not a phone number!` + }, + }, + bankAccount: { + type: String, + trim: true, + validate: { + validator: IBAN.isValid, + message: props => `${props.value} is not a valid IBAN!` + }, + }, + discount: { + type: Number, + min: 0, + max: 50, + }, }, { timestamps: { createdAt: "created", diff --git a/yarn.lock b/yarn.lock index 984edd8..42392e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1626,6 +1626,11 @@ autoprefixer@^9.6.0: postcss "^7.0.27" postcss-value-parser "^4.0.3" +awesome-phonenumber@^2.29.0: + version "2.29.0" + resolved "https://registry.yarnpkg.com/awesome-phonenumber/-/awesome-phonenumber-2.29.0.tgz#bda4c2bf303a095054d7933ac51956276d49bfba" + integrity sha512-SLa0WBpMkZHCupRWHWoFxl+VKSmqdQDcqwBc6B1A72yNr6rewspARsqvgsl+y1Ervw4cf2fW1x+YyeAbazXuYw== + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -3013,11 +3018,6 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - detect-node@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" @@ -3767,13 +3767,6 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" -fs-minipass@^1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" @@ -4335,7 +4328,12 @@ https-proxy-agent@^3.0.0: agent-base "^4.3.0" debug "^3.1.0" -iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: +iban@^0.0.14: + version "0.0.14" + resolved "https://registry.yarnpkg.com/iban/-/iban-0.0.14.tgz#fd8a65ac50c8b770682634b20dc5c5c9feba5c24" + integrity sha512-+rocNKk+Ga9m8Lr9fTMWd+87JnsBrucm0ZsIx5ROOarZlaDLmd+FKdbtvb0XyoBw9GAFOYG2GuLqoNB16d+p3w== + +iconv-lite@0.4.24, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -4369,13 +4367,6 @@ ignore-by-default@^1.0.1: resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= -ignore-walk@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== - dependencies: - minimatch "^3.0.4" - ignore@^3.3.5: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" @@ -5517,21 +5508,6 @@ minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" - mississippi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" @@ -5697,15 +5673,6 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -needle@^2.2.1: - version "2.3.3" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.3.tgz#a041ad1d04a871b0ebb666f40baaf1fb47867117" - integrity sha512-EkY0GeSq87rWp1hoq/sH/wnTWgFVhYlnIkbJ0YJFfRgEFlz2RraCjBpFQ+vrEgEdp0ThfyHADmkChEhcb7PKyw== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -5793,22 +5760,6 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-pre-gyp@*: - version "0.14.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" - integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4.4.2" - node-releases@^1.1.52: version "1.1.53" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.53.tgz#2d821bfa499ed7c5dffc5e2f28c88e78a08ee3f4" @@ -5860,14 +5811,6 @@ nodemon@^1.19.1: dependencies: abbrev "1" -nopt@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" - integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== - dependencies: - abbrev "1" - osenv "^0.1.4" - nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -5917,27 +5860,6 @@ normalize-url@^3.0.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== -npm-bundled@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" - integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== - dependencies: - npm-normalize-package-bin "^1.0.1" - -npm-normalize-package-bin@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" - integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== - -npm-packlist@^1.1.6: - version "1.4.8" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" - integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - npm-normalize-package-bin "^1.0.1" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -5945,7 +5867,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -6142,7 +6064,7 @@ os-tmpdir@^1.0.0: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@0, osenv@^0.1.4: +osenv@0: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== @@ -7117,7 +7039,7 @@ raw-body@^2.2.0: iconv-lite "0.4.24" unpipe "1.0.0" -rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: +rc@^1.0.1, rc@^1.1.6: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -7651,7 +7573,7 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= -rimraf@2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: +rimraf@2, rimraf@^2.5.4, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -7723,7 +7645,7 @@ sass-loader@^7.1.0: pify "^4.0.1" semver "^6.3.0" -sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4: +sax@>=0.6.0, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -7780,7 +7702,7 @@ semver-diff@^2.0.0: dependencies: semver "^5.0.3" -"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -8426,19 +8348,6 @@ tar@^2.0.0: fstream "^1.0.12" inherits "2" -tar@^4.4.2: - version "4.4.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" - integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" - term-size@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" @@ -9275,7 +9184,7 @@ yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: +yallist@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== From 83084c08dcdce58e543d29fbe74301af4a3bc516 Mon Sep 17 00:00:00 2001 From: "antonio.molner" Date: Mon, 30 Mar 2020 21:14:45 +0200 Subject: [PATCH 12/15] Add Transaction model --- package.json | 1 + server/models/commerce.js | 3 ++ server/models/transaction.js | 67 ++++++++++++++++++++++++++++++++++++ yarn.lock | 5 +++ 4 files changed, 76 insertions(+) create mode 100644 server/models/transaction.js diff --git a/package.json b/package.json index 8e48208..4118965 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "cors": "^2.8.5", "crypto": "^1.0.1", "dotenv": "^8.0.0", + "email-validator": "^2.0.4", "express": "^4.17.1", "font-awesome": "^4.7.0", "history": "^4.9.0", diff --git a/server/models/commerce.js b/server/models/commerce.js index c5b14d5..e223354 100644 --- a/server/models/commerce.js +++ b/server/models/commerce.js @@ -36,6 +36,7 @@ const CommerceSchema = new Schema({ phoneNumber: { type: String, trim: true, + required: true, validate: { validator: phone => { const parsedNumber = PhoneNumber(phone); @@ -55,6 +56,7 @@ const CommerceSchema = new Schema({ bankAccount: { type: String, trim: true, + required: true, validate: { validator: IBAN.isValid, message: props => `${props.value} is not a valid IBAN!` @@ -64,6 +66,7 @@ const CommerceSchema = new Schema({ type: Number, min: 0, max: 50, + required: true, }, }, { timestamps: { diff --git a/server/models/transaction.js b/server/models/transaction.js new file mode 100644 index 0000000..ec8394a --- /dev/null +++ b/server/models/transaction.js @@ -0,0 +1,67 @@ +const Mongoose = require('mongoose'); +const slug = require('mongoose-slug-generator'); +const PhoneNumber = require('awesome-phonenumber'); +const EmailValidator = require("email-validator"); +const { Schema } = Mongoose; + +const options = { + separator: '-', + lang: 'en', + truncate: 120 +}; + +Mongoose.plugin(slug, options); + +const TransactionSchema = new Schema({ + client: { + firstName: { + type: String, + trim: true, + required: true, + }, + lastName: { + type: String, + trim: true, + required: true, + }, + email: { + type: String, + trim: true, + required: true, + validate: { + validator: email => EmailValidator.validate(email), + message: props => `${props.value} is not a valid email!` + }, + }, + phoneNumber: { + type: String, + trim: true, + required: true, + validate: { + validator: phone => PhoneNumber(phone).isMobile(), + message: props => `${props.value} is not a phone number!` + }, + } + }, + commerce: { + type: Schema.Types.ObjectId, + ref: "Commerce", + required: true, + }, + quantity: { + type: Number, + min: 1, + required: true, + }, + isConfirmed: { + type: Boolean, + default: false, + }, +}, { + timestamps: { + createdAt: "created", + updatedAt: "updated", + } +}); + +module.exports = Mongoose.model('Transaction', TransactionSchema); diff --git a/yarn.lock b/yarn.lock index 42392e8..b119e39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3204,6 +3204,11 @@ elliptic@^6.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" +email-validator@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/email-validator/-/email-validator-2.0.4.tgz#b8dfaa5d0dae28f1b03c95881d904d4e40bfe7ed" + integrity sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ== + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" From ee5f5f881e79e0c9eb6242a287c4785df9d28959 Mon Sep 17 00:00:00 2001 From: "antonio.molner" Date: Mon, 30 Mar 2020 21:19:12 +0200 Subject: [PATCH 13/15] Add MoneyCard model --- server/models/money-card.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 server/models/money-card.js diff --git a/server/models/money-card.js b/server/models/money-card.js new file mode 100644 index 0000000..ee7c56e --- /dev/null +++ b/server/models/money-card.js @@ -0,0 +1,31 @@ +const Mongoose = require('mongoose'); +const { Schema } = Mongoose; + +const MoneyCardSchema = new Schema({ + hash: { + type: String, + trim: true, + unique: true, + required: true, + }, + quantity: { + type: Number, + required: true, + min: 0, + }, + transaction: { + type: Schema.Types.ObjectId, + ref: 'Transaction', + required: true, + }, + isConsumed: { + type: Boolean, + default: false, + }, +},{ + timestamps: { + createdAt: "created", + } +}); + +module.exports = Mongoose.model('MoneyCard', MoneyCardSchema); From c524dce94a13effeaff930f7ca12846159d5c7c2 Mon Sep 17 00:00:00 2001 From: "antonio.molner" Date: Tue, 31 Mar 2020 00:16:16 +0200 Subject: [PATCH 14/15] Add ecommerce service --- server/models/commerce.js | 6 ++++ server/services/commerces.js | 56 +++++++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/server/models/commerce.js b/server/models/commerce.js index e223354..531920d 100644 --- a/server/models/commerce.js +++ b/server/models/commerce.js @@ -68,6 +68,10 @@ const CommerceSchema = new Schema({ max: 50, required: true, }, + deleted: { + type: Boolean, + default: false, + }, }, { timestamps: { createdAt: "created", @@ -75,4 +79,6 @@ const CommerceSchema = new Schema({ } }); +CommerceSchema.index({ name: 'text' }); + module.exports = Mongoose.model('Commerce', CommerceSchema); diff --git a/server/services/commerces.js b/server/services/commerces.js index c28a7fc..05c5cc2 100644 --- a/server/services/commerces.js +++ b/server/services/commerces.js @@ -1,5 +1,53 @@ +const Commerce = require('../models/commerce'); -exports.createCommerce = async (commerceInfo, userId, cityId) => { - // TODO: create commerce - return {} -} \ No newline at end of file +exports.createCommerce = async (name, description, phoneNumber, cityId, bizum, bankAccount, discount) => { + const commerce = new Commerce({ + name, + description, + city: cityId, + bizum, + bankAccount, + discount + }); + await commerce.save(); + return commerce +}; + +exports.updateCommerce = async (id, name, description, phoneNumber, cityId, bizum, bankAccount, discount) => { + const updated = await Commerce.updateOne({ _id: id }, { + $set: { + name, + description, + phoneNumber, + cityId, + bizum, + bankAccount, + discount + }, + }); + await updated.save(); + return updated +}; + +exports.deleteCommerce = async (id) => { + const deletedItem = await Commerce.updateOne({ _id: id}, { + $set: { deleted: true }, + }); + await deletedItem.save(); + return true; +}; + +exports.getCommerceById = async (id) => { + const item = await Commerce.findOne({ _id: id, deleted: false }); + return item || {}; +}; + +exports.getCommercesByName = async (textQuery) => { + const items = await Commerce.find({ $text: { $search: textQuery }, deleted: false }); + return items || []; +}; + +exports.getCommercesByCity = async (cityId) => { + const items = await Commerce.find({ city: cityId, deleted: false }); + return items || []; +}; From ca1cf18b4332a5ba315414055d333149314950f8 Mon Sep 17 00:00:00 2001 From: "antonio.molner" Date: Tue, 31 Mar 2020 01:11:31 +0200 Subject: [PATCH 15/15] Add services for the rest of the models --- server/models/city.js | 2 ++ server/models/gift-card.js | 28 +++++++++++++++---------- server/models/money-card.js | 31 ---------------------------- server/models/transaction.js | 4 ++++ server/services/cities.js | 7 +++---- server/services/commerces.js | 6 ++++++ server/services/gift-cards.js | 36 ++++++++++++++++++++++++++++++++- server/services/transactions.js | 36 +++++++++++++++++++++++++++++++++ 8 files changed, 103 insertions(+), 47 deletions(-) delete mode 100644 server/models/money-card.js create mode 100644 server/services/transactions.js diff --git a/server/models/city.js b/server/models/city.js index 2d73f01..49273ce 100644 --- a/server/models/city.js +++ b/server/models/city.js @@ -41,4 +41,6 @@ const CitySchema = new Schema({ } }); +CitySchema.index({ name: 'text' }); + module.exports = Mongoose.model('City', CitySchema); diff --git a/server/models/gift-card.js b/server/models/gift-card.js index 8596805..116a1c1 100644 --- a/server/models/gift-card.js +++ b/server/models/gift-card.js @@ -11,27 +11,33 @@ const options = { Mongoose.plugin(slug, options); const GiftCardSchema = new Schema({ - description: { + hash: { type: String, - trim: true + trim: true, + unique: true, + required: true, }, quantity: { type: Number, required: true, + min: 0, }, - price: { - type: Number - }, - commerce: { + transaction: { type: Schema.Types.ObjectId, - ref: 'Commerce' + ref: 'Transaction', + required: true, }, - used: { + isConsumed: { type: Boolean, + default: false, }, - user: { - type: Schema.Types.ObjectId, - ref: "User" + deleted: { + type: Boolean, + default: false, + }, +},{ + timestamps: { + createdAt: "created", } }); diff --git a/server/models/money-card.js b/server/models/money-card.js deleted file mode 100644 index ee7c56e..0000000 --- a/server/models/money-card.js +++ /dev/null @@ -1,31 +0,0 @@ -const Mongoose = require('mongoose'); -const { Schema } = Mongoose; - -const MoneyCardSchema = new Schema({ - hash: { - type: String, - trim: true, - unique: true, - required: true, - }, - quantity: { - type: Number, - required: true, - min: 0, - }, - transaction: { - type: Schema.Types.ObjectId, - ref: 'Transaction', - required: true, - }, - isConsumed: { - type: Boolean, - default: false, - }, -},{ - timestamps: { - createdAt: "created", - } -}); - -module.exports = Mongoose.model('MoneyCard', MoneyCardSchema); diff --git a/server/models/transaction.js b/server/models/transaction.js index ec8394a..7dad1c9 100644 --- a/server/models/transaction.js +++ b/server/models/transaction.js @@ -57,6 +57,10 @@ const TransactionSchema = new Schema({ type: Boolean, default: false, }, + deleted: { + type: Boolean, + default: false, + }, }, { timestamps: { createdAt: "created", diff --git a/server/services/cities.js b/server/services/cities.js index 2ef87da..2a318aa 100644 --- a/server/services/cities.js +++ b/server/services/cities.js @@ -32,9 +32,9 @@ exports.deleteCity = async (cityId) => { return true; }; -exports.getCityByName = async (name) => { - const city = await City.findOne({ name }); - return createResult(city); +exports.getCitiesByName = async (textQuery) => { + const cities = await City.find({ $text: { $search: textQuery }, deleted: false }); + return cities ? cities.map(createResult) : [] }; exports.getCityById = async (cityId) => { @@ -45,5 +45,4 @@ exports.getCityById = async (cityId) => { exports.getAllCities = async () => { const cities = await City.find({ deleted: false }); return cities ? cities.map(createResult) : [] - }; diff --git a/server/services/commerces.js b/server/services/commerces.js index 05c5cc2..c4a1a16 100644 --- a/server/services/commerces.js +++ b/server/services/commerces.js @@ -51,3 +51,9 @@ exports.getCommercesByCity = async (cityId) => { const items = await Commerce.find({ city: cityId, deleted: false }); return items || []; }; + +exports.getCommerces = async ({ query, select, cursor }) => { + const newQuery = { ...query, deleted: false }; + const items = await Commerce.find(newQuery, select, cursor); + return items || []; +}; diff --git a/server/services/gift-cards.js b/server/services/gift-cards.js index 28f0c57..96bc0d7 100644 --- a/server/services/gift-cards.js +++ b/server/services/gift-cards.js @@ -1,5 +1,39 @@ +const GiftCard = require('../models/gift-card'); exports.generateDefaultCards = async (commerceId) => { // TODO: generate default gift cards return [] -} \ No newline at end of file +}; + +exports.createGiftCard = async (quantity, transaction) => { + const item = new GiftCard({ + quantity, + transaction, + hash: '' // TODO: Generate hash + }); + await item.save(); + return item +}; + +exports.updateGiftCard = async (id, quantity, isConsumed) => { + // TODO: Hash validation + const updated = await GiftCard.updateOne({ _id: id }, { + $set: { quantity, isConsumed }, + }); + await updated.save(); + return updated +}; + +exports.deleteGiftCard = async (id) => { + const deletedItem = await GiftCard.updateOne({ _id: id}, { + $set: { deleted: true }, + }); + await deletedItem.save(); + return true; +}; + +exports.getGiftCards = async ({ query, select, cursor }) => { + const newQuery = { ...query, deleted: false }; + const items = await GiftCard.find(newQuery, select, cursor); + return items || []; +}; diff --git a/server/services/transactions.js b/server/services/transactions.js new file mode 100644 index 0000000..50c0d36 --- /dev/null +++ b/server/services/transactions.js @@ -0,0 +1,36 @@ +const Transaction = require('../models/commerce'); + +exports.createTransaction = async (name, description, phoneNumber, cityId, bizum, bankAccount, discount) => { + const transaction = new Transaction({ + name, + description, + city: cityId, + bizum, + bankAccount, + discount + }); + await transaction.save(); + return transaction +}; + +exports.updateTransaction = async (id, client, quantity, commerce, isConfirmed) => { + const updated = await Transaction.updateOne({ _id: id }, { + $set: { client, quantity, commerce, isConfirmed }, + }); + await updated.save(); + return updated +}; + +exports.deleteTransaction = async (id) => { + const deletedItem = await Transaction.updateOne({ _id: id}, { + $set: { deleted: true }, + }); + await deletedItem.save(); + return true; +}; + +exports.getTransactions = async ({ query, select, cursor }) => { + const newQuery = { ...query, deleted: false }; + const items = await Transaction.find(newQuery, select, cursor); + return items || []; +};