0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-27 21:39:16 -05:00

feat(core): remove unavailable social connector targets in the sie (#2328)

This commit is contained in:
Xiao Yijun 2022-11-08 19:10:22 +08:00 committed by GitHub
parent 536d3a53db
commit 22cb416713
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 281 additions and 124 deletions

View file

@ -0,0 +1,125 @@
import type { ConnectorMetadata } from '@logto/connector-kit';
import { ConnectorPlatform } from '@logto/connector-kit';
import type { Connector } from '@logto/schemas';
export const mockMetadata: ConnectorMetadata = {
id: 'id',
target: 'connector',
platform: null,
name: {
en: 'Connector',
'pt-PT': 'Conector',
'zh-CN': '连接器',
'tr-TR': 'Connector',
ko: 'Connector',
},
logo: './logo.png',
logoDark: './logo-dark.png',
description: {
en: 'Connector',
'pt-PT': 'Conector',
'zh-CN': '连接器',
'tr-TR': 'Connector',
ko: 'Connector',
},
readme: 'README.md',
configTemplate: 'config-template.json',
};
export const mockMetadata0: ConnectorMetadata = {
...mockMetadata,
id: 'id0',
target: 'connector_0',
platform: ConnectorPlatform.Universal,
};
export const mockMetadata1: ConnectorMetadata = {
...mockMetadata,
id: 'id1',
target: 'connector_1',
platform: ConnectorPlatform.Universal,
};
export const mockMetadata2: ConnectorMetadata = {
...mockMetadata,
id: 'id2',
target: 'connector_2',
platform: ConnectorPlatform.Universal,
};
export const mockMetadata3: ConnectorMetadata = {
...mockMetadata,
id: 'id3',
target: 'connector_3',
platform: ConnectorPlatform.Universal,
};
export const mockMetadata4: ConnectorMetadata = {
...mockMetadata,
id: 'id4',
target: 'connector_4',
platform: ConnectorPlatform.Universal,
};
export const mockMetadata5: ConnectorMetadata = {
...mockMetadata,
id: 'id5',
target: 'connector_5',
platform: ConnectorPlatform.Universal,
};
export const mockMetadata6: ConnectorMetadata = {
...mockMetadata,
id: 'id6',
target: 'connector_6',
platform: ConnectorPlatform.Universal,
};
export const mockConnector0: Connector = {
id: 'id0',
enabled: true,
config: {},
createdAt: 1_234_567_890_123,
};
export const mockConnector1: Connector = {
id: 'id1',
enabled: true,
config: {},
createdAt: 1_234_567_890_234,
};
export const mockConnector2: Connector = {
id: 'id2',
enabled: true,
config: {},
createdAt: 1_234_567_890_345,
};
export const mockConnector3: Connector = {
id: 'id3',
enabled: true,
config: {},
createdAt: 1_234_567_890_456,
};
export const mockConnector4: Connector = {
id: 'id4',
enabled: true,
config: {},
createdAt: 1_234_567_890_567,
};
export const mockConnector5: Connector = {
id: 'id5',
enabled: true,
config: {},
createdAt: 1_234_567_890_567,
};
export const mockConnector6: Connector = {
id: 'id6',
enabled: true,
config: {},
createdAt: 1_234_567_890_567,
};

View file

@ -1,33 +1,29 @@
import { ConnectorPlatform } from '@logto/connector-kit';
import type { Connector, ConnectorMetadata } from '@logto/schemas';
import type { Connector } from '@logto/schemas';
import { ConnectorType } from '@logto/schemas';
import { any } from 'zod';
import type { LogtoConnector } from '@/connectors/types';
export const mockMetadata: ConnectorMetadata = {
id: 'id',
target: 'connector',
platform: null,
name: {
en: 'Connector',
'pt-PT': 'Conector',
'zh-CN': '连接器',
'tr-TR': 'Connector',
ko: 'Connector',
},
logo: './logo.png',
logoDark: './logo-dark.png',
description: {
en: 'Connector',
'pt-PT': 'Conector',
'zh-CN': '连接器',
'tr-TR': 'Connector',
ko: 'Connector',
},
readme: 'README.md',
configTemplate: 'config-template.json',
};
import {
mockConnector0,
mockConnector1,
mockConnector2,
mockConnector3,
mockConnector4,
mockConnector5,
mockConnector6,
mockMetadata,
mockMetadata0,
mockMetadata1,
mockMetadata2,
mockMetadata3,
mockMetadata4,
mockMetadata5,
mockMetadata6,
} from './connector-base-data';
export { mockMetadata } from './connector-base-data';
export const mockConnector: Connector = {
id: 'id',
@ -44,104 +40,6 @@ export const mockLogtoConnector = {
configGuard: any(),
};
const mockMetadata0: ConnectorMetadata = {
...mockMetadata,
id: 'id0',
target: 'connector_0',
platform: ConnectorPlatform.Universal,
};
const mockMetadata1: ConnectorMetadata = {
...mockMetadata,
id: 'id1',
target: 'connector_1',
platform: ConnectorPlatform.Universal,
};
const mockMetadata2: ConnectorMetadata = {
...mockMetadata,
id: 'id2',
target: 'connector_2',
platform: ConnectorPlatform.Universal,
};
const mockMetadata3: ConnectorMetadata = {
...mockMetadata,
id: 'id3',
target: 'connector_3',
platform: ConnectorPlatform.Universal,
};
const mockMetadata4: ConnectorMetadata = {
...mockMetadata,
id: 'id4',
target: 'connector_4',
platform: ConnectorPlatform.Universal,
};
const mockMetadata5: ConnectorMetadata = {
...mockMetadata,
id: 'id5',
target: 'connector_5',
platform: ConnectorPlatform.Universal,
};
const mockMetadata6: ConnectorMetadata = {
...mockMetadata,
id: 'id6',
target: 'connector_6',
platform: ConnectorPlatform.Universal,
};
const mockConnector0: Connector = {
id: 'id0',
enabled: true,
config: {},
createdAt: 1_234_567_890_123,
};
const mockConnector1: Connector = {
id: 'id1',
enabled: true,
config: {},
createdAt: 1_234_567_890_234,
};
const mockConnector2: Connector = {
id: 'id2',
enabled: true,
config: {},
createdAt: 1_234_567_890_345,
};
const mockConnector3: Connector = {
id: 'id3',
enabled: true,
config: {},
createdAt: 1_234_567_890_456,
};
const mockConnector4: Connector = {
id: 'id4',
enabled: true,
config: {},
createdAt: 1_234_567_890_567,
};
const mockConnector5: Connector = {
id: 'id5',
enabled: true,
config: {},
createdAt: 1_234_567_890_567,
};
const mockConnector6: Connector = {
id: 'id6',
enabled: true,
config: {},
createdAt: 1_234_567_890_567,
};
export const mockConnectorList: Connector[] = [
mockConnector0,
mockConnector1,
@ -312,3 +210,52 @@ export const mockLogtoConnectors = [
mockWechatConnector,
mockWechatNativeConnector,
];
export const disabledSocialTarget01 = 'disableSocialTarget-id01';
export const disabledSocialTarget02 = 'disableSocialTarget-id02';
export const enabledSocialTarget01 = 'enabledSocialTarget-id01';
export const mockSocialConnectors: LogtoConnector[] = [
{
dbEntry: {
id: 'id0',
enabled: false,
config: {},
createdAt: 1_234_567_890_123,
},
metadata: {
...mockMetadata,
target: disabledSocialTarget01,
},
type: ConnectorType.Social,
...mockLogtoConnector,
},
{
dbEntry: {
id: 'id1',
enabled: true,
config: {},
createdAt: 1_234_567_890_123,
},
metadata: {
...mockMetadata,
target: enabledSocialTarget01,
},
type: ConnectorType.Social,
...mockLogtoConnector,
},
{
dbEntry: {
id: 'id2',
enabled: false,
config: {},
createdAt: 1_234_567_890_123,
},
metadata: {
...mockMetadata,
target: disabledSocialTarget02,
},
type: ConnectorType.Social,
...mockLogtoConnector,
},
];

View file

@ -1,22 +1,53 @@
import type { LanguageTag } from '@logto/language-kit';
import { builtInLanguages } from '@logto/phrases-ui';
import type { CreateSignInExperience, SignInExperience } from '@logto/schemas';
import { BrandingStyle } from '@logto/schemas';
import { mockBranding } from '@/__mocks__';
import {
disabledSocialTarget01,
disabledSocialTarget02,
enabledSocialTarget01,
mockBranding,
mockSignInExperience,
mockSocialConnectors,
} from '@/__mocks__';
import type { LogtoConnector } from '@/connectors/types';
import RequestError from '@/errors/RequestError';
import {
validateBranding,
validateTermsOfUse,
validateLanguageInfo,
removeUnavailableSocialConnectorTargets,
} from '@/lib/sign-in-experience';
import { updateDefaultSignInExperience } from '@/queries/sign-in-experience';
const allCustomLanguageTags: LanguageTag[] = [];
const findAllCustomLanguageTags = jest.fn(async () => allCustomLanguageTags);
const getLogtoConnectorsPlaceHolder = jest.fn() as jest.MockedFunction<
() => Promise<LogtoConnector[]>
>;
const findDefaultSignInExperience = jest.fn() as jest.MockedFunction<
() => Promise<SignInExperience>
>;
jest.mock('@/queries/custom-phrase', () => ({
findAllCustomLanguageTags: async () => findAllCustomLanguageTags(),
}));
jest.mock('@/connectors', () => ({
getLogtoConnectors: async () => getLogtoConnectorsPlaceHolder(),
}));
jest.mock('@/queries/sign-in-experience', () => ({
findDefaultSignInExperience: async () => findDefaultSignInExperience(),
updateDefaultSignInExperience: jest.fn(
async (data: Partial<CreateSignInExperience>): Promise<SignInExperience> => ({
...mockSignInExperience,
...data,
})
),
}));
beforeEach(() => {
jest.clearAllMocks();
});
@ -123,3 +154,25 @@ describe('validate terms of use', () => {
}).toMatchError(new RequestError('sign_in_experiences.empty_content_url_of_terms_of_use'));
});
});
describe('remove unavailable social connector targets', () => {
test('should remove unavailable social connector targets in sign-in experience', async () => {
const mockSocialConnectorTargets = mockSocialConnectors.map(
({ metadata: { target } }) => target
);
findDefaultSignInExperience.mockResolvedValueOnce({
...mockSignInExperience,
socialSignInConnectorTargets: mockSocialConnectorTargets,
});
getLogtoConnectorsPlaceHolder.mockResolvedValueOnce(mockSocialConnectors);
expect(mockSocialConnectorTargets).toEqual([
disabledSocialTarget01,
enabledSocialTarget01,
disabledSocialTarget02,
]);
await removeUnavailableSocialConnectorTargets();
expect(updateDefaultSignInExperience).toBeCalledWith({
socialSignInConnectorTargets: [enabledSocialTarget01],
});
});
});

