mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
refactor: remove demo app db entity (#3165)
This commit is contained in:
parent
dfa17ba555
commit
e3f88f5250
12 changed files with 104 additions and 92 deletions
|
@ -4,7 +4,6 @@ import path from 'path';
|
|||
import {
|
||||
defaultSignInExperience,
|
||||
createDefaultAdminConsoleConfig,
|
||||
createDemoAppApplication,
|
||||
defaultTenantId,
|
||||
adminTenantId,
|
||||
defaultManagementApi,
|
||||
|
@ -125,8 +124,6 @@ export const seedTables = async (
|
|||
await Promise.all([
|
||||
connection.query(insertInto(createDefaultAdminConsoleConfig(defaultTenantId), 'logto_configs')),
|
||||
connection.query(insertInto(defaultSignInExperience, 'sign_in_experiences')),
|
||||
// TODO: @gao remove demo app
|
||||
connection.query(insertInto(createDemoAppApplication(defaultTenantId), 'applications')),
|
||||
updateDatabaseTimestamp(connection, latestTimestamp),
|
||||
]);
|
||||
};
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import type { AdminConsoleKey } from '@logto/phrases';
|
||||
import type { Application } from '@logto/schemas';
|
||||
import { AppearanceMode, demoAppApplicationId } from '@logto/schemas';
|
||||
import { AppearanceMode } from '@logto/schemas';
|
||||
import { useContext, useMemo } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import CheckDemoDark from '@/assets/images/check-demo-dark.svg';
|
||||
import CheckDemo from '@/assets/images/check-demo.svg';
|
||||
|
@ -19,7 +17,6 @@ import SocialDark from '@/assets/images/social-dark.svg';
|
|||
import Social from '@/assets/images/social.svg';
|
||||
import { ConnectorsTabs } from '@/consts/page-tabs';
|
||||
import { AppEndpointsContext } from '@/containers/AppEndpointsProvider';
|
||||
import { RequestError } from '@/hooks/use-api';
|
||||
import useConfigs from '@/hooks/use-configs';
|
||||
import useDocumentationUrl from '@/hooks/use-documentation-url';
|
||||
import { useTheme } from '@/hooks/use-theme';
|
||||
|
@ -41,21 +38,7 @@ const useGetStartedMetadata = () => {
|
|||
const { userEndpoint } = useContext(AppEndpointsContext);
|
||||
const theme = useTheme();
|
||||
const isLightMode = theme === AppearanceMode.LightMode;
|
||||
const { data: demoApp, error } = useSWR<Application, RequestError>(
|
||||
`api/applications/${demoAppApplicationId}`,
|
||||
{
|
||||
shouldRetryOnError: (error: unknown) => {
|
||||
if (error instanceof RequestError) {
|
||||
return error.status !== 404;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
}
|
||||
);
|
||||
const navigate = useNavigate();
|
||||
const isLoadingDemoApp = !demoApp && !error;
|
||||
const hideDemo = error?.status === 404;
|
||||
|
||||
const data = useMemo(() => {
|
||||
const metadataItems: GetStartedMetadata[] = [
|
||||
|
@ -66,7 +49,6 @@ const useGetStartedMetadata = () => {
|
|||
icon: isLightMode ? CheckDemo : CheckDemoDark,
|
||||
buttonText: 'general.check_out',
|
||||
isComplete: configs?.demoChecked,
|
||||
isHidden: hideDemo,
|
||||
onClick: async () => {
|
||||
void updateConfigs({ demoChecked: true });
|
||||
window.open(new URL('/demo-app', userEndpoint), '_blank');
|
||||
|
@ -142,7 +124,6 @@ const useGetStartedMetadata = () => {
|
|||
configs?.passwordlessConfigured,
|
||||
configs?.socialSignInConfigured,
|
||||
configs?.furtherReadingsChecked,
|
||||
hideDemo,
|
||||
updateConfigs,
|
||||
userEndpoint,
|
||||
navigate,
|
||||
|
@ -153,7 +134,7 @@ const useGetStartedMetadata = () => {
|
|||
data,
|
||||
completedCount: data.filter(({ isComplete }) => isComplete).length,
|
||||
totalCount: data.length,
|
||||
isLoading: isLoadingDemoApp,
|
||||
isLoading: false,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { adminTenantId } from '@logto/schemas';
|
||||
import { trySafe } from '@silverhand/essentials';
|
||||
import type { Optional } from '@silverhand/essentials';
|
||||
import { deduplicate, trySafe } from '@silverhand/essentials';
|
||||
|
||||
import type GlobalValues from './GlobalValues.js';
|
||||
|
||||
|
@ -23,3 +24,29 @@ export const getTenantEndpoint = (
|
|||
|
||||
return tenantUrl;
|
||||
};
|
||||
|
||||
export const getTenantLocalhost = (
|
||||
id: string,
|
||||
{ urlSet, adminUrlSet, isDomainBasedMultiTenancy }: GlobalValues
|
||||
): Optional<URL> => {
|
||||
const adminUrl = trySafe(() => adminUrlSet.localhostUrl);
|
||||
|
||||
if (adminUrl && id === adminTenantId) {
|
||||
return adminUrl;
|
||||
}
|
||||
|
||||
if (!isDomainBasedMultiTenancy) {
|
||||
return trySafe(() => urlSet.localhostUrl);
|
||||
}
|
||||
};
|
||||
|
||||
export const getTenantUrls = (id: string, globalValues: GlobalValues): URL[] => {
|
||||
const endpoint = getTenantEndpoint(id, globalValues);
|
||||
const localhost = getTenantLocalhost(id, globalValues);
|
||||
|
||||
return deduplicate(
|
||||
[endpoint.toString(), localhost?.toString()].filter(
|
||||
(value): value is string => typeof value === 'string'
|
||||
)
|
||||
).map((element) => new URL(element));
|
||||
};
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
import { demoAppApplicationId } from '@logto/schemas';
|
||||
import type { MiddlewareType } from 'koa';
|
||||
|
||||
import type Queries from '#src/tenants/Queries.js';
|
||||
|
||||
export default function koaCheckDemoApp<StateT, ContextT, ResponseBodyT>(
|
||||
queries: Queries
|
||||
): MiddlewareType<StateT, ContextT, ResponseBodyT> {
|
||||
const { findApplicationById } = queries.applications;
|
||||
|
||||
return async (ctx, next) => {
|
||||
try {
|
||||
await findApplicationById(demoAppApplicationId);
|
||||
|
||||
await next();
|
||||
|
||||
return;
|
||||
} catch {
|
||||
ctx.throw(404);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
import type { CreateApplication, OidcClientMetadata } from '@logto/schemas';
|
||||
import type { CreateApplication } from '@logto/schemas';
|
||||
import { ApplicationType, adminConsoleApplicationId, demoAppApplicationId } from '@logto/schemas';
|
||||
import { tryThat } from '@logto/shared';
|
||||
import { deduplicate } from '@silverhand/essentials';
|
||||
import { addSeconds } from 'date-fns';
|
||||
import type { AdapterFactory, AllClientMetadata } from 'oidc-provider';
|
||||
import { errors } from 'oidc-provider';
|
||||
import snakecaseKeys from 'snakecase-keys';
|
||||
|
||||
import { EnvSet, UserApps } from '#src/env-set/index.js';
|
||||
import { EnvSet } from '#src/env-set/index.js';
|
||||
import { getTenantUrls } from '#src/env-set/utils.js';
|
||||
import type Queries from '#src/tenants/Queries.js';
|
||||
import { appendPath } from '#src/utils/url.js';
|
||||
|
||||
|
@ -28,18 +28,18 @@ const buildAdminConsoleClientMetadata = (envSet: EnvSet): AllClientMetadata => {
|
|||
};
|
||||
};
|
||||
|
||||
const buildDemoAppUris = (
|
||||
oidcClientMetadata: OidcClientMetadata
|
||||
): Pick<OidcClientMetadata, 'redirectUris' | 'postLogoutRedirectUris'> => {
|
||||
const { urlSet } = EnvSet.values;
|
||||
const urls = urlSet.deduplicated().map((url) => appendPath(url, UserApps.DemoApp).toString());
|
||||
const buildDemoAppClientMetadata = (envSet: EnvSet): AllClientMetadata => {
|
||||
const urls = getTenantUrls(envSet.tenantId, EnvSet.values).map((url) =>
|
||||
appendPath(url, '/demo-app').toString()
|
||||
);
|
||||
|
||||
const data = {
|
||||
redirectUris: deduplicate([...urls, ...oidcClientMetadata.redirectUris]),
|
||||
postLogoutRedirectUris: deduplicate([...urls, ...oidcClientMetadata.postLogoutRedirectUris]),
|
||||
return {
|
||||
...getConstantClientMetadata(envSet, ApplicationType.SPA),
|
||||
client_id: demoAppApplicationId,
|
||||
client_name: 'Demo App',
|
||||
redirect_uris: urls,
|
||||
post_logout_redirect_uris: urls,
|
||||
};
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
export default function postgresAdapter(
|
||||
|
@ -76,8 +76,6 @@ export default function postgresAdapter(
|
|||
client_name,
|
||||
...getConstantClientMetadata(envSet, type),
|
||||
...snakecaseKeys(oidcClientMetadata),
|
||||
...(client_id === demoAppApplicationId &&
|
||||
snakecaseKeys(buildDemoAppUris(oidcClientMetadata))),
|
||||
// `node-oidc-provider` won't camelCase custom parameter keys, so we need to keep the keys camelCased
|
||||
...customClientMetadata,
|
||||
});
|
||||
|
@ -90,6 +88,10 @@ export default function postgresAdapter(
|
|||
return buildAdminConsoleClientMetadata(envSet);
|
||||
}
|
||||
|
||||
if (id === demoAppApplicationId) {
|
||||
return buildDemoAppClientMetadata(envSet);
|
||||
}
|
||||
|
||||
return transpileClient(
|
||||
await tryThat(findApplicationById(id), new errors.InvalidClient(`invalid client ${id}`))
|
||||
);
|
||||
|
|
|
@ -25,7 +25,6 @@ const middlewareList = Object.freeze(
|
|||
'oidc-error-handler',
|
||||
'slonik-error-handler',
|
||||
'spa-proxy',
|
||||
'check-demo-app',
|
||||
'console-redirect-proxy',
|
||||
].map((name) => [name, buildMockMiddleware(name)] as const)
|
||||
);
|
||||
|
|
|
@ -7,7 +7,6 @@ import mount from 'koa-mount';
|
|||
import type Provider from 'oidc-provider';
|
||||
|
||||
import { AdminApps, EnvSet, UserApps } from '#src/env-set/index.js';
|
||||
import koaCheckDemoApp from '#src/middleware/koa-check-demo-app.js';
|
||||
import koaConnectorErrorHandler from '#src/middleware/koa-connector-error-handler.js';
|
||||
import koaConsoleRedirectProxy from '#src/middleware/koa-console-redirect-proxy.js';
|
||||
import koaErrorHandler from '#src/middleware/koa-error-handler.js';
|
||||
|
@ -97,10 +96,7 @@ export default class Tenant implements TenantContext {
|
|||
app.use(
|
||||
mount(
|
||||
'/' + UserApps.DemoApp,
|
||||
compose([
|
||||
koaCheckDemoApp(this.queries),
|
||||
koaSpaProxy(mountedApps, UserApps.DemoApp, 5003, UserApps.DemoApp),
|
||||
])
|
||||
koaSpaProxy(mountedApps, UserApps.DemoApp, 5003, UserApps.DemoApp)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ApplicationType, demoAppApplicationId } from '@logto/schemas';
|
||||
import { ApplicationType } from '@logto/schemas';
|
||||
import { HTTPError } from 'got';
|
||||
|
||||
import {
|
||||
|
@ -9,12 +9,6 @@ import {
|
|||
} from '#src/api/index.js';
|
||||
|
||||
describe('admin console application', () => {
|
||||
it('should get demo app details successfully', async () => {
|
||||
const demoApp = await getApplication(demoAppApplicationId);
|
||||
|
||||
expect(demoApp.id).toBe(demoAppApplicationId);
|
||||
});
|
||||
|
||||
it('should create application successfully', async () => {
|
||||
const applicationName = 'test-create-app';
|
||||
const applicationType = ApplicationType.SPA;
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
import { generateStandardId } from '@logto/core-kit';
|
||||
import chalk from 'chalk';
|
||||
import inquirer from 'inquirer';
|
||||
import { sql } from 'slonik';
|
||||
|
||||
import type { AlterationScript } from '../lib/types/alteration.js';
|
||||
|
||||
const defaultTenantId = 'default';
|
||||
|
||||
const alteration: AlterationScript = {
|
||||
up: async (pool) => {
|
||||
const isCi = process.env.CI;
|
||||
const { confirm } = await inquirer.prompt<{ confirm: boolean }>({
|
||||
type: 'confirm',
|
||||
name: 'confirm',
|
||||
message: String(
|
||||
chalk.bold(chalk.yellow('***CAUTION***')) +
|
||||
'\n' +
|
||||
'The application `demo-app` will be removed from your database.\n' +
|
||||
'Usually this is harmless since the demo app will be still functional with predefined data.\n' +
|
||||
'Are you sure to continue?'
|
||||
),
|
||||
default: false,
|
||||
when: !isCi,
|
||||
});
|
||||
|
||||
if (!isCi && !confirm) {
|
||||
throw new Error('User cancelled alteration.');
|
||||
}
|
||||
|
||||
await pool.query(sql`
|
||||
delete from applications where id = 'demo-app';
|
||||
`);
|
||||
},
|
||||
down: async (pool) => {
|
||||
await pool.query(sql`
|
||||
insert into applications
|
||||
(tenant_id, id, secret, name, description, type, oidc_client_metadata)
|
||||
values (
|
||||
'default',
|
||||
'demo-app',
|
||||
${generateStandardId()},
|
||||
'Demo App',
|
||||
'Logto demo app.',
|
||||
'SPA',
|
||||
'{ "redirectUris": [], "postLogoutRedirectUris": [] }'::jsonb
|
||||
)
|
||||
`);
|
||||
},
|
||||
};
|
||||
|
||||
export default alteration;
|
|
@ -48,6 +48,7 @@
|
|||
"@types/node": "^18.11.18",
|
||||
"@types/pluralize": "^0.0.29",
|
||||
"camelcase": "^7.0.0",
|
||||
"chalk": "^5.0.0",
|
||||
"eslint": "^8.34.0",
|
||||
"jest": "^29.1.2",
|
||||
"lint-staged": "^13.0.0",
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
import { generateStandardId } from '@logto/core-kit';
|
||||
|
||||
import type { CreateApplication } from '../db-entries/index.js';
|
||||
import { ApplicationType } from '../db-entries/index.js';
|
||||
|
||||
/**
|
||||
* The fixed application ID for Admin Console.
|
||||
*
|
||||
|
@ -11,14 +6,3 @@ import { ApplicationType } from '../db-entries/index.js';
|
|||
export const adminConsoleApplicationId = 'admin-console';
|
||||
|
||||
export const demoAppApplicationId = 'demo-app';
|
||||
|
||||
/** @deprecated Demo app database entity will be removed soon. */
|
||||
export const createDemoAppApplication = (forTenantId: string): Readonly<CreateApplication> => ({
|
||||
tenantId: forTenantId,
|
||||
id: demoAppApplicationId,
|
||||
secret: generateStandardId(),
|
||||
name: 'Demo App',
|
||||
description: 'Logto demo app.',
|
||||
type: ApplicationType.SPA,
|
||||
oidcClientMetadata: { redirectUris: [], postLogoutRedirectUris: [] },
|
||||
});
|
||||
|
|
|
@ -653,6 +653,7 @@ importers:
|
|||
'@types/pluralize': ^0.0.29
|
||||
'@withtyped/server': ^0.8.0
|
||||
camelcase: ^7.0.0
|
||||
chalk: ^5.0.0
|
||||
eslint: ^8.34.0
|
||||
jest: ^29.1.2
|
||||
lint-staged: ^13.0.0
|
||||
|
@ -680,6 +681,7 @@ importers:
|
|||
'@types/node': 18.11.18
|
||||
'@types/pluralize': 0.0.29
|
||||
camelcase: 7.0.0
|
||||
chalk: 5.1.2
|
||||
eslint: 8.34.0
|
||||
jest: 29.1.2_@types+node@18.11.18
|
||||
lint-staged: 13.0.0
|
||||
|
@ -5283,7 +5285,6 @@ packages:
|
|||
/chalk/5.1.2:
|
||||
resolution: {integrity: sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==}
|
||||
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
|
||||
dev: false
|
||||
|
||||
/char-regex/1.0.2:
|
||||
resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
|
||||
|
|
Loading…
Reference in a new issue