mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01: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({
 | 
			
		||||
                    tags: ['Archive'],
 | 
			
		||||
                    operationId: 'deleteFeatures',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'This endpoint deletes the specified features, that are in archive.',
 | 
			
		||||
                    summary: 'Deletes a list of features',
 | 
			
		||||
                    requestBody: createRequestSchema('batchFeaturesSchema'),
 | 
			
		||||
                    responses: { 200: emptyResponse },
 | 
			
		||||
                }),
 | 
			
		||||
@ -69,11 +72,32 @@ export default class ProjectArchiveController extends Controller {
 | 
			
		||||
                openApiService.validPath({
 | 
			
		||||
                    tags: ['Archive'],
 | 
			
		||||
                    operationId: 'reviveFeatures',
 | 
			
		||||
                    description:
 | 
			
		||||
                        'This endpoint revives the specified features.',
 | 
			
		||||
                    summary: 'Revives a list of features',
 | 
			
		||||
                    requestBody: createRequestSchema('batchFeaturesSchema'),
 | 
			
		||||
                    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(
 | 
			
		||||
@ -103,6 +127,22 @@ export default class ProjectArchiveController extends Controller {
 | 
			
		||||
        await this.featureService.reviveFeatures(features, projectId, user);
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,6 @@ import { extractUsername } from '../../../util';
 | 
			
		||||
import { IAuthRequest } from '../../unleash-types';
 | 
			
		||||
import {
 | 
			
		||||
    AdminFeaturesQuerySchema,
 | 
			
		||||
    BatchFeaturesSchema,
 | 
			
		||||
    CreateFeatureSchema,
 | 
			
		||||
    CreateFeatureStrategySchema,
 | 
			
		||||
    createRequestSchema,
 | 
			
		||||
@ -72,7 +71,6 @@ export interface IFeatureProjectUserParams extends ProjectParam {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const PATH = '/:projectId/features';
 | 
			
		||||
const PATH_ARCHIVE = '/:projectId/archive';
 | 
			
		||||
const PATH_STALE = '/:projectId/stale';
 | 
			
		||||
const PATH_FEATURE = `${PATH}/:featureName`;
 | 
			
		||||
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({
 | 
			
		||||
            method: 'post',
 | 
			
		||||
            path: PATH_STALE,
 | 
			
		||||
@ -609,22 +590,6 @@ export default class ProjectFeaturesController extends Controller {
 | 
			
		||||
        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(
 | 
			
		||||
        req: IAuthRequest<{ projectId: string }, void, BatchStaleSchema>,
 | 
			
		||||
        res: Response,
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,15 @@ import { DEFAULT_PROJECT } from '../../../../lib/types';
 | 
			
		||||
let app;
 | 
			
		||||
let db;
 | 
			
		||||
 | 
			
		||||
const createFeatureToggle = (
 | 
			
		||||
    featureName: string,
 | 
			
		||||
    project = DEFAULT_PROJECT,
 | 
			
		||||
) => {
 | 
			
		||||
    return app.request.post(`/api/admin/projects/${project}/features`).send({
 | 
			
		||||
        name: featureName,
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
beforeAll(async () => {
 | 
			
		||||
    db = await dbInit('archive_serial', getLogger);
 | 
			
		||||
    app = await setupAppWithCustomConfig(db.stores, {
 | 
			
		||||
@ -253,3 +262,28 @@ test('can bulk revive features', async () => {
 | 
			
		||||
            .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 () => {
 | 
			
		||||
    const staledFeatureName1 = 'staledFeature1';
 | 
			
		||||
    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": {
 | 
			
		||||
      "post": {
 | 
			
		||||
        "description": "This endpoint deletes the specified features, that are in archive.",
 | 
			
		||||
        "operationId": "deleteFeatures",
 | 
			
		||||
        "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.",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "summary": "Deletes a list of features",
 | 
			
		||||
        "tags": [
 | 
			
		||||
          "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": {
 | 
			
		||||
      "post": {
 | 
			
		||||
        "description": "This endpoint revives the specified features.",
 | 
			
		||||
        "operationId": "reviveFeatures",
 | 
			
		||||
        "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.",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "summary": "Revives a list of features",
 | 
			
		||||
        "tags": [
 | 
			
		||||
          "Archive",
 | 
			
		||||
        ],
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user