Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sign-up Page Functionality #202

Merged
merged 9 commits into from
Nov 23, 2023
4 changes: 4 additions & 0 deletions backend/app/rest/auth_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
InvalidPasswordException,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this needs to be addressed in this PR, but I was trying to sign up with an account that is "Invited" but clicking "Create Account" didn't do anything. I looked in the networks tab and found that the register endpoint failed with the error: "Invalid password string. Password must be a string at least 6 characters long." This could be unintuitive for the users since it didn't show an error box so they don't know that this password character limit exists.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved ; I approached this by offloading the password verification to the frontend (by simply doing a length check to verify the password is >= 6 characters long). This check is performed both in the onClick handler for createAccount and within the handlePasswordChange function (which functions the same way as the valid email error does, in which we only check for the validity of these fields after the create account button has been clicked)

TooManyLoginAttemptsException,
)
from ..utilities.exceptions.auth_exceptions import EmailAlreadyInUseException

from flask import Blueprint, current_app, jsonify, request
from twilio.rest import Client
Expand Down Expand Up @@ -188,6 +189,9 @@ def register():
**cookie_options,
)
return response, 200
except EmailAlreadyInUseException as e:
error_message = getattr(e, "message", None)
return jsonify({"error": (error_message if error_message else str(e))}), 409
except Exception as e:
error_message = getattr(e, "message", None)
return jsonify({"error": (error_message if error_message else str(e))}), 500
Expand Down
4 changes: 4 additions & 0 deletions backend/app/rest/user_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from ..services.implementations.email_service import EmailService
from ..services.implementations.user_service import UserService
from ..utilities.csv_utils import generate_csv_from_list
from ..utilities.exceptions.auth_exceptions import UserNotInvitedException


user_service = UserService(current_app.logger)
Expand Down Expand Up @@ -91,6 +92,9 @@ def get_user_status():
email = request.args.get("email")
user_status = user_service.get_user_status_by_email(email)
return jsonify({"user_status": user_status, "email": email}), 201
except UserNotInvitedException as e:
error_message = getattr(e, "message", None)
return jsonify({"error": (error_message if error_message else str(e))}), 403
except Exception as e:
error_message = getattr(e, "message", None)
return jsonify({"error": (error_message if error_message else str(e))}), 500
Expand Down
11 changes: 9 additions & 2 deletions backend/app/services/implementations/user_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
from ...models.user import User
from ...models import db
from ...resources.user_dto import UserDTO
from ...utilities.exceptions.auth_exceptions import (
UserNotInvitedException, EmailAlreadyInUseException
)


class UserService(IUserService):
Expand Down Expand Up @@ -146,7 +149,7 @@ def get_user_status_by_email(self, email):
user = User.query.filter_by(email=email).first()

if not user:
raise Exception("user with email {email} not found".format(email))
raise UserNotInvitedException

return user.user_status
except Exception as e:
Expand Down Expand Up @@ -210,7 +213,11 @@ def activate_user(self, user, auth_id=None, signup_method="PASSWORD"):
firebase_user = None

try:
if self.get_user_status_by_email(user.email) == "Invited":
cur_user_status = self.get_user_status_by_email(user.email)

