mirror of
https://github.com/logto-io/logto.git
synced 2025-01-06 20:40:08 -05:00
refactor(connector,core): add config param to email/sms connector test API
This commit is contained in:
parent
a3d3a79dd9
commit
f53aceff6f
8 changed files with 77 additions and 36 deletions
|
@ -32,10 +32,12 @@ export default class AliyunDmConnector implements EmailConnector {
|
|||
}
|
||||
};
|
||||
|
||||
public sendMessage: EmailSendMessageFunction = async (address, type, data) => {
|
||||
const config = await this.getConfig(this.metadata.id);
|
||||
await this.validateConfig(config);
|
||||
const { accessKeyId, accessKeySecret, accountName, fromAlias, templates } = config;
|
||||
// eslint-disable-next-line complexity
|
||||
public sendMessage: EmailSendMessageFunction = async (address, type, data, config) => {
|
||||
const emailConfig =
|
||||
(config as AliyunDmConfig | undefined) ?? (await this.getConfig(this.metadata.id));
|
||||
await this.validateConfig(emailConfig);
|
||||
const { accessKeyId, accessKeySecret, accountName, fromAlias, templates } = emailConfig;
|
||||
const template = templates.find((template) => template.usageType === type);
|
||||
|
||||
assert(
|
||||
|
|
|
@ -26,10 +26,11 @@ export default class AliyunSmsConnector implements SmsConnector {
|
|||
}
|
||||
};
|
||||
|
||||
public sendMessage: SmsSendMessageFunction = async (phone, type, { code }) => {
|
||||
const config = await this.getConfig(this.metadata.id);
|
||||
await this.validateConfig(config);
|
||||
const { accessKeyId, accessKeySecret, signName, templates } = config;
|
||||
public sendMessage: SmsSendMessageFunction = async (phone, type, { code }, config) => {
|
||||
const smsConfig =
|
||||
(config as AliyunSmsConfig | undefined) ?? (await this.getConfig(this.metadata.id));
|
||||
await this.validateConfig(smsConfig);
|
||||
const { accessKeyId, accessKeySecret, signName, templates } = smsConfig;
|
||||
const template = templates.find(({ usageType }) => usageType === type);
|
||||
|
||||
assert(
|
||||
|
|
|
@ -64,13 +64,15 @@ export type SmsMessageTypes = EmailMessageTypes;
|
|||
export type EmailSendMessageFunction<T = unknown> = (
|
||||
address: string,
|
||||
type: keyof EmailMessageTypes,
|
||||
payload: EmailMessageTypes[typeof type]
|
||||
payload: EmailMessageTypes[typeof type],
|
||||
config?: Record<string, unknown>
|
||||
) => Promise<T>;
|
||||
|
||||
export type SmsSendMessageFunction<T = unknown> = (
|
||||
phone: string,
|
||||
type: keyof SmsMessageTypes,
|
||||
payload: SmsMessageTypes[typeof type]
|
||||
payload: SmsMessageTypes[typeof type],
|
||||
config?: Record<string, unknown>
|
||||
) => Promise<T>;
|
||||
|
||||
export interface BaseConnector {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { ConnectorType } from '@logto/schemas';
|
||||
import { phoneRegEx, emailRegEx } from '@logto/shared';
|
||||
import classNames from 'classnames';
|
||||
import ky from 'ky';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
@ -10,18 +9,21 @@ import Button from '@/components/Button';
|
|||
import FormField from '@/components/FormField';
|
||||
import TextInput from '@/components/TextInput';
|
||||
import Tooltip from '@/components/Tooltip';
|
||||
import useApi from '@/hooks/use-api';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
type Props = {
|
||||
connectorType: Exclude<ConnectorType, ConnectorType.Social>;
|
||||
config?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
type FormData = {
|
||||
sendTo: string;
|
||||
};
|
||||
|
||||
const SenderTester = ({ connectorType }: Props) => {
|
||||
const SenderTester = ({ connectorType, config, className }: Props) => {
|
||||
const buttonPosReference = useRef(null);
|
||||
const [showTooltip, setShowTooltip] = useState(false);
|
||||
const [isSubmitting, seIsSubmitting] = useState(false);
|
||||
|
@ -33,6 +35,7 @@ const SenderTester = ({ connectorType }: Props) => {
|
|||
},
|
||||
} = useForm<FormData>();
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const api = useApi();
|
||||
const isSms = connectorType === ConnectorType.SMS;
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -52,12 +55,13 @@ const SenderTester = ({ connectorType }: Props) => {
|
|||
|
||||
const onSubmit = handleSubmit(async (formData) => {
|
||||
const { sendTo } = formData;
|
||||
const configJson = config ? (JSON.parse(config) as JSON) : undefined;
|
||||
seIsSubmitting(true);
|
||||
|
||||
const data = isSms ? { phone: sendTo } : { email: sendTo };
|
||||
const data = { config: configJson, ...(isSms ? { phone: sendTo } : { email: sendTo }) };
|
||||
|
||||
try {
|
||||
await ky
|
||||
await api
|
||||
.post(`/api/connectors/test/${connectorType.toLowerCase()}`, {
|
||||
json: data,
|
||||
})
|
||||
|
@ -70,7 +74,7 @@ const SenderTester = ({ connectorType }: Props) => {
|
|||
});
|
||||
|
||||
return (
|
||||
<form onSubmit={onSubmit}>
|
||||
<form className={className}>
|
||||
<div className={styles.fields}>
|
||||
<FormField
|
||||
isRequired
|
||||
|
@ -95,10 +99,10 @@ const SenderTester = ({ connectorType }: Props) => {
|
|||
</FormField>
|
||||
<div ref={buttonPosReference} className={styles.send}>
|
||||
<Button
|
||||
htmlType="submit"
|
||||
isLoading={isSubmitting}
|
||||
title="admin_console.connector_details.send"
|
||||
type="outline"
|
||||
onClick={onSubmit}
|
||||
/>
|
||||
</div>
|
||||
{showTooltip && (
|
||||
|
|
|
@ -93,3 +93,7 @@
|
|||
.resetIcon {
|
||||
color: var(--color-icon);
|
||||
}
|
||||
|
||||
.readme {
|
||||
margin-top: _.unit(-6);
|
||||
}
|
||||
|
|
|
@ -210,7 +210,9 @@ const ConnectorDetails = () => {
|
|||
}}
|
||||
/>
|
||||
</FormField>
|
||||
{data.type !== ConnectorType.Social && <SenderTester connectorType={data.type} />}
|
||||
{data.type !== ConnectorType.Social && (
|
||||
<SenderTester connectorType={data.type} config={config} />
|
||||
)}
|
||||
{saveError && <div>{saveError}</div>}
|
||||
</div>
|
||||
<div className={detailsStyles.footer}>
|
||||
|
|
|
@ -123,11 +123,16 @@ describe('connector route', () => {
|
|||
const sendMessageSpy = jest.spyOn(mockedEmailConnector, 'sendMessage');
|
||||
const response = await connectorRequest
|
||||
.post('/connectors/test/email')
|
||||
.send({ email: 'test@email.com' });
|
||||
.send({ email: 'test@email.com', config: { test: 123 } });
|
||||
expect(sendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(sendMessageSpy).toHaveBeenCalledWith('test@email.com', 'Test', {
|
||||
code: 'email-test',
|
||||
});
|
||||
expect(sendMessageSpy).toHaveBeenCalledWith(
|
||||
'test@email.com',
|
||||
'Test',
|
||||
{
|
||||
code: 'email-test',
|
||||
},
|
||||
{ test: 123 }
|
||||
);
|
||||
expect(response).toHaveProperty('statusCode', 204);
|
||||
});
|
||||
|
||||
|
@ -166,11 +171,16 @@ describe('connector route', () => {
|
|||
const sendMessageSpy = jest.spyOn(mockedSmsConnectorInstance, 'sendMessage');
|
||||
const response = await connectorRequest
|
||||
.post('/connectors/test/sms')
|
||||
.send({ phone: '12345678901' });
|
||||
.send({ phone: '12345678901', config: { test: 123 } });
|
||||
expect(sendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(sendMessageSpy).toHaveBeenCalledWith('12345678901', 'Test', {
|
||||
code: '123456',
|
||||
});
|
||||
expect(sendMessageSpy).toHaveBeenCalledWith(
|
||||
'12345678901',
|
||||
'Test',
|
||||
{
|
||||
code: '123456',
|
||||
},
|
||||
{ test: 123 }
|
||||
);
|
||||
expect(response).toHaveProperty('statusCode', 204);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ConnectorDTO, Connectors, ConnectorType } from '@logto/schemas';
|
||||
import { arbitraryObjectGuard, ConnectorDTO, Connectors, ConnectorType } from '@logto/schemas';
|
||||
import { emailRegEx, phoneRegEx } from '@logto/shared';
|
||||
import { object, string } from 'zod';
|
||||
|
||||
|
@ -153,15 +153,16 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
|||
koaGuard({
|
||||
body: object({
|
||||
email: string().regex(emailRegEx),
|
||||
config: arbitraryObjectGuard.optional(),
|
||||
}),
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const { email } = ctx.guard.body;
|
||||
const { email, config } = ctx.guard.body;
|
||||
|
||||
const connectorInstances = await getConnectorInstances();
|
||||
const connector = connectorInstances.find(
|
||||
(connector): connector is EmailConnectorInstance =>
|
||||
connector.connector.enabled && connector.metadata.type === ConnectorType.Email
|
||||
connector.metadata.type === ConnectorType.Email
|
||||
);
|
||||
|
||||
assertThat(
|
||||
|
@ -169,9 +170,18 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
|||
new RequestError({ code: 'connector.not_found', type: ConnectorType.Email })
|
||||
);
|
||||
|
||||
await connector.sendMessage(email, 'Test', {
|
||||
code: 'email-test',
|
||||
});
|
||||
if (config) {
|
||||
await connector.validateConfig(config);
|
||||
}
|
||||
|
||||
await connector.sendMessage(
|
||||
email,
|
||||
'Test',
|
||||
{
|
||||
code: 'email-test',
|
||||
},
|
||||
config
|
||||
);
|
||||
|
||||
ctx.status = 204;
|
||||
|
||||
|
@ -184,15 +194,16 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
|||
koaGuard({
|
||||
body: object({
|
||||
phone: string().regex(phoneRegEx),
|
||||
config: arbitraryObjectGuard.optional(),
|
||||
}),
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const { phone } = ctx.guard.body;
|
||||
const { phone, config } = ctx.guard.body;
|
||||
|
||||
const connectorInstances = await getConnectorInstances();
|
||||
const connector = connectorInstances.find(
|
||||
(connector): connector is SmsConnectorInstance =>
|
||||
connector.connector.enabled && connector.metadata.type === ConnectorType.SMS
|
||||
connector.metadata.type === ConnectorType.SMS
|
||||
);
|
||||
|
||||
assertThat(
|
||||
|
@ -200,9 +211,14 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
|||
new RequestError({ code: 'connector.not_found', type: ConnectorType.SMS })
|
||||
);
|
||||
|
||||
await connector.sendMessage(phone, 'Test', {
|
||||
code: '123456',
|
||||
});
|
||||
await connector.sendMessage(
|
||||
phone,
|
||||
'Test',
|
||||
{
|
||||
code: '123456',
|
||||
},
|
||||
config
|
||||
);
|
||||
|
||||
ctx.status = 204;
|
||||
|
||||
|
|
Loading…
Reference in a new issue