Esempio n. 1
0
    def on_get(self, req, res):
        """
        Search for user's Menu ratings based on supplied user
        Only allows for searching by user
        """
        query_params = req.params.get('query')

        try:
            # get pagination limits
            start = int(query_params.pop('start', 0))
            limit = int(query_params.pop('limit', constants.PAGE_LIMIT))
            end = start + limit

        except ValueError as e:
            raise HTTPBadRequest(
                title='Invalid Value',
                description='Invalid arguments in URL query:\n{}'.format(
                    e.message))

        user_id = query_params.pop('user_id', None)
        if not user_id:
            raise HTTPBadRequest(
                title='Invalid Request',
                description='Please supply a user ID in the query params')

        user = User.objects.get(id=user_id)
        updated_params = {'__raw__': {'user.$id': user.id}}

        ratings = MenuRating.objects(**updated_params)[start:end]
        res.body = {'items': ratings, 'count': len(ratings)}
Esempio n. 2
0
def deserialize(req, res, resource, schema=None):
    """
    A BEFORE hook function
    Deserializes data from the request object based on HTTP method
    if a colander Schema is provided, further deserialize data with the schema
    updates req.params with the deserialized data, in either 'body' or 'query' key
    :param req: request object
    :param res: response object
    :param resource: response pbject
    :param schema: colander Schema object
    """
    def _is_json_type(content_type):
        return content_type == 'application/json'

    if req.method.upper() in ['POST', 'PUT', 'PATCH']:

        if not _is_json_type(req.content_type):
            raise HTTPNotAcceptable(
                description='JSON required. '
                'Invalid Content-Type\n{}'.format(req.content_type))

        req.params['body'] = {}

        stream = req.stream.read()
        if not stream:
            return

        json_body = json_util.loads(stream)

        if schema:
            try:
                body = schema.deserialize(json_body)
            except colander.Invalid as e:
                raise HTTPBadRequest(title='Invalid Value',
                                     description='Invalid arguments '
                                     'in params:\n{}'.format(e.asdict()))

        req.params['body'] = body

    elif req.method.upper() in ['OPTIONS', 'HEAD', 'GET', 'DELETE']:

        req.params['query'] = {}

        if not req.query_string:
            return

        query = map_query(req.query_string, ignores=['token'])

        if schema:
            try:
                query = schema.deserialize(query)
            except colander.Invalid as e:
                raise HTTPBadRequest(title='Invalid Value',
                                     description='Invalid arguments '
                                     'in params:\n{}'.format(e.asdict()))

        req.params['query'] = query
Esempio n. 3
0
    def on_get(self, req, res):
        query_params = req.params.get('query')

        try:
            # get pagination limits
            start = int(query_params.pop('start', 0))
            limit = int(query_params.pop('limit', constants.PAGE_LIMIT))
            end = start + limit

        except ValueError as e:
            raise HTTPBadRequest(title='Invalid Value',
                                 description='Invalid arguments in URL query:\n{}'.format(e.message))
        # custom filters
        # temp dict for updating query filters
        updated_params = {}

        for item in ['name', 'description']:
            if item in query_params:
                item_val = query_params.pop(item)
                updated_params['{}__icontains'.format(item)] = item_val

        try:
            if 'geolocation' in query_params:
                geolocation_val = query_params.pop('geolocation')
                geolocation_val = map(float, geolocation_val.split(',')[:2])
                max_distance = int(query_params.pop('maxDistance', constants.MAX_DISTANCE_SEARCH))

                # we deal with geolocation query in raw instead due to mongoengine bugs
                # see https://github.com/MongoEngine/mongoengine/issues/795
                # dated: 3/1/2015

                updated_params['__raw__'] = {
                    'geolocation': {
                        '$near': {
                            '$geometry': {
                                'type': 'Point',
                                'coordinates': geolocation_val
                            },
                            '$maxDistance': max_distance
                        },
                    }
                }

        except Exception:
            raise HTTPBadRequest('Invalid Value', 'geolocation supplied is invalid: {}'.format(geolocation_val))

        query_params.update(updated_params)  # update modified params for filtering

        restaurants = Restaurant.objects(**query_params)[start:end]
        for r in restaurants:
            reformat_geolocations_point_field_to_map(r, 'geolocation')

        res.body = {'items': restaurants, 'count': len(restaurants)}
Esempio n. 4
0
 def _try_get_user(self, id):
     try:
         return User.objects.get(id=id)
     except (ValidationError, DoesNotExist, MultipleObjectsReturned) as e:
         raise HTTPBadRequest(title='Invalid Value',
                              description='Invalid ID provided. {}'.format(
                                  e.message))
Esempio n. 5
0
    def on_delete(self, req, res, id):
        menu = self._try_get_menu(id)
        query_params = req.params.get('query')
        user_id = query_params.get('user_id')

        if not user_id:
            raise HTTPBadRequest(
                title='Invalid Request',
                description='Please supply a user ID in the query params')

        try:
            user = User.objects.get(id=user_id)
            MenuRating.objects(menu=menu, user=user).delete()

        except (ValidationError, DoesNotExist):
            raise HTTPBadRequest(
                title='Invalid Value',
                description='Invalid user or menu ID provided')
