From eeca05117a236ffd3d55160388dd99967dba2dd8 Mon Sep 17 00:00:00 2001 From: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> Date: Tue, 25 Aug 2020 09:51:30 +0200 Subject: [PATCH] Adds ip lookup middleware for cart creation --- packages/medusa-plugin-ip-lookup/.babelrc | 13 +++++++ packages/medusa-plugin-ip-lookup/.gitignore | 14 ++++++++ packages/medusa-plugin-ip-lookup/.prettierrc | 7 ++++ packages/medusa-plugin-ip-lookup/package.json | 36 +++++++++++++++++++ .../src/api/medusa-middleware.js | 36 +++++++++++++++++++ .../src/services/ip-lookup.js | 18 ++++++++++ .../src/api/routes/store/carts/index.js | 11 ++++-- packages/medusa/src/api/routes/store/index.js | 2 +- packages/medusa/src/loaders/plugins.js | 4 +++ packages/medusa/src/services/middleware.js | 16 +++++++++ packages/medusa/yarn.lock | 20 ----------- 11 files changed, 154 insertions(+), 23 deletions(-) create mode 100644 packages/medusa-plugin-ip-lookup/.babelrc create mode 100644 packages/medusa-plugin-ip-lookup/.gitignore create mode 100644 packages/medusa-plugin-ip-lookup/.prettierrc create mode 100644 packages/medusa-plugin-ip-lookup/package.json create mode 100644 packages/medusa-plugin-ip-lookup/src/api/medusa-middleware.js create mode 100644 packages/medusa-plugin-ip-lookup/src/services/ip-lookup.js diff --git a/packages/medusa-plugin-ip-lookup/.babelrc b/packages/medusa-plugin-ip-lookup/.babelrc new file mode 100644 index 0000000000..1947586437 --- /dev/null +++ b/packages/medusa-plugin-ip-lookup/.babelrc @@ -0,0 +1,13 @@ +{ + "plugins": [ + "@babel/plugin-proposal-class-properties", + "@babel/plugin-transform-classes", + "@babel/plugin-transform-instanceof" + ], + "presets": ["@babel/preset-env"], + "env": { + "test": { + "plugins": ["@babel/plugin-transform-runtime"] + } + } +} \ No newline at end of file diff --git a/packages/medusa-plugin-ip-lookup/.gitignore b/packages/medusa-plugin-ip-lookup/.gitignore new file mode 100644 index 0000000000..2653074ca0 --- /dev/null +++ b/packages/medusa-plugin-ip-lookup/.gitignore @@ -0,0 +1,14 @@ +dist/ +node_modules/ +.DS_store +.env* +/*.js +!index.js +yarn.lock +yarn-error.log + +/api +/services +/models +/subscribers + diff --git a/packages/medusa-plugin-ip-lookup/.prettierrc b/packages/medusa-plugin-ip-lookup/.prettierrc new file mode 100644 index 0000000000..70175ce150 --- /dev/null +++ b/packages/medusa-plugin-ip-lookup/.prettierrc @@ -0,0 +1,7 @@ +{ + "endOfLine": "lf", + "semi": false, + "singleQuote": false, + "tabWidth": 2, + "trailingComma": "es5" +} \ No newline at end of file diff --git a/packages/medusa-plugin-ip-lookup/package.json b/packages/medusa-plugin-ip-lookup/package.json new file mode 100644 index 0000000000..f25ade2293 --- /dev/null +++ b/packages/medusa-plugin-ip-lookup/package.json @@ -0,0 +1,36 @@ +{ + "name": "medusa-plugin-ip-lookup", + "version": "1.0.0-alpha.3", + "description": "IP lookup middleware for Medusa core", + "main": "dist/index.js", + "repository": { + "type": "git", + "url": "https://github.com/medusajs/medusa", + "directory": "packages/medusa-plugin-ip-lookup" + }, + "scripts": { + "build": "babel src --out-dir . --ignore **/__tests__", + "prepare": "cross-env NODE_ENV=production npm run build", + "watch": "babel -w src --out-dir . --ignore **/__tests__", + "test": "jest" + }, + "author": "Oliver Juhl", + "license": "AGPL-3.0-or-later", + "devDependencies": { + "@babel/cli": "^7.7.5", + "@babel/core": "^7.7.5", + "@babel/plugin-proposal-class-properties": "^7.7.4", + "@babel/plugin-transform-classes": "^7.9.5", + "@babel/plugin-transform-instanceof": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.7.6", + "@babel/preset-env": "^7.7.5", + "@babel/runtime": "^7.7.6", + "cross-env": "^5.2.1", + "jest": "^25.5.2" + }, + "dependencies": { + "axios": "^0.20.0", + "mongoose": "^5.8.0" + }, + "gitHead": "3cc7cbe5124cbcbb75f6e1435db4dcfaa2a60408" +} \ No newline at end of file diff --git a/packages/medusa-plugin-ip-lookup/src/api/medusa-middleware.js b/packages/medusa-plugin-ip-lookup/src/api/medusa-middleware.js new file mode 100644 index 0000000000..4a26b1ee56 --- /dev/null +++ b/packages/medusa-plugin-ip-lookup/src/api/medusa-middleware.js @@ -0,0 +1,36 @@ +export default { + preCartCreation: async function (req, res, next) { + try { + if (req.body.region_id) { + next() + return + } + + const ipLookupService = req.scope.resolve("ipLookupService") + const regionService = req.scope.resolve("regionService") + + const ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress + + const { data } = await ipLookupService.lookupIp(ip) + + if (!data.country_code) { + next() + return + } + + // Find region using the country code from ip lookup + const regions = await regionService.list({ + countries: data.country_code, + }) + + // If this region exists, add it to the body of the cart creation request + if (regions[0]) { + req.body.region_id = regions[0]._id.toString() + } + + next() + } catch (error) { + next() + } + }, +} diff --git a/packages/medusa-plugin-ip-lookup/src/services/ip-lookup.js b/packages/medusa-plugin-ip-lookup/src/services/ip-lookup.js new file mode 100644 index 0000000000..e2a97d54e3 --- /dev/null +++ b/packages/medusa-plugin-ip-lookup/src/services/ip-lookup.js @@ -0,0 +1,18 @@ +import { BaseService } from "medusa-interfaces" +import axios from "axios" + +class IpLookupService extends BaseService { + constructor({}, options) { + super() + + this.options_ = options + } + + async lookupIp(ipAddress) { + return axios.get( + `http://api.ipstack.com/${ipAddress}?access_key=${this.options_.access_token}` + ) + } +} + +export default IpLookupService diff --git a/packages/medusa/src/api/routes/store/carts/index.js b/packages/medusa/src/api/routes/store/carts/index.js index b90151ca48..de71d41f03 100644 --- a/packages/medusa/src/api/routes/store/carts/index.js +++ b/packages/medusa/src/api/routes/store/carts/index.js @@ -3,12 +3,19 @@ import middlewares from "../../../middlewares" const route = Router() -export default app => { +export default (app, container) => { + const middlewareService = container.resolve("middlewareService") + app.use("/carts", route) route.get("/:id", middlewares.wrap(require("./get-cart").default)) - route.post("/", middlewares.wrap(require("./create-cart").default)) + route.post( + "/", + middlewareService.usePreCartCreation(), + middlewares.wrap(require("./create-cart").default) + ) + route.post("/:id", middlewares.wrap(require("./update-cart").default)) // Line items diff --git a/packages/medusa/src/api/routes/store/index.js b/packages/medusa/src/api/routes/store/index.js index 95a118517c..ac33ad0290 100644 --- a/packages/medusa/src/api/routes/store/index.js +++ b/packages/medusa/src/api/routes/store/index.js @@ -30,7 +30,7 @@ export default (app, container, config) => { customerRoutes(route, container) productRoutes(route) orderRoutes(route) - cartRoutes(route) + cartRoutes(route, container) shippingOptionRoutes(route) regionRoutes(route) diff --git a/packages/medusa/src/loaders/plugins.js b/packages/medusa/src/loaders/plugins.js index d7c8199e31..78dcdb31b8 100644 --- a/packages/medusa/src/loaders/plugins.js +++ b/packages/medusa/src/loaders/plugins.js @@ -109,6 +109,10 @@ function registerMedusaMiddleware(pluginDetails, container) { pluginDetails.options ) } + + if (module.preCartCreation) { + middlewareService.addPreCartCreation(module.preCartCreation) + } } function registerCoreRouters(pluginDetails, container) { diff --git a/packages/medusa/src/services/middleware.js b/packages/medusa/src/services/middleware.js index 15700bea71..889f2caace 100644 --- a/packages/medusa/src/services/middleware.js +++ b/packages/medusa/src/services/middleware.js @@ -7,6 +7,7 @@ class MiddlewareService { constructor(container) { this.postAuthentication_ = [] this.preAuthentication_ = [] + this.preCartCreation_ = [] this.routers = {} } @@ -65,6 +66,17 @@ class MiddlewareService { }) } + /** + * Adds a middleware function to be called before cart creation + * @param {function} middleware - the middleware function. Should return a + * middleware function. + * @return {void} + */ + addPreCartCreation(middleware) { + this.validateMiddleware_(middleware) + this.preCartCreation_.push(middleware) + } + /** * Adds post authentication middleware to an express app. * @param {ExpressApp} app - the express app to add the middleware to @@ -86,6 +98,10 @@ class MiddlewareService { app.use(object.middleware(object.options)) } } + + usePreCartCreation() { + return this.preCartCreation_ + } } export default MiddlewareService diff --git a/packages/medusa/yarn.lock b/packages/medusa/yarn.lock index f27d08a532..25164ec6c0 100644 --- a/packages/medusa/yarn.lock +++ b/packages/medusa/yarn.lock @@ -1965,13 +1965,6 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= -client-sessions@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/client-sessions/-/client-sessions-0.8.0.tgz#a7d8c5558ad5d56f2a199f3533eb654b5df893fd" - integrity sha1-p9jFVYrV1W8qGZ81M+tlS134k/0= - dependencies: - cookies "^0.7.0" - cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -2178,14 +2171,6 @@ cookiejar@^2.1.0: resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== -cookies@^0.7.0: - version "0.7.3" - resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.7.3.tgz#7912ce21fbf2e8c2da70cf1c3f351aecf59dadfa" - integrity sha512-+gixgxYSgQLTaTIilDHAdlNPZDENDQernEMiIcZpYYP14zgHsCt4Ce1FEjFtcp6GefhozebB6orvhAAWx/IS0A== - dependencies: - depd "~1.1.2" - keygrip "~1.0.3" - copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" @@ -4363,11 +4348,6 @@ kareem@2.3.1: resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.1.tgz#def12d9c941017fabfb00f873af95e9c99e1be87" integrity sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw== -keygrip@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.3.tgz#399d709f0aed2bab0a059e0cdd3a5023a053e1dc" - integrity sha512-/PpesirAIfaklxUzp4Yb7xBper9MwP6hNRA6BGGUFCgbJ+BM5CKBtsoxinNXkLHAr+GXS1/lSlF2rP7cv5Fl+g== - kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"