Esempio n. 1
0
def get_performer_available_time(curr_id):
    v = Validator(purge_unknown=True)
    schema = {
        'service_id': {
            'required': True,
            'coerce': int
        },
        'coordx': {
            'required': True,
            'coerce': float
        },
        'coordy': {
            'required': True,
            'coerce': float
        },
        'date': {
            'required': True,
            'coerce': lambda x: parse(x).date()
        }
    }
    req_data = v.validated(request.args.to_dict(), schema)
    if not req_data:
        abort(400, v.errors)
    return jsonify([[str(x[0]), str(x[1])]
                    for x in calc_vacant_hours(perf_id=curr_id,
                                               serv_id=req_data['service_id'],
                                               coord=(req_data['coordx'],
                                                      req_data['coordy']),
                                               xdate=req_data['date'])]), 200
Esempio n. 2
0
def linode_action_input_validated(schema, definition, args):
    from cerberus import Validator
    from json import dumps

    log.vvvvv('linode_action_input_validated(%s): %s' %
              (definition, str(args)))

    v = Validator(
        schema=schema.get(definition),
        purge_unknown=True,
    )

    normalized = v.normalized(args)

    log.vvvvv('linode_action_input_validated(%s): normalized %s' %
              (definition, str(normalized)))

    if not v.validate(normalized):
        for err in dumps(v.errors, indent=2).split("\n"):
            log.warning('linode_action_input_validated(%s): %s' %
                        (definition, err))
        raise AnsibleError('while validating %s got errors: %s' %
                           (definition, str(v.errors)))

    validated = v.validated(args)

    log.vvv('linode_action_input_validated(%s): validated %s' %
            (definition, str(validated)))

    return validated
Esempio n. 3
0
def business_schedule_get():
    v = Validator(purge_unknown=True)
    schema = {
        'service_id': {
            'default': None,
            'coerce': lambda x: int(x) if x else x,
            'nullable': True
        },
        'performer_id': {
            'default': None,
            'coerce': lambda x: int(x) if x else x,
            'nullable': True
        },
        'date': {
            'default': None,
            'coerce': lambda x: parse(x) if x else x,
            'nullable': True
        }
    }
    req_data = v.validated(request.args.to_dict(), schema)
    if not req_data:
        abort(400, v.errors)
    business = db.session.query(Business).filter(
        Business.user_id == get_jwt_claims()['id']).first()
    perf_id = req_data['performer_id']
    if perf_id and Performer.get(perf_id).business_id != business.id:
        abort(403)
    serv_id = req_data['service_id']
    if serv_id and Service.get(serv_id).business_id != business.id:
        abort(403)
    return jsonify(get_schedule(business_id=business.id, kwargs=req_data)), 200
Esempio n. 4
0
def register():
    v = Validator(purge_unknown=True)
    schema = {
        'email': {
            'type': 'string',
            'required': True
            # 'regex': REGEX_EMAIL
        },
        'password': {
            'required': True,
            'type': 'string'
        },
        'role': {
            'type': 'string',
            'required': True,
            'allowed': ['user', 'business']
        }
    }
    req_data = v.validated(request.get_json(), schema)
    if not req_data:
        abort(400, v.errors)
    user = db.session.query(User).filter(
        User.email == req_data['email']).first()
    if user:
        return jsonify({"msg": "User already exists"}), 422
    user = User(email=req_data['email'], role=req_data['role'])
    db.session.add(user)
    user.set_password(req_data['password'])
    db.session.commit()
    return jsonify({"msg": "Mr Bee flies around"}), 200
Esempio n. 5
0
def create_business():
    v = Validator(purge_unknown=True)
    schema = {
        'name': {
            'type': 'string',
            'required': True
        },
        'phone': {
            'type': 'string',
            'required': True
            # 'regex': REGEX_PHONE
        },
        'address': {
            'type': 'string'
        }
    }
    req_data = v.validated(request.get_json(), schema)
    if not req_data:
        abort(400, v.errors)
    business = db.session.query(Business).filter(
        Business.name == req_data['name']).first()
    if business:
        return jsonify({"msg": "Business already exists"}), 400
    business = Business(user_id=get_jwt_claims()['id'])
    return add(business, req_data)
Esempio n. 6
0
    def post(self):
        us = ServiceLocator.resolve(ServiceLocator.USERS)

        v = Validator(check_params_schema)
        args = v.validated(request.get_json())

        if args is None:
            return ApiResponse(status=4001, errors=v.errors)

        try:
            login = args.get('login', None)
            email = args.get('email', None)

            login_result = login and us.check_login(login)
            email_result = email and us.check_email(email)

            return {
                'login': login_result,
                'email': email_result
            }

        except Exception as ex:
            error(u'UsersCheckAPI.post', ex)

            return {
                'login': None,
                'email': None
            }
Esempio n. 7
0
    def post(self):
        us = ServiceLocator.resolve(ServiceLocator.USERS)
        ss = ServiceLocator.resolve(ServiceLocator.SESSIONS)

        v = Validator(user_signin_schema)

        args = v.validated(request.get_json())
        if args is None:
            return ApiResponse(status=4001, errors=v.errors)

        login = args.get(u'login')
        password = args.get(u'password')

        user = us.sign_in(login, password)
        if user is None:
            return ApiResponse(status=4001, errors=errors.SignErrors.login_or_password_wrong(['login', 'password']))

        token = us.make_auth_token(user)

        # Save the user to session
        ss.create(user, token)

        user[u'auth_token'] = token

        return user
Esempio n. 8
0
    def validate(self, config_dict):
        """Validates the mode using its relevant configuration dict

        Returns a validated configuration dict with the mode filled in. If no mode is given in the input
        dict, a default mode will be filled in if availble. If the mode has a validation_schema, it will
        be used to validate the input dict. If any error is encountered during the process, A serializer
        ValidationError will be raised with the error.

        Args:
            config_dict (dict): A dictionary of input structure that this mode is a part of
        Returns:
            dict: A version of the input dictionary with defaults filled in based on the validation_schema
        Raises:
            serializers.ValidationError: If validation fails
        """
        mode_value = self._get_mode_from_config_dict(config_dict)
        if not mode_value:
            mode_value = self.get_default_mode()
            if not mode_value:
                return config_dict
        if not self.mode_exists(mode_value):
            return config_dict
        config_dict = self._set_mode_in_config_dict(mode_value, config_dict)
        mode = configdb.get_mode_with_code(self._instrument_type, mode_value,
                                           self._mode_type)
        validation_schema = mode.get('validation_schema', {})
        validator = Validator(validation_schema)
        validator.allow_unknown = True
        validated_config_dict = validator.validated(
            config_dict) or config_dict.copy()
        if validator.errors:
            raise serializers.ValidationError(
                _(f'{self._mode_type.capitalize()} mode {mode_value} requirements are not met: {cerberus_validation_error_to_str(validator.errors)}'
                  ))
        return validated_config_dict
