From 29914d3e89467878fae05c914c1434642947581d Mon Sep 17 00:00:00 2001 From: Tiago Ribeiro Date: Tue, 3 Oct 2023 23:53:54 +0100 Subject: [PATCH] Updated the register to only allow to create users if they have a code available --- src/email/templates/main.handlebars | 9 ++- src/pages/api/code.ts | 2 +- src/pages/api/register.ts | 19 ++++-- src/pages/register.tsx | 23 +++++++- src/pages/stats.tsx | 92 +++++++++++++++++++++++------ 5 files changed, 119 insertions(+), 26 deletions(-) diff --git a/src/email/templates/main.handlebars b/src/email/templates/main.handlebars index fbbcb802..4a7bb4d6 100644 --- a/src/email/templates/main.handlebars +++ b/src/email/templates/main.handlebars @@ -11,13 +11,20 @@
Hello future {{type}} of EnCoach,
- You have been invited to register at EnCoach to become a + You have been invited to register at EnCoach to + become a {{type}}!
Please use the following code when registering:
+
+
+ {{code}} + +
+
Thanks,
Your EnCoach team
diff --git a/src/pages/api/code.ts b/src/pages/api/code.ts index 8457d8a6..3eea2e4d 100644 --- a/src/pages/api/code.ts +++ b/src/pages/api/code.ts @@ -28,7 +28,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { } const codePromises = codes.map(async (code, index) => { - const codeRef = doc(db, "codes", uuidv4()); + const codeRef = doc(db, "codes", code); await setDoc(codeRef, {type, code}); if (emails && emails.length > index) { diff --git a/src/pages/api/register.ts b/src/pages/api/register.ts index 34468ca8..71fb07cd 100644 --- a/src/pages/api/register.ts +++ b/src/pages/api/register.ts @@ -3,8 +3,8 @@ import {createUserWithEmailAndPassword, getAuth, sendPasswordResetEmail} from "f import {app} from "@/firebase"; import {sessionOptions} from "@/lib/session"; import {withIronSessionApiRoute} from "iron-session/next"; -import {getFirestore, getDoc, doc, setDoc} from "firebase/firestore"; -import {DemographicInformation} from "@/interfaces/user"; +import {getFirestore, getDoc, doc, setDoc, deleteDoc} from "firebase/firestore"; +import {DemographicInformation, Type} from "@/interfaces/user"; const auth = getAuth(app); const db = getFirestore(app); @@ -26,7 +26,15 @@ const DEFAULT_LEVELS = { }; async function login(req: NextApiRequest, res: NextApiResponse) { - const {email, password} = req.body as {email: string; password: string; demographicInformation: DemographicInformation}; + const {email, password, code} = req.body as {email: string; password: string; code: string; demographicInformation: DemographicInformation}; + + const codeRef = await getDoc(doc(db, "codes", code)); + if (!codeRef.exists()) { + res.status(400).json({error: "Invalid Code!"}); + return; + } + + const codeData = codeRef.data() as {code: string; type: Type}; createUserWithEmailAndPassword(auth, email, password) .then(async (userCredentials) => { @@ -38,12 +46,13 @@ async function login(req: NextApiRequest, res: NextApiResponse) { desiredLevels: DEFAULT_DESIRED_LEVELS, levels: DEFAULT_LEVELS, bio: "", - isFirstLogin: true, + isFirstLogin: codeData.type === "student", focus: "academic", - type: "student", + type: codeData.type, }; await setDoc(doc(db, "users", userId), user); + await deleteDoc(codeRef.ref); req.session.user = {...user, id: userId}; await req.session.save(); diff --git a/src/pages/register.tsx b/src/pages/register.tsx index d27a4c09..2995add0 100644 --- a/src/pages/register.tsx +++ b/src/pages/register.tsx @@ -11,12 +11,23 @@ import axios from "axios"; import {Divider} from "primereact/divider"; import {useRouter} from "next/router"; import clsx from "clsx"; +import {NextPageContext} from "next"; +import {NextRequest, NextResponse} from "next/server"; -export default function Register() { +export const getServerSideProps = (context: any) => { + const {code} = context.query; + + return { + props: {code}, + }; +}; + +export default function Register({code: queryCode}: {code: string}) { const [name, setName] = useState(""); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); + const [code, setCode] = useState(queryCode || ""); const [isLoading, setIsLoading] = useState(false); const router = useRouter(); @@ -40,6 +51,7 @@ export default function Register() { name, email, password, + code, profilePicture: "/defaultAvatar.png", }) .then((response) => { @@ -52,6 +64,12 @@ export default function Register() { toast.error("There is already a user with that e-mail!"); return; } + + if (error.response.status === 400) { + toast.error("The provided code is invalid!"); + return; + } + toast.error("There was something wrong, please try again!"); }) .finally(() => setIsLoading(false)); @@ -95,10 +113,11 @@ export default function Register() { defaultValue={confirmPassword} required /> + setCode(e)} placeholder="Enter your registration code" defaultValue={code} required /> diff --git a/src/pages/stats.tsx b/src/pages/stats.tsx index 5074c4f4..23e0ffef 100644 --- a/src/pages/stats.tsx +++ b/src/pages/stats.tsx @@ -19,6 +19,8 @@ import {Chart} from "react-chartjs-2"; import useUsers from "@/hooks/useUsers"; import Select from "react-select"; import useGroups from "@/hooks/useGroups"; +import DatePicker from "react-datepicker"; +import moment from "moment"; ChartJS.register(LinearScale, CategoryScale, PointElement, LineElement, LineController, Legend, Tooltip); @@ -45,6 +47,8 @@ export const getServerSideProps = withIronSessionSsr(({req, res}) => { export default function Stats() { const [statsUserId, setStatsUserId] = useState(); + const [startDate, setStartDate] = useState(null); + const [endDate, setEndDate] = useState(new Date()); const {user} = useUser({redirectTo: "/login"}); const {users} = useUsers(); @@ -56,6 +60,17 @@ export default function Stats() { if (user) setStatsUserId(user.id); }, [user]); + useEffect(() => { + if (stats && stats.length > 0) { + const sortedStats = stats.sort((a, b) => a.date - b.date); + const firstStat = sortedStats.shift()!; + + setStartDate(moment.unix(firstStat.date).toDate()); + console.log(stats.filter((x) => moment.unix(x.date).isAfter(startDate))); + console.log(stats.filter((x) => moment.unix(x.date).isBefore(endDate))); + } + }, [stats]); + const calculateTotalScorePerSession = () => { const groupedBySession = groupBySession(stats); const sessionAverage = Object.keys(groupedBySession).map((x: string) => { @@ -160,22 +175,53 @@ export default function Stats() { {stats.length > 0 && (
- {(user.type === "developer" || user.type === "owner") && ( - ({value: x.id, label: `${x.name} - ${x.email}`}))} + defaultValue={{value: user.id, label: `${user.name} - ${user.email}`}} + onChange={(value) => setStatsUserId(value?.value)} + styles={{ + option: (styles, state) => ({ + ...styles, + backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white", + color: state.isFocused ? "black" : styles.color, + }), + }} + /> + )} + {(user.type === "admin" || user.type === "teacher") && groups.length > 0 && ( + groups.flatMap((y) => y.participants).includes(x.id)) - .map((x) => ({value: x.id, label: `${x.name} - ${x.email}`}))} - defaultValue={{value: user.id, label: `${user.name} - ${user.email}`}} - onChange={(value) => setStatsUserId(value?.value)} - /> - )} +
{/* Exams per module */}
@@ -319,7 +365,13 @@ export default function Stats() { index), + labels: Object.keys( + groupBySession( + stats.filter( + (x) => moment.unix(x.date).isAfter(startDate) && moment.unix(x.date).isBefore(endDate), + ), + ), + ).map((_, index) => index), datasets: [ { type: "line", @@ -342,7 +394,13 @@ export default function Stats() { index), + labels: Object.keys( + groupBySession( + stats.filter( + (x) => moment.unix(x.date).isAfter(startDate) && moment.unix(x.date).isBefore(endDate), + ), + ), + ).map((_, index) => index), datasets: [ ...MODULE_ARRAY.map((module, index) => ({ type: "line" as const,