utils.py 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. # -*- coding: utf-8 -*-
  2. import os
  3. import time
  4. import signal
  5. import tg
  6. from tg import config
  7. from tg import require
  8. from tg import response
  9. from tg.controllers.util import abort
  10. from tg.appwrappers.errorpage import ErrorPageApplicationWrapper \
  11. as BaseErrorPageApplicationWrapper
  12. from tg.i18n import ugettext
  13. from tg.support.registry import StackedObjectProxy
  14. from tg.util import LazyString as BaseLazyString
  15. from tg.util import lazify
  16. from redis import Redis
  17. from rq import Queue
  18. from tracim.lib.base import logger
  19. from webob import Response
  20. from webob.exc import WSGIHTTPException
  21. def exec_time_monitor():
  22. def decorator_func(func):
  23. def wrapper_func(*args, **kwargs):
  24. start = time.time()
  25. retval = func(*args, **kwargs)
  26. end = time.time()
  27. logger.debug(func, 'exec time: {} seconds'.format(end-start))
  28. return retval
  29. return wrapper_func
  30. return decorator_func
  31. class SameValueError(ValueError):
  32. pass
  33. def replace_reset_password_templates(engines):
  34. try:
  35. if engines['text/html'][1] == 'resetpassword.templates.index':
  36. engines['text/html'] = (
  37. 'mako',
  38. 'tracim.templates.reset_password_index',
  39. engines['text/html'][2],
  40. engines['text/html'][3]
  41. )
  42. if engines['text/html'][1] == 'resetpassword.templates.change_password':
  43. engines['text/html'] = (
  44. 'mako',
  45. 'tracim.templates.reset_password_change_password',
  46. engines['text/html'][2],
  47. engines['text/html'][3]
  48. )
  49. except IndexError:
  50. pass
  51. except KeyError:
  52. pass
  53. @property
  54. def NotImplemented():
  55. raise NotImplementedError()
  56. class APIWSGIHTTPException(WSGIHTTPException):
  57. def json_formatter(self, body, status, title, environ):
  58. if self.comment:
  59. msg = '{0}: {1}'.format(title, self.comment)
  60. else:
  61. msg = title
  62. return {
  63. 'code': self.code,
  64. 'msg': msg,
  65. 'detail': self.detail,
  66. }
  67. class api_require(require):
  68. def default_denial_handler(self, reason):
  69. # Add code here if we have to hide 401 errors (security reasons)
  70. abort(response.status_int, reason, passthrough='json')
  71. class ErrorPageApplicationWrapper(BaseErrorPageApplicationWrapper):
  72. # Define here response code to manage in APIWSGIHTTPException
  73. api_managed_error_codes = [
  74. 400, 401, 403, 404,
  75. ]
  76. def __call__(self, controller, environ, context) -> Response:
  77. # We only do ou work when it's /api request
  78. # TODO BS 20161025: Look at PATH_INFO is not smart, find better way
  79. if not environ['PATH_INFO'].startswith('/api'):
  80. return super().__call__(controller, environ, context)
  81. try:
  82. resp = self.next_handler(controller, environ, context)
  83. except: # We catch all exception to display an 500 error json response
  84. if config.get('debug', False): # But in debug, we want to see it
  85. raise
  86. return APIWSGIHTTPException()
  87. # We manage only specified errors codes
  88. if resp.status_int not in self.api_managed_error_codes:
  89. return resp
  90. # Rewrite error in api format
  91. return APIWSGIHTTPException(
  92. code=resp.status_int,
  93. detail=resp.detail,
  94. title=resp.title,
  95. comment=resp.comment,
  96. )
  97. def get_valid_header_file_name(file_name: str) -> str:
  98. """
  99. :param file_name: file name to test
  100. :return: Return given string if compatible to header encoding, or
  101. download.ext if not.
  102. """
  103. try:
  104. file_name.encode('iso-8859-1')
  105. return file_name
  106. except UnicodeEncodeError:
  107. split_file_name = file_name.split('.')
  108. if len(split_file_name) > 1: # If > 1 so file have extension
  109. return 'download.{0}'.format(split_file_name[-1])
  110. return 'download'
  111. def str_as_bool(string: str) -> bool:
  112. if string == '0':
  113. return False
  114. return bool(string)
  115. class LazyString(BaseLazyString):
  116. pass
  117. def _lazy_ugettext(text: str):
  118. """
  119. This function test if application context is available
  120. :param text: String to traduce
  121. :return: lazyfied string or string
  122. """
  123. try:
  124. # Test if tg.translator is defined
  125. #
  126. # cf. https://github.com/tracim/tracim/issues/173
  127. #
  128. # HACK - 2017-11-03 - D.A
  129. # Replace context proxyfied by direct access to gettext function
  130. # which is not setup in case the tg2 context is not initialized
  131. tg.translator.gettext # raises a TypeError exception if context not set
  132. return ugettext(text)
  133. except TypeError as e:
  134. logger.debug(_lazy_ugettext, 'TG2 context not available for translation. TypeError: {}'.format(e))
  135. return text
  136. lazy_ugettext = lazify(_lazy_ugettext)
  137. def get_rq_queue(queue_name: str= 'default') -> Queue:
  138. """
  139. :param queue_name: name of queue
  140. :return: wanted queue
  141. """
  142. from tracim.config.app_cfg import CFG
  143. cfg = CFG.get_instance()
  144. return Queue(queue_name, connection=Redis(
  145. host=cfg.EMAIL_SENDER_REDIS_HOST,
  146. port=cfg.EMAIL_SENDER_REDIS_PORT,
  147. db=cfg.EMAIL_SENDER_REDIS_DB,
  148. ))