refine message object schema; update docstrings
parent
73a9063f93
commit
af5b53e7e3
62
server.py
62
server.py
|
@ -30,8 +30,7 @@ def api_method(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 cherrypy.thread_data so other
|
||||
funtions can handle the request.
|
||||
from header data, and prepares the arguments for each method.
|
||||
|
||||
In the body of each api method and all the functions
|
||||
they utilize, BBJExceptions are caught and their attached
|
||||
|
@ -40,8 +39,9 @@ def api_method(function):
|
|||
it for inspection. Errors related to JSON decoding are
|
||||
caught as well and returned to the client as code 0.
|
||||
"""
|
||||
function.exposed = True
|
||||
@wraps(function)
|
||||
def wrapper(*args, **kwargs):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
response = None
|
||||
try:
|
||||
# read in the body from the request to a string...
|
||||
|
@ -50,11 +50,8 @@ def api_method(function):
|
|||
if body:
|
||||
body = json.loads(body)
|
||||
if isinstance(body, dict):
|
||||
# lowercase all of its keys
|
||||
body = {str(key).lower(): value for key, value
|
||||
in body.items()}
|
||||
else: # would rather a NoneType than b""
|
||||
body = None
|
||||
# lowercase all of its top-level keys
|
||||
body = {str(key).lower(): value for key, value in body.items()}
|
||||
|
||||
username = cherrypy.request.headers.get("User")
|
||||
auth = cherrypy.request.headers.get("Auth")
|
||||
|
@ -78,8 +75,7 @@ def api_method(function):
|
|||
# api_methods may choose to bind a usermap into the thread_data
|
||||
# which will send it off with the response
|
||||
cherrypy.thread_data.usermap = {}
|
||||
# TODO: Why in kek's name is self needing to be supplied a value positionally?
|
||||
value = function(None, body, cherrypy.thread_data.db, user)
|
||||
value = function(self, body, cherrypy.thread_data.db, user)
|
||||
response = schema.response(value, cherrypy.thread_data.usermap)
|
||||
|
||||
except BBJException as e:
|
||||
|
@ -91,7 +87,7 @@ def api_method(function):
|
|||
except Exception as e:
|
||||
error_id = uuid1().hex
|
||||
response = schema.error(1,
|
||||
"Internal server error: code {}. {}"
|
||||
"Internal server error: code {} {}"
|
||||
.format(error_id, repr(e)))
|
||||
with open("logs/exceptions/" + error_id, "a") as log:
|
||||
traceback.print_tb(e.__traceback__, file=log)
|
||||
|
@ -111,10 +107,6 @@ def create_usermap(connection, obj):
|
|||
be a thread_index or a messages object from one.
|
||||
"""
|
||||
|
||||
if isinstance(obj, dict):
|
||||
# this is a message object for a thread, ditch the keys
|
||||
obj = obj.values()
|
||||
|
||||
return {
|
||||
user_id: db.user_resolve(
|
||||
connection,
|
||||
|
@ -144,22 +136,19 @@ def validate(json, args):
|
|||
.format(arg, ", ".join(args)))
|
||||
|
||||
|
||||
APICONFIG = {
|
||||
"/": {
|
||||
"tools.response_headers.on": True,
|
||||
"tools.response_headers.headers": [
|
||||
("Content-Type", "application/json")
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
class API(object):
|
||||
"""
|
||||
This object contains all the API endpoints for bbj.
|
||||
The html serving part of the server is not written
|
||||
yet, so this is currently the only module being
|
||||
served.
|
||||
"""
|
||||
@api_method
|
||||
@cherrypy.expose
|
||||
def user_register(self, args, database, user, **kwargs):
|
||||
"""
|
||||
Register a new user into the system and return the new object.
|
||||
Requires the string arguments `user_name` and `auth_hash`
|
||||
Requires the string arguments `user_name` and `auth_hash`.
|
||||
Do not send User/Auth headers with this method.
|
||||
"""
|
||||
validate(args, ["user_name", "auth_hash"])
|
||||
return db.user_register(
|
||||
|
@ -167,7 +156,6 @@ class API(object):
|
|||
|
||||
|
||||
@api_method
|
||||
@cherrypy.expose
|
||||
def user_update(self, args, database, user, **kwargs):
|
||||
"""
|
||||
Receives new parameters and assigns them to the user_object
|
||||
|
@ -182,7 +170,6 @@ class API(object):
|
|||
|
||||
|
||||
@api_method
|
||||
@cherrypy.expose
|
||||
def get_me(self, args, database, user, **kwargs):
|
||||
"""
|
||||
Requires no arguments. Returns your internal user object,
|
||||
|
@ -192,7 +179,6 @@ class API(object):
|
|||
|
||||
|
||||
@api_method
|
||||
@cherrypy.expose
|
||||
def user_get(self, args, database, user, **kwargs):
|
||||
"""
|
||||
Retreive an external user object for the given `user`.
|
||||
|
@ -204,7 +190,6 @@ class API(object):
|
|||
|
||||
|
||||
@api_method
|
||||
@cherrypy.expose
|
||||
def thread_index(self, args, database, user, **kwargs):
|
||||
"""
|
||||
Return an array with all the threads, ordered by most recent activity.
|
||||
|
@ -216,7 +201,6 @@ class API(object):
|
|||
|
||||
|
||||
@api_method
|
||||
@cherrypy.expose
|
||||
def thread_create(self, args, database, user, **kwargs):
|
||||
"""
|
||||
Creates a new thread and returns it. Requires the non-empty
|
||||
|
@ -225,12 +209,11 @@ class API(object):
|
|||
validate(args, ["body", "title"])
|
||||
thread = db.thread_create(
|
||||
database, user["user_id"], args["body"], args["title"])
|
||||
cherrypy.thread_data.usermap = {user["user_id"]: user}
|
||||
cherrypy.thread_data.usermap = thread
|
||||
return thread
|
||||
|
||||
|
||||
@api_method
|
||||
@cherrypy.expose
|
||||
def thread_reply(self, args, database, user, **kwargs):
|
||||
"""
|
||||
Creates a new reply for the given thread and returns it.
|
||||
|
@ -242,7 +225,6 @@ class API(object):
|
|||
|
||||
|
||||
@api_method
|
||||
@cherrypy.expose
|
||||
def thread_load(self, args, database, user, **kwargs):
|
||||
"""
|
||||
Returns the thread object with all of its messages loaded.
|
||||
|
@ -256,7 +238,6 @@ class API(object):
|
|||
|
||||
|
||||
@api_method
|
||||
@cherrypy.expose
|
||||
def edit_post(self, args, database, user, **kwargs):
|
||||
"""
|
||||
Replace a post with a new body. Requires the arguments
|
||||
|
@ -265,8 +246,9 @@ class API(object):
|
|||
otherwise an error object is returned whose description
|
||||
should be shown to the user.
|
||||
|
||||
To perform sanity checks without actually attempting to
|
||||
edit a post, use `edit_query`
|
||||
To perform sanity checks and retrieve the unformatted body
|
||||
of a post without actually attempting to replace it, use
|
||||
`edit_query` first.
|
||||
|
||||
Returns the new message object.
|
||||
"""
|
||||
|
@ -278,14 +260,14 @@ class API(object):
|
|||
|
||||
|
||||
@api_method
|
||||
@cherrypy.expose
|
||||
def edit_query(self, args, database, user, **kwargs):
|
||||
"""
|
||||
Queries the database to ensure the user can edit a given
|
||||
message. Requires the arguments `thread_id` and `post_id`
|
||||
(does not require a new body)
|
||||
|
||||
Returns either boolean true or the current message object
|
||||
Returns the original message object without any formatting
|
||||
on success.
|
||||
"""
|
||||
if user == db.anon:
|
||||
raise BBJUserError("Anons cannot edit messages.")
|
||||
|
@ -294,10 +276,10 @@ class API(object):
|
|||
database, user["user_id"], args["thread_id"], args["post_id"])
|
||||
|
||||
|
||||
@cherrypy.expose
|
||||
def test(self, **kwargs):
|
||||
print(cherrypy.request.body.read())
|
||||
return "{\"wow\": \"jolly good show!\"}"
|
||||
test.exposed = True
|
||||
|
||||
|
||||
|
||||
|
|
14
src/db.py
14
src/db.py
|
@ -36,13 +36,6 @@ def thread_get(connection, thread_id, messages=True):
|
|||
|
||||
MESSAGES, if False, will omit the inclusion of a thread's messages
|
||||
and only get its metadata, such as title, author, etc.
|
||||
|
||||
FORMATTER should be a callable object who takes a body string
|
||||
as it's only argument and returns an object to be sent in the
|
||||
response. It isn't strictly necessary that it returns a string,
|
||||
for example the entity parser will return an array with the
|
||||
body string and another array with indices and types of objects
|
||||
contained in it.
|
||||
"""
|
||||
c = connection.cursor()
|
||||
c.execute("SELECT * FROM threads WHERE thread_id = ?", (thread_id,))
|
||||
|
@ -53,12 +46,11 @@ def thread_get(connection, thread_id, messages=True):
|
|||
thread = schema.thread(*thread)
|
||||
|
||||
if messages:
|
||||
c.execute("SELECT * FROM messages WHERE thread_id = ?", (thread_id,))
|
||||
c.execute("""SELECT * FROM messages WHERE thread_id = ?
|
||||
ORDER BY post_id""", (thread_id,))
|
||||
# create a dictionary where each message is accessible by its
|
||||
# integer post_id as a key
|
||||
thread["messages"] = \
|
||||
{message["post_id"]: message for message in
|
||||
[schema.message(*values) for values in c.fetchall()]}
|
||||
thread["messages"] = [schema.message(*values) for values in c.fetchall()]
|
||||
|
||||
return thread
|
||||
|
||||
|
|
Loading…
Reference in New Issue