utils.py 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. # -*- coding: utf-8 -*-
  2. import datetime
  3. import random
  4. import string
  5. from enum import Enum
  6. import colorsys
  7. from redis import Redis
  8. from rq import Queue
  9. import typing
  10. if typing.TYPE_CHECKING:
  11. from tracim_backend.config import CFG
  12. DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
  13. DEFAULT_WEBDAV_CONFIG_FILE = "wsgidav.conf"
  14. DEFAULT_TRACIM_CONFIG_FILE = "development.ini"
  15. CONTENT_FRONTEND_URL_SCHEMA = 'workspaces/{workspace_id}/contents/{content_type}/{content_id}' # nopep8
  16. WORKSPACE_FRONTEND_URL_SCHEMA = 'workspaces/{workspace_id}' # nopep8
  17. def get_root_frontend_url(config: 'CFG') -> str:
  18. """
  19. Return website base url with always '/' at the end
  20. """
  21. base_url = ''
  22. if config.WEBSITE_BASE_URL[-1] == '/':
  23. base_url = config.WEBSITE_BASE_URL
  24. else:
  25. base_url = config.WEBSITE_BASE_URL + '/'
  26. return base_url
  27. def get_login_frontend_url(config: 'CFG'):
  28. """
  29. Return login page url
  30. """
  31. return get_root_frontend_url(config) + 'login'
  32. def get_email_logo_frontend_url(config: 'CFG'):
  33. # TODO - G.M - 11-06-2018 - [emailTemplateURL] correct value for email_logo_frontend_url # nopep8
  34. return 'data:image/png;base64,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' # nopep8'
  35. def get_redis_connection(config: 'CFG') -> Redis:
  36. """
  37. :param config: current app_config
  38. :return: redis connection
  39. """
  40. return Redis(
  41. host=config.EMAIL_SENDER_REDIS_HOST,
  42. port=config.EMAIL_SENDER_REDIS_PORT,
  43. db=config.EMAIL_SENDER_REDIS_DB,
  44. )
  45. def get_rq_queue(redis_connection: Redis, queue_name: str ='default') -> Queue:
  46. """
  47. :param queue_name: name of queue
  48. :return: wanted queue
  49. """
  50. return Queue(name=queue_name, connection=redis_connection)
  51. def cmp_to_key(mycmp):
  52. """
  53. List sort related function
  54. Convert a cmp= function into a key= function
  55. """
  56. class K(object):
  57. def __init__(self, obj, *args):
  58. self.obj = obj
  59. def __lt__(self, other):
  60. return mycmp(self.obj, other.obj) < 0
  61. def __gt__(self, other):
  62. return mycmp(self.obj, other.obj) > 0
  63. def __eq__(self, other):
  64. return mycmp(self.obj, other.obj) == 0
  65. def __le__(self, other):
  66. return mycmp(self.obj, other.obj) <= 0
  67. def __ge__(self, other):
  68. return mycmp(self.obj, other.obj) >= 0
  69. def __ne__(self, other):
  70. return mycmp(self.obj, other.obj) != 0
  71. return K
  72. def current_date_for_filename() -> str:
  73. """
  74. ISO8601 current date, adapted to be used in filename (for
  75. webdav feature for example), with trouble-free characters.
  76. :return: current date as string like "2018-03-19T15.49.27.246592"
  77. """
  78. # INFO - G.M - 19-03-2018 - As ':' is in transform_to_bdd method in
  79. # webdav utils, it may cause trouble. So, it should be replaced to
  80. # a character which will not change in bdd.
  81. return datetime.datetime.now().isoformat().replace(':', '.')
  82. # INFO - G.M - 2018-08-02 - Simple password generator, inspired by
  83. # https://gist.github.com/23maverick23/4131896
  84. ALLOWED_AUTOGEN_PASSWORD_CHAR = string.ascii_letters + \
  85. string.digits + \
  86. string.punctuation
  87. DEFAULT_PASSWORD_GEN_CHAR_LENGTH = 12
  88. def password_generator(
  89. length: int=DEFAULT_PASSWORD_GEN_CHAR_LENGTH,
  90. chars: str=ALLOWED_AUTOGEN_PASSWORD_CHAR
  91. ) -> str:
  92. """
  93. :param length: length of the new password
  94. :param chars: characters allowed
  95. :return: password as string
  96. """
  97. return ''.join(random.choice(chars) for char_number in range(length))
  98. def clamp(val: float, minimum: float = 0.0, maximum: float= 255.0) -> int:
  99. """ Fix value between min an max"""
  100. if val < minimum:
  101. return minimum
  102. if val > maximum:
  103. return maximum
  104. return int(val)
  105. COLOR_DARKEN_SCALE_FACTOR = 0.85
  106. COLOR_LIGHTEN_SCALE_FACTOR = 1.15
  107. class Color(object):
  108. def __init__(self, base_hex_code: str):
  109. """
  110. :param base_hex_code: hex color like '#FFFFFF'
  111. """
  112. assert len(base_hex_code) == 7
  113. self._base_hex_code = base_hex_code
  114. # INFO - G.M - 2018-08-10 - get_hexcolor, inspired by
  115. # https://thadeusb.com/weblog/2010/10/10/python_scale_hex_color/
  116. def get_hexcolor(self, scalefactor: float) -> str:
  117. """
  118. :param scalefactor: factor of scaling,
  119. value between 0 and 1 darken the color,
  120. value >1 lighten the color.
  121. :return: new hex_color
  122. """
  123. hex_color = self._base_hex_code.strip('#')
  124. assert scalefactor > 0
  125. r = int(hex_color[:2], 16)
  126. g = int(hex_color[2:4], 16)
  127. b = int(hex_color[4:], 16)
  128. h, l, s = colorsys.rgb_to_hls(r, g, b)
  129. l = scalefactor * l
  130. r, g, b = colorsys.hls_to_rgb(h, l, s)
  131. return "#%02x%02x%02x" % (clamp(r), clamp(g), clamp(b))
  132. @property
  133. def normal(self):
  134. return self._base_hex_code
  135. @property
  136. def darken(self):
  137. return self.get_hexcolor(COLOR_DARKEN_SCALE_FACTOR)
  138. @property
  139. def lighten(self):
  140. return self.get_hexcolor(COLOR_LIGHTEN_SCALE_FACTOR)