mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-24 01:18:01 +02:00
parent
00bef41836
commit
1821af8fe7
@ -49,6 +49,7 @@ import { validateTagTypeSchema } from './spec/validate-tag-type-schema';
|
|||||||
import { variantSchema } from './spec/variant-schema';
|
import { variantSchema } from './spec/variant-schema';
|
||||||
import { variantsSchema } from './spec/variants-schema';
|
import { variantsSchema } from './spec/variants-schema';
|
||||||
import { versionSchema } from './spec/version-schema';
|
import { versionSchema } from './spec/version-schema';
|
||||||
|
import { tagWithVersionSchema } from './spec/tag-with-version-schema';
|
||||||
|
|
||||||
// All schemas in `openapi/spec` should be listed here.
|
// All schemas in `openapi/spec` should be listed here.
|
||||||
export const schemas = {
|
export const schemas = {
|
||||||
@ -87,6 +88,7 @@ export const schemas = {
|
|||||||
splashSchema,
|
splashSchema,
|
||||||
strategySchema,
|
strategySchema,
|
||||||
tagSchema,
|
tagSchema,
|
||||||
|
tagWithVersionSchema,
|
||||||
tagsSchema,
|
tagsSchema,
|
||||||
tagTypeSchema,
|
tagTypeSchema,
|
||||||
tagTypesSchema,
|
tagTypesSchema,
|
||||||
|
22
src/lib/openapi/spec/tag-with-version-schema.ts
Normal file
22
src/lib/openapi/spec/tag-with-version-schema.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { tagSchema } from './tag-schema';
|
||||||
|
import { FromSchema } from 'json-schema-to-ts';
|
||||||
|
|
||||||
|
export const tagWithVersionSchema = {
|
||||||
|
$id: '#/components/schemas/tagWithVersionSchema',
|
||||||
|
type: 'object',
|
||||||
|
additionalProperties: false,
|
||||||
|
required: ['version', 'tag'],
|
||||||
|
properties: {
|
||||||
|
version: {
|
||||||
|
type: 'integer',
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
$ref: '#/components/schemas/tagSchema',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
schemas: { tagSchema },
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type TagWithVersionSchema = FromSchema<typeof tagWithVersionSchema>;
|
@ -72,9 +72,9 @@ test('should get all tags added', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to get single tag by type and value', () => {
|
test('should be able to get single tag by type and value', async () => {
|
||||||
expect.assertions(1);
|
expect.assertions(1);
|
||||||
tagStore.createTag({ value: 'TeamRed', type: 'simple' });
|
await tagStore.createTag({ value: 'TeamRed', type: 'simple' });
|
||||||
return request
|
return request
|
||||||
.get(`${base}/api/admin/tags/simple/TeamRed`)
|
.get(`${base}/api/admin/tags/simple/TeamRed`)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
|
@ -6,9 +6,18 @@ import { Logger } from '../../logger';
|
|||||||
|
|
||||||
import Controller from '../controller';
|
import Controller from '../controller';
|
||||||
|
|
||||||
import { UPDATE_FEATURE } from '../../types/permissions';
|
import { NONE, UPDATE_FEATURE } from '../../types/permissions';
|
||||||
import { extractUsername } from '../../util/extract-user';
|
import { extractUsername } from '../../util/extract-user';
|
||||||
import { IAuthRequest } from '../unleash-types';
|
import { IAuthRequest } from '../unleash-types';
|
||||||
|
import { createRequestSchema, createResponseSchema } from '../../openapi';
|
||||||
|
import { emptyResponse } from '../../openapi/spec/empty-response';
|
||||||
|
import { tagsSchema, TagsSchema } from '../../openapi/spec/tags-schema';
|
||||||
|
import { TagSchema } from '../../openapi/spec/tag-schema';
|
||||||
|
import { OpenApiService } from '../../services/openapi-service';
|
||||||
|
import {
|
||||||
|
tagWithVersionSchema,
|
||||||
|
TagWithVersionSchema,
|
||||||
|
} from '../../openapi/spec/tag-with-version-schema';
|
||||||
|
|
||||||
const version = 1;
|
const version = 1;
|
||||||
|
|
||||||
@ -17,44 +26,147 @@ class TagController extends Controller {
|
|||||||
|
|
||||||
private tagService: TagService;
|
private tagService: TagService;
|
||||||
|
|
||||||
|
private openApiService: OpenApiService;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
{ tagService }: Pick<IUnleashServices, 'tagService'>,
|
{
|
||||||
|
tagService,
|
||||||
|
openApiService,
|
||||||
|
}: Pick<IUnleashServices, 'tagService' | 'openApiService'>,
|
||||||
) {
|
) {
|
||||||
super(config);
|
super(config);
|
||||||
this.tagService = tagService;
|
this.tagService = tagService;
|
||||||
|
this.openApiService = openApiService;
|
||||||
this.logger = config.getLogger('/admin-api/tag.js');
|
this.logger = config.getLogger('/admin-api/tag.js');
|
||||||
|
|
||||||
this.get('/', this.getTags);
|
this.route({
|
||||||
this.post('/', this.createTag, UPDATE_FEATURE);
|
method: 'get',
|
||||||
this.get('/:type', this.getTagsByType);
|
path: '',
|
||||||
this.get('/:type/:value', this.getTag);
|
handler: this.getTags,
|
||||||
this.delete('/:type/:value', this.deleteTag, UPDATE_FEATURE);
|
permission: NONE,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['admin'],
|
||||||
|
operationId: 'getTags',
|
||||||
|
responses: { 200: createResponseSchema('tagsSchema') },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
this.route({
|
||||||
|
method: 'post',
|
||||||
|
path: '',
|
||||||
|
handler: this.createTag,
|
||||||
|
permission: UPDATE_FEATURE,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['admin'],
|
||||||
|
operationId: 'createTag',
|
||||||
|
responses: {
|
||||||
|
201: emptyResponse,
|
||||||
|
},
|
||||||
|
requestBody: createRequestSchema('tagSchema'),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
this.route({
|
||||||
|
method: 'get',
|
||||||
|
path: '/:type',
|
||||||
|
handler: this.getTagsByType,
|
||||||
|
permission: NONE,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['admin'],
|
||||||
|
operationId: 'getTagsByType',
|
||||||
|
responses: {
|
||||||
|
200: createResponseSchema('tagsSchema'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
this.route({
|
||||||
|
method: 'get',
|
||||||
|
path: '/:type/:value',
|
||||||
|
handler: this.getTag,
|
||||||
|
permission: NONE,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['admin'],
|
||||||
|
operationId: 'getTag',
|
||||||
|
responses: {
|
||||||
|
200: createResponseSchema('tagWithVersionSchema'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
this.route({
|
||||||
|
method: 'delete',
|
||||||
|
path: '/:type/:value',
|
||||||
|
handler: this.deleteTag,
|
||||||
|
acceptAnyContentType: true,
|
||||||
|
permission: UPDATE_FEATURE,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['admin'],
|
||||||
|
operationId: 'deleteTag',
|
||||||
|
responses: {
|
||||||
|
200: emptyResponse,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTags(req: Request, res: Response): Promise<void> {
|
async getTags(req: Request, res: Response<TagsSchema>): Promise<void> {
|
||||||
const tags = await this.tagService.getTags();
|
const tags = await this.tagService.getTags();
|
||||||
res.json({ version, tags });
|
this.openApiService.respondWithValidation<TagsSchema>(
|
||||||
|
200,
|
||||||
|
res,
|
||||||
|
tagsSchema.$id,
|
||||||
|
{ version, tags },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTagsByType(req: Request, res: Response): Promise<void> {
|
async getTagsByType(
|
||||||
|
req: Request,
|
||||||
|
res: Response<TagsSchema>,
|
||||||
|
): Promise<void> {
|
||||||
const tags = await this.tagService.getTagsByType(req.params.type);
|
const tags = await this.tagService.getTagsByType(req.params.type);
|
||||||
res.json({ version, tags });
|
this.openApiService.respondWithValidation<TagsSchema>(
|
||||||
|
200,
|
||||||
|
res,
|
||||||
|
tagsSchema.$id,
|
||||||
|
{ version, tags },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTag(req: Request, res: Response): Promise<void> {
|
async getTag(
|
||||||
|
req: Request<TagSchema>,
|
||||||
|
res: Response<TagWithVersionSchema>,
|
||||||
|
): Promise<void> {
|
||||||
const { type, value } = req.params;
|
const { type, value } = req.params;
|
||||||
const tag = await this.tagService.getTag({ type, value });
|
const tag = await this.tagService.getTag({ type, value });
|
||||||
res.json({ version, tag });
|
this.openApiService.respondWithValidation<TagWithVersionSchema>(
|
||||||
|
200,
|
||||||
|
res,
|
||||||
|
tagWithVersionSchema.$id,
|
||||||
|
{ version, tag },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createTag(req: IAuthRequest, res: Response): Promise<void> {
|
async createTag(
|
||||||
|
req: IAuthRequest<unknown, unknown, TagSchema>,
|
||||||
|
res: Response,
|
||||||
|
): Promise<void> {
|
||||||
const userName = extractUsername(req);
|
const userName = extractUsername(req);
|
||||||
await this.tagService.createTag(req.body, userName);
|
await this.tagService.createTag(req.body, userName);
|
||||||
res.status(201).end();
|
res.status(201).end();
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteTag(req: IAuthRequest, res: Response): Promise<void> {
|
async deleteTag(
|
||||||
|
req: IAuthRequest<TagSchema>,
|
||||||
|
res: Response,
|
||||||
|
): Promise<void> {
|
||||||
const { type, value } = req.params;
|
const { type, value } = req.params;
|
||||||
const userName = extractUsername(req);
|
const userName = extractUsername(req);
|
||||||
await this.tagService.deleteTag({ type, value }, userName);
|
await this.tagService.deleteTag({ type, value }, userName);
|
||||||
|
@ -62,13 +62,13 @@ test('Can create a tag', async () =>
|
|||||||
app.request
|
app.request
|
||||||
.post('/api/admin/tags')
|
.post('/api/admin/tags')
|
||||||
.send({
|
.send({
|
||||||
id: 1,
|
|
||||||
value: 'TeamRed',
|
value: 'TeamRed',
|
||||||
type: 'simple',
|
type: 'simple',
|
||||||
})
|
})
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
expect(res.status).toBe(201);
|
expect(res.status).toBe(201);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
test('Can validate a tag', async () =>
|
test('Can validate a tag', async () =>
|
||||||
app.request
|
app.request
|
||||||
.post('/api/admin/tags')
|
.post('/api/admin/tags')
|
||||||
@ -79,11 +79,8 @@ test('Can validate a tag', async () =>
|
|||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(400)
|
.expect(400)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
expect(res.body.details.length).toBe(2);
|
expect(res.body.details.length).toBe(1);
|
||||||
expect(res.body.details[0].message).toBe(
|
expect(res.body.details[0].message).toBe(
|
||||||
'"value" must be a string',
|
|
||||||
);
|
|
||||||
expect(res.body.details[1].message).toBe(
|
|
||||||
'"type" must be URL friendly',
|
'"type" must be URL friendly',
|
||||||
);
|
);
|
||||||
}));
|
}));
|
||||||
|
@ -950,6 +950,22 @@ Object {
|
|||||||
],
|
],
|
||||||
"type": "object",
|
"type": "object",
|
||||||
},
|
},
|
||||||
|
"tagWithVersionSchema": Object {
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": Object {
|
||||||
|
"tag": Object {
|
||||||
|
"$ref": "#/components/schemas/tagSchema",
|
||||||
|
},
|
||||||
|
"version": Object {
|
||||||
|
"type": "integer",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": Array [
|
||||||
|
"version",
|
||||||
|
"tag",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
"tagsSchema": Object {
|
"tagsSchema": Object {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": Object {
|
"properties": Object {
|
||||||
@ -3208,6 +3224,145 @@ Object {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"/api/admin/tags": Object {
|
||||||
|
"get": Object {
|
||||||
|
"operationId": "getTags",
|
||||||
|
"responses": Object {
|
||||||
|
"200": Object {
|
||||||
|
"content": Object {
|
||||||
|
"application/json": Object {
|
||||||
|
"schema": Object {
|
||||||
|
"$ref": "#/components/schemas/tagsSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description": "tagsSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tags": Array [
|
||||||
|
"admin",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"post": Object {
|
||||||
|
"operationId": "createTag",
|
||||||
|
"requestBody": Object {
|
||||||
|
"content": Object {
|
||||||
|
"application/json": Object {
|
||||||
|
"schema": Object {
|
||||||
|
"$ref": "#/components/schemas/tagSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description": "tagSchema",
|
||||||
|
"required": true,
|
||||||
|
},
|
||||||
|
"responses": Object {
|
||||||
|
"201": Object {
|
||||||
|
"description": "emptyResponse",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tags": Array [
|
||||||
|
"admin",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"/api/admin/tags/{type}": Object {
|
||||||
|
"get": Object {
|
||||||
|
"operationId": "getTagsByType",
|
||||||
|
"parameters": Array [
|
||||||
|
Object {
|
||||||
|
"in": "path",
|
||||||
|
"name": "type",
|
||||||
|
"required": true,
|
||||||
|
"schema": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"responses": Object {
|
||||||
|
"200": Object {
|
||||||
|
"content": Object {
|
||||||
|
"application/json": Object {
|
||||||
|
"schema": Object {
|
||||||
|
"$ref": "#/components/schemas/tagsSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description": "tagsSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tags": Array [
|
||||||
|
"admin",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"/api/admin/tags/{type}/{value}": Object {
|
||||||
|
"delete": Object {
|
||||||
|
"operationId": "deleteTag",
|
||||||
|
"parameters": Array [
|
||||||
|
Object {
|
||||||
|
"in": "path",
|
||||||
|
"name": "type",
|
||||||
|
"required": true,
|
||||||
|
"schema": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"in": "path",
|
||||||
|
"name": "value",
|
||||||
|
"required": true,
|
||||||
|
"schema": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"responses": Object {
|
||||||
|
"200": Object {
|
||||||
|
"description": "emptyResponse",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tags": Array [
|
||||||
|
"admin",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"get": Object {
|
||||||
|
"operationId": "getTag",
|
||||||
|
"parameters": Array [
|
||||||
|
Object {
|
||||||
|
"in": "path",
|
||||||
|
"name": "type",
|
||||||
|
"required": true,
|
||||||
|
"schema": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"in": "path",
|
||||||
|
"name": "value",
|
||||||
|
"required": true,
|
||||||
|
"schema": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"responses": Object {
|
||||||
|
"200": Object {
|
||||||
|
"content": Object {
|
||||||
|
"application/json": Object {
|
||||||
|
"schema": Object {
|
||||||
|
"$ref": "#/components/schemas/tagWithVersionSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description": "tagWithVersionSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tags": Array [
|
||||||
|
"admin",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
"/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