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)}
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
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)}
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))
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')
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)}
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)}
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)}
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
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)}