From 2db03bd5a942f1698382ab054273ad9dd156496c Mon Sep 17 00:00:00 2001 From: Sky Singh <114267538+Akash-Singh04@users.noreply.github.com> Date: Mon, 19 Aug 2024 11:43:18 +0530 Subject: [PATCH] Revert "fix: Add Google reCAPTCHA to SIH Registration Form and Recruitment Form" --- .../api/registration/recruitment/route.ts | 49 ++- app/(default)/api/registration/sih/route.ts | 115 +++---- components/forms/reCaptcha.tsx | 33 ++ components/forms/recruitmentForm.tsx | 54 +-- components/forms/sihForm.tsx | 308 ++++++++---------- lib/constants/dropdownOptions.ts | 43 +-- lib/types/global.d.ts | 12 + lib/utils.ts | 4 +- package-lock.json | 24 -- package.json | 3 +- tsconfig.json | 1 + 11 files changed, 300 insertions(+), 346 deletions(-) create mode 100644 components/forms/reCaptcha.tsx create mode 100644 lib/types/global.d.ts diff --git a/app/(default)/api/registration/recruitment/route.ts b/app/(default)/api/registration/recruitment/route.ts index 9dbd9ec..94175db 100644 --- a/app/(default)/api/registration/recruitment/route.ts +++ b/app/(default)/api/registration/recruitment/route.ts @@ -4,35 +4,48 @@ import { addDoc, collection, getDocs } from "firebase/firestore"; import { NextResponse } from "next/server"; // Verify reCAPTCHA Token +async function verifyRecaptcha(token: string) { + const secretKey = process.env.RECAPTCHA_SECRET_KEY; + const response = await fetch( + `https://www.google.com/recaptcha/api/siteverify`, + { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: new URLSearchParams({ + secret: secretKey || "", + response: token, + }), + } + ); + const data = await response.json(); + return data.success; +} // Add a new registration export async function POST(request: Request) { - const formData = await request.json(); - const { recaptcha_token, ...data } = formData; - const recaptchaToken = recaptcha_token; - if (!recaptchaToken) { - throw new Error("Token not found!"); - } - const recaptchaSecretKey = process.env.RECAPTCHA_SECRET_KEY; + const data = await request.json(); + const recaptchaToken = data.recaptchaToken; // Extract the reCAPTCHA token from the request - // Verify reCAPTCHA token - const recaptchaResponse = await fetch( - `https://www.google.com/recaptcha/api/siteverify?secret=${recaptchaSecretKey}&response=${recaptchaToken}`, - { method: "POST" } - ); - const recaptchaResult = await recaptchaResponse.json(); - console.log(data); - console.log(recaptchaResult); - if (!recaptchaResult.success) { + // Verify the reCAPTCHA token + const isRecaptchaValid = await verifyRecaptcha(recaptchaToken); + + if (!isRecaptchaValid) { return NextResponse.json({ - message: "reCAPTCHA validation failed", - error: recaptchaResult["error-codes"], + message: "reCAPTCHA verification failed", + error: true, }); } // Validate the data const val = recruitValidate(data); + if (!Array.isArray(data)) { + return NextResponse.json({ + message: "Expected an array of JSON objects", + error: true, + }); + } + if (val.error) { return NextResponse.json({ message: "Validation error", error: val.error }); } diff --git a/app/(default)/api/registration/sih/route.ts b/app/(default)/api/registration/sih/route.ts index dcc91c8..b368caa 100644 --- a/app/(default)/api/registration/sih/route.ts +++ b/app/(default)/api/registration/sih/route.ts @@ -1,62 +1,67 @@ -import { db } from "@/Firebase"; -import { sihValidate } from "@/lib/utils"; -import { addDoc, collection, getDocs } from "firebase/firestore"; -import { NextResponse } from "next/server"; +import { db } from '@/Firebase'; +import { sihValidate } from '@/lib/utils'; +import { addDoc, collection, getDocs } from 'firebase/firestore'; +import { NextResponse } from 'next/server'; + + +// Verify reCAPTCHA Token +// async function verifyRecaptcha(token: string) { +// const secretKey = process.env.RECAPTCHA_SECRET_KEY; +// const response = await fetch(`https://www.google.com/recaptcha/api/siteverify`, { +// method: 'POST', +// headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, +// body: new URLSearchParams({ +// secret: secretKey || '', +// response: token, +// }), +// }); +// const data = await response.json(); +// return data.success; +// } + // Add a new registration export async function POST(request: Request) { - const formData = await request.json(); - const { recaptcha_token, ...data } = formData; - const recaptchaToken = recaptcha_token; - if (!recaptchaToken) { - throw new Error("Token not found!"); - } - const recaptchaSecretKey = process.env.RECAPTCHA_SECRET_KEY; - - // Verify reCAPTCHA token - const recaptchaResponse = await fetch( - `https://www.google.com/recaptcha/api/siteverify?secret=${recaptchaSecretKey}&response=${recaptchaToken}`, - { method: "POST" } - ); - const recaptchaResult = await recaptchaResponse.json(); - console.log(data); - console.log(recaptchaResult); - if (!recaptchaResult.success) { - return NextResponse.json({ - message: "reCAPTCHA validation failed", - error: recaptchaResult["error-codes"], - }); - } - - // Validate the data - const val = sihValidate(data); - - if (val.error) { - return NextResponse.json({ message: "Validation error", error: val.error }); - } - - try { - // Save to Firebase - const docRef = await addDoc(collection(db, "sih2024"), data); - console.log("Document written with ID: ", docRef.id); - } catch (error) { - console.error(error); - return NextResponse.json({ message: "An error occurred", error }); - } - // Return a response - return NextResponse.json({ message: "Registration successful", data }); + const data = await request.json(); + const recaptchaToken = data.recaptchaToken; // Extract the reCAPTCHA token from the request + + // Verify the reCAPTCHA token + // const isRecaptchaValid = await verifyRecaptcha(recaptchaToken); + + // if (!isRecaptchaValid) { + // return NextResponse.json({ message: 'reCAPTCHA verification failed', error: true }); + // } + + // Validate the data + const val = sihValidate(data); + + if (val.error) { + return NextResponse.json({ message: 'Validation error', error: val.error }); + } + + try { + console.log('Data:', data); + // Save to Firebase + const docRef = await addDoc(collection(db, "sih2024"), data); + console.log("Document written with ID: ", docRef.id); + } catch (error) { + console.error(error); + return NextResponse.json({ message: 'An error occurred', error }); + } + // Return a response + return NextResponse.json({ message: 'Registration successful', data }); } //get all registrations export async function GET() { - try { - // Get all registrations in sih2024 collection - const querySnapshot = await getDocs(collection(db, "sih2024")); - // Map the data to get only the data - const data = querySnapshot.docs.map((doc) => doc.data()); - return NextResponse.json({ data }); - } catch (error) { - console.error(error); - return NextResponse.json({ message: "An error occurred", error }); - } -} + try { + // Get all registrations in sih2024 collection + const querySnapshot = await getDocs(collection(db, "sih2024")); + // Map the data to get only the data + const data = querySnapshot.docs.map((doc) => doc.data()); + return NextResponse.json({ data }); + } catch (error) { + console.error(error); + return NextResponse.json({ message: 'An error occurred', error }); + } +} \ No newline at end of file diff --git a/components/forms/reCaptcha.tsx b/components/forms/reCaptcha.tsx new file mode 100644 index 0000000..d6381cf --- /dev/null +++ b/components/forms/reCaptcha.tsx @@ -0,0 +1,33 @@ +import { useEffect } from "react"; + +const Recaptcha = ({ onChange }: { onChange: (token: string | null) => void }) => { + useEffect(() => { + const loadRecaptcha = () => { + if (window.grecaptcha) { + window.grecaptcha.ready(() => { + window.grecaptcha.execute(process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY || '', { action: 'submit' }).then((token: string) => { + onChange(token); + }); + }); + } + }; + + const script = document.createElement("script"); + script.src = `https://www.google.com/recaptcha/api.js?render=${process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY}`; + script.async = true; + script.defer = true; + script.onload = loadRecaptcha; + document.head.appendChild(script); + + return () => { + document.head.removeChild(script); + }; + }, [onChange]); + + return null; +}; + +export default Recaptcha; + + + diff --git a/components/forms/recruitmentForm.tsx b/components/forms/recruitmentForm.tsx index e1c8cf3..7f997a5 100644 --- a/components/forms/recruitmentForm.tsx +++ b/components/forms/recruitmentForm.tsx @@ -1,28 +1,17 @@ "use client"; import "../../app/css/additional-styles/utility-patterns.css"; import "../../app/css/additional-styles/theme.css"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import { useForm, SubmitHandler } from "react-hook-form"; import { years, branches } from "@/lib/constants/dropdownOptions"; -import { - GoogleReCaptchaProvider, - GoogleReCaptcha, -} from "react-google-recaptcha-v3"; -import toast from "react-hot-toast"; +import Recaptcha from "./reCaptcha"; const RecruitmentForm: React.FC = () => { const [isSuccess, setSuccess] = useState(false); const [mode, setMode] = useState(false); const [display, setDisplay] = useState(false); - const [token, setToken] = useState(""); - const [refreshReCaptcha, setRefreshReCaptcha] = useState(false); + const [recaptchaToken, setRecaptchaToken] = useState(null); - useEffect(() => { - const script = document.createElement("script"); - script.src = `https://www.google.com/recaptcha/api.js?render=your_site_key`; - script.async = true; - document.body.appendChild(script); - }, []); const { register, handleSubmit, @@ -40,32 +29,31 @@ const RecruitmentForm: React.FC = () => { }); const changeMode = (e: any) => { + console.log(e.target.value); if (e.target.value === "1st year") setMode(true); else setMode(false); setDisplay(true); }; - const setTokenFunc = (getToken: string) => { - setToken(getToken); - }; - const onSubmit: SubmitHandler = async (data: any) => { - try { - data.recaptcha_token = token; + if (!recaptchaToken) { + alert("Please complete the reCAPTCHA"); + return; + } - const response = await fetch("/api/registration/recruitment", { + + try { + let response = await fetch("/api/registration/recruitment", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }); - const res = await response.json(); - - if (!res.error) { + if (response.status == 200) { setSuccess(true); } + response = await response.json(); } catch (error) { - setRefreshReCaptcha(!refreshReCaptcha); - console.log("Error submitting form:", error); + console.error("Error submitting form:", error); } }; @@ -318,24 +306,14 @@ const RecruitmentForm: React.FC = () => { )} + + - - - diff --git a/components/forms/sihForm.tsx b/components/forms/sihForm.tsx index 2ad0199..e150ab8 100644 --- a/components/forms/sihForm.tsx +++ b/components/forms/sihForm.tsx @@ -5,8 +5,7 @@ import { useEffect, useState } from "react"; import Accordion from "./accordion"; import { useForm, SubmitHandler } from "react-hook-form"; import { useFormContext } from "../forms/formContext"; -import toast, { Toaster } from "react-hot-toast"; - +import Recaptcha from "./reCaptcha"; import { years, courses, @@ -14,28 +13,22 @@ import { problems, } from "@/lib/constants/dropdownOptions"; import { useRouter } from "next/navigation"; -import { - GoogleReCaptcha, - GoogleReCaptchaProvider, -} from "react-google-recaptcha-v3"; +import { onAuthStateChanged } from "firebase/auth"; +import { auth } from "@/Firebase"; const SIHMultiStepForm: React.FC = () => { const { formData, setFormData } = useFormContext(); const [step, setStep] = useState(1); const [isSuccess, setSuccess] = useState(false); - const [token, setToken] = useState(""); - const [refreshReCaptcha, setRefreshReCaptcha] = useState(false); - - const setTokenFunc = (getToken: string) => { - setToken(getToken); - }; - + const [recaptchaToken, setRecaptchaToken] = useState(null); + const router = useRouter(); useEffect(() => { - const script = document.createElement("script"); - script.src = `https://www.google.com/recaptcha/api.js?render=your_site_key`; - script.async = true; - document.body.appendChild(script); - }, []); + onAuthStateChanged(auth, (user) => { + if (!user) { + router.push("/login"); + } + }); + }); const { register, @@ -44,25 +37,28 @@ const SIHMultiStepForm: React.FC = () => { } = useForm({ defaultValues: formData, }); - const onSubmit: SubmitHandler = async (data: any) => { - data.recaptcha_token = token; + const onSubmit: SubmitHandler = async (data : any) => { + setFormData({ ...formData, ...data }); if (step < 3) { setStep(step + 1); console.log(step); } else { + if (!recaptchaToken) { + alert("Please complete the reCAPTCHA"); + return; + } + try { - const response = await fetch("/api/registration/sih", { + let response = await fetch("/api/registration/sih", { method: "POST", body: JSON.stringify(data), }); - const res = await response.json(); - if (!res.error) { + if (response.status == 200) { setSuccess(true); } + response = await response.json(); } catch (error) { - toast.error(`Error submitting form: ${error}`); - setRefreshReCaptcha(!refreshReCaptcha); console.error("Error submitting form:", error); } } @@ -183,7 +179,7 @@ const SIHMultiStepForm: React.FC = () => {
{
- - - {errors.team_info?.team_leader?.role && ( -

- {errors.team_info.team_leader.role.message} -

- )} -
+ + + {errors.team_info?.team_leader?.role && ( +

+ {errors.team_info.team_leader.role.message} +

+ )} + -
- - - {errors.team_info?.team_leader?.enrollment_id && ( -

- {errors.team_info.team_leader.enrollment_id.message} -

- )} -
+
+ + + {errors.team_info?.team_leader?.enrollment_id && ( +

+ {errors.team_info.team_leader.enrollment_id.message} +

+ )} +
-
- - - {course} - - ))} - - {errors.team_info?.team_leader?.course && ( -

- {errors.team_info.team_leader.course.message} -

- )} -
+ {courses.map((course) => ( + + ))} + + {errors.team_info?.team_leader?.course && ( +

+ {errors.team_info.team_leader.course.message} +

+ )} + -
- - - {year} - - ))} - - {errors.team_info?.team_leader?.year_of_study && ( -

- {errors.team_info.team_leader.year_of_study.message} -

- )} -
+ {years.map((year) => ( + + ))} + + {errors.team_info?.team_leader?.year_of_study && ( +

+ {errors.team_info.team_leader.year_of_study.message} +

+ )} + -
- - - {branch} - - ))} - - {errors.team_info?.team_leader?.branch && ( -

- {errors.team_info.team_leader.branch.message} -

- )} -
+ {branches.map((branch) => ( + + ))} + + {errors.team_info?.team_leader?.branch && ( +

+ {errors.team_info.team_leader.branch.message} +

+ )} + + +