Esempio n. 9
0
    def post(self):
        u"""
        Creates new card and adds it to group.
        :return: Card
        """

        v = Validator(card_schema)
        args = v.validated(request.get_json())

        if args is None:
            return ApiResponse(status=4001, errors=v.errors)

        foreign = args.get(u'foreign')
        native = args.get(u'native')
        group_id = args.get(u'group_id')

        transcription = args.get(u'transcription', u'')
        context = args.get(u'context', u'')

        user = self.ss.get_user()
        group = self.gs.single(group_id, user)

        exists_card = self.cs.exists(user, foreign, user.foreign_lng)
        if exists_card:
            return ApiResponse(status=409, errors=CardsErrors.card_already_exists(foreign, [u'foreign']))

        card = self.cs.create(user, group, foreign, native, transcription, context)
        if card is None:
            return ApiResponse(status=500, errors=ServerErrors.internal_server_error([]))

        return card
Esempio n. 10
0
def flexio_handler(flex):

    # get the input
    input = flex.input.read()
    input = json.loads(input)
    if not isinstance(input, list):
        input = []

    # define the expected parameters and map the values to the parameter names
    # based on the positions of the keys/values
    params = OrderedDict()
    params['properties'] = {'required': False, 'validator': validator_list, 'coerce': to_list, 'default': '*'}
    params['filter'] = {'required': False, 'type': 'string', 'default': ''} # placeholder to match form of index-styled functions
    params['config'] = {'required': False, 'type': 'string', 'default': ''} # index-styled config string
    input = dict(zip(params.keys(), input))

    # validate the mapped input against the validator
    v = Validator(params, allow_unknown = True)
    params = v.validated(input)
    if params is None:
        raise ValueError

    # get the properties to return and the property map;
    # if we have a wildcard, get all the properties
    properties = [p.lower().strip() for p in params['properties']]
    if len(properties) == 1 and (properties[0] == '' or properties[0] == '*'):
        properties = list(get_item_info({}).keys())

    # get any configuration settings
    config = urllib.parse.parse_qs(params['config'])
    config = {k: v[0] for k, v in config.items()}
    limit = int(config.get('limit', 100))
    if limit >= 1000:
        limit = 1000
    headers = config.get('headers', 'true').lower()
    if headers == 'true':
        headers = True
    else:
        headers = False

    # write the output
    flex.output.content_type = 'application/json'
    flex.output.write('[')

    first_row = True
    if headers is True:
        result = json.dumps(properties)
        first_row = False
        flex.output.write(result)

    for item in get_data(params, limit):
        result = json.dumps([(item.get(p) or '') for p in properties])
        if first_row is False:
            result = ',' + result
        first_row = False
        flex.output.write(result)

    flex.output.write(']')
Esempio n. 11
0
def flexio_handler(flex):

    # get the input
    input = flex.input.read()
    input = json.loads(input)
    if not isinstance(input, list):
        raise ValueError

    # define the expected parameters and map the values to the parameter names
    # based on the positions of the keys/values
    params = OrderedDict()
    params['urls'] = {
        'required': True,
        'validator': validator_list,
        'coerce': to_list
    }
    #params['columns'] = {'required': True, 'validator': validator_list, 'coerce': to_list}
    input = dict(zip(params.keys(), input))

    # validate the mapped input against the validator
    v = Validator(params, allow_unknown=True)
    input = v.validated(input)
    if input is None:
        raise ValueError

    urls = input['urls']
    loop = asyncio.get_event_loop()
    temp_fp_all = loop.run_until_complete(fetch_all(urls))

    flex.output.content_type = 'application/json'
    flex.output.write('[')

    # get the columns for each of the input urls
    properties = []
    for temp_fp in temp_fp_all:
        try:
            fp = io.TextIOWrapper(temp_fp, encoding='utf-8-sig')
            reader = csv.DictReader(fp, delimiter=',', quotechar='"')
            for row in reader:
                properties = list(row.keys())
                break
        finally:
            fp.seek(0)
            fp.detach()

    flex.output.write(json.dumps(properties))

    for temp_fp in temp_fp_all:
        fp = io.TextIOWrapper(temp_fp, encoding='utf-8-sig')
        reader = csv.DictReader(fp, delimiter=',', quotechar='"')
        for row in reader:
            row = ',' + json.dumps([(row.get(p) or '') for p in properties])
            flex.output.write(row)
        temp_fp.close()

    flex.output.write(']')
Esempio n. 12
0
def flexio_handler(flex):

    # get the input
    input = flex.input.read()
    try:
        input = json.loads(input)
        if not isinstance(input, list): raise ValueError
    except ValueError:
        raise ValueError

    # define the expected parameters and map the values to the parameter names
    # based on the positions of the keys/values
    params = OrderedDict()
    params['urls'] = {'required': True, 'validator': validator_list, 'coerce': to_list}
    params['search'] = {'required': True, 'type': 'string'}
    params['properties'] = {'required': False, 'validator': validator_list, 'coerce': to_list, 'default': '*'}
    input = dict(zip(params.keys(), input))

    # validate the mapped input against the validator
    v = Validator(params, allow_unknown = True)
    input = v.validated(input)
    if input is None:
        raise ValueError

    # get the urls to process
    search_urls = input['urls']
    search_urls = [s.strip() for s in search_urls]

    # get the search term to use to find the corresponding links
    search_text = input['search']
    search_text = " ".join(search_text.split()).lower().strip() # remove leading/trailing/duplicate spaces and convert to lowercase

    # get the properties to return and the property map
    property_map = OrderedDict()
    property_map['domain'] = 'domain'
    property_map['link'] = 'link'
    property_map['text'] = 'text'
    properties = [p.lower().strip() for p in input['properties']]

    # if we have a wildcard, get all the properties
    if len(properties) == 1 and properties[0] == '*':
        properties = list(property_map.keys())

    loop = asyncio.get_event_loop()
    result = loop.run_until_complete(fetch_all(search_urls, search_text, properties))

    # if we don't have any results, return an empty result
    if len(result) == 0:
        result = [['']]

    # return the results
    result = json.dumps(result, default=to_string)
    flex.output.content_type = "application/json"
    flex.output.write(result)