View file

@ -1,9 +1,14 @@
import { builtInLanguages } from '@logto/phrases-ui';
import type { Branding, LanguageInfo, TermsOfUse } from '@logto/schemas';
import { BrandingStyle } from '@logto/schemas';
import { ConnectorType, BrandingStyle } from '@logto/schemas';
import { getLogtoConnectors } from '@/connectors';
import RequestError from '@/errors/RequestError';
import { findAllCustomLanguageTags } from '@/queries/custom-phrase';
import {
findDefaultSignInExperience,
updateDefaultSignInExperience,
} from '@/queries/sign-in-experience';
import assertThat from '@/utils/assert-that';
export * from './sign-up';
@ -35,3 +40,19 @@ export const validateTermsOfUse = (termsOfUse: TermsOfUse) => {
'sign_in_experiences.empty_content_url_of_terms_of_use'
);
};
export const removeUnavailableSocialConnectorTargets = async () => {
const connectors = await getLogtoConnectors();
const availableSocialConnectorTargets = new Set(
connectors
.filter(({ type, dbEntry: { enabled } }) => enabled && type === ConnectorType.Social)
.map(({ metadata: { target } }) => target)
);
const { socialSignInConnectorTargets } = await findDefaultSignInExperience();
await updateDefaultSignInExperience({
socialSignInConnectorTargets: socialSignInConnectorTargets.filter((target) =>
availableSocialConnectorTargets.has(target)
),
});
};

