diff --git a/packages/medusa-plugin-restock-notification/package.json b/packages/medusa-plugin-restock-notification/package.json index 780840320c..b915bb5735 100644 --- a/packages/medusa-plugin-restock-notification/package.json +++ b/packages/medusa-plugin-restock-notification/package.json @@ -41,6 +41,7 @@ "dependencies": { "@medusajs/medusa": "^1.1.17", "body-parser": "^1.19.0", + "express": "^4.17.1", "medusa-core-utils": "^1.1.3" }, "gitHead": "0646bd395a6056657cb0aa93c13699c4a9dbbcdd" diff --git a/packages/medusa-plugin-restock-notification/src/api/routes/add-email.js b/packages/medusa-plugin-restock-notification/src/api/routes/add-email.js index debfb6082f..89f0bb35ce 100644 --- a/packages/medusa-plugin-restock-notification/src/api/routes/add-email.js +++ b/packages/medusa-plugin-restock-notification/src/api/routes/add-email.js @@ -1,7 +1,7 @@ import { Validator, MedusaError } from "medusa-core-utils" export default async (req, res) => { - const { variant_id } = req.parmas + const { variant_id } = req.params const schema = Validator.object().keys({ email: Validator.string().required(), @@ -9,7 +9,8 @@ export default async (req, res) => { const { value, error } = schema.validate(req.body) if (error) { - throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details) + res.status(400).json({ message: error.message }) + return } try { @@ -19,6 +20,6 @@ export default async (req, res) => { await restockNotificationService.addEmail(variant_id, value.email) res.sendStatus(200) } catch (err) { - res.sendStatus(400).json({ message: err.message }) + res.status(400).json({ message: err.message }) } } diff --git a/packages/medusa-plugin-restock-notification/src/api/routes/index.js b/packages/medusa-plugin-restock-notification/src/api/routes/index.js index c0aa54bf15..b1a74939d1 100644 --- a/packages/medusa-plugin-restock-notification/src/api/routes/index.js +++ b/packages/medusa-plugin-restock-notification/src/api/routes/index.js @@ -9,7 +9,7 @@ export default (app) => { route.post( "/variants/:variant_id", - bodyParser.raw({ type: "application/json" }), + bodyParser.json(), middlewares.wrap(require("./add-email").default) ) return app diff --git a/packages/medusa-plugin-restock-notification/src/services/restock-notification.js b/packages/medusa-plugin-restock-notification/src/services/restock-notification.js index a218f173aa..053c36815c 100644 --- a/packages/medusa-plugin-restock-notification/src/services/restock-notification.js +++ b/packages/medusa-plugin-restock-notification/src/services/restock-notification.js @@ -16,6 +16,23 @@ class RestockNotificationService extends BaseService { this.eventBus_ = eventBusService } + withTransaction(transactionManager) { + if (!transactionManager) { + return this + } + + const cloned = new RestockNotificationService({ + manager: transactionManager, + options: this.options_, + eventBusService: this.eventBus_, + productVariantService: this.productVariantService_, + }) + + cloned.transactionManager_ = transactionManager + + return cloned + } + async retrieve(variantId) { const restockRepo = this.manager_.getRepository(RestockNotification) return await restockRepo.findOne({ where: { variant_id: variantId } }) @@ -29,13 +46,13 @@ class RestockNotificationService extends BaseService { if (existing) { // Converting to a set handles duplicates for us const emailSet = new Set(existing.emails) - emailSet.push(email) + emailSet.add(email) existing.emails = Array.from(emailSet) return await restockRepo.save(existing) } else { - const variant = await productVariantService.retrieve(variantId) + const variant = await this.productVariantService_.retrieve(variantId) if (variant.inventory_quantity > 0) { throw new MedusaError( @@ -54,15 +71,10 @@ class RestockNotificationService extends BaseService { }) } - async delete(variantId) { - return this.atomicPhase_(async (manager) => { - const restockRepo = manager.getRepository(RestockNotification) - return restockRepo.delete(variantId) - }) - } - async triggerRestock(variantId) { return this.atomicPhase_(async (manager) => { + const restockRepo = manager.getRepository(RestockNotification) + const existing = await this.retrieve(variantId) if (!existing) { return @@ -70,10 +82,13 @@ class RestockNotificationService extends BaseService { const variant = await this.productVariantService_.retrieve(variantId) if (variant.inventory_quantity > 0) { - await eventBus_ + await this.eventBus_ .withTransaction(manager) - .emit("restock_notification.restocked") - await this.delete(variantId) + .emit("restock_notification.restocked", { + variant_id: variantId, + emails: existing.emails, + }) + await restockRepo.delete(variantId) } }) } diff --git a/packages/medusa-plugin-restock-notification/src/subscribers/index.js b/packages/medusa-plugin-restock-notification/src/subscribers/index.js index b7a3092a20..53b3e1dbd7 100644 --- a/packages/medusa-plugin-restock-notification/src/subscribers/index.js +++ b/packages/medusa-plugin-restock-notification/src/subscribers/index.js @@ -1,9 +1,10 @@ class VariantSubscriber { - constructor({ eventBusService, restockNotificationService }) { + constructor({ manager, eventBusService, restockNotificationService }) { + this.manager_ = manager this.restockNotificationService_ = restockNotificationService eventBusService.subscribe( - "product_variant.updated", + "product-variant.updated", this.handleVariantUpdate ) } @@ -11,7 +12,12 @@ class VariantSubscriber { handleVariantUpdate = async (data) => { const { id, fields } = data if (fields.includes("inventory_quantity")) { - return this.restockNotificationService_.triggerRestock(id) + return await this.manager_.transaction( + async (m) => + await this.restockNotificationService_ + .withTransaction(m) + .triggerRestock(id) + ) } } } diff --git a/packages/medusa/src/loaders/index.js b/packages/medusa/src/loaders/index.js index 842864ded0..1eccf4e4cb 100644 --- a/packages/medusa/src/loaders/index.js +++ b/packages/medusa/src/loaders/index.js @@ -11,7 +11,7 @@ import modelsLoader from "./models" import servicesLoader from "./services" import subscribersLoader from "./subscribers" import passportLoader from "./passport" -import pluginsLoader from "./plugins" +import pluginsLoader, { registerPluginModels } from "./plugins" import defaultsLoader from "./defaults" import Logger from "./logger" import { getManager } from "typeorm" @@ -64,6 +64,9 @@ export default async ({ directory: rootDirectory, expressApp }) => { await modelsLoader({ container }) Logger.info("Models initialized") + await registerPluginModels({ rootDirectory, container }) + Logger.info("Models initialized") + await repositoriesLoader({ container }) Logger.info("Repositories initialized") diff --git a/packages/medusa/src/loaders/plugins.js b/packages/medusa/src/loaders/plugins.js index 6e588de7f0..8b42468f02 100644 --- a/packages/medusa/src/loaders/plugins.js +++ b/packages/medusa/src/loaders/plugins.js @@ -13,13 +13,32 @@ import { getConfigFile, createRequireFromPath } from "medusa-core-utils" import _ from "lodash" import path from "path" import fs from "fs" -import { asFunction, aliasTo } from "awilix" +import { asValue, asClass, asFunction, aliasTo } from "awilix" import { sync as existsSync } from "fs-exists-cached" /** * Registers all services in the services directory */ export default async ({ rootDirectory, container, app }) => { + const resolved = getResolvedPlugins(rootDirectory) + + await Promise.all( + resolved.map(async pluginDetails => { + registerRepositories(pluginDetails, container) + await registerServices(pluginDetails, container) + registerMedusaApi(pluginDetails, container) + registerApi(pluginDetails, app, rootDirectory, container) + registerCoreRouters(pluginDetails, container) + registerSubscribers(pluginDetails, container) + }) + ) + + await Promise.all( + resolved.map(async pluginDetails => runLoaders(pluginDetails, container)) + ) +} + +function getResolvedPlugins(rootDirectory) { const { configModule } = getConfigFile(rootDirectory, `medusa-config`) if (!configModule) { @@ -47,21 +66,16 @@ export default async ({ rootDirectory, container, app }) => { version: createFileContentHash(process.cwd(), `**`), }) + return resolved +} + +export async function registerPluginModels({ rootDirectory, container }) { + const resolved = getResolvedPlugins(rootDirectory) await Promise.all( resolved.map(async pluginDetails => { - // registerModels(pluginDetails, container) - registerRepositories(pluginDetails, container) - await registerServices(pluginDetails, container) - registerMedusaApi(pluginDetails, container) - registerApi(pluginDetails, app, rootDirectory, container) - registerCoreRouters(pluginDetails, container) - registerSubscribers(pluginDetails, container) + registerModels(pluginDetails, container) }) ) - - await Promise.all( - resolved.map(async pluginDetails => runLoaders(pluginDetails, container)) - ) } async function runLoaders(pluginDetails, container) { @@ -309,7 +323,6 @@ function registerRepositories(pluginDetails, container) { Object.entries(loaded).map(([key, val]) => { if (typeof val === "function") { const name = formatRegistrationName(fn) - console.log(name) container.register({ [name]: asClass(val), }) @@ -336,14 +349,12 @@ function registerModels(pluginDetails, container) { Object.entries(loaded).map(([key, val]) => { if (typeof val === "function" || val instanceof EntitySchema) { - if (config.register) { - const name = formatRegistrationName(fn) - container.register({ - [name]: asClass(val), - }) + const name = formatRegistrationName(fn) + container.register({ + [name]: asClass(val), + }) - container.registerAdd("db_entities", asValue(val)) - } + container.registerAdd("db_entities", asValue(val)) } }) }) diff --git a/packages/medusa/yarn.lock b/packages/medusa/yarn.lock index 55177a08e4..be32e7d9b7 100644 --- a/packages/medusa/yarn.lock +++ b/packages/medusa/yarn.lock @@ -5662,21 +5662,21 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -medusa-core-utils@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/medusa-core-utils/-/medusa-core-utils-1.1.0.tgz#0641b365b769dbf99856025d935eef5cf5d81f2c" - integrity sha512-zocRthKhLK3eSjrXbAhZZkIMBRxyvU7GcAMFh5UCEgfe7f935vjE7r5lGTr5jTEwgwaoTUk9ep0VBekz0SEdyw== +medusa-core-utils@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/medusa-core-utils/-/medusa-core-utils-1.1.4.tgz#ec2bb98c83426d7033632cd225b3b5dc62c26f1a" + integrity sha512-SzFfMmNbE9ukSfhapJOuYEksOKDo3yYSCeuBLFWnCZZRDnUV4ttH4Yp/ydT+cZKtqZwF2vKceXNbrT4uJYjHgw== dependencies: joi "^17.3.0" joi-objectid "^3.0.1" -medusa-test-utils@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/medusa-test-utils/-/medusa-test-utils-1.1.3.tgz#c2b45d44b9567fa2255e936d7bed73a31dfb42dd" - integrity sha512-0saYG5BhEjc4BZP76/2IJL7CyqIdbCasAci+EYXzwnwgS+nCUhKDjzzNAnC+PZMK/teD3M7x4n7isFtjgNSIDQ== +medusa-test-utils@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/medusa-test-utils/-/medusa-test-utils-1.1.7.tgz#19d0bdf3f6f7fef0bc7f2f8e258f8c66167c692f" + integrity sha512-kcN4oJjUEAkFeko7DEaok9Qy3aty41gEzGSdR4F3KPORXZJ+YADHuj4F219/X1k+3iGqCUgmNQ9eKl6Aobq44g== dependencies: "@babel/plugin-transform-classes" "^7.9.5" - medusa-core-utils "^1.1.0" + medusa-core-utils "^1.1.4" randomatic "^3.1.1" merge-descriptors@1.0.1: