1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-11 00:08:30 +01:00

feat: check if child and parent are in the same project (#5093)

This commit is contained in:
Mateusz Kwasniewski 2023-10-19 11:11:05 +02:00 committed by GitHub
parent 7195a63e56
commit 56892c54d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 56 additions and 1 deletions

View File

@ -96,9 +96,10 @@ export class DependentFeaturesService {
); );
} }
const [children, parentExists] = await Promise.all([ const [children, parentExists, sameProject] = await Promise.all([
this.dependentFeaturesReadModel.getChildren([child]), this.dependentFeaturesReadModel.getChildren([child]),
this.featuresReadModel.featureExists(parent), this.featuresReadModel.featureExists(parent),
this.featuresReadModel.featuresInTheSameProject(child, parent),
]); ]);
if (children.length > 0) { if (children.length > 0) {
@ -113,6 +114,12 @@ export class DependentFeaturesService {
); );
} }
if (!sameProject) {
throw new InvalidOperationError(
'Parent and child features should be in the same project',
);
}
const featureDependency: FeatureDependency = const featureDependency: FeatureDependency =
enabled === false enabled === false
? { ? {

View File

@ -11,7 +11,9 @@ import {
FEATURE_DEPENDENCY_ADDED, FEATURE_DEPENDENCY_ADDED,
FEATURE_DEPENDENCY_REMOVED, FEATURE_DEPENDENCY_REMOVED,
IEventStore, IEventStore,
IUser,
} from '../../types'; } from '../../types';
import { ProjectService } from '../../services';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
@ -34,6 +36,15 @@ beforeAll(async () => {
eventStore = db.stores.eventStore; eventStore = db.stores.eventStore;
}); });
const createProject = async (name: string) => {
await db.stores.projectStore.create({
name: name,
description: '',
id: name,
mode: 'open' as const,
});
};
const getRecordedEventTypesForDependencies = async () => const getRecordedEventTypesForDependencies = async () =>
(await eventStore.getEvents()) (await eventStore.getEvents())
.map((event) => event.type) .map((event) => event.type)
@ -207,3 +218,19 @@ test('should not allow to add dependency to self', async () => {
403, 403,
); );
}); });
test('should not allow to add dependency to feature from another project', async () => {
const child = uuidv4();
const parent = uuidv4();
await app.createFeature(parent);
await createProject('another-project');
await app.createFeature(child, 'another-project');
await addFeatureDependency(
child,
{
feature: parent,
},
403,
);
});

View File

@ -4,4 +4,11 @@ export class FakeFeaturesReadModel implements IFeaturesReadModel {
featureExists(): Promise<boolean> { featureExists(): Promise<boolean> {
return Promise.resolve(false); return Promise.resolve(false);
} }
featuresInTheSameProject(
featureA: string,
featureB: string,
): Promise<boolean> {
return Promise.resolve(true);
}
} }

View File

@ -16,4 +16,14 @@ export class FeaturesReadModel implements IFeaturesReadModel {
return rows.length > 0; return rows.length > 0;
} }
async featuresInTheSameProject(
featureA: string,
featureB: string,
): Promise<boolean> {
const rows = await this.db('features')
.countDistinct('project as count')
.whereIn('name', [featureA, featureB]);
return Number(rows[0].count) === 1;
}
} }

View File

@ -1,3 +1,7 @@
export interface IFeaturesReadModel { export interface IFeaturesReadModel {
featureExists(parent: string): Promise<boolean>; featureExists(parent: string): Promise<boolean>;
featuresInTheSameProject(
featureA: string,
featureB: string,
): Promise<boolean>;
} }