/circuits/web/controllers.py

https://bitbucket.org/prologic/circuits/ · Python · 184 lines · 112 code · 40 blank · 32 comment · 32 complexity · c24e8272cd8ade7cf221962b87ecddb9 MD5 · raw file

  1. # Module: controllers
  2. # Date: 6th November 2008
  3. # Author: James Mills, prologic at shortcircuit dot net dot au
  4. """Controllers
  5. This module implements ...
  6. """
  7. import json
  8. from inspect import getargspec
  9. from collections import Callable
  10. from functools import update_wrapper
  11. from circuits.core import handler, BaseComponent
  12. from . import tools
  13. from .wrappers import Response
  14. from .errors import forbidden, httperror, notfound, redirect
  15. def expose(*channels, **config):
  16. def decorate(f):
  17. @handler(*channels, **config)
  18. def wrapper(self, event, *args, **kwargs):
  19. try:
  20. if not hasattr(self, "request"):
  21. (self.request, self.response), args = args[:2], args[2:]
  22. self.request.args = args
  23. self.request.kwargs = kwargs
  24. self.cookie = self.request.cookie
  25. if hasattr(self.request, "session"):
  26. self.session = self.request.session
  27. if not getattr(f, "event", False):
  28. return f(self, *args, **kwargs)
  29. else:
  30. return f(self, event, *args, **kwargs)
  31. finally:
  32. if hasattr(self, "request"):
  33. del self.request
  34. del self.response
  35. del self.cookie
  36. if hasattr(self, "session"):
  37. del self.session
  38. wrapper.args, wrapper.varargs, wrapper.varkw, wrapper.defaults = \
  39. getargspec(f)
  40. if wrapper.args and wrapper.args[0] == "self":
  41. del wrapper.args[0]
  42. if wrapper.args and wrapper.args[0] == "event":
  43. f.event = True
  44. del wrapper.args[0]
  45. wrapper.event = True
  46. return update_wrapper(wrapper, f)
  47. return decorate
  48. class ExposeMetaClass(type):
  49. def __init__(cls, name, bases, dct):
  50. super(ExposeMetaClass, cls).__init__(name, bases, dct)
  51. for k, v in dct.items():
  52. if isinstance(v, Callable) \
  53. and not (k[0] == "_" or hasattr(v, "handler")):
  54. setattr(cls, k, expose(k)(v))
  55. class BaseController(BaseComponent):
  56. channel = "/"
  57. @property
  58. def uri(self):
  59. """Return the current Request URI
  60. .. seealso:: :py:class:`circuits.web.url.URL`
  61. """
  62. if hasattr(self, "request"):
  63. return self.request.uri
  64. def forbidden(self, description=None):
  65. """Return a 403 (Forbidden) response
  66. :param description: Message to display
  67. :type description: str
  68. """
  69. return forbidden(self.request, self.response, description=description)
  70. def notfound(self, description=None):
  71. """Return a 404 (Not Found) response
  72. :param description: Message to display
  73. :type description: str
  74. """
  75. return notfound(self.request, self.response, description=description)
  76. def redirect(self, urls, code=None):
  77. """Return a 30x (Redirect) response
  78. Redirect to another location specified by urls with an optional
  79. custom response code.
  80. :param urls: A single URL or list of URLs
  81. :type urls: str or list
  82. :param code: HTTP Redirect code
  83. :type code: int
  84. """
  85. return redirect(self.request, self.response, urls, code=code)
  86. def serve_file(self, path, type=None, disposition=None, name=None):
  87. return tools.serve_file(
  88. self.request, self.response, path, type, disposition, name
  89. )
  90. def serve_download(self, path, name=None):
  91. return tools.serve_download(
  92. self.request, self.response, path, name
  93. )
  94. def expires(self, secs=0, force=False):
  95. tools.expires(self.request, self.response, secs, force)
  96. Controller = ExposeMetaClass("Controller", (BaseController,), {})
  97. def exposeJSON(*channels, **config):
  98. def decorate(f):
  99. @handler(*channels, **config)
  100. def wrapper(self, *args, **kwargs):
  101. try:
  102. if not hasattr(self, "request"):
  103. self.request, self.response = args[:2]
  104. args = args[2:]
  105. self.cookie = self.request.cookie
  106. if hasattr(self.request, "session"):
  107. self.session = self.request.session
  108. result = f(self, *args, **kwargs)
  109. if (isinstance(result, httperror)
  110. or isinstance(result, Response)):
  111. return result
  112. else:
  113. self.response.headers["Content-Type"] = (
  114. "application/json"
  115. )
  116. return json.dumps(result)
  117. finally:
  118. if hasattr(self, "request"):
  119. del self.request
  120. del self.response
  121. del self.cookie
  122. if hasattr(self, "session"):
  123. del self.session
  124. wrapper.args, wrapper.varargs, wrapper.varkw, wrapper.defaults = \
  125. getargspec(f)
  126. if wrapper.args and wrapper.args[0] == "self":
  127. del wrapper.args[0]
  128. return update_wrapper(wrapper, f)
  129. return decorate
  130. class ExposeJSONMetaClass(type):
  131. def __init__(cls, name, bases, dct):
  132. super(ExposeJSONMetaClass, cls).__init__(name, bases, dct)
  133. for k, v in dct.items():
  134. if isinstance(v, Callable) \
  135. and not (k[0] == "_" or hasattr(v, "handler")):
  136. setattr(cls, k, exposeJSON(k)(v))
  137. JSONController = ExposeJSONMetaClass("JSONController", (BaseController,), {})