Esempio n. 13
0
def update_service(curr_id):
    v = Validator(purge_unknown=True)
    schema = {
        'name': {
            'type': 'string'
        },
        'price': {
            'type': 'float'
        },
        'description': {
            'type': 'string'
        },
        'duration': {
            'coerce':
            lambda x: timedelta(hours=parse(x).hour, minutes=parse(x).minute),
        },
        'performers': {
            'type': 'list'
        }
    }
    req_data = v.validated(request.get_json(), schema)
    if not req_data:
        abort(400, v.errors)
    service = Service.get(curr_id)
    if not service:
        return jsonify(
            {"msg": "{0} doesn't exist".format(type(service).__name__)}), 400
    if 'performers' in req_data.keys():
        old_performers = set(map(lambda x: x.id, service.performers))
        new_performers = set(req_data['performers'])
        to_remove = old_performers.difference(new_performers)
        to_add = new_performers.difference(old_performers)
        try:
            if len(to_remove):
                db.session.execute(performer_service.delete().where(
                    and_(performer_service.c.service_id == curr_id,
                         performer_service.c.performer_id.in_(to_remove))))
            if len(to_add):
                db.session.execute(performer_service.insert(),
                                   [{
                                       'performer_id': x,
                                       'service_id': curr_id
                                   } for x in to_add])
        except:
            db.session.rollback()
            return jsonify({"msg":
                            "Probably performers parameter is invalid"}), 400
    return update(
        service,
        {key: req_data[key]
         for key in req_data if key != 'performers'})
Esempio n. 14
0
def validate_schema(schema_id, data):
    """
    Generic schema validation function.

    :param str schema_id: Name of the schema to validate against.
    :param dict data: Data to validate.

    :return: A tuple of a dictionary with validated and coersed data and the
     validation errors found, if any.
    :rtype: tuple
    """
    validator = Validator(SCHEMAS[schema_id])
    validated = validator.validated(data)
    return validated, validator.errors
Esempio n. 15
0
def create_service():
    v = Validator(purge_unknown=True)
    schema = {
        'name': {
            'type': 'string',
            'required': True
        },
        'price': {
            'coerce': float,
            'required': True
        },
        'description': {
            'type': 'string',
            'required': True
        },
        'duration': {
            'required':
            True,
            'coerce':
            lambda x: timedelta(hours=parse(x).hour, minutes=parse(x).minute)
        },
        'performers': {
            'type': 'list'
        }
    }
    req_data = v.validated(request.get_json(), schema)
    if not req_data:
        abort(400, v.errors)
    service = db.session.query(Service).filter(
        Service.name == req_data['name']).first()
    if service:
        return jsonify({"msg": "Service already exists"}), 400
    service = Service(business_id=Business.get(get_jwt_claims()['id']).id)
    msg = add(service,
              {key: req_data[key]
               for key in req_data if key != 'performers'})
    try:
        if 'performers' in req_data.keys() and len(req_data['performers']) > 0:
            db.session.execute(performer_service.insert(),
                               [{
                                   'performer_id': x,
                                   'service_id': service.id
                               } for x in req_data['performers']])
            db.session.commit()
    except:
        db.session.rollback()
        return jsonify({"msg":
                        "Probably performers parameter is invalid"}), 400
    return msg
Esempio n. 16
0
def validated_method_example():
    """validated能返回验证后的document, 下面的代码给出了一种对输入的数据流进行处理的例子。
    """
    schema = {"value": {"type": "number"}}
    v = Validator(schema)
    
    documents = [
        {"value": 1},
        {"value": [1, 2, 3]},
        {"value": 2},
        ]
    valid_documents = [x for x in [v.validated(y) for y in documents] if x is not None]
    print(valid_documents)
    
# validated_method_example()
Esempio n. 17
0
def create_appointment():
    v = Validator(purge_unknown=True)
    schema = {
        'service_id': {
            'coerce': int,
            'required': True
        },
        'performer_id': {
            'coerce': int,
            'required': True
        },
        'date': {
            'coerce': lambda x: parse(x).isoformat(),
            'required': True
        },
        'user_id': {
            'coerce': lambda x: int(x) if x else None,
            'default': None,
            'nullable': True
        },
        'notes': {
            'type': 'string'
        },
        'coordx': {
            'type': 'float'
        },
        'coordy': {
            'type': 'float'
        }
    }
    req_data = v.validated(request.get_json(), schema)
    if not req_data:
        abort(400, v.errors)
    user_id = get_jwt_claims()['id']
    if get_jwt_claims()['role'] == 'business':
        business = db.session.query(Business).filter(
            Business.user_id == user_id).first()
        if business.id != Performer.get(req_data['performer_id']).business_id:
            abort(403)
        if business.id != Service.get(req_data['service_id']).business_id:
            abort(403)
        user_id = req_data['user_id']
    appointment = Appointment(user_id=user_id, is_confirmed=False)
    return add(appointment,
               {key: req_data[key]
                for key in req_data if key != 'user_id'})
Esempio n. 18
0
def flexio_handler(flex):

    # get the input
    input = flex.input.read()
    try:
        input = json.loads(input)
        if not isinstance(input, list): raise ValueError
    except ValueError:
        raise ValueError

    # define the expected parameters and map the values to the parameter names
    # based on the positions of the keys/values
    params = OrderedDict()
    params['cur'] = {
        'required': True,
        'validator': validate_currency,
        'coerce': lambda s: s.upper()
    }
    params['date'] = {'required': False, 'type': 'date', 'coerce': to_date}
    input = dict(zip(params.keys(), input))

    # validate the mapped input against the validator
    # if the input is valid return an error
    v = Validator(params, allow_unknown=True)
    input = v.validated(input)
    if input is None:
        raise ValueError

    date = 'latest'
    if 'date' in input.keys():
        date = input['date'].strftime('%Y-%m-%d')

    url = 'https://api.exchangeratesapi.io/' + date + '?base=' + input['cur']
    response = requests_retry_session().get(url)
    rates = response.json()['rates']

    items = list()
    for currency, amount in rates.items():
        items.append([currency, amount])
    items = sorted(items, key=itemgetter(0))

    result = [['currency', 'amount']]
    result.extend(items)

    flex.output.content_type = "application/json"
    flex.output.write(result)
Esempio n. 19
0
def update_appointment(curr_id):
    v = Validator(purge_unknown=True)
    schema = {
        'service_id': {
            'coerce': int,
        },
        'performer_id': {
            'coerce': int,
        },
        'date': {
            'coerce': lambda x: parse(x).isoformat(),
        },
        'notes': {
            'type': 'string'
        },
        'coordx': {
            'type': 'float'
        },
        'coordy': {
            'type': 'float'
        }
    }
    req_data = v.validated(request.get_json(), schema)
    if not req_data:
        abort(400, v.errors)
    user_id = get_jwt_claims()['id']
    appointment = Appointment.get(curr_id)
    if not appointment:
        abort(404)
    if get_jwt_claims()['role'] == 'user':
        if appointment.user.id != user_id:
            abort(403)
    else:
        business = appointment.service.business
        if business.id != db.session.query(Business).filter(
                Business.user_id == user_id).first().id:
            abort(403)
        if 'performer_id' in req_data.keys():
            if business.id != Performer.get(
                    req_data['performer_id']).business_id:
                abort(403)
        if 'service_id' in req_data.keys():
            if business.id != Service.get(req_data['service_id']).business_id:
                abort(403)
    return update(appointment, req_data)
