Feat:contentful plugin archive on delete

* extend plugin with methods for archival in contentful

* add events to services

* rename entities

* eventbusservice to delete

* Update packages/medusa-plugin-contentful/src/services/contentful.js

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>

* Update packages/medusa-plugin-contentful/src/services/contentful.js

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>

* Update packages/medusa-plugin-contentful/src/services/contentful.js

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>

* testing

* adjust options

* Update packages/medusa-plugin-contentful/src/services/contentful.js

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>

* adjust options

* Update packages/medusa-plugin-contentful/src/services/contentful.js

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>

* Update packages/medusa-plugin-contentful/src/services/contentful.js

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>
This commit is contained in:
Philip Korsholm
2021-10-14 17:00:27 +02:00
committed by GitHub
parent 62fda1043e
commit ba2de6906a
9 changed files with 319 additions and 4 deletions

View File

@@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ContentfulMock = void 0;
var ContentfulMock = {
createClient: jest.fn()
};
exports.ContentfulMock = ContentfulMock;

View File

@@ -0,0 +1,6 @@
export const createClient = jest.fn()
const mock = jest.fn().mockImplementation(() => {
return { createClient }
})
export default mock

View File

@@ -0,0 +1,179 @@
import ContentfulService from "../contentful"
describe("ContentfulService", () => {
describe("delete in medusa", () => {
const regionService = {
retrieve: jest.fn((id) => {
if (id === "exists") {
return Promise.resolve({ id: "exists" })
}
return Promise.resolve(undefined)
}),
}
const productService = {
retrieve: jest.fn((id) => {
if (id === "exists") {
return Promise.resolve({ id: "exists" })
}
return Promise.resolve(undefined)
}),
}
const redisClient = {
get: async (id) => {
// const key = `${id}_ignore_${side}`
if (id === `ignored_ignore_contentful`) {
return { id }
}
return undefined
},
set: async (id) => {
return undefined
},
}
const productVariantService = {
retrieve: jest.fn((id) => {
if (id === "exists") {
return Promise.resolve({ id: "exists" })
}
return Promise.resolve(undefined)
}),
}
const eventBusService = {}
const service = new ContentfulService(
{
regionService,
productService,
redisClient,
productVariantService,
eventBusService,
},
{
space_id: "test_id",
environment: "master",
access_token: "test_token",
}
)
const entry = {
unpublish: jest.fn(async () => {
return {
id: "id",
}
}),
archive: jest.fn(async () => {
return {
id: "id",
}
}),
}
service.contentful_ = {
getSpace: async (space_id) => {
return {
getEnvironment: async (env) => {
return {
getEntry: async (id) => {
if (id === "onlyMedusa") {
throw new Error("doesn't exist")
}
return entry
},
}
},
}
},
}
beforeEach(() => {
jest.clearAllMocks()
})
describe("archiveProductInContentful", () => {
it("Calls entry.unpublish and entry.archive", async () => {
await service.archiveProductInContentful({ id: "test" })
expect(entry.unpublish).toHaveBeenCalledTimes(1)
expect(entry.archive).toHaveBeenCalledTimes(1)
})
it("Doesn't call entry.unpublish and entry.archive if the product still exists in medusa", async () => {
await service.archiveProductInContentful({ id: "exists" })
expect(entry.unpublish).toHaveBeenCalledTimes(0)
expect(entry.archive).toHaveBeenCalledTimes(0)
})
it("Doesn't call productService if request should be ignored", async () => {
await service.archiveProductInContentful({ id: "ignored" })
expect(productService.retrieve).toHaveBeenCalledTimes(0)
expect(entry.unpublish).toHaveBeenCalledTimes(0)
expect(entry.archive).toHaveBeenCalledTimes(0)
})
})
describe("archiveProductVariantInContentful", () => {
it("Calls entry.unpublish and entry.archive", async () => {
await service.archiveProductVariantInContentful({ id: "test" })
expect(entry.unpublish).toHaveBeenCalledTimes(1)
expect(entry.archive).toHaveBeenCalledTimes(1)
})
it("Doesn't call entry.unpublish and entry.archive if the variant still exists in medusa", async () => {
await service.archiveProductVariantInContentful({ id: "exists" })
expect(entry.unpublish).toHaveBeenCalledTimes(0)
expect(entry.archive).toHaveBeenCalledTimes(0)
})
it("Doesn't call productVariantService if request should be ignored", async () => {
await service.archiveProductVariantInContentful({ id: "ignored" })
expect(productVariantService.retrieve).toHaveBeenCalledTimes(0)
expect(entry.unpublish).toHaveBeenCalledTimes(0)
expect(entry.archive).toHaveBeenCalledTimes(0)
})
})
describe("archiveRegionInContentful", () => {
it("Calls entry.unpublish and entry.archive", async () => {
await service.archiveRegionInContentful({ id: "test" })
expect(entry.unpublish).toHaveBeenCalledTimes(1)
expect(entry.archive).toHaveBeenCalledTimes(1)
})
it("Doesn't call entry.unpublish and entry.archive if the region still exists in medusa", async () => {
await service.archiveRegionInContentful({ id: "exists" })
expect(entry.unpublish).toHaveBeenCalledTimes(0)
expect(entry.archive).toHaveBeenCalledTimes(0)
})
it("Doesn't call RegionService if request should be ignored", async () => {
await service.archiveRegionInContentful({ id: "ignored" })
expect(regionService.retrieve).toHaveBeenCalledTimes(0)
expect(entry.unpublish).toHaveBeenCalledTimes(0)
expect(entry.archive).toHaveBeenCalledTimes(0)
})
})
describe("archiveEntryWidthId", () => {
it("Calls archive if entry exists", async () => {
await service.archiveEntryWidthId("exists")
expect(entry.unpublish).toHaveBeenCalledTimes(1)
expect(entry.archive).toHaveBeenCalledTimes(1)
})
it("Doesnt call archive if entry doesn't exists", async () => {
await service.archiveEntryWidthId("onlyMedusa")
expect(entry.unpublish).toHaveBeenCalledTimes(0)
expect(entry.archive).toHaveBeenCalledTimes(0)
})
})
})
})

