Esempio n. 1
0
def cancel_email_change(user_id):
    """Cancels any attempts to update the user's email address.

    Args:
        user_id: The id of the user who wants to cancel their email update.

    Returns:
        204 no content.
    """

    # Find the user who is confirming their email address
    user = User.query.filter_by(id=user_id).first()

    if user is None:
        # Return 404 if this user doesn't exist
        return errors.user_not_found()

    if user.pending_email and user.email == user.pending_email:
        # Return 400 if the user is trying to cancel their first email verification
        return errors.must_confirm_email()

    # Remove all verification attempts for this user
    EmailVerification.query.filter_by(user_id=user.id).delete()

    # Remove the user's pending email address
    user.pending_email = None
    db.session.commit()

    return ("", 204)
Esempio n. 2
0
def resend_confirmation_email(user_id):
    """Resends a confirmation email used to verify a user's email address.

    Args:
        user_id: The user whose id needs the new confirmation email.

    Returns:
        204 no content.
    """

    # Find the user who is confirming their email address
    user = User.query.filter_by(id=user_id).first()

    if user is None:
        # Return 404 if this user doesn't exist
        return errors.user_not_found()

    if not user.pending_email:
        # Return 400 if there is no email address the user needs to confirm
        return errors.no_pending_email()

    # Add an email verification object to the database, to be deleted when the
    # user clicks the link in their email
    verification = EmailVerification(user.id, user.pending_email)
    db.session.add(verification)
    db.session.commit()

    # Send the verification email
    send(Email.VERIFY_EMAIL, user, verification)

    return ("", 204)
Esempio n. 3
0
def get_user(user_id):
    """Retrieves data for a user. Some data is omitted or included depending on
    the permissions of the person requesting the data.

    Args:
        user_id: The id of the user whose data is being requested.

    Returns:
        The JSON data for this user.
    """

    # Find user in the SQL database
    user = User.query.filter_by(id=user_id).first()

    # Return 404 if there is no user with this id
    if user is None:
        return errors.user_not_found()

    # full = Should the user's full data be returned. False if sensitive data
    # should be omitted.
    full = False

    # Check if anyone is currently authenticated
    if current_user.is_active:
        # Sensitive data should be returned if the user is requesting his/her
        # own data or if the requester is an admin
        if current_user.id == int(user_id) or current_user.is_admin:
            full = True

    # Return the user's JSON data
    return jsonify(user.serialize(full))
Esempio n. 4
0
def update_password(user_id):
    """Updates a user's password.

    Args:
        user_id: The id of the user who is updating their password.

    Body:
        current_password: The user's current password.
        new_password: The password the user would like to change it to.

    Returns:
        The user's JSON data.
    """

    # Check that all necessary data is in the request body
    if not check_body(["current_password", "new_password"]):
        return errors.missing_password_update_parameters()

    current_password = request.json["current_password"]
    new_password = request.json["new_password"]

    # Retrieve the user who is being updated
    user = User.query.filter_by(id=user_id).first()

    if user is None:
        # Return 404 if this user doesn't exist
        return errors.user_not_found()
    elif user.id != current_user.id:
        # Only the authenticated user can update their password
        return errors.not_authorized()

    # Use bcrypt to check if the current password is correct
    current_password_is_correct = bcrypt.checkpw(
        current_password.encode("utf-8"), user.password.encode("utf-8"))

    # Return 400 if the current password is incorrect
    if not current_password_is_correct:
        return errors.incorrect_password()

    # Ensure that this password can be used
    password_error = validate_password(new_password,
                                       [user.username, user.email])
    if password_error is not None:
        return password_error

    # Hash the new password, this is what will be stored in MySQL
    hashed_password = bcrypt.hashpw(new_password.encode("utf-8"),
                                    bcrypt.gensalt())

    # Make the update to this user and save to MySQL
    user.password = hashed_password
    db.session.commit()

    # Return this user's JSON data
    return get_user(user.id)
Esempio n. 5
0
def update_user(user_id):
    """Updates a user's settings.

    Args:
        user_id: The id of the user whose settings are being updated.

    Body:
        section: The settings section that is being updated.
        data: The new settings data for the specified section.

    Returns:
        The JSON data for the user whose settings have been updated.
    """

    # Check that all necessary data is in the request body
    if not check_body(["section", "data"]):
        return errors.missing_update_parameters()

    section = request.json["section"]
    data = request.json["data"]

    # Retrieve the user who is being updated
    user = User.query.filter_by(id=user_id).first()

    if user is None:
        # Return 404 if this user doesn't exist
        return errors.user_not_found()
    elif user.id != current_user.id and not current_user.is_admin:
        # Only the authenticated user and admins can update a user's settings
        return errors.not_authorized()

    # Get the settings that need to be updated
    settings = user.get_settings()

    if section not in settings:
        # Ensure that the settings section is valid
        return errors.invalid_settings_section()
    elif section == "profile":
        # Handle username correctly if the profile section is being updated
        if "username" in data and data["username"] != user.username:
            username = data["username"]

            # Ensure that this username can be used
            username_error = validate_username(username)
            if username_error is not None:
                return username_error

            # Set the user's new username
            user.username = username

        # Handle email correctly if the profile section is being updated
        if "email" in data and data["email"] != user.email:
            email = data["email"]

            # Ensure that this email address can be used
            email_error = validate_email(email)

            if email_error is not None:
                return email_error

            # Set the user's new email address
            user.pending_email = email

            # Add an email verification object to the database, to be deleted
            # when the user clicks the link in their inbox
            verification = EmailVerification(user.id, email)
            db.session.add(verification)
            db.session.commit()

            # Send the verification email
            send(Email.VERIFY_EMAIL, user, verification)

        settings[section] = {
            "first_name": data["first_name"],
            "last_name": data["last_name"]
        }
    else:
        # Just set the data for this section for all other sections
        settings[section] = data

    # Update the user's settings in MySQL
    user.settings = json.dumps(settings)
    db.session.commit()

    # Return this user's JSON data
    return get_user(user.id)