Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add support for sendgrid and logger notification providers (#7290)
* feat: Add support for sendgrid and logger notification providers * fix: changes based on PR review
- Loading branch information
Showing
24 changed files
with
631 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
"@medusajs/notification-sendgrid": patch | ||
"@medusajs/notification-logger": patch | ||
"@medusajs/types": patch | ||
--- | ||
|
||
Add sendgrid and logger notification providers |
128 changes: 128 additions & 0 deletions
128
integration-tests/modules/__tests__/notification/admin/notification.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import { ModuleRegistrationName } from "@medusajs/modules-sdk" | ||
import { | ||
CreateNotificationDTO, | ||
INotificationModuleService, | ||
Logger, | ||
} from "@medusajs/types" | ||
import { ContainerRegistrationKeys } from "@medusajs/utils" | ||
import { medusaIntegrationTestRunner } from "medusa-test-utils" | ||
|
||
jest.setTimeout(50000) | ||
|
||
const env = { MEDUSA_FF_MEDUSA_V2: true } | ||
medusaIntegrationTestRunner({ | ||
env, | ||
testSuite: ({ getContainer }) => { | ||
describe("Notification module", () => { | ||
let service: INotificationModuleService | ||
let logger: Logger | ||
|
||
beforeAll(async () => { | ||
service = getContainer().resolve(ModuleRegistrationName.NOTIFICATION) | ||
logger = getContainer().resolve(ContainerRegistrationKeys.LOGGER) | ||
}) | ||
|
||
afterEach(() => { | ||
jest.restoreAllMocks() | ||
}) | ||
|
||
it("should successfully send a notification for an available channel", async () => { | ||
const logSpy = jest.spyOn(logger, "info") | ||
const notification = { | ||
to: "[email protected]", | ||
channel: "email", | ||
template: "order-created", | ||
data: { username: "john-doe" }, | ||
trigger_type: "order-created", | ||
resource_id: "order-id", | ||
resource_type: "order", | ||
} as CreateNotificationDTO | ||
|
||
const result = await service.create(notification) | ||
const fromDB = await service.retrieve(result.id) | ||
|
||
expect(result).toEqual( | ||
expect.objectContaining({ | ||
id: expect.any(String), | ||
to: "[email protected]", | ||
provider_id: "local-notification-provider", | ||
}) | ||
) | ||
|
||
delete fromDB.original_notification_id | ||
delete fromDB.external_id | ||
delete fromDB.receiver_id | ||
delete (fromDB as any).idempotency_key | ||
delete (fromDB as any).provider | ||
|
||
expect(result).toEqual(fromDB) | ||
expect(logSpy).toHaveBeenCalledWith( | ||
'Attempting to send a notification to: [email protected] on the channel: email with template: order-created and data: {"username":"john-doe"}' | ||
) | ||
}) | ||
|
||
it("should throw an exception if there is no provider for the channel", async () => { | ||
const notification = { | ||
to: "[email protected]", | ||
channel: "sms", | ||
} as CreateNotificationDTO | ||
|
||
const error = await service.create(notification).catch((e) => e) | ||
expect(error.message).toEqual( | ||
"Could not find a notification provider for channel: sms" | ||
) | ||
}) | ||
|
||
it("should allow listing all notifications with filters", async () => { | ||
const notification1 = { | ||
to: "[email protected]", | ||
channel: "email", | ||
template: "order-created", | ||
} as CreateNotificationDTO | ||
|
||
const notification2 = { | ||
to: "[email protected]", | ||
channel: "log", | ||
template: "product-created", | ||
} as CreateNotificationDTO | ||
|
||
await service.create([notification1, notification2]) | ||
|
||
const notifications = await service.list({ channel: "log" }) | ||
expect(notifications).toHaveLength(1) | ||
expect(notifications[0]).toEqual( | ||
expect.objectContaining({ | ||
to: "[email protected]", | ||
channel: "log", | ||
template: "product-created", | ||
}) | ||
) | ||
}) | ||
|
||
it("should allow retrieving a notification", async () => { | ||
const notification1 = { | ||
to: "[email protected]", | ||
channel: "email", | ||
template: "order-created", | ||
} as CreateNotificationDTO | ||
|
||
const notification2 = { | ||
to: "[email protected]", | ||
channel: "log", | ||
template: "product-created", | ||
} as CreateNotificationDTO | ||
|
||
const [first] = await service.create([notification1, notification2]) | ||
|
||
const notification = await service.retrieve(first.id) | ||
expect(notification).toEqual( | ||
expect.objectContaining({ | ||
to: "[email protected]", | ||
channel: "email", | ||
template: "order-created", | ||
}) | ||
) | ||
}) | ||
}) | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export * from "./local" | ||
export * from "./logger" | ||
export * from "./sendgrid" |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export interface SendgridNotificationServiceOptions { | ||
api_key: string | ||
from: string | ||
} |
Empty file.
Empty file.
36 changes: 36 additions & 0 deletions
36
packages/modules/providers/notification-local/integration-tests/__tests__/services.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { LocalNotificationService } from "../../src/services/local" | ||
jest.setTimeout(100000) | ||
|
||
describe("Local notification provider", () => { | ||
let localService: LocalNotificationService | ||
|
||
beforeAll(() => { | ||
localService = new LocalNotificationService( | ||
{ | ||
logger: console as any, | ||
}, | ||
{} | ||
) | ||
}) | ||
|
||
afterEach(() => { | ||
jest.restoreAllMocks() | ||
}) | ||
|
||
it("sends logs to the console output with the notification details", async () => { | ||
const logSpy = jest.spyOn(console, "info") | ||
await localService.send({ | ||
to: "[email protected]", | ||
channel: "email", | ||
template: "some-template", | ||
data: { | ||
username: "john-doe", | ||
}, | ||
}) | ||
|
||
expect(logSpy).toHaveBeenCalled() | ||
expect(logSpy).toHaveBeenCalledWith( | ||
'Attempting to send a notification to: [email protected] on the channel: email with template: some-template and data: {"username":"john-doe"}' | ||
) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module.exports = { | ||
transform: { | ||
"^.+\\.[jt]s?$": "@swc/jest", | ||
}, | ||
testEnvironment: `node`, | ||
moduleFileExtensions: [`js`, `jsx`, `ts`, `tsx`, `json`], | ||
} |
39 changes: 39 additions & 0 deletions
39
packages/modules/providers/notification-local/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
{ | ||
"name": "@medusajs/notification-local", | ||
"version": "0.0.1", | ||
"description": "Local (logging) notification provider for Medusa, useful for testing purposes and log audits", | ||
"main": "dist/index.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/medusajs/medusa", | ||
"directory": "packages/modules/providers/notification-local" | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"engines": { | ||
"node": ">=16" | ||
}, | ||
"author": "Medusa", | ||
"license": "MIT", | ||
"scripts": { | ||
"prepublishOnly": "cross-env NODE_ENV=production tsc --build", | ||
"test": "jest --passWithNoTests src", | ||
"test:integration": "jest --forceExit -- integration-tests/**/__tests__/**/*.spec.ts", | ||
"build": "rimraf dist && tsc -p ./tsconfig.json", | ||
"watch": "tsc --watch" | ||
}, | ||
"devDependencies": { | ||
"cross-env": "^5.2.1", | ||
"jest": "^25.5.4", | ||
"rimraf": "^5.0.1", | ||
"typescript": "^4.9.5" | ||
}, | ||
"dependencies": { | ||
"@medusajs/utils": "^1.11.7" | ||
}, | ||
"keywords": [ | ||
"medusa-provider", | ||
"medusa-provider-local" | ||
] | ||
} |
10 changes: 10 additions & 0 deletions
10
packages/modules/providers/notification-local/src/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { ModuleProviderExports } from "@medusajs/types" | ||
import { LocalNotificationService } from "./services/local" | ||
|
||
const services = [LocalNotificationService] | ||
|
||
const providerExport: ModuleProviderExports = { | ||
services, | ||
} | ||
|
||
export default providerExport |
48 changes: 48 additions & 0 deletions
48
packages/modules/providers/notification-local/src/services/local.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { | ||
Logger, | ||
NotificationTypes, | ||
LocalNotificationServiceOptions, | ||
} from "@medusajs/types" | ||
import { | ||
AbstractNotificationProviderService, | ||
MedusaError, | ||
} from "@medusajs/utils" | ||
|
||
type InjectedDependencies = { | ||
logger: Logger | ||
} | ||
|
||
interface LocalServiceConfig {} | ||
|
||
export class LocalNotificationService extends AbstractNotificationProviderService { | ||
protected config_: LocalServiceConfig | ||
protected logger_: Logger | ||
|
||
constructor( | ||
{ logger }: InjectedDependencies, | ||
options: LocalNotificationServiceOptions | ||
) { | ||
super() | ||
this.config_ = options | ||
this.logger_ = logger | ||
} | ||
|
||
async send( | ||
notification: NotificationTypes.ProviderSendNotificationDTO | ||
): Promise<NotificationTypes.ProviderSendNotificationResultsDTO> { | ||
if (!notification) { | ||
throw new MedusaError( | ||
MedusaError.Types.INVALID_DATA, | ||
`No notification information provided` | ||
) | ||
} | ||
|
||
const message = | ||
`Attempting to send a notification to: ${notification.to}` + | ||
` on the channel: ${notification.channel} with template: ${notification.template}` + | ||
` and data: ${JSON.stringify(notification.data)}` | ||
|
||
this.logger_.info(message) | ||
return {} | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
packages/modules/providers/notification-local/tsconfig.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"compilerOptions": { | ||
"lib": ["es2020"], | ||
"target": "es2020", | ||
"jsx": "react-jsx" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */, | ||
"outDir": "./dist", | ||
"esModuleInterop": true, | ||
"declaration": true, | ||
"module": "commonjs", | ||
"moduleResolution": "node", | ||
"emitDecoratorMetadata": true, | ||
"experimentalDecorators": true, | ||
"noImplicitReturns": true, | ||
"strictNullChecks": true, | ||
"strictFunctionTypes": true, | ||
"noImplicitThis": true, | ||
"allowJs": true, | ||
"skipLibCheck": true, | ||
"downlevelIteration": true, // to use ES5 specific tooling | ||
"inlineSourceMap": true /* Emit a single file with source maps instead of having a separate file. */ | ||
}, | ||
"include": ["src"], | ||
"exclude": [ | ||
"dist", | ||
"build", | ||
"src/**/__tests__", | ||
"src/**/__mocks__", | ||
"src/**/__fixtures__", | ||
"node_modules", | ||
".eslintrc.js" | ||
] | ||
} |
Empty file.
Empty file.
Oops, something went wrong.