fuck commit messages

pull/4/head
Blake DeMarcy 2017-04-02 09:53:55 -05:00
parent 3640d1b1de
commit 474f13842b
3 changed files with 80 additions and 43 deletions

View File

@ -1,6 +1,8 @@
from src.exceptions import BBJException, BBJParameterError from src.exceptions import BBJException, BBJParameterError, BBJUserError
from src import db, schema, endpoints from src import db, schema
from functools import wraps from functools import wraps
from uuid import uuid1
import traceback
import cherrypy import cherrypy
import sqlite3 import sqlite3
import json import json
@ -30,12 +32,28 @@ def api_method(function):
they utilize, BBJExceptions are caught and their attached they utilize, BBJExceptions are caught and their attached
schema is dispatched to the client. All other unhandled schema is dispatched to the client. All other unhandled
exceptions will throw a code 1 back at the client and log exceptions will throw a code 1 back at the client and log
it for inspection. it for inspection. Errors related to JSON decoding are
caught as well and returned to the client as code 0.
""" """
@wraps(function) @wraps(function)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
response = None response = None
try: try:
# read in the body from the request to a string...
body = str(cherrypy.request.body.read(), "utf8")
# is it empty? not all methods require an input
if body:
# if this fucks up, we throw code 0 instead of code 1
body = json.loads(body)
if isinstance(body, dict):
# lowercase all of its keys
body = {str(key).lower(): value for key, value
in body.items()}
cherrypy.request.json = body
else:
cherrypy.request.json = None
username = cherrypy.request.headers.get("User") username = cherrypy.request.headers.get("User")
auth = cherrypy.request.headers.get("Auth") auth = cherrypy.request.headers.get("Auth")
anon = False anon = False
@ -43,12 +61,16 @@ def api_method(function):
if not username and not auth: if not username and not auth:
user = db.anon_object user = db.anon_object
anon = True anon = True
elif not username or not auth: elif not username or not auth:
return json.dumps(schema.error(5, return json.dumps(schema.error(5,
"User or Auth was given without the other.")) "User or Auth was given without the other."))
if not anon: if not anon:
user = db.user_resolve(cherrypy.thread_data.db, username) user = db.user_resolve(cherrypy.thread_data.db, username)
if not user:
raise BBJUserError("User %s is not registered" % username)
if auth != user["auth_hash"]: if auth != user["auth_hash"]:
return json.dumps(schema.error(5, return json.dumps(schema.error(5,
"Invalid authorization key for user.")) "Invalid authorization key for user."))
@ -57,14 +79,20 @@ def api_method(function):
cherrypy.thread_data.anon = anon cherrypy.thread_data.anon = anon
response = function(*args, **kwargs) response = function(*args, **kwargs)
except json.JSONDecodeError as e:
response = schema.error(0, str(e))
except BBJException as e: except BBJException as e:
response = e.schema response = e.schema
except Exception as e: except Exception as e:
response = schema.error(1, repr(e)) error_id = uuid1().hex
# TODO: use a logging file or module or something response = schema.error(1,
# repr() in this case is more verbose than just passing it in "Internal server error: code {}. Tell ~desvox (the code too)"
print(repr(e)) .format(error_id))
with open("logs/exceptions/" + error_id, "a") as log:
traceback.print_tb(e.__traceback__, file=log)
log.write(repr(e))
finally: finally:
return json.dumps(response) return json.dumps(response)
@ -99,13 +127,19 @@ def create_usermap(connection, obj):
def validate(json, args): def validate(json, args):
""" """
Ensure the json object contains all the keys needed to satisfy Ensure the json object contains all the keys needed to satisfy
its endpoint. its endpoint (and isnt empty)
""" """
if not json:
raise BBJParameterError(
"JSON input is empty. This method requires the following "
"arguments: {}".format(", ".join(args)))
for arg in args: for arg in args:
if arg not in json.keys(): if arg not in json.keys():
raise BBJParameterError( raise BBJParameterError(
"Required parameter %s is " "Required parameter {} is absent from the request. "
"absent from the request." % arg) "This method requires the following arguments: {}"
.format(arg, ", ".join(args)))
APICONFIG = { APICONFIG = {
@ -120,7 +154,7 @@ APICONFIG = {
class API(object): class API(object):
@api_method @api_method
@cherrypy.expose @cherrypy.expose
def get_me(self): def get_me(self, *args, **kwargs):
""" """
Requires no arguments. Returns your internal user object, Requires no arguments. Returns your internal user object,
including your authorization hash. including your authorization hash.
@ -129,13 +163,13 @@ class API(object):
@api_method @api_method
@cherrypy.expose @cherrypy.expose
def user_get(self): def user_get(self, *args, **kwargs):
""" """
Retreive an external user object for the given `user`. Retreive an external user object for the given `user`.
Can be a user_id or user_name. Can be a user_id or user_name.
""" """
args = cherrypy.request.json args = cherrypy.request.json
validate(["user"]) validate(args, ["user"])
return schema.response(db.user_resolve( return schema.response(db.user_resolve(
cherrypy.thread_data.db, cherrypy.thread_data.db,
args["user"], args["user"],
@ -145,7 +179,7 @@ class API(object):
@api_method @api_method
@cherrypy.expose @cherrypy.expose
def thread_index(self): def thread_index(self, *args, **kwargs):
threads = db.thread_index(cherrypy.thread_data.db) threads = db.thread_index(cherrypy.thread_data.db)
usermap = create_usermap(cherrypy.thread_data.db, threads) usermap = create_usermap(cherrypy.thread_data.db, threads)
return schema.response(threads, usermap) return schema.response(threads, usermap)
@ -153,8 +187,7 @@ class API(object):
@api_method @api_method
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_in() def thread_create(self, *args, **kwargs):
def thread_create(self):
args = cherrypy.request.json args = cherrypy.request.json
validate(args, ["body", "title"]) validate(args, ["body", "title"])
@ -173,8 +206,7 @@ class API(object):
@api_method @api_method
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_in() def thread_reply(self, *args, **kwargs):
def thread_reply(self):
args = cherrypy.request.json args = cherrypy.request.json
validate(args, ["thread_id", "body"]) validate(args, ["thread_id", "body"])
return schema.response(db.thread_reply( return schema.response(db.thread_reply(
@ -185,8 +217,7 @@ class API(object):
@api_method @api_method
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_in() def thread_load(self, *args, **kwargs):
def thread_load(self):
args = cherrypy.request.json args = cherrypy.request.json
validate(args, ["thread_id"]) validate(args, ["thread_id"])
@ -203,8 +234,7 @@ class API(object):
@api_method @api_method
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_in() def user_register(self, *args, **kwargs):
def user_register(self):
args = cherrypy.request.json args = cherrypy.request.json
validate(args, ["user_name", "auth_hash"]) validate(args, ["user_name", "auth_hash"])
return schema.response(db.user_register( return schema.response(db.user_register(
@ -215,8 +245,7 @@ class API(object):
@api_method @api_method
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_in() def edit_query(self, *args, **kwargs):
def edit_query(self):
args = cherrypy.request.json args = cherrypy.request.json
validate(args, ["thread_id", "post_id"]) validate(args, ["thread_id", "post_id"])
return schema.response(message_edit_query( return schema.response(message_edit_query(
@ -226,6 +255,12 @@ class API(object):
args["post_id"])) args["post_id"]))
@cherrypy.expose
def test(self, *args, **kwargs):
print(cherrypy.request.body.read())
return "{\"wow\": \"good job!\"}"
def run(): def run():
cherrypy.quickstart(API(), "/api") cherrypy.quickstart(API(), "/api")

View File

@ -1,27 +1,33 @@
#!/bin/bash #!/bin/bash
set -e
if [[ $1 == --init ]]; then
sqlite3 data.sqlite < schema.sql
echo cleared
exit
fi
DEPS=( DEPS=(
cherrypy cherrypy
markdown markdown
) )
if [[ -z $1 ]]; then case $1 in
cat << EOF --help )
Pass the python interpreter to use for pip installation cat <<EOF
(either a venv or a system interpreter) This script initializes the deps and files for bbj and also sets up its database.
It takes the following flags:
--help to print this
--dbset only runs the sql script
You can optionally pass a different python interpreter to use (such as
a virtual environment), with no arguments this will use the system python3
EOF EOF
exit exit;;
fi --dbset )
sqlite3 data.sqlite < schema.sql
$1 -m pip install ${DEPS[*]} echo cleared
exit;;
esac
PYTHON=`which python3`
[[ -e logs ]] || mkdir logs; mkdir logs/exceptions
[[ -z $1 ]] || PYTHON=$1
echo Using $PYTHON...
$PYTHON -m pip install ${DEPS[*]}
echo "Enter [i] to initialize a new database" echo "Enter [i] to initialize a new database"
read CLEAR read CLEAR
[[ $CLEAR == "i" ]] && sqlite3 bbj.db < schema.sql [[ $CLEAR == "i" ]] && sqlite3 bbj.db < schema.sql

View File

@ -1,4 +0,0 @@
from src import db, schema
def user_register(user_name, auth_hash):
return db.user_register(user_name, auth_hash)