1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

feat: first skeleton of the batch import (#2868)

First skeleton of batch import:
* injecting feature toggle service because I want to reuse logic and not
just the store
This commit is contained in:
Mateusz Kwasniewski 2023-01-11 15:19:16 +01:00 committed by GitHub
parent 3e4e0e4df9
commit afdcd45042
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 72 additions and 3 deletions

View File

@ -7,8 +7,10 @@ import { Logger } from '../../logger';
import { OpenApiService } from '../../services/openapi-service';
import ExportImportService, {
IExportQuery,
IImportDTO,
} from 'lib/services/export-import-service';
import { InvalidOperationError } from '../../error';
import { IAuthRequest } from '../unleash-types';
class ExportImportController extends Controller {
private logger: Logger;
@ -45,6 +47,12 @@ class ExportImportController extends Controller {
// }),
// ],
});
this.route({
method: 'post',
path: '/import',
permission: NONE,
handler: this.importData,
});
}
async export(
@ -65,5 +73,16 @@ class ExportImportController extends Controller {
);
}
}
async importData(
req: IAuthRequest<unknown, unknown, IImportDTO, unknown>,
res: Response,
): Promise<void> {
const dto = req.body;
const user = req.user;
await this.exportImportService.import(dto, user);
res.status(201).end();
}
}
export default ExportImportController;

View File

@ -13,14 +13,22 @@ import { IEnvironmentStore } from '../types/stores/environment-store';
import { IFeatureEnvironmentStore } from '../types/stores/feature-environment-store';
import { IUnleashStores } from '../types/stores';
import { ISegmentStore } from '../types/stores/segment-store';
import { IFlagResolver } from 'lib/types';
import { IFlagResolver, IUnleashServices } from 'lib/types';
import { IContextFieldDto } from '../types/stores/context-field-store';
import FeatureToggleService from './feature-toggle-service';
import User from 'lib/types/user';
export interface IExportQuery {
features: string[];
environment: string;
}
export interface IImportDTO {
data: IExportData;
project?: string;
environment?: string;
}
export interface IExportData {
features: FeatureToggle[];
tags?: ITag[];
@ -54,12 +62,17 @@ export default class ExportImportService {
private flagResolver: IFlagResolver;
private featureToggleService: FeatureToggleService;
constructor(
stores: IUnleashStores,
{
getLogger,
flagResolver,
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>,
{
featureToggleService,
}: Pick<IUnleashServices, 'featureToggleService'>,
) {
this.eventStore = stores.eventStore;
this.toggleStore = stores.featureToggleStore;
@ -73,6 +86,7 @@ export default class ExportImportService {
this.environmentStore = stores.environmentStore;
this.segmentStore = stores.segmentStore;
this.flagResolver = flagResolver;
this.featureToggleService = featureToggleService;
this.logger = getLogger('services/state-service.js');
}
@ -82,6 +96,18 @@ export default class ExportImportService {
).filter((toggle) => query.features.includes(toggle.name));
return { features: features };
}
async import(dto: IImportDTO, user: User): Promise<void> {
await Promise.all(
dto.data.features.map((feature) =>
this.featureToggleService.createFeatureToggle(
dto.project || feature.project,
feature,
user.name,
),
),
);
}
}
module.exports = ExportImportService;

View File

@ -61,7 +61,6 @@ export const createServices = (
const featureTypeService = new FeatureTypeService(stores, config);
const resetTokenService = new ResetTokenService(stores, config);
const stateService = new StateService(stores, config);
const exportImportService = new ExportImportService(stores, config);
const strategyService = new StrategyService(stores, config);
const tagService = new TagService(stores, config);
const tagTypeService = new TagTypeService(stores, config);
@ -85,6 +84,9 @@ export const createServices = (
segmentService,
accessService,
);
const exportImportService = new ExportImportService(stores, config, {
featureToggleService: featureToggleServiceV2,
});
const environmentService = new EnvironmentService(stores, config);
const featureTagService = new FeatureTagService(stores, config);
const favoritesService = new FavoritesService(stores, config);

View File

@ -5,7 +5,7 @@ import {
import dbInit, { ITestDb } from '../../helpers/database-init';
import getLogger from '../../../fixtures/no-logger';
import { IEventStore } from 'lib/types/stores/event-store';
import { FeatureToggleDTO, IStrategyConfig } from 'lib/types';
import { FeatureToggle, FeatureToggleDTO, IStrategyConfig } from 'lib/types';
import { DEFAULT_ENV } from '../../../../lib/util';
let app: IUnleashTest;
@ -79,3 +79,25 @@ test('exports features', async () => {
],
});
});
test('import features', async () => {
const feature: FeatureToggle = { project: 'ignore', name: 'first_feature' };
await app.request
.post('/api/admin/features-batch/import')
.send({
data: { features: [feature] },
project: 'default',
environment: 'custom_environment',
})
.set('Content-Type', 'application/json')
.expect(201);
const { body } = await app.request
.get('/api/admin/features/first_feature')
.expect(200);
expect(body).toMatchObject({
name: 'first_feature',
project: 'default',
});
});