mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
fix(core,connector): fix patch connector api cannot reset config/metadata bug (#4166)
This commit is contained in:
parent
305f1409fd
commit
e441c089d7
7 changed files with 67 additions and 16 deletions
|
@ -26,7 +26,7 @@ const sendMessage =
|
|||
const config = inputConfig ?? (await getConfig(defaultMetadata.id));
|
||||
validateConfig<MockMailConfig>(config, mockMailConfigGuard);
|
||||
const { templates } = config;
|
||||
const template = templates.find((template) => template.usageType === type);
|
||||
const template = templates?.find((template) => template.usageType === type);
|
||||
|
||||
assert(
|
||||
template,
|
||||
|
|
|
@ -12,11 +12,13 @@ const templateGuard = z.object({
|
|||
content: z.string(), // With variable {{code}}, support HTML
|
||||
});
|
||||
|
||||
export const mockMailConfigGuard = z.object({
|
||||
apiKey: z.string(),
|
||||
fromEmail: z.string(),
|
||||
fromName: z.string().optional(),
|
||||
templates: z.array(templateGuard),
|
||||
});
|
||||
export const mockMailConfigGuard = z
|
||||
.object({
|
||||
apiKey: z.string(),
|
||||
fromEmail: z.string(),
|
||||
fromName: z.string().optional(),
|
||||
templates: z.array(templateGuard),
|
||||
})
|
||||
.partial();
|
||||
|
||||
export type MockMailConfig = z.infer<typeof mockMailConfigGuard>;
|
||||
|
|
|
@ -69,12 +69,20 @@ describe('buildUpdateWhere()', () => {
|
|||
).resolves.toStrictEqual({ id: 'foo', customClientMetadata: '{"idTokenTtl":3600}' });
|
||||
});
|
||||
|
||||
it('throws an error when `undefined` found in values', async () => {
|
||||
it('should skip the keys whose value is `undefined`', async () => {
|
||||
const user: CreateUser = {
|
||||
id: 'foo',
|
||||
username: '456',
|
||||
};
|
||||
const pool = createTestPool(
|
||||
'update "users"\nset "username"=$1\nwhere "id"=$2 and "username"=$3'
|
||||
'update "users"\nset "username"=$1\nwhere "id"=$2 and "username"=$3\nreturning *',
|
||||
(_, [username, id]) => ({
|
||||
id: String(id),
|
||||
username: String(username),
|
||||
})
|
||||
);
|
||||
|
||||
const updateWhere = buildUpdateWhereWithPool(pool)(Users);
|
||||
const updateWhere = buildUpdateWhereWithPool(pool)(Users, true);
|
||||
|
||||
await expect(
|
||||
updateWhere({
|
||||
|
@ -82,7 +90,7 @@ describe('buildUpdateWhere()', () => {
|
|||
where: { id: 'foo', username: '456' },
|
||||
jsonbMode: 'merge',
|
||||
})
|
||||
).rejects.toMatchError(new Error(`Cannot convert id to primitive`));
|
||||
).resolves.toStrictEqual({ ...user, username: '123' });
|
||||
});
|
||||
|
||||
it('throws `entity.not_exists_with_id` error with `undefined` when `returning` is true', async () => {
|
||||
|
|
|
@ -32,7 +32,7 @@ export const buildUpdateWhereWithPool =
|
|||
const connectKeyValueWithEqualSign = (data: Partial<Schema>, jsonbMode: 'replace' | 'merge') =>
|
||||
Object.entries<SchemaValue>(data)
|
||||
.map(([key, value]) => {
|
||||
if (!isKeyOfSchema(key)) {
|
||||
if (!isKeyOfSchema(key) || value === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -179,6 +179,34 @@ describe('connector data routes', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('successfully reset connector config', async () => {
|
||||
getLogtoConnectors.mockResolvedValue([
|
||||
{
|
||||
dbEntry: mockConnector,
|
||||
metadata: { ...mockMetadata, isStandard: true },
|
||||
type: ConnectorType.Social,
|
||||
...mockLogtoConnector,
|
||||
},
|
||||
]);
|
||||
updateConnector.mockResolvedValueOnce({
|
||||
...mockConnector,
|
||||
config: {},
|
||||
});
|
||||
const response = await connectorRequest.patch('/connectors/id').send({
|
||||
config: {},
|
||||
});
|
||||
expect(response).toHaveProperty('statusCode', 200);
|
||||
expect(updateConnector).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
where: { id: 'id' },
|
||||
set: {
|
||||
config: {},
|
||||
},
|
||||
jsonbMode: 'replace',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('successfully updates connector config and metadata', async () => {
|
||||
getLogtoConnectors.mockResolvedValue([
|
||||
{
|
||||
|
@ -235,9 +263,6 @@ describe('connector data routes', () => {
|
|||
...mockConnector,
|
||||
metadata: {
|
||||
target: 'connector',
|
||||
name: { en: '' },
|
||||
logo: '',
|
||||
logoDark: '',
|
||||
},
|
||||
});
|
||||
const response = await connectorRequest.patch('/connectors/id').send({
|
||||
|
|
|
@ -5,8 +5,10 @@ import {
|
|||
Connectors,
|
||||
ConnectorType,
|
||||
connectorResponseGuard,
|
||||
type JsonObject,
|
||||
} from '@logto/schemas';
|
||||
import { buildIdGenerator } from '@logto/shared';
|
||||
import { conditional } from '@silverhand/essentials';
|
||||
import cleanDeep from 'clean-deep';
|
||||
import { string, object } from 'zod';
|
||||
|
||||
|
@ -308,7 +310,17 @@ export default function connectorRoutes<T extends AuthedRouter>(
|
|||
}
|
||||
|
||||
await updateConnector({
|
||||
set: cleanDeep({ config, metadata, syncProfile }),
|
||||
set: {
|
||||
/**
|
||||
* `JsonObject` has all non-undefined values, and `cleanDeep` method with default settings
|
||||
* drops all keys with undefined values, the return type of `Partial<JsonObject>` is still `JsonObject`.
|
||||
* The type inference failed to infer this, manually assign type `JsonObject`.
|
||||
*/
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
config: conditional(config && (cleanDeep(config) as JsonObject)),
|
||||
metadata: conditional(metadata && cleanDeep(metadata)),
|
||||
syncProfile,
|
||||
},
|
||||
where: { id },
|
||||
jsonbMode: 'replace',
|
||||
});
|
||||
|
|
|
@ -115,6 +115,10 @@ test('connector set-up flow', async () => {
|
|||
currentConnectors.find((connector) => connector.connectorId === mockAlternativeEmailConnectorId)
|
||||
?.config
|
||||
).toEqual(mockAlternativeEmailConnectorConfig);
|
||||
// Can reset the connector config to empty object `{}` (when it is valid).
|
||||
await expect(updateConnectorConfig(id, { config: {} })).resolves.not.toThrow();
|
||||
const alternativeEmailConnector = await getConnector(id);
|
||||
expect(alternativeEmailConnector.config).toEqual({});
|
||||
|
||||
/*
|
||||
* Delete (i.e. disable) a connector
|
||||
|
|
Loading…
Reference in a new issue