1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-06 01:15:28 +02:00

fix: API improvements aligning the types to our schemas (#4650)

Some of our types in OSS have drifted apart from our OpenAPI schemas.
This will help them be aligned again
This commit is contained in:
Gastón Fournier 2023-09-12 15:40:57 +02:00 committed by GitHub
parent 2b2f5e20fa
commit c39d815516
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 87 additions and 86 deletions

View File

@ -20,6 +20,7 @@ import {
ROOT_PERMISSION_TYPE, ROOT_PERMISSION_TYPE,
} from '../util/constants'; } from '../util/constants';
import { Db } from './db'; import { Db } from './db';
import { IdPermissionRef } from 'lib/services/access-service';
const T = { const T = {
ROLE_USER: 'role_user', ROLE_USER: 'role_user',
@ -221,7 +222,7 @@ export class AccessStore implements IAccessStore {
async addEnvironmentPermissionsToRole( async addEnvironmentPermissionsToRole(
role_id: number, role_id: number,
permissions: IPermission[], permissions: IdPermissionRef[],
): Promise<void> { ): Promise<void> {
const rows = permissions.map((permission) => { const rows = permissions.map((permission) => {
return { return {

View File

@ -12,12 +12,29 @@ export const createStrategySchema = {
description: 'The name of the strategy type. Must be unique.', description: 'The name of the strategy type. Must be unique.',
example: 'my-custom-strategy', example: 'my-custom-strategy',
}, },
title: {
type: 'string',
description: 'The title of the strategy',
example: 'My awesome strategy',
},
description: { description: {
type: 'string', type: 'string',
description: 'A description of the strategy type.', description: 'A description of the strategy type.',
example: example:
'Enable the feature for users who have not logged in before.', 'Enable the feature for users who have not logged in before.',
}, },
editable: {
type: 'boolean',
description:
'Whether the strategy type is editable or not. Defaults to `true`.',
example: false,
},
deprecated: {
type: 'boolean',
description:
'Whether the strategy type is deprecated or not. Defaults to `false`.',
example: true,
},
parameters: { parameters: {
type: 'array', type: 'array',
description: description:

View File

@ -238,7 +238,7 @@ class StrategyController extends Controller {
} }
async createStrategy( async createStrategy(
req: IAuthRequest<unknown, CreateStrategySchema>, req: IAuthRequest<unknown, unknown, CreateStrategySchema>,
res: Response<StrategySchema>, res: Response<StrategySchema>,
): Promise<void> { ): Promise<void> {
const userName = extractUsername(req); const userName = extractUsername(req);

View File

@ -52,17 +52,22 @@ const PROJECT_ADMIN = [
permissions.DELETE_FEATURE, permissions.DELETE_FEATURE,
]; ];
/** @deprecated prefer to use NamePermissionRef */
export type IdPermissionRef = Pick<IPermission, 'id' | 'environment'>;
export type NamePermissionRef = Pick<IPermission, 'name' | 'environment'>;
export type PermissionRef = IdPermissionRef | NamePermissionRef;
interface IRoleCreation { interface IRoleCreation {
name: string; name: string;
description: string; description: string;
type?: 'root-custom' | 'custom'; type?: 'root-custom' | 'custom';
permissions?: IPermission[]; permissions?: PermissionRef[];
} }
export interface IRoleValidation { export interface IRoleValidation {
name: string; name: string;
description?: string; description?: string;
permissions?: Pick<IPermission, 'id' | 'environment'>[]; permissions?: PermissionRef[];
} }
interface IRoleUpdate { interface IRoleUpdate {
@ -70,7 +75,7 @@ interface IRoleUpdate {
name: string; name: string;
description: string; description: string;
type?: 'root-custom' | 'custom'; type?: 'root-custom' | 'custom';
permissions?: IPermission[]; permissions?: PermissionRef[];
} }
export interface AccessWithRoles { export interface AccessWithRoles {
@ -627,7 +632,7 @@ export class AccessService {
if (roleType === CUSTOM_ROOT_ROLE_TYPE) { if (roleType === CUSTOM_ROOT_ROLE_TYPE) {
await this.store.addPermissionsToRole( await this.store.addPermissionsToRole(
newRole.id, newRole.id,
rolePermissions.map(({ name }) => name), rolePermissions.map((p: NamePermissionRef) => p.name),
); );
} else { } else {
await this.store.addEnvironmentPermissionsToRole( await this.store.addEnvironmentPermissionsToRole(
@ -668,7 +673,7 @@ export class AccessService {
if (roleType === CUSTOM_ROOT_ROLE_TYPE) { if (roleType === CUSTOM_ROOT_ROLE_TYPE) {
await this.store.addPermissionsToRole( await this.store.addPermissionsToRole(
newRole.id, newRole.id,
rolePermissions.map(({ name }) => name), rolePermissions.map((p: NamePermissionRef) => p.name),
); );
} else { } else {
await this.store.addEnvironmentPermissionsToRole( await this.store.addEnvironmentPermissionsToRole(

View File

@ -39,6 +39,7 @@ import {
IProjectRoleUsage, IProjectRoleUsage,
ProjectAccessUserRolesDeleted, ProjectAccessUserRolesDeleted,
IFeatureNaming, IFeatureNaming,
CreateProject,
} from '../types'; } from '../types';
import { IProjectQuery, IProjectStore } from '../types/stores/project-store'; import { IProjectQuery, IProjectStore } from '../types/stores/project-store';
import { import {
@ -190,10 +191,7 @@ export default class ProjectService {
}; };
async createProject( async createProject(
newProject: Pick< newProject: CreateProject,
IProject,
'id' | 'name' | 'mode' | 'defaultStickiness'
>,
user: IUser, user: IUser,
): Promise<IProject> { ): Promise<IProject> {
const data = await projectSchema.validateAsync(newProject); const data = await projectSchema.validateAsync(newProject);

View File

@ -320,6 +320,7 @@ test('should export strategies', async () => {
await stores.strategyStore.createStrategy({ await stores.strategyStore.createStrategy({
name: 'a-strategy', name: 'a-strategy',
editable: true, editable: true,
parameters: [],
}); });
const data = await stateService.export({ includeStrategies: true }); const data = await stateService.export({ includeStrategies: true });
@ -595,7 +596,10 @@ test('exporting to new format works', async () => {
await stores.featureToggleStore.create('fancy', { await stores.featureToggleStore.create('fancy', {
name: 'Some-feature', name: 'Some-feature',
}); });
await stores.strategyStore.createStrategy({ name: 'format' }); await stores.strategyStore.createStrategy({
name: 'format',
parameters: [],
});
await stores.featureEnvironmentStore.addEnvironmentToFeature( await stores.featureEnvironmentStore.addEnvironmentToFeature(
'Some-feature', 'Some-feature',
'dev', 'dev',
@ -650,7 +654,10 @@ test('featureStrategies can keep existing', async () => {
await stores.featureToggleStore.create('fancy', { await stores.featureToggleStore.create('fancy', {
name: 'Some-feature', name: 'Some-feature',
}); });
await stores.strategyStore.createStrategy({ name: 'format' }); await stores.strategyStore.createStrategy({
name: 'format',
parameters: [],
});
await stores.featureEnvironmentStore.addEnvironmentToFeature( await stores.featureEnvironmentStore.addEnvironmentToFeature(
'Some-feature', 'Some-feature',
'dev', 'dev',
@ -697,7 +704,10 @@ test('featureStrategies should not keep existing if dropBeforeImport', async ()
await stores.featureToggleStore.create('fancy', { await stores.featureToggleStore.create('fancy', {
name: 'Some-feature', name: 'Some-feature',
}); });
await stores.strategyStore.createStrategy({ name: 'format' }); await stores.strategyStore.createStrategy({
name: 'format',
parameters: [],
});
await stores.featureEnvironmentStore.addEnvironmentToFeature( await stores.featureEnvironmentStore.addEnvironmentToFeature(
'Some-feature', 'Some-feature',
'dev', 'dev',

View File

@ -163,6 +163,7 @@ test('counts toggles', async () => {
await stores.strategyStore.createStrategy({ await stores.strategyStore.createStrategy({
name: uuidv4(), name: uuidv4(),
editable: true, editable: true,
parameters: [],
}); });
const latest = { const latest = {
oss: '4.0.0', oss: '4.0.0',
@ -213,10 +214,12 @@ test('counts custom strategies', async () => {
await stores.strategyStore.createStrategy({ await stores.strategyStore.createStrategy({
name: strategyName, name: strategyName,
editable: true, editable: true,
parameters: [],
}); });
await stores.strategyStore.createStrategy({ await stores.strategyStore.createStrategy({
name: uuidv4(), name: uuidv4(),
editable: true, editable: true,
parameters: [],
}); });
await stores.featureStrategiesStore.createStrategyFeatureEnv({ await stores.featureStrategiesStore.createStrategyFeatureEnv({
featureName: toggleName, featureName: toggleName,

View File

@ -402,6 +402,14 @@ export interface IImportData extends ImportCommon {
data: any; data: any;
} }
// Create project aligns with #/components/schemas/createProjectSchema
// joi is providing default values when the optional inputs are not provided
// const data = await projectSchema.validateAsync(newProject);
export type CreateProject = Pick<IProject, 'id' | 'name'> & {
mode?: ProjectMode;
defaultStickiness?: string;
};
export interface IProject { export interface IProject {
id: string; id: string;
name: string; name: string;

View File

@ -1,3 +1,4 @@
import { PermissionRef } from 'lib/services/access-service';
import { IGroupModelWithProjectRole } from '../group'; import { IGroupModelWithProjectRole } from '../group';
import { IPermission, IUserWithRole } from '../model'; import { IPermission, IUserWithRole } from '../model';
import { Store } from './store'; import { Store } from './store';
@ -100,7 +101,7 @@ export interface IAccessStore extends Store<IRole, number> {
addEnvironmentPermissionsToRole( addEnvironmentPermissionsToRole(
role_id: number, role_id: number,
permissions: IPermission[], permissions: PermissionRef[],
): Promise<void>; ): Promise<void>;
addUserToRole( addUserToRole(

View File

@ -1,3 +1,4 @@
import { CreateStrategySchema } from 'lib/openapi';
import { Store } from './store'; import { Store } from './store';
export interface IStrategy { export interface IStrategy {
@ -18,24 +19,22 @@ export interface IEditableStrategy {
title?: string; title?: string;
} }
export interface IMinimalStrategy { export type IMinimalStrategy = Pick<
name: string; CreateStrategySchema,
description?: string; 'name' | 'description' | 'editable' | 'parameters' | 'title'
editable?: boolean; >;
parameters?: any[];
title?: string;
}
export interface IStrategyImport { export type IStrategyImport = Pick<
name: string; CreateStrategySchema,
description?: string; | 'name'
deprecated?: boolean; | 'description'
parameters?: object[]; | 'deprecated'
builtIn?: boolean; | 'parameters'
sortOrder?: number; | 'builtIn'
displayName?: string; | 'sortOrder'
title?: string; | 'displayName'
} | 'title'
>;
export interface IMinimalStrategyRow { export interface IMinimalStrategyRow {
name: string; name: string;

View File

@ -801,18 +801,10 @@ test('should add a user to the project with a custom role', async () => {
description: '', description: '',
permissions: [ permissions: [
{ {
id: 2, id: 2, // CREATE_FEATURE
name: 'CREATE_FEATURE',
environment: undefined,
displayName: 'Create Feature Toggles',
type: 'project',
}, },
{ {
id: 8, id: 8, // DELETE_FEATURE
name: 'DELETE_FEATURE',
environment: undefined,
displayName: 'Delete Feature Toggles',
type: 'project',
}, },
], ],
}); });
@ -859,18 +851,10 @@ test('should delete role entries when deleting project', async () => {
description: '', description: '',
permissions: [ permissions: [
{ {
id: 2, id: 2, // CREATE_FEATURE
name: 'CREATE_FEATURE',
environment: undefined,
displayName: 'Create Feature Toggles',
type: 'project',
}, },
{ {
id: 8, id: 8, // DELETE_FEATURE
name: 'DELETE_FEATURE',
environment: undefined,
displayName: 'Delete Feature Toggles',
type: 'project',
}, },
], ],
}); });
@ -907,18 +891,10 @@ test('should change a users role in the project', async () => {
description: '', description: '',
permissions: [ permissions: [
{ {
id: 2, id: 2, // CREATE_FEATURE
name: 'CREATE_FEATURE',
environment: undefined,
displayName: 'Create Feature Toggles',
type: 'project',
}, },
{ {
id: 8, id: 8, // DELETE_FEATURE
name: 'DELETE_FEATURE',
environment: undefined,
displayName: 'Delete Feature Toggles',
type: 'project',
}, },
], ],
}); });
@ -1098,11 +1074,7 @@ test('Should allow bulk update of group permissions', async () => {
description: '', description: '',
permissions: [ permissions: [
{ {
id: 2, id: 2, // CREATE_FEATURE
name: 'CREATE_FEATURE',
environment: undefined,
displayName: 'Create Feature Toggles',
type: 'project',
}, },
], ],
}); });
@ -1129,11 +1101,7 @@ test('Should bulk update of only users', async () => {
description: '', description: '',
permissions: [ permissions: [
{ {
id: 2, id: 2, // CREATE_FEATURE
name: 'CREATE_FEATURE',
environment: undefined,
displayName: 'Create Feature Toggles',
type: 'project',
}, },
], ],
}); });
@ -1168,11 +1136,7 @@ test('Should allow bulk update of only groups', async () => {
description: '', description: '',
permissions: [ permissions: [
{ {
id: 2, id: 2, // CREATE_FEATURE
name: 'CREATE_FEATURE',
environment: undefined,
displayName: 'Create Feature Toggles',
type: 'project',
}, },
], ],
}); });
@ -1221,10 +1185,7 @@ test('Should allow permutations of roles, groups and users when adding a new acc
description: '', description: '',
permissions: [ permissions: [
{ {
id: 2, id: 2, // CREATE_FEATURE
name: 'CREATE_FEATURE',
displayName: 'Create feature toggles',
type: 'project',
}, },
], ],
}); });
@ -1234,10 +1195,7 @@ test('Should allow permutations of roles, groups and users when adding a new acc
description: '', description: '',
permissions: [ permissions: [
{ {
id: 7, id: 7, // UPDATE_FEATURE
name: 'UPDATE_FEATURE',
displayName: 'Update feature toggles',
type: 'project',
}, },
], ],
}); });

View File

@ -12,6 +12,7 @@ import {
import { IPermission } from 'lib/types/model'; import { IPermission } from 'lib/types/model';
import { IRoleStore } from 'lib/types'; import { IRoleStore } from 'lib/types';
import FakeRoleStore from './fake-role-store'; import FakeRoleStore from './fake-role-store';
import { PermissionRef } from 'lib/services/access-service';
class AccessStoreMock implements IAccessStore { class AccessStoreMock implements IAccessStore {
fakeRolesStore: IRoleStore; fakeRolesStore: IRoleStore;
@ -118,7 +119,7 @@ class AccessStoreMock implements IAccessStore {
addEnvironmentPermissionsToRole( addEnvironmentPermissionsToRole(
role_id: number, role_id: number,
permissions: IPermission[], permissions: PermissionRef[],
): Promise<void> { ): Promise<void> {
return Promise.resolve(undefined); return Promise.resolve(undefined);
} }