mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-24 01:18:01 +02:00
feat: refactor archive (#3330)
This commit is contained in:
parent
c48f3ad4de
commit
d94dd31677
@ -53,6 +53,9 @@ export default class ProjectArchiveController extends Controller {
|
|||||||
openApiService.validPath({
|
openApiService.validPath({
|
||||||
tags: ['Archive'],
|
tags: ['Archive'],
|
||||||
operationId: 'deleteFeatures',
|
operationId: 'deleteFeatures',
|
||||||
|
description:
|
||||||
|
'This endpoint deletes the specified features, that are in archive.',
|
||||||
|
summary: 'Deletes a list of features',
|
||||||
requestBody: createRequestSchema('batchFeaturesSchema'),
|
requestBody: createRequestSchema('batchFeaturesSchema'),
|
||||||
responses: { 200: emptyResponse },
|
responses: { 200: emptyResponse },
|
||||||
}),
|
}),
|
||||||
@ -69,11 +72,32 @@ export default class ProjectArchiveController extends Controller {
|
|||||||
openApiService.validPath({
|
openApiService.validPath({
|
||||||
tags: ['Archive'],
|
tags: ['Archive'],
|
||||||
operationId: 'reviveFeatures',
|
operationId: 'reviveFeatures',
|
||||||
|
description:
|
||||||
|
'This endpoint revives the specified features.',
|
||||||
|
summary: 'Revives a list of features',
|
||||||
requestBody: createRequestSchema('batchFeaturesSchema'),
|
requestBody: createRequestSchema('batchFeaturesSchema'),
|
||||||
responses: { 200: emptyResponse },
|
responses: { 200: emptyResponse },
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.route({
|
||||||
|
method: 'post',
|
||||||
|
path: PATH,
|
||||||
|
handler: this.archiveFeatures,
|
||||||
|
permission: DELETE_FEATURE,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['Features'],
|
||||||
|
operationId: 'archiveFeatures',
|
||||||
|
description:
|
||||||
|
'This endpoint archives the specified features.',
|
||||||
|
summary: 'Archives a list of features',
|
||||||
|
requestBody: createRequestSchema('batchFeaturesSchema'),
|
||||||
|
responses: { 202: emptyResponse },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteFeatures(
|
async deleteFeatures(
|
||||||
@ -103,6 +127,22 @@ export default class ProjectArchiveController extends Controller {
|
|||||||
await this.featureService.reviveFeatures(features, projectId, user);
|
await this.featureService.reviveFeatures(features, projectId, user);
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async archiveFeatures(
|
||||||
|
req: IAuthRequest<IProjectParam, void, BatchFeaturesSchema>,
|
||||||
|
res: Response,
|
||||||
|
): Promise<void> {
|
||||||
|
if (!this.flagResolver.isEnabled('bulkOperations')) {
|
||||||
|
throw new NotFoundError('Bulk operations are not enabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { features } = req.body;
|
||||||
|
const { projectId } = req.params;
|
||||||
|
const userName = extractUsername(req);
|
||||||
|
|
||||||
|
await this.featureService.archiveToggles(features, userName, projectId);
|
||||||
|
res.status(202).end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ProjectArchiveController;
|
module.exports = ProjectArchiveController;
|
||||||
|
@ -20,7 +20,6 @@ import { extractUsername } from '../../../util';
|
|||||||
import { IAuthRequest } from '../../unleash-types';
|
import { IAuthRequest } from '../../unleash-types';
|
||||||
import {
|
import {
|
||||||
AdminFeaturesQuerySchema,
|
AdminFeaturesQuerySchema,
|
||||||
BatchFeaturesSchema,
|
|
||||||
CreateFeatureSchema,
|
CreateFeatureSchema,
|
||||||
CreateFeatureStrategySchema,
|
CreateFeatureStrategySchema,
|
||||||
createRequestSchema,
|
createRequestSchema,
|
||||||
@ -72,7 +71,6 @@ export interface IFeatureProjectUserParams extends ProjectParam {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PATH = '/:projectId/features';
|
const PATH = '/:projectId/features';
|
||||||
const PATH_ARCHIVE = '/:projectId/archive';
|
|
||||||
const PATH_STALE = '/:projectId/stale';
|
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`;
|
||||||
@ -398,23 +396,6 @@ export default class ProjectFeaturesController extends Controller {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.route({
|
|
||||||
method: 'post',
|
|
||||||
path: PATH_ARCHIVE,
|
|
||||||
handler: this.archiveFeatures,
|
|
||||||
permission: DELETE_FEATURE,
|
|
||||||
middleware: [
|
|
||||||
openApiService.validPath({
|
|
||||||
tags: ['Features'],
|
|
||||||
operationId: 'archiveFeatures',
|
|
||||||
description:
|
|
||||||
'This endpoint archives the specified features.',
|
|
||||||
summary: 'Archives a list of features',
|
|
||||||
requestBody: createRequestSchema('batchFeaturesSchema'),
|
|
||||||
responses: { 202: emptyResponse },
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
this.route({
|
this.route({
|
||||||
method: 'post',
|
method: 'post',
|
||||||
path: PATH_STALE,
|
path: PATH_STALE,
|
||||||
@ -609,22 +590,6 @@ export default class ProjectFeaturesController extends Controller {
|
|||||||
res.status(202).send();
|
res.status(202).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
async archiveFeatures(
|
|
||||||
req: IAuthRequest<{ projectId: string }, void, BatchFeaturesSchema>,
|
|
||||||
res: Response,
|
|
||||||
): Promise<void> {
|
|
||||||
if (!this.flagResolver.isEnabled('bulkOperations')) {
|
|
||||||
throw new NotFoundError('Bulk operations are not enabled');
|
|
||||||
}
|
|
||||||
|
|
||||||
const { features } = req.body;
|
|
||||||
const { projectId } = req.params;
|
|
||||||
const userName = extractUsername(req);
|
|
||||||
|
|
||||||
await this.featureService.archiveToggles(features, userName, projectId);
|
|
||||||
res.status(202).end();
|
|
||||||
}
|
|
||||||
|
|
||||||
async staleFeatures(
|
async staleFeatures(
|
||||||
req: IAuthRequest<{ projectId: string }, void, BatchStaleSchema>,
|
req: IAuthRequest<{ projectId: string }, void, BatchStaleSchema>,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
@ -6,6 +6,15 @@ import { DEFAULT_PROJECT } from '../../../../lib/types';
|
|||||||
let app;
|
let app;
|
||||||
let db;
|
let db;
|
||||||
|
|
||||||
|
const createFeatureToggle = (
|
||||||
|
featureName: string,
|
||||||
|
project = DEFAULT_PROJECT,
|
||||||
|
) => {
|
||||||
|
return app.request.post(`/api/admin/projects/${project}/features`).send({
|
||||||
|
name: featureName,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
db = await dbInit('archive_serial', getLogger);
|
db = await dbInit('archive_serial', getLogger);
|
||||||
app = await setupAppWithCustomConfig(db.stores, {
|
app = await setupAppWithCustomConfig(db.stores, {
|
||||||
@ -253,3 +262,28 @@ test('can bulk revive features', async () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Should be able to bulk archive features', async () => {
|
||||||
|
const featureName1 = 'archivedFeature1';
|
||||||
|
const featureName2 = 'archivedFeature2';
|
||||||
|
|
||||||
|
await createFeatureToggle(featureName1);
|
||||||
|
await createFeatureToggle(featureName2);
|
||||||
|
|
||||||
|
await app.request
|
||||||
|
.post(`/api/admin/projects/${DEFAULT_PROJECT}/archive`)
|
||||||
|
.send({
|
||||||
|
features: [featureName1, featureName2],
|
||||||
|
})
|
||||||
|
.expect(202);
|
||||||
|
|
||||||
|
const { body } = await app.request
|
||||||
|
.get(`/api/admin/archive/features/${DEFAULT_PROJECT}`)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
const archivedFeatures = body.features.filter(
|
||||||
|
(feature) =>
|
||||||
|
feature.name === featureName1 || feature.name === featureName2,
|
||||||
|
);
|
||||||
|
expect(archivedFeatures).toHaveLength(2);
|
||||||
|
});
|
||||||
|
@ -2824,28 +2824,6 @@ test('Can query for two tags at the same time. Tags are ORed together', async ()
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should be able to bulk archive features', async () => {
|
|
||||||
const featureName1 = 'archivedFeature1';
|
|
||||||
const featureName2 = 'archivedFeature2';
|
|
||||||
|
|
||||||
await createFeatureToggle(featureName1);
|
|
||||||
await createFeatureToggle(featureName2);
|
|
||||||
|
|
||||||
await app.request
|
|
||||||
.post(`/api/admin/projects/${DEFAULT_PROJECT}/archive`)
|
|
||||||
.send({
|
|
||||||
features: [featureName1, featureName2],
|
|
||||||
})
|
|
||||||
.expect(202);
|
|
||||||
|
|
||||||
const { body } = await app.request
|
|
||||||
.get(`/api/admin/archive/features/${DEFAULT_PROJECT}`)
|
|
||||||
.expect(200);
|
|
||||||
expect(body).toMatchObject({
|
|
||||||
features: [{}, { name: featureName1 }, { name: featureName2 }],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should batch stale features', async () => {
|
test('Should batch stale features', async () => {
|
||||||
const staledFeatureName1 = 'staledFeature1';
|
const staledFeatureName1 = 'staledFeature1';
|
||||||
const staledFeatureName2 = 'staledFeature2';
|
const staledFeatureName2 = 'staledFeature2';
|
||||||
|
@ -6082,6 +6082,7 @@ If the provided project does not exist, the list of events will be empty.",
|
|||||||
},
|
},
|
||||||
"/api/admin/projects/{projectId}/archive/delete": {
|
"/api/admin/projects/{projectId}/archive/delete": {
|
||||||
"post": {
|
"post": {
|
||||||
|
"description": "This endpoint deletes the specified features, that are in archive.",
|
||||||
"operationId": "deleteFeatures",
|
"operationId": "deleteFeatures",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@ -6109,6 +6110,7 @@ If the provided project does not exist, the list of events will be empty.",
|
|||||||
"description": "This response has no body.",
|
"description": "This response has no body.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"summary": "Deletes a list of features",
|
||||||
"tags": [
|
"tags": [
|
||||||
"Archive",
|
"Archive",
|
||||||
],
|
],
|
||||||
@ -6116,6 +6118,7 @@ If the provided project does not exist, the list of events will be empty.",
|
|||||||
},
|
},
|
||||||
"/api/admin/projects/{projectId}/archive/revive": {
|
"/api/admin/projects/{projectId}/archive/revive": {
|
||||||
"post": {
|
"post": {
|
||||||
|
"description": "This endpoint revives the specified features.",
|
||||||
"operationId": "reviveFeatures",
|
"operationId": "reviveFeatures",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@ -6143,6 +6146,7 @@ If the provided project does not exist, the list of events will be empty.",
|
|||||||
"description": "This response has no body.",
|
"description": "This response has no body.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"summary": "Revives a list of features",
|
||||||
"tags": [
|
"tags": [
|
||||||
"Archive",
|
"Archive",
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user