620 bug redundant attendees in the invitation list (#629)
Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
@@ -76,6 +76,80 @@ describe("parseCalendarEvent", () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("dedupes attendees addresses correctly", () => {
|
||||||
|
const rawData = [
|
||||||
|
["UID", {}, "text", "event-1"],
|
||||||
|
["DTSTART", {}, "date-time", "2025-07-18T09:00:00Z"],
|
||||||
|
["DTEND", {}, "date-time", "2025-07-18T10:00:00Z"],
|
||||||
|
["SUMMARY", {}, "text", "Team Meeting"],
|
||||||
|
["DESCRIPTION", {}, "text", "Discuss roadmap"],
|
||||||
|
["LOCATION", {}, "text", "Zoom"],
|
||||||
|
["ORGANIZER", { cn: "Alice" }, "cal-address", "alice@example.com"],
|
||||||
|
[
|
||||||
|
"ATTENDEE",
|
||||||
|
{ cn: "Bob", partstat: "ACCEPTED" },
|
||||||
|
"cal-address",
|
||||||
|
"bob@example.com",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ATTENDEE",
|
||||||
|
{ cn: "Bob", partstat: "ACCEPTED" },
|
||||||
|
"cal-address",
|
||||||
|
"bob@example.com",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ATTENDEE",
|
||||||
|
{ cn: "Bob", partstat: "ACCEPTED" },
|
||||||
|
"cal-address",
|
||||||
|
"bob@example.com",
|
||||||
|
],
|
||||||
|
["X-OPENPAAS-VIDEOCONFERENCE", {}, "text", "https://meet.link"],
|
||||||
|
["STATUS", {}, "text", "CONFIRMED"],
|
||||||
|
["SEQUENCE", {}, "integer", "2"],
|
||||||
|
["TRANSP", {}, "text", "OPAQUE"],
|
||||||
|
["CLASS", {}, "text", "PUBLIC"],
|
||||||
|
["DTSTAMP", {}, "date-time", "2025-07-18T08:00:00Z"],
|
||||||
|
] as VObjectProperty[];
|
||||||
|
|
||||||
|
const result = parseCalendarEvent(
|
||||||
|
rawData,
|
||||||
|
baseColor,
|
||||||
|
calendar,
|
||||||
|
"/calendars/test.ics"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.uid).toBe("event-1");
|
||||||
|
expect(result.title).toBe("Team Meeting");
|
||||||
|
expect(result.description).toBe("Discuss roadmap");
|
||||||
|
expect(result.location).toBe("Zoom");
|
||||||
|
expect(result.start).toBe("2025-07-18T09:00:00Z");
|
||||||
|
expect(result.end).toBe("2025-07-18T10:00:00Z");
|
||||||
|
expect(result.stamp).toBe("2025-07-18T08:00:00Z");
|
||||||
|
expect(result.sequence).toBe(2);
|
||||||
|
expect(result.color).toBe(baseColor);
|
||||||
|
expect(result.status).toBe("CONFIRMED");
|
||||||
|
expect(result.transp).toBe("OPAQUE");
|
||||||
|
expect(result.class).toBe("PUBLIC");
|
||||||
|
expect(result.x_openpass_videoconference).toBe("https://meet.link");
|
||||||
|
expect(result.timezone).not.toBeDefined();
|
||||||
|
|
||||||
|
expect(result.organizer).toEqual({
|
||||||
|
cn: "Alice",
|
||||||
|
cal_address: "alice@example.com",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.attendee).toEqual([
|
||||||
|
{
|
||||||
|
cn: "Bob",
|
||||||
|
cal_address: "bob@example.com",
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
cutype: "INDIVIDUAL",
|
||||||
|
role: "REQ-PARTICIPANT",
|
||||||
|
rsvp: "FALSE",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it("parses a full event correctly", () => {
|
it("parses a full event correctly", () => {
|
||||||
const rawData = [
|
const rawData = [
|
||||||
["UID", {}, "text", "event-1"],
|
["UID", {}, "text", "event-1"],
|
||||||
|
|||||||
@@ -297,11 +297,16 @@ export function PeopleSearch({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setInputError(null);
|
setInputError(null);
|
||||||
const mapped = value.map((v: string | User) =>
|
const mapped = value
|
||||||
typeof v === "string"
|
.map((v: string | User) =>
|
||||||
? { email: v.trim(), displayName: v.trim() }
|
typeof v === "string"
|
||||||
: v
|
? { email: v.trim(), displayName: v.trim() }
|
||||||
);
|
: v
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
(user, index, self) =>
|
||||||
|
self.findIndex((u) => u.email === user.email) === index
|
||||||
|
);
|
||||||
onChange(event, mapped);
|
onChange(event, mapped);
|
||||||
}}
|
}}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
|
|||||||
@@ -110,16 +110,23 @@ export function parseCalendarEvent(
|
|||||||
}
|
}
|
||||||
case "attendee": {
|
case "attendee": {
|
||||||
const paramsObj = params as Record<string, string>;
|
const paramsObj = params as Record<string, string>;
|
||||||
(event.attendee as userAttendee[]).push(
|
if (
|
||||||
createAttendee({
|
!event.attendee?.find(
|
||||||
cn: paramsObj?.cn,
|
(attendee) =>
|
||||||
cal_address: String(value).replace(/^mailto:/i, ""),
|
attendee.cal_address === String(value).replace(/^mailto:/i, "")
|
||||||
partstat: paramsObj?.partstat as userAttendee["partstat"],
|
)
|
||||||
rsvp: paramsObj?.rsvp as userAttendee["rsvp"],
|
) {
|
||||||
role: paramsObj?.role as userAttendee["role"],
|
(event.attendee as userAttendee[]).push(
|
||||||
cutype: paramsObj?.cutype as userAttendee["cutype"],
|
createAttendee({
|
||||||
})
|
cn: paramsObj?.cn,
|
||||||
);
|
cal_address: String(value).replace(/^mailto:/i, ""),
|
||||||
|
partstat: paramsObj?.partstat as userAttendee["partstat"],
|
||||||
|
rsvp: paramsObj?.rsvp as userAttendee["rsvp"],
|
||||||
|
role: paramsObj?.role as userAttendee["role"],
|
||||||
|
cutype: paramsObj?.cutype as userAttendee["cutype"],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "dtstamp":
|
case "dtstamp":
|
||||||
|
|||||||
Reference in New Issue
Block a user