def api_query(table, id = None): #if censored_table(table): # return flask.abort(404) # parsing the meta parameters _format and _offset format = request.args.get("_format", "html") offset = int(request.args.get("_offset", 0)) DELIM = request.args.get("_delim", ",") fields = request.args.get("_fields", None) sortby = request.args.get("_sort", None) if fields: fields = ['id'] + fields.split(DELIM) else: fields = 1.1 if sortby: sortby = sortby.split(DELIM) if offset > 10000: if format != "html": flask.abort(404) else: flash_error("offset %s too large, please refine your query.", offset) return flask.redirect(url_for(".api_query", table=table)) # preparing the actual database query q try: coll = getattr(db, table) except AttributeError: if format != "html": flask.abort(404) else: flash_error("table %s does not exist", table) return flask.redirect(url_for(".index")) q = {} # if id is set, just go and get it, ignore query parameeters if id is not None: if offset: return flask.abort(404) single_object = True api_logger.info("API query: id = '%s', fields = '%s'" % (id, fields)) if re.match(r'^\d+$', id): id = int(id) data = coll.lucky({'id':id}, projection=fields) data = [data] if data else [] else: single_object = False for qkey, qval in request.args.iteritems(): from ast import literal_eval try: if qkey.startswith("_"): continue elif qval.startswith("s"): qval = qval[1:] elif qval.startswith("i"): qval = int(qval[1:]) elif qval.startswith("f"): qval = float(qval[1:]) elif qval.startswith("o"): qval = ObjectId(qval[1:]) elif qval.startswith("ls"): # indicator, that it might be a list of strings qval = qval[2].split(DELIM) elif qval.startswith("li"): print qval qval = [int(_) for _ in qval[2:].split(DELIM)] print qval elif qval.startswith("lf"): qval = [float(_) for _ in qval[2:].split(DELIM)] elif qval.startswith("py"): # literal evaluation qval = literal_eval(qval[2:]) elif qval.startswith("cs"): # containing string in list qval = { "$contains" : [qval[2:]] } elif qval.startswith("ci"): qval = { "$contains" : [int(qval[2:])] } elif qval.startswith("cf"): qval = { "contains" : [float(qval[2:])] } elif qval.startswith("cpy"): qval = { "$contains" : [literal_eval(qval[3:])] } except: # no suitable conversion for the value, keep it as string pass # update the query q[qkey] = qval # assure that one of the keys of the query is indexed # however, this doesn't assure that the query will be fast... #if q != {} and len(set(q.keys()).intersection(collection_indexed_keys(coll))) == 0: # flash_error("no key in the query %s is indexed.", q) # return flask.redirect(url_for(".api_query", table=table)) # sort = [('fieldname1', 1 (ascending) or -1 (descending)), ...] if sortby is not None: sort = [] for key in sortby: if key.startswith("-"): sort.append((key[1:], -1)) else: sort.append((key, 1)) else: sort = None # executing the query "q" and replacing the _id in the result list api_logger.info("API query: q = '%s', fields = '%s', sort = '%s', offset = %s" % (q, fields, sort, offset)) try: data = list(coll.search(q, projection=fields, sort=sort, limit=100, offset=offset)) except QueryCanceledError: flash_error("Query %s exceeded time limit.", q) return flask.redirect(url_for(".api_query", table=table)) except KeyError, err: flash_error("No key %s in table %s", err, table) return flask.redirect(url_for(".api_query", table=table))
def api_query(table, id = None): #if censored_table(table): # return abort(404) # parsing the meta parameters _format and _offset format = request.args.get("_format", "html") offset = int(request.args.get("_offset", 0)) DELIM = request.args.get("_delim", ",") fields = request.args.get("_fields", None) sortby = request.args.get("_sort", None) if fields: fields = ['id'] + fields.split(DELIM) else: fields = 3 if sortby: sortby = sortby.split(DELIM) if offset > 10000: if format != "html": return abort(404) else: flash_error("offset %s too large, please refine your query.", offset) return redirect(url_for(".api_query", table=table)) # preparing the actual database query q try: coll = getattr(db, table) except AttributeError: if format != "html": return abort(404) else: flash_error("table %s does not exist", table) return redirect(url_for(".index")) q = {} # if id is set, just go and get it, ignore query parameeters if id is not None: if offset: return abort(404) single_object = True api_logger.info("API query: id = '%s', fields = '%s'" % (id, fields)) if re.match(r'^\d+$', id): id = int(id) else: return abort(404, "id '%s' must be an integer" % id) data = coll.lucky({'id':id}, projection=fields) data = [data] if data else [] else: single_object = False for qkey, qval in request.args.items(): from ast import literal_eval try: if qkey.startswith("_"): continue elif qval.startswith("s"): qval = qval[1:] elif qval.startswith("i"): qval = int(qval[1:]) elif qval.startswith("f"): qval = float(qval[1:]) elif qval.startswith("ls"): # indicator, that it might be a list of strings qval = qval[2].split(DELIM) elif qval.startswith("li"): qval = [int(_) for _ in qval[2:].split(DELIM)] elif qval.startswith("lf"): qval = [float(_) for _ in qval[2:].split(DELIM)] elif qval.startswith("py"): # literal evaluation qval = literal_eval(qval[2:]) elif qval.startswith("cs"): # containing string in list qval = { "$contains" : [qval[2:]] } elif qval.startswith("ci"): qval = { "$contains" : [int(qval[2:])] } elif qval.startswith("cf"): qval = { "contains" : [float(qval[2:])] } elif qval.startswith("cpy"): qval = { "$contains" : [literal_eval(qval[3:])] } except: # no suitable conversion for the value, keep it as string pass # update the query q[qkey] = qval # assure that one of the keys of the query is indexed # however, this doesn't assure that the query will be fast... #if q != {} and len(set(q.keys()).intersection(collection_indexed_keys(coll))) == 0: # flash_error("no key in the query %s is indexed.", q) # return redirect(url_for(".api_query", table=table)) # sort = [('fieldname1', 1 (ascending) or -1 (descending)), ...] if sortby is not None: sort = [] for key in sortby: if key.startswith("-"): sort.append((key[1:], -1)) else: sort.append((key, 1)) else: sort = None # executing the query "q" and replacing the _id in the result list # So as not to preserve backwards compatibility (see test_api_usage() test) if table=='ec_curvedata': for oldkey, newkey in zip(['label', 'iso', 'number'], ['Clabel', 'Ciso', 'Cnumber']): if oldkey in q: q[newkey] = q[oldkey] q.pop(oldkey) try: data = list(coll.search(q, projection=fields, sort=sort, limit=100, offset=offset)) except QueryCanceledError: flash_error("Query %s exceeded time limit.", q) return redirect(url_for(".api_query", table=table)) except KeyError as err: flash_error("No key %s in table %s", err, table) return redirect(url_for(".api_query", table=table)) except ValueError as err: flash_error(str(err)) return redirect(url_for(".api_query", table=table)) if single_object and not data: if format != 'html': return abort(404) else: flash_error("no document with id %s found in table %s.", id, table) return redirect(url_for(".api_query", table=table)) # fixup data for display and json/yaml encoding if 'bytea' in coll.col_type.values(): for row in data: for key, val in row.items(): if type(val) == buffer: row[key] = "[binary data]" #data = [ dict([ (key, val if coll.col_type[key] != 'bytea' else "binary data") for key, val in row.items() ]) for row in data] data = Json.prep(data) # preparing the datastructure start = offset next_req = dict(request.args) next_req["_offset"] = offset url_args = next_req.copy() query = url_for(".api_query", table=table, **next_req) offset += len(data) next_req["_offset"] = offset next = url_for(".api_query", table=table, **next_req) # the collected result data = { "table": table, "timestamp": datetime.utcnow().isoformat(), "data": data, "start": start, "offset": offset, "query": query, "next": next, "rec_id": 'id' if coll._label_col is None else coll._label_col, } if format.lower() == "json": #return flask.jsonify(**data) # can't handle binary data if PY3: return current_app.response_class(json.dumps(data, indent=2), mimetype='application/json') else: return current_app.response_class(json.dumps(data, encoding='ISO-8859-1', indent=2), mimetype='application/json') elif format.lower() == "yaml": y = yaml.dump(data, default_flow_style=False, canonical=False, allow_unicode=True) return Response(y, mimetype='text/plain') else: # sort displayed records by key (as jsonify and yaml_dump do) data["pretty"] = pretty_document location = table title = "API - " + location bc = [("API", url_for(".index")), (table,)] query_unquote = unquote(data["query"]) return render_template("collection.html", title=title, single_object=single_object, query_unquote = query_unquote, url_args = url_args, bread=bc, **data)
def api_query(db, collection, id=None): if censored_db(db) or censored_collection(collection): return flask.abort(404) # parsing the meta parameters _format and _offset format = request.args.get("_format", "html") offset = int(request.args.get("_offset", 0)) DELIM = request.args.get("_delim", ",") fields = request.args.get("_fields", None) sortby = request.args.get("_sort", None) if fields: fields = fields.split(DELIM) if sortby: sortby = sortby.split(DELIM) if offset > 10000: if format != "html": flask.abort(404) else: flash_error("offset %s too large, please refine your query.", offset) return flask.redirect( url_for(".api_query", db=db, collection=collection)) # preparing the actual database query q C = base.getDBConnection() q = {} # if id is set, just go and get it, ignore query parameeters if id is not None: if offset: return flask.abort(404) single_object = True data = [] api_logger.info("API query: id = '%s', fields = '%s'" % (id, fields)) # if id looks like an ObjectId, assume it is and try to find it if len(id) == 24 and re.match('[0-9a-f]+$', id.strip()): data = C[db][collection].find_one({'_id': ObjectId(id)}, projection=fields) if not data: data = C[db][collection].find_one({'_id': id}, projection=fields) data = [data] if data else [] else: single_object = False for qkey, qval in request.args.iteritems(): from ast import literal_eval try: if qkey.startswith("_"): continue elif qval.startswith("s"): qval = qval[1:] elif qval.startswith("i"): qval = int(qval[1:]) elif qval.startswith("f"): qval = float(qval[1:]) elif qval.startswith("o"): qval = ObjectId(qval[1:]) elif qval.startswith( "ls"): # indicator, that it might be a list of strings qval = qval[2:].split(DELIM) elif qval.startswith("li"): qval = [int(_) for _ in qval[2:].split(DELIM)] elif qval.startswith("lf"): qval = [float(_) for _ in qval[2:].split(DELIM)] elif qval.startswith("py"): # literal evaluation qval = literal_eval(qval[2:]) elif qval.startswith("cs"): # containing string in list qval = {"$in": [qval[2:]]} elif qval.startswith("ci"): qval = {"$in": [int(qval[2:])]} elif qval.startswith("cf"): qval = {"$in": [float(qval[2:])]} elif qval.startswith("cpy"): qval = {"$in": [literal_eval(qval[3:])]} except: # no suitable conversion for the value, keep it as string pass # update the query q[qkey] = qval # assure that one of the keys of the query is indexed # however, this doesn't assure that the query will be fast... if q != {} and len( set(q.keys()).intersection( collection_indexed_keys(C[db][collection]))) == 0: flash_error("no key in the query %s is indexed.", q) return flask.redirect( url_for(".api_query", db=db, collection=collection)) # sort = [('fieldname1', ASC/DESC), ...] if sortby is not None: sort = [] for key in sortby: if key.startswith("-"): sort.append((key[1:], DESC)) else: sort.append((key, ASC)) else: sort = None # executing the query "q" and replacing the _id in the result list api_logger.info( "API query: q = '%s', fields = '%s', sort = '%s', offset = %s" % (q, fields, sort, offset)) from pymongo.errors import ExecutionTimeout try: data = list(C[db][collection].find( q, projection=fields, sort=sort).skip(offset).limit(100).max_time_ms(10000)) except ExecutionTimeout: flash_error("Query %s exceeded time limit.", q) return flask.redirect( url_for(".api_query", db=db, collection=collection)) if single_object and not data: if format != 'html': flask.abort(404) else: flash_error("no document with id %s found in collection %s.%s.", id, db, collection) return flask.redirect( url_for(".api_query", db=db, collection=collection)) # fixup object ids for display and json/yaml encoding for document in data: oids_to_strings(document) # preparing the datastructure start = offset next_req = dict(request.args) next_req["_offset"] = offset url_args = next_req.copy() query = url_for(".api_query", db=db, collection=collection, **next_req) offset += len(data) next_req["_offset"] = offset next = url_for(".api_query", db=db, collection=collection, **next_req) # the collected result data = { "database": db, "collection": collection, "timestamp": datetime.utcnow().isoformat(), "data": data, "start": start, "offset": offset, "query": query, "next": next } if format.lower() == "json": #return flask.jsonify(**data) # can't handle binary data return current_app.response_class(json.dumps( data, encoding='ISO-8859-1', indent=2, default=json_util.default), mimetype='application/json') elif format.lower() == "yaml": y = yaml.dump(data, default_flow_style=False, canonical=False, allow_unicode=True) return flask.Response(y, mimetype='text/plain') else: # sort displayed records by key (as jsonify and yaml_dump do) data["pretty"] = pretty_document location = "%s/%s" % (db, collection) title = "API - " + location bc = [("API", url_for(".index")), (location, query)] query_unquote = urllib2.unquote(data["query"]) return render_template("collection.html", title=title, single_object=single_object, query_unquote=query_unquote, url_args=url_args, oid_strip=oid_strip, bread=bc, **data)
def api_query(table, id=None): #if censored_table(table): # return flask.abort(404) # parsing the meta parameters _format and _offset format = request.args.get("_format", "html") offset = int(request.args.get("_offset", 0)) DELIM = request.args.get("_delim", ",") fields = request.args.get("_fields", None) sortby = request.args.get("_sort", None) if fields: fields = ['id'] + fields.split(DELIM) else: fields = 3 if sortby: sortby = sortby.split(DELIM) if offset > 10000: if format != "html": flask.abort(404) else: flash_error("offset %s too large, please refine your query.", offset) return flask.redirect(url_for(".api_query", table=table)) # preparing the actual database query q try: coll = getattr(db, table) except AttributeError: if format != "html": flask.abort(404) else: flash_error("table %s does not exist", table) return flask.redirect(url_for(".index")) q = {} # if id is set, just go and get it, ignore query parameeters if id is not None: if offset: return flask.abort(404) single_object = True api_logger.info("API query: id = '%s', fields = '%s'" % (id, fields)) if re.match(r'^\d+$', id): id = int(id) data = coll.lucky({'id': id}, projection=fields) data = [data] if data else [] else: single_object = False for qkey, qval in request.args.iteritems(): from ast import literal_eval try: if qkey.startswith("_"): continue elif qval.startswith("s"): qval = qval[1:] elif qval.startswith("i"): qval = int(qval[1:]) elif qval.startswith("f"): qval = float(qval[1:]) elif qval.startswith( "ls"): # indicator, that it might be a list of strings qval = qval[2].split(DELIM) elif qval.startswith("li"): print qval qval = [int(_) for _ in qval[2:].split(DELIM)] print qval elif qval.startswith("lf"): qval = [float(_) for _ in qval[2:].split(DELIM)] elif qval.startswith("py"): # literal evaluation qval = literal_eval(qval[2:]) elif qval.startswith("cs"): # containing string in list qval = {"$contains": [qval[2:]]} elif qval.startswith("ci"): qval = {"$contains": [int(qval[2:])]} elif qval.startswith("cf"): qval = {"contains": [float(qval[2:])]} elif qval.startswith("cpy"): qval = {"$contains": [literal_eval(qval[3:])]} except: # no suitable conversion for the value, keep it as string pass # update the query q[qkey] = qval # assure that one of the keys of the query is indexed # however, this doesn't assure that the query will be fast... #if q != {} and len(set(q.keys()).intersection(collection_indexed_keys(coll))) == 0: # flash_error("no key in the query %s is indexed.", q) # return flask.redirect(url_for(".api_query", table=table)) # sort = [('fieldname1', 1 (ascending) or -1 (descending)), ...] if sortby is not None: sort = [] for key in sortby: if key.startswith("-"): sort.append((key[1:], -1)) else: sort.append((key, 1)) else: sort = None # executing the query "q" and replacing the _id in the result list api_logger.info( "API query: q = '%s', fields = '%s', sort = '%s', offset = %s" % (q, fields, sort, offset)) try: data = list( coll.search(q, projection=fields, sort=sort, limit=100, offset=offset)) except QueryCanceledError: flash_error("Query %s exceeded time limit.", q) return flask.redirect(url_for(".api_query", table=table)) except KeyError, err: flash_error("No key %s in table %s", err, table) return flask.redirect(url_for(".api_query", table=table))
def api_query(db, collection, id = None): if censored_db(db) or censored_collection(collection): return flask.abort(404) # parsing the meta parameters _format and _offset format = request.args.get("_format", "html") offset = int(request.args.get("_offset", 0)) DELIM = request.args.get("_delim", ",") fields = request.args.get("_fields", None) sortby = request.args.get("_sort", None) if fields: fields = fields.split(DELIM) if sortby: sortby = sortby.split(DELIM) if offset > 10000: if format != "html": flask.abort(404) else: flash_error("offset %s too large, please refine your query.", offset) return flask.redirect(url_for(".api_query", db=db, collection=collection)) # preparing the actual database query q C = base.getDBConnection() q = {} # if id is set, just go and get it, ignore query parameeters if id is not None: if offset: return flask.abort(404) single_object = True data = [] api_logger.info("API query: id = '%s', fields = '%s'" % (id, fields)) # if id looks like an ObjectId, assume it is and try to find it if len(id) == 24 and re.match('[0-9a-f]+$', id.strip()): data = C[db][collection].find_one({'_id':ObjectId(id)},projection=fields) if not data: data = C[db][collection].find_one({'_id':id},projection=fields) data = [data] if data else [] else: single_object = False for qkey, qval in request.args.iteritems(): from ast import literal_eval try: if qkey.startswith("_"): continue elif qval.startswith("s"): qval = qval[1:] elif qval.startswith("i"): qval = int(qval[1:]) elif qval.startswith("f"): qval = float(qval[1:]) elif qval.startswith("o"): qval = ObjectId(qval[1:]) elif qval.startswith("ls"): # indicator, that it might be a list of strings qval = qval[2:].split(DELIM) elif qval.startswith("li"): qval = [int(_) for _ in qval[2:].split(DELIM)] elif qval.startswith("lf"): qval = [float(_) for _ in qval[2:].split(DELIM)] elif qval.startswith("py"): # literal evaluation qval = literal_eval(qval[2:]) elif qval.startswith("cs"): # containing string in list qval = { "$in" : [qval[2:]] } elif qval.startswith("ci"): qval = { "$in" : [int(qval[2:])] } elif qval.startswith("cf"): qval = { "$in" : [float(qval[2:])] } elif qval.startswith("cpy"): qval = { "$in" : [literal_eval(qval[3:])] } except: # no suitable conversion for the value, keep it as string pass # update the query q[qkey] = qval # assure that one of the keys of the query is indexed # however, this doesn't assure that the query will be fast... if q != {} and len(set(q.keys()).intersection(collection_indexed_keys(C[db][collection]))) == 0: flash_error("no key in the query %s is indexed.", q) return flask.redirect(url_for(".api_query", db=db, collection=collection)) # sort = [('fieldname1', ASC/DESC), ...] if sortby is not None: sort = [] for key in sortby: if key.startswith("-"): sort.append((key[1:], DESC)) else: sort.append((key, ASC)) else: sort = None # executing the query "q" and replacing the _id in the result list api_logger.info("API query: q = '%s', fields = '%s', sort = '%s', offset = %s" % (q, fields, sort, offset)) from pymongo.errors import ExecutionTimeout try: data = list(C[db][collection].find(q, projection = fields, sort=sort).skip(offset).limit(100).max_time_ms(10000)) except ExecutionTimeout: flash_error("Query %s exceeded time limit.", q) return flask.redirect(url_for(".api_query", db=db, collection=collection)) if single_object and not data: if format != 'html': flask.abort(404) else: flash_error("no document with id %s found in collection %s.%s.", id, db, collection) return flask.redirect(url_for(".api_query", db=db, collection=collection)) # fixup object ids for display and json/yaml encoding for document in data: oids_to_strings(document) # preparing the datastructure start = offset next_req = dict(request.args) next_req["_offset"] = offset url_args = next_req.copy() query = url_for(".api_query", db=db, collection=collection, **next_req) offset += len(data) next_req["_offset"] = offset next = url_for(".api_query", db=db, collection=collection, **next_req) # the collected result data = { "database": db, "collection": collection, "timestamp": datetime.utcnow().isoformat(), "data": data, "start": start, "offset": offset, "query": query, "next": next } if format.lower() == "json": #return flask.jsonify(**data) # can't handle binary data return current_app.response_class(json.dumps(data, encoding='ISO-8859-1', indent=2, default=json_util.default), mimetype='application/json') elif format.lower() == "yaml": y = yaml.dump(data, default_flow_style=False, canonical=False, allow_unicode=True) return flask.Response(y, mimetype='text/plain') else: # sort displayed records by key (as jsonify and yaml_dump do) data["pretty"] = pretty_document location = "%s/%s" % (db, collection) title = "API - " + location bc = [("API", url_for(".index")), (location, query)] query_unquote = urllib2.unquote(data["query"]) return render_template("collection.html", title=title, single_object=single_object, query_unquote = query_unquote, url_args = url_args, oid_strip = oid_strip, bread=bc, **data)
def api_query(db, collection, id = None): init_database_info() # check what is queried for if db not in _databases or collection not in pluck(0, _databases[db]): return flask.abort(404) # parsing the meta parameters _format and _offset format = request.args.get("_format", "html") offset = int(request.args.get("_offset", 0)) DELIM = request.args.get("_delim", ",") fields = request.args.get("_fields", None) sortby = request.args.get("_sort", None) if fields: fields = fields.split(DELIM) if sortby: sortby = sortby.split(DELIM) if offset > 10000: if format != "html": flask.abort(404) else: flask.flash("offset too large, please refine your query.", "error") return flask.redirect(url_for(".api_query", db=db, collection=collection)) # sort = [('fieldname1', ASC/DESC), ...] if sortby is not None: sort = [] for key in sortby: if key.startswith("-"): sort.append((key[1:], DESC)) else: sort.append((key, ASC)) else: sort = None # preparing the actual database query q C = base.getDBConnection() q = {} if id is not None: if id.startswith('ObjectId('): q["_id"] = ObjectId(id[10:-2]) else: q["_id"] = id single_object = True else: single_object = False for qkey, qval in request.args.iteritems(): from ast import literal_eval try: if qkey.startswith("_"): continue if qval.startswith("s"): qval = qval[1:] if qval.startswith("i"): qval = int(qval[1:]) elif qval.startswith("f"): qval = float(qval[1:]) elif qval.startswith("ls"): # indicator, that it might be a list of strings qval = qval[2:].split(DELIM) elif qval.startswith("li"): qval = [int(_) for _ in qval[2:].split(DELIM)] elif qval.startswith("lf"): qval = [float(_) for _ in qval[2:].split(DELIM)] elif qval.startswith("py"): # literal evaluation qval = literal_eval(qval[2:]) elif qval.startswith("cs"): # containing string in list qval = { "$in" : [qval[2:]] } elif qval.startswith("ci"): qval = { "$in" : [int(qval[2:])] } elif qval.startswith("cf"): qval = { "$in" : [float(qval[2:])] } elif qval.startswith("cpy"): qval = { "$in" : [literal_eval(qval[3:])] } except: # no suitable conversion for the value, keep it as string pass # update the query q[qkey] = qval # executing the query "q" and replacing the _id in the result list api_logger.info("API query: q = '%s', fields = '%s', sort = '%s', offset = %s" % (q, fields, sort, offset)) data = list(C[db][collection].find(q, projection = fields, sort=sort).skip(offset).limit(100)) for document in data: oid = document["_id"] if type(oid) == ObjectId: document["_id"] = "ObjectId('%s')" % oid elif isinstance(oid, basestring): document["_id"] = str(oid) # preparing the datastructure start = offset next_req = dict(request.args) next_req["_offset"] = offset url_args = next_req.copy() query = url_for(".api_query", db=db, collection=collection, **next_req) offset += len(data) next_req["_offset"] = offset next = url_for(".api_query", db=db, collection=collection, **next_req) # the collected result data = { "database": db, "collection": collection, "timestamp": datetime.utcnow().isoformat(), "data": data, "start": start, "offset": offset, "query": query, "next": next } # display of the result (default html) if format.lower() == "json": return flask.jsonify(**data) elif format.lower() == "yaml": y = yaml.dump(data, default_flow_style=False, canonical=False, allow_unicode=True) return flask.Response(y, mimetype='text/plain') else: location = "%s/%s" % (db, collection) title = "API - " + location bc = [("API", url_for(".index")), (location, query)] query_unquote = urllib2.unquote(data["query"]) return render_template("collection.html", title=title, single_object=single_object, query_unquote = query_unquote, url_args = url_args, bread=bc, **data)
def api_query(db, collection, id = None): init_database_info() # check what is queried for if db not in _databases or collection not in pluck(0, _databases[db]): return flask.abort(404) # parsing the meta parameters _format and _offset format = request.args.get("_format", "html") offset = int(request.args.get("_offset", 0)) DELIM = request.args.get("_delim", ",") fields = request.args.get("_fields", None) sortby = request.args.get("_sort", None) if fields: fields = fields.split(DELIM) if sortby: sortby = sortby.split(DELIM) if offset > 10000: if format != "html": flask.abort(404) else: flask.flash("offset too large, please refine your query.", "error") return flask.redirect(url_for(".api_query", db=db, collection=collection)) # sort = [('fieldname1', ASC/DESC), ...] if sortby is not None: sort = [] for key in sortby: if key.startswith("-"): sort.append((key[1:], DESC)) else: sort.append((key, ASC)) else: sort = None # preparing the actual database query q C = base.getDBConnection() q = {} if id is not None: if id.startswith('ObjectId('): q["_id"] = ObjectId(id[10:-2]) else: q["_id"] = id single_object = True else: single_object = False for qkey, qval in request.args.iteritems(): from ast import literal_eval try: if qkey.startswith("_"): continue if qval.startswith("s"): qval = qval[1:] if qval.startswith("i"): qval = int(qval[1:]) elif qval.startswith("f"): qval = float(qval[1:]) elif qval.startswith("ls"): # indicator, that it might be a list of strings qval = qval[2:].split(DELIM) elif qval.startswith("li"): qval = [int(_) for _ in qval[2:].split(DELIM)] elif qval.startswith("lf"): qval = [float(_) for _ in qval[2:].split(DELIM)] elif qval.startswith("py"): # literal evaluation qval = literal_eval(qval[2:]) elif qval.startswith("cs"): # containing string in list qval = { "$in" : [qval[2:]] } elif qval.startswith("ci"): qval = { "$in" : [int(qval[2:])] } elif qval.startswith("cf"): qval = { "$in" : [float(qval[2:])] } elif qval.startswith("cpy"): qval = { "$in" : [literal_eval(qval[3:])] } except: # no suitable conversion for the value, keep it as string pass # update the query q[qkey] = qval # executing the query "q" and replacing the _id in the result list api_logger.info("API query: q = '%s', fields = '%s', sort = '%s', offset = %s" % (q, fields, sort, offset)) data = list(C[db][collection].find(q, fields = fields, sort=sort).skip(offset).limit(100)) for document in data: oid = document["_id"] if type(oid) == ObjectId: document["_id"] = "ObjectId('%s')" % oid elif isinstance(oid, basestring): document["_id"] = str(oid) # preparing the datastructure start = offset next_req = dict(request.args) next_req["_offset"] = offset url_args = next_req.copy() query = url_for(".api_query", db=db, collection=collection, **next_req) offset += len(data) next_req["_offset"] = offset next = url_for(".api_query", db=db, collection=collection, **next_req) # the collected result data = { "database": db, "collection": collection, "timestamp": datetime.utcnow().isoformat(), "data": data, "start": start, "offset": offset, "query": query, "next": next } # display of the result (default html) if format.lower() == "json": return flask.jsonify(**data) elif format.lower() == "yaml": y = yaml.dump(data, default_flow_style=False, canonical=False, allow_unicode=True) return flask.Response(y, mimetype='text/plain') else: location = "%s/%s" % (db, collection) title = "API - " + location bc = [("API", url_for(".index")), (location, query)] query_unquote = urllib2.unquote(data["query"]) return render_template("collection.html", title=title, single_object=single_object, query_unquote = query_unquote, url_args = url_args, bread=bc, **data)