if cur_user_status == "Active":
raise EmailAlreadyInUseException
if cur_user_status == "Invited":
if signup_method == "PASSWORD":
firebase_user = firebase_admin.auth.create_user(
email=user.email, password=user.password
Expand Down
17 changes: 17 additions & 0 deletions backend/app/utilities/exceptions/auth_exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class UserNotInvitedException(Exception):
"""
Raised when a user that has not been invited attempts to register
"""

def __init__(self):
self.message = "This email address has not been invited. Please try again with a different email."
super().__init__(self.message)

class EmailAlreadyInUseException(Exception):
"""
Raised when a user attempts to register with an email of a previously activated user
"""

def __init__(self):
self.message = "This email is already in use. Please try again with a different email."
super().__init__(self.message)
16 changes: 13 additions & 3 deletions frontend/src/APIClients/AuthAPIClient.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import {
FetchResult,

Check warning on line 2 in frontend/src/APIClients/AuthAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

'FetchResult' is defined but never used
MutationFunctionOptions,

Check warning on line 3 in frontend/src/APIClients/AuthAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

'MutationFunctionOptions' is defined but never used
OperationVariables,

Check warning on line 4 in frontend/src/APIClients/AuthAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

'OperationVariables' is defined but never used
} from "@apollo/client";
import { AxiosError } from "axios";
import getLoginErrMessage from "../helper/authErrorMessage";
import {

Check warning on line 7 in frontend/src/APIClients/AuthAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Replace `⏎··getAuthErrMessage⏎}·⏎` with `getAuthErrMessage·}·`
getAuthErrMessage
}
from "../helper/authError";
import AUTHENTICATED_USER_KEY from "../constants/AuthConstants";
import {
AuthenticatedUser,
Expand All @@ -29,11 +32,11 @@
);
return data;
} catch (error) {
const axiosErr = (error as any) as AxiosError;

Check warning on line 35 in frontend/src/APIClients/AuthAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Unexpected any. Specify a different type
if (axiosErr.response && axiosErr.response.status === 401) {
return {
errCode: axiosErr.response.status,
errMessage: getLoginErrMessage(axiosErr.response),
errMessage: getAuthErrMessage(axiosErr.response, 'LOGIN'),

Check warning on line 39 in frontend/src/APIClients/AuthAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Replace `'LOGIN'` with `"LOGIN"`
};
}
return {
Expand Down Expand Up @@ -99,7 +102,7 @@
lastName: string,
email: string,
password: string,
): Promise<AuthTokenResponse> => {
): Promise<AuthTokenResponse | ErrorResponse> => {
try {
const { data } = await baseAPIClient.post(
"/auth/register",
Expand All @@ -108,6 +111,13 @@
);
return data;
} catch (error) {
const axiosErr = (error as any) as AxiosError;

Check warning on line 114 in frontend/src/APIClients/AuthAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Unexpected any. Specify a different type
if (axiosErr.response && axiosErr.response.status === 409) {
return {
errCode: axiosErr.response.status,
errMessage: getAuthErrMessage(axiosErr.response, 'SIGNUP'),

Check warning on line 118 in frontend/src/APIClients/AuthAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Replace `'SIGNUP'` with `"SIGNUP"`
};
}
return null;
}
};
Expand Down
11 changes: 10 additions & 1 deletion frontend/src/APIClients/CommonAPIClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { AxiosError } from "axios";
import AUTHENTICATED_USER_KEY from "../constants/AuthConstants";
import { getLocalStorageObjProperty } from "../utils/LocalStorageUtils";
import baseAPIClient from "./BaseAPIClient";
import { ErrorResponse } from "../types/AuthTypes";

const inviteUser = async (
email: string,
Expand All @@ -19,12 +21,12 @@
{ headers: { Authorization: bearerToken } },
);
return "Success";
} catch (error: any) {

Check warning on line 24 in frontend/src/APIClients/CommonAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Unexpected any. Specify a different type
return error.message;
}
};

const getUserStatus = async (email: string): Promise<string> => {
const getUserStatus = async (email: string): Promise<string | ErrorResponse> => {

Check warning on line 29 in frontend/src/APIClients/CommonAPIClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Replace `email:·string` with `⏎··email:·string,⏎`
try {
if (email === "") {
return "";
Expand All @@ -44,6 +46,13 @@
}
return "Not invited";
} catch (error) {
const axiosErr = (error as any) as AxiosError;
if (axiosErr.response && axiosErr.response.status === 403) {
return {
errCode: axiosErr.response.status,
errMessage: axiosErr.response.data.error,
};
}
return "Not invited";
}
};
Expand Down
122 changes: 0 additions & 122 deletions frontend/src/components/auth/Signup.tsx

This file was deleted.

11 changes: 3 additions & 8 deletions frontend/src/components/forms/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { HOME_PAGE, SIGNUP_PAGE } from "../../constants/Routes";
import AuthContext from "../../contexts/AuthContext";
import { ErrorResponse, AuthTokenResponse } from "../../types/AuthTypes";
import commonApiClient from "../../APIClients/CommonAPIClient";
import { isAuthErrorResponse } from "../../helper/authError";

type CredentialsProps = {
email: string;
Expand All @@ -26,12 +27,6 @@ type CredentialsProps = {
setToggle: (toggle: boolean) => void;
};

const isLoginErrorResponse = (
res: AuthTokenResponse | ErrorResponse,
): res is ErrorResponse => {
return res !== null && "errCode" in res;
};

Comment on lines -29 to -34
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a more comprehensive version of this function isAuthErrorResponse

const Login = ({
email,
setEmail,
Expand Down Expand Up @@ -77,11 +72,11 @@ const Login = ({
const onLogInClick = async () => {
setLoginClicked(true);
const isInvited = await commonApiClient.isUserInvited(email);
if (isInvited) {
if (isInvited !== "Not Invited") {
const loginResponse:
| AuthTokenResponse
| ErrorResponse = await authAPIClient.login(email, password);
if (isLoginErrorResponse(loginResponse)) {
if (isAuthErrorResponse(loginResponse)) {
setPasswordError(true);
setPasswordErrStr(loginResponse.errMessage);
} else if (loginResponse) {
Expand Down
Loading
Loading