View File

@@ -91,7 +91,7 @@ class ContentfulService extends BaseService {
async createImageAssets(product) {
const environment = await this.getContentfulEnvironment_()
let assets = []
const assets = []
await Promise.all(
product.images
.filter((image) => image.url !== product.thumbnail)
@@ -646,6 +646,92 @@ class ContentfulService extends BaseService {
}
}
async archiveProductVariantInContentful(variant) {
let variantEntity
try {
const ignore = await this.shouldIgnore_(variant.id, "contentful")
if (ignore) {
return Promise.resolve()
}
try {
variantEntity = await this.productVariantService_.retrieve(variant.id)
} catch (err) {
// ignore
}
if (variantEntity) {
return Promise.resolve()
}
return await this.archiveEntryWidthId(variant.id)
} catch (error) {
throw error
}
}
async archiveProductInContentful(product) {
let productEntity
try {
const ignore = await this.shouldIgnore_(product.id, "contentful")
if (ignore) {
return Promise.resolve()
}
try {
productEntity = await this.productService_.retrieve(product.id)
} catch (err) {}
if (productEntity) {
return Promise.resolve()
}
return await this.archiveEntryWidthId(product.id)
} catch (error) {
throw error
}
}
async archiveRegionInContentful(region) {
let regionEntity
try {
const ignore = await this.shouldIgnore_(region.id, "contentful")
if (ignore) {
return Promise.resolve()
}
try {
regionEntity = await this.regionService_.retrieve(region.id)
} catch (err) {}
if (regionEntity) {
return Promise.resolve()
}
return await this.archiveEntryWidthId(region.id)
} catch (error) {
throw error
}
}
async archiveEntryWidthId(id) {
const environment = await this.getContentfulEnvironment_()
// check if product exists
let entry = undefined
try {
entry = await environment.getEntry(id)
} catch (error) {
return Promise.resolve()
}
const unpublishEntry = await entry.unpublish()
const archivedEntry = await entry.archive()
await this.addIgnore_(id, "medusa")
return archivedEntry
}
async sendContentfulProductToAdmin(productId) {
const ignore = await this.shouldIgnore_(productId, "medusa")
if (ignore) {
@@ -658,7 +744,7 @@ class ContentfulService extends BaseService {
const product = await this.productService_.retrieve(productId)
let update = {}
const update = {}
const title =
productEntry.fields[this.getCustomField("title", "product")]["en-US"]
@@ -741,9 +827,9 @@ class ContentfulService extends BaseService {
isArray = false
}
let output = []
const output = []
for (const obj of input) {
let transformed = Object.assign({}, obj)
const transformed = Object.assign({}, obj)
transformed.medusaId = obj.id
output.push(transformed)
}

View File

@@ -18,10 +18,18 @@ class ContentfulSubscriber {
await this.contentfulService_.updateRegionInContentful(data)
})
this.eventBus_.subscribe("region.deleted", async (data) => {
await this.contentfulService_.updateRegionInContentful(data)
})
this.eventBus_.subscribe("product-variant.updated", async (data) => {
await this.contentfulService_.updateProductVariantInContentful(data)
})
this.eventBus_.subscribe("product-variant.deleted", async (data) => {
await this.contentfulService_.archiveProductVariantInContentful(data)
})
this.eventBus_.subscribe("product.updated", async (data) => {
await this.contentfulService_.updateProductInContentful(data)
})
@@ -29,6 +37,10 @@ class ContentfulSubscriber {
this.eventBus_.subscribe("product.created", async (data) => {
await this.contentfulService_.createProductInContentful(data)
})
this.eventBus_.subscribe("product.deleted", async (data) => {
await this.contentfulService_.archiveProductInContentful(data)
})
}
}

View File

@@ -415,6 +415,7 @@ describe("ProductService", () => {
const productService = new ProductService({
manager: MockManager,
eventBusService,
productRepository,
})

View File

@@ -11,6 +11,7 @@ class ProductVariantService extends BaseService {
static Events = {
UPDATED: "product-variant.updated",
CREATED: "product-variant.created",
DELETED: "product-variant.deleted",
}
/** @param { productVariantModel: (ProductVariantModel) } */
@@ -588,6 +589,12 @@ class ProductVariantService extends BaseService {
await variantRepo.softRemove(variant)
await this.eventBus_
.withTransaction(manager)
.emit(ProductVariantService.Events.DELETED, {
id: variantId,
})
return Promise.resolve()
})
}

View File

@@ -11,6 +11,7 @@ class ProductService extends BaseService {
static Events = {
UPDATED: "product.updated",
CREATED: "product.created",
DELETED: "product.deleted",
}
constructor({
@@ -475,6 +476,12 @@ class ProductService extends BaseService {
await productRepo.softRemove(product)
await this.eventBus_
.withTransaction(manager)
.emit(ProductService.Events.DELETED, {
id: productId,
})
return Promise.resolve()
})
}

View File

@@ -10,6 +10,7 @@ class RegionService extends BaseService {
static Events = {
UPDATED: "region.updated",
CREATED: "region.created",
DELETED: "region.deleted",
}
constructor({
@@ -389,6 +390,12 @@ class RegionService extends BaseService {
await regionRepo.softRemove(region)
await this.eventBus_
.withTransaction(manager)
.emit(RegionService.Events.DELETED, {
id: regionId,
})
return Promise.resolve()
})
}