* feat: add toggle to opt out of booking title translation in instant meetings (#25547) * feat: add toggle to opt out of booking title translation in instant meetings Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: add autoTranslateTitleEnabled to test builder Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: respect autoTranslateTitleEnabled toggle in InstantBookingCreateService Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: fetch autoTranslateTitleEnabled directly in InstantBookingCreateService Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * refactor: rename autoTranslateTitleEnabled to autoTranslateInstantMeetingTitleEnabled - Renamed field to clarify it only applies to instant meeting title translation - Moved Prisma query to EventTypeRepository.findInstantMeetingConfigById() - Removed title translation logic from update.handler.ts (flag only controls instant meeting title) - Updated all references across the codebase - Added new i18n translation keys for the renamed field Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: add autoTranslateInstantMeetingTitleEnabled to test destructuring patterns Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: use Prisma.TeamCreateInput type for metadata in test helper Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: add autoTranslateInstantMeetingTitleEnabled to mockUpdatedEventType in test Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * refactor: use generic findByIdMinimal instead of business-specific method - Add autoTranslateInstantMeetingTitleEnabled to eventTypeSelect constant - Remove findInstantMeetingConfigById from EventTypeRepository - Update InstantBookingCreateService to use findByIdMinimal Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * refactor: remove autoTranslateInstantMeetingTitleEnabled from eventTypeSelect (not needed for findByIdMinimal) Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * feat: add autoTranslateInstantMeetingTitleEnabled to event type form defaults - Rename shouldTranslateTitle to shouldAutoTranslateInstantMeetingTitle for clarity - Add autoTranslateInstantMeetingTitleEnabled to findById and findByIdForOrgAdmin selects - Add autoTranslateInstantMeetingTitleEnabled to useEventTypeForm defaultValues Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: only update autoTranslateInstantMeetingTitleEnabled when explicitly provided Fixes issue where omitting the field in update requests would overwrite the saved opt-out setting with the default value (true). Now the field is only included in the update payload when explicitly provided. Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * chore: Create standard for rate limits --------- Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
50 lines
1.8 KiB
TypeScript
50 lines
1.8 KiB
TypeScript
import { defaultResponderForAppDir } from "app/api/defaultResponderForAppDir";
|
|
import { parseRequestData } from "app/api/parseRequestData";
|
|
import type { NextRequest } from "next/server";
|
|
import { NextResponse } from "next/server";
|
|
|
|
import { passwordResetRequest } from "@calcom/features/auth/lib/passwordResetRequest";
|
|
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
|
|
import { emailSchema } from "@calcom/lib/emailSchema";
|
|
import prisma from "@calcom/prisma";
|
|
import { piiHasher } from "@calcom/lib/server/PiiHasher";
|
|
|
|
async function handler(req: NextRequest) {
|
|
const body = await parseRequestData(req);
|
|
const email = emailSchema.transform((val) => val.toLowerCase()).safeParse(body?.email);
|
|
|
|
if (!email.success) {
|
|
return NextResponse.json({ message: "email is required" }, { status: 400 });
|
|
}
|
|
|
|
// fallback to email if ip is not present
|
|
let ip = (req.headers.get("x-real-ip") as string) ?? email.data;
|
|
|
|
const forwardedFor = req.headers.get("x-forwarded-for") as string;
|
|
if (!ip && forwardedFor) {
|
|
ip = forwardedFor?.split(",").at(0) ?? email.data;
|
|
}
|
|
|
|
// 10 requests per minute
|
|
|
|
await checkRateLimitAndThrowError({
|
|
rateLimitingType: "core",
|
|
identifier: `forgotPassword:${piiHasher.hash(ip)}`,
|
|
});
|
|
|
|
try {
|
|
const user = await prisma.user.findUnique({
|
|
where: { email: email.data },
|
|
select: { name: true, email: true, locale: true },
|
|
});
|
|
// Don't leak info about whether the user exists
|
|
if (user) passwordResetRequest(user).catch(console.error);
|
|
return NextResponse.json({ message: "password_reset_email_sent" }, { status: 201 });
|
|
} catch (reason) {
|
|
console.error(reason);
|
|
return NextResponse.json({ message: "Unable to create password reset request" }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
export const POST = defaultResponderForAppDir(handler);
|