web.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import flask
  2. import pystache
  3. import lc.config as c
  4. import lc.error as e
  5. import lc.model as m
  6. class Endpoint:
  7. def __init__(self):
  8. self.user = None
  9. # try finding the token
  10. token = None
  11. # first check the HTTP headers
  12. if (auth := flask.request.headers.get("Authorization", None)) :
  13. token = auth.split()[1]
  14. # if that fails, check the session
  15. elif flask.session.get("auth", None):
  16. token = flask.session["auth"]
  17. # if that exists and we can deserialize it, then make sure
  18. # it contains a valid user password, too
  19. if token and (payload := c.SERIALIZER.loads(token)):
  20. if "name" not in payload or "password" not in payload:
  21. return
  22. try:
  23. u = m.User.by_slug(payload["name"])
  24. except e.LCException:
  25. return
  26. if u.authenticate(payload["password"]):
  27. self.user = u
  28. def require_authentication(self, name: str):
  29. """
  30. Check that the currently logged-in user exists and is the
  31. same as the user whose username is given. Raises an exception
  32. otherwise.
  33. """
  34. if not self.user or name != self.user.name:
  35. raise e.BadPermissions()
  36. def route(self, *args, **kwargs):
  37. try:
  38. if flask.request.method == "POST":
  39. return flask.jsonify(self.api_post(*args, **kwargs))
  40. elif (
  41. flask.request.method in ["GET", "HEAD"]
  42. and flask.request.content_type == "application/json"
  43. ):
  44. return flask.jsonify(self.api_get(*args, **kwargs))
  45. except e.LCException as exn:
  46. return ({"status": exn.http_code(), "error": str(exn)}, exn.http_code())
  47. except e.LCRedirect as exn:
  48. return flask.redirect(exn.to_path())
  49. try:
  50. return self.html(*args, **kwargs)
  51. except e.LCException as exn:
  52. page = render(
  53. "main", title="error", content=f"shit's fucked yo: {exn}", user=None,
  54. )
  55. return (page, exn.http_code())
  56. except e.LCRedirect as exn:
  57. return flask.redirect(exn.to_path())
  58. def endpoint(route):
  59. def do_endpoint(cls):
  60. def func(*args, **kwargs):
  61. return cls().route(*args, **kwargs)
  62. methods = ["GET"]
  63. if "api_post" in dir(cls):
  64. methods.append("POST")
  65. func.__name__ = cls.__name__
  66. return c.app.route(route, methods=methods)(func)
  67. return do_endpoint
  68. LOADER = pystache.loader.Loader(extension="mustache", search_dirs=["templates"])
  69. def render(name, **kwargs):
  70. """Load and use a Mustache template from the project root"""
  71. template = LOADER.load_name(name)
  72. renderer = pystache.Renderer(missing_tags="strict", search_dirs=["templates"])
  73. return renderer.render(template, kwargs)