aboutsummaryrefslogtreecommitdiffstats
path: root/server.py
diff options
context:
space:
mode:
authorBlake DeMarcy <ofunknowndescent@gmail.com>2017-05-01 03:13:36 -0500
committerBlake DeMarcy <ofunknowndescent@gmail.com>2017-05-01 03:13:36 -0500
commitecef425e8b4f669193ac70ff9f1931959e7f6381 (patch)
treec0cb610e916fcfef7d77a10af1b8289a2c1e43de /server.py
parent970edc10c625819a414a83c027da267bb6b9ad81 (diff)
downloadbbj-ecef425e8b4f669193ac70ff9f1931959e7f6381.tar.gz
add config system, shut up the linter
Diffstat (limited to 'server.py')
-rw-r--r--server.py139
1 files changed, 73 insertions, 66 deletions
diff --git a/server.py b/server.py
index 3f65364..45a07cc 100644
--- a/server.py
+++ b/server.py
@@ -9,7 +9,24 @@ import sqlite3
import json
dbname = "data.sqlite"
-debug = False
+
+# any values here may be overrided in the config.json. Any values not listed
+# here will have no effect on the server.
+app_config = {
+ "port": 7099,
+ "host": "127.0.0.1",
+ "instance_name": "BBJ",
+ "allow_anon": True,
+ "debug": False
+}
+
+try:
+ with open("config.json") as _conf:
+ app_config.update(json.load(_conf))
+except FileNotFoundError:
+ with open("config.json", "w") as _conf:
+ json.dump(app_config, _conf)
+
def api_method(function):
"""
@@ -25,9 +42,11 @@ def api_method(function):
caught as well and returned to the client as code 0.
"""
function.exposed = True
+
@wraps(function)
def wrapper(self, *args, **kwargs):
response = None
+ debug = app_config["debug"]
try:
connection = sqlite3.connect(dbname)
# read in the body from the request to a string...
@@ -49,7 +68,8 @@ def api_method(function):
print("\n\n\nBody: {}\n\ne----------".format(body))
if (username and not auth) or (auth and not username):
- raise BBJParameterError("User or Auth was given without the other.")
+ raise BBJParameterError(
+ "User or Auth was given without the other.")
elif not username and not auth:
user = db.anon
@@ -60,7 +80,8 @@ def api_method(function):
raise BBJUserError("User %s is not registered" % username)
elif auth.lower() != user["auth_hash"].lower():
- raise BBJException(5, "Invalid authorization key for user.")
+ raise BBJException(
+ 5, "Invalid authorization key for user.")
# api_methods may choose to bind a usermap into the thread_data
# which will send it off with the response
@@ -76,9 +97,9 @@ def api_method(function):
except Exception as e:
error_id = uuid1().hex
- response = schema.error(1,
- "Internal server error: code {} {}"
- .format(error_id, repr(e)))
+ response = schema.error(
+ 1, "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)
log.write(repr(e))
@@ -142,6 +163,16 @@ def validate(json, args):
.format(arg, ", ".join(args)))
+def no_anon_hook(user, message=None, user_error=True):
+ if user is db.anon:
+ exception = BBJUserError if user_error else BBJParameterError
+ if message:
+ raise exception(message)
+ elif not app_config["allow_anon"]:
+ raise exception(
+ "Anonymous participation has been disabled on this instance.")
+
+
class API(object):
"""
This object contains all the API endpoints for bbj.
@@ -149,6 +180,7 @@ class API(object):
yet, so this is currently the only module being
served.
"""
+
@api_method
def user_register(self, args, database, user, **kwargs):
"""
@@ -160,7 +192,6 @@ class API(object):
return db.user_register(
database, args["user_name"], args["auth_hash"])
-
@api_method
def user_update(self, args, database, user, **kwargs):
"""
@@ -171,12 +202,10 @@ class API(object):
The newly updated user object is returned on success.
"""
- if user == db.anon:
- raise BBJParameterError("Anons cannot modify their account.")
- validate(args, []) # just make sure its not empty
+ no_anon_hook(user, "Anons cannot modify their account.")
+ validate(args, []) # just make sure its not empty
return db.user_update(database, user, args)
-
@api_method
def get_me(self, args, database, user, **kwargs):
"""
@@ -185,14 +214,15 @@ class API(object):
"""
return user
-
@api_method
def user_map(self, args, database, user, **kwargs):
"""
Returns an array with all registered user_ids, with the usermap
object populated by their full objects.
"""
- users = {user[0] for user in database.execute("SELECT user_id FROM users")}
+ users = {
+ user[0] for user in database.execute("SELECT user_id FROM users")
+ }
cherrypy.thread_data.usermap = {
user: db.user_resolve(
database,
@@ -203,7 +233,6 @@ class API(object):
}
return list(users)
-
@api_method
def user_get(self, args, database, user, **kwargs):
"""
@@ -214,7 +243,6 @@ class API(object):
return db.user_resolve(
database, args["user"], return_false=False, externalize=True)
-
@api_method
def user_is_registered(self, args, database, user, **kwargs):
"""
@@ -224,7 +252,6 @@ class API(object):
validate(args, ["target_user"])
return bool(db.user_resolve(database, args["target_user"]))
-
@api_method
def check_auth(self, args, database, user, **kwargs):
"""
@@ -232,26 +259,25 @@ class API(object):
returns boolean true or false whether the hash is valid.
"""
validate(args, ["target_user", "target_hash"])
- user = db.user_resolve(database, args["target_user"], return_false=False)
+ user = db.user_resolve(
+ database, args["target_user"], return_false=False)
return args["target_hash"].lower() == user["auth_hash"].lower()
-
@api_method
def thread_index(self, args, database, user, **kwargs):
"""
Return an array with all the threads, ordered by most recent activity.
Requires no arguments.
- Optionally, you may supply the argument `include_op`, which, when non-nil,
- will include a "messages" key with the object, whose sole content is the
- original message (post_id 0).
+ Optionally, you may supply the argument `include_op`, which, when
+ non-nil, will include a "messages" key with the object, whose sole
+ content is the original message (post_id 0).
"""
op = isinstance(args, dict) and args.get("include_op")
threads = db.thread_index(database, include_op=op)
cherrypy.thread_data.usermap = create_usermap(database, threads, True)
return threads
-
@api_method
def message_feed(self, args, database, user, **kwargs):
"""
@@ -292,7 +318,6 @@ class API(object):
do_formatting(args.get("format"), feed["messages"])
return feed
-
@api_method
def thread_create(self, args, database, user, **kwargs):
"""
@@ -302,6 +327,7 @@ class API(object):
If the argument `send_raw` is specified and has a non-nil
value, the OP message will never recieve special formatting.
"""
+ no_anon_hook(user)
validate(args, ["body", "title"])
thread = db.thread_create(
database, user["user_id"], args["body"],
@@ -310,7 +336,6 @@ class API(object):
create_usermap(database, thread["messages"])
return thread
-
@api_method
def thread_reply(self, args, database, user, **kwargs):
"""
@@ -320,12 +345,12 @@ class API(object):
If the argument `send_raw` is specified and has a non-nil
value, the message will never recieve special formatting.
"""
+ no_anon_hook(user)
validate(args, ["thread_id", "body"])
return db.thread_reply(
database, user["user_id"], args["thread_id"],
args["body"], args.get("send_raw"))
-
@api_method
def thread_load(self, args, database, user, **kwargs):
"""
@@ -345,7 +370,6 @@ class API(object):
do_formatting(args.get("format"), thread["messages"])
return thread
-
@api_method
def edit_post(self, args, database, user, **kwargs):
"""
@@ -366,14 +390,12 @@ class API(object):
Returns the new message object.
"""
- if user == db.anon:
- raise BBJUserError("Anons cannot edit messages.")
+ no_anon_hook(user, "Anons cannot edit messages.")
validate(args, ["body", "thread_id", "post_id"])
return db.message_edit_commit(
database, user["user_id"], args["thread_id"],
args["post_id"], args["body"], args.get("send_raw"))
-
@api_method
def delete_post(self, args, database, user, **kwargs):
"""
@@ -388,13 +410,11 @@ class API(object):
If the post_id is 0, the whole thread is deleted.
"""
- if user == db.anon:
- raise BBJUserError("Anons cannot delete messages.")
+ no_anon_hook(user, "Anons cannot delete messages.")
validate(args, ["thread_id", "post_id"])
return db.message_delete(
database, user["user_id"], args["thread_id"], args["post_id"])
-
@api_method
def set_post_raw(self, args, database, user, **kwargs):
"""
@@ -412,15 +432,13 @@ class API(object):
but if this is the only change you want to make to the message,
using this endpoint instead is preferable.
"""
- if user == db.anon:
- raise BBJUserError("Anons cannot edit messages.")
+ no_anon_hook(user, "Anons cannot edit messages.")
validate(args, ["value", "thread_id", "post_id"])
return db.message_edit_commit(
database, user["user_id"],
args["thread_id"], args["post_id"],
None, args["value"], None)
-
@api_method
def is_admin(self, args, database, user, **kwargs):
"""
@@ -428,10 +446,10 @@ class API(object):
of whether that user is an admin.
"""
validate(args, ["target_user"])
- user = db.user_resolve(database, args["target_user"], return_false=False)
+ user = db.user_resolve(
+ database, args["target_user"], return_false=False)
return user["is_admin"]
-
@api_method
def edit_query(self, args, database, user, **kwargs):
"""
@@ -442,13 +460,11 @@ class API(object):
Returns the original message object without any formatting
on success. Returns a descriptive code 4 otherwise.
"""
- if user == db.anon:
- raise BBJUserError("Anons cannot edit messages.")
+ no_anon_hook(user, "Anons cannot edit messages.")
validate(args, ["thread_id", "post_id"])
return db.message_edit_query(
database, user["user_id"], args["thread_id"], args["post_id"])
-
@api_method
def format_message(self, args, database, user, **kwargs):
"""
@@ -461,7 +477,6 @@ class API(object):
do_formatting(args["format"], message)
return message[0]["body"]
-
@api_method
def set_thread_pin(self, args, database, user, **kwargs):
"""
@@ -477,7 +492,6 @@ class API(object):
raise BBJUserError("Only admins can set thread pins")
return db.set_thread_pin(database, args["thread_id"], args["value"])
-
@api_method
def db_validate(self, args, database, user, **kwargs):
"""
@@ -516,10 +530,11 @@ class API(object):
def api_http_error(status, message, traceback, version):
- return json.dumps(schema.error(2, "HTTP error {}: {}".format(status, message)))
+ return json.dumps(schema.error(
+ 2, "HTTP error {}: {}".format(status, message)))
-CONFIG = {
+API_CONFIG = {
"/": {
"error_page.default": api_http_error
}
@@ -534,37 +549,29 @@ def run():
db.anon = db.user_resolve(_c, "anonymous")
if not db.anon:
db.anon = db.user_register(
- _c, "anonymous", # this is the hash for "anon"
+ _c, "anonymous", # this is the hash for "anon"
"5430eeed859cad61d925097ec4f53246"
"1ccf1ab6b9802b09a313be1478a4d614")
finally:
_c.close()
- cherrypy.quickstart(API(), "/api", CONFIG)
-
+ cherrypy.quickstart(API(), "/api", API_CONFIG)
-if __name__ == "__main__":
- try:
- port_spec = argv.index("--port")
- port = argv[port_spec+1]
- except ValueError: # --port not specified
- port = 7099
- except IndexError: # flag given but no value
- exit("thats not how this works, silly! --port 7099")
+def get_arg(key, default, get_value=True):
try:
- host_spec = argv.index("--host")
- host = argv[host_spec+1]
- except ValueError: # --host not specified
- host = "127.0.0.1"
- except IndexError: # flag given but no value
- exit("thats not how this works, silly! --host 127.0.0.1")
+ spec = argv.index("--" + key)
+ value = argv[spec + 1] if get_value else True
+ except ValueError: # --key not specified
+ value = default
+ except IndexError: # flag given but no value
+ exit("invalid format for --" + key)
+ return value
- try:
- host_spec = argv.index("--debug")
- debug = True
- except ValueError:
- pass
+if __name__ == "__main__":
+ port = get_arg("port", app_config["port"])
+ host = get_arg("host", app_config["host"])
+ debug = get_arg("debug", app_config["debug"], False)
cherrypy.config.update({
"server.socket_port": int(port),
"server.socket_host": host
Un proyecto texto-plano.xyz