mirror of
https://github.com/Unleash/unleash.git
synced 2024-11-01 19:07:38 +01:00
29be130757
## About the changes According to our docs, we only support up to 1 decimal place for weights. This is to use integers to represent the percentages (we divide them by 10) and supporting more decimals results in bad maths due to floating point arithmetics. This PRs adds Frontend and Backend validations to enforce this restriction Closes #2222 ## Discussion points Should we reconsider supporting more decimal places, that door remains open, but for now we'll just adhere to our documentation because that change would require some development.
163 lines
4.8 KiB
TypeScript
163 lines
4.8 KiB
TypeScript
import joi from 'joi';
|
|
import { ALL_OPERATORS } from '../util/constants';
|
|
import { nameType } from '../routes/util';
|
|
import { validateJsonString } from '../util/validateJsonString';
|
|
|
|
export const nameSchema = joi
|
|
.object()
|
|
.keys({ name: nameType })
|
|
.options({ stripUnknown: true, allowUnknown: false, abortEarly: false });
|
|
|
|
export const constraintSchema = joi.object().keys({
|
|
contextName: joi.string().required(),
|
|
operator: joi
|
|
.string()
|
|
.valid(...ALL_OPERATORS)
|
|
.required(),
|
|
// Constraints must have a values array to support legacy SDKs.
|
|
values: joi.array().items(joi.string().min(1).max(100)).default([]),
|
|
value: joi.optional(),
|
|
caseInsensitive: joi.boolean().optional(),
|
|
inverted: joi.boolean().optional(),
|
|
});
|
|
|
|
export const strategiesSchema = joi.object().keys({
|
|
id: joi.string().optional(),
|
|
name: nameType,
|
|
constraints: joi.array().allow(null).items(constraintSchema),
|
|
parameters: joi.object(),
|
|
});
|
|
|
|
export const variantValueSchema = joi
|
|
.string()
|
|
.required()
|
|
// perform additional validation
|
|
// when provided 'type' is 'json'
|
|
.when('type', {
|
|
is: 'json',
|
|
then: joi.custom((val, helper) => {
|
|
const isValidJsonString = validateJsonString(val);
|
|
if (isValidJsonString === false) {
|
|
return helper.error('invalidJsonString');
|
|
}
|
|
return val;
|
|
}),
|
|
})
|
|
.messages({
|
|
invalidJsonString:
|
|
"'value' must be a valid json string when 'type' is json",
|
|
});
|
|
|
|
export const variantsSchema = joi.object().keys({
|
|
name: nameType,
|
|
weight: joi
|
|
.number()
|
|
.integer()
|
|
.message('Weight only supports 1 decimal')
|
|
.min(0)
|
|
.max(1000)
|
|
.required(),
|
|
weightType: joi.string().valid('variable', 'fix').default('variable'),
|
|
payload: joi
|
|
.object()
|
|
.keys({
|
|
type: joi.string().required(),
|
|
value: variantValueSchema,
|
|
})
|
|
.optional(),
|
|
stickiness: joi.string().default('default'),
|
|
overrides: joi.array().items(
|
|
joi
|
|
.object()
|
|
.keys({
|
|
contextName: joi.string().required(),
|
|
values: joi.array().items(joi.string()),
|
|
})
|
|
.optional(),
|
|
),
|
|
});
|
|
|
|
export const variantsArraySchema = joi
|
|
.array()
|
|
.min(0)
|
|
.items(variantsSchema)
|
|
.unique((a, b) => a.name === b.name);
|
|
|
|
export const featureMetadataSchema = joi
|
|
.object()
|
|
.keys({
|
|
name: nameType,
|
|
stale: joi.boolean().default(false),
|
|
archived: joi.boolean().default(false),
|
|
type: joi.string().default('release'),
|
|
description: joi.string().allow('').allow(null).optional(),
|
|
impressionData: joi
|
|
.boolean()
|
|
.allow(true)
|
|
.allow(false)
|
|
.default(false)
|
|
.optional(),
|
|
createdAt: joi.date().optional().allow(null),
|
|
variants: joi
|
|
.array()
|
|
.allow(null)
|
|
.unique((a, b) => a.name === b.name)
|
|
.optional()
|
|
.items(variantsSchema),
|
|
})
|
|
.options({ allowUnknown: false, stripUnknown: true, abortEarly: false });
|
|
|
|
export const featureSchema = joi
|
|
.object()
|
|
.keys({
|
|
name: nameType,
|
|
enabled: joi.boolean().default(false),
|
|
stale: joi.boolean().default(false),
|
|
archived: joi.boolean().default(false),
|
|
type: joi.string().default('release'),
|
|
project: joi.string().default('default'),
|
|
description: joi.string().allow('').allow(null).optional(),
|
|
impressionData: joi
|
|
.boolean()
|
|
.allow(true)
|
|
.allow(false)
|
|
.default(false)
|
|
.optional(),
|
|
strategies: joi
|
|
.array()
|
|
.min(0)
|
|
.allow(null)
|
|
.optional()
|
|
.items(strategiesSchema),
|
|
variants: joi
|
|
.array()
|
|
.allow(null)
|
|
.unique((a, b) => a.name === b.name)
|
|
.optional()
|
|
.items(variantsSchema),
|
|
})
|
|
.options({ allowUnknown: false, stripUnknown: true, abortEarly: false });
|
|
|
|
export const querySchema = joi
|
|
.object()
|
|
.keys({
|
|
tag: joi
|
|
.array()
|
|
.allow(null)
|
|
.items(joi.string().pattern(/\w+:.+/, { name: 'tag' }))
|
|
.optional(),
|
|
project: joi.array().allow(null).items(nameType).optional(),
|
|
namePrefix: joi.string().allow(null).optional(),
|
|
environment: joi.string().allow(null).optional(),
|
|
inlineSegmentConstraints: joi.boolean().optional(),
|
|
})
|
|
.options({ allowUnknown: false, stripUnknown: true, abortEarly: false });
|
|
|
|
export const featureTagSchema = joi.object().keys({
|
|
featureName: nameType,
|
|
tagType: nameType.optional(),
|
|
tagValue: joi.string(),
|
|
type: nameType.optional(),
|
|
value: joi.string().optional(),
|
|
});
|