From 6fc6a9de6a336204fa0e1037502cb5cf801089dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frane=20Poli=C4=87?= <16856471+fPolic@users.noreply.github.com> Date: Fri, 5 Jan 2024 14:51:57 +0100 Subject: [PATCH] feat(medusa, link-modules): sales channel <> pubkey link (#5820) --- .changeset/rotten-lobsters-move.md | 7 +++ .../__tests__/admin/publishable-api-key.js | 28 ++++----- .../link-modules/src/definitions/index.ts | 1 + .../publishable-api-key-sales-channel.ts | 63 +++++++++++++++++++ packages/link-modules/src/links.ts | 6 ++ packages/medusa/src/joiner-configs/index.ts | 1 + .../publishable-api-key-service.ts | 26 ++++++++ ...811-publishable-key-sales-channels-link.ts | 29 +++++++++ .../publishable-api-key-sales-channel.ts | 23 +++++-- packages/medusa/src/models/sales-channel.ts | 15 +++++ .../publishable-api-key-sales-channel.ts | 14 +++-- .../services/__tests__/publishable-api-key.ts | 20 +++--- 12 files changed, 195 insertions(+), 38 deletions(-) create mode 100644 .changeset/rotten-lobsters-move.md create mode 100644 packages/link-modules/src/definitions/publishable-api-key-sales-channel.ts create mode 100644 packages/medusa/src/joiner-configs/publishable-api-key-service.ts create mode 100644 packages/medusa/src/migrations/1701894188811-publishable-key-sales-channels-link.ts diff --git a/.changeset/rotten-lobsters-move.md b/.changeset/rotten-lobsters-move.md new file mode 100644 index 0000000000..be856f4b6b --- /dev/null +++ b/.changeset/rotten-lobsters-move.md @@ -0,0 +1,7 @@ +--- +"@medusajs/link-modules": patch +"@medusajs/medusa": patch + +--- + +feat: PubKey <> SC joiner config diff --git a/integration-tests/api/__tests__/admin/publishable-api-key.js b/integration-tests/api/__tests__/admin/publishable-api-key.js index 4f4765adc6..5386fa0dd4 100644 --- a/integration-tests/api/__tests__/admin/publishable-api-key.js +++ b/integration-tests/api/__tests__/admin/publishable-api-key.js @@ -338,14 +338,14 @@ describe("Publishable API keys", () => { expect(response.status).toBe(200) expect(mappings).toEqual([ - { + expect.objectContaining({ sales_channel_id: salesChannel1.id, publishable_key_id: pubKeyId, - }, - { + }), + expect.objectContaining({ sales_channel_id: salesChannel2.id, publishable_key_id: pubKeyId, - }, + }), ]) expect(response.data.publishable_api_key).toMatchObject({ @@ -386,10 +386,10 @@ describe("Publishable API keys", () => { await dbConnection.manager.query( `INSERT INTO publishable_api_key_sales_channel - (publishable_key_id, sales_channel_id) - VALUES ('${pubKeyId}', '${salesChannel1.id}'), - ('${pubKeyId}', '${salesChannel2.id}'), - ('${pubKeyId}', '${salesChannel3.id}');` + (id, publishable_key_id, sales_channel_id) + VALUES ('pksc-1','${pubKeyId}', '${salesChannel1.id}'), + ('pksc-2','${pubKeyId}', '${salesChannel2.id}'), + ('pksc-3','${pubKeyId}', '${salesChannel3.id}');` ) }) @@ -417,16 +417,16 @@ describe("Publishable API keys", () => { const mappings = await dbConnection.manager.query( `SELECT * FROM publishable_api_key_sales_channel - WHERE publishable_key_id = '${pubKeyId}'` + WHERE publishable_key_id = '${pubKeyId}';` ) expect(response.status).toBe(200) expect(mappings).toEqual([ - { + expect.objectContaining({ sales_channel_id: salesChannel3.id, publishable_key_id: pubKeyId, - }, + }), ]) expect(response.data.publishable_api_key).toMatchObject({ @@ -467,9 +467,9 @@ describe("Publishable API keys", () => { await dbConnection.manager.query( `INSERT INTO publishable_api_key_sales_channel - (publishable_key_id, sales_channel_id) - VALUES ('${pubKeyId}', '${salesChannel1.id}'), - ('${pubKeyId}', '${salesChannel2.id}');` + (id, publishable_key_id, sales_channel_id) + VALUES ('pksc-1', '${pubKeyId}', '${salesChannel1.id}'), + ('pksc-2', '${pubKeyId}', '${salesChannel2.id}');` ) }) diff --git a/packages/link-modules/src/definitions/index.ts b/packages/link-modules/src/definitions/index.ts index 14cf0ca3d5..4c75b587b2 100644 --- a/packages/link-modules/src/definitions/index.ts +++ b/packages/link-modules/src/definitions/index.ts @@ -5,3 +5,4 @@ export * from "./product-shipping-profile" export * from "./product-sales-channel" export * from "./cart-sales-channel" export * from "./order-sales-channel" +export * from "./publishable-api-key-sales-channel" diff --git a/packages/link-modules/src/definitions/publishable-api-key-sales-channel.ts b/packages/link-modules/src/definitions/publishable-api-key-sales-channel.ts new file mode 100644 index 0000000000..a9fd53ab42 --- /dev/null +++ b/packages/link-modules/src/definitions/publishable-api-key-sales-channel.ts @@ -0,0 +1,63 @@ +import { ModuleJoinerConfig } from "@medusajs/types" +import { LINKS } from "../links" + +export const PublishableApiKeySalesChannel: ModuleJoinerConfig = { + serviceName: LINKS.PublishableApiKeySalesChannel, + isLink: true, + databaseConfig: { + tableName: "publishable_api_key_sales_channel", + idPrefix: "pksc", + }, + alias: [ + { + name: "publishable_api_key_sales_channel", + }, + { + name: "publishable_api_key_sales_channels", + }, + ], + primaryKeys: ["id", "publishable_key_id", "sales_channel_id"], + relationships: [ + { + serviceName: "publishableApiKeyService", + isInternalService: true, + primaryKey: "id", + foreignKey: "publishable_key_id", + alias: "publishable_key", + }, + { + serviceName: "salesChannelService", + isInternalService: true, + primaryKey: "id", + foreignKey: "sales_channel_id", + alias: "sales_channel", + }, + ], + extends: [ + { + serviceName: "publishableApiKeyService", + fieldAlias: { + sales_channels: "sales_channels_link.sales_channel", + }, + relationship: { + serviceName: LINKS.PublishableApiKeySalesChannel, + isInternalService: true, + primaryKey: "publishable_key_id", + foreignKey: "id", + alias: "sales_channels_link", + isList: true, + }, + }, + { + serviceName: "salesChannelService", + relationship: { + serviceName: LINKS.PublishableApiKeySalesChannel, + isInternalService: true, + primaryKey: "sales_channel_id", + foreignKey: "id", + alias: "publishable_keys_link", + isList: true, + }, + }, + ], +} diff --git a/packages/link-modules/src/links.ts b/packages/link-modules/src/links.ts index c38b0ed715..5f6c39dfff 100644 --- a/packages/link-modules/src/links.ts +++ b/packages/link-modules/src/links.ts @@ -40,4 +40,10 @@ export const LINKS = { "salesChannelService", "sales_channel_id" ), + PublishableApiKeySalesChannel: composeLinkName( + "publishableApiKeyService", + "publishable_key_id", + "salesChannelService", + "sales_channel_id" + ), } diff --git a/packages/medusa/src/joiner-configs/index.ts b/packages/medusa/src/joiner-configs/index.ts index 084dc203f6..7f7849d2d7 100644 --- a/packages/medusa/src/joiner-configs/index.ts +++ b/packages/medusa/src/joiner-configs/index.ts @@ -3,3 +3,4 @@ export * as customer from "./customer-service" export * as region from "./region-service" export * as salesChannel from "./sales-channel-service" export * as shippingProfile from "./shipping-profile-service" +export * as publishableApiKey from "./publishable-api-key-service" diff --git a/packages/medusa/src/joiner-configs/publishable-api-key-service.ts b/packages/medusa/src/joiner-configs/publishable-api-key-service.ts new file mode 100644 index 0000000000..dc7bf58356 --- /dev/null +++ b/packages/medusa/src/joiner-configs/publishable-api-key-service.ts @@ -0,0 +1,26 @@ +import { ModuleJoinerConfig } from "@medusajs/types" + +export default { + serviceName: "publishableApiKeyService", + primaryKeys: ["id"], + linkableKeys: { publishable_key_id: "PublishableApiKey" }, + schema: ` + scalar Date + scalar JSON + + type PublishableApiKey { + id: ID! + sales_channel_id: String! + publishable_key_id: String! + created_at: Date! + updated_at: Date! + deleted_at: Date + } + `, + alias: [ + { + name: ["publishable_api_key", "publishable_api_keys"], + args: { entity: "PublishableApiKey" }, + }, + ], +} as ModuleJoinerConfig diff --git a/packages/medusa/src/migrations/1701894188811-publishable-key-sales-channels-link.ts b/packages/medusa/src/migrations/1701894188811-publishable-key-sales-channels-link.ts new file mode 100644 index 0000000000..017645c1fe --- /dev/null +++ b/packages/medusa/src/migrations/1701894188811-publishable-key-sales-channels-link.ts @@ -0,0 +1,29 @@ +import { MigrationInterface, QueryRunner } from "typeorm" + +export class PublishableKeySalesChannelLink1701894188811 + implements MigrationInterface +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + ALTER TABLE "publishable_api_key_sales_channel" ADD COLUMN IF NOT EXISTS "id" text; + UPDATE "publishable_api_key_sales_channel" SET "id" = 'pksc_' || substr(md5(random()::text), 0, 27) WHERE id is NULL; + ALTER TABLE "publishable_api_key_sales_channel" ALTER COLUMN "id" SET NOT NULL; + + CREATE INDEX IF NOT EXISTS "IDX_id_publishable_api_key_sales_channel" ON "publishable_api_key_sales_channel" ("id"); + + ALTER TABLE "publishable_api_key_sales_channel" ADD COLUMN IF NOT EXISTS "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(); + ALTER TABLE "publishable_api_key_sales_channel" ADD COLUMN IF NOT EXISTS "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(); + ALTER TABLE "publishable_api_key_sales_channel" ADD COLUMN IF NOT EXISTS "deleted_at" TIMESTAMP WITH TIME ZONE; + `) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + DROP INDEX IF EXISTS "IDX_id_publishable_api_key_sales_channel"; + ALTER TABLE "publishable_api_key_sales_channel" DROP COLUMN IF EXISTS "id"; + ALTER TABLE "publishable_api_key_sales_channel" DROP COLUMN IF EXISTS "created_at"; + ALTER TABLE "publishable_api_key_sales_channel" DROP COLUMN IF EXISTS "updated_at"; + ALTER TABLE "publishable_api_key_sales_channel" DROP COLUMN IF EXISTS "deleted_at"; + `) + } +} diff --git a/packages/medusa/src/models/publishable-api-key-sales-channel.ts b/packages/medusa/src/models/publishable-api-key-sales-channel.ts index 32ba90818f..744b5e0146 100644 --- a/packages/medusa/src/models/publishable-api-key-sales-channel.ts +++ b/packages/medusa/src/models/publishable-api-key-sales-channel.ts @@ -1,12 +1,25 @@ -import { Entity, PrimaryColumn } from "typeorm" +import { BeforeInsert, Column, Entity, PrimaryColumn } from "typeorm" +import { BaseEntity } from "../interfaces" +import { generateEntityId } from "../utils" -@Entity() -export class PublishableApiKeySalesChannel { - @PrimaryColumn() +@Entity("publishable_api_key_sales_channel") +export class PublishableApiKeySalesChannel extends BaseEntity { + @Column({ type: "text" }) + id: string + + @PrimaryColumn({ type: "text" }) sales_channel_id: string - @PrimaryColumn() + @PrimaryColumn({ type: "text" }) publishable_key_id: string + + /** + * @apiIgnore + */ + @BeforeInsert() + private beforeInsert(): void { + this.id = generateEntityId(this.id, "pksc") + } } /** diff --git a/packages/medusa/src/models/sales-channel.ts b/packages/medusa/src/models/sales-channel.ts index 6a71b6ad26..4e3f5c8525 100644 --- a/packages/medusa/src/models/sales-channel.ts +++ b/packages/medusa/src/models/sales-channel.ts @@ -11,6 +11,7 @@ import { SalesChannelLocation } from "./sales-channel-location" import { Product } from "./product" import { Cart } from "./cart" import { Order } from "./order" +import { PublishableApiKey } from "./publishable-api-key" @FeatureFlagEntity("sales_channels") export class SalesChannel extends SoftDeletableEntity { @@ -74,6 +75,20 @@ export class SalesChannel extends SoftDeletableEntity { ) orders: Order[] + @ManyToMany(() => PublishableApiKey) + @JoinTable({ + name: "publishable_api_key_sales_channel", + inverseJoinColumn: { + name: "publishable_key_id", + referencedColumnName: "id", + }, + joinColumn: { + name: "sales_channel_id", + referencedColumnName: "id", + }, + }) + publishableKeys: PublishableApiKey[] + @OneToMany( () => SalesChannelLocation, (scLocation) => scLocation.sales_channel, diff --git a/packages/medusa/src/repositories/publishable-api-key-sales-channel.ts b/packages/medusa/src/repositories/publishable-api-key-sales-channel.ts index 2a51854749..11e1cd96dd 100644 --- a/packages/medusa/src/repositories/publishable-api-key-sales-channel.ts +++ b/packages/medusa/src/repositories/publishable-api-key-sales-channel.ts @@ -3,6 +3,7 @@ import { Brackets, In } from "typeorm" import { PublishableApiKeySalesChannel, SalesChannel } from "../models" import { dataSource } from "../loaders/database" import SalesChannelRepository from "./sales-channel" +import { generateEntityId } from "../utils" const publishableApiKeySalesChannelAlias = "PublishableKeySalesChannel" @@ -64,15 +65,16 @@ export const PublishableApiKeySalesChannelRepository = dataSource publishableApiKeyId: string, salesChannelIds: string[] ): Promise { + const valuesToInsert = salesChannelIds.map((id) => ({ + id: generateEntityId(undefined, "pksc"), + sales_channel_id: id, + publishable_key_id: publishableApiKeyId, + })) + await this.createQueryBuilder() .insert() .into(PublishableApiKeySalesChannel) - .values( - salesChannelIds.map((id) => ({ - sales_channel_id: id, - publishable_key_id: publishableApiKeyId, - })) - ) + .values(valuesToInsert) .orIgnore() .execute() }, diff --git a/packages/medusa/src/services/__tests__/publishable-api-key.ts b/packages/medusa/src/services/__tests__/publishable-api-key.ts index 8c0e093932..453930090c 100644 --- a/packages/medusa/src/services/__tests__/publishable-api-key.ts +++ b/packages/medusa/src/services/__tests__/publishable-api-key.ts @@ -41,19 +41,13 @@ describe("PublishableApiKeyService", () => { await publishableApiKeyService.retrieve( IdMap.getId("order-edit-with-changes") ) - expect( - publishableApiKeyRepository.findOne - ).toHaveBeenCalledTimes(1) - expect( - publishableApiKeyRepository.findOne - ).toHaveBeenCalledWith( - { - relationLoadStrategy: "query", - where: { - id: IdMap.getId("order-edit-with-changes") - } - } - ) + expect(publishableApiKeyRepository.findOne).toHaveBeenCalledTimes(1) + expect(publishableApiKeyRepository.findOne).toHaveBeenCalledWith({ + relationLoadStrategy: "query", + where: { + id: IdMap.getId("order-edit-with-changes"), + }, + }) }) it("should create a publishable api key and call the repository with the right arguments as well as the event bus service", async () => {