aboutsummaryrefslogtreecommitdiffstats
path: root/server.py
diff options
context:
space:
mode:
authorBlake DeMarcy <ofunknowndescent@gmail.com>2017-04-02 02:35:58 -0500
committerBlake DeMarcy <ofunknowndescent@gmail.com>2017-04-02 02:35:58 -0500
commit26b6dc190733facb01edbb32d3454b4824bac4bc (patch)
tree6dc257da0ab984baea5d461205a004a8fd34de1c /server.py
parentf9e4783f7544134bfeb7db5396d09c684a7560a9 (diff)
downloadbbj-26b6dc190733facb01edbb32d3454b4824bac4bc.tar.gz
initial commit of non-prototype
Diffstat (limited to 'server.py')
-rw-r--r--server.py220
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")
Un proyecto texto-plano.xyz