Repository: freeCodeCamp/freeCodeCamp
File: api/src/routes/settings.ts (TypeScript)

Code before:
        void reply.code(400);
        return {
          type: 'info',
          message: `${newEmail} is already associated with this account.
You can update a new email address instead.`
        } as const;
      }

      const isResendUpdateToSameEmail =
        newEmail === user.newEmail?.toLowerCase();
      const isLinkSentWithinLimit = getWaitMessage(user.emailVerifyTTL);

      if (isResendUpdateToSameEmail && isLinkSentWithinLimit) {
        void reply.code(429);
        return {
          type: 'info',
          message: `We have already sent an email confirmation request to ${newEmail}.
${isLinkSentWithinLimit}`
        } as const;
      }

      const isEmailAlreadyTaken =
        (await fastify.prisma.user.count({ where: { email: newEmail } })) > 0;

      if (isEmailAlreadyTaken && !isOwnEmail) {
        void reply.code(400);
        return {
          type: 'info',
          message: `${newEmail} is already associated with another account.`
        } as const;
      }

      try {
        await fastify.prisma.user.update({
          where: { id: req.session.user.id },
          data: {
            newEmail,
            emailVerified: false,
            emailVerifyTTL: new Date()
          }
        });

        // TODO: combine emailVerifyTTL and emailAuthLinkTTL? I'm not sure why
        // we need emailVeriftyTTL given that the main thing we want is to
        // restrict the rate of attempts and the emailAuthLinkTTL already does
        // that.
        const tooManyRequestsMessage = getWaitMessage(user.emailAuthLinkTTL);

        if (tooManyRequestsMessage) {
          void reply.code(429);
          return {

Review comment (suggestion):
```suggestion
      const isLinkSentWithinLimitTTL = getWaitMessage(user.emailVerifyTTL);
```

Code after:
      const user = await fastify.prisma.user.findUniqueOrThrow({
        where: { id: req.session.user.id },
        select: {
          email: true,
          emailVerifyTTL: true,
          newEmail: true,
          emailVerified: true,
          emailAuthLinkTTL: true
        }
      });
      const newEmail = req.body.email.toLowerCase();
      const currentEmailFormatted = user.email.toLowerCase();
      const isVerifiedEmail = user.emailVerified;
      const isOwnEmail = newEmail === currentEmailFormatted;
      if (isOwnEmail && isVerifiedEmail) {
        void reply.code(400);
        return {
          type: 'info',
          message: `${newEmail} is already associated with this account.
You can update a new email address instead.`
        } as const;
      }

      const isResendUpdateToSameEmail =
        newEmail === user.newEmail?.toLowerCase();
      const isLinkSentWithinLimitTTL = getWaitMessage(user.emailVerifyTTL);

      if (isResendUpdateToSameEmail && isLinkSentWithinLimitTTL) {
        void reply.code(429);
        return {
          type: 'info',
          message: `We have already sent an email confirmation request to ${newEmail}.
${isLinkSentWithinLimitTTL}`
        } as const;
      }

      const isEmailAlreadyTaken =
        (await fastify.prisma.user.count({ where: { email: newEmail } })) > 0;

      if (isEmailAlreadyTaken && !isOwnEmail) {
        void reply.code(400);
        return {
          type: 'info',
          message: `${newEmail} is already associated with another account.`
        } as const;
      }

      // ToDo(MVP): email the new email and wait user to confirm it, before we update the user schema.
      try {
        await fastify.prisma.user.update({
          where: { id: req.session.user.id },