diff options
author | Blake DeMarcy <ofunknowndescent@gmail.com> | 2017-04-02 02:35:58 -0500 |
---|---|---|
committer | Blake DeMarcy <ofunknowndescent@gmail.com> | 2017-04-02 02:35:58 -0500 |
commit | 26b6dc190733facb01edbb32d3454b4824bac4bc (patch) | |
tree | 6dc257da0ab984baea5d461205a004a8fd34de1c /server.py | |
parent | f9e4783f7544134bfeb7db5396d09c684a7560a9 (diff) | |
download | bbj-26b6dc190733facb01edbb32d3454b4824bac4bc.tar.gz |
initial commit of non-prototype
Diffstat (limited to 'server.py')
-rw-r--r-- | server.py | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/server.py b/server.py new file mode 100644 index 0000000..957d23b --- /dev/null +++ b/server.py @@ -0,0 +1,220 @@ +from src.exceptions import BBJException, BBJParameterError +from src import db, schema, endpoints +from functools import wraps +import cherrypy +import sqlite3 +import json + +dbname = "data.sqlite" + +with sqlite3.connect(dbname) as _c: + if not db.user_resolve(_c, "anonymous"): + db.user_register(_c, *db.anonymous) + + +# creates a database connection for each thread +def connect(_): + cherrypy.thread_data.db = sqlite3.connect(dbname) +cherrypy.engine.subscribe('start_thread', connect) + + +def bbjapi(function): + """ + A wrapper that handles encoding of objects and errors to a + standard format for the API, resolves and authorizes users + from header data, and prepares thread data to handle the + request. + + In addition, all BBJException's will return their attached + schema, and unhandled exceptions return a code 1 error schema. + """ + @wraps(function) + def wrapper(*args, **kwargs): + headers = cherrypy.request.headers + username = headers.get("User") + auth = headers.get("Auth") + anon = False + + if not username and not auth: + user = db.user_resolve(cherrypy.thread_data.db, "anonymous") + anon = True + elif not username or not auth: + return json.dumps(schema.error(5, + "User or Auth was given without the other.")) + + if not anon: + user = db.user_resolve(cherrypy.thread_data.db, username) + if not user: + return json.dumps(schema.error(4, + "Username is not registered.")) + + elif auth != user["auth_hash"]: + return json.dumps(schema.error(5, + "Invalid authorization key for user.")) + + cherrypy.thread_data.user = user + cherrypy.thread_data.anon = anon + + try: + value = function(*args, **kwargs) + + except BBJException as e: + value = e.schema + + except Exception as e: + value = schema.error(1, str(e)) + + return json.dumps(value) + return wrapper + + +def create_usermap(connection, obj): + """ + Creates a mapping of all the user_ids that occur in OBJ to + their full user objects (names, profile info, etc). Can + be a thread_index or a messages object from one. + """ + + if isinstance(obj, dict): + # this is a message object for a thread, unravel it + obj = [value for key, value in obj.items()] + + return { + user_id: db.user_resolve( + connection, + user_id, + externalize=True, + return_false=False) + for user_id in { + item["author"] for item in obj + } + } + + + +def validate(json, args): + """ + Ensure the json object contains all the keys needed to satisfy + its endpoint. + """ + for arg in args: + if arg not in json.keys(): + raise BBJParameterError( + "Required parameter %s is " + "absent from the request." % arg) + + +APICONFIG = { + "/": { + "tools.response_headers.on": True, + "tools.response_headers.headers": [ + ("Content-Type", "application/json") + ], + } +} + +class API(object): + @bbjapi + @cherrypy.expose + def thread_index(self): + threads = db.thread_index(cherrypy.thread_data.db) + usermap = create_usermap(cherrypy.thread_data.db, threads) + return schema.response({ + "data": threads, + "usermap": usermap + }) + + + @bbjapi + @cherrypy.expose + @cherrypy.tools.json_in() + def thread_create(self): + args = cherrypy.request.json + validate(args, ["body", "title"]) + + thread = db.thread_create( + cherrypy.thread_data.db, + cherrypy.thread_data.user["user_id"], + args["body"], args["title"]) + + usermap = { + cherrypy.thread_data.user["user_id"]: + cherrypy.thread_data.user + } + + return schema.response({ + "data": thread, + "usermap": usermap + }) + + + @bbjapi + @cherrypy.expose + @cherrypy.tools.json_in() + def thread_reply(self): + args = cherrypy.request.json + validate(args, ["thread_id", "body"]) + return schema.response({ + "data": db.thread_reply( + cherrypy.thread_data.db, + cherrypy.thread_data.user["user_id"], + args["thread_id"], args["body"]) + }) + + + @bbjapi + @cherrypy.expose + @cherrypy.tools.json_in() + def thread_load(self): + args = cherrypy.request.json + validate(args, ["thread_id"]) + + thread = db.thread_get( + cherrypy.thread_data.db, + args["thread_id"]) + + usermap = create_usermap( + cherrypy.thread_data.db, + thread["messages"]) + + return schema.response({ + "data": thread, + "usermap": usermap + }) + + + @bbjapi + @cherrypy.expose + @cherrypy.tools.json_in() + def user_register(self): + args = cherrypy.request.json + validate(args, ["user_name", "auth_hash"]) + return schema.response({ + "data": db.user_register( + cherrypy.thread_data.db, + args["user_name"], args["auth_hash"]) + }) + + + @bbjapi + @cherrypy.expose + @cherrypy.tools.json_in() + def edit_query(self): + args = cherrypy.request.json + validate(args, ["thread_id", "post_id"]) + return schema.response({ + "data": message_edit_query( + cherrypy.thread_data.db, + cherrypy.thread_data.user["user_id"], + args["thread_id"], + args["post_id"]) + }) + + + +def run(): + cherrypy.quickstart(API(), "/api") + + +if __name__ == "__main__": + print("wew") |