Skip to content

Commit

Permalink
fix: enable segment importing for oss (#5010)
Browse files Browse the repository at this point in the history
  • Loading branch information
sjaanus committed Oct 12, 2023
1 parent 66304cf commit 7b7a2a7
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 7 deletions.
Expand Up @@ -46,6 +46,10 @@ import {
import { DbServiceFactory } from 'lib/db/transaction';
import { DependentFeaturesReadModel } from '../dependent-features/dependent-features-read-model';
import { FakeDependentFeaturesReadModel } from '../dependent-features/fake-dependent-features-read-model';
import {
createFakeSegmentService,
createSegmentService,
} from '../segment/createSegmentService';

export const createFakeExportImportTogglesService = (
config: IUnleashConfig,
Expand Down Expand Up @@ -106,6 +110,8 @@ export const createFakeExportImportTogglesService = (
);
const dependentFeaturesReadModel = new FakeDependentFeaturesReadModel();

const segmentService = createFakeSegmentService(config);

const exportImportService = new ExportImportService(
{
importTogglesStore,
Expand All @@ -126,6 +132,7 @@ export const createFakeExportImportTogglesService = (
contextService,
strategyService,
tagTypeService,
segmentService,
},
dependentFeaturesReadModel,
);
Expand Down Expand Up @@ -220,6 +227,8 @@ export const deferredExportImportTogglesService = (
);
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);

const segmentService = createSegmentService(db, config);

const exportImportService = new ExportImportService(
{
importTogglesStore,
Expand All @@ -240,6 +249,7 @@ export const deferredExportImportTogglesService = (
contextService,
strategyService,
tagTypeService,
segmentService,
},
dependentFeaturesReadModel,
);
Expand Down
Expand Up @@ -170,9 +170,18 @@ const tags = [
];

const tagTypes = [
{ name: 'bestt', description: 'test' },
{ name: 'special_tag', description: 'this is my special tag' },
{ name: 'special_tag', description: 'this is my special tag' }, // deliberate duplicate
{
name: 'bestt',
description: 'test',
},
{
name: 'special_tag',
description: 'this is my special tag',
},
{
name: 'special_tag',
description: 'this is my special tag',
}, // deliberate duplicate
];

const importPayload: ImportTogglesSchema = {
Expand All @@ -199,13 +208,19 @@ const importPayload: ImportTogglesSchema = {

const createUserEditorAccess = async (name, email) => {
const { userStore } = stores;
const user = await userStore.insert({ name, email });
const user = await userStore.insert({
name,
email,
});
return user;
};

const createUserAdminAccess = async (name, email) => {
const { userStore } = stores;
const user = await userStore.insert({ name, email });
const user = await userStore.insert({
name,
email,
});
await accessService.addUserToRole(user.id, adminRole.id, 'default');
return user;
};
Expand Down Expand Up @@ -301,7 +316,12 @@ test('validate import data', async () => {
data: {
...importPayload.data,
featureStrategies: [{ name: 'customStrategy' }],
segments: [{ id: 1, name: 'customSegment' }],
segments: [
{
id: 1,
name: 'customSegment',
},
],
contextFields: [
{
...contextField,
Expand All @@ -328,6 +348,11 @@ test('validate import data', async () => {
'We detected the following context fields that do not have matching legal values with the imported ones:',
affectedItems: [contextField.name],
},
{
affectedItems: ['customSegment'],
message:
'We detected the following segments in the import file that need to be created first:',
},
],
warnings: [
{
Expand Down
42 changes: 42 additions & 0 deletions src/lib/features/export-import-toggles/export-import-service.ts
Expand Up @@ -51,6 +51,7 @@ import { findDuplicates } from '../../util/findDuplicates';
import { FeatureNameCheckResultWithFeaturePattern } from '../feature-toggle/feature-toggle-service';
import { IDependentFeaturesReadModel } from '../dependent-features/dependent-features-read-model-type';
import groupBy from 'lodash.groupby';
import { ISegmentService } from '../../segments/segment-service-interface';

export type IImportService = {
validate(
Expand Down Expand Up @@ -103,6 +104,8 @@ export default class ExportImportService

private tagTypeService: TagTypeService;

private segmentService: ISegmentService;

private featureTagService: FeatureTagService;

private importPermissionsService: ImportPermissionsService;
Expand Down Expand Up @@ -133,6 +136,7 @@ export default class ExportImportService
eventService,
tagTypeService,
featureTagService,
segmentService,
}: Pick<
IUnleashServices,
| 'featureToggleService'
Expand All @@ -142,6 +146,7 @@ export default class ExportImportService
| 'eventService'
| 'tagTypeService'
| 'featureTagService'
| 'segmentService'
>,
dependentFeaturesReadModel: IDependentFeaturesReadModel,
) {
Expand All @@ -158,6 +163,7 @@ export default class ExportImportService
this.strategyService = strategyService;
this.contextService = contextService;
this.accessService = accessService;
this.segmentService = segmentService;
this.eventService = eventService;
this.tagTypeService = tagTypeService;
this.featureTagService = featureTagService;
Expand Down Expand Up @@ -187,6 +193,7 @@ export default class ExportImportService
duplicateFeatures,
featureNameCheckResult,
featureLimitResult,
unsupportedSegments,
] = await Promise.all([
this.getUnsupportedStrategies(dto),
this.getUsedCustomStrategies(dto),
Expand All @@ -202,6 +209,7 @@ export default class ExportImportService
this.getDuplicateFeatures(dto),
this.getInvalidFeatureNames(dto),
this.getFeatureLimit(dto),
this.getUnsupportedSegments(dto),
]);

const errors = ImportValidationMessages.compileErrors({
Expand All @@ -212,6 +220,7 @@ export default class ExportImportService
duplicateFeatures,
featureNameCheckResult,
featureLimitResult,
segments: unsupportedSegments,
});
const warnings = ImportValidationMessages.compileWarnings({
archivedFeatures,
Expand Down Expand Up @@ -240,6 +249,7 @@ export default class ExportImportService
this.verifyContextFields(dto),
this.importPermissionsService.verifyPermissions(dto, user, mode),
this.verifyFeatures(dto),
this.verifySegments(dto),
]);
}

Expand Down Expand Up @@ -426,6 +436,38 @@ export default class ExportImportService
}
}

private async getUnsupportedSegments(
dto: ImportTogglesSchema,
): Promise<string[]> {
const supportedSegments = await this.segmentService.getAll();
const targetProject = dto.project;
return dto.data.segments
? dto.data.segments
.filter(
(importingSegment) =>
!supportedSegments.find(
(existingSegment) =>
importingSegment.name ===
existingSegment.name &&
(!existingSegment.project ||
existingSegment.project ===
targetProject),
),
)

.map((it) => it.name)
: [];
}

private async verifySegments(dto: ImportTogglesSchema) {
const unsupportedSegments = await this.getUnsupportedSegments(dto);
if (unsupportedSegments.length > 0) {
throw new BadDataError(
`Unsupported segments: ${unsupportedSegments.join(', ')}`,
);
}
}

private async verifyContextFields(dto: ImportTogglesSchema) {
const unsupportedContextFields = await this.getUnsupportedContextFields(
dto,
Expand Down
Expand Up @@ -1018,6 +1018,11 @@ test('validate import data', async () => {
'We detected you want to create 2 new features to a project that already has 0 existing features, exceeding the maximum limit of 1.',
affectedItems: [],
},
{
message:
'We detected the following segments in the import file that need to be created first:',
affectedItems: ['customSegment'],
},
],
warnings: [
{
Expand Down
Expand Up @@ -14,6 +14,7 @@ export interface IErrorsParams {
duplicateFeatures: string[];
featureNameCheckResult: FeatureNameCheckResultWithFeaturePattern;
featureLimitResult: ProjectFeaturesLimit;
segments: string[];
}

export interface IWarningParams {
Expand Down Expand Up @@ -46,6 +47,7 @@ export class ImportValidationMessages {
duplicateFeatures,
featureNameCheckResult,
featureLimitResult,
segments,
}: IErrorsParams): ImportTogglesValidateItemSchema[] {
const errors: ImportTogglesValidateItemSchema[] = [];

Expand Down Expand Up @@ -106,6 +108,14 @@ export class ImportValidationMessages {
});
}

if (segments.length > 0) {
errors.push({
message:
'We detected the following segments in the import file that need to be created first:',
affectedItems: segments,
});
}

return errors;
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/openapi/spec/export-result-schema.ts
Expand Up @@ -142,7 +142,7 @@ export const exportResultSchema = {
items: {
type: 'object',
additionalProperties: false,
required: ['id'],
required: ['id', 'name'],
properties: {
id: {
type: 'number',
Expand Down

0 comments on commit 7b7a2a7

Please sign in to comment.