mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: add CREATE_TAG_TYPE permission (#5386)
https://linear.app/unleash/issue/2-1164/update-tag-type-covers-both-creation-and-update Adds a new `CREATE_TAG_TYPE` permission instead of using `UPDATE_TAG_TYPE` for both actions.
This commit is contained in:
parent
fac2578922
commit
5dc3e830a8
@ -224,7 +224,7 @@ export const ManageBulkTagsDialog: VFC<IManageBulkTagsDialogProps> = ({
|
||||
open={open}
|
||||
secondaryButtonText='Cancel'
|
||||
primaryButtonText='Save tags'
|
||||
title='Update tags to feature toggle'
|
||||
title='Update feature toggle tags'
|
||||
onClick={() => onSubmit(payload)}
|
||||
disabledPrimaryButton={
|
||||
payload.addedTags.length === 0 &&
|
||||
|
@ -248,7 +248,7 @@ export const ManageTagsDialog = ({ open, setOpen }: IManageTagsProps) => {
|
||||
open={open}
|
||||
secondaryButtonText='Cancel'
|
||||
primaryButtonText='Save tags'
|
||||
title='Update tags to feature toggle'
|
||||
title='Update feature toggle tags'
|
||||
onClick={onSubmit}
|
||||
disabledPrimaryButton={loading || differenceCount === 0}
|
||||
onClose={onCancel}
|
||||
|
@ -13,8 +13,9 @@ export const DELETE_CONTEXT_FIELD = 'DELETE_CONTEXT_FIELD';
|
||||
export const CREATE_PROJECT = 'CREATE_PROJECT';
|
||||
export const UPDATE_PROJECT = 'UPDATE_PROJECT';
|
||||
export const DELETE_PROJECT = 'DELETE_PROJECT';
|
||||
export const DELETE_TAG_TYPE = 'DELETE_TAG_TYPE';
|
||||
export const CREATE_TAG_TYPE = 'CREATE_TAG_TYPE';
|
||||
export const UPDATE_TAG_TYPE = 'UPDATE_TAG_TYPE';
|
||||
export const DELETE_TAG_TYPE = 'DELETE_TAG_TYPE';
|
||||
export const CREATE_ADDON = 'CREATE_ADDON';
|
||||
export const UPDATE_ADDON = 'UPDATE_ADDON';
|
||||
export const DELETE_ADDON = 'DELETE_ADDON';
|
||||
|
@ -3,7 +3,7 @@ import useTagTypeForm from '../TagTypeForm/useTagTypeForm';
|
||||
import TagTypeForm from '../TagTypeForm/TagTypeForm';
|
||||
import { CreateButton } from 'component/common/CreateButton/CreateButton';
|
||||
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
|
||||
import { UPDATE_TAG_TYPE } from 'component/providers/AccessProvider/permissions';
|
||||
import { CREATE_TAG_TYPE } from 'component/providers/AccessProvider/permissions';
|
||||
import useTagTypesApi from 'hooks/api/actions/useTagTypesApi/useTagTypesApi';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import useToast from 'hooks/useToast';
|
||||
@ -78,7 +78,7 @@ const CreateTagType = () => {
|
||||
clearErrors={clearErrors}
|
||||
validateNameUniqueness={validateNameUniqueness}
|
||||
>
|
||||
<CreateButton name='type' permission={UPDATE_TAG_TYPE} />
|
||||
<CreateButton name='type' permission={CREATE_TAG_TYPE} />
|
||||
</TagTypeForm>
|
||||
</FormTemplate>
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
|
||||
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
||||
import { UPDATE_TAG_TYPE } from 'component/providers/AccessProvider/permissions';
|
||||
import { CREATE_TAG_TYPE } from 'component/providers/AccessProvider/permissions';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
@ -18,14 +18,14 @@ export const AddTagTypeButton = () => {
|
||||
<PermissionIconButton
|
||||
onClick={() => navigate('/tag-types/create')}
|
||||
size='large'
|
||||
permission={UPDATE_TAG_TYPE}
|
||||
permission={CREATE_TAG_TYPE}
|
||||
>
|
||||
<Add />
|
||||
</PermissionIconButton>
|
||||
}
|
||||
elseShow={
|
||||
<PermissionButton
|
||||
permission={UPDATE_TAG_TYPE}
|
||||
permission={CREATE_TAG_TYPE}
|
||||
onClick={() => navigate('/tag-types/create')}
|
||||
>
|
||||
New tag type
|
||||
|
@ -373,11 +373,11 @@ test('validate import data', async () => {
|
||||
affectedItems: [
|
||||
'Create feature toggles',
|
||||
'Update feature toggles',
|
||||
'Update tag types',
|
||||
'Create context fields',
|
||||
'Create activation strategies',
|
||||
'Delete activation strategies',
|
||||
'Update variants',
|
||||
'Create tag types',
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
UPDATE_FEATURE,
|
||||
UPDATE_FEATURE_ENVIRONMENT_VARIANTS,
|
||||
UPDATE_TAG_TYPE,
|
||||
CREATE_TAG_TYPE,
|
||||
} from '../../types';
|
||||
import { PermissionError } from '../../error';
|
||||
|
||||
@ -94,7 +95,7 @@ export class ImportPermissionsService {
|
||||
]);
|
||||
const permissions = [UPDATE_FEATURE];
|
||||
if (newTagTypes.length > 0) {
|
||||
permissions.push(UPDATE_TAG_TYPE);
|
||||
permissions.push(CREATE_TAG_TYPE);
|
||||
}
|
||||
if (Array.isArray(newContextFields) && newContextFields.length > 0) {
|
||||
permissions.push(CREATE_CONTEXT_FIELD);
|
||||
|
@ -329,6 +329,34 @@ test('Does not double check permission if not changing project when updating tog
|
||||
);
|
||||
});
|
||||
|
||||
test('CREATE_TAG_TYPE does not need projectId', async () => {
|
||||
const accessService = {
|
||||
hasPermission: jest.fn().mockReturnValue(true),
|
||||
};
|
||||
|
||||
const func = rbacMiddleware(
|
||||
config,
|
||||
{ featureToggleStore, segmentStore },
|
||||
accessService,
|
||||
);
|
||||
const cb = jest.fn();
|
||||
const req: any = {
|
||||
user: new User({ username: 'user', id: 1 }),
|
||||
params: {},
|
||||
body: { name: 'new-tag-type', description: 'New tag type for testing' },
|
||||
};
|
||||
func(req, undefined, cb);
|
||||
|
||||
await req.checkRbac(perms.CREATE_TAG_TYPE);
|
||||
expect(accessService.hasPermission).toHaveBeenCalledTimes(1);
|
||||
expect(accessService.hasPermission).toHaveBeenCalledWith(
|
||||
req.user,
|
||||
[perms.CREATE_TAG_TYPE],
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
test('UPDATE_TAG_TYPE does not need projectId', async () => {
|
||||
const accessService = {
|
||||
hasPermission: jest.fn().mockReturnValue(true),
|
||||
|
@ -2,6 +2,7 @@ import { Request, Response } from 'express';
|
||||
import Controller from '../controller';
|
||||
|
||||
import {
|
||||
CREATE_TAG_TYPE,
|
||||
DELETE_TAG_TYPE,
|
||||
NONE,
|
||||
UPDATE_TAG_TYPE,
|
||||
@ -72,7 +73,7 @@ class TagTypeController extends Controller {
|
||||
method: 'post',
|
||||
path: '',
|
||||
handler: this.createTagType,
|
||||
permission: UPDATE_TAG_TYPE,
|
||||
permission: CREATE_TAG_TYPE,
|
||||
middleware: [
|
||||
openApiService.validPath({
|
||||
tags: ['Tags'],
|
||||
@ -91,7 +92,7 @@ class TagTypeController extends Controller {
|
||||
method: 'post',
|
||||
path: '/validate',
|
||||
handler: this.validateTagType,
|
||||
permission: UPDATE_TAG_TYPE,
|
||||
permission: NONE,
|
||||
middleware: [
|
||||
openApiService.validPath({
|
||||
tags: ['Tags'],
|
||||
|
@ -37,6 +37,7 @@ export const CREATE_STRATEGY = 'CREATE_STRATEGY';
|
||||
export const UPDATE_STRATEGY = 'UPDATE_STRATEGY';
|
||||
export const DELETE_STRATEGY = 'DELETE_STRATEGY';
|
||||
|
||||
export const CREATE_TAG_TYPE = 'CREATE_TAG_TYPE';
|
||||
export const UPDATE_TAG_TYPE = 'UPDATE_TAG_TYPE';
|
||||
export const DELETE_TAG_TYPE = 'DELETE_TAG_TYPE';
|
||||
|
||||
@ -112,6 +113,6 @@ export const ROOT_PERMISSION_CATEGORIES = [
|
||||
},
|
||||
{
|
||||
label: 'Tag type',
|
||||
permissions: [UPDATE_TAG_TYPE, DELETE_TAG_TYPE],
|
||||
permissions: [CREATE_TAG_TYPE, UPDATE_TAG_TYPE, DELETE_TAG_TYPE],
|
||||
},
|
||||
];
|
||||
|
@ -0,0 +1,18 @@
|
||||
exports.up = function (db, cb) {
|
||||
db.runSql(
|
||||
`
|
||||
INSERT INTO permissions (permission, display_name, type) VALUES ('CREATE_TAG_TYPE', 'Create tag types', 'root');
|
||||
SELECT assign_unleash_permission_to_role('CREATE_TAG_TYPE', 'Editor');
|
||||
`,
|
||||
cb
|
||||
);
|
||||
};
|
||||
|
||||
exports.down = function (db, cb) {
|
||||
db.runSql(
|
||||
`
|
||||
DELETE FROM permissions WHERE permission = 'CREATE_TAG_TYPE';
|
||||
`,
|
||||
cb
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user