mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-05 16:19:55 -06:00
fix: user attributes updates api email fix (#5827)
This commit is contained in:
@@ -240,4 +240,126 @@ describe("updateUser", () => {
|
||||
expect(result.state.data).toEqual(expect.objectContaining(mockUserState));
|
||||
expect(result.messages).toEqual([]);
|
||||
});
|
||||
|
||||
test("should handle email attribute update with ignoreEmailAttribute flag", async () => {
|
||||
vi.mocked(getContactByUserIdWithAttributes).mockResolvedValue(mockContact);
|
||||
const newAttributes = { email: "new@example.com", name: "John Doe" };
|
||||
vi.mocked(updateAttributes).mockResolvedValue({
|
||||
success: true,
|
||||
messages: [],
|
||||
ignoreEmailAttribute: true,
|
||||
});
|
||||
|
||||
vi.mocked(getUserState).mockResolvedValue({
|
||||
...mockUserState,
|
||||
});
|
||||
|
||||
const result = await updateUser(mockEnvironmentId, mockUserId, "desktop", newAttributes);
|
||||
|
||||
expect(updateAttributes).toHaveBeenCalledWith(
|
||||
mockContactId,
|
||||
mockUserId,
|
||||
mockEnvironmentId,
|
||||
newAttributes
|
||||
);
|
||||
// Email should not be included in the final attributes
|
||||
expect(result.state.data).toEqual(
|
||||
expect.objectContaining({
|
||||
...mockUserState,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("should handle failed attribute update gracefully", async () => {
|
||||
vi.mocked(getContactByUserIdWithAttributes).mockResolvedValue(mockContact);
|
||||
const newAttributes = { company: "Formbricks" };
|
||||
vi.mocked(updateAttributes).mockResolvedValue({
|
||||
success: false,
|
||||
messages: ["Update failed"],
|
||||
});
|
||||
|
||||
const result = await updateUser(mockEnvironmentId, mockUserId, "desktop", newAttributes);
|
||||
|
||||
expect(updateAttributes).toHaveBeenCalledWith(
|
||||
mockContactId,
|
||||
mockUserId,
|
||||
mockEnvironmentId,
|
||||
newAttributes
|
||||
);
|
||||
// Should still return state even if update failed
|
||||
expect(result.state.data).toEqual(expect.objectContaining(mockUserState));
|
||||
expect(result.messages).toEqual(["Update failed"]);
|
||||
});
|
||||
|
||||
test("should handle multiple attribute updates correctly", async () => {
|
||||
vi.mocked(getContactByUserIdWithAttributes).mockResolvedValue(mockContact);
|
||||
const newAttributes = {
|
||||
company: "Formbricks",
|
||||
role: "Developer",
|
||||
language: "en",
|
||||
country: "US",
|
||||
};
|
||||
vi.mocked(updateAttributes).mockResolvedValue({
|
||||
success: true,
|
||||
messages: ["Attributes updated successfully"],
|
||||
});
|
||||
|
||||
const result = await updateUser(mockEnvironmentId, mockUserId, "desktop", newAttributes);
|
||||
|
||||
expect(updateAttributes).toHaveBeenCalledWith(
|
||||
mockContactId,
|
||||
mockUserId,
|
||||
mockEnvironmentId,
|
||||
newAttributes
|
||||
);
|
||||
expect(result.state.data?.language).toBe("en");
|
||||
expect(result.messages).toEqual(["Attributes updated successfully"]);
|
||||
});
|
||||
|
||||
test("should handle contact creation with multiple initial attributes", async () => {
|
||||
vi.mocked(getContactByUserIdWithAttributes).mockResolvedValue(null);
|
||||
const initialAttributes = {
|
||||
userId: mockUserId,
|
||||
email: "test@example.com",
|
||||
name: "Test User",
|
||||
};
|
||||
vi.mocked(prisma.contact.create).mockResolvedValue({
|
||||
id: mockContactId,
|
||||
attributes: [
|
||||
{ attributeKey: { key: "userId" }, value: mockUserId },
|
||||
{ attributeKey: { key: "email" }, value: "test@example.com" },
|
||||
{ attributeKey: { key: "name" }, value: "Test User" },
|
||||
],
|
||||
} as any);
|
||||
|
||||
const result = await updateUser(mockEnvironmentId, mockUserId, "desktop", initialAttributes);
|
||||
|
||||
expect(prisma.contact.create).toHaveBeenCalledWith({
|
||||
data: {
|
||||
environment: { connect: { id: mockEnvironmentId } },
|
||||
attributes: {
|
||||
create: [
|
||||
{
|
||||
attributeKey: {
|
||||
connect: { key_environmentId: { key: "userId", environmentId: mockEnvironmentId } },
|
||||
},
|
||||
value: mockUserId,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
attributes: {
|
||||
select: { attributeKey: { select: { key: true } }, value: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(contactCache.revalidate).toHaveBeenCalledWith({
|
||||
environmentId: mockEnvironmentId,
|
||||
userId: mockUserId,
|
||||
id: mockContactId,
|
||||
});
|
||||
expect(result.state.data).toEqual(expect.objectContaining(mockUserState));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -85,20 +85,26 @@ export const updateUser = async (
|
||||
}
|
||||
|
||||
if (shouldUpdate) {
|
||||
const { success, messages: updateAttrMessages } = await updateAttributes(
|
||||
contact.id,
|
||||
userId,
|
||||
environmentId,
|
||||
attributes
|
||||
);
|
||||
const {
|
||||
success,
|
||||
messages: updateAttrMessages,
|
||||
ignoreEmailAttribute,
|
||||
} = await updateAttributes(contact.id, userId, environmentId, attributes);
|
||||
|
||||
messages = updateAttrMessages ?? [];
|
||||
|
||||
// If the attributes update was successful and the language attribute was provided, set the language
|
||||
if (success) {
|
||||
let attributesToUpdate = { ...attributes };
|
||||
|
||||
if (ignoreEmailAttribute) {
|
||||
const { email, ...rest } = attributes;
|
||||
attributesToUpdate = rest;
|
||||
}
|
||||
|
||||
contactAttributes = {
|
||||
...contactAttributes,
|
||||
...attributes,
|
||||
...attributesToUpdate,
|
||||
};
|
||||
|
||||
if (attributes.language) {
|
||||
|
||||
@@ -13,7 +13,7 @@ export const updateAttributes = async (
|
||||
userId: string,
|
||||
environmentId: string,
|
||||
contactAttributesParam: TContactAttributes
|
||||
): Promise<{ success: boolean; messages?: string[] }> => {
|
||||
): Promise<{ success: boolean; messages?: string[]; ignoreEmailAttribute?: boolean }> => {
|
||||
validateInputs(
|
||||
[contactId, ZId],
|
||||
[userId, ZString],
|
||||
@@ -21,6 +21,8 @@ export const updateAttributes = async (
|
||||
[contactAttributesParam, ZContactAttributes]
|
||||
);
|
||||
|
||||
let ignoreEmailAttribute = false;
|
||||
|
||||
// Fetch contact attribute keys and email check in parallel
|
||||
const [contactAttributeKeys, existingEmailAttribute] = await Promise.all([
|
||||
getContactAttributeKeys(environmentId),
|
||||
@@ -58,6 +60,10 @@ export const updateAttributes = async (
|
||||
? ["The email already exists for this environment and was not updated."]
|
||||
: [];
|
||||
|
||||
if (emailExists) {
|
||||
ignoreEmailAttribute = true;
|
||||
}
|
||||
|
||||
// First, update all existing attributes
|
||||
if (existingAttributes.length > 0) {
|
||||
await prisma.$transaction(
|
||||
@@ -124,5 +130,6 @@ export const updateAttributes = async (
|
||||
return {
|
||||
success: true,
|
||||
messages,
|
||||
ignoreEmailAttribute,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user