View file

@ -7,6 +7,7 @@ import { object, string } from 'zod';
import { getLogtoConnectorById, getLogtoConnectors } from '@/connectors';
import type { LogtoConnector } from '@/connectors/types';
import RequestError from '@/errors/RequestError';
import { removeUnavailableSocialConnectorTargets } from '@/lib/sign-in-experience';
import koaGuard from '@/middleware/koa-guard';
import { updateConnector } from '@/queries/connector';
import assertThat from '@/utils/assert-that';
@ -115,6 +116,12 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
where: { id },
jsonbMode: 'merge',
});
// Delete the social connector in the sign-in experience if it is disabled.
if (!enabled && type === ConnectorType.Social) {
await removeUnavailableSocialConnectorTargets();
}
ctx.body = { ...connector, metadata, type };
return next();

View file

@ -46,6 +46,10 @@ jest.mock('@/connectors', () => ({
getLogtoConnectorById: async (connectorId: string) =>
getLogtoConnectorByIdPlaceholder(connectorId),
}));
jest.mock('@/lib/sign-in-experience', () => ({
// eslint-disable-next-line @typescript-eslint/no-empty-function
removeUnavailableSocialConnectorTargets: async () => {},
}));
describe('connector PATCH routes', () => {
const connectorRequest = createRequester({ authedRoutes: connectorRoutes });