Esempio n. 20
0
    def post(self):
        """

        :return:
        """

        v = Validator(translation_schema)
        args = v.validated(request.get_json())

        if args is None:
            return ApiResponse(status=4001, errors=v.errors)

        text = args.get(u'text')
        lang = self.ts.detect(text)

        return {
            u'lang': lang
        }
Esempio n. 21
0
def update_business():
    v = Validator(purge_unknown=True)
    schema = {
        'name': {
            'type': 'string'
        },
        'phone': {
            'type': 'string'
            # 'regex': REGEX_PHONE
        },
        'address': {
            'type': 'string'
        }
    }
    req_data = v.validated(request.get_json(), schema)
    if not req_data:
        abort(400, v.errors)
    return update(Business.get(get_jwt_claims()['id']), req_data)
Esempio n. 22
0
    def post(self):
        us = ServiceLocator.resolve(ServiceLocator.USERS)
        ss = ServiceLocator.resolve(ServiceLocator.SESSIONS)

        v = Validator(user_schema)
        args = v.validated(request.get_json())

        if args is None:
            return ApiResponse(status=4001, errors=v.errors)

        login = args.get('login')
        email = args.get('email')
        password = args.get('password')

        first_name = args.get('first_name', '')
        last_name = args.get('last_name', '')

        try:
            us.check(login, email)

            user = us.create(login, email, password, first_name=first_name, last_name=last_name)

            # Create session
            token = us.make_auth_token(user)
            ss.create(user, token)

            user['auth_token'] = token

            return user
        except LoginAlreadyExists as ex:
            error(u'UserService.signup({0})'.format(login), ex)

            return ApiResponse(status=4001, errors=errors.SignErrors.login_already_exists(['login']))
        except EmailAlreadyExists as ex:
            error(u'UserService.signup({0})'.format(email), ex)

            return ApiResponse(status=4001, errors=errors.SignErrors.email_already_exists(['email']))
        except Exception as ex:
            error(u'UserSignUpAPI -> us.create({0})'.format(login), ex)

            return ApiResponse(status=500, errors=errors.ServerErrors.internal_server_error([]))
Esempio n. 23
0
def login():
    v = Validator(purge_unknown=True)
    schema = {
        'email': {
            'type': 'string',
            'required': True
            # 'regex': REGEX_EMAIL
        },
        'password': {
            'required': True,
            'type': 'string'
        }
    }
    req_data = v.validated(request.get_json(), schema)
    if not req_data:
        abort(400, v.errors)
    user = User.query.filter(User.email == req_data['email']).first()
    if not (user and user.check_password(req_data['password'])):
        return jsonify({"msg": "Failed to log in"}), 401
    access_token = create_access_token(identity=user.id)
    return jsonify(access_token=access_token), 200
Esempio n. 24
0
    def post(self):
        """
        Translate text
        :return:
        """

        v = Validator(translation_schema)
        args = v.validated(request.get_json())

        if args is None:
            return ApiResponse(status=4001, errors=v.errors)

        text = args.get(u'text')
        user = self.ss.get_user()

        try:
            translation = self.ts.translate(text, user.direction)
            return translation
        except Exception as ex:
            error(u'TranslationsAPI.post(text={0}, dir={1})'.format(text, user.direction), ex)

            return ApiResponse(status=500, errors=ServerErrors.internal_server_error([]))
Esempio n. 25
0
    def patch(self, card_id):
        u"""
        Update card entity
        :param card_id: card's id
        :return: updated card
        """

        v = Validator(card_schema)
        args = v.validated(request.get_json())

        if args is None:
            return ApiResponse(status=4001, errors=v.errors)

        user = self.ss.get_user()

        card = self.cs.get(user, ObjectId(card_id))
        if card is None:
            return ApiResponse(status=404, errors=CardsErrors.card_dont_exists([]))

        foreign = args.get(u'foreign')
        native = args.get(u'native')
        transcription = args.get(u'transcription', card.transcription)
        context = args.get(u'context', card.foreign_context)

        duplicate_card = self.cs.single(user, foreign, user.foreign_lng)
        if duplicate_card.id != card.id:
            return ApiResponse(status=409, errors=CardsErrors.card_already_exists(foreign, [u'foreign']))

        try:
            card.foreign = foreign
            card.native = native
            card.transcription = transcription
            card.context = context

            card.save()
        except Exception as ex:
            error(u'CardApi.patch(card_id={0})'.format(card_id), ex)

            return ApiResponse(status=500, errors=ServerErrors.internal_server_error([]))
Esempio n. 26
0
def normalize_and_validate(dict_to_check, schema):
    # type: (dict, dict) -> (dict)
    """Normalize and validate a dictionary, will raise if invalid

    Args:
        dict_to_check(dict): dictionary to check
        schema(dict): schema to use

    Returns:
        dict: Normalized and valid dictionary

    Raises:
        SchemaMisMatch:

    """

    c_validator = Validator(schema, allow_unknown=True)
    valid_dict = c_validator.validated(dict_to_check, normalize=True)
    if valid_dict is None:
        raise SchemaMisMatch(c_validator.errors)

    return valid_dict
Esempio n. 27
0
def normalize_validate_config(config_data, strict_validation=False):
    """
    Normalize and validate endpoints
    :param config_data: dictionary with endpoints
    :param strict_validation: whether to fail in the case of bad configuration entry
    :return: dictionary with normalized and validated endpoints
    """
    validated_config_data = dict()
    v = Validator(endpoint_schema)
    error_str = None
    error_list = list()

    for endpoint_key, endpoint_value in config_data.items():
        normalized_item = v.normalized(endpoint_value)
        validated_endpoint = v.validated(normalized_item)
        if validated_endpoint is None:
            error_str = "Schema failed to validate for endpoint {0}, removing it. Errors: {1}".format(
                endpoint_key, json.dumps(v.errors, indent=2, sort_keys=True))
            error_list.append(error_str)
            logger.error(error_str)
        else:
            validated_config_data[endpoint_key] = validated_endpoint

    logger.debug("Original configuration:")
    for k, v in config_data.items():
        logger.debug("{0}: {1}".format(k,
                                       json.dumps(v, indent=2,
                                                  sort_keys=True)))
    logger.debug("Normalized configuration:")
    for k, v in validated_config_data.items():
        logger.debug("{0}: {1}".format(k,
                                       json.dumps(v, indent=2,
                                                  sort_keys=True)))

    if strict_validation and len(error_list) > 0:
        raise InvalidConfigurationError("\n".join(error_list))

    return validated_config_data
