def task(): print("request", request) if request.method == "PATCH": print("heelloooooo") return send_response("tasks", patch_internal("tasks", payload = request.json)) return send_response("tasks", post_internal("tasks", request.json))
def item_endpoint(**lookup): """ Item endpoint handler :param url: the url that led here :param lookup: the query .. versionchanged:: 0.1.1 Relying on request.path for determining the current endpoint url. .. versionchanged:: 0.1.0 Support for PUT method. .. versionchanged:: 0.0.7 Using 'utils.request_method' helper function now. .. versionchanged:: 0.0.6 Support for HEAD requests """ k = request.path.rstrip('/').rfind('/') resource = config.RESOURCES[request.path[:k]] response = None method = request_method() if method in ('GET', 'HEAD'): response = getitem(resource, **lookup) elif method == 'PATCH': response = patch(resource, **lookup) elif method == 'PUT': response = put(resource, **lookup) elif method == 'DELETE': response = delete(resource, **lookup) elif method == 'OPTIONS': send_response(resource, response) else: abort(405) return send_response(resource, response)
def item_endpoint(url, **lookup): """ Item endpoint handler :param url: the url that led here :param lookup: the query .. versionchanged:: 0.1.0 Support for PUT method. .. versionchanged:: 0.0.7 Using 'utils.request_method' helper function now. .. versionchanged:: 0.0.6 Support for HEAD requests """ resource = config.RESOURCES[url] response = None method = request_method() if method in ('GET', 'HEAD'): response = getitem(resource, **lookup) elif method == 'PATCH': response = patch(resource, **lookup) elif method == 'PUT': response = put(resource, **lookup) elif method == 'DELETE': response = delete(resource, **lookup) elif method == 'OPTIONS': send_response(resource, response) else: abort(405) return send_response(resource, response)
def item_endpoint(url, **lookup): """ Item endpoint handler :param url: the url that led here :param lookup: the query .. versionchanged:: 0.0.7 Using 'utils.request_method' helper function now. .. versionchanged:: 0.0.6 Support for HEAD requests """ resource = config.RESOURCES[url] response = None method = request_method() if method in ('GET', 'HEAD'): response = getitem(resource, **lookup) elif method == 'PATCH': response = patch(resource, **lookup) elif method == 'DELETE': response = delete(resource, **lookup) elif method == 'OPTIONS': send_response(resource, response) else: abort(405) return send_response(resource, response)
def collections_endpoint(**lookup): """ Resource endpoint handler :param url: the url that led here .. versionchanged:: 0.2 Relying on request.endpoint to retrieve the resource being consumed. .. versionchanged:: 0.1.1 Relying on request.path for determining the current endpoint url. .. versionchanged:: 0.0.7 Using 'utils.request_method' helper function now. .. versionchanged:: 0.0.6 Support for HEAD requests .. versionchanged:: 0.0.2 Support for DELETE resource method. """ resource = _resource() response = None method = request_method() if method in ('GET', 'HEAD'): response = get(resource, lookup) elif method == 'POST': response = post(resource) elif method == 'DELETE': response = delete_resource(resource) elif method == 'OPTIONS': send_response(resource, response) else: abort(405) return send_response(resource, response)
def refresh(self): """ A flask endpoint to refresh the jwt token. Must be provided with a valid jwt token. """ method = request.method resource = request.endpoint.split("|")[0] # /refresh -> refresh if method == "OPTIONS": # CORS request return send_response(resource, None) if not request.is_json: return jsonify({"msg": "Missing JSON in request"}), 400 token = request.json.get("token", None) if not token: return jsonify({"msg": "Missing token parameter"}), 400 try: payload = jwt.decode(token, self.app.config.get("JWT_SECRET"), algorithms="HS256") except jwt.exceptions.DecodeError: return jsonify({"msg": "Invalid token"}), 401 identity = payload.get("identity", "") admin = payload.get("admin", False) token = self.create_token(identity, admin=admin) return send_response(resource, ({"token": token}, ))
def collections_endpoint(): """ Resource endpoint handler :param url: the url that led here .. versionchanged:: 0.1.1 Relying on request.path for determining the current endpoint url. .. versionchanged:: 0.0.7 Using 'utils.request_method' helper function now. .. versionchanged:: 0.0.6 Support for HEAD requests .. versionchanged:: 0.0.2 Support for DELETE resource method. """ url = request.path.rstrip('/') resource = config.RESOURCES[url] response = None method = request_method() if method in ('GET', 'HEAD'): response = get(resource) elif method == 'POST': response = post(resource) elif method == 'DELETE': response = delete_resource(resource) elif method == 'OPTIONS': send_response(resource, response) else: abort(405) return send_response(resource, response)
def vidible(**kwargs): meta = get_vidible_metadata(**kwargs) if meta: return send_response(None, (meta, utcnow(), None, 200)) else: return send_response(None, ({ 'error': 'not found' }, utcnow(), None, 404))
def login(self): """ A flask endpoint to login and to obtain a token. Must be provided with valid ldap user credentials. """ method = request.method resource = request.endpoint.split("|")[0] # /login -> login if method == "OPTIONS": # CORS request return send_response(resource, None) if not request.is_json: return jsonify({"msg": "Missing JSON in request"}), 400 username = request.json.get("username", None).lower() # Note lowercase password = request.json.get("password", None) if not username: return jsonify({"msg": "Missing username parameter"}), 400 if not password: return jsonify({"msg": "Missing password parameter"}), 400 if len(self.app.config["LDAP_EMAIL_DOMAIN"]) > 0: user = "******".format(username, self.app.config["LDAP_EMAIL_DOMAIN"]) else: user = username ldap_filter = "(&({user_key}={user})({admin_key}={admin_value}))".format( user_key=self.app.config["LDAP_USER_KEY"], user=username, admin_key=self.app.config["LDAP_ADMIN_KEY"], admin_value=self.app.config["LDAP_ADMIN_VALUE"], ) try: with Connection( self.server, user=user, password=password, read_only=True, raise_exceptions=True, ) as conn: conn.search( search_base=self.app.config["LDAP_SEARCH_BASE"], search_filter=ldap_filter, search_scope=SUBTREE, ) if conn.entries: token = self.create_token(username, admin=True) else: token = self.create_token(username, admin=False) response = send_response(resource, ({"token": token}, )) return response except LDAPException: # LDAP error the user credentials are not valid return jsonify({"msg": "Invalid credentials"}), 401
def home_endpoint(): """ Home/API entry point. Will provide links to each available resource .. versionchanged:: 0.5 Resource URLs are relative to API root. Don't list internal resources. .. versionchanged:: 0.4 Prevent versioning collections from being added in links. .. versionchanged:: 0.2 Use new 'resource_title' setting for link titles. .. versionchanged:: 0.1.0 Support for optional HATEOAS. """ response = {} if config.INFO: info = {} info["server"] = "Eve" info["version"] = eve.__version__ if config.API_VERSION: info["api_version"] = config.API_VERSION response[config.INFO] = info if config.HATEOAS: links = [] for resource in config.DOMAIN.keys(): internal = config.DOMAIN[resource]["internal_resource"] if not resource.endswith(config.VERSIONS): if not bool(internal): links.append( { "href": "%s" % config.URLS[resource], "title": "%s" % config.DOMAIN[resource]["resource_title"], } ) if config.SCHEMA_ENDPOINT is not None: links.append( { "href": "%s" % config.SCHEMA_ENDPOINT, "title": "%s" % config.SCHEMA_ENDPOINT, } ) response[config.LINKS] = {"child": links} return send_response(None, (response,)) else: return send_response(None, (response,))
def schema_collection_endpoint(): """ This endpoint is active when SCHEMA_ENDPOINT != None. It returns the schema definition for all public or request authenticated resources in JSON format. """ schemas = {} for resource_name, resource_config in app.config['DOMAIN'].items(): # skip versioned shadow collections if resource_name.endswith(config.VERSIONS): continue # skip internal resources internal = resource_config.get('internal_resource', False) if internal: continue # skip resources for which request does not have read authorization auth = resource_auth(resource_name) if auth and request.method not in resource_config['public_methods']: roles = list(resource_config['allowed_roles']) roles += resource_config['allowed_read_roles'] if not auth.authorized(roles, resource_name, request.method): continue # otherwise include this resource in domain wide schema response schemas[resource_name] = resource_config['schema'] return send_response(None, (schemas,))
def assert_error_handler(error): print("error", error) return send_response( None, ({ "code": 400, "error": str(error) if str(error) else "assert" }, None, None, 400))
def get_company_name_employees(company_name): db = app.data.driver.db company = db['companies'].find_one({"company": company_name}) if db['companies'].count_documents({"company": company_name}) > 0: response = get('get_employees', {'company_id': int(company['index'])}) return send_response('get_employees', response) return abort(404)
def locales_view(): if not flask.current_app.auth.authorized([], "locales", "GET"): flask.abort(401) resp = None if flask.request.method == "GET": resp = {"timezones": get_timezones()} return send_response(None, (resp, None, None, 200))
def schema_collection_endpoint(): """ This endpoint is active when SCHEMA_ENDPOINT != None. It returns the schema definition for all public or request authenticated resources in JSON format. """ schemas = {} for resource_name, resource_config in app.config["DOMAIN"].items(): # skip versioned shadow collections if resource_name.endswith(config.VERSIONS): continue # skip internal resources internal = resource_config.get("internal_resource", False) if internal: continue # skip resources for which request does not have read authorization auth = resource_auth(resource_name) if auth and request.method not in resource_config["public_methods"]: roles = list(resource_config["allowed_roles"]) roles += resource_config["allowed_read_roles"] if not auth.authorized(roles, resource_name, request.method): continue # otherwise include this resource in domain wide schema response schemas[resource_name] = resource_config["schema"] return send_response(None, (schemas, ))
def before_POST_posts(request): ''' Callback to be executed before documents have been validated. Primarily used to handle multipart form data. ''' if request.mimetype == 'multipart/form-data': # This is designed to parse only a single `request.form` item. # Additional items will be ignored. payload = {} for key in request.form: payload = json.loads(request.form[key]) break # The actual names of the keys used to send `request.files` data are # ignored. attachments = [] for key in request.files: file = request.files[key] attachments.append(save_attachment(file)) if attachments: payload['attachments'] = attachments response = post_internal('posts', payload) # Instead of continuing with the default response (where the request # will be sent to Eve's `post` function), we abort normal operation and # create our own response. abort(send_response('posts', response))
def home_endpoint(): """ Home/API entry point. Will provide links to each available resource .. versionchanged:: 0.4 Prevent versioning collections from being added in links. .. versionchanged:: 0.2 Use new 'resource_title' setting for link titles. .. versionchanged:: 0.1.0 Support for optional HATEOAS. """ if config.HATEOAS: response = {} links = [] for resource in config.DOMAIN.keys(): if not resource.endswith(config.VERSIONS): links.append({'href': '%s' % resource_uri(resource), 'title': '%s' % config.DOMAIN[resource]['resource_title']}) response[config.LINKS] = {'child': links} return send_response(None, (response,)) else: abort(404, debug_error_message("HATEOAS is disabled so we have no data" " to display at the API homepage."))
def home_endpoint(): """ Home/API entry point. Will provide links to each available resource .. versionchanged:: 0.5 Resource URLs are relative to API root. Don't list internal resources. .. versionchanged:: 0.4 Prevent versioning collections from being added in links. .. versionchanged:: 0.2 Use new 'resource_title' setting for link titles. .. versionchanged:: 0.1.0 Support for optional HATEOAS. """ if config.HATEOAS: response = {} links = [] for resource in config.DOMAIN.keys(): internal = config.DOMAIN[resource]['internal_resource'] if not resource.endswith(config.VERSIONS): if not bool(internal): links.append({'href': '%s' % config.URLS[resource], 'title': '%s' % config.DOMAIN[resource]['resource_title']}) response[config.LINKS] = {'child': links} return send_response(None, (response,)) else: abort(404, debug_error_message("HATEOAS is disabled so we have no data" " to display at the API homepage."))
def client_error_handler(error): """Return json error response. :param error: an instance of :attr:`koldocta.KoldoctaError` class """ return send_response( None, (error.to_dict(), None, None, error.status_code))
def waterpoint_values(field): "Return the unique values for a given field in the waterpoints collection." # FIXME: Direct call to the PyMongo driver, should be abstracted resources = app.data.driver.db['resources'] if request.args: resources = resources.find(dict(request.args.items())) return send_response('resources', (sorted(resources.distinct(field)), datetime.now()))
def waterpoint_stats_by(field): """Return number of waterpoints of a given status grouped by a certain attribute.""" # FIXME: Direct call to the PyMongo driver, should be abstracted resources = app.data.driver.db['resources'] return send_response('resources', (resources.aggregate([ {"$match": dict(request.args.items())}, {"$group": {"_id": {field: "$" + field, "status": "$status_group"}, "statusCount": {"$sum": 1}, "populationCount": {"$sum": "$pop_served"}}}, {"$group": {"_id": "$_id." + field, "waterpoints": { "$push": { "status": "$_id.status", "count": "$statusCount", "population": "$populationCount", }, }, "count": {"$sum": "$statusCount"}}}, {"$project": {"_id": 0, field: "$_id", "waterpoints": 1, "population": 1, "count": 1}}, {"$sort": {field: 1}}])['result'],))
def waterpoint_requests(): "Return the unique values for a given field in the waterpoints collection." # FIXME: Direct call to the PyMongo driver, should be abstracted reqs = app.data.driver.db['requests'].find( {'status': 'open'}, ['attribute.waterpoint_id']) return send_response('requests', (reqs.distinct('attribute.waterpoint_id'),))
def waterpoint_status(): "Return number of waterpoints grouped by status." # FIXME: Direct call to the PyMongo driver, should be abstracted resources = app.data.driver.db['resources'] return send_response('resources', (resources.group( ['status_group'], dict(request.args.items()), initial={'count': 0}, reduce="function(curr, result) {result.count++;}"),))
def waterpoint_count_by(field): "Return number of waterpoints grouped a given field." # FIXME: Direct call to the PyMongo driver, should be abstracted resources = app.data.driver.db['resources'] return send_response('resources', (resources.group( field.split(','), dict(request.args.items()), initial={'count': 0}, reduce="function(curr, result) {result.count++;}"),))
def xml_collections_endpoint(**lookup): resource = _resource() response = None method = request_method() if request.content_type.endswith("/xml"): if method == "POST": # response = post(resource, payl=xml2json(request.data)) response = post_internal(resource, payl=xml2json(request.data), skip_validation=True) elif method == "GET": response = collections_endpoint(**lookup) l = json.loads(response.data.decode('utf-8'))['_items'] response.data = xmltodict.unparse({ 'gdxp': { "supplier": list(map(popper, l)) } }) else: raise NotImplementedError('Not implemented') return send_response(resource, response) else: return collections_endpoint(**lookup)
def error_endpoint(error): """ Response returned when an error is raised by the API (e.g. my means of an abort(4xx). """ headers = [] try: headers.append(error.response.headers) except AttributeError: pass try: if error.www_authenticate != (None, ): headers.append(error.www_authenticate) except AttributeError: pass response = { config.STATUS: config.STATUS_ERR, config.ERROR: { "code": error.code, "message": error.description }, } return send_response(None, (response, None, None, error.code, headers))
def assert_error_handler(error): print('error', error) return send_response( None, ({ 'code': 400, 'error': str(error) if str(error) else 'assert' }, None, None, 400))
def client_error_handler(error): """Return json error response. :param error: an instance of :attr:`superdesk.SuperdeskError` class """ return send_response(None, (error.to_dict(), None, None, error.status_code))
def locales_view(): if not flask.current_app.auth.authorized([], 'locales', 'GET'): flask.abort(401) resp = None if flask.request.method == 'GET': resp = {'timezones': get_timezones()} return send_response(None, (resp, None, None, 200))
def resource_sum(group, field): """ Return sum of a given field per group. """ fields = field.split(',') params = dict(request.args.items()) fmt = params.pop('fmt', None) # FIXME: Direct call to the PyMongo driver, should be abstracted data = app.data.driver.db['resources'].aggregate([ { "$match": params }, { "$group": { "_id": '$' + group, "sum": {'$sum': {'$add': ['$' + f for f in fields] }}, } }, {"$sort": {group: 1}}])['result'] if fmt == 'csv': headers = { 'Content-Type': 'text/csv', 'Content-Disposition': 'attachment; filename="sum_%s-%s.csv"' %(field, group) } return Response(csv_dictwritter(data), mimetype='text/csv', headers=headers) if fmt == 'csv': headers = { 'Content-Type': 'text/csv', 'Content-Disposition': 'attachment; filename="sum_%s-%s.csv"' %(field, group) } return Response(csv_dictwritter(data), mimetype='text/csv', headers=headers) return send_response('resources', [data])
def home_endpoint(): """ Home/API entry point. Will provide links to each available resource .. versionchanged:: 0.5 Resource URLs are relative to API root. Don't list internal resources. .. versionchanged:: 0.4 Prevent versioning collections from being added in links. .. versionchanged:: 0.2 Use new 'resource_title' setting for link titles. .. versionchanged:: 0.1.0 Support for optional HATEOAS. """ response = {} if config.INFO: info = {} info["server"] = "Eve" info["version"] = eve.__version__ if config.API_VERSION: info["api_version"] = config.API_VERSION response[config.INFO] = info if config.HATEOAS: links = [] for resource in config.DOMAIN.keys(): internal = config.DOMAIN[resource]["internal_resource"] if not resource.endswith(config.VERSIONS): if not bool(internal): links.append({ "href": "%s" % config.URLS[resource], "title": "%s" % config.DOMAIN[resource]["resource_title"], }) if config.SCHEMA_ENDPOINT is not None: links.append({ "href": "%s" % config.SCHEMA_ENDPOINT, "title": "%s" % config.SCHEMA_ENDPOINT, }) response[config.LINKS] = {"child": links} return send_response(None, (response, )) else: return send_response(None, (response, ))
def get_subjectcodes(): from .iptc import subject_codes items = [] for code in sorted(subject_codes): items.append({'qcode': code, 'name': subject_codes[code]}) return send_response(None, ({'_items': items}, datetime(2012, 7, 10), None, 200))
def get_subjectcodes(): from .iptc import subject_codes items = [] for code in sorted(subject_codes): items.append({'code': code, 'name': subject_codes[code]}) return send_response(None, ({'_items': items}, datetime(2012, 7, 10), None, 200))
def performance(group): """ Return performance stats. """ # FIXME: Direct call to the PyMongo driver, should be abstracted # TODO: Provide generic implementation to allow more dynamic grouping params = dict(request.args.items()) fmt = params.pop('fmt', None) data = app.data.driver.db['resources'].aggregate( [ { "$match": params }, { "$group": { "_id": '$' + group, "numberPass": {'$sum': '$number_pass'}, "numberPassLast": {'$sum': '$number_pass_last'}, "numberPassBeforeLast": {'$sum': '$number_pass_before_last'}, "candidates": {'$sum': '$candidates'}, "candidatesLast": {'$sum': '$candidates_last'}, "candidatesBeforeLast": {'$sum': '$candidates_before_last'} } }, { "$project": { "_id": 0, group: "$_id", "numberPass": 1, "numberPassLast": 1, "numberPassBeforeLast": 1, "candidates": 1, "candidatesLast": 1, "candidatesBeforeLast": 1, "percentPass": { '$cond': {'if': { '$ne': [ "$candidates", 0 ] }, 'then': {'$multiply': [{'$divide': ['$numberPass', '$candidates']}, 100]}, 'else': None }}, "percentPassLast": { '$cond': {'if': { '$ne': [ "$candidatesLast", 0 ] }, 'then': {'$multiply': [{'$divide': ['$numberPassLast', '$candidatesLast']}, 100]}, 'else': None }}, "percentPassBeforeLast": { '$cond': {'if': { '$ne': [ "$candidatesBeforeLast", 0 ] }, 'then': {'$multiply': [{'$divide': ['$numberPassBeforeLast', '$candidatesBeforeLast']}, 100]}, 'else': None }} } }, {"$sort": {group: 1}} ])['result'] if fmt == 'csv': headers = { 'Content-Type': 'text/csv', 'Content-Disposition': 'attachment; filename="performance_%s.csv"' %group } return Response(csv_dictwritter(data), mimetype='text/csv', headers=headers) return send_response('resources', [data])
def get_cities(country_code=None, state_code=None): """ Fetches cities and sends the list as response body. :param country_code: Country Code as defined in the locators.json file. For example, AU for Australia, NZ for New Zealand. :param state_code: State Code as defined in the locators.json file. For example, VIC for Victoria, NV for Nevada. :return: Returns HTTP Response with body {'_items': cities, '_meta': {'total': City Count}}. """ cities = app.locators.find_cities(country_code=country_code, state_code=state_code) if cities and len(cities): response_data = {"_items": cities, "_meta": {"total": len(cities)}} return send_response(None, (response_data, utcnow(), None, 200)) else: return send_response(None, ({}, utcnow(), None, 404))
def schema_item_endpoint(resource): """ This endpoint is active when SCHEMA_ENDPOINT != None. It returns the requested resource's schema definition in JSON format. """ resource_config = app.config["DOMAIN"].get(resource) if not resource_config or resource_config.get("internal_resource") is True: return abort(404) return send_response(None, (resource_config["schema"], ))
def schema_item_endpoint(resource): """ This endpoint is active when SCHEMA_ENDPOINT != None. It returns the requested resource's schema definition in JSON format. """ resource_config = app.config['DOMAIN'].get(resource) if not resource_config or resource_config.get('internal_resource') is True: return abort(404) return send_response(None, (resource_config['schema'],))
def error_handler(error): """Return json error response. :param error: an instance of :attr:`superdesk.SuperdeskError` class """ return send_response( None, (error.to_dict(), None, None, error.status_code) )
def get_cities(country_code=None, state_code=None): """ Fetches cities and sends the list as response body. :param country_code: Country Code as defined in the locators.json file. For example, AU for Australia, NZ for New Zealand. :param state_code: State Code as defined in the locators.json file. For example, VIC for Victoria, NV for Nevada. :return: Returns HTTP Response with body {'_items': cities, '_meta': {'total': City Count}}. """ cities = app.locators.find_cities(country_code=country_code, state_code=state_code) if cities and len(cities): response_data = {'_items': cities, '_meta': {'total': len(cities)}} return send_response(None, (response_data, utcnow(), None, 200)) else: return send_response(None, ({}, utcnow(), None, 404))
def get_subjectcodes(): from .iptc import subject_codes items = [] for code in sorted(subject_codes): items.append({'qcode': code, 'name': subject_codes[code]}) response_data = {'_items': items, '_meta': {'total': len(items)}} return send_response(None, (response_data, datetime(2012, 7, 10), None, 200))
def home_endpoint(): """ Home/API entry point. Will provide links to each available resource """ response = {} links = [] for resource in config.DOMAIN.keys(): links.append({'href': '%s' % resource_uri(resource), 'title': '%s' % config.URLS[resource]}) response['_links'] = {'child': links} return send_response(None, (response,))
def home_endpoint(): """ Home/API entry point. Will provide links to each available resource """ response = {} links = [] for resource in config.DOMAIN.keys(): links.append({ 'href': '%s' % resource_uri(resource), 'title': '%s' % config.URLS[resource] }) response['_links'] = {'child': links} return send_response(None, (response, ))
def view_health_func(hc, resource=None): message, status, headers = hc.run() response = ( json.loads(message), None, None, status, None, ) resp = send_response(resource, response) [resp.headers.set(k, v) for k, v in headers.items()] return resp
def error_endpoint(error): """ Response returned when an error is raised by the API (e.g. my means of an abort(4xx). .. versionadded:: 0.4 """ headers = None if error.response: headers = error.response.headers response = { config.STATUS: config.STATUS_ERR, config.ERROR: {'code': error.code, 'message': error.description}} return send_response(None, (response, None, None, error.code, headers))
def resource_total_count(): """ Return number of resources matching a given query. """ # FIXME: Direct call to the PyMongo driver, should be abstracted resources = app.data.driver.db['resources'] query = dict(request.args.items()) if query.has_key('$where'): try: query = json.loads(query['$where']) except: pass return send_response('resources', ({'count': resources.find(query).count()},))
def collections_endpoint(**lookup): """ Resource endpoint handler :param url: the url that led here .. versionchanged:: 0.3 Pass lookup query down to delete_resource, so it can properly process sub-resources. .. versionchanged:: 0.2 Relying on request.endpoint to retrieve the resource being consumed. .. versionchanged:: 0.1.1 Relying on request.path for determining the current endpoint url. .. versionchanged:: 0.0.7 Using 'utils.request_method' helper function now. .. versionchanged:: 0.0.6 Support for HEAD requests .. versionchanged:: 0.0.2 Support for DELETE resource method. """ resource = _resource() response = None method = request.method if method in ("GET", "HEAD"): response = get(resource, lookup) elif method == "POST": response = post(resource) elif method == "DELETE": response = delete(resource, lookup) elif method == "OPTIONS": send_response(resource, response) else: abort(405) return send_response(resource, response)
def item_endpoint(**lookup): """ Item endpoint handler :param url: the url that led here :param lookup: sub resource query .. versionchanged:: 0.2 Support for sub-resources. Relying on request.endpoint to retrieve the resource being consumed. .. versionchanged:: 0.1.1 Relying on request.path for determining the current endpoint url. .. versionchanged:: 0.1.0 Support for PUT method. .. versionchanged:: 0.0.7 Using 'utils.request_method' helper function now. .. versionchanged:: 0.0.6 Support for HEAD requests """ resource = _resource() response = None method = request_method() if method in ('GET', 'HEAD'): response = getitem(resource, **lookup) elif method == 'PATCH': response = patch(resource, **lookup) elif method == 'PUT': response = put(resource, **lookup) elif method == 'DELETE': response = deleteitem(resource, **lookup) elif method == 'OPTIONS': send_response(resource, response) else: abort(405) return send_response(resource, response)
def resource_download(): """ Return resources. """ params = dict(request.args.items()) fmt = params.pop('fmt', 'csv') fields = params.pop('fields', None) limit = params.pop('max_results', 1000) sort = params.pop('sort', None) search = params.pop('search', None) if sort: sort = json.loads(sort) if limit: try: limit = int(limit) if limit > 1000 or limit < 0: limit = 1000 except: limit = 1000 if fields: fields = fields.split(',') if search: params['$text'] = {'$search': '\"' + search + '\"'} # FIXME: Direct call to the PyMongo driver, should be abstracted data = list( app.data.driver.db['resources'].find( params, sort=sort).limit(limit)) if fmt == 'csv': for item in data: location = item.get('location') if location: try: item['longitude'] = location['coordinates'][0] item['latitude'] = location['coordinates'][1] item.pop('location') except: pass headers = { 'Content-Type': 'text/csv', 'Content-Disposition': 'attachment; filename="schools.csv"' } try: csvdata = csv_dictwritter(data, fields) return Response(csvdata, mimetype='text/csv', headers=headers) except: pass return send_response('resources', [data])
def home_endpoint(): """ Home/API entry point. Will provide links to each available resource .. versionchanged:: 0.1.0 Support for optional HATEOAS. """ if config.HATEOAS: response = {} links = [] for resource in config.DOMAIN.keys(): links.append({'href': '%s' % resource_uri(resource), 'title': '%s' % config.URLS[resource]}) response['_links'] = {'child': links} return send_response(None, (response,)) else: abort(404, debug_error_message("HATEOAS is disabled so we have no data" " to display at the API homepage."))
def resource_count(field): """ Return number of resources grouped a given field. """ params = dict(request.args.items()) fmt = params.pop('fmt', None) # FIXME: Direct call to the PyMongo driver, should be abstracted data = app.data.driver.db['resources'].group( field.split(','), params, initial={'count': 0}, reduce="function(curr, result) {result.count++;}") if fmt == 'csv': headers = { 'Content-Type': 'text/csv', 'Content-Disposition': 'attachment; filename="count_%s.csv"' %field } return Response(csv_dictwritter(data), mimetype='text/csv', headers=headers) return send_response('resources', [data])