1
0
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:
Jaanus Sellin 2023-03-16 10:26:02 +02:00 committed by GitHub
parent c48f3ad4de
commit d94dd31677
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 78 additions and 57 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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);
});

View File

@ -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';

View File

@ -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",
], ],