mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-04 01:18:20 +02:00
feat: create stubs for bulk toggle (#3792)
This commit is contained in:
parent
6a12403eca
commit
45505d6996
@ -11,6 +11,7 @@ import {
|
|||||||
applicationSchema,
|
applicationSchema,
|
||||||
applicationsSchema,
|
applicationsSchema,
|
||||||
batchFeaturesSchema,
|
batchFeaturesSchema,
|
||||||
|
bulkToggleFeaturesSchema,
|
||||||
changePasswordSchema,
|
changePasswordSchema,
|
||||||
clientApplicationSchema,
|
clientApplicationSchema,
|
||||||
clientFeatureSchema,
|
clientFeatureSchema,
|
||||||
@ -194,6 +195,7 @@ export const schemas: UnleashSchemas = {
|
|||||||
batchStaleSchema,
|
batchStaleSchema,
|
||||||
bulkRegistrationSchema,
|
bulkRegistrationSchema,
|
||||||
bulkMetricsSchema,
|
bulkMetricsSchema,
|
||||||
|
bulkToggleFeaturesSchema,
|
||||||
changePasswordSchema,
|
changePasswordSchema,
|
||||||
clientApplicationSchema,
|
clientApplicationSchema,
|
||||||
clientFeatureSchema,
|
clientFeatureSchema,
|
||||||
|
@ -289,7 +289,7 @@ const metaRules: Rule[] = [
|
|||||||
describe.each(metaRules)('OpenAPI schemas $name', (rule) => {
|
describe.each(metaRules)('OpenAPI schemas $name', (rule) => {
|
||||||
const validateMetaSchema = ajv.compile(rule.metaSchema);
|
const validateMetaSchema = ajv.compile(rule.metaSchema);
|
||||||
|
|
||||||
// test all schemas agaisnt the rule
|
// test all schemas against the rule
|
||||||
Object.entries(schemas).forEach(([schemaName, schema]) => {
|
Object.entries(schemas).forEach(([schemaName, schema]) => {
|
||||||
if (!rule.match || rule.match(schemaName, schema)) {
|
if (!rule.match || rule.match(schemaName, schema)) {
|
||||||
it(`${schemaName}`, () => {
|
it(`${schemaName}`, () => {
|
||||||
|
24
src/lib/openapi/spec/bulk-toggle-features-schema.ts
Normal file
24
src/lib/openapi/spec/bulk-toggle-features-schema.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { FromSchema } from 'json-schema-to-ts';
|
||||||
|
|
||||||
|
export const bulkToggleFeaturesSchema = {
|
||||||
|
$id: '#/components/schemas/bulkToggleFeaturesSchema',
|
||||||
|
type: 'object',
|
||||||
|
required: ['features'],
|
||||||
|
description: 'The feature list used for bulk toggle operations',
|
||||||
|
properties: {
|
||||||
|
features: {
|
||||||
|
type: 'array',
|
||||||
|
description: 'The features that we want to bulk toggle',
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'The feature name we want to toggle',
|
||||||
|
},
|
||||||
|
example: ['feature-a', 'feature-b'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type BulkToggleFeaturesSchema = FromSchema<
|
||||||
|
typeof bulkToggleFeaturesSchema
|
||||||
|
>;
|
@ -134,3 +134,4 @@ export * from './tags-bulk-add-schema';
|
|||||||
export * from './upsert-segment-schema';
|
export * from './upsert-segment-schema';
|
||||||
export * from './batch-features-schema';
|
export * from './batch-features-schema';
|
||||||
export * from './token-string-list-schema';
|
export * from './token-string-list-schema';
|
||||||
|
export * from './bulk-toggle-features-schema';
|
||||||
|
@ -20,6 +20,7 @@ import { extractUsername } from '../../../util';
|
|||||||
import { IAuthRequest } from '../../unleash-types';
|
import { IAuthRequest } from '../../unleash-types';
|
||||||
import {
|
import {
|
||||||
AdminFeaturesQuerySchema,
|
AdminFeaturesQuerySchema,
|
||||||
|
BulkToggleFeaturesSchema,
|
||||||
CreateFeatureSchema,
|
CreateFeatureSchema,
|
||||||
CreateFeatureStrategySchema,
|
CreateFeatureStrategySchema,
|
||||||
createRequestSchema,
|
createRequestSchema,
|
||||||
@ -49,6 +50,11 @@ interface FeatureStrategyParams {
|
|||||||
sortOrder?: number;
|
sortOrder?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface BulkFeaturesStrategyParams {
|
||||||
|
projectId: string;
|
||||||
|
environment: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface FeatureStrategyQuery {
|
interface FeatureStrategyQuery {
|
||||||
shouldActivateDisabledStrategies: string;
|
shouldActivateDisabledStrategies: string;
|
||||||
}
|
}
|
||||||
@ -78,6 +84,7 @@ const PATH_STALE = '/:projectId/stale';
|
|||||||
const PATH_FEATURE = `${PATH}/:featureName`;
|
const PATH_FEATURE = `${PATH}/:featureName`;
|
||||||
const PATH_FEATURE_CLONE = `${PATH_FEATURE}/clone`;
|
const PATH_FEATURE_CLONE = `${PATH_FEATURE}/clone`;
|
||||||
const PATH_ENV = `${PATH_FEATURE}/environments/:environment`;
|
const PATH_ENV = `${PATH_FEATURE}/environments/:environment`;
|
||||||
|
const BULK_PATH_ENV = `/:projectId/bulk_features/environments/:environment`;
|
||||||
const PATH_STRATEGIES = `${PATH_ENV}/strategies`;
|
const PATH_STRATEGIES = `${PATH_ENV}/strategies`;
|
||||||
const PATH_STRATEGY = `${PATH_STRATEGIES}/:strategyId`;
|
const PATH_STRATEGY = `${PATH_STRATEGIES}/:strategyId`;
|
||||||
|
|
||||||
@ -151,6 +158,46 @@ export default class ProjectFeaturesController extends Controller {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.route({
|
||||||
|
method: 'post',
|
||||||
|
path: `${BULK_PATH_ENV}/on`,
|
||||||
|
handler: this.bulkToggleFeaturesEnvironmentOn,
|
||||||
|
permission: UPDATE_FEATURE_ENVIRONMENT,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['Unstable'],
|
||||||
|
description:
|
||||||
|
'This endpoint enables multiple feature toggles.',
|
||||||
|
summary: 'Bulk enable a list of features.',
|
||||||
|
operationId: 'bulkToggleFeaturesEnvironmentOn',
|
||||||
|
requestBody: createRequestSchema(
|
||||||
|
'bulkToggleFeaturesSchema',
|
||||||
|
),
|
||||||
|
responses: { 405: emptyResponse },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
this.route({
|
||||||
|
method: 'post',
|
||||||
|
path: `${BULK_PATH_ENV}/off`,
|
||||||
|
handler: this.bulkToggleFeaturesEnvironmentOff,
|
||||||
|
permission: UPDATE_FEATURE_ENVIRONMENT,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['Unstable'],
|
||||||
|
description:
|
||||||
|
'This endpoint disables multiple feature toggles.',
|
||||||
|
summary: 'Bulk disabled a list of features.',
|
||||||
|
operationId: 'bulkToggleFeaturesEnvironmentOff',
|
||||||
|
requestBody: createRequestSchema(
|
||||||
|
'bulkToggleFeaturesSchema',
|
||||||
|
),
|
||||||
|
responses: { 405: emptyResponse },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
this.route({
|
this.route({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
path: PATH_STRATEGIES,
|
path: PATH_STRATEGIES,
|
||||||
@ -667,6 +714,30 @@ export default class ProjectFeaturesController extends Controller {
|
|||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async bulkToggleFeaturesEnvironmentOn(
|
||||||
|
req: IAuthRequest<
|
||||||
|
BulkFeaturesStrategyParams,
|
||||||
|
any,
|
||||||
|
BulkToggleFeaturesSchema,
|
||||||
|
FeatureStrategyQuery
|
||||||
|
>,
|
||||||
|
res: Response<void>,
|
||||||
|
): Promise<void> {
|
||||||
|
res.status(405).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
async bulkToggleFeaturesEnvironmentOff(
|
||||||
|
req: IAuthRequest<
|
||||||
|
BulkFeaturesStrategyParams,
|
||||||
|
any,
|
||||||
|
BulkToggleFeaturesSchema,
|
||||||
|
FeatureStrategyQuery
|
||||||
|
>,
|
||||||
|
res: Response<void>,
|
||||||
|
): Promise<void> {
|
||||||
|
res.status(405).end();
|
||||||
|
}
|
||||||
|
|
||||||
async toggleFeatureEnvironmentOff(
|
async toggleFeatureEnvironmentOff(
|
||||||
req: IAuthRequest<FeatureStrategyParams, any, any, any>,
|
req: IAuthRequest<FeatureStrategyParams, any, any, any>,
|
||||||
res: Response<void>,
|
res: Response<void>,
|
||||||
|
@ -372,6 +372,57 @@ test('Can enable/disable environment for feature with strategies', async () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Can bulk enable/disable environment for feature with strategies', async () => {
|
||||||
|
const envName = 'bulk-enable-feature-environment';
|
||||||
|
const featureName = 'com.test.bulk.enable.environment';
|
||||||
|
const project = 'default';
|
||||||
|
// Create environment
|
||||||
|
await db.stores.environmentStore.create({
|
||||||
|
name: envName,
|
||||||
|
type: 'production',
|
||||||
|
});
|
||||||
|
// Connect environment to project
|
||||||
|
await app.request
|
||||||
|
.post(`/api/admin/projects/${project}/environments`)
|
||||||
|
.send({
|
||||||
|
environment: envName,
|
||||||
|
})
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
// Create feature
|
||||||
|
await app.createFeature(featureName).expect((res) => {
|
||||||
|
expect(res.body.name).toBe(featureName);
|
||||||
|
expect(res.body.createdAt).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add strategy to it
|
||||||
|
await app.request
|
||||||
|
.post(
|
||||||
|
`/api/admin/projects/${project}/features/${featureName}/environments/${envName}/strategies`,
|
||||||
|
)
|
||||||
|
.send({
|
||||||
|
name: 'default',
|
||||||
|
parameters: {
|
||||||
|
userId: 'string',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.expect(200);
|
||||||
|
await app.request
|
||||||
|
.post(
|
||||||
|
`/api/admin/projects/${project}/bulk_features/environments/${envName}/on`,
|
||||||
|
)
|
||||||
|
.send({ features: [featureName] })
|
||||||
|
.set('Content-Type', 'application/json')
|
||||||
|
.expect(405);
|
||||||
|
|
||||||
|
await app.request
|
||||||
|
.post(
|
||||||
|
`/api/admin/projects/${project}/bulk_features/environments/${envName}/off`,
|
||||||
|
)
|
||||||
|
.send({ features: [featureName] })
|
||||||
|
.expect(405);
|
||||||
|
});
|
||||||
|
|
||||||
test("Trying to get a project that doesn't exist yields 404", async () => {
|
test("Trying to get a project that doesn't exist yields 404", async () => {
|
||||||
await app.request.get('/api/admin/projects/nonexisting').expect(404);
|
await app.request.get('/api/admin/projects/nonexisting').expect(404);
|
||||||
});
|
});
|
||||||
|
@ -926,6 +926,27 @@ The provider you choose for your addon dictates what properties the \`parameters
|
|||||||
],
|
],
|
||||||
"type": "object",
|
"type": "object",
|
||||||
},
|
},
|
||||||
|
"bulkToggleFeaturesSchema": {
|
||||||
|
"description": "The feature list used for bulk toggle operations",
|
||||||
|
"properties": {
|
||||||
|
"features": {
|
||||||
|
"description": "The features that we want to bulk toggle",
|
||||||
|
"example": [
|
||||||
|
"feature-a",
|
||||||
|
"feature-b",
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"description": "The feature name we want to toggle",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"features",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
"changePasswordSchema": {
|
"changePasswordSchema": {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -9159,6 +9180,94 @@ If the provided project does not exist, the list of events will be empty.",
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"/api/admin/projects/{projectId}/bulk_features/environments/{environment}/off": {
|
||||||
|
"post": {
|
||||||
|
"description": "This endpoint disables multiple feature toggles.",
|
||||||
|
"operationId": "bulkToggleFeaturesEnvironmentOff",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "projectId",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "environment",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/bulkToggleFeaturesSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description": "bulkToggleFeaturesSchema",
|
||||||
|
"required": true,
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"405": {
|
||||||
|
"description": "This response has no body.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"summary": "Bulk disabled a list of features.",
|
||||||
|
"tags": [
|
||||||
|
"Unstable",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"/api/admin/projects/{projectId}/bulk_features/environments/{environment}/on": {
|
||||||
|
"post": {
|
||||||
|
"description": "This endpoint enables multiple feature toggles.",
|
||||||
|
"operationId": "bulkToggleFeaturesEnvironmentOn",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "projectId",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "environment",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/bulkToggleFeaturesSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description": "bulkToggleFeaturesSchema",
|
||||||
|
"required": true,
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"405": {
|
||||||
|
"description": "This response has no body.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"summary": "Bulk enable a list of features.",
|
||||||
|
"tags": [
|
||||||
|
"Unstable",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
"/api/admin/projects/{projectId}/delete": {
|
"/api/admin/projects/{projectId}/delete": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "This endpoint deletes the specified features, that are in archive.",
|
"description": "This endpoint deletes the specified features, that are in archive.",
|
||||||
|
Loading…
Reference in New Issue
Block a user