fix: Encode usernames in booking url to UTF-8 to prevent 500 throws (#19475)
* fix: Encode usernames in booking url to UTF-8 to prevent throws * add dynamic booking page e2e * add 1 more test
This commit is contained in:
@@ -75,6 +75,26 @@ test.describe("user with a special character in the username", () => {
|
||||
const response = await page.goto(`/${user.username}/30-min`);
|
||||
expect(response?.status()).not.toBe(404);
|
||||
});
|
||||
|
||||
test("Should not throw 500 when redirecting user to his/her only event-type page even if username contains special characters", async ({
|
||||
page,
|
||||
users,
|
||||
}) => {
|
||||
const benny = await users.create({
|
||||
username: "ßenny", // ß is a special character
|
||||
eventTypes: [
|
||||
{
|
||||
title: "15 min",
|
||||
slug: "15-min",
|
||||
length: 15,
|
||||
},
|
||||
],
|
||||
overrideDefaultEventTypes: true,
|
||||
});
|
||||
// This redirects to /[user]/[type] because this user has only 1 event-type
|
||||
const response = await page.goto(`/${benny.username}`);
|
||||
expect(response?.status()).not.toBe(500);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("free user", () => {
|
||||
|
||||
@@ -143,4 +143,33 @@ test.describe("Organization:", () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("dynamic booking for usernames with special characters", async ({ page, users, orgs }) => {
|
||||
const org = await orgs.create({
|
||||
name: "TestOrg",
|
||||
});
|
||||
|
||||
const user1 = await users.create({
|
||||
organizationId: org.id,
|
||||
name: "User 1",
|
||||
roleInOrganization: MembershipRole.MEMBER,
|
||||
});
|
||||
|
||||
const user2 = await users.create({
|
||||
username: "ßenny-Joo", // ß is a special character
|
||||
organizationId: org.id,
|
||||
name: "User 2",
|
||||
roleInOrganization: MembershipRole.MEMBER,
|
||||
});
|
||||
await doOnOrgDomain(
|
||||
{
|
||||
orgSlug: org.slug,
|
||||
page,
|
||||
},
|
||||
async () => {
|
||||
const response = await page.goto(`/${user1.username}+${user2.username}`);
|
||||
expect(response?.status()).not.toBe(500);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -268,6 +268,7 @@ export const createUsersFixture = (
|
||||
opts?:
|
||||
| (CustomUserOpts & {
|
||||
organizationId?: number | null;
|
||||
overrideDefaultEventTypes?: boolean;
|
||||
})
|
||||
| null,
|
||||
scenario: {
|
||||
@@ -300,18 +301,20 @@ export const createUsersFixture = (
|
||||
},
|
||||
});
|
||||
|
||||
let defaultEventTypes: SupportedTestEventTypes[] = [
|
||||
{ title: "30 min", slug: "30-min", length: 30 },
|
||||
{ title: "Paid", slug: "paid", length: 30, price: 1000 },
|
||||
{ title: "Opt in", slug: "opt-in", requiresConfirmation: true, length: 30 },
|
||||
{ title: "Seated", slug: "seated", seatsPerTimeSlot: 2, length: 30 },
|
||||
{
|
||||
title: "Multiple duration",
|
||||
slug: "multiple-duration",
|
||||
length: 30,
|
||||
metadata: { multipleDuration: [30, 60, 90] },
|
||||
},
|
||||
];
|
||||
let defaultEventTypes: SupportedTestEventTypes[] = opts?.overrideDefaultEventTypes
|
||||
? []
|
||||
: [
|
||||
{ title: "30 min", slug: "30-min", length: 30 },
|
||||
{ title: "Paid", slug: "paid", length: 30, price: 1000 },
|
||||
{ title: "Opt in", slug: "opt-in", requiresConfirmation: true, length: 30 },
|
||||
{ title: "Seated", slug: "seated", seatsPerTimeSlot: 2, length: 30 },
|
||||
{
|
||||
title: "Multiple duration",
|
||||
slug: "multiple-duration",
|
||||
length: 30,
|
||||
metadata: { multipleDuration: [30, 60, 90] },
|
||||
},
|
||||
];
|
||||
|
||||
if (opts?.eventTypes) defaultEventTypes = defaultEventTypes.concat(opts.eventTypes);
|
||||
for (const eventTypeData of defaultEventTypes) {
|
||||
|
||||
@@ -106,7 +106,7 @@ export const getServerSideProps: GetServerSideProps<UserPageProps> = async (cont
|
||||
log.debug(safeStringify({ usersInOrgContext, isValidOrgDomain, currentOrgDomain, isDynamicGroup }));
|
||||
|
||||
if (isDynamicGroup) {
|
||||
const destinationUrl = `/${usernameList.join("+")}/dynamic`;
|
||||
const destinationUrl = encodeURI(`/${usernameList.join("+")}/dynamic`);
|
||||
|
||||
// EXAMPLE - context.params: { orgSlug: 'acme', user: 'member0+owner1' }
|
||||
// EXAMPLE - context.query: { redirect: 'undefined', orgRedirection: 'undefined', user: 'member0+owner1' }
|
||||
@@ -166,7 +166,7 @@ export const getServerSideProps: GetServerSideProps<UserPageProps> = async (cont
|
||||
return {
|
||||
redirect: {
|
||||
permanent: false,
|
||||
destination: `${urlDestination}?${urlQuery}`,
|
||||
destination: `${encodeURI(urlDestination)}?${urlQuery}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user