helpers.py 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. # -*- coding: utf-8 -*-
  2. """WebHelpers used in tracim."""
  3. # from webhelpers import date, feedgenerator, html, number, misc, text
  4. import datetime
  5. from babel.dates import format_date
  6. from babel.dates import format_time
  7. from markupsafe import Markup
  8. import pytz
  9. import slugify
  10. import tg
  11. from tg import tmpl_context
  12. from tg.i18n import ugettext as _
  13. from tracim.lib import app_globals as plag
  14. from tracim.lib import CST
  15. from tracim.lib.base import logger
  16. from tracim.lib.content import ContentApi
  17. from tracim.lib.userworkspace import RoleApi
  18. from tracim.lib.workspace import WorkspaceApi
  19. from tracim.model.data import Content
  20. from tracim.model.data import ContentStatus
  21. from tracim.model.data import ContentType
  22. from tracim.model.data import UserRoleInWorkspace
  23. from tracim.model.data import Workspace
  24. def get_lang() -> str:
  25. """
  26. Gets language code.
  27. Provides the first language:
  28. - asked by the request to the server,
  29. - supported by Tracim.
  30. """
  31. # TODO - A.P - language code access from test environment
  32. # try based workaround instead of raw get language call for test
  33. # environment only, this should be set with tg.i18n.set_lang but
  34. # I was unable to achieve that.
  35. try:
  36. result = tg.i18n.get_lang(all=False)[0]
  37. except IndexError:
  38. result = 'en'
  39. return result
  40. def get_with_timezone(
  41. datetime_object: datetime.datetime,
  42. to_timezone: str='',
  43. default_from_timezone: str='UTC',
  44. ) -> datetime.datetime:
  45. """
  46. Change timezone of a date
  47. :param datetime_object: datetime to update
  48. :param to_timezone: timezone name, if equal to '',
  49. try to grap current user timezone. If no given timezone name and no
  50. current user timezone, return original date time
  51. :param default_from_timezone: datetime original timezone if datetime
  52. object is naive
  53. :return: datetime updated
  54. """
  55. # If no to_timezone, try to grab from current user
  56. if not to_timezone and tmpl_context.current_user:
  57. to_timezone = tmpl_context.current_user.timezone
  58. # If no to_timezone, return original datetime
  59. if not to_timezone:
  60. return datetime_object
  61. # If datetime_object have not timezone, set new from default_from_timezone
  62. if not datetime_object.tzinfo:
  63. from_tzinfo = pytz.timezone(default_from_timezone)
  64. datetime_object = from_tzinfo.localize(datetime_object)
  65. new_tzinfo = pytz.timezone(to_timezone)
  66. return datetime_object.astimezone(new_tzinfo)
  67. def date_time_in_long_format(datetime_object, format=''):
  68. current_locale = tg.i18n.get_lang()[0]
  69. date = format_date(datetime_object, locale=current_locale)
  70. time = format_time(datetime_object, locale=current_locale)
  71. return _('{date} at {time}').format(date=date, time=time)
  72. def date_time(datetime_object):
  73. return date_time_in_long_format(datetime_object)
  74. def date(datetime_object):
  75. current_locale = tg.i18n.get_lang()[0]
  76. return format_date(datetime_object, locale=current_locale)
  77. def time(datetime_object):
  78. current_locale = tg.i18n.get_lang()[0]
  79. return format_time(datetime_object, locale=current_locale)
  80. def update_date(datetime_object):
  81. current_locale = tg.i18n.get_lang()[0]
  82. return format_date(datetime_object, locale=current_locale)
  83. def update_time(datetime_object):
  84. current_locale = tg.i18n.get_lang()[0]
  85. return format_time(datetime_object, locale=current_locale)
  86. def format_short(datetime_object):
  87. return datetime_object.strftime(format = plag.Globals.SHORT_DATE_FORMAT.__str__())
  88. def user_friendly_file_size(file_size: int):
  89. file_size_kib = file_size/1024
  90. if file_size_kib<1024:
  91. return '{:.3f} ko'.format(file_size_kib)
  92. else:
  93. mega_size = file_size_kib/1024
  94. if mega_size<1024:
  95. return '{:.3f} Mo'.format(int(mega_size))
  96. def current_year():
  97. now = datetime.datetime.now()
  98. return now.strftime('%Y')
  99. def icon(icon_name, white=False):
  100. if (white):
  101. return Markup('<i class="icon-%s icon-white"></i>' % icon_name)
  102. else:
  103. return Markup('<i class="icon-%s"></i>' % icon_name)
  104. class ICON(object):
  105. Shared = '<i class="fa fa-group"></i>'
  106. Private = '<i class="fa fa-key"></i>'
  107. def IconPath(icon_size, icon_path):
  108. return tg.url('/assets/icons/{0}x{0}/{1}.png'.format(icon_size, icon_path))
  109. def PodVersion():
  110. return plag.Globals.VERSION_NUMBER
  111. def RoleLevelAssociatedCss(role_level):
  112. if role_level==UserRoleInWorkspace.NOT_APPLICABLE:
  113. return '#CCC'
  114. elif role_level==UserRoleInWorkspace.READER:
  115. return '#1fdb11'
  116. elif role_level==UserRoleInWorkspace.CONTRIBUTOR:
  117. return '#759ac5'
  118. elif role_level==UserRoleInWorkspace.CONTENT_MANAGER:
  119. return '#ea983d'
  120. elif role_level==UserRoleInWorkspace.WORKSPACE_MANAGER:
  121. return '#F00'
  122. def AllStatus(type=''):
  123. return ContentStatus.all(type)
  124. def is_debug_mode():
  125. return tg.config.get('debug')
  126. def on_off_to_boolean(on_or_off: str) -> bool:
  127. return True if on_or_off=='on' else False
  128. def convert_id_into_instances(id: str) -> (Workspace, Content):
  129. """
  130. TODO - D.A. - 2014-10-18 - Refactor and move this function where it must be placed
  131. convert an id like 'workspace_<workspace_id>|content_<content_id>'
  132. into two objects: the given workspace instance and the given content instance
  133. """
  134. if id=='#':
  135. return None, None
  136. workspace_str = ''
  137. content_str = ''
  138. try:
  139. workspace_str, content_str = id.split(CST.TREEVIEW_MENU.ITEM_SEPARATOR)
  140. except:
  141. pass
  142. workspace = None
  143. content = None
  144. try:
  145. workspace_data = workspace_str.split(CST.TREEVIEW_MENU.ID_SEPARATOR)
  146. workspace_id = workspace_data[1]
  147. workspace = WorkspaceApi(tg.tmpl_context.current_user).get_one(workspace_id)
  148. except:
  149. workspace = None
  150. try:
  151. content_data = content_str.split(CST.TREEVIEW_MENU.ID_SEPARATOR)
  152. content_id = int(content_data[1])
  153. content = ContentApi(
  154. tg.tmpl_context.current_user,
  155. show_archived=True,
  156. show_deleted=True,
  157. ).get_one(content_id, ContentType.Any)
  158. except (IndexError, ValueError) as e:
  159. content = None
  160. return workspace, content
  161. def user_role(user, workspace) -> int:
  162. """
  163. This function works on DictLikeClass() instances
  164. :param user: the serialized version of the user (cf CTX.CURRENT_USER)
  165. :param workspace: the serialized version of the workspace
  166. :return: the user role id (int)
  167. """
  168. for role in user.roles:
  169. if role.workspace.id==workspace.id:
  170. return role.id
  171. return 0
  172. def delete_label_for_item(item) -> str:
  173. """
  174. :param item: is a serialized Content item (be carefull; it's not an instance of 'Content')
  175. :return: the delete label to show to the user (in the right language)
  176. """
  177. return ContentType._DELETE_LABEL[item.type]
  178. def is_item_still_editable(CFG, item):
  179. if item.type.id != 'comment':
  180. return False
  181. # HACK - D.A - 2014-12-24 - item contains a datetime object!!!
  182. # 'item' is a variable which is created by serialization and it should be an instance of DictLikeClass.
  183. # therefore, it contains strins, integers and booleans (something json-ready or almost json-ready)
  184. #
  185. # BUT, the property 'created' is still a datetime object
  186. #
  187. edit_duration = CFG.get_instance().DATA_UPDATE_ALLOWED_DURATION
  188. if edit_duration<0:
  189. return True
  190. elif edit_duration==0:
  191. return False
  192. else:
  193. time_limit = item.created + datetime.timedelta(0, edit_duration)
  194. logger.warning(is_item_still_editable, 'limit is: {}'.format(time_limit))
  195. if datetime.datetime.now() < time_limit:
  196. return True
  197. return False
  198. def shorten(text: str, maxlength: int, add_three_points=True) -> str:
  199. result = text
  200. if len(text)>maxlength:
  201. result = text[:maxlength]
  202. if add_three_points:
  203. result += '…'
  204. return result
  205. def ini_conf_to_bool(value):
  206. """
  207. Depending INI file interpreter, False values are simple parsed as string,
  208. so use this function to consider them as boolean
  209. :param value: value of ini parameter
  210. :return: bollean value
  211. """
  212. if value in ('False', 'false', '0', 'off', 'no'):
  213. return False
  214. return bool(value)
  215. def is_user_externalized_field(field_name):
  216. if not tg.config.get('auth_instance').is_internal:
  217. return field_name in tg.config.get('auth_instance').managed_fields
  218. return False
  219. def slug(string):
  220. return slugify.slugify(string, only_ascii=True)
  221. def get_viewable_members_for_role(role: int, members: [dict]) -> [dict]:
  222. """
  223. Return given users list with viewable members by given role.
  224. :param role: One of tracim.model.data.UserRoleInWorkspace roles
  225. :param members: list of workspace members. Where member object own "role"
  226. property containing tracim.model.data.UserRoleInWorkspace role.
  227. :return: filtered member list
  228. """
  229. viewable_users = []
  230. for member in members:
  231. if RoleApi.role_can_read_member_role(
  232. reader_role=role,
  233. tested_role=member.role
  234. ):
  235. viewable_users.append(member)
  236. return viewable_users