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.
 
 
 
 
 

101 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. return render_template(error_template, traceback=exc.text)
  43. except Exception:
  44. app.logger.exception("Caught exception:")
  45. return render_template(error_template, traceback=format_exc())
  46. return inner
  47. return callback
  48. def make_route_restricter(auth, on_failure):
  49. """Wrap a route to ensure the user is authenticated."""
  50. def callback(func):
  51. @wraps(func)
  52. def inner(*args, **kwargs):
  53. success, caught = try_func(auth.is_authenticated)
  54. if success:
  55. return func(*args, **kwargs)
  56. if not caught:
  57. flash(Messages.LOG_IN_FIRST, "error")
  58. return on_failure()
  59. return inner
  60. return callback
  61. def set_up_asset_versioning(app):
  62. """Add a staticv endpoint that adds hash versioning to static assets."""
  63. def callback(app, error, endpoint, values):
  64. if endpoint == "staticv":
  65. filename = values["filename"]
  66. fpath = path.join(app.static_folder, filename)
  67. try:
  68. mtime = path.getmtime(fpath)
  69. except OSError:
  70. return url_for("static", filename=filename)
  71. cache = app._hash_cache.get(fpath)
  72. if cache and cache[0] == mtime:
  73. hashstr = cache[1]
  74. else:
  75. with open(fpath, "rb") as fp:
  76. hashstr = md5(fp.read()).hexdigest()
  77. app._hash_cache[fpath] = (mtime, hashstr)
  78. return url_for("static", filename=filename, v=hashstr)
  79. raise error
  80. old_get_max_age = app.get_send_file_max_age
  81. def extend_max_age(filename):
  82. if "v" in request.args:
  83. return 60 * 60 * 24 * 365 # 1 year
  84. return old_get_max_age(filename)
  85. app._hash_cache = {}
  86. app.url_build_error_handlers.append(lambda a, b, c: callback(app, a, b, c))
  87. app.get_send_file_max_age = extend_max_age