mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-04 01:18:20 +02:00
refactor: remove bootstrap endpoint (#1900)
This commit is contained in:
parent
eb2de89b3c
commit
49095025ff
@ -7,7 +7,6 @@ import { apiTokenSchema } from './spec/api-token-schema';
|
|||||||
import { apiTokensSchema } from './spec/api-tokens-schema';
|
import { apiTokensSchema } from './spec/api-tokens-schema';
|
||||||
import { applicationSchema } from './spec/application-schema';
|
import { applicationSchema } from './spec/application-schema';
|
||||||
import { applicationsSchema } from './spec/applications-schema';
|
import { applicationsSchema } from './spec/applications-schema';
|
||||||
import { bootstrapUiSchema } from './spec/bootstrap-ui-schema';
|
|
||||||
import { changePasswordSchema } from './spec/change-password-schema';
|
import { changePasswordSchema } from './spec/change-password-schema';
|
||||||
import { clientApplicationSchema } from './spec/client-application-schema';
|
import { clientApplicationSchema } from './spec/client-application-schema';
|
||||||
import { clientFeatureSchema } from './spec/client-feature-schema';
|
import { clientFeatureSchema } from './spec/client-feature-schema';
|
||||||
@ -116,7 +115,6 @@ export const schemas = {
|
|||||||
apiTokensSchema,
|
apiTokensSchema,
|
||||||
applicationSchema,
|
applicationSchema,
|
||||||
applicationsSchema,
|
applicationsSchema,
|
||||||
bootstrapUiSchema,
|
|
||||||
changePasswordSchema,
|
changePasswordSchema,
|
||||||
clientApplicationSchema,
|
clientApplicationSchema,
|
||||||
clientFeatureSchema,
|
clientFeatureSchema,
|
||||||
|
@ -1,157 +0,0 @@
|
|||||||
import { validateSchema } from '../validate';
|
|
||||||
import { BootstrapUiSchema } from './bootstrap-ui-schema';
|
|
||||||
|
|
||||||
test('bootstrapUiSchema', () => {
|
|
||||||
const data: BootstrapUiSchema = {
|
|
||||||
uiConfig: {
|
|
||||||
flags: { E: true },
|
|
||||||
authenticationType: 'open-source',
|
|
||||||
unleashUrl: 'http://localhost:4242',
|
|
||||||
version: '4.14.0-beta.0',
|
|
||||||
baseUriPath: '',
|
|
||||||
versionInfo: {
|
|
||||||
current: { oss: '4.14.0-beta.0', enterprise: '' },
|
|
||||||
latest: {},
|
|
||||||
isLatest: true,
|
|
||||||
instanceId: '51c9190a-4ff5-4f47-b73a-7aebe06f9331',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
isAPI: false,
|
|
||||||
id: 1,
|
|
||||||
username: 'admin',
|
|
||||||
imageUrl:
|
|
||||||
'https://gravatar.com/avatar/21232f297a57a5a743894a0e4a801fc3?size=42&default=retro',
|
|
||||||
seenAt: '2022-06-27T12:19:15.838Z',
|
|
||||||
loginAttempts: 0,
|
|
||||||
createdAt: '2022-04-08T10:59:25.072Z',
|
|
||||||
permissions: [
|
|
||||||
{ permission: 'READ_API_TOKEN' },
|
|
||||||
{
|
|
||||||
project: 'default',
|
|
||||||
environment: 'staging',
|
|
||||||
permission: 'CREATE_FEATURE_STRATEGY',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
project: 'default',
|
|
||||||
environment: 'staging',
|
|
||||||
permission: 'UPDATE_FEATURE_STRATEGY',
|
|
||||||
},
|
|
||||||
{ project: 'default', permission: 'UPDATE_FEATURE' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
email: false,
|
|
||||||
context: [
|
|
||||||
{
|
|
||||||
name: 'appName',
|
|
||||||
description: 'Allows you to constrain on application name',
|
|
||||||
stickiness: false,
|
|
||||||
sortOrder: 2,
|
|
||||||
legalValues: [],
|
|
||||||
createdAt: '2022-04-08T10:59:24.374Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'currentTime',
|
|
||||||
description: '',
|
|
||||||
stickiness: false,
|
|
||||||
sortOrder: 10,
|
|
||||||
legalValues: [],
|
|
||||||
createdAt: '2022-05-18T08:15:18.917Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'environment',
|
|
||||||
description:
|
|
||||||
'Allows you to constrain on application environment',
|
|
||||||
stickiness: false,
|
|
||||||
sortOrder: 0,
|
|
||||||
legalValues: [],
|
|
||||||
createdAt: '2022-04-08T10:59:24.374Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'userId',
|
|
||||||
description: 'Allows you to constrain on userId',
|
|
||||||
stickiness: false,
|
|
||||||
sortOrder: 1,
|
|
||||||
legalValues: [],
|
|
||||||
createdAt: '2022-04-08T10:59:24.374Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
featureTypes: [
|
|
||||||
{
|
|
||||||
id: 'release',
|
|
||||||
name: 'Release',
|
|
||||||
description:
|
|
||||||
'Release feature toggles are used to release new features.',
|
|
||||||
lifetimeDays: 40,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'experiment',
|
|
||||||
name: 'Experiment',
|
|
||||||
description:
|
|
||||||
'Experiment feature toggles are used to test and verify multiple different versions of a feature.',
|
|
||||||
lifetimeDays: 40,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'operational',
|
|
||||||
name: 'Operational',
|
|
||||||
description:
|
|
||||||
'Operational feature toggles are used to control aspects of a rollout.',
|
|
||||||
lifetimeDays: 7,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
tagTypes: [
|
|
||||||
{
|
|
||||||
name: 'simple',
|
|
||||||
description: 'Used to simplify filtering of features',
|
|
||||||
icon: '#',
|
|
||||||
},
|
|
||||||
{ name: 'hashtag', description: '', icon: null },
|
|
||||||
],
|
|
||||||
strategies: [
|
|
||||||
{
|
|
||||||
displayName: 'Standard',
|
|
||||||
name: 'default',
|
|
||||||
editable: false,
|
|
||||||
description:
|
|
||||||
'The standard strategy is strictly on / off for your entire userbase.',
|
|
||||||
parameters: [],
|
|
||||||
deprecated: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayName: null,
|
|
||||||
name: 'gradualRolloutRandom',
|
|
||||||
editable: true,
|
|
||||||
description:
|
|
||||||
'Randomly activate the feature toggle. No stickiness.',
|
|
||||||
parameters: [
|
|
||||||
{
|
|
||||||
name: 'percentage',
|
|
||||||
type: 'percentage',
|
|
||||||
description: '',
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
deprecated: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
projects: [
|
|
||||||
{
|
|
||||||
name: 'Default',
|
|
||||||
id: 'default',
|
|
||||||
description: 'Default project',
|
|
||||||
health: 74,
|
|
||||||
featureCount: 10,
|
|
||||||
memberCount: 3,
|
|
||||||
updatedAt: '2022-06-28T17:33:53.963Z',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(
|
|
||||||
validateSchema('#/components/schemas/bootstrapUiSchema', {}),
|
|
||||||
).not.toBeUndefined();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
validateSchema('#/components/schemas/bootstrapUiSchema', data),
|
|
||||||
).toBeUndefined();
|
|
||||||
});
|
|
@ -1,94 +0,0 @@
|
|||||||
import { FromSchema } from 'json-schema-to-ts';
|
|
||||||
import { uiConfigSchema } from './ui-config-schema';
|
|
||||||
import { userSchema } from './user-schema';
|
|
||||||
import { permissionSchema } from './permission-schema';
|
|
||||||
import { featureTypeSchema } from './feature-type-schema';
|
|
||||||
import { tagTypeSchema } from './tag-type-schema';
|
|
||||||
import { contextFieldSchema } from './context-field-schema';
|
|
||||||
import { strategySchema } from './strategy-schema';
|
|
||||||
import { projectSchema } from './project-schema';
|
|
||||||
import { versionSchema } from './version-schema';
|
|
||||||
import { legalValueSchema } from './legal-value-schema';
|
|
||||||
|
|
||||||
export const bootstrapUiSchema = {
|
|
||||||
$id: '#/components/schemas/bootstrapUiSchema',
|
|
||||||
type: 'object',
|
|
||||||
additionalProperties: false,
|
|
||||||
required: [
|
|
||||||
'uiConfig',
|
|
||||||
'user',
|
|
||||||
'email',
|
|
||||||
'context',
|
|
||||||
'featureTypes',
|
|
||||||
'tagTypes',
|
|
||||||
'strategies',
|
|
||||||
'projects',
|
|
||||||
],
|
|
||||||
properties: {
|
|
||||||
uiConfig: {
|
|
||||||
$ref: '#/components/schemas/uiConfigSchema',
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
type: 'object',
|
|
||||||
required: [...userSchema.required],
|
|
||||||
properties: {
|
|
||||||
...userSchema.properties,
|
|
||||||
permissions: {
|
|
||||||
type: 'array',
|
|
||||||
items: {
|
|
||||||
$ref: '#/components/schemas/permissionSchema',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
email: {
|
|
||||||
type: 'boolean',
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
type: 'array',
|
|
||||||
items: {
|
|
||||||
$ref: '#/components/schemas/contextFieldSchema',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
featureTypes: {
|
|
||||||
type: 'array',
|
|
||||||
items: {
|
|
||||||
$ref: '#/components/schemas/featureTypeSchema',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tagTypes: {
|
|
||||||
type: 'array',
|
|
||||||
items: {
|
|
||||||
$ref: '#/components/schemas/tagTypeSchema',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
strategies: {
|
|
||||||
type: 'array',
|
|
||||||
items: {
|
|
||||||
$ref: '#/components/schemas/strategySchema',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
projects: {
|
|
||||||
type: 'array',
|
|
||||||
items: {
|
|
||||||
$ref: '#/components/schemas/projectSchema',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
schemas: {
|
|
||||||
uiConfigSchema,
|
|
||||||
userSchema,
|
|
||||||
permissionSchema,
|
|
||||||
contextFieldSchema,
|
|
||||||
featureTypeSchema,
|
|
||||||
tagTypeSchema,
|
|
||||||
strategySchema,
|
|
||||||
projectSchema,
|
|
||||||
versionSchema,
|
|
||||||
legalValueSchema,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export type BootstrapUiSchema = FromSchema<typeof bootstrapUiSchema>;
|
|
@ -8,7 +8,11 @@ test('contextFieldSchema', () => {
|
|||||||
stickiness: false,
|
stickiness: false,
|
||||||
sortOrder: 0,
|
sortOrder: 0,
|
||||||
createdAt: '2022-01-01T00:00:00.000Z',
|
createdAt: '2022-01-01T00:00:00.000Z',
|
||||||
legalValues: [],
|
legalValues: [
|
||||||
|
{ value: 'a' },
|
||||||
|
{ value: 'b', description: '' },
|
||||||
|
{ value: 'c', description: 'd' },
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
|
22
src/lib/openapi/spec/project-schema.test.ts
Normal file
22
src/lib/openapi/spec/project-schema.test.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { validateSchema } from '../validate';
|
||||||
|
import { ProjectSchema } from './project-schema';
|
||||||
|
|
||||||
|
test('projectSchema', () => {
|
||||||
|
const data: ProjectSchema = {
|
||||||
|
name: 'Default',
|
||||||
|
id: 'default',
|
||||||
|
description: 'Default project',
|
||||||
|
health: 74,
|
||||||
|
featureCount: 10,
|
||||||
|
memberCount: 3,
|
||||||
|
updatedAt: '2022-06-28T17:33:53.963Z',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(
|
||||||
|
validateSchema('#/components/schemas/projectSchema', {}),
|
||||||
|
).not.toBeUndefined();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
validateSchema('#/components/schemas/projectSchema', data),
|
||||||
|
).toBeUndefined();
|
||||||
|
});
|
28
src/lib/openapi/spec/tag-types-schema.test.ts
Normal file
28
src/lib/openapi/spec/tag-types-schema.test.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { validateSchema } from '../validate';
|
||||||
|
import { TagTypesSchema } from './tag-types-schema';
|
||||||
|
|
||||||
|
test('tagTypesSchema', () => {
|
||||||
|
const data: TagTypesSchema = {
|
||||||
|
version: 1,
|
||||||
|
tagTypes: [
|
||||||
|
{
|
||||||
|
name: 'simple',
|
||||||
|
description: 'Used to simplify filtering of features',
|
||||||
|
icon: '#',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'hashtag',
|
||||||
|
description: '',
|
||||||
|
icon: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(
|
||||||
|
validateSchema('#/components/schemas/tagTypesSchema', {}),
|
||||||
|
).not.toBeUndefined();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
validateSchema('#/components/schemas/tagTypesSchema', data),
|
||||||
|
).toBeUndefined();
|
||||||
|
});
|
@ -28,6 +28,9 @@ export const uiConfigSchema = {
|
|||||||
disablePasswordAuth: {
|
disablePasswordAuth: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
},
|
},
|
||||||
|
emailEnabled: {
|
||||||
|
type: 'boolean',
|
||||||
|
},
|
||||||
segmentValuesLimit: {
|
segmentValuesLimit: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
},
|
},
|
||||||
|
22
src/lib/openapi/spec/user-schema.test.ts
Normal file
22
src/lib/openapi/spec/user-schema.test.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { validateSchema } from '../validate';
|
||||||
|
import { UserSchema } from './user-schema';
|
||||||
|
|
||||||
|
test('userSchema', () => {
|
||||||
|
const data: UserSchema = {
|
||||||
|
isAPI: false,
|
||||||
|
id: 1,
|
||||||
|
username: 'admin',
|
||||||
|
imageUrl: 'avatar',
|
||||||
|
seenAt: '2022-06-27T12:19:15.838Z',
|
||||||
|
loginAttempts: 0,
|
||||||
|
createdAt: '2022-04-08T10:59:25.072Z',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(
|
||||||
|
validateSchema('#/components/schemas/userSchema', {}),
|
||||||
|
).not.toBeUndefined();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
validateSchema('#/components/schemas/userSchema', data),
|
||||||
|
).toBeUndefined();
|
||||||
|
});
|
@ -1,63 +0,0 @@
|
|||||||
import supertest from 'supertest';
|
|
||||||
import { createTestConfig } from '../../../test/config/test-config';
|
|
||||||
import { randomId } from '../../util/random-id';
|
|
||||||
|
|
||||||
import createStores from '../../../test/fixtures/store';
|
|
||||||
import getApp from '../../app';
|
|
||||||
import { createServices } from '../../services';
|
|
||||||
const uiConfig = {
|
|
||||||
headerBackground: 'red',
|
|
||||||
slogan: 'hello',
|
|
||||||
};
|
|
||||||
|
|
||||||
async function getSetup() {
|
|
||||||
const base = `/random${randomId()}`;
|
|
||||||
const config = createTestConfig({
|
|
||||||
server: { baseUriPath: base },
|
|
||||||
ui: uiConfig,
|
|
||||||
});
|
|
||||||
const stores = createStores();
|
|
||||||
const services = createServices(stores, config);
|
|
||||||
|
|
||||||
const app = await getApp(config, stores, services);
|
|
||||||
|
|
||||||
return {
|
|
||||||
base,
|
|
||||||
request: supertest(app),
|
|
||||||
destroy: () => {
|
|
||||||
services.versionService.destroy();
|
|
||||||
services.clientInstanceService.destroy();
|
|
||||||
services.apiTokenService.destroy();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let request;
|
|
||||||
let base;
|
|
||||||
let destroy;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const setup = await getSetup();
|
|
||||||
request = setup.request;
|
|
||||||
base = setup.base;
|
|
||||||
destroy = setup.destroy;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should get ui config', async () => {
|
|
||||||
const { body } = await request
|
|
||||||
.get(`${base}/api/admin/ui-bootstrap`)
|
|
||||||
.expect('Content-Type', /json/)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
expect(body.uiConfig.slogan).toEqual('hello');
|
|
||||||
expect(body.email).toEqual(false);
|
|
||||||
expect(body.user).toHaveProperty('permissions');
|
|
||||||
expect(body.context).toBeInstanceOf(Array);
|
|
||||||
expect(body.tagTypes).toBeInstanceOf(Array);
|
|
||||||
expect(body.strategies).toBeInstanceOf(Array);
|
|
||||||
expect(body.projects).toBeInstanceOf(Array);
|
|
||||||
});
|
|
@ -1,173 +0,0 @@
|
|||||||
import { Response } from 'express';
|
|
||||||
import Controller from '../controller';
|
|
||||||
import { AuthedRequest } from '../../types/core';
|
|
||||||
import { Logger } from '../../logger';
|
|
||||||
import ContextService from '../../services/context-service';
|
|
||||||
import TagTypeService from '../../services/tag-type-service';
|
|
||||||
import StrategyService from '../../services/strategy-service';
|
|
||||||
import ProjectService from '../../services/project-service';
|
|
||||||
import { AccessService } from '../../services/access-service';
|
|
||||||
import { EmailService } from '../../services/email-service';
|
|
||||||
import { IUnleashConfig } from '../../types/option';
|
|
||||||
import { IUnleashServices } from '../../types/services';
|
|
||||||
import VersionService from '../../services/version-service';
|
|
||||||
import FeatureTypeService from '../../services/feature-type-service';
|
|
||||||
import version from '../../util/version';
|
|
||||||
import { IContextField } from '../../types/stores/context-field-store';
|
|
||||||
import { IFeatureType } from '../../types/stores/feature-type-store';
|
|
||||||
import { ITagType } from '../../types/stores/tag-type-store';
|
|
||||||
import { IStrategy } from '../../types/stores/strategy-store';
|
|
||||||
import { IProject } from '../../types/model';
|
|
||||||
import { IUserPermission } from '../../types/stores/access-store';
|
|
||||||
import { OpenApiService } from '../../services/openapi-service';
|
|
||||||
import { NONE } from '../../types/permissions';
|
|
||||||
import { createResponseSchema } from '../../openapi/util/create-response-schema';
|
|
||||||
import {
|
|
||||||
BootstrapUiSchema,
|
|
||||||
bootstrapUiSchema,
|
|
||||||
} from '../../openapi/spec/bootstrap-ui-schema';
|
|
||||||
import { serializeDates } from '../../types/serialize-dates';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides admin UI configuration.
|
|
||||||
* Not to be confused with SDK bootstrapping.
|
|
||||||
*/
|
|
||||||
class BootstrapUIController extends Controller {
|
|
||||||
private logger: Logger;
|
|
||||||
|
|
||||||
private accessService: AccessService;
|
|
||||||
|
|
||||||
private contextService: ContextService;
|
|
||||||
|
|
||||||
private emailService: EmailService;
|
|
||||||
|
|
||||||
private featureTypeService: FeatureTypeService;
|
|
||||||
|
|
||||||
private projectService: ProjectService;
|
|
||||||
|
|
||||||
private strategyService: StrategyService;
|
|
||||||
|
|
||||||
private tagTypeService: TagTypeService;
|
|
||||||
|
|
||||||
private versionService: VersionService;
|
|
||||||
|
|
||||||
private openApiService: OpenApiService;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
config: IUnleashConfig,
|
|
||||||
{
|
|
||||||
contextService,
|
|
||||||
tagTypeService,
|
|
||||||
strategyService,
|
|
||||||
projectService,
|
|
||||||
accessService,
|
|
||||||
emailService,
|
|
||||||
versionService,
|
|
||||||
featureTypeService,
|
|
||||||
openApiService,
|
|
||||||
}: Pick<
|
|
||||||
IUnleashServices,
|
|
||||||
| 'contextService'
|
|
||||||
| 'tagTypeService'
|
|
||||||
| 'strategyService'
|
|
||||||
| 'projectService'
|
|
||||||
| 'accessService'
|
|
||||||
| 'emailService'
|
|
||||||
| 'versionService'
|
|
||||||
| 'featureTypeService'
|
|
||||||
| 'openApiService'
|
|
||||||
>,
|
|
||||||
) {
|
|
||||||
super(config);
|
|
||||||
this.contextService = contextService;
|
|
||||||
this.tagTypeService = tagTypeService;
|
|
||||||
this.strategyService = strategyService;
|
|
||||||
this.projectService = projectService;
|
|
||||||
this.accessService = accessService;
|
|
||||||
this.featureTypeService = featureTypeService;
|
|
||||||
this.emailService = emailService;
|
|
||||||
this.versionService = versionService;
|
|
||||||
this.openApiService = openApiService;
|
|
||||||
|
|
||||||
this.logger = config.getLogger('routes/admin-api/bootstrap-ui.ts');
|
|
||||||
this.route({
|
|
||||||
method: 'get',
|
|
||||||
path: '',
|
|
||||||
handler: this.bootstrap,
|
|
||||||
permission: NONE,
|
|
||||||
middleware: [
|
|
||||||
openApiService.validPath({
|
|
||||||
tags: ['other'],
|
|
||||||
operationId: 'getBootstrapUiData',
|
|
||||||
responses: {
|
|
||||||
202: createResponseSchema('bootstrapUiSchema'),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async bootstrap(
|
|
||||||
req: AuthedRequest,
|
|
||||||
res: Response<BootstrapUiSchema>,
|
|
||||||
): Promise<void> {
|
|
||||||
const jobs: [
|
|
||||||
Promise<IContextField[]>,
|
|
||||||
Promise<IFeatureType[]>,
|
|
||||||
Promise<ITagType[]>,
|
|
||||||
Promise<IStrategy[]>,
|
|
||||||
Promise<IProject[]>,
|
|
||||||
Promise<IUserPermission[]>,
|
|
||||||
] = [
|
|
||||||
this.contextService.getAll(),
|
|
||||||
this.featureTypeService.getAll(),
|
|
||||||
this.tagTypeService.getAll(),
|
|
||||||
this.strategyService.getStrategies(),
|
|
||||||
this.projectService.getProjects(),
|
|
||||||
this.accessService.getPermissionsForUser(req.user),
|
|
||||||
];
|
|
||||||
const [
|
|
||||||
context,
|
|
||||||
featureTypes,
|
|
||||||
tagTypes,
|
|
||||||
strategies,
|
|
||||||
projects,
|
|
||||||
userPermissions,
|
|
||||||
] = await Promise.all(jobs);
|
|
||||||
|
|
||||||
const authenticationType =
|
|
||||||
this.config.authentication && this.config.authentication.type;
|
|
||||||
const versionInfo = this.versionService.getVersionInfo();
|
|
||||||
|
|
||||||
const uiConfig = {
|
|
||||||
...this.config.ui,
|
|
||||||
authenticationType,
|
|
||||||
unleashUrl: this.config.server.unleashUrl,
|
|
||||||
version,
|
|
||||||
baseUriPath: this.config.server.baseUriPath,
|
|
||||||
versionInfo,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.openApiService.respondWithValidation(
|
|
||||||
200,
|
|
||||||
res,
|
|
||||||
bootstrapUiSchema.$id,
|
|
||||||
{
|
|
||||||
uiConfig,
|
|
||||||
user: {
|
|
||||||
...serializeDates(req.user),
|
|
||||||
permissions: userPermissions,
|
|
||||||
},
|
|
||||||
email: this.emailService.isEnabled(),
|
|
||||||
context: serializeDates(context),
|
|
||||||
featureTypes,
|
|
||||||
tagTypes,
|
|
||||||
strategies,
|
|
||||||
projects: serializeDates(projects),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BootstrapUIController;
|
|
||||||
module.exports = BootstrapUIController;
|
|
@ -16,12 +16,15 @@ import {
|
|||||||
UiConfigSchema,
|
UiConfigSchema,
|
||||||
} from '../../openapi/spec/ui-config-schema';
|
} from '../../openapi/spec/ui-config-schema';
|
||||||
import { OpenApiService } from '../../services/openapi-service';
|
import { OpenApiService } from '../../services/openapi-service';
|
||||||
|
import { EmailService } from '../../services/email-service';
|
||||||
|
|
||||||
class ConfigController extends Controller {
|
class ConfigController extends Controller {
|
||||||
private versionService: VersionService;
|
private versionService: VersionService;
|
||||||
|
|
||||||
private settingService: SettingService;
|
private settingService: SettingService;
|
||||||
|
|
||||||
|
private emailService: EmailService;
|
||||||
|
|
||||||
private readonly openApiService: OpenApiService;
|
private readonly openApiService: OpenApiService;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -29,15 +32,20 @@ class ConfigController extends Controller {
|
|||||||
{
|
{
|
||||||
versionService,
|
versionService,
|
||||||
settingService,
|
settingService,
|
||||||
|
emailService,
|
||||||
openApiService,
|
openApiService,
|
||||||
}: Pick<
|
}: Pick<
|
||||||
IUnleashServices,
|
IUnleashServices,
|
||||||
'versionService' | 'settingService' | 'openApiService'
|
| 'versionService'
|
||||||
|
| 'settingService'
|
||||||
|
| 'emailService'
|
||||||
|
| 'openApiService'
|
||||||
>,
|
>,
|
||||||
) {
|
) {
|
||||||
super(config);
|
super(config);
|
||||||
this.versionService = versionService;
|
this.versionService = versionService;
|
||||||
this.settingService = settingService;
|
this.settingService = settingService;
|
||||||
|
this.emailService = emailService;
|
||||||
this.openApiService = openApiService;
|
this.openApiService = openApiService;
|
||||||
|
|
||||||
this.route({
|
this.route({
|
||||||
@ -71,6 +79,7 @@ class ConfigController extends Controller {
|
|||||||
const response: UiConfigSchema = {
|
const response: UiConfigSchema = {
|
||||||
...this.config.ui,
|
...this.config.ui,
|
||||||
version,
|
version,
|
||||||
|
emailEnabled: this.emailService.isEnabled(),
|
||||||
unleashUrl: this.config.server.unleashUrl,
|
unleashUrl: this.config.server.unleashUrl,
|
||||||
baseUriPath: this.config.server.baseUriPath,
|
baseUriPath: this.config.server.baseUriPath,
|
||||||
authenticationType: this.config.authentication?.type,
|
authenticationType: this.config.authentication?.type,
|
||||||
|
@ -13,7 +13,6 @@ import UserController from './user';
|
|||||||
import ConfigController from './config';
|
import ConfigController from './config';
|
||||||
import { ContextController } from './context';
|
import { ContextController } from './context';
|
||||||
import ClientMetricsController from './client-metrics';
|
import ClientMetricsController from './client-metrics';
|
||||||
import BootstrapUIController from './bootstrap-ui';
|
|
||||||
import StateController from './state';
|
import StateController from './state';
|
||||||
import TagController from './tag';
|
import TagController from './tag';
|
||||||
import TagTypeController from './tag-type';
|
import TagTypeController from './tag-type';
|
||||||
@ -68,10 +67,6 @@ class AdminApi extends Controller {
|
|||||||
'/ui-config',
|
'/ui-config',
|
||||||
new ConfigController(config, services).router,
|
new ConfigController(config, services).router,
|
||||||
);
|
);
|
||||||
this.app.use(
|
|
||||||
'/ui-bootstrap',
|
|
||||||
new BootstrapUIController(config, services).router,
|
|
||||||
);
|
|
||||||
this.app.use(
|
this.app.use(
|
||||||
'/context',
|
'/context',
|
||||||
new ContextController(config, services).router,
|
new ContextController(config, services).router,
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
import dbInit from '../../helpers/database-init';
|
|
||||||
import getLogger from '../../../fixtures/no-logger';
|
|
||||||
import { setupAppWithAuth } from '../../helpers/test-helper';
|
|
||||||
|
|
||||||
let app;
|
|
||||||
let db;
|
|
||||||
|
|
||||||
const email = 'user@getunleash.io';
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
db = await dbInit('ui_bootstrap_serial', getLogger);
|
|
||||||
app = await setupAppWithAuth(db.stores);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
await app.destroy();
|
|
||||||
await db.destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should get ui-bootstrap data', async () => {
|
|
||||||
// login
|
|
||||||
await app.request
|
|
||||||
.post('/auth/demo/login')
|
|
||||||
.send({
|
|
||||||
email,
|
|
||||||
})
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
// get user data
|
|
||||||
await app.request
|
|
||||||
.get('/api/admin/ui-bootstrap')
|
|
||||||
.expect(200)
|
|
||||||
.expect('Content-Type', /json/)
|
|
||||||
.expect((res) => {
|
|
||||||
const bootstrap = res.body;
|
|
||||||
expect(bootstrap.context).toBeDefined();
|
|
||||||
expect(bootstrap.featureTypes).toBeDefined();
|
|
||||||
expect(bootstrap.uiConfig).toBeDefined();
|
|
||||||
expect(bootstrap.user).toBeDefined();
|
|
||||||
expect(bootstrap.context.length).toBeGreaterThan(0);
|
|
||||||
expect(bootstrap.user.email).toBe(email);
|
|
||||||
});
|
|
||||||
});
|
|
@ -16,7 +16,7 @@ afterAll(async () => {
|
|||||||
await db.destroy();
|
await db.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('gets ui config', async () => {
|
test('gets ui config fields', async () => {
|
||||||
const { body } = await app.request
|
const { body } = await app.request
|
||||||
.get('/api/admin/ui-config')
|
.get('/api/admin/ui-config')
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
@ -24,10 +24,12 @@ test('gets ui config', async () => {
|
|||||||
|
|
||||||
expect(body.unleashUrl).toBe('http://localhost:4242');
|
expect(body.unleashUrl).toBe('http://localhost:4242');
|
||||||
expect(body.version).toBeDefined();
|
expect(body.version).toBeDefined();
|
||||||
|
expect(body.emailEnabled).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('gets ui config with disablePasswordAuth', async () => {
|
test('gets ui config with disablePasswordAuth', async () => {
|
||||||
await db.stores.settingStore.insert(simpleAuthKey, { disabled: true });
|
await db.stores.settingStore.insert(simpleAuthKey, { disabled: true });
|
||||||
|
|
||||||
const { body } = await app.request
|
const { body } = await app.request
|
||||||
.get('/api/admin/ui-config')
|
.get('/api/admin/ui-config')
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
|
@ -305,111 +305,6 @@ Object {
|
|||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
},
|
},
|
||||||
"bootstrapUiSchema": Object {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": Object {
|
|
||||||
"context": Object {
|
|
||||||
"items": Object {
|
|
||||||
"$ref": "#/components/schemas/contextFieldSchema",
|
|
||||||
},
|
|
||||||
"type": "array",
|
|
||||||
},
|
|
||||||
"email": Object {
|
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"featureTypes": Object {
|
|
||||||
"items": Object {
|
|
||||||
"$ref": "#/components/schemas/featureTypeSchema",
|
|
||||||
},
|
|
||||||
"type": "array",
|
|
||||||
},
|
|
||||||
"projects": Object {
|
|
||||||
"items": Object {
|
|
||||||
"$ref": "#/components/schemas/projectSchema",
|
|
||||||
},
|
|
||||||
"type": "array",
|
|
||||||
},
|
|
||||||
"strategies": Object {
|
|
||||||
"items": Object {
|
|
||||||
"$ref": "#/components/schemas/strategySchema",
|
|
||||||
},
|
|
||||||
"type": "array",
|
|
||||||
},
|
|
||||||
"tagTypes": Object {
|
|
||||||
"items": Object {
|
|
||||||
"$ref": "#/components/schemas/tagTypeSchema",
|
|
||||||
},
|
|
||||||
"type": "array",
|
|
||||||
},
|
|
||||||
"uiConfig": Object {
|
|
||||||
"$ref": "#/components/schemas/uiConfigSchema",
|
|
||||||
},
|
|
||||||
"user": Object {
|
|
||||||
"properties": Object {
|
|
||||||
"createdAt": Object {
|
|
||||||
"format": "date-time",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"email": Object {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"emailSent": Object {
|
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"id": Object {
|
|
||||||
"type": "number",
|
|
||||||
},
|
|
||||||
"imageUrl": Object {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"inviteLink": Object {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"isAPI": Object {
|
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"loginAttempts": Object {
|
|
||||||
"type": "number",
|
|
||||||
},
|
|
||||||
"name": Object {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"permissions": Object {
|
|
||||||
"items": Object {
|
|
||||||
"$ref": "#/components/schemas/permissionSchema",
|
|
||||||
},
|
|
||||||
"type": "array",
|
|
||||||
},
|
|
||||||
"rootRole": Object {
|
|
||||||
"type": "number",
|
|
||||||
},
|
|
||||||
"seenAt": Object {
|
|
||||||
"format": "date-time",
|
|
||||||
"nullable": true,
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"username": Object {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": Array [
|
|
||||||
"id",
|
|
||||||
],
|
|
||||||
"type": "object",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": Array [
|
|
||||||
"uiConfig",
|
|
||||||
"user",
|
|
||||||
"email",
|
|
||||||
"context",
|
|
||||||
"featureTypes",
|
|
||||||
"tagTypes",
|
|
||||||
"strategies",
|
|
||||||
"projects",
|
|
||||||
],
|
|
||||||
"type": "object",
|
|
||||||
},
|
|
||||||
"changePasswordSchema": Object {
|
"changePasswordSchema": Object {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": Object {
|
"properties": Object {
|
||||||
@ -2684,6 +2579,9 @@ Object {
|
|||||||
"disablePasswordAuth": Object {
|
"disablePasswordAuth": Object {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
},
|
},
|
||||||
|
"emailEnabled": Object {
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
"environment": Object {
|
"environment": Object {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
@ -6003,26 +5901,6 @@ If the provided project does not exist, the list of events will be empty.",
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"/api/admin/ui-bootstrap": Object {
|
|
||||||
"get": Object {
|
|
||||||
"operationId": "getBootstrapUiData",
|
|
||||||
"responses": Object {
|
|
||||||
"202": Object {
|
|
||||||
"content": Object {
|
|
||||||
"application/json": Object {
|
|
||||||
"schema": Object {
|
|
||||||
"$ref": "#/components/schemas/bootstrapUiSchema",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"description": "bootstrapUiSchema",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"tags": Array [
|
|
||||||
"other",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"/api/admin/ui-config": Object {
|
"/api/admin/ui-config": Object {
|
||||||
"get": Object {
|
"get": Object {
|
||||||
"operationId": "getUIConfig",
|
"operationId": "getUIConfig",
|
||||||
|
Loading…
Reference in New Issue
Block a user