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.featuresReadModel.featureExists(parent),
this.featuresReadModel.featuresInTheSameProject(child, parent),
]);
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 =
enabled === false
? {

View File

@ -11,7 +11,9 @@ import {
FEATURE_DEPENDENCY_ADDED,
FEATURE_DEPENDENCY_REMOVED,
IEventStore,
IUser,
} from '../../types';
import { ProjectService } from '../../services';
let app: IUnleashTest;
let db: ITestDb;
@ -34,6 +36,15 @@ beforeAll(async () => {
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 () =>
(await eventStore.getEvents())
.map((event) => event.type)
@ -207,3 +218,19 @@ test('should not allow to add dependency to self', async () => {
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> {
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;
}
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 {
featureExists(parent: string): Promise<boolean>;
featuresInTheSameProject(
featureA: string,
featureB: string,
): Promise<boolean>;
}