Esempio n. 28
0
    def post(self):
        """
        Translate text
        :return:
        """

        v = Validator(picture_schema)
        args = v.validated(request.get_json())

        if args is None:
            return ApiResponse(status=4001, errors=v.errors)

        text = args.get(u'text')

        try:
            picture = self.ps.get(text)
            if picture:
                return picture

            return self.ps.add(text, self.gs.random(text))
        except Exception as ex:
            error(u'PicturesRandomAPI.post(text={0})'.format(text), ex)

            return ApiResponse(status=500, errors=ServerErrors.internal_server_error([]))
Esempio n. 29
0
    def validate(self, userconf):
        """
        Validate the given user configuration dictionary with the declared
        config handled by this configurator.

        :raise MissingOptions: if mandatory options are missing.
        :raise UnknownOptions: if non declared options are present.

        :param dict userconf: The user configuration.

        :return: A custom named tuple that maps the config keys with another
         named tuple that holds the name of the key, the value and the flag
         marking it as secret or not.
        :rtype: namedtuple
        """
        if not self._declared:
            self._configtype = namedtuple('config', [])
            return self._configtype()

        # All mandatory keys are present in user config
        mandatory = {
            key
            for key, info in self._declared.items() if not info['optional']
        }
        available = set(userconf.keys())

        if mandatory - available:
            raise MissingOptions(sorted(mandatory - available))

        # Check for unknown configuration options
        declared = set(self._declared.keys())

        if available - declared:
            raise UnknownOptions(sorted(available - declared))

        # Check schema of the options
        for key, info in self._declared.items():
            schema = info['schema']

            if key in userconf and schema is not None:
                validator = Validator({key: schema})
                validated = validator.validated({key: userconf[key]})

                if validated is None:
                    log.critical('Invalid config option {} = {}:\n{}'.format(
                        key, userconf[key], pformat(validator.errors)))
                    raise SyntaxError('Invalid config option {} = {}'.format(
                        key, userconf[key]))

                userconf[key] = validated[key]

        # Add missing default values
        validated = deepcopy(userconf)
        validated.update({
            key: info['default']
            for key, info in self._declared.items() if key not in available
        })

        # Pass custom validators
        for validator in self._validators:
            validator(validated)

        # Log configuration
        def is_secret(key):
            return self._declared[key]['secret']

        log_config = []
        for key in self._declared.keys():

            # Allow custom validators to delete keys
            if key not in validated:
                continue

            if is_secret(key):
                log_config.append('{} = {}'.format(key, '*' * 20))
                continue

            log_config.append('{} = {}'.format(key, validated[key]))

        log.info('Using configuration:\n    {}'.format(
            '\n    '.join(log_config)))

        # Create configuration type for this declared configuration
        self._configtype = namedtuple('config', validated.keys())

        # Create inmutable configuration object
        return self._configtype(
            **{
                key: self._configitem(
                    key=key, value=value, is_secret=is_secret(key))
                for key, value in validated.items()
            })
Esempio n. 30
0
def flexio_handler(flex):

    # get the api key from the variable input
    auth_token = dict(flex.vars).get('hunter_api_key')
    if auth_token is None:
        raise ValueError

    # get the input
    input = flex.input.read()
    input = json.loads(input)
    if not isinstance(input, list):
        raise ValueError

    # define the expected parameters and map the values to the parameter names
    # based on the positions of the keys/values
    params = OrderedDict()
    params['email'] = {'required': True, 'type': 'string'}
    params['properties'] = {'required': False, 'validator': validator_list, 'coerce': to_list, 'default': '*'}
    input = dict(zip(params.keys(), input))

    # validate the mapped input against the validator
    # if the input is valid return an error
    v = Validator(params, allow_unknown = True)
    input = v.validated(input)
    if input is None:
        raise ValueError

    # map this function's property names to the API's property names
    property_map = OrderedDict()
    property_map['score'] = 'score'
    property_map['status'] = 'result'
    property_map['regexp'] = 'regexp'
    property_map['autogen'] = 'gibberish'
    property_map['disposable'] = 'disposable'
    property_map['webmail'] = 'webmail'
    property_map['mx_records'] = 'mx_records'
    property_map['smtp_server'] = 'smtp_server'
    property_map['smtp_check'] = 'smtp_check'
    property_map['smtp_check_blocked'] = 'block'
    property_map['smtp_accept_all'] = 'accept_all'

    # get the properties to return and the property map;
    # if we have a wildcard, get all the properties
    properties = [p.lower().strip() for p in input['properties']]
    if len(properties) == 1 and (properties[0] == '' or properties[0] == '*'):
        properties = list(property_map.keys())

    # see here for more info:
    # https://hunter.io/api/docs#email-verifier
    url_query_params = {
        'email': input['email'],
        'api_key': auth_token
    }
    url_query_str = urllib.parse.urlencode(url_query_params)
    url = 'https://api.hunter.io/v2/email-verifier?' + url_query_str

    # get the response data as a JSON object
    response = requests_retry_session().get(url)
    response.raise_for_status()
    content = response.json()
    content = content.get('data', {})

    # get the properties
    result = [[content.get(property_map.get(p,''),'') for p in properties]] # don't use "or '' for p in properties" because result can be true/false

    # return the results
    result = json.dumps(result, default=to_string)
    flex.output.content_type = "application/json"
    flex.output.write(result)
Esempio n. 31
0
def flexio_handler(flex):

    # get the api key from the variable input
    auth_token = dict(flex.vars).get('quandl_api_key')
    if auth_token is None:
        raise ValueError

    # get the input
    input = flex.input.read()
    try:
        input = json.loads(input)
        if not isinstance(input, list): raise ValueError
    except ValueError:
        raise ValueError

    # define the expected parameters and map the values to the parameter names
    # based on the positions of the keys/values
    params = OrderedDict()
    params['name'] = {'required': True, 'type': 'string', 'coerce': str}
    params['properties'] = {
        'required': False,
        'validator': validator_list,
        'coerce': to_list,
        'default': '*'
    }
    params['mindate'] = {
        'required': False,
        'type': 'date',
        'default': '1900-01-01',
        'coerce': to_date
    }
    params['maxdate'] = {
        'required': False,
        'type': 'date',
        'default': '2099-12-31',
        'coerce': to_date
    }

    input = dict(zip(params.keys(), input))

    # validate the mapped input against the validator
    # if the input is valid return an error
    v = Validator(params, allow_unknown=True)
    input = v.validated(input)
    if input is None:
        raise ValueError

    # make the request
    # see here for more info: https://docs.quandl.com/
    url_query_params = {
        "api_key": auth_token,
        "start_date": input['mindate'],
        "end_date": input['maxdate']
    }
    url_query_str = urllib.parse.urlencode(url_query_params)

    url = 'https://www.quandl.com/api/v3/datasets/' + input[
        'name'] + '?' + url_query_str
    headers = {'Accept': 'application/json'}
    response = requests_retry_session().get(url, headers=headers)
    response.raise_for_status()
    content = response.json()

    # get the columns and rows; clean up columns by converting them to
    # lowercase and removing leading/trailing spaces
    rows = content.get('dataset', {}).get('data', [])
    columns = content.get('dataset', {}).get('column_names', [])
    columns = [c.lower().strip() for c in columns]

    # get the properties (columns) to return based on the input;
    # if we have a wildcard, get all the properties
    properties = [p.lower().strip() for p in input['properties']]
    if len(properties) == 1 and properties[0] == '*':
        properties = columns

    # build up the result
    result = []

    result.append(properties)
    for r in rows:
        item = dict(
            zip(columns, r)
        )  # create a key/value for each column/row so we can return appropriate columns
        item_filtered = [item.get(p) or '' for p in properties]
        result.append(item_filtered)

    result = json.dumps(result, default=to_string)
    flex.output.content_type = "application/json"
    flex.output.write(result)
