feat(medusa, medusa-js, medusa-react): PublishableApiKey "update" endpoint & add "title" property (#2609)

**What**
- update PK endpoint
  - medusa-js/react implementation
- add a title property to the entity
  - update the migration file
  - pass a title on create
  - list PKs by title
  - update the client libs with new param signatures
- change id prefix to: "pk_"
This commit is contained in:
Frane Polić
2022-11-16 04:35:22 +00:00
committed by GitHub
parent ccfc5f666d
commit 03fc9e18e9
17 changed files with 390 additions and 30 deletions
@@ -82,9 +82,15 @@ describe("[MEDUSA_FF_PUBLISHABLE_API_KEYS] Publishable API keys", () => {
beforeEach(async () => { beforeEach(async () => {
await adminSeeder(dbConnection) await adminSeeder(dbConnection)
await simplePublishableApiKeyFactory(dbConnection, {}) await simplePublishableApiKeyFactory(dbConnection, {
await simplePublishableApiKeyFactory(dbConnection, {}) title: "just a title",
await simplePublishableApiKeyFactory(dbConnection, {}) })
await simplePublishableApiKeyFactory(dbConnection, {
title: "special title 1",
})
await simplePublishableApiKeyFactory(dbConnection, {
title: "special title 2",
})
}) })
afterEach(async () => { afterEach(async () => {
@@ -105,6 +111,30 @@ describe("[MEDUSA_FF_PUBLISHABLE_API_KEYS] Publishable API keys", () => {
expect(response.data.offset).toBe(0) expect(response.data.offset).toBe(0)
expect(response.data.publishable_api_keys).toHaveLength(2) expect(response.data.publishable_api_keys).toHaveLength(2)
}) })
it("list publishable keys with query search", async () => {
const api = useApi()
const response = await api.get(
`/admin/publishable-api-keys?q=special`,
adminHeaders
)
expect(response.data.count).toBe(2)
expect(response.data.limit).toBe(20)
expect(response.data.offset).toBe(0)
expect(response.data.publishable_api_keys).toHaveLength(2)
expect(response.data.publishable_api_keys).toEqual(
expect.arrayContaining([
expect.objectContaining({
title: "special title 1",
}),
expect.objectContaining({
title: "special title 2",
}),
])
)
})
}) })
describe("POST /admin/publishable-api-keys", () => { describe("POST /admin/publishable-api-keys", () => {
@@ -122,7 +152,7 @@ describe("[MEDUSA_FF_PUBLISHABLE_API_KEYS] Publishable API keys", () => {
const response = await api.post( const response = await api.post(
`/admin/publishable-api-keys`, `/admin/publishable-api-keys`,
{}, { title: "Store api key" },
adminHeaders adminHeaders
) )
@@ -130,6 +160,45 @@ describe("[MEDUSA_FF_PUBLISHABLE_API_KEYS] Publishable API keys", () => {
expect(response.data.publishable_api_key).toMatchObject({ expect(response.data.publishable_api_key).toMatchObject({
created_by: "admin_user", created_by: "admin_user",
id: expect.any(String), id: expect.any(String),
title: "Store api key",
revoked_by: null,
revoked_at: null,
created_at: expect.any(String),
updated_at: expect.any(String),
})
})
})
describe("POST /admin/publishable-api-keys/:id", () => {
const pubKeyId = IdMap.getId("pubkey-get-id-update")
beforeEach(async () => {
await adminSeeder(dbConnection)
await simplePublishableApiKeyFactory(dbConnection, {
id: pubKeyId,
title: "Initial key title",
})
})
afterEach(async () => {
const db = useDb()
return await db.teardown()
})
it("update a publishable key", async () => {
const api = useApi()
const response = await api.post(
`/admin/publishable-api-keys/${pubKeyId}`,
{ title: "Changed title" },
adminHeaders
)
expect(response.status).toBe(200)
expect(response.data.publishable_api_key).toMatchObject({
id: pubKeyId,
title: "Changed title",
revoked_by: null, revoked_by: null,
revoked_at: null, revoked_at: null,
created_at: expect.any(String), created_at: expect.any(String),
@@ -9,7 +9,6 @@ const adminSeeder = require("../../helpers/admin-seeder")
const { const {
simpleSalesChannelFactory, simpleSalesChannelFactory,
simpleProductFactory, simpleProductFactory,
simpleCartFactory,
} = require("../../factories") } = require("../../factories")
const { simpleOrderFactory } = require("../../factories") const { simpleOrderFactory } = require("../../factories")
const orderSeeder = require("../../helpers/order-seeder") const orderSeeder = require("../../helpers/order-seeder")
@@ -3,7 +3,6 @@ import {
MoneyAmount, MoneyAmount,
PriceListType, PriceListType,
PriceListStatus, PriceListStatus,
CustomerGroup,
} from "@medusajs/medusa" } from "@medusajs/medusa"
import faker from "faker" import faker from "faker"
import { Connection } from "typeorm" import { Connection } from "typeorm"
@@ -1,4 +1,6 @@
import faker from "faker"
import { Connection } from "typeorm" import { Connection } from "typeorm"
import { PublishableApiKey } from "@medusajs/medusa" import { PublishableApiKey } from "@medusajs/medusa"
export type PublishableApiKeyData = { export type PublishableApiKeyData = {
@@ -6,6 +8,7 @@ export type PublishableApiKeyData = {
revoked_at?: Date revoked_at?: Date
revoked_by?: string revoked_by?: string
created_by?: string created_by?: string
title?: string
} }
export const simplePublishableApiKeyFactory = async ( export const simplePublishableApiKeyFactory = async (
@@ -14,7 +17,10 @@ export const simplePublishableApiKeyFactory = async (
): Promise<PublishableApiKey> => { ): Promise<PublishableApiKey> => {
const manager = connection.manager const manager = connection.manager
const pubKey = manager.create(PublishableApiKey, data) const pubKey = manager.create(PublishableApiKey, {
...data,
title: data.title || `${faker.commerce.department()} API key`,
})
return await manager.save(pubKey) return await manager.save(pubKey)
} }
@@ -5,6 +5,8 @@ import {
AdminPublishableApiKeysRes, AdminPublishableApiKeysRes,
GetPublishableApiKeysParams, GetPublishableApiKeysParams,
AdminPublishableApiKeysListRes, AdminPublishableApiKeysListRes,
AdminPostPublishableApiKeysReq,
AdminPostPublishableApiKeysPublishableApiKeyReq,
} from "@medusajs/medusa" } from "@medusajs/medusa"
import { ResponsePromise } from "../../typings" import { ResponsePromise } from "../../typings"
@@ -41,13 +43,22 @@ class AdminPublishableApiKeyResource extends BaseResource {
} }
create( create(
payload: {}, payload: AdminPostPublishableApiKeysReq,
customHeaders: Record<string, any> = {} customHeaders: Record<string, any> = {}
): ResponsePromise<AdminPublishableApiKeysRes> { ): ResponsePromise<AdminPublishableApiKeysRes> {
const path = `/admin/publishable-api-keys` const path = `/admin/publishable-api-keys`
return this.client.request("POST", path, payload, {}, customHeaders) return this.client.request("POST", path, payload, {}, customHeaders)
} }
update(
id: string,
payload: AdminPostPublishableApiKeysPublishableApiKeyReq,
customHeaders: Record<string, any> = {}
) {
const path = `/admin/publishable-api-keys/${id}`
return this.client.request("POST", path, payload, {}, customHeaders)
}
delete( delete(
id: string, id: string,
customHeaders: Record<string, any> = {} customHeaders: Record<string, any> = {}
@@ -980,6 +980,18 @@ export const adminHandlers = [
) )
}), }),
rest.post("/admin/publishable-api-keys/:id", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
publishable_api_key: {
...fixtures.get("publishable_api_key"),
...(req.body as any),
},
})
)
}),
rest.post("/admin/publishable-api-keys/", (req, res, ctx) => { rest.post("/admin/publishable-api-keys/", (req, res, ctx) => {
return res( return res(
ctx.status(200), ctx.status(200),
@@ -4,6 +4,8 @@ import { Response } from "@medusajs/medusa-js"
import { import {
AdminPublishableApiKeyDeleteRes, AdminPublishableApiKeyDeleteRes,
AdminPublishableApiKeysRes, AdminPublishableApiKeysRes,
AdminPostPublishableApiKeysPublishableApiKeyReq,
AdminPostPublishableApiKeysReq,
} from "@medusajs/medusa" } from "@medusajs/medusa"
import { buildOptions } from "../../utils/buildOptions" import { buildOptions } from "../../utils/buildOptions"
@@ -11,16 +13,47 @@ import { useMedusa } from "../../../contexts"
import { adminPublishableApiKeysKeys } from "." import { adminPublishableApiKeysKeys } from "."
export const useAdminCreatePublishableApiKey = ( export const useAdminCreatePublishableApiKey = (
options?: UseMutationOptions<Response<AdminPublishableApiKeysRes>, Error, {}> options?: UseMutationOptions<
Response<AdminPublishableApiKeysRes>,
Error,
AdminPostPublishableApiKeysReq
>
) => { ) => {
const { client } = useMedusa() const { client } = useMedusa()
const queryClient = useQueryClient() const queryClient = useQueryClient()
return useMutation( return useMutation(
(payload: {}) => client.admin.publishableApiKeys.create(payload), (payload: AdminPostPublishableApiKeysReq) =>
client.admin.publishableApiKeys.create(payload),
buildOptions(queryClient, [adminPublishableApiKeysKeys.lists()], options) buildOptions(queryClient, [adminPublishableApiKeysKeys.lists()], options)
) )
} }
export const useAdminUpdatePublishableApiKey = (
id: string,
options?: UseMutationOptions<
Response<AdminPublishableApiKeysRes>,
Error,
AdminPostPublishableApiKeysPublishableApiKeyReq
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(
(payload: AdminPostPublishableApiKeysPublishableApiKeyReq) =>
client.admin.publishableApiKeys.update(id, payload),
buildOptions(
queryClient,
[
adminPublishableApiKeysKeys.lists(),
adminPublishableApiKeysKeys.detail(id),
adminPublishableApiKeysKeys.details(),
],
options
)
)
}
export const useAdminDeletePublishableApiKey = ( export const useAdminDeletePublishableApiKey = (
id: string, id: string,
options?: UseMutationOptions< options?: UseMutationOptions<
@@ -1,12 +1,13 @@
import { renderHook } from "@testing-library/react-hooks" import { renderHook } from "@testing-library/react-hooks"
import { createWrapper } from "../../../utils"
import { import {
useAdminDeletePublishableApiKey, useAdminDeletePublishableApiKey,
useAdminRevokePublishableApiKey, useAdminRevokePublishableApiKey,
useAdminUpdatePublishableApiKey,
useAdminCreatePublishableApiKey,
} from "../../../../src" } from "../../../../src"
import { createWrapper } from "../../../utils"
import { fixtures } from "../../../../mocks/data" import { fixtures } from "../../../../mocks/data"
import { useAdminCreatePublishableApiKey } from "../../../../src"
describe("useAdminCreatePublishableApiKey hook", () => { describe("useAdminCreatePublishableApiKey hook", () => {
test("Created a publishable api key", async () => { test("Created a publishable api key", async () => {
@@ -17,7 +18,7 @@ describe("useAdminCreatePublishableApiKey hook", () => {
} }
) )
result.current.mutate({}) result.current.mutate({ title: "Mandatory title" })
await waitFor(() => result.current.isSuccess) await waitFor(() => result.current.isSuccess)
@@ -25,6 +26,7 @@ describe("useAdminCreatePublishableApiKey hook", () => {
expect(result.current.data).toEqual( expect(result.current.data).toEqual(
expect.objectContaining({ expect.objectContaining({
publishable_api_key: { publishable_api_key: {
title: "Mandatory title",
...fixtures.get("publishable_api_key"), ...fixtures.get("publishable_api_key"),
}, },
}) })
@@ -32,6 +34,34 @@ describe("useAdminCreatePublishableApiKey hook", () => {
}) })
}) })
describe("useAdminUpdatePublishableApiKey hook", () => {
test("updates an publishable key and returns it", async () => {
const pubKey = {
title: "changed title",
}
const { result, waitFor } = renderHook(
() =>
useAdminUpdatePublishableApiKey(fixtures.get("publishable_api_key").id),
{
wrapper: createWrapper(),
}
)
result.current.mutate(pubKey)
await waitFor(() => result.current.isSuccess)
expect(result.current.data.response.status).toEqual(200)
expect(result.current.data.publishable_api_key).toEqual(
expect.objectContaining({
...fixtures.get("publishable_api_key"),
...pubKey,
})
)
})
})
describe("useAdminRevokePublishableApiKey hook", () => { describe("useAdminRevokePublishableApiKey hook", () => {
test("Revoke a publishable api key", async () => { test("Revoke a publishable api key", async () => {
const id = "pubkey_1234" const id = "pubkey_1234"
@@ -1,5 +1,6 @@
import { Request, Response } from "express" import { Request, Response } from "express"
import { EntityManager } from "typeorm" import { EntityManager } from "typeorm"
import { IsString } from "class-validator"
import PublishableApiKeyService from "../../../../services/publishable-api-key" import PublishableApiKeyService from "../../../../services/publishable-api-key"
@@ -8,6 +9,16 @@ import PublishableApiKeyService from "../../../../services/publishable-api-key"
* operationId: "PostPublishableApiKeys" * operationId: "PostPublishableApiKeys"
* summary: "Create a PublishableApiKey" * summary: "Create a PublishableApiKey"
* description: "Creates a PublishableApiKey." * description: "Creates a PublishableApiKey."
* requestBody:
* content:
* application/json:
* schema:
* required:
* - title
* properties:
* title:
* description: A title for the publishable api key
* type: string
* x-authenticated: true * x-authenticated: true
* x-codeSamples: * x-codeSamples:
* - lang: JavaScript * - lang: JavaScript
@@ -59,14 +70,20 @@ export default async (req: Request, res: Response) => {
) as PublishableApiKeyService ) as PublishableApiKeyService
const manager = req.scope.resolve("manager") as EntityManager const manager = req.scope.resolve("manager") as EntityManager
const data = req.validatedBody as AdminPostPublishableApiKeysReq
const loggedInUserId = (req.user?.id ?? req.user?.userId) as string const loggedInUserId = (req.user?.id ?? req.user?.userId) as string
const pubKey = await manager.transaction(async (transactionManager) => { const pubKey = await manager.transaction(async (transactionManager) => {
return await publishableApiKeyService return await publishableApiKeyService
.withTransaction(transactionManager) .withTransaction(transactionManager)
.create({ loggedInUserId }) .create(data, { loggedInUserId })
}) })
return res.status(200).json({ publishable_api_key: pubKey }) return res.status(200).json({ publishable_api_key: pubKey })
} }
export class AdminPostPublishableApiKeysReq {
@IsString()
title: string
}
@@ -2,10 +2,15 @@ import { Router } from "express"
import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled" import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled"
import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys" import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys"
import middlewares, { transformQuery } from "../../../middlewares" import middlewares, {
transformBody,
transformQuery,
} from "../../../middlewares"
import { GetPublishableApiKeysParams } from "./list-publishable-api-keys" import { GetPublishableApiKeysParams } from "./list-publishable-api-keys"
import { PublishableApiKey } from "../../../../models" import { PublishableApiKey } from "../../../../models"
import { DeleteResponse, PaginatedResponse } from "../../../../types/common" import { DeleteResponse, PaginatedResponse } from "../../../../types/common"
import { AdminPostPublishableApiKeysReq } from "./create-publishable-api-key"
import { AdminPostPublishableApiKeysPublishableApiKeyReq } from "./update-publishable-api-key"
const route = Router() const route = Router()
@@ -18,6 +23,7 @@ export default (app) => {
route.post( route.post(
"/", "/",
transformBody(AdminPostPublishableApiKeysReq),
middlewares.wrap(require("./create-publishable-api-key").default) middlewares.wrap(require("./create-publishable-api-key").default)
) )
@@ -26,6 +32,12 @@ export default (app) => {
middlewares.wrap(require("./get-publishable-api-key").default) middlewares.wrap(require("./get-publishable-api-key").default)
) )
route.post(
"/:id",
transformBody(AdminPostPublishableApiKeysPublishableApiKeyReq),
middlewares.wrap(require("./update-publishable-api-key").default)
)
route.delete( route.delete(
"/:id", "/:id",
middlewares.wrap(require("./delete-publishable-api-key").default) middlewares.wrap(require("./delete-publishable-api-key").default)
@@ -54,3 +66,5 @@ export type AdminPublishableApiKeysListRes = PaginatedResponse & {
export type AdminPublishableApiKeyDeleteRes = DeleteResponse export type AdminPublishableApiKeyDeleteRes = DeleteResponse
export * from "./list-publishable-api-keys" export * from "./list-publishable-api-keys"
export * from "./create-publishable-api-key"
export * from "./update-publishable-api-key"
@@ -11,7 +11,7 @@ import PublishableApiKeyService from "../../../../services/publishable-api-key"
* description: "List PublishableApiKeys." * description: "List PublishableApiKeys."
* x-authenticated: true * x-authenticated: true
* parameters: * parameters:
* - (query) order_id {string} List publishable keys by id. * - (query) q {string} Query used for searching publishable api keys by title.
* - (query) limit=20 {number} The number of items in the response * - (query) limit=20 {number} The number of items in the response
* - (query) offset=0 {number} The offset of items in response * - (query) offset=0 {number} The offset of items in response
* - (query) expand {string} Comma separated list of relations to include in the results. * - (query) expand {string} Comma separated list of relations to include in the results.
@@ -84,4 +84,8 @@ export default async (req: Request, res: Response) => {
export class GetPublishableApiKeysParams extends extendedFindParamsMixin({ export class GetPublishableApiKeysParams extends extendedFindParamsMixin({
limit: 20, limit: 20,
offset: 0, offset: 0,
}) {} }) {
@IsString()
@IsOptional()
q?: string
}
@@ -0,0 +1,97 @@
import { Request, Response } from "express"
import { IsOptional, IsString } from "class-validator"
import { EntityManager } from "typeorm"
import PublishableApiKeyService from "../../../../services/publishable-api-key"
/**
* @oas [post] /publishable-api-key/{id}
* operationId: "PostPublishableApiKysPublishableApiKey"
* summary: "Updates a PublishableApiKey"
* description: "Updates a PublishableApiKey."
* x-authenticated: true
* parameters:
* - (path) id=* {string} The ID of the PublishableApiKey.
* requestBody:
* content:
* application/json:
* schema:
* properties:
* title:
* description: A title to update for the key.
* type: string
* x-codeSamples:
* - lang: JavaScript
* label: JS Client
* source: |
* import Medusa from "@medusajs/medusa-js"
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
* // must be previously logged in or use api token
* medusa.admin.publishableApiKey.update(publishable_key_id, {
* title: "new title"
* })
* .then(({ publishable_api_key }) => {
* console.log(publishable_api_key.id)
* })
* - lang: Shell
* label: cURL
* source: |
* curl --location --request POST 'https://medusa-url.com/admin/publishable-api-key/{id}' \
* --header 'Authorization: Bearer {api_token}' \
* --header 'Content-Type: application/json' \
* --data-raw '{
* "title": "updated title"
* }'
* security:
* - api_token: []
* - cookie_auth: []
* tags:
* - PublishableApiKey
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* properties:
* publishable_api_key:
* $ref: "#/components/schemas/publishable_api_key"
* "400":
* $ref: "#/components/responses/400_error"
* "401":
* $ref: "#/components/responses/unauthorized"
* "404":
* $ref: "#/components/responses/not_found_error"
* "409":
* $ref: "#/components/responses/invalid_state_error"
* "422":
* $ref: "#/components/responses/invalid_request_error"
* "500":
* $ref: "#/components/responses/500_error"
*/
export default async (req: Request, res: Response) => {
const { id } = req.params
const { validatedBody } = req as {
validatedBody: AdminPostPublishableApiKeysPublishableApiKeyReq
}
const publishableApiKeysService: PublishableApiKeyService = req.scope.resolve(
"publishableApiKeyService"
)
const manager: EntityManager = req.scope.resolve("manager")
const updatedKey = await manager.transaction(async (transactionManager) => {
return await publishableApiKeysService
.withTransaction(transactionManager)
.update(id, validatedBody)
})
res.status(200).json({ publishable_api_key: updatedKey })
}
export class AdminPostPublishableApiKeysPublishableApiKeyReq {
@IsString()
@IsOptional()
title?: string
}
@@ -12,7 +12,7 @@ export class publishableApiKey1667815005070 implements MigrationInterface {
`CREATE TABLE "publishable_api_key_sales_channel" ("sales_channel_id" character varying NOT NULL, "publishable_key_id" character varying NOT NULL, CONSTRAINT "PK_68eaeb14bdac8954460054c567c" PRIMARY KEY ("sales_channel_id", "publishable_key_id"))` `CREATE TABLE "publishable_api_key_sales_channel" ("sales_channel_id" character varying NOT NULL, "publishable_key_id" character varying NOT NULL, CONSTRAINT "PK_68eaeb14bdac8954460054c567c" PRIMARY KEY ("sales_channel_id", "publishable_key_id"))`
) )
await queryRunner.query( await queryRunner.query(
`CREATE TABLE "publishable_api_key" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "created_by" character varying, "revoked_by" character varying, "revoked_at" TIMESTAMP WITH TIME ZONE, CONSTRAINT "PK_9e613278673a87de92c606b4494" PRIMARY KEY ("id"))` `CREATE TABLE "publishable_api_key" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "created_by" character varying, "revoked_by" character varying, "revoked_at" TIMESTAMP WITH TIME ZONE, "title" character varying NOT NULL, CONSTRAINT "PK_9e613278673a87de92c606b4494" PRIMARY KEY ("id"))`
) )
} }
@@ -17,9 +17,12 @@ export class PublishableApiKey extends BaseEntity {
@Column({ type: resolveDbType("timestamptz"), nullable: true }) @Column({ type: resolveDbType("timestamptz"), nullable: true })
revoked_at?: Date revoked_at?: Date
@Column()
title: string
@BeforeInsert() @BeforeInsert()
private beforeInsert(): void { private beforeInsert(): void {
this.id = generateEntityId(this.id, "pubkey") this.id = generateEntityId(this.id, "pk")
} }
} }
@@ -32,7 +35,7 @@ export class PublishableApiKey extends BaseEntity {
* id: * id:
* type: string * type: string
* description: The key's ID * description: The key's ID
* example: pak_01G1G5V27GYX4QXNARRQCW1N8T * example: pk_01G1G5V27GYX4QXNARRQCW1N8T
* created_by: * created_by:
* type: string * type: string
* description: "The unique identifier of the user that created the key." * description: "The unique identifier of the user that created the key."
@@ -48,13 +48,17 @@ describe("PublishableApiKeyService", () => {
}) })
it("should create a publishable api key and call the repository with the right arguments as well as the event bus service", async () => { it("should create a publishable api key and call the repository with the right arguments as well as the event bus service", async () => {
await publishableApiKeyService.create({ await publishableApiKeyService.create(
loggedInUserId: IdMap.getId("admin_user"), { title: "API key title" },
}) {
loggedInUserId: IdMap.getId("admin_user"),
}
)
expect(publishableApiKeyRepository.create).toHaveBeenCalledTimes(1) expect(publishableApiKeyRepository.create).toHaveBeenCalledTimes(1)
expect(publishableApiKeyRepository.create).toHaveBeenCalledWith({ expect(publishableApiKeyRepository.create).toHaveBeenCalledWith({
created_by: IdMap.getId("admin_user"), created_by: IdMap.getId("admin_user"),
title: "API key title",
}) })
expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1)
expect(EventBusServiceMock.emit).toHaveBeenCalledWith( expect(EventBusServiceMock.emit).toHaveBeenCalledWith(
@@ -63,6 +67,19 @@ describe("PublishableApiKeyService", () => {
) )
}) })
it("should update a publishable api key", async () => {
await publishableApiKeyService.update(pubKeyToRetrieve.id, {
title: "new title",
})
expect(publishableApiKeyRepository.save).toHaveBeenLastCalledWith(
expect.objectContaining({
id: pubKeyToRetrieve.id,
title: "new title",
})
)
})
it("should revoke a publishable api key", async () => { it("should revoke a publishable api key", async () => {
await publishableApiKeyService.revoke("id", { await publishableApiKeyService.revoke("id", {
loggedInUserId: IdMap.getId("admin_user"), loggedInUserId: IdMap.getId("admin_user"),
@@ -1,4 +1,4 @@
import { EntityManager } from "typeorm" import { EntityManager, ILike } from "typeorm"
import { MedusaError } from "medusa-core-utils" import { MedusaError } from "medusa-core-utils"
import { PublishableApiKeyRepository } from "../repositories/publishable-api-key" import { PublishableApiKeyRepository } from "../repositories/publishable-api-key"
@@ -6,7 +6,11 @@ import { FindConfig, Selector } from "../types/common"
import { PublishableApiKey } from "../models" import { PublishableApiKey } from "../models"
import { TransactionBaseService } from "../interfaces" import { TransactionBaseService } from "../interfaces"
import EventBusService from "./event-bus" import EventBusService from "./event-bus"
import { buildQuery } from "../utils" import { buildQuery, isDefined, isString } from "../utils"
import {
CreatePublishableApiKeyInput,
UpdatePublishableApiKeyInput,
} from "../types/publishable-api-key"
type InjectedDependencies = { type InjectedDependencies = {
manager: EntityManager manager: EntityManager
@@ -45,17 +49,22 @@ class PublishableApiKeyService extends TransactionBaseService {
/** /**
* Create a PublishableApiKey record. * Create a PublishableApiKey record.
* *
* @params context - key creation context object * @param data - partial data for creating the entity
* @param context - key creation context object
*/ */
async create(context: { async create(
loggedInUserId: string data: CreatePublishableApiKeyInput,
}): Promise<PublishableApiKey | never> { context: {
loggedInUserId: string
}
): Promise<PublishableApiKey | never> {
return await this.atomicPhase_(async (manager) => { return await this.atomicPhase_(async (manager) => {
const publishableApiKeyRepo = manager.getCustomRepository( const publishableApiKeyRepo = manager.getCustomRepository(
this.publishableApiKeyRepository_ this.publishableApiKeyRepository_
) )
const publishableApiKey = publishableApiKeyRepo.create({ const publishableApiKey = publishableApiKeyRepo.create({
...data,
created_by: context.loggedInUserId, created_by: context.loggedInUserId,
}) })
@@ -122,7 +131,7 @@ class PublishableApiKeyService extends TransactionBaseService {
* @return an array containing publishable API keys and a total count of records that matches the query * @return an array containing publishable API keys and a total count of records that matches the query
*/ */
async listAndCount( async listAndCount(
selector: Selector<PublishableApiKey>, selector: Selector<PublishableApiKey> & { q?: string },
config: FindConfig<PublishableApiKey> = { config: FindConfig<PublishableApiKey> = {
skip: 0, skip: 0,
take: 20, take: 20,
@@ -133,11 +142,44 @@ class PublishableApiKeyService extends TransactionBaseService {
this.publishableApiKeyRepository_ this.publishableApiKeyRepository_
) )
let q
if (isString(selector.q)) {
q = selector.q
delete selector.q
}
const query = buildQuery(selector, config) const query = buildQuery(selector, config)
if (q) {
query.where.title = ILike(`%${q}%`)
}
return await pubKeyRepo.findAndCount(query) return await pubKeyRepo.findAndCount(query)
} }
async update(
publishableApiKeyId: string,
data: UpdatePublishableApiKeyInput
): Promise<PublishableApiKey> {
{
return await this.atomicPhase_(async (manager) => {
const publishableApiKeyRepository = manager.getCustomRepository(
this.publishableApiKeyRepository_
)
const pubKey = await this.retrieve(publishableApiKeyId)
for (const key of Object.keys(data)) {
if (isDefined(data[key])) {
pubKey[key] = data[key]
}
}
return await publishableApiKeyRepository.save(pubKey)
})
}
}
/** /**
* Delete Publishable API key. * Delete Publishable API key.
* *
@@ -0,0 +1,7 @@
export type CreatePublishableApiKeyInput = {
title: string
}
export type UpdatePublishableApiKeyInput = {
title?: string
}