chore: Migrate notification module to DML (#7835)
This commit is contained in:
@@ -10,9 +10,7 @@ import { medusaIntegrationTestRunner, TestEventUtils } from "medusa-test-utils"
|
|||||||
|
|
||||||
jest.setTimeout(50000)
|
jest.setTimeout(50000)
|
||||||
|
|
||||||
const env = { MEDUSA_FF_MEDUSA_V2: true }
|
|
||||||
medusaIntegrationTestRunner({
|
medusaIntegrationTestRunner({
|
||||||
env,
|
|
||||||
testSuite: ({ getContainer }) => {
|
testSuite: ({ getContainer }) => {
|
||||||
describe("Notifications", () => {
|
describe("Notifications", () => {
|
||||||
let service: INotificationModuleService
|
let service: INotificationModuleService
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
InjectTransactionManager,
|
InjectTransactionManager,
|
||||||
MedusaContext,
|
MedusaContext,
|
||||||
} from "./decorators"
|
} from "./decorators"
|
||||||
|
import { DmlEntity, toMikroORMEntity } from "../dml"
|
||||||
|
|
||||||
type SelectorAndData = {
|
type SelectorAndData = {
|
||||||
selector: FilterQuery<any> | BaseFilterable<FilterQuery<any>>
|
selector: FilterQuery<any> | BaseFilterable<FilterQuery<any>>
|
||||||
@@ -35,12 +36,16 @@ type SelectorAndData = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function MedusaInternalService<TContainer extends object = object>(
|
export function MedusaInternalService<TContainer extends object = object>(
|
||||||
model: any
|
rawModel: any
|
||||||
): {
|
): {
|
||||||
new <TEntity extends object = any>(
|
new <TEntity extends object = any>(
|
||||||
container: TContainer
|
container: TContainer
|
||||||
): ModulesSdkTypes.IMedusaInternalService<TEntity, TContainer>
|
): ModulesSdkTypes.IMedusaInternalService<TEntity, TContainer>
|
||||||
} {
|
} {
|
||||||
|
const model = DmlEntity.isDmlEntity(rawModel)
|
||||||
|
? toMikroORMEntity(rawModel)
|
||||||
|
: rawModel
|
||||||
|
|
||||||
const injectedRepositoryName = `${lowerCaseFirst(model.name)}Repository`
|
const injectedRepositoryName = `${lowerCaseFirst(model.name)}Repository`
|
||||||
const propertyRepositoryName = `__${injectedRepositoryName}__`
|
const propertyRepositoryName = `__${injectedRepositoryName}__`
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
import * as entities from "./src/models"
|
import * as entities from "./src/models"
|
||||||
import { TSMigrationGenerator } from "@medusajs/utils"
|
import { defineMikroOrmCliConfig } from "@medusajs/utils"
|
||||||
|
|
||||||
module.exports = {
|
module.exports = defineMikroOrmCliConfig({
|
||||||
entities: Object.values(entities),
|
entities: Object.values(entities),
|
||||||
schema: "public",
|
schema: "public",
|
||||||
clientUrl: "postgres://postgres@localhost/medusa-notification",
|
databaseName: "medusa-notification",
|
||||||
type: "postgresql",
|
})
|
||||||
migrations: {
|
|
||||||
generator: TSMigrationGenerator,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import { moduleProviderLoader } from "@medusajs/modules-sdk"
|
import { moduleProviderLoader } from "@medusajs/modules-sdk"
|
||||||
import { LoaderOptions, ModuleProvider, ModulesSdkTypes } from "@medusajs/types"
|
import {
|
||||||
|
DAL,
|
||||||
|
InferEntityType,
|
||||||
|
LoaderOptions,
|
||||||
|
ModuleProvider,
|
||||||
|
ModulesSdkTypes,
|
||||||
|
} from "@medusajs/types"
|
||||||
import {
|
import {
|
||||||
ContainerRegistrationKeys,
|
ContainerRegistrationKeys,
|
||||||
lowerCaseFirst,
|
lowerCaseFirst,
|
||||||
@@ -62,8 +68,9 @@ async function syncDatabaseProviders({
|
|||||||
const providerServiceRegistrationKey = lowerCaseFirst(
|
const providerServiceRegistrationKey = lowerCaseFirst(
|
||||||
NotificationProviderService.name
|
NotificationProviderService.name
|
||||||
)
|
)
|
||||||
const providerService: ModulesSdkTypes.IMedusaInternalService<NotificationProvider> =
|
const providerService: ModulesSdkTypes.IMedusaInternalService<
|
||||||
container.resolve(providerServiceRegistrationKey)
|
typeof NotificationProvider
|
||||||
|
> = container.resolve(providerServiceRegistrationKey)
|
||||||
|
|
||||||
const logger = container.resolve(ContainerRegistrationKeys.LOGGER) ?? console
|
const logger = container.resolve(ContainerRegistrationKeys.LOGGER) ?? console
|
||||||
const normalizedProviders = providers.map((provider) => {
|
const normalizedProviders = providers.map((provider) => {
|
||||||
@@ -106,7 +113,10 @@ async function syncDatabaseProviders({
|
|||||||
if (providersToDisable.length) {
|
if (providersToDisable.length) {
|
||||||
promises.push(
|
promises.push(
|
||||||
providerService.update(
|
providerService.update(
|
||||||
providersToDisable.map((p) => ({ id: p.id, is_enabled: false }))
|
providersToDisable.map((p) => ({
|
||||||
|
entity: p,
|
||||||
|
update: { is_enabled: false },
|
||||||
|
}))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,40 @@
|
|||||||
"autoincrement": false,
|
"autoincrement": false,
|
||||||
"primary": false,
|
"primary": false,
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
|
"default": "'{}'",
|
||||||
"mappedType": "array"
|
"mappedType": "array"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"deleted_at": {
|
||||||
|
"name": "deleted_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"length": 6,
|
||||||
|
"mappedType": "datetime"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "notification_provider",
|
"name": "notification_provider",
|
||||||
@@ -198,6 +231,27 @@
|
|||||||
"length": 6,
|
"length": 6,
|
||||||
"default": "now()",
|
"default": "now()",
|
||||||
"mappedType": "datetime"
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"deleted_at": {
|
||||||
|
"name": "deleted_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"length": 6,
|
||||||
|
"mappedType": "datetime"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "notification",
|
"name": "notification",
|
||||||
@@ -209,15 +263,15 @@
|
|||||||
"composite": false,
|
"composite": false,
|
||||||
"primary": false,
|
"primary": false,
|
||||||
"unique": false,
|
"unique": false,
|
||||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_notification_receiver_id\" ON \"notification\" (receiver_id)"
|
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_notification_receiver_id\" ON \"notification\" (receiver_id) WHERE deleted_at IS NULL"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"keyName": "IDX_notification_idempotency_key",
|
"keyName": "IDX_notification_idempotency_key_unique",
|
||||||
"columnNames": [],
|
"columnNames": [],
|
||||||
"composite": false,
|
"composite": false,
|
||||||
"primary": false,
|
"primary": false,
|
||||||
"unique": false,
|
"unique": false,
|
||||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_notification_idempotency_key\" ON \"notification\" (idempotency_key)"
|
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_notification_idempotency_key_unique\" ON \"notification\" (idempotency_key) WHERE deleted_at IS NULL"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"keyName": "IDX_notification_provider_id",
|
"keyName": "IDX_notification_provider_id",
|
||||||
@@ -225,7 +279,7 @@
|
|||||||
"composite": false,
|
"composite": false,
|
||||||
"primary": false,
|
"primary": false,
|
||||||
"unique": false,
|
"unique": false,
|
||||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_notification_provider_id\" ON \"notification\" (provider_id)"
|
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_notification_provider_id\" ON \"notification\" (provider_id) WHERE deleted_at IS NULL"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"keyName": "notification_pkey",
|
"keyName": "notification_pkey",
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { Migration } from "@mikro-orm/migrations"
|
||||||
|
|
||||||
|
export class Migration20240628075401 extends Migration {
|
||||||
|
async up(): Promise<void> {
|
||||||
|
this.addSql(
|
||||||
|
'alter table if exists "notification_provider" add column if not exists "created_at" timestamptz not null default now(), add column "updated_at" timestamptz not null default now(), add column "deleted_at" timestamptz null;'
|
||||||
|
)
|
||||||
|
this.addSql(
|
||||||
|
'alter table if exists "notification_provider" alter column "channels" type text[] using ("channels"::text[]);'
|
||||||
|
)
|
||||||
|
this.addSql(
|
||||||
|
'alter table if exists "notification_provider" alter column "channels" set default \'{}\';'
|
||||||
|
)
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
'alter table if exists "notification" add column if not exists "updated_at" timestamptz not null default now(), add column "deleted_at" timestamptz null;'
|
||||||
|
)
|
||||||
|
this.addSql('drop index if exists "IDX_notification_idempotency_key";')
|
||||||
|
this.addSql(
|
||||||
|
'CREATE UNIQUE INDEX IF NOT EXISTS "IDX_notification_idempotency_key_unique" ON "notification" (idempotency_key) WHERE deleted_at IS NULL;'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,2 @@
|
|||||||
export { default as Notification } from "./notification"
|
export { Notification } from "./notification"
|
||||||
export { default as NotificationProvider } from "./notification-provider"
|
export { NotificationProvider } from "./notification-provider"
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +1,11 @@
|
|||||||
import { generateEntityId } from "@medusajs/utils"
|
import { model } from "@medusajs/utils"
|
||||||
import {
|
import { Notification } from "./notification"
|
||||||
ArrayType,
|
|
||||||
BeforeCreate,
|
|
||||||
Collection,
|
|
||||||
Entity,
|
|
||||||
OnInit,
|
|
||||||
OneToMany,
|
|
||||||
PrimaryKey,
|
|
||||||
Property,
|
|
||||||
} from "@mikro-orm/core"
|
|
||||||
import Notification from "./notification"
|
|
||||||
|
|
||||||
@Entity()
|
export const NotificationProvider = model.define("notificationProvider", {
|
||||||
export default class NotificationProvider {
|
id: model.id({ prefix: "notpro" }),
|
||||||
@PrimaryKey({ columnType: "text" })
|
handle: model.text(),
|
||||||
id: string
|
name: model.text(),
|
||||||
|
is_enabled: model.boolean().default(true),
|
||||||
@Property({ columnType: "text" })
|
channels: model.array().default([]),
|
||||||
handle: string
|
notifications: model.hasMany(() => Notification, { mappedBy: "provider" }),
|
||||||
|
})
|
||||||
@Property({ columnType: "text" })
|
|
||||||
name: string
|
|
||||||
|
|
||||||
@Property({ columnType: "boolean", defaultRaw: "true" })
|
|
||||||
is_enabled: boolean = true
|
|
||||||
|
|
||||||
@Property({ type: ArrayType })
|
|
||||||
channels: string[]
|
|
||||||
|
|
||||||
@OneToMany({
|
|
||||||
entity: () => Notification,
|
|
||||||
mappedBy: (notification) => notification.provider_id,
|
|
||||||
})
|
|
||||||
notifications = new Collection<Notification>(this)
|
|
||||||
|
|
||||||
@BeforeCreate()
|
|
||||||
onCreate() {
|
|
||||||
this.id = generateEntityId(this.id, "notpro")
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnInit()
|
|
||||||
onInit() {
|
|
||||||
this.id = generateEntityId(this.id, "notpro")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,109 +1,30 @@
|
|||||||
import {
|
import { model } from "@medusajs/utils"
|
||||||
createPsqlIndexStatementHelper,
|
import { NotificationProvider } from "./notification-provider"
|
||||||
generateEntityId,
|
|
||||||
} from "@medusajs/utils"
|
|
||||||
|
|
||||||
import {
|
|
||||||
BeforeCreate,
|
|
||||||
Entity,
|
|
||||||
ManyToOne,
|
|
||||||
OnInit,
|
|
||||||
PrimaryKey,
|
|
||||||
Property,
|
|
||||||
} from "@mikro-orm/core"
|
|
||||||
import NotificationProvider from "./notification-provider"
|
|
||||||
|
|
||||||
const NotificationProviderIdIndex = createPsqlIndexStatementHelper({
|
|
||||||
tableName: "notification",
|
|
||||||
columns: "provider_id",
|
|
||||||
})
|
|
||||||
|
|
||||||
const NotificationIdempotencyKeyIndex = createPsqlIndexStatementHelper({
|
|
||||||
tableName: "notification",
|
|
||||||
columns: "idempotency_key",
|
|
||||||
})
|
|
||||||
|
|
||||||
const NotificationReceiverIdIndex = createPsqlIndexStatementHelper({
|
|
||||||
tableName: "notification",
|
|
||||||
columns: "receiver_id",
|
|
||||||
})
|
|
||||||
|
|
||||||
// We don't need to support soft deletes here as this information is mainly used for auditing purposes.
|
|
||||||
// Instead, we probably want to have a TTL for each entry, so we don't bloat the DB (and also for GDPR reasons if TTL < 30 days).
|
|
||||||
@NotificationProviderIdIndex.MikroORMIndex()
|
|
||||||
@NotificationIdempotencyKeyIndex.MikroORMIndex()
|
|
||||||
@NotificationReceiverIdIndex.MikroORMIndex()
|
|
||||||
@Entity({ tableName: "notification" })
|
|
||||||
// Since there is a native `Notification` type, we have to call this something else here and in a couple of other places.
|
|
||||||
export default class Notification {
|
|
||||||
@PrimaryKey({ columnType: "text" })
|
|
||||||
id: string
|
|
||||||
|
|
||||||
|
// We probably want to have a TTL for each entry, so we don't bloat the DB (and also for GDPR reasons if TTL < 30 days).
|
||||||
|
export const Notification = model.define("notification", {
|
||||||
|
id: model.id({ prefix: "noti" }),
|
||||||
// This can be an email, phone number, or username, depending on the channel.
|
// This can be an email, phone number, or username, depending on the channel.
|
||||||
@Property({ columnType: "text" })
|
to: model.text(),
|
||||||
to: string
|
channel: model.text(),
|
||||||
|
|
||||||
@Property({ columnType: "text" })
|
|
||||||
channel: string
|
|
||||||
|
|
||||||
// The template name in the provider's system.
|
// The template name in the provider's system.
|
||||||
@Property({ columnType: "text" })
|
template: model.text(),
|
||||||
template: string
|
|
||||||
|
|
||||||
// The data that gets passed over to the provider for rendering the notification.
|
// The data that gets passed over to the provider for rendering the notification.
|
||||||
@Property({ columnType: "jsonb", nullable: true })
|
data: model.json().nullable(),
|
||||||
data: Record<string, unknown> | null
|
|
||||||
|
|
||||||
// This can be the event name, the workflow, or anything else that can help to identify what triggered the notification.
|
// This can be the event name, the workflow, or anything else that can help to identify what triggered the notification.
|
||||||
@Property({ columnType: "text", nullable: true })
|
trigger_type: model.text().nullable(),
|
||||||
trigger_type?: string | null
|
|
||||||
|
|
||||||
// The ID of the resource this notification is for, if applicable. Useful for displaying relevant information in the UI
|
// The ID of the resource this notification is for, if applicable. Useful for displaying relevant information in the UI
|
||||||
@Property({ columnType: "text", nullable: true })
|
resource_id: model.text().nullable(),
|
||||||
resource_id?: string | null
|
|
||||||
|
|
||||||
// The typeame of the resource this notification is for, if applicable, eg. "order"
|
// The typeame of the resource this notification is for, if applicable, eg. "order"
|
||||||
@Property({ columnType: "text", nullable: true })
|
resource_type: model.text().nullable(),
|
||||||
resource_type?: string | null
|
|
||||||
|
|
||||||
// The ID of the receiver of the notification, if applicable. This can be a customer, user, a company, or anything else.
|
// The ID of the receiver of the notification, if applicable. This can be a customer, user, a company, or anything else.
|
||||||
@Property({ columnType: "text", nullable: true })
|
receiver_id: model.text().index().nullable(),
|
||||||
receiver_id?: string | null
|
|
||||||
|
|
||||||
// The original notification, in case this is a retried notification.
|
// The original notification, in case this is a retried notification.
|
||||||
@Property({ columnType: "text", nullable: true })
|
original_notification_id: model.text().nullable(),
|
||||||
original_notification_id?: string | null
|
idempotency_key: model.text().unique().nullable(),
|
||||||
|
|
||||||
@Property({ columnType: "text", nullable: true })
|
|
||||||
idempotency_key?: string | null
|
|
||||||
|
|
||||||
// The ID of the notification in the external system, if applicable
|
// The ID of the notification in the external system, if applicable
|
||||||
@Property({ columnType: "text", nullable: true })
|
external_id: model.text().nullable(),
|
||||||
external_id?: string | null
|
provider: model
|
||||||
|
.belongsTo(() => NotificationProvider, { mappedBy: "notifications" })
|
||||||
@ManyToOne(() => NotificationProvider, {
|
.nullable(),
|
||||||
columnType: "text",
|
})
|
||||||
fieldName: "provider_id",
|
|
||||||
mapToPk: true,
|
|
||||||
nullable: true,
|
|
||||||
onDelete: "set null",
|
|
||||||
})
|
|
||||||
provider_id: string
|
|
||||||
|
|
||||||
@ManyToOne(() => NotificationProvider, { persist: false })
|
|
||||||
provider: NotificationProvider
|
|
||||||
|
|
||||||
@Property({
|
|
||||||
onCreate: () => new Date(),
|
|
||||||
columnType: "timestamptz",
|
|
||||||
defaultRaw: "now()",
|
|
||||||
})
|
|
||||||
created_at: Date
|
|
||||||
|
|
||||||
@BeforeCreate()
|
|
||||||
@OnInit()
|
|
||||||
onCreate() {
|
|
||||||
this.id = generateEntityId(this.id, "noti")
|
|
||||||
this.provider_id ??= this.provider_id ?? this.provider?.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
ModuleJoinerConfig,
|
ModuleJoinerConfig,
|
||||||
ModulesSdkTypes,
|
ModulesSdkTypes,
|
||||||
NotificationTypes,
|
NotificationTypes,
|
||||||
|
InferEntityType,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import {
|
import {
|
||||||
InjectManager,
|
InjectManager,
|
||||||
@@ -21,7 +22,9 @@ import NotificationProviderService from "./notification-provider"
|
|||||||
|
|
||||||
type InjectedDependencies = {
|
type InjectedDependencies = {
|
||||||
baseRepository: DAL.RepositoryService
|
baseRepository: DAL.RepositoryService
|
||||||
notificationService: ModulesSdkTypes.IMedusaInternalService<any>
|
notificationService: ModulesSdkTypes.IMedusaInternalService<
|
||||||
|
typeof Notification
|
||||||
|
>
|
||||||
notificationProviderService: NotificationProviderService
|
notificationProviderService: NotificationProviderService
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +35,9 @@ export default class NotificationModuleService
|
|||||||
implements INotificationModuleService
|
implements INotificationModuleService
|
||||||
{
|
{
|
||||||
protected baseRepository_: DAL.RepositoryService
|
protected baseRepository_: DAL.RepositoryService
|
||||||
protected readonly notificationService_: ModulesSdkTypes.IMedusaInternalService<Notification>
|
protected readonly notificationService_: ModulesSdkTypes.IMedusaInternalService<
|
||||||
|
typeof Notification
|
||||||
|
>
|
||||||
protected readonly notificationProviderService_: NotificationProviderService
|
protected readonly notificationProviderService_: NotificationProviderService
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -91,7 +96,7 @@ export default class NotificationModuleService
|
|||||||
protected async createNotifications_(
|
protected async createNotifications_(
|
||||||
data: NotificationTypes.CreateNotificationDTO[],
|
data: NotificationTypes.CreateNotificationDTO[],
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<Notification[]> {
|
): Promise<InferEntityType<typeof Notification>[]> {
|
||||||
if (!data.length) {
|
if (!data.length) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
@@ -108,12 +113,13 @@ export default class NotificationModuleService
|
|||||||
{ take: null },
|
{ take: null },
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
const existsMap = new Map(
|
const existsMap = new Map(
|
||||||
alreadySentNotifications.map((n) => [n.idempotency_key, true])
|
alreadySentNotifications.map((n) => [n.idempotency_key as string, true])
|
||||||
)
|
)
|
||||||
|
|
||||||
const notificationsToProcess = data.filter(
|
const notificationsToProcess = data.filter(
|
||||||
(entry) => !existsMap.has(entry.idempotency_key)
|
(entry) => !entry.idempotency_key || !existsMap.has(entry.idempotency_key)
|
||||||
)
|
)
|
||||||
|
|
||||||
const notificationsToCreate = await promiseAll(
|
const notificationsToCreate = await promiseAll(
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { DAL, NotificationTypes } from "@medusajs/types"
|
import { DAL, InferEntityType, NotificationTypes } from "@medusajs/types"
|
||||||
import { MedusaError, ModulesSdkUtils } from "@medusajs/utils"
|
import { MedusaError, ModulesSdkUtils } from "@medusajs/utils"
|
||||||
import { NotificationProvider } from "@models"
|
import { NotificationProvider } from "@models"
|
||||||
import { NotificationProviderRegistrationPrefix } from "@types"
|
import { NotificationProviderRegistrationPrefix } from "@types"
|
||||||
|
|
||||||
type InjectedDependencies = {
|
type InjectedDependencies = {
|
||||||
notificationProviderRepository: DAL.RepositoryService
|
notificationProviderRepository: DAL.RepositoryService<
|
||||||
|
InferEntityType<typeof NotificationProvider>
|
||||||
|
>
|
||||||
[
|
[
|
||||||
key: `${typeof NotificationProviderRegistrationPrefix}${string}`
|
key: `${typeof NotificationProviderRegistrationPrefix}${string}`
|
||||||
]: NotificationTypes.INotificationProvider
|
]: NotificationTypes.INotificationProvider
|
||||||
@@ -13,9 +15,14 @@ type InjectedDependencies = {
|
|||||||
export default class NotificationProviderService extends ModulesSdkUtils.MedusaInternalService<InjectedDependencies>(
|
export default class NotificationProviderService extends ModulesSdkUtils.MedusaInternalService<InjectedDependencies>(
|
||||||
NotificationProvider
|
NotificationProvider
|
||||||
) {
|
) {
|
||||||
protected readonly notificationProviderRepository_: DAL.RepositoryService<NotificationProvider>
|
protected readonly notificationProviderRepository_: DAL.RepositoryService<
|
||||||
|
InferEntityType<typeof NotificationProvider>
|
||||||
|
>
|
||||||
// We can store the providers in a memory since they can only be registered on startup and not changed during runtime
|
// We can store the providers in a memory since they can only be registered on startup and not changed during runtime
|
||||||
protected providersCache: Map<string, NotificationProvider>
|
protected providersCache: Map<
|
||||||
|
string,
|
||||||
|
InferEntityType<typeof NotificationProvider>
|
||||||
|
>
|
||||||
|
|
||||||
constructor(container: InjectedDependencies) {
|
constructor(container: InjectedDependencies) {
|
||||||
super(container)
|
super(container)
|
||||||
@@ -40,7 +47,7 @@ export default class NotificationProviderService extends ModulesSdkUtils.MedusaI
|
|||||||
|
|
||||||
async getProviderForChannel(
|
async getProviderForChannel(
|
||||||
channel: string
|
channel: string
|
||||||
): Promise<NotificationProvider | undefined> {
|
): Promise<InferEntityType<typeof NotificationProvider> | undefined> {
|
||||||
if (!this.providersCache) {
|
if (!this.providersCache) {
|
||||||
const providers = await this.notificationProviderRepository_.find()
|
const providers = await this.notificationProviderRepository_.find()
|
||||||
this.providersCache = new Map(
|
this.providersCache = new Map(
|
||||||
@@ -54,7 +61,7 @@ export default class NotificationProviderService extends ModulesSdkUtils.MedusaI
|
|||||||
}
|
}
|
||||||
|
|
||||||
async send(
|
async send(
|
||||||
provider: NotificationProvider,
|
provider: InferEntityType<typeof NotificationProvider>,
|
||||||
notification: NotificationTypes.ProviderSendNotificationDTO
|
notification: NotificationTypes.ProviderSendNotificationDTO
|
||||||
): Promise<NotificationTypes.ProviderSendNotificationResultsDTO> {
|
): Promise<NotificationTypes.ProviderSendNotificationResultsDTO> {
|
||||||
const providerHandler = this.retrieveProviderRegistration(provider.id)
|
const providerHandler = this.retrieveProviderRegistration(provider.id)
|
||||||
|
|||||||
Reference in New Issue
Block a user