diff --git a/packages/core/js-sdk/src/admin/index.ts b/packages/core/js-sdk/src/admin/index.ts index 8d8d28a476..6730c91728 100644 --- a/packages/core/js-sdk/src/admin/index.ts +++ b/packages/core/js-sdk/src/admin/index.ts @@ -5,6 +5,7 @@ import { FulfillmentProvider } from "./fulfillment-provider" import { FulfillmentSet } from "./fulfillment-set" import { InventoryItem } from "./inventory-item" import { Invite } from "./invite" +import { Notification } from "./notification" import { Order } from "./order" import { PriceList } from "./price-list" import { PricePreference } from "./price-preference" @@ -44,6 +45,7 @@ export class Admin { public shippingOption: ShippingOption public shippingProfile: ShippingProfile public inventoryItem: InventoryItem + public notification: Notification public order: Order public taxRate: TaxRate public taxRegion: TaxRegion @@ -71,6 +73,7 @@ export class Admin { this.shippingOption = new ShippingOption(client) this.shippingProfile = new ShippingProfile(client) this.inventoryItem = new InventoryItem(client) + this.notification = new Notification(client) this.order = new Order(client) this.taxRate = new TaxRate(client) this.taxRegion = new TaxRegion(client) diff --git a/packages/core/js-sdk/src/admin/notification.ts b/packages/core/js-sdk/src/admin/notification.ts new file mode 100644 index 0000000000..f882dee785 --- /dev/null +++ b/packages/core/js-sdk/src/admin/notification.ts @@ -0,0 +1,39 @@ +import { HttpTypes } from "@medusajs/types" +import { Client } from "../client" +import { ClientHeaders } from "../types" + +export class Notification { + private client: Client + constructor(client: Client) { + this.client = client + } + + async retrieve( + id: string, + query?: HttpTypes.AdminNotificationParams, + headers?: ClientHeaders + ) { + return await this.client.fetch( + `/admin/notifications/${id}`, + { + method: "GET", + headers, + query, + } + ) + } + + async list( + query?: HttpTypes.AdminNotificationListParams, + headers?: ClientHeaders + ) { + return await this.client.fetch( + `/admin/notifications`, + { + method: "GET", + headers, + query, + } + ) + } +} diff --git a/packages/core/types/src/http/index.ts b/packages/core/types/src/http/index.ts index fae4cec70d..efcfa0e731 100644 --- a/packages/core/types/src/http/index.ts +++ b/packages/core/types/src/http/index.ts @@ -12,6 +12,7 @@ export * from "./fulfillment-set" export * from "./inventory" export * from "./inventory-level" export * from "./invite" +export * from "./notification" export * from "./order" export * from "./payment" export * from "./price-list" @@ -32,4 +33,3 @@ export * from "./store" export * from "./tax-rate" export * from "./tax-region" export * from "./user" - diff --git a/packages/core/types/src/http/notification/admin/entities.ts b/packages/core/types/src/http/notification/admin/entities.ts new file mode 100644 index 0000000000..dddfc21e20 --- /dev/null +++ b/packages/core/types/src/http/notification/admin/entities.ts @@ -0,0 +1,15 @@ +export interface AdminNotification { + id: string + to: string + channel: string + template: string + data?: Record | null + trigger_type?: string | null + resource_id?: string | null + resource_type?: string | null + receiver_id?: string | null + original_notification_id?: string | null + external_id?: string | null + provider_id: string + created_at: Date +} diff --git a/packages/core/types/src/http/notification/admin/index.ts b/packages/core/types/src/http/notification/admin/index.ts new file mode 100644 index 0000000000..020c34f02c --- /dev/null +++ b/packages/core/types/src/http/notification/admin/index.ts @@ -0,0 +1,3 @@ +export * from "./entities" +export * from "./queries" +export * from "./responses" diff --git a/packages/core/types/src/http/notification/admin/queries.ts b/packages/core/types/src/http/notification/admin/queries.ts new file mode 100644 index 0000000000..2507417d20 --- /dev/null +++ b/packages/core/types/src/http/notification/admin/queries.ts @@ -0,0 +1,12 @@ +import { BaseFilterable } from "../../../dal" +import { FindParams, SelectParams } from "../../common" + +export interface AdminNotificationListParams + extends BaseFilterable, + FindParams { + q?: string + id?: string | string[] + channel?: string | string[] +} + +export interface AdminNotificationParams extends SelectParams {} diff --git a/packages/core/types/src/http/notification/admin/responses.ts b/packages/core/types/src/http/notification/admin/responses.ts new file mode 100644 index 0000000000..d3e4f4ccc1 --- /dev/null +++ b/packages/core/types/src/http/notification/admin/responses.ts @@ -0,0 +1,11 @@ +import { PaginatedResponse } from "../../common" +import { AdminNotification } from "./entities" + +export interface AdminNotificationResponse { + notification: AdminNotification +} + +export interface AdminNotificationListResponse + extends PaginatedResponse<{ + notifications: AdminNotification[] + }> {} diff --git a/packages/core/types/src/http/notification/index.ts b/packages/core/types/src/http/notification/index.ts new file mode 100644 index 0000000000..26b8eb9dad --- /dev/null +++ b/packages/core/types/src/http/notification/index.ts @@ -0,0 +1 @@ +export * from "./admin" diff --git a/packages/medusa/src/api/admin/notifications/[id]/route.ts b/packages/medusa/src/api/admin/notifications/[id]/route.ts new file mode 100644 index 0000000000..8735efd6e0 --- /dev/null +++ b/packages/medusa/src/api/admin/notifications/[id]/route.ts @@ -0,0 +1,19 @@ +import { + AuthenticatedMedusaRequest, + MedusaResponse, +} from "../../../../types/routing" +import { AdminGetNotificationParamsType } from "../validators" +import { refetchEntity } from "../../../utils/refetch-entity" + +export const GET = async ( + req: AuthenticatedMedusaRequest, + res: MedusaResponse +) => { + const notification = await refetchEntity( + "notification", + req.params.id, + req.scope, + req.remoteQueryConfig.fields + ) + res.status(200).json({ notification }) +} diff --git a/packages/medusa/src/api/admin/notifications/middlewares.ts b/packages/medusa/src/api/admin/notifications/middlewares.ts new file mode 100644 index 0000000000..b9423db726 --- /dev/null +++ b/packages/medusa/src/api/admin/notifications/middlewares.ts @@ -0,0 +1,30 @@ +import { MiddlewareRoute } from "../../../loaders/helpers/routing/types" +import { validateAndTransformQuery } from "../../utils/validate-query" +import * as QueryConfig from "./query-config" +import { + AdminGetNotificationParams, + AdminGetNotificationsParams, +} from "./validators" + +export const adminNotificationRoutesMiddlewares: MiddlewareRoute[] = [ + { + method: ["GET"], + matcher: "/admin/notifications", + middlewares: [ + validateAndTransformQuery( + AdminGetNotificationsParams, + QueryConfig.listTransformQueryConfig + ), + ], + }, + { + method: ["GET"], + matcher: "/admin/notifications/:id", + middlewares: [ + validateAndTransformQuery( + AdminGetNotificationParams, + QueryConfig.retrieveTransformQueryConfig + ), + ], + }, +] diff --git a/packages/medusa/src/api/admin/notifications/query-config.ts b/packages/medusa/src/api/admin/notifications/query-config.ts new file mode 100644 index 0000000000..b99027960b --- /dev/null +++ b/packages/medusa/src/api/admin/notifications/query-config.ts @@ -0,0 +1,23 @@ +export const defaultAdminNotificationFields = [ + "id", + "to", + "channel", + "template", + "data", + "trigger_type", + "resource_id", + "resource_type", + "receiver_id", + "created_at", + "updated_at", +] + +export const retrieveTransformQueryConfig = { + defaults: defaultAdminNotificationFields, + isList: false, +} + +export const listTransformQueryConfig = { + ...retrieveTransformQueryConfig, + isList: true, +} diff --git a/packages/medusa/src/api/admin/notifications/route.ts b/packages/medusa/src/api/admin/notifications/route.ts new file mode 100644 index 0000000000..e5d29f9007 --- /dev/null +++ b/packages/medusa/src/api/admin/notifications/route.ts @@ -0,0 +1,25 @@ +import { + AuthenticatedMedusaRequest, + MedusaResponse, +} from "../../../types/routing" +import { AdminGetNotificationsParamsType } from "./validators" +import { refetchEntities } from "../../utils/refetch-entity" + +export const GET = async ( + req: AuthenticatedMedusaRequest, + res: MedusaResponse +) => { + const { rows: notifications, metadata } = await refetchEntities( + "notification", + req.filterableFields, + req.scope, + req.remoteQueryConfig.fields, + req.remoteQueryConfig.pagination + ) + res.json({ + notifications, + count: metadata.count, + offset: metadata.skip, + limit: metadata.take, + }) +} diff --git a/packages/medusa/src/api/admin/notifications/validators.ts b/packages/medusa/src/api/admin/notifications/validators.ts new file mode 100644 index 0000000000..e360309d22 --- /dev/null +++ b/packages/medusa/src/api/admin/notifications/validators.ts @@ -0,0 +1,23 @@ +import { z } from "zod" +import { createFindParams, createSelectParams } from "../../utils/validators" + +export type AdminGetNotificationParamsType = z.infer< + typeof AdminGetNotificationParams +> +export const AdminGetNotificationParams = createSelectParams() + +export type AdminGetNotificationsParamsType = z.infer< + typeof AdminGetNotificationsParams +> +export const AdminGetNotificationsParams = createFindParams({ + limit: 50, + offset: 0, +}).merge( + z.object({ + q: z.string().optional(), + id: z.union([z.string(), z.array(z.string())]).optional(), + channel: z.union([z.string(), z.array(z.string())]).optional(), + $and: z.lazy(() => AdminGetNotificationsParams.array()).optional(), + $or: z.lazy(() => AdminGetNotificationsParams.array()).optional(), + }) +) diff --git a/packages/medusa/src/api/middlewares.ts b/packages/medusa/src/api/middlewares.ts index 9c9aa2312f..c96ae6c4e1 100644 --- a/packages/medusa/src/api/middlewares.ts +++ b/packages/medusa/src/api/middlewares.ts @@ -11,6 +11,7 @@ import { adminFulfillmentSetsRoutesMiddlewares } from "./admin/fulfillment-sets/ import { adminFulfillmentsRoutesMiddlewares } from "./admin/fulfillments/middlewares" import { adminInventoryRoutesMiddlewares } from "./admin/inventory-items/middlewares" import { adminInviteRoutesMiddlewares } from "./admin/invites/middlewares" +import { adminNotificationRoutesMiddlewares } from "./admin/notifications/middlewares" import { adminOrderRoutesMiddlewares } from "./admin/orders/middlewares" import { adminPaymentRoutesMiddlewares } from "./admin/payments/middlewares" import { adminPriceListsRoutesMiddlewares } from "./admin/price-lists/middlewares" @@ -92,6 +93,7 @@ export const config: MiddlewaresConfig = { ...adminProductTagRoutesMiddlewares, ...adminUploadRoutesMiddlewares, ...adminFulfillmentSetsRoutesMiddlewares, + ...adminNotificationRoutesMiddlewares, ...adminOrderRoutesMiddlewares, ...adminReservationRoutesMiddlewares, ...adminProductCategoryRoutesMiddlewares, diff --git a/packages/modules/notification/src/models/notification.ts b/packages/modules/notification/src/models/notification.ts index 2b214974d6..a03294d41e 100644 --- a/packages/modules/notification/src/models/notification.ts +++ b/packages/modules/notification/src/models/notification.ts @@ -5,7 +5,7 @@ import { NotificationProvider } from "./notification-provider" export const Notification = model.define("notification", { id: model.id({ prefix: "noti" }).primaryKey(), // This can be an email, phone number, or username, depending on the channel. - to: model.text(), + to: model.text().searchable(), channel: model.text(), // The template name in the provider's system. template: model.text(), @@ -14,7 +14,7 @@ export const Notification = model.define("notification", { // This can be the event name, the workflow, or anything else that can help to identify what triggered the notification. trigger_type: model.text().nullable(), // The ID of the resource this notification is for, if applicable. Useful for displaying relevant information in the UI - resource_id: model.text().nullable(), + resource_id: model.text().searchable().nullable(), // The typeame of the resource this notification is for, if applicable, eg. "order" resource_type: model.text().nullable(), // The ID of the receiver of the notification, if applicable. This can be a customer, user, a company, or anything else.