def login() -> Response:
    """Authenticate the user with successful credentials.
    
    Returns
    -------
    Response
        If the user credentials match, return an authenticated response
        containing the user's token.
    """
    needed = ['username', 'password']
    if all([key in request.data for key in needed]):
        user = get_user(request.data['username'])
        if not user or not hasher.verify(request.data['password'],
                                         user.password):
            response = jsonify(
                {'error': 'The username/password combination is invalid.'})
            response.status_code = status.HTTP_400_BAD_REQUEST
            return response

        response = jsonify(user.to_json())
        response.status_code = status.HTTP_200_OK
        return authenticate(response, user=user)

    response = jsonify({'error': 'Some fields are missing'})
    response.status_code = status.HTTP_400_BAD_REQUEST
    return response
def verify_token(token: str) -> bool:
    """Verify that the incoming request has the expected token."""
    if token:
        username, user_token = token.split(':')
        user = get_user(username)
        return user_token == user.token
    return False
def delete_account(username: str) -> Response:
    """Deletes a user account given the corresponding username.
    
    Parameters
    ----------
    username : str
        The username corresponding to the account to be deleted

    Returns
    -------
    Response
        If the user trying to delete an account is not the account owner,
        the Response will have a status of 401 Unauthorized. Otherwise,
        the Response will be an unauthenticated 204 No Content.
    """
    user = get_user(username)
    if not user:
        response = jsonify({'error': 'This user does not exist.'})
        response.status_code = status.HTTP_404_NOT_FOUND
        return response

    if not verify_user(username):
        response = jsonify(
            {'error': 'User is not authorized to make this request'})
        repsonse.status_code = status.HTTP_401_UNAUTHORIZED
        return response

    db.session.delete(user)
    db.session.commit()

    response = Response()
    response.status_code = status.HTTP_204_NO_CONTENT
    return response
def authenticate_account(username: str) -> Response:
    """Retrieve account details after verifying request credentials.
    
    Parameters
    ----------
    username : str
        The username of the requested account

    Returns
    -------
    Response
        The details of the user account in JSON format. 
    """
    user = get_user(username)
    return jsonify(user.to_json())
def register_user() -> Response:
    """Add a new user if it doesn't already exist.
    
    Given the appropriate user information, create a new user object.
    If that user already exists, return an error (409 Conflict). If the
    information is itself incomplete, return an error (400 Bad Request).
    Although the password matching should be checked on the client side, check
    here, and if they don't match return an error (417 Expectation Failed).

    Returns
    -------
    Response
        An authenticated Response object containing the new user's information
        on a successful user registration. On a failed one, contains the 
        right status as well as the reason for failure.
    """
    needed = ['username', 'password', 'password2']
    if all([key in request.data for key in needed]):
        user = get_user(request.data['username'])

        if user:
            response = jsonify({'error': 'User already exists'})
            response.status_code = status.HTTP_400_BAD_REQUEST
            return response

        if request.data['password'] != request.data['password2']:
            response = jsonify({'error': "Passwords don't match"})
            response.status_code = status.HTTP_400_BAD_REQUEST
            return response

        new_user = User(username=request.data['username'],
                        password=request.data['password'])

        db.session.add(new_user)
        db.session.commit()

        response = jsonify(new_user.to_json())
        response.status_code = status.HTTP_201_CREATED
        return authenticate(response, user=new_user)

    response = jsonify({'error': 'Some fields are missing'})
    response.status_code = status.HTTP_400_BAD_REQUEST
    return response
def get_account(username: str) -> Response:
    """Retrieve details for a given user account.
    
    Parameters
    ----------
    username : str
        The username of the requested account

    Returns
    -------
    Response
        The details of the user account in JSON format.
    """
    user = get_user(username)
    if not user:
        response = jsonify({'error': 'This user does not exist.'})
        response.status_code = status.HTTP_404_NOT_FOUND
        return response

    return jsonify(user.to_json())
def update_account(username: str) -> Response:
    """Update the user's account with new information.
    
    Submit new information to be added to the user account. Can be used to
    update the user's password as well.

    Parameters
    ----------
    username : str
        The username for the user's account
    
    Returns
    -------
    Response
        The response body will contain the updated user information as it
        exists within the database
    """
    user = get_user(username)
    if not user:
        response = jsonify({'error': 'This user does not exist.'})
        response.status_code = status.HTTP_404_NOT_FOUND
        return response

    if not verify_user(username):
        response = jsonify(
            {'error': 'User is not authorized to make this request'})
        response.status_code = status.HTTP_401_UNAUTHORIZED
        return response

    if get_user(request.data.get('username')):
        response = jsonify({'error': 'Username already exists'})
        response.status_code = status.HTTP_403_FORBIDDEN
        return response

    user.username = request.data.get('username', user.username)
    user.bio = request.data.get('bio', user.bio)

    if "new_password" in request.data:
        old_pass = request.data["password"]
        new_pass = request.data["new_password"]
        new_pass_match = request.data["new_password2"]

        verify_pass = hasher.verify(old_pass, user.password)
        passwords_match = new_pass == new_pass_match

        if verify_pass and passwords_match:
            user.password = hasher.hash(new_pass)

        elif not verify_pass:
            response = jsonify({'error': "Old password is invalid"})
            response.status_code = status.HTTP_403_FORBIDDEN
            return response

        else:
            response = jsonify({'error': "New password isn't matched"})
            response.status_code = status.HTTP_400_BAD_REQUEST
            return response

    user.last_updated = datetime.datetime.utcnow()

    db.session.add(user)
    db.session.commit()

    response = jsonify(user.to_json())
    response.status_code = status.HTTP_200_OK
    return authenticate(response, user)