base.py 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. # -*- coding: utf-8 -*-
  2. """The base Controller API."""
  3. import logging
  4. import tg
  5. from tg import TGController, RestController, tmpl_context, flash
  6. from tg.render import render
  7. from tg import request, redirect
  8. from tg.i18n import ugettext as _, ungettext
  9. __all__ = ['BaseController']
  10. class BaseController(TGController):
  11. """
  12. Base class for the controllers in the application.
  13. Your web application should have one of these. The root of
  14. your application is used to compute URLs used by your app.
  15. """
  16. def __call__(self, environ, context):
  17. """Invoke the Controller"""
  18. # TGController.__call__ dispatches to the Controller method
  19. # the request is routed to.
  20. request.identity = request.environ.get('repoze.who.identity')
  21. tmpl_context.identity = request.identity
  22. return TGController.__call__(self, environ, context)
  23. def _before(self, *args, **kwargs):
  24. tmpl_context.auth_is_internal = tg.config.get('auth_is_internal', True)
  25. tmpl_context.auth_instance = tg.config.get('auth_instance')
  26. @property
  27. def parent_controller(self):
  28. possible_parent = None
  29. for path, controller in self.mount_steps:
  30. if controller==self:
  31. break
  32. possible_parent = controller
  33. return possible_parent
  34. def url(self, id: int=None, subpath: str='', params:dict=None, skip_id=False) -> str:
  35. """
  36. return a standard REST URL for list or one item.
  37. If your mount point is /someitems, then this will return /someitems or /someitems/4 if id not None
  38. if subpath is given, then it will be added at the end, eg /someitems/subpath or /someitems/4/subpath
  39. :param id:
  40. :param subpath: path to be concatenated after the base url
  41. :param params: url parameters given as dict
  42. :param skip_id: by default, the method tris to find an item in tmpl_context (and will return the related url).
  43. If skip_id is True, then force to return default url (with no specific content)
  44. :return:
  45. """
  46. url = ''
  47. for step in self.mount_steps:
  48. path = step[0]
  49. controller = step[1]
  50. url = '/'.join([url.rstrip('/'), path.rstrip('/')]) # we always remove trailing slash
  51. # LOW-LEVEL DEBUG related log
  52. # logger.debug(self, ' Looking for item related to controller {} [type: {}]'.format(path, controller.__class__))
  53. if not skip_id:
  54. if id and self==controller:
  55. url = '/'.join([url, str(id)])
  56. elif controller.current_item_id():
  57. url = '/'.join([url, '{}'.format(controller.current_item_id())])
  58. if subpath:
  59. url = '/'.join([url, subpath])
  60. return tg.url(url, params)
  61. @classmethod
  62. def current_item_id_key_in_context(cls) -> str:
  63. """
  64. :return: the key name for getting item from tmpl_context.
  65. """
  66. raise NotImplementedError('This method must be implemented in sub-classes.')
  67. @classmethod
  68. def current_item_id(cls) -> int:
  69. """
  70. This method is to be implemented in child classes.
  71. It should return the id of the item related to the current REST controller in case of a REST controller or None
  72. example:
  73. WorkspaceController should return the current workspace id (if there is one) according to the url (eg if the url is /user/workspace/4/members, then it should return 4
  74. The implementation is to find the item in the current context through tmpl_context.
  75. if the id parameter is given, then force to use this id (otherwise, search in tmpl_context
  76. :param id:
  77. :return:
  78. """
  79. return getattr(tmpl_context, cls.current_item_id_key_in_context(), '')
  80. def back_with_error(self, message):
  81. flash(message)
  82. redirect(request.headers['Referer'])
  83. def current_user():
  84. return request.environ.get('repoze.who.identity')['user']
  85. class Logger(object):
  86. TPL = '[{cls}] {msg}'
  87. def __init__(self, logger_name):
  88. self._name = logger_name
  89. self._logger = logging.getLogger(self._name)
  90. def _txt(self, instance_or_class):
  91. if instance_or_class.__class__.__name__ in ('function', 'type'):
  92. return instance_or_class.__name__
  93. else:
  94. return instance_or_class.__class__.__name__
  95. def debug(self, instance_or_class, message):
  96. self._logger.debug(Logger.TPL.format(cls=self._txt(instance_or_class), msg=message))
  97. def error(self, instance_or_class, message, exc_info=0):
  98. self._logger.error(Logger.TPL.format(cls=self._txt(instance_or_class), msg=message, exc_info=exc_info))
  99. def info(self, instance_or_class, message):
  100. self._logger.info(Logger.TPL.format(cls=self._txt(instance_or_class), msg=message))
  101. def warning(self, instance_or_class, message):
  102. self._logger.warning(Logger.TPL.format(cls=self._txt(instance_or_class), msg=message))
  103. logger = Logger('tracim')