def flexio_handler(flex):

    # TODO: support language
    language = 'en'

    # get the input
    input = flex.input.read()
    try:
        input = json.loads(input)
        if not isinstance(input, list): raise ValueError
    except ValueError:
        raise ValueError

    # define the expected parameters and map the values to the parameter names
    # based on the positions of the keys/values
    params = OrderedDict()
    params['search'] = {'required': True, 'type': 'string'}
    input = dict(zip(params.keys(), input))

    # validate the mapped input against the validator
    # if the input is valid return an error
    v = Validator(params, allow_unknown=True)
    input = v.validated(input)
    if input is None:
        raise ValueError

    # see here for more info: https://en.wikipedia.org/w/api.php?action=help&modules=query
    # see here to experiment with the api: https://en.wikipedia.org/wiki/Special:ApiSandbox

    # STEP 1: perform a search and get the page id for the top item in the search
    url_query_params = {
        'action': 'query',
        'format': 'json',
        'list': 'search',
        'srprop': 'timestamp',
        'srsearch': input['search']
    }
    url_query_str = urllib.parse.urlencode(url_query_params)

    url = 'https://en.wikipedia.org/w/api.php?' + url_query_str
    response = requests_retry_session().get(url)
    search_info = response.json()
    search_items = search_info.get('query', {}).get('search', [])

    top_search_item = {}
    if len(search_items) > 0:
        top_search_item = search_items[0]

    top_search_item_page_id = top_search_item.get('pageid')
    if top_search_item_page_id is None:
        flex.output.content_type = "application/json"
        flex.output.write([[""]])
        return

    # STEP 2: get the article for the page id returned by the search
    top_search_item_page_id = str(top_search_item_page_id)
    url = 'https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&explaintext=&exintro=&exsentences=1&pageids=' + top_search_item_page_id
    response = requests_retry_session().get(url)
    article_info = response.json()
    extract = article_info.get('query',
                               {}).get('pages',
                                       {}).get(top_search_item_page_id,
                                               {}).get('extract', '')

    result = [[extract]]
    flex.output.content_type = "application/json"
    flex.output.write(result)
class TestCerberus:
    package = 'cerberus'
    version = str(__version__)

    def __init__(self, allow_extra):
        schema = {
            'id': {
                'type': 'integer',
                'required': True
            },
            'client_name': {
                'type': 'string',
                'maxlength': 255,
                'required': True
            },
            'sort_index': {
                'type': 'float',
                'required': True
            },
            'client_phone': {
                'type': 'string',
                'maxlength': 255,
                'nullable': True
            },
            'location': {
                'type': 'dict',
                'schema': {
                    'latitude': {
                        'type': 'float'
                    },
                    'longitude': {
                        'type': 'float'
                    }
                },
                'nullable': True,
            },
            'contractor': {
                'type': 'integer',
                'min': 0,
                'nullable': True,
                'coerce': int
            },
            'upstream_http_referrer': {
                'type': 'string',
                'maxlength': 1023,
                'nullable': True
            },
            'grecaptcha_response': {
                'type': 'string',
                'minlength': 20,
                'maxlength': 1000,
                'required': True
            },
            'last_updated': {
                'type': 'datetime',
                'nullable': True,
                'coerce': datetime_parse
            },
            'skills': {
                'type': 'list',
                'default': [],
                'schema': {
                    'type': 'dict',
                    'schema': {
                        'subject': {
                            'type': 'string',
                            'required': True
                        },
                        'subject_id': {
                            'type': 'integer',
                            'required': True
                        },
                        'category': {
                            'type': 'string',
                            'required': True
                        },
                        'qual_level': {
                            'type': 'string',
                            'required': True
                        },
                        'qual_level_id': {
                            'type': 'integer',
                            'required': True
                        },
                        'qual_level_ranking': {
                            'type': 'float',
                            'default': 0,
                            'required': True
                        },
                    },
                },
            },
        }

        self.v = Validator(schema)
        self.v.allow_unknown = allow_extra

    def validate(self, data):
        validated = self.v.validated(data)
        if validated is None:
            return False, self.v.errors
        else:
            return True, validated
