Beispiel #1
0
def update_user(admin, user_id):
    """
    Update the user with the given id.

    :param admin:   Is the administrator user, determined by @adminRequired.
    :param user_id: Is the user id.

    :return:        A message that the update was successful and a list of all updated fields.
    """
    # Get the update data
    data = json_body()

    # Query the user. If he/she is not verified yet, there *must* be a
    # rank_id given in the update data.
    user = User.query.filter(User.id == user_id).first()
    if not user:
        raise exc.EntryNotFound()

    if not user.is_verified and 'rank_id' not in data:
        raise exc.UserIsNotVerified()

    # The password pre-check must be done here...
    if 'password' in data:
        # The repeat password must be there, too!
        if 'password_repeat' not in data:
            raise exc.DataIsMissing()

        # Both must be strings
        if not all([isinstance(x, str) for x in [data['password'], data['password_repeat']]]):
            raise exc.WrongType()

        # Passwords must match
        if data['password'] != data['password_repeat']:
            raise exc.PasswordsDoNotMatch()

        # Minimum password length
        if len(data['password']) < app.config['MINIMUM_PASSWORD_LENGTH']:
            raise exc.PasswordTooShort()

        # Convert the password into a salted hash
        # DONT YOU DARE TO REMOVE THIS LINE
        data['password'] = bcrypt.generate_password_hash(data['password'])
        # DONT YOU DARE TO REMOVE THIS LINE

        # All fine, delete repeat_password from the dict and do the rest of the update
        del data['password_repeat']

    return generic_update(User, user_id, data, admin)
Beispiel #2
0
def parse_timestamp(data: dict, required: bool) -> dict:
    """
    Parses a timestamp in a input dictionary. If there is no timestamp and it's not required, nothing happens.
    Otherwise an exception gets raised. If a timestamp exists, it gets parsed.

    :param data:       The input dictionary
    :param required:   Flag whether the timestamp is required.
    :return:           The parsed input dictionary.
    """
    # If the timestamp is missing but it is required, raise an exception.
    # Otherwise return the (non-modified) input data.
    if 'timestamp' not in data:
        if required:
            raise exc.DataIsMissing()
        else:
            return data

    # Get the timestamp
    timestamp = data.get('timestamp')

    # If the timestamp is not a string, raise an exception
    if not isinstance(timestamp, str):
        raise exc.WrongType()

    # Catch empty string timestamp which is caused by some JS date pickers
    # inputs when they get cleared. If the timestamp is required, raise an exception.
    if timestamp == '':
        if required:
            raise exc.DataIsMissing()
        else:
            del data['timestamp']
            return data
    else:
        try:
            timestamp = dateutil.parser.parse(data['timestamp'])
            assert isinstance(timestamp, datetime.datetime)
            assert timestamp < datetime.datetime.now(datetime.timezone.utc)
            data['timestamp'] = timestamp.replace(microsecond=0)
        except (TypeError, ValueError, AssertionError):
            raise exc.InvalidData()

    return data
Beispiel #3
0
def get_product_pricehistory(admin, product_id):
    """
    Returns the pricehistory of the product with the given id. If only want to
    query a part of the history in a range there are optional request arguments:
    - start_date:          Is the unix timestamp of the start date.
    - end_date:            Is the unix timestamp of the end date.

    :param admin:          Is the administrator user, determined by
                           @adminRequired.
    :param product_id:     Is the product id.

    :raises EntryNotFound: If the product does not exist.
    :raises WrongType:     If the request args are invalid.

    :return:               The pricehistory of the product.
    """

    # Check, whether the product exists.
    product = Product.query.filter(Product.id == product_id).first()
    if not product:
        raise exc.EntryNotFound()

    # Get the (optional) time range parameters
    try:
        start = request.args.get('start_date')
        if start:
            start = int(start)
        end = request.args.get('end_date')
        if end:
            end = int(end)
    except (TypeError, ValueError):
        raise exc.WrongType()

    # Check whether start lies before end date
    if start and end:
        if not start <= end:
            raise exc.InvalidData()

    history = product.get_pricehistory(start, end)

    return jsonify(history), 200
Beispiel #4
0
def check_allowed_parameters(allowed):
    """
    This method checks all GET parameters for their type.

    :param allowed:               A dictionary containing all allowed parameters
                                  and types.

    :return:                      A dictionary with all converted and checked
                                  parameters.

    :raises UnauthorizedAccess:   If there's an illegal parameter in the data.
    :raises WrongType:            If an argument is of the wrong type.
    """
    result = {}
    if any([argument not in allowed for argument in request.args]):
        raise exc.UnauthorizedAccess()

    for key in request.args:
        try:
            result[key] = allowed[key](request.args.get(key))
        except ValueError:
            raise exc.WrongType()

    return result
Beispiel #5
0
def check_fields_and_types(data, required, optional=None):
    """
    This function checks the given data for its types and existence.
    Required fields must exist, optional fields must not.

    :param data:            The data sent to the API.
    :param required:        A dictionary with all required entries and their
                            types.
    :param optional:        A dictionary with all optional entries and their
                            types.

    :return:                None

    :raises DataIsMissing:  If a required field is not in the data.
    :raises WrongType:      If a field is of the wrong type.
    """

    if required and optional:
        allowed = dict(**required, **optional)
    elif required:
        allowed = required
    else:
        allowed = optional

    # Check if there is an unknown field in the data
    if not all(x in allowed for x in data):
        raise exc.UnknownField()

    # Check whether all required data is available
    if required and any(item not in data for item in required):
        raise exc.DataIsMissing()

    # Check all data (including optional data) for their types
    for key, value in data.items():
        if not isinstance(value, allowed.get(key)):
            raise exc.WrongType()