Esempio n. 6
0
    def on_get(self, req, res):
        query_params = req.params.get('query')

        try:
            # get pagination limits
            start = int(query_params.pop('start', 0))
            limit = int(query_params.pop('limit', constants.PAGE_LIMIT))
            end = start + limit

        except ValueError as e:
            raise HTTPBadRequest(
                title='Invalid Value',
                description='Invalid arguments in URL query:\n{}'.format(
                    e.message))

        users = User.objects(**query_params)[start:end]
        res.body = {'items': users, 'count': len(users)}
Esempio n. 7
0
    def on_get(self, req, res):
        res.status = falcon.HTTP_200
        query_params = req.params.get('query')

        try:
            # get pagination limits
            start = int(query_params.get('start', 0))
            limit = int(query_params.get('limit', 20))
            end = start + limit
        except ValueError as e:
            raise HTTPBadRequest(
                title='Invalid Value',
                description='Invalid arguments in URL query:\n{}'.format(
                    e.message))

        tag_freqs = Menu.objects.item_frequencies('tags', normalize=True)
        tags = sorted(tag_freqs.iteritems(), key=itemgetter(1),
                      reverse=True)[start:end]
        res.body = {'items': tags, 'count': len(tags)}
Esempio n. 8
0
    def on_get(self, req, res):
        query_params = req.params.get('query')

        # get IDs
        try:
            ids = query_params.pop('ids')
        except KeyError:
            raise HTTPBadRequest(
                title='Invalid Request',
                description='Missing ID parameter in URL query')

        # parse IDs
        ids = ids.split(',')
        restaurants = []
        for id in ids:
            restaurant = self._try_get_restaurant(id)
            reformat_geolocations_point_field_to_map(restaurant, 'geolocation')
            restaurants.append(restaurant)

        res.body = {'items': restaurants, 'count': len(restaurants)}
Esempio n. 9
0
    def on_post(self, req, res, id):
        menu = self._try_get_menu(id)

        data = req.params.get('body')
        try:
            user = User.objects.get(id=data['user_id'])
        except (ValidationError, DoesNotExist, MultipleObjectsReturned):
            raise HTTPBadRequest(title='Invalid Request',
                                 description='Please supply a valid menu ID')

        # update menu ratings
        menu.rating_count += 1
        menu.rating_total += data['rating']

        # create a new menu rating instance
        rating = MenuRating(menu=menu, user=user, rating=data['rating'])

        menu.save()
        rating.save()

        rating = MenuRating.objects.get(id=rating.id)
        res.body = rating
Esempio n. 10
0
    def on_get(self, req, res):
        query_params = req.params.get('query')

        try:
            # get pagination limits
            start = int(query_params.pop('start', 0))
            limit = int(query_params.pop('limit', constants.PAGE_LIMIT))
            end = start + limit

        except ValueError as e:
            raise HTTPBadRequest(
                title='Invalid Value',
                description='Invalid arguments in URL query:\n{}'.format(
                    e.message))

        # custom filters
        # temp dict for updating query filters
        updated_params = {}

        for item in ['name']:
            if item in query_params:
                item_val = query_params.pop(item)
                updated_params['{}__icontains'.format(item)] = item_val

        # skip updating query_params for filters on list fields like tags,
        # since mongoengine filters directly by finding any Menu that has tags of that value
        # e.g., GET /menu?tags=chicken returns all restaurants having 'chicken' tag

        for item in ['price', 'rating']:
            if item in query_params:
                range = query_params.pop(item)
                r_min, r_max = min_max(range, type='float')
                updated_params['{}__gte'.format(item)] = r_min
                updated_params['{}__lte'.format(item)] = r_max

        # for convenience, we allow users to search for menus by their restaurant's geolocation too
        if 'geolocation' in query_params:
            try:
                geolocation_val = query_params.pop('geolocation')
                geolocation_val = map(float, geolocation_val.split(',')[:2])
                max_distance = int(
                    query_params.pop('maxDistance',
                                     constants.MAX_DISTANCE_SEARCH))

                # we deal with geolocation query in raw instead due to mongoengine bugs
                # see https://github.com/MongoEngine/mongoengine/issues/795
                # dated: 3/1/2015

                restaurant_query_params = {
                    '__raw__': {
                        'geolocation': {
                            '$near': {
                                '$geometry': {
                                    'type': 'Point',
                                    'coordinates': geolocation_val
                                },
                                '$maxDistance': max_distance
                            },
                        }
                    }
                }
                # return list of restaurants satisfying geolocation requirements
                restaurants = Restaurant.objects(**restaurant_query_params)

                # we found nearby restaurants, filter menus further to menus from these restaurants only
                updated_params['__raw__'] = {
                    "restaurant.$id": {
                        "$in": [r.id for r in restaurants]
                    }
                }

            except Exception:
                raise HTTPBadRequest(
                    'Invalid Value',
                    'geolocation supplied is invalid: {}'.format(
                        geolocation_val))

        query_params.update(
            updated_params)  # update modified params for filtering
        menus = Menu.objects(**query_params)[start:end]

        res.body = {'items': menus, 'count': len(menus)}