1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

refactor: add OpenAPI schema to UI config controller (#1681)

This commit is contained in:
olav 2022-06-08 14:57:39 +02:00 committed by GitHub
parent cbffe0eda0
commit 09a6b578bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 327 additions and 34 deletions

View File

@ -18,10 +18,12 @@ import { patchesSchema } from './spec/patches-schema';
import { strategySchema } from './spec/strategy-schema';
import { tagSchema } from './spec/tag-schema';
import { tagsSchema } from './spec/tags-schema';
import { uiConfigSchema } from './spec/ui-config-schema';
import { updateFeatureSchema } from './spec/update-feature-schema';
import { updateStrategySchema } from './spec/update-strategy-schema';
import { variantSchema } from './spec/variant-schema';
import { variantsSchema } from './spec/variants-schema';
import { versionSchema } from './spec/version-schema';
// Schemas must have $id property on the form "#/components/schemas/mySchema".
export type SchemaId = typeof schemas[keyof typeof schemas]['$id'];
@ -57,10 +59,12 @@ export const schemas = {
strategySchema,
tagSchema,
tagsSchema,
uiConfigSchema,
updateFeatureSchema,
updateStrategySchema,
variantSchema,
variantsSchema,
versionSchema,
};
export const createRequestSchema = (

View File

@ -0,0 +1,24 @@
import { validateSchema } from '../validate';
import { UiConfigSchema } from './ui-config-schema';
test('uiConfigSchema', () => {
const data: UiConfigSchema = {
slogan: 'a',
version: 'a',
unleashUrl: 'a',
baseUriPath: 'a',
disablePasswordAuth: false,
segmentValuesLimit: 0,
strategySegmentsLimit: 0,
versionInfo: {
current: {},
latest: {},
isLatest: true,
instanceId: 'a',
},
};
expect(
validateSchema('#/components/schemas/uiConfigSchema', data),
).toBeUndefined();
});

View File

@ -0,0 +1,76 @@
import { FromSchema } from 'json-schema-to-ts';
import { versionSchema } from './version-schema';
export const uiConfigSchema = {
$id: '#/components/schemas/uiConfigSchema',
type: 'object',
additionalProperties: false,
required: [
'version',
'unleashUrl',
'baseUriPath',
'versionInfo',
'disablePasswordAuth',
'segmentValuesLimit',
'strategySegmentsLimit',
],
properties: {
slogan: {
type: 'string',
},
name: {
type: 'string',
},
version: {
type: 'string',
},
unleashUrl: {
type: 'string',
},
baseUriPath: {
type: 'string',
},
disablePasswordAuth: {
type: 'boolean',
},
segmentValuesLimit: {
type: 'number',
},
strategySegmentsLimit: {
type: 'number',
},
flags: {
type: 'object',
additionalProperties: {
type: 'boolean',
},
},
links: {
type: 'array',
items: {
type: 'object',
},
},
authenticationType: {
type: 'string',
enum: [
'open-source',
'demo',
'enterprise',
'hosted',
'custom',
'none',
],
},
versionInfo: {
$ref: '#/components/schemas/versionSchema',
},
},
components: {
schemas: {
versionSchema,
},
},
} as const;
export type UiConfigSchema = FromSchema<typeof uiConfigSchema>;

View File

@ -0,0 +1,43 @@
import { FromSchema } from 'json-schema-to-ts';
export const versionSchema = {
$id: '#/components/schemas/versionSchema',
type: 'object',
additionalProperties: false,
required: ['current', 'latest', 'isLatest', 'instanceId'],
properties: {
current: {
type: 'object',
additionalProperties: false,
properties: {
oss: {
type: 'string',
},
enterprise: {
type: 'string',
},
},
},
latest: {
type: 'object',
additionalProperties: false,
properties: {
oss: {
type: 'string',
},
enterprise: {
type: 'string',
},
},
},
isLatest: {
type: 'boolean',
},
instanceId: {
type: 'string',
},
},
components: {},
} as const;
export type VersionSchema = FromSchema<typeof versionSchema>;

View File

@ -1,73 +1,91 @@
import { Request, Response } from 'express';
import { IUnleashServices } from '../../types/services';
import { IAuthType, IUIConfig, IUnleashConfig } from '../../types/option';
import { IAuthType, IUnleashConfig } from '../../types/option';
import version from '../../util/version';
import Controller from '../controller';
import VersionService, { IVersionHolder } from '../../services/version-service';
import VersionService from '../../services/version-service';
import SettingService from '../../services/setting-service';
import {
simpleAuthKey,
SimpleAuthSettings,
} from '../../types/settings/simple-auth-settings';
interface IUIConfigResponse extends IUIConfig {
version: string;
unleashUrl: string;
baseUriPath: string;
authenticationType?: IAuthType;
versionInfo: IVersionHolder;
disablePasswordAuth: boolean;
segmentValuesLimit: number;
strategySegmentsLimit: number;
}
import { NONE } from '../../types/permissions';
import { createResponseSchema } from '../../openapi';
import {
uiConfigSchema,
UiConfigSchema,
} from '../../openapi/spec/ui-config-schema';
import { OpenApiService } from '../../services/openapi-service';
class ConfigController extends Controller {
private versionService: VersionService;
private settingService: SettingService;
private uiConfig: Omit<
IUIConfigResponse,
'versionInfo' | 'disablePasswordAuth'
>;
private readonly openApiService: OpenApiService;
constructor(
config: IUnleashConfig,
{
versionService,
settingService,
}: Pick<IUnleashServices, 'versionService' | 'settingService'>,
openApiService,
}: Pick<
IUnleashServices,
'versionService' | 'settingService' | 'openApiService'
>,
) {
super(config);
this.versionService = versionService;
this.settingService = settingService;
const authenticationType =
config.authentication && config.authentication.type;
this.uiConfig = {
...config.ui,
version,
unleashUrl: config.server.unleashUrl,
baseUriPath: config.server.baseUriPath,
authenticationType,
segmentValuesLimit: config.segmentValuesLimit,
strategySegmentsLimit: config.strategySegmentsLimit,
};
this.get('/', this.getUIConfig);
this.openApiService = openApiService;
this.route({
method: 'get',
path: '',
handler: this.getUIConfig,
permission: NONE,
middleware: [
openApiService.validPath({
tags: ['admin'],
operationId: 'getUIConfig',
responses: {
200: createResponseSchema('uiConfigSchema'),
},
}),
],
});
}
async getUIConfig(
req: Request,
res: Response<IUIConfigResponse>,
res: Response<UiConfigSchema>,
): Promise<void> {
const config = this.uiConfig;
const simpleAuthSettings =
await this.settingService.get<SimpleAuthSettings>(simpleAuthKey);
const versionInfo = this.versionService.getVersionInfo();
const disablePasswordAuth =
simpleAuthSettings?.disabled ||
this.config.authentication.type == IAuthType.NONE;
res.json({ ...config, versionInfo, disablePasswordAuth });
const response: UiConfigSchema = {
...this.config.ui,
version,
unleashUrl: this.config.server.unleashUrl,
baseUriPath: this.config.server.baseUriPath,
authenticationType: this.config.authentication?.type,
segmentValuesLimit: this.config.segmentValuesLimit,
strategySegmentsLimit: this.config.strategySegmentsLimit,
versionInfo: this.versionService.getVersionInfo(),
disablePasswordAuth,
};
this.openApiService.respondWithValidation(
200,
res,
uiConfigSchema.$id,
response,
);
}
}
export default ConfigController;

View File

@ -147,6 +147,7 @@ export interface IUIConfig {
},
];
}
export interface ICspDomainOptions {
defaultSrc?: string[];
fontSrc?: string[];

View File

@ -455,6 +455,71 @@ Object {
],
"type": "object",
},
"uiConfigSchema": Object {
"additionalProperties": false,
"properties": Object {
"authenticationType": Object {
"enum": Array [
"open-source",
"demo",
"enterprise",
"hosted",
"custom",
"none",
],
"type": "string",
},
"baseUriPath": Object {
"type": "string",
},
"disablePasswordAuth": Object {
"type": "boolean",
},
"flags": Object {
"additionalProperties": Object {
"type": "boolean",
},
"type": "object",
},
"links": Object {
"items": Object {
"type": "object",
},
"type": "array",
},
"name": Object {
"type": "string",
},
"segmentValuesLimit": Object {
"type": "number",
},
"slogan": Object {
"type": "string",
},
"strategySegmentsLimit": Object {
"type": "number",
},
"unleashUrl": Object {
"type": "string",
},
"version": Object {
"type": "string",
},
"versionInfo": Object {
"$ref": "#/components/schemas/versionSchema",
},
},
"required": Array [
"version",
"unleashUrl",
"baseUriPath",
"versionInfo",
"disablePasswordAuth",
"segmentValuesLimit",
"strategySegmentsLimit",
],
"type": "object",
},
"updateFeatureSchema": Object {
"properties": Object {
"archived": Object {
@ -567,6 +632,48 @@ Object {
},
"type": "array",
},
"versionSchema": Object {
"additionalProperties": false,
"properties": Object {
"current": Object {
"additionalProperties": false,
"properties": Object {
"enterprise": Object {
"type": "string",
},
"oss": Object {
"type": "string",
},
},
"type": "object",
},
"instanceId": Object {
"type": "string",
},
"isLatest": Object {
"type": "boolean",
},
"latest": Object {
"additionalProperties": false,
"properties": Object {
"enterprise": Object {
"type": "string",
},
"oss": Object {
"type": "string",
},
},
"type": "object",
},
},
"required": Array [
"current",
"latest",
"isLatest",
"instanceId",
],
"type": "object",
},
},
"securitySchemes": Object {
"apiKey": Object {
@ -1676,6 +1783,26 @@ Object {
],
},
},
"/api/admin/ui-config": Object {
"get": Object {
"operationId": "getUIConfig",
"responses": Object {
"200": Object {
"content": Object {
"application/json": Object {
"schema": Object {
"$ref": "#/components/schemas/uiConfigSchema",
},
},
},
"description": "uiConfigSchema",
},
},
"tags": Array [
"admin",
],
},
},
},
"security": Array [
Object {