Ejemplo n.º 1
0
def user_post() -> Response:
    """
    Create a new user.
    :return: A response object for the POST API request.
    """
    user_data: dict = request.get_json()

    def create_validation_error_response(message: str):
        """
        Reusable 400 HTTP error response for the users POST request.
        :param message: Message sent in the response JSON's 'error' field.
        :return: An HTTP response object.
        """
        error_response = jsonify({
            'self': f'/v2/users',
            'added': False,
            'user': None,
            'error': message
        })
        error_response.status_code = 400
        return error_response

    if user_data is None:
        return create_validation_error_response(
            "The request body isn't populated.")

    user_to_add = User(user_data)

    if None in [
            user_to_add.username, user_to_add.first, user_to_add.last,
            user_to_add.password, user_to_add.activation_code,
            user_to_add.email
    ]:
        return create_validation_error_response(
            "'username', 'first', 'last', 'email', 'password', and 'activation_code' are required fields"
        )

    if len(user_to_add.password) < 6:
        return create_validation_error_response(
            "Password must contain at least 6 characters.")

    username_pattern = re.compile('^[a-zA-Z0-9]+$')

    if not username_pattern.match(user_to_add.username):
        return create_validation_error_response(
            "Username can only contain Roman characters and numbers.")

    email_pattern = re.compile(
        '^(([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+\\.([a-zA-Z])+([a-zA-Z])+)?$')

    if not email_pattern.match(user_to_add.email):
        return create_validation_error_response(
            "The email address is invalid.")

    # Passwords must be hashed before stored in the database
    password = user_to_add.password
    hashed_password = flask_bcrypt.generate_password_hash(password).decode(
        'utf-8')
    user_to_add.password = hashed_password

    activation_code_count = CodeDao.get_code_count(
        activation_code=user_to_add.activation_code)

    if activation_code_count == 1:
        now = datetime.now()
        user_to_add.member_since = now.date()
        user_to_add.created_date = now
        user_to_add.last_signin = now
        user_to_add.created_app = 'saints-xctf-api'
        user_to_add.created_user = None
        user_to_add.modified_date = None
        user_to_add.modified_app = None
        user_to_add.modified_user = None
        user_to_add.deleted_date = None
        user_to_add.deleted_app = None
        user_to_add.deleted_user = None
        user_to_add.deleted = False

        # First, add the user since its activation code is valid.
        UserDao.add_user(user_to_add)

        # Second, set the initial team and group for the user.
        code: Code = ActivationCodeDao.get_activation_code(
            user_to_add.activation_code)

        initial_group_id = int(code.group_id)
        initial_group: Group = GroupDao.get_group_by_id(initial_group_id)
        initial_team: Team = TeamDao.get_team_by_group_id(initial_group_id)

        TeamMemberDao.set_initial_membership(
            username=user_to_add.username,
            team_name=initial_team.name,
            group_id=initial_group_id,
            group_name=initial_group.group_name)

        # Third, remove the activation code so it cant be used again.
        CodeDao.remove_code(code)

        added_user = UserDao.get_user_by_username(user_to_add.username)

        if added_user is None:
            response = jsonify({
                'self':
                '/v2/users',
                'added':
                False,
                'user':
                None,
                'error':
                'An unexpected error occurred creating the user.'
            })
            response.status_code = 500
            return response
        else:
            response = jsonify({
                'self': '/v2/users',
                'added': True,
                'user': UserData(added_user).__dict__,
                'new_user': f'/v2/users/{added_user.username}'
            })
            response.status_code = 201
            return response
    else:
        current_app.logger.error(
            'Failed to create new User: The Activation Code does not exist.')
        response = jsonify({
            'self':
            '/v2/users',
            'added':
            False,
            'user':
            None,
            'error':
            'The activation code is invalid or expired.'
        })
        response.status_code = 400
        return response