1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-23 13:46:45 +02:00

fix: bulk tags will work now with project permissions (#4177)

This commit is contained in:
Jaanus Sellin 2023-07-07 11:55:13 +03:00 committed by GitHub
parent 2d44656a9b
commit 3c52550474
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 54 additions and 38 deletions

View File

@ -59,7 +59,7 @@ export const ManageTags: VFC<IManageTagsProps> = ({ projectId, data }) => {
const features = data.map(({ name }) => name); const features = data.map(({ name }) => name);
const payload = { features, tags: { addedTags, removedTags } }; const payload = { features, tags: { addedTags, removedTags } };
try { try {
await bulkUpdateTags(payload); await bulkUpdateTags(payload, projectId);
refetch(); refetch();
const added = addedTags.length const added = addedTags.length
? `Added tags: ${addedTags ? `Added tags: ${addedTags

View File

@ -20,8 +20,11 @@ const useTagApi = () => {
} }
}; };
const bulkUpdateTags = async (payload: TagsBulkAddSchema) => { const bulkUpdateTags = async (
const path = `api/admin/tags/features`; payload: TagsBulkAddSchema,
projectId: string
) => {
const path = `api/admin/projects/${projectId}/tags`;
const req = createRequest(path, { const req = createRequest(path, {
method: 'PUT', method: 'PUT',
body: JSON.stringify(payload), body: JSON.stringify(payload),

View File

@ -36,10 +36,16 @@ import {
getStandardResponses, getStandardResponses,
ParametersSchema, ParametersSchema,
SetStrategySortOrderSchema, SetStrategySortOrderSchema,
TagsBulkAddSchema,
TagSchema,
UpdateFeatureSchema, UpdateFeatureSchema,
UpdateFeatureStrategySchema, UpdateFeatureStrategySchema,
} from '../../../openapi'; } from '../../../openapi';
import { OpenApiService, FeatureToggleService } from '../../../services'; import {
OpenApiService,
FeatureToggleService,
FeatureTagService,
} from '../../../services';
import { querySchema } from '../../../schema/feature-schema'; import { querySchema } from '../../../schema/feature-schema';
import { BatchStaleSchema } from '../../../openapi/spec/batch-stale-schema'; import { BatchStaleSchema } from '../../../openapi/spec/batch-stale-schema';
import { import {
@ -85,6 +91,7 @@ export interface IFeatureProjectUserParams extends ProjectParam {
const PATH = '/:projectId/features'; const PATH = '/:projectId/features';
const PATH_STALE = '/:projectId/stale'; const PATH_STALE = '/:projectId/stale';
const PATH_TAGS = `/:projectId/tags`;
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`;
@ -98,11 +105,14 @@ type ProjectFeaturesServices = Pick<
| 'projectHealthService' | 'projectHealthService'
| 'openApiService' | 'openApiService'
| 'transactionalFeatureToggleService' | 'transactionalFeatureToggleService'
| 'featureTagService'
>; >;
export default class ProjectFeaturesController extends Controller { export default class ProjectFeaturesController extends Controller {
private featureService: FeatureToggleService; private featureService: FeatureToggleService;
private featureTagService: FeatureTagService;
private transactionalFeatureToggleService: ( private transactionalFeatureToggleService: (
db: UnleashTransaction, db: UnleashTransaction,
) => FeatureToggleService; ) => FeatureToggleService;
@ -121,6 +131,7 @@ export default class ProjectFeaturesController extends Controller {
featureToggleServiceV2, featureToggleServiceV2,
openApiService, openApiService,
transactionalFeatureToggleService, transactionalFeatureToggleService,
featureTagService,
}: ProjectFeaturesServices, }: ProjectFeaturesServices,
startTransaction: TransactionCreator<UnleashTransaction>, startTransaction: TransactionCreator<UnleashTransaction>,
) { ) {
@ -130,6 +141,7 @@ export default class ProjectFeaturesController extends Controller {
transactionalFeatureToggleService; transactionalFeatureToggleService;
this.startTransaction = startTransaction; this.startTransaction = startTransaction;
this.openApiService = openApiService; this.openApiService = openApiService;
this.featureTagService = featureTagService;
this.flagResolver = config.flagResolver; this.flagResolver = config.flagResolver;
this.logger = config.getLogger('/admin-api/project/features.ts'); 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( async getFeatures(
@ -976,6 +1003,21 @@ export default class ProjectFeaturesController extends Controller {
res.status(200).json(updatedStrategy); 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( async getStrategyParameters(
req: Request<StrategyIdParams, any, any, any>, req: Request<StrategyIdParams, any, any, any>,
res: Response<ParametersSchema>, res: Response<ParametersSchema>,

View File

@ -23,7 +23,6 @@ import {
} from '../../openapi/spec/tag-with-version-schema'; } from '../../openapi/spec/tag-with-version-schema';
import { emptyResponse } from '../../openapi/util/standard-responses'; import { emptyResponse } from '../../openapi/util/standard-responses';
import FeatureTagService from 'lib/services/feature-tag-service'; import FeatureTagService from 'lib/services/feature-tag-service';
import { TagsBulkAddSchema } from '../../openapi/spec/tags-bulk-add-schema';
import { IFlagResolver } from '../../types'; import { IFlagResolver } from '../../types';
const version = 1; const version = 1;
@ -74,7 +73,7 @@ class TagController extends Controller {
method: 'post', method: 'post',
path: '', path: '',
handler: this.createTag, handler: this.createTag,
permission: UPDATE_FEATURE, permission: NONE,
middleware: [ middleware: [
openApiService.validPath({ openApiService.validPath({
tags: ['Tags'], 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({ this.route({
method: 'get', method: 'get',
path: '/:type', path: '/:type',
@ -208,20 +194,5 @@ class TagController extends Controller {
await this.tagService.deleteTag({ type, value }, userName); await this.tagService.deleteTag({ type, value }, userName);
res.status(200).end(); 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; export default TagController;

View File

@ -143,7 +143,7 @@ test('Can tag features', async () => {
strategies: [{ name: 'default' }], 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], features: [featureName, featureName2],
tags: { tags: {
addedTags: [addedTag], addedTags: [addedTag],
@ -185,7 +185,7 @@ test('Can bulk remove tags', async () => {
}); });
await app.request await app.request
.put('/api/admin/tags/features') .put('/api/admin/projects/default/tags')
.send({ .send({
features: [featureName, featureName2], features: [featureName, featureName2],
tags: { tags: {
@ -196,7 +196,7 @@ test('Can bulk remove tags', async () => {
.expect(200); .expect(200);
await app.request await app.request
.put('/api/admin/tags/features') .put('/api/admin/projects/default/tags')
.send({ .send({
features: [featureName, featureName2], features: [featureName, featureName2],
tags: { tags: {