mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	fix: bulk tags will work now with project permissions (#4177)
This commit is contained in:
		
							parent
							
								
									2d44656a9b
								
							
						
					
					
						commit
						3c52550474
					
				| @ -59,7 +59,7 @@ export const ManageTags: VFC<IManageTagsProps> = ({ projectId, data }) => { | ||||
|         const features = data.map(({ name }) => name); | ||||
|         const payload = { features, tags: { addedTags, removedTags } }; | ||||
|         try { | ||||
|             await bulkUpdateTags(payload); | ||||
|             await bulkUpdateTags(payload, projectId); | ||||
|             refetch(); | ||||
|             const added = addedTags.length | ||||
|                 ? `Added tags: ${addedTags | ||||
|  | ||||
| @ -20,8 +20,11 @@ const useTagApi = () => { | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     const bulkUpdateTags = async (payload: TagsBulkAddSchema) => { | ||||
|         const path = `api/admin/tags/features`; | ||||
|     const bulkUpdateTags = async ( | ||||
|         payload: TagsBulkAddSchema, | ||||
|         projectId: string | ||||
|     ) => { | ||||
|         const path = `api/admin/projects/${projectId}/tags`; | ||||
|         const req = createRequest(path, { | ||||
|             method: 'PUT', | ||||
|             body: JSON.stringify(payload), | ||||
|  | ||||
| @ -36,10 +36,16 @@ import { | ||||
|     getStandardResponses, | ||||
|     ParametersSchema, | ||||
|     SetStrategySortOrderSchema, | ||||
|     TagsBulkAddSchema, | ||||
|     TagSchema, | ||||
|     UpdateFeatureSchema, | ||||
|     UpdateFeatureStrategySchema, | ||||
| } from '../../../openapi'; | ||||
| import { OpenApiService, FeatureToggleService } from '../../../services'; | ||||
| import { | ||||
|     OpenApiService, | ||||
|     FeatureToggleService, | ||||
|     FeatureTagService, | ||||
| } from '../../../services'; | ||||
| import { querySchema } from '../../../schema/feature-schema'; | ||||
| import { BatchStaleSchema } from '../../../openapi/spec/batch-stale-schema'; | ||||
| import { | ||||
| @ -85,6 +91,7 @@ export interface IFeatureProjectUserParams extends ProjectParam { | ||||
| 
 | ||||
| const PATH = '/:projectId/features'; | ||||
| const PATH_STALE = '/:projectId/stale'; | ||||
| const PATH_TAGS = `/:projectId/tags`; | ||||
| const PATH_FEATURE = `${PATH}/:featureName`; | ||||
| const PATH_FEATURE_CLONE = `${PATH_FEATURE}/clone`; | ||||
| const PATH_ENV = `${PATH_FEATURE}/environments/:environment`; | ||||
| @ -98,11 +105,14 @@ type ProjectFeaturesServices = Pick< | ||||
|     | 'projectHealthService' | ||||
|     | 'openApiService' | ||||
|     | 'transactionalFeatureToggleService' | ||||
|     | 'featureTagService' | ||||
| >; | ||||
| 
 | ||||
| export default class ProjectFeaturesController extends Controller { | ||||
|     private featureService: FeatureToggleService; | ||||
| 
 | ||||
|     private featureTagService: FeatureTagService; | ||||
| 
 | ||||
|     private transactionalFeatureToggleService: ( | ||||
|         db: UnleashTransaction, | ||||
|     ) => FeatureToggleService; | ||||
| @ -121,6 +131,7 @@ export default class ProjectFeaturesController extends Controller { | ||||
|             featureToggleServiceV2, | ||||
|             openApiService, | ||||
|             transactionalFeatureToggleService, | ||||
|             featureTagService, | ||||
|         }: ProjectFeaturesServices, | ||||
|         startTransaction: TransactionCreator<UnleashTransaction>, | ||||
|     ) { | ||||
| @ -130,6 +141,7 @@ export default class ProjectFeaturesController extends Controller { | ||||
|             transactionalFeatureToggleService; | ||||
|         this.startTransaction = startTransaction; | ||||
|         this.openApiService = openApiService; | ||||
|         this.featureTagService = featureTagService; | ||||
|         this.flagResolver = config.flagResolver; | ||||
|         this.logger = config.getLogger('/admin-api/project/features.ts'); | ||||
| 
 | ||||
| @ -480,6 +492,21 @@ export default class ProjectFeaturesController extends Controller { | ||||
|                 }), | ||||
|             ], | ||||
|         }); | ||||
| 
 | ||||
|         this.route({ | ||||
|             method: 'put', | ||||
|             path: PATH_TAGS, | ||||
|             handler: this.updateFeaturesTags, | ||||
|             permission: UPDATE_FEATURE, | ||||
|             middleware: [ | ||||
|                 openApiService.validPath({ | ||||
|                     tags: ['Tags'], | ||||
|                     operationId: 'addTagToFeatures', | ||||
|                     requestBody: createRequestSchema('tagsBulkAddSchema'), | ||||
|                     responses: { 200: emptyResponse }, | ||||
|                 }), | ||||
|             ], | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     async getFeatures( | ||||
| @ -976,6 +1003,21 @@ export default class ProjectFeaturesController extends Controller { | ||||
|         res.status(200).json(updatedStrategy); | ||||
|     } | ||||
| 
 | ||||
|     async updateFeaturesTags( | ||||
|         req: IAuthRequest<void, void, TagsBulkAddSchema>, | ||||
|         res: Response<TagSchema>, | ||||
|     ): Promise<void> { | ||||
|         const { features, tags } = req.body; | ||||
|         const userName = extractUsername(req); | ||||
|         await this.featureTagService.updateTags( | ||||
|             features, | ||||
|             tags.addedTags, | ||||
|             tags.removedTags, | ||||
|             userName, | ||||
|         ); | ||||
|         res.status(200).end(); | ||||
|     } | ||||
| 
 | ||||
|     async getStrategyParameters( | ||||
|         req: Request<StrategyIdParams, any, any, any>, | ||||
|         res: Response<ParametersSchema>, | ||||
|  | ||||
| @ -23,7 +23,6 @@ import { | ||||
| } from '../../openapi/spec/tag-with-version-schema'; | ||||
| import { emptyResponse } from '../../openapi/util/standard-responses'; | ||||
| import FeatureTagService from 'lib/services/feature-tag-service'; | ||||
| import { TagsBulkAddSchema } from '../../openapi/spec/tags-bulk-add-schema'; | ||||
| import { IFlagResolver } from '../../types'; | ||||
| 
 | ||||
| const version = 1; | ||||
| @ -74,7 +73,7 @@ class TagController extends Controller { | ||||
|             method: 'post', | ||||
|             path: '', | ||||
|             handler: this.createTag, | ||||
|             permission: UPDATE_FEATURE, | ||||
|             permission: NONE, | ||||
|             middleware: [ | ||||
|                 openApiService.validPath({ | ||||
|                     tags: ['Tags'], | ||||
| @ -88,20 +87,7 @@ class TagController extends Controller { | ||||
|                 }), | ||||
|             ], | ||||
|         }); | ||||
|         this.route({ | ||||
|             method: 'put', | ||||
|             path: '/features', | ||||
|             handler: this.updateFeaturesTags, | ||||
|             permission: UPDATE_FEATURE, | ||||
|             middleware: [ | ||||
|                 openApiService.validPath({ | ||||
|                     tags: ['Tags'], | ||||
|                     operationId: 'addTagToFeatures', | ||||
|                     requestBody: createRequestSchema('tagsBulkAddSchema'), | ||||
|                     responses: { 200: emptyResponse }, | ||||
|                 }), | ||||
|             ], | ||||
|         }); | ||||
| 
 | ||||
|         this.route({ | ||||
|             method: 'get', | ||||
|             path: '/:type', | ||||
| @ -208,20 +194,5 @@ class TagController extends Controller { | ||||
|         await this.tagService.deleteTag({ type, value }, userName); | ||||
|         res.status(200).end(); | ||||
|     } | ||||
| 
 | ||||
|     async updateFeaturesTags( | ||||
|         req: IAuthRequest<void, void, TagsBulkAddSchema>, | ||||
|         res: Response<TagSchema>, | ||||
|     ): Promise<void> { | ||||
|         const { features, tags } = req.body; | ||||
|         const userName = extractUsername(req); | ||||
|         await this.featureTagService.updateTags( | ||||
|             features, | ||||
|             tags.addedTags, | ||||
|             tags.removedTags, | ||||
|             userName, | ||||
|         ); | ||||
|         res.status(200).end(); | ||||
|     } | ||||
| } | ||||
| export default TagController; | ||||
|  | ||||
| @ -143,7 +143,7 @@ test('Can tag features', async () => { | ||||
|         strategies: [{ name: 'default' }], | ||||
|     }); | ||||
| 
 | ||||
|     await app.request.put('/api/admin/tags/features').send({ | ||||
|     await app.request.put('/api/admin/projects/default/tags').send({ | ||||
|         features: [featureName, featureName2], | ||||
|         tags: { | ||||
|             addedTags: [addedTag], | ||||
| @ -185,7 +185,7 @@ test('Can bulk remove tags', async () => { | ||||
|     }); | ||||
| 
 | ||||
|     await app.request | ||||
|         .put('/api/admin/tags/features') | ||||
|         .put('/api/admin/projects/default/tags') | ||||
|         .send({ | ||||
|             features: [featureName, featureName2], | ||||
|             tags: { | ||||
| @ -196,7 +196,7 @@ test('Can bulk remove tags', async () => { | ||||
|         .expect(200); | ||||
| 
 | ||||
|     await app.request | ||||
|         .put('/api/admin/tags/features') | ||||
|         .put('/api/admin/projects/default/tags') | ||||
|         .send({ | ||||
|             features: [featureName, featureName2], | ||||
|             tags: { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user