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:
parent
536d3a53db
commit
22cb416713
6 changed files with 281 additions and 124 deletions
125
packages/core/src/__mocks__/connector-base-data.ts
Normal file
125
packages/core/src/__mocks__/connector-base-data.ts
Normal 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,
|
||||
};
|
|
@ -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,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -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],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
),
|
||||
});
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 });
|
||||
|
|
Loading…
Add table
Reference in a new issue