mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: check if child and parent are in the same project (#5093)
This commit is contained in:
		
							parent
							
								
									7195a63e56
								
							
						
					
					
						commit
						56892c54d9
					
				@ -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
 | 
			
		||||
                ? {
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
    );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,7 @@
 | 
			
		||||
export interface IFeaturesReadModel {
 | 
			
		||||
    featureExists(parent: string): Promise<boolean>;
 | 
			
		||||
    featuresInTheSameProject(
 | 
			
		||||
        featureA: string,
 | 
			
		||||
        featureB: string,
 | 
			
		||||
    ): Promise<boolean>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user