1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-23 00:22:19 +01:00

fix: Adds feature-variant-updated event. (#1189)

This triggers when we update or overwrite variants, and will include the
previous variants and the new variants.

Co-authored-by: Ivar Østhus <ivarconr@gmail.com>
This commit is contained in:
Christopher Kolstad 2021-12-16 11:07:19 +01:00 committed by GitHub
parent b05216bc76
commit 994db02f84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 77 additions and 10 deletions

View File

@ -259,12 +259,13 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
}
async saveVariants(
project: string,
featureName: string,
newVariants: IVariant[],
): Promise<FeatureToggle> {
const row = await this.db(TABLE)
.update({ variants: JSON.stringify(newVariants) })
.where({ name: featureName })
.where({ project: project, name: featureName })
.returning(FEATURE_COLUMNS);
return this.rowToFeature(row[0]);
}

View File

@ -7,6 +7,8 @@ import { Request, Response } from 'express';
import { Operation } from 'fast-json-patch';
import { UPDATE_FEATURE } from '../../../types/permissions';
import { IVariant } from '../../../types/model';
import { extractUsername } from '../../../util/extract-user';
import { IAuthRequest } from '../../unleash-types';
const PREFIX = '/:projectId/features/:featureName/variants';
@ -47,13 +49,17 @@ export default class VariantsController extends Controller {
}
async patchVariants(
req: Request<FeatureParams, any, Operation[], any>,
req: IAuthRequest<FeatureParams, any, Operation[]>,
res: Response,
): Promise<void> {
const { featureName } = req.params;
const { projectId, featureName } = req.params;
const userName = extractUsername(req);
const updatedFeature = await this.featureService.updateVariants(
featureName,
projectId,
req.body,
userName,
);
res.status(200).json({
version: '1',
@ -62,13 +68,16 @@ export default class VariantsController extends Controller {
}
async overwriteVariants(
req: Request<FeatureParams, any, IVariant[], any>,
req: IAuthRequest<FeatureParams, any, IVariant[], any>,
res: Response,
): Promise<void> {
const { featureName } = req.params;
const { projectId, featureName } = req.params;
const userName = extractUsername(req);
const updatedFeature = await this.featureService.saveVariants(
featureName,
projectId,
req.body,
userName,
);
res.status(200).json({
version: '1',

View File

@ -11,6 +11,7 @@ import {
variantsArraySchema,
} from '../schema/feature-schema';
import {
FEATURE_UPDATED,
FeatureArchivedEvent,
FeatureChangeProjectEvent,
FeatureCreatedEvent,
@ -22,7 +23,7 @@ import {
FeatureStrategyAddEvent,
FeatureStrategyRemoveEvent,
FeatureStrategyUpdateEvent,
FEATURE_UPDATED,
FeatureVariantEvent,
} from '../types/events';
import NotFoundError from '../error/notfound-error';
import {
@ -36,8 +37,8 @@ import { IFeatureToggleStore } from '../types/stores/feature-toggle-store';
import {
FeatureToggle,
FeatureToggleDTO,
FeatureToggleWithEnvironment,
FeatureToggleLegacy,
FeatureToggleWithEnvironment,
IEnvironmentDetail,
IFeatureEnvironmentInfo,
IFeatureOverview,
@ -232,6 +233,7 @@ class FeatureToggleService {
throw e;
}
}
/**
* PUT /api/admin/projects/:projectId/features/:featureName/strategies/:strategyId ?
* {
@ -910,20 +912,43 @@ class FeatureToggleService {
async updateVariants(
featureName: string,
project: string,
newVariants: Operation[],
createdBy: string,
): Promise<FeatureToggle> {
const oldVariants = await this.getVariants(featureName);
const { newDocument } = await applyPatch(oldVariants, newVariants);
return this.saveVariants(featureName, newDocument);
return this.saveVariants(featureName, project, newDocument, createdBy);
}
async saveVariants(
featureName: string,
project: string,
newVariants: IVariant[],
createdBy: string,
): Promise<FeatureToggle> {
await variantsArraySchema.validateAsync(newVariants);
const fixedVariants = this.fixVariantWeights(newVariants);
return this.featureToggleStore.saveVariants(featureName, fixedVariants);
const oldVariants = await this.featureToggleStore.getVariants(
featureName,
);
const featureToggle = await this.featureToggleStore.saveVariants(
project,
featureName,
fixedVariants,
);
const tags = await this.tagStore.getAllTagsForFeature(featureName);
await this.eventStore.store(
new FeatureVariantEvent({
project,
featureName,
createdBy,
tags,
oldVariants,
newVariants: featureToggle.variants,
}),
);
return featureToggle;
}
fixVariantWeights(variants: IVariant[]): IVariant[] {

View File

@ -1,4 +1,4 @@
import { FeatureToggle, IStrategyConfig, ITag } from './model';
import { FeatureToggle, IStrategyConfig, ITag, IVariant } from './model';
export const APPLICATION_CREATED = 'application-created';
@ -7,6 +7,7 @@ export const FEATURE_CREATED = 'feature-created';
export const FEATURE_DELETED = 'feature-deleted';
export const FEATURE_UPDATED = 'feature-updated';
export const FEATURE_METADATA_UPDATED = 'feature-metadata-updated';
export const FEATURE_VARIANTS_UPDATED = 'feature-variants-updated';
export const FEATURE_PROJECT_CHANGE = 'feature-project-change';
export const FEATURE_ARCHIVED = 'feature-archived';
export const FEATURE_REVIVED = 'feature-revived';
@ -140,6 +141,31 @@ export class FeatureEnvironmentEvent extends BaseEvent {
}
}
export class FeatureVariantEvent extends BaseEvent {
readonly project: string;
readonly featureName: string;
readonly data: {
oldVariants: IVariant[];
newVariants: IVariant[];
};
constructor(p: {
project: string;
featureName: string;
createdBy: string;
tags: ITag[];
oldVariants: IVariant[];
newVariants: IVariant[];
}) {
super(FEATURE_VARIANTS_UPDATED, p.createdBy, p.tags);
this.project = p.project;
this.featureName = p.featureName;
this.data = { oldVariants: p.oldVariants, newVariants: p.newVariants };
}
}
export class FeatureChangeProjectEvent extends BaseEvent {
readonly project: string;

View File

@ -18,6 +18,7 @@ export interface IFeatureToggleStore extends Store<FeatureToggle, string> {
getAll(query?: Partial<IFeatureToggleQuery>): Promise<FeatureToggle[]>;
getVariants(featureName: string): Promise<IVariant[]>;
saveVariants(
project: string,
featureName: string,
newVariants: IVariant[],
): Promise<FeatureToggle>;

View File

@ -38,10 +38,14 @@ beforeAll(async () => {
const createVariants = async (
featureName: string,
variants: IVariant[],
projectId: string = 'default',
username: string = 'test',
) => {
await app.services.featureToggleServiceV2.saveVariants(
featureName,
projectId,
variants,
username,
);
};

View File

@ -134,6 +134,7 @@ export default class FakeFeatureToggleStore implements IFeatureToggleStore {
}
async saveVariants(
project: string,
featureName: string,
newVariants: IVariant[],
): Promise<FeatureToggle> {