mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-04 04:41:38 -05:00
fix: fixes number being passed into string attribute (#7255)
This commit is contained in:
@@ -2,13 +2,26 @@ import { NextRequest, userAgent } from "next/server";
|
||||
import { logger } from "@formbricks/logger";
|
||||
import { TContactAttributesInput } from "@formbricks/types/contact-attribute";
|
||||
import { ZEnvironmentId } from "@formbricks/types/environment";
|
||||
import { ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
import { ResourceNotFoundError, ValidationError } from "@formbricks/types/errors";
|
||||
import { TJsPersonState } from "@formbricks/types/js";
|
||||
import { responses } from "@/app/lib/api/response";
|
||||
import { withV1ApiWrapper } from "@/app/lib/api/with-api-logging";
|
||||
import { getIsContactsEnabled } from "@/modules/ee/license-check/lib/utils";
|
||||
import { updateUser } from "./lib/update-user";
|
||||
|
||||
const handleError = (err: unknown, url: string): { response: Response } => {
|
||||
if (err instanceof ResourceNotFoundError) {
|
||||
return { response: responses.notFoundResponse(err.resourceType, err.resourceId) };
|
||||
}
|
||||
|
||||
if (err instanceof ValidationError) {
|
||||
return { response: responses.badRequestResponse(err.message, undefined, true) };
|
||||
}
|
||||
|
||||
logger.error({ error: err, url }, "Error in POST /api/v1/client/[environmentId]/user");
|
||||
return { response: responses.internalServerErrorResponse("Unable to fetch user state", true) };
|
||||
};
|
||||
|
||||
export const OPTIONS = async (): Promise<Response> => {
|
||||
return responses.successResponse(
|
||||
{},
|
||||
@@ -123,16 +136,7 @@ export const POST = withV1ApiWrapper({
|
||||
response: responses.successResponse(responseJson, true),
|
||||
};
|
||||
} catch (err) {
|
||||
if (err instanceof ResourceNotFoundError) {
|
||||
return {
|
||||
response: responses.notFoundResponse(err.resourceType, err.resourceId),
|
||||
};
|
||||
}
|
||||
|
||||
logger.error({ error: err, url: req.url }, "Error in POST /api/v1/client/[environmentId]/user");
|
||||
return {
|
||||
response: responses.internalServerErrorResponse(err.message ?? "Unable to fetch person state", true),
|
||||
};
|
||||
return handleError(err, req.url);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -13,22 +13,14 @@ describe("validateAndParseAttributeValue", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("converts numbers to string", () => {
|
||||
test("rejects number values (SDK must pass actual strings)", () => {
|
||||
const result = validateAndParseAttributeValue(42, "string", "testKey");
|
||||
expect(result.valid).toBe(true);
|
||||
if (result.valid) {
|
||||
expect(result.parsedValue.value).toBe("42");
|
||||
expect(result.parsedValue.valueNumber).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
test("converts Date to ISO string", () => {
|
||||
const date = new Date("2024-01-15T10:30:00.000Z");
|
||||
const result = validateAndParseAttributeValue(date, "string", "testKey");
|
||||
expect(result.valid).toBe(true);
|
||||
if (result.valid) {
|
||||
expect(result.parsedValue.value).toBe("2024-01-15T10:30:00.000Z");
|
||||
expect(result.parsedValue.valueDate).toBeNull();
|
||||
expect(result.valid).toBe(false);
|
||||
if (!result.valid) {
|
||||
expect(result.error.code).toBe("string_type_mismatch");
|
||||
expect(result.error.params.key).toBe("testKey");
|
||||
expect(result.error.params.type).toBe("number");
|
||||
expect(formatValidationError(result.error)).toContain("received a number");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,15 +27,6 @@ export type TAttributeValidationResult =
|
||||
error: TAttributeValidationError;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts any value to a string representation
|
||||
*/
|
||||
const convertToString = (value: TRawValue): string => {
|
||||
if (value instanceof Date) return value.toISOString();
|
||||
if (typeof value === "number") return String(value);
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a human-readable type name for error messages
|
||||
*/
|
||||
@@ -45,16 +36,28 @@ const getTypeName = (value: TRawValue): string => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates and parses a string type attribute
|
||||
* Validates and parses a string type attribute.
|
||||
*/
|
||||
const validateStringType = (value: TRawValue): TAttributeValidationResult => ({
|
||||
valid: true,
|
||||
parsedValue: {
|
||||
value: convertToString(value),
|
||||
valueNumber: null,
|
||||
valueDate: null,
|
||||
},
|
||||
});
|
||||
const validateStringType = (value: TRawValue, attributeKey: string): TAttributeValidationResult => {
|
||||
if (typeof value === "string") {
|
||||
return {
|
||||
valid: true,
|
||||
parsedValue: {
|
||||
value,
|
||||
valueNumber: null,
|
||||
valueDate: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
error: {
|
||||
code: "string_type_mismatch",
|
||||
params: { key: attributeKey, type: getTypeName(value) },
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates and parses a number type attribute.
|
||||
@@ -170,13 +173,13 @@ export const validateAndParseAttributeValue = (
|
||||
): TAttributeValidationResult => {
|
||||
switch (expectedDataType) {
|
||||
case "string":
|
||||
return validateStringType(value);
|
||||
return validateStringType(value, attributeKey);
|
||||
case "number":
|
||||
return validateNumberType(value, attributeKey);
|
||||
case "date":
|
||||
return validateDateType(value, attributeKey);
|
||||
default:
|
||||
return validateStringType(value);
|
||||
return validateStringType(value, attributeKey);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -185,6 +188,8 @@ export const validateAndParseAttributeValue = (
|
||||
* Used for API/SDK responses.
|
||||
*/
|
||||
const VALIDATION_ERROR_TEMPLATES: Record<string, string> = {
|
||||
string_type_mismatch:
|
||||
"Attribute '{key}' expects a string but received a {type}. Pass an actual string value.",
|
||||
number_type_mismatch:
|
||||
"Attribute '{key}' expects a number but received a string. Pass an actual number value (e.g., 123 instead of \"123\").",
|
||||
date_invalid: "Attribute '{key}' expects a valid date. Received: Invalid Date",
|
||||
|
||||
Reference in New Issue
Block a user