A corporation manager and dashboard for EVE Online
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

102 lines
3.4 KiB

  1. # -*- coding: utf-8 -*-
  2. from functools import wraps
  3. from hashlib import md5
  4. from os import path
  5. from traceback import format_exc
  6. from flask import flash, g, request, url_for
  7. from flask_mako import render_template, TemplateError
  8. from werkzeug.exceptions import HTTPException
  9. from .exceptions import AccessDeniedError, EVEAPIError
  10. from .messages import Messages
  11. __all__ = [
  12. "try_func", "make_error_catcher", "make_route_restricter",
  13. "set_up_asset_versioning"]
  14. def try_func(inner):
  15. """Evaluate inner(), catching subclasses of CalefactionError.
  16. If nothing was caught, return (inner(), False). Otherwise, flash an
  17. appropriate error message and return (False, True).
  18. """
  19. try:
  20. result = inner()
  21. except EVEAPIError:
  22. flash(Messages.EVE_API_ERROR, "error")
  23. return (False, True)
  24. except AccessDeniedError:
  25. flash(Messages.ACCESS_DENIED, "error")
  26. return (False, True)
  27. if getattr(g, "_session_expired", False):
  28. flash(Messages.SESSION_EXPIRED, "error")
  29. return (result, True)
  30. return (result, False)
  31. def make_error_catcher(app, error_template):
  32. """Wrap a route to display and log any uncaught exceptions."""
  33. def callback(func):
  34. @wraps(func)
  35. def inner(*args, **kwargs):
  36. try:
  37. return func(*args, **kwargs)
  38. except HTTPException:
  39. raise
  40. except TemplateError as exc:
  41. app.logger.error("Caught exception:\n{0}".format(exc.text))
  42. trace = exc.text
  43. except Exception:
  44. app.logger.exception("Caught exception:")
  45. trace = format_exc()
  46. return render_template(error_template, traceback=trace), 500
  47. return inner
  48. return callback
  49. def make_route_restricter(auth, on_failure):
  50. """Wrap a route to ensure the user is authenticated."""
  51. def callback(func):
  52. @wraps(func)
  53. def inner(*args, **kwargs):
  54. success, caught = try_func(auth.is_authenticated)
  55. if success:
  56. return func(*args, **kwargs)
  57. if not caught:
  58. flash(Messages.LOG_IN_FIRST, "error")
  59. return on_failure()
  60. return inner
  61. return callback
  62. def set_up_asset_versioning(app):
  63. """Add a staticv endpoint that adds hash versioning to static assets."""
  64. def callback(app, error, endpoint, values):
  65. if endpoint == "staticv":
  66. filename = values["filename"]
  67. fpath = path.join(app.static_folder, filename)
  68. try:
  69. mtime = path.getmtime(fpath)
  70. except OSError:
  71. return url_for("static", filename=filename)
  72. cache = app._hash_cache.get(fpath)
  73. if cache and cache[0] == mtime:
  74. hashstr = cache[1]
  75. else:
  76. with open(fpath, "rb") as fp:
  77. hashstr = md5(fp.read()).hexdigest()
  78. app._hash_cache[fpath] = (mtime, hashstr)
  79. return url_for("static", filename=filename, v=hashstr)
  80. raise error
  81. old_get_max_age = app.get_send_file_max_age
  82. def extend_max_age(filename):
  83. if "v" in request.args:
  84. return 60 * 60 * 24 * 365 # 1 year
  85. return old_get_max_age(filename)
  86. app._hash_cache = {}
  87. app.url_build_error_handlers.append(lambda a, b, c: callback(app, a, b, c))
  88. app.get_send_file_max_age = extend_max_age