Esempio n. 34
0
def flexio_handler(flex):

    # TODO: support language
    language = 'en'

    # get the input
    input = flex.input.read()
    try:
        input = json.loads(input)
        if not isinstance(input, list): raise ValueError
    except ValueError:
        raise ValueError

    # define the expected parameters and map the values to the parameter names
    # based on the positions of the keys/values
    params = OrderedDict()
    params['search'] = {'required': True, 'type': 'string'}
    params['properties'] = {
        'required': False,
        'validator': validator_list,
        'coerce': to_list,
        'default': 'description'
    }
    input = dict(zip(params.keys(), input))

    # validate the mapped input against the validator
    # if the input is valid return an error
    v = Validator(params, allow_unknown=True)
    input = v.validated(input)
    if input is None:
        raise ValueError

    default_properties = OrderedDict()
    default_properties['label'] = ''
    default_properties['description'] = ''
    default_properties['wikipedia_url'] = ''
    default_properties['gender'] = ''
    default_properties['birth_name'] = ''
    default_properties['given_name'] = ''
    default_properties['family_name'] = ''
    default_properties['native_name'] = ''
    default_properties['birth_date'] = ''
    default_properties['death_date'] = ''
    default_properties['birth_place'] = ''
    default_properties['death_place'] = ''
    default_properties['religion'] = ''
    default_properties['citizenship'] = ''
    default_properties['native_language'] = ''
    default_properties['father'] = ''
    default_properties['mother'] = ''
    default_properties['spouse'] = ''
    default_properties['residence'] = ''
    default_properties['occupation'] = ''
    default_properties['education'] = ''
    default_properties['net_worth'] = ''
    default_properties['twitter_id'] = ''
    default_properties['instagram_id'] = ''
    default_properties['reddit_id'] = ''
    default_properties['bloomberg_id'] = ''
    default_properties['updated_dt'] = ''

    # see here for general information about the wikidata api: https://www.wikidata.org/wiki/Wikidata:Data_access
    # see here for list of sorted properties: https://www.wikidata.org/wiki/MediaWiki:Wikibase-SortedProperties

    # STEP 1: make an initial search request to find the most relevant item
    # https://www.wikidata.org/w/api.php?action=wbsearchentities&language=en&search=:search_term
    url_query_params = {
        'action': 'wbsearchentities',
        'language': language,
        'format': 'json',
        'search': input['search']
    }
    url_query_str = urllib.parse.urlencode(url_query_params)

    url = 'https://www.wikidata.org/w/api.php?' + url_query_str
    response = requests_retry_session().get(url)
    search_info = response.json()
    search_items = search_info.get('search', [])

    if len(search_items) == 0:
        flex.output.content_type = "application/json"
        flex.output.write([[""]])
        return

    search_first_item_id = search_items[0].get('id', '')

    # STEP 2: get the info about the item
    # https://www.wikidata.org/w/api.php?action=wbgetentities&sites=enwiki&props=claims&format=json&ids=:id
    props = 'info|sitelinks|sitelinks/urls|labels|descriptions|claims|datatype'
    url_query_params = {
        'action': 'wbgetentities',
        'sites': 'enwiki',
        'props': props,
        'format': 'json',
        'ids': search_first_item_id
    }
    url_query_str = urllib.parse.urlencode(url_query_params)

    url = 'https://www.wikidata.org/w/api.php?' + url_query_str
    response = requests_retry_session().get(url)
    content = response.json()

    # TODO:
    # confirm we have a human
    # instanceof (P31) is Q5 (human)

    # STEP 3: get primary item info and additional info
    item_primary_info = get_basic_info(content, search_first_item_id, language)
    item_claim_info = get_claim_info(content, search_first_item_id, language)

    # STEP 4: make an additional lookup to find out the info from the wikipedia entity values
    # https://www.wikidata.org/w/api.php?action=wbgetentities&sites=enwiki&props=claims&format=json&ids=:id
    props = 'labels'
    search_ids = [
        i.get('datavalue', {}).get('value', {}).get('id', '')
        for i in item_claim_info
        if i.get('datavalue', {}).get('type') == 'wikibase-entityid'
    ]
    search_ids = '|'.join(search_ids)
    url_query_params = {
        'action': 'wbgetentities',
        'sites': 'enwiki',
        'props': props,
        'format': 'json',
        'ids': search_ids
    }
    url_query_str = urllib.parse.urlencode(url_query_params)

    url = 'https://www.wikidata.org/w/api.php?' + url_query_str
    response = requests_retry_session().get(url)
    content = response.json()

    # STEP 5: use the info from the additional lookup to populate the values in the item info
    item_claim_info_enriched = [
        update_claim_info(i, content, language) for i in item_claim_info
    ]

    # STEP 6: merge the primary info and the enriched info
    item_info_lookup = {}
    for i in item_primary_info:
        item_info_lookup[i['name']] = i.get('value', '')
    for i in item_claim_info:
        item_info_lookup[i['name']] = i.get('value', '')

    # get the properties to return
    properties = [p.lower().strip() for p in input['properties']]

    # if we have a wildcard, get all the properties
    if len(properties) == 1 and properties[0] == '*':
        properties = list(default_properties.keys())

    # build up the result
    result = [[item_info_lookup.get(p, '') or '' for p in properties]]

    # return the results
    result = json.dumps(result, default=to_string)
    flex.output.content_type = "application/json"
    flex.output.write(result)
Esempio n. 35
0
def validate_booking_data(booking_data: dict) -> dict:
    validator = Validator(BOOKING_DATA_SCHEMA)
    validated_data = validator.validated(booking_data)
    if validated_data is None:
        raise RuntimeError('Validation for booking data was failed. : ' + str(validator.errors))
    return validated_data
def flexio_handler(flex):

    # get the api key from the variable input
    auth_token = dict(flex.vars).get('producthunt_connection',
                                     {}).get('access_token')
    if auth_token is None:
        raise ValueError

    # get the input
    input = flex.input.read()
    try:
        input = json.loads(input)
        if not isinstance(input, list): raise ValueError
    except ValueError:
        raise ValueError

    # define the expected parameters and map the values to the parameter names
    # based on the positions of the keys/values
    params = OrderedDict()
    params['properties'] = {
        'required': False,
        'validator': validator_list,
        'coerce': to_list,
        'default': '*'
    }
    input = dict(zip(params.keys(), input))

    # validate the mapped input against the validator
    # if the input is valid return an error
    v = Validator(params, allow_unknown=True)
    input = v.validated(input)
    if input is None:
        raise ValueError

    # map this function's property names to the API's property names
    property_map = OrderedDict()
    property_map['id'] = 'id'
    property_map['name'] = 'name'
    property_map['createdAt'] = 'createdAt'
    property_map['featuredAt'] = 'featuredAt'
    property_map['url'] = 'url'
    property_map['tagline'] = 'tagline'
    property_map['description'] = 'description'

    # make the request
    # see here for more info: https://api.producthunt.com/v2/docs

    url = 'https://api.producthunt.com/v2/api/graphql'
    headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + auth_token,
        'Host': 'api.producthunt.com'
    }
    columns = list(property_map.values())
    data = {
        "query":
        "query { posts { edges { node {" + " ".join(columns) + " } } } }"
    }

    response = requests_retry_session().post(url,
                                             data=json.dumps(data),
                                             headers=headers)
    response.raise_for_status()
    content = response.json()

    # get the properties to return and the property map
    properties = [p.lower().strip() for p in input['properties']]

    # if we have a wildcard, get all the properties
    if len(properties) == 1 and properties[0] == '*':
        properties = list(property_map.keys())

    # build up the result
    result = []
    result.append(properties)

    edges = content.get('data', {}).get('posts', {}).get('edges', [])
    for item in edges:
        row = [
            item.get('node').get(property_map.get(p, '')) or ''
            for p in properties
        ]
        result.append(row)

    flex.output.content_type = "application/json"
    flex.output.write(result)
