fuck commit messages
parent
3640d1b1de
commit
474f13842b
83
server.py
83
server.py
|
@ -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")
|
||||||
|
|
36
setup.sh
36
setup.sh
|
@ -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
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
from src import db, schema
|
|
||||||
|
|
||||||
def user_register(user_name, auth_hash):
|
|
||||||
return db.user_register(user_name, auth_hash)
|
|
Loading…
Reference in New Issue