Esempio n. 37
0
def create_performer():
    v = Validator(purge_unknown=True)
    schema = {
        'name': {
            'type': 'string',
            'required': True
        },
        'phone': {
            'type': 'string',
            'required': True
            # 'regex' : REGEX_PHONE
        },
        'description': {
            'type': 'string',
            'required': True
        },
        'photo': {},
        'services': {
            'type': 'list'
        },
        'work_beg': {
            'coerce':
            lambda x: timedelta(hours=parse(x).hour, minutes=parse(x).minute)
        },
        'work_end': {
            'coerce':
            lambda x: timedelta(hours=parse(x).hour, minutes=parse(x).minute)
        },
        'lunch_beg': {
            'coerce':
            lambda x: timedelta(hours=parse(x).hour, minutes=parse(x).minute)
        },
        'lunch_end': {
            'coerce':
            lambda x: timedelta(hours=parse(x).hour, minutes=parse(x).minute)
        },
        'non_working_days': {
            'type': 'list',
            'default': []
        }
    }
    req_data = v.validated(request.get_json(), schema)
    if not req_data:
        abort(400, v.errors)
    performer = db.session.query(Performer).filter(
        Performer.name == req_data['name']).first()
    if performer:
        return jsonify({"msg": "Performer already exists"}), 400
    performer = Performer(business_id=Business.get(get_jwt_claims()['id']).id)

    if ('photo' in req_data.keys()) and req_data['photo']:
        photo = Image(data=req_data['photo'])
        db.session.add(photo)
        db.session.commit()
        performer.photo_id = photo.id

    msg = add(performer, {
        key: req_data[key]
        for key in req_data if key not in ['services', 'photo']
    })
    try:
        if ('services' in req_data.keys()) and (len(req_data['services']) > 0):
            db.session.execute(performer_service.insert(),
                               [{
                                   'performer_id': performer.id,
                                   'service_id': x
                               } for x in req_data['services']])
            db.session.commit()
    except:
        return jsonify({"msg": "Probably services parameter is invalid"}), 400

    return msg
Esempio n. 38
0
def update_performer(curr_id):
    v = Validator(purge_unknown=True)
    schema = {
        'name': {
            'type': 'string'
        },
        'phone': {
            'type': 'string'
            # 'regex' : REGEX_PHONE
        },
        'description': {
            'type': 'string'
        },
        'newPhoto': {},
        'services': {
            'type': 'list'
        },
        'work_beg': {
            'coerce':
            lambda x: timedelta(hours=parse(x).hour, minutes=parse(x).minute)
        },
        'work_end': {
            'coerce':
            lambda x: timedelta(hours=parse(x).hour, minutes=parse(x).minute)
        },
        'lunch_beg': {
            'coerce':
            lambda x: timedelta(hours=parse(x).hour, minutes=parse(x).minute)
        },
        'lunch_end': {
            'coerce':
            lambda x: timedelta(hours=parse(x).hour, minutes=parse(x).minute)
        },
        'non_working_days': {
            'type': 'list',
            'default': []
        }
    }
    req_data = v.validated(request.get_json(), schema)
    if not req_data:
        abort(400, v.errors)
    performer = Performer.get(curr_id)
    if not performer:
        return jsonify(
            {"msg": "{0} doesn't exist".format(type(performer).__name__)}), 400
    if 'services' in req_data.keys():
        old_services = set(list(map(lambda x: x.id, performer.services)))
        new_services = set(req_data['services'])
        to_remove = old_services.difference(new_services)
        to_add = new_services.difference(old_services)
        try:
            if len(to_remove) > 0:
                db.session.execute(performer_service.delete().where(
                    and_(performer_service.c.performer_id == curr_id,
                         performer_service.c.service_id.in_(to_remove))))
            if len(to_add) > 0:
                db.session.execute(performer_service.insert(),
                                   [{
                                       'performer_id': curr_id,
                                       'service_id': x
                                   } for x in to_add])
        except:
            db.session.rollback()
            return jsonify({"msg":
                            "Probably performers parameter is invalid"}), 400

    if 'photo' in req_data.keys():
        if performer.photo_id:
            Image.query.filter(Image.id == performer.photo_id).delete()

        if req_data['photo']:
            photo = Image(data=req_data['photo'])
            db.session.add(photo)
            db.session.commit()
            performer.photo_id = photo.id

    return update(performer, {
        key: req_data[key]
        for key in req_data if key not in ['services', 'photo']
    })
def flexio_handler(flex):

    # get the api key from the variable input
    auth_token = dict(flex.vars).get('fullcontact_api_key')
    if auth_token is None:
        raise ValueError

    # get the input
    input = flex.input.read()
    try:
        input = json.loads(input)
        if not isinstance(input, list): raise ValueError
    except ValueError:
        raise ValueError

    # define the expected parameters and map the values to the parameter names
    # based on the positions of the keys/values
    params = OrderedDict()
    params['email'] = {'required': True, 'type': 'string'}
    params['properties'] = {
        'required': False,
        'validator': validator_list,
        'coerce': to_list,
        'default': '*'
    }
    input = dict(zip(params.keys(), input))

    # validate the mapped input against the validator
    # if the input is valid return an error
    v = Validator(params, allow_unknown=True)
    input = v.validated(input)
    if input is None:
        raise ValueError

    # map this function's property names to the API's property names
    property_map = OrderedDict()
    property_map['full_name'] = 'fullName'
    property_map['age_range'] = 'ageRange'
    property_map['gender'] = 'gender'
    property_map['location'] = 'location'
    property_map['title'] = 'title'
    property_map['organization'] = 'organization'
    property_map['twitter_url'] = 'twitter'
    property_map['facebook_url'] = 'facebook'
    property_map['linkedin_url'] = 'linkedin'
    property_map['bio'] = 'bio'
    property_map['avatar_url'] = 'avatar'

    # get the properties to return and the property map
    properties = [p.lower().strip() for p in input['properties']]

    # if we have a wildcard, get all the properties
    if len(properties) == 1 and properties[0] == '*':
        properties = list(property_map.keys())

    # see here for more info:
    # https://docs.fullcontact.com/#person-enrichment
    # https://dashboard.fullcontact.com/api-ref#response-codes-&-errors

    data = json.dumps({'email': input['email'].lower().strip()})
    headers = {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + auth_token
    }
    url = 'https://api.fullcontact.com/v3/person.enrich'

    # get the response data as a JSON object
    response = requests_retry_session().post(url, data=data, headers=headers)

    # sometimes results are pending; for these, return text indicating
    # the result is pending so the user can refresh later to look for
    # the completed result
    status_code = response.status_code
    if status_code == 202:
        flex.output.content_type = "application/json"
        flex.output.write([['Result Pending...']])
        return

    # if a result can't be found or wasn't formatted properly,
    # return a blank (equivalent to not finding a bad email address)
    if status_code == 400 or status_code == 404 or status_code == 422:
        flex.output.content_type = "application/json"
        flex.output.write([['']])
        return

    # return an error for any other non-200 result
    response.raise_for_status()

    # limit the results to the requested properties
    content = response.json()
    properties = [
        content.get(property_map.get(p, ''), '') or '' for p in properties
    ]
    result = [properties]

    # return the results
    result = json.dumps(result, default=to_string)
    flex.output.content_type = "application/json"
    flex.output.write(result)