workspace.py 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. # -*- coding: utf-8 -*-
  2. import typing
  3. from sqlalchemy.orm import Query
  4. from sqlalchemy.orm import Session
  5. from tracim_backend import CFG
  6. from tracim_backend.exceptions import EmptyLabelNotAllowed
  7. from tracim_backend.lib.utils.translation import fake_translator as _
  8. from tracim_backend.lib.core.userworkspace import RoleApi
  9. from tracim_backend.models.auth import Group
  10. from tracim_backend.models.auth import User
  11. from tracim_backend.models.context_models import WorkspaceInContext
  12. from tracim_backend.models.data import UserRoleInWorkspace
  13. from tracim_backend.models.data import Workspace
  14. __author__ = 'damien'
  15. class WorkspaceApi(object):
  16. def __init__(
  17. self,
  18. session: Session,
  19. current_user: User,
  20. config: CFG,
  21. force_role: bool=False
  22. ):
  23. """
  24. :param current_user: Current user of context
  25. :param force_role: If True, app role in queries even if admin
  26. """
  27. self._session = session
  28. self._user = current_user
  29. self._config = config
  30. self._force_role = force_role
  31. def _base_query_without_roles(self):
  32. return self._session.query(Workspace).filter(Workspace.is_deleted == False)
  33. def _base_query(self):
  34. if not self._force_role and self._user.profile.id>=Group.TIM_ADMIN:
  35. return self._base_query_without_roles()
  36. return self._session.query(Workspace).\
  37. join(Workspace.roles).\
  38. filter(UserRoleInWorkspace.user_id == self._user.user_id).\
  39. filter(Workspace.is_deleted == False)
  40. def get_workspace_with_context(
  41. self,
  42. workspace: Workspace
  43. ) -> WorkspaceInContext:
  44. """
  45. Return WorkspaceInContext object from Workspace
  46. """
  47. workspace = WorkspaceInContext(
  48. workspace=workspace,
  49. dbsession=self._session,
  50. config=self._config,
  51. )
  52. return workspace
  53. def create_workspace(
  54. self,
  55. label: str='',
  56. description: str='',
  57. calendar_enabled: bool=False,
  58. save_now: bool=False,
  59. ) -> Workspace:
  60. if not label:
  61. raise EmptyLabelNotAllowed('Workspace label cannot be empty')
  62. workspace = Workspace()
  63. workspace.label = label
  64. workspace.description = description
  65. workspace.calendar_enabled = calendar_enabled
  66. # By default, we force the current user to be the workspace manager
  67. # And to receive email notifications
  68. role_api = RoleApi(
  69. session=self._session,
  70. current_user=self._user,
  71. config=self._config
  72. )
  73. role = role_api.create_one(
  74. self._user,
  75. workspace,
  76. UserRoleInWorkspace.WORKSPACE_MANAGER,
  77. with_notif=True,
  78. )
  79. self._session.add(workspace)
  80. self._session.add(role)
  81. if save_now:
  82. self._session.flush()
  83. # TODO - G.M - 28-03-2018 - [Calendar] Reenable calendar stuff
  84. # if calendar_enabled:
  85. # self._ensure_calendar_exist(workspace)
  86. # else:
  87. # self._disable_calendar(workspace)
  88. return workspace
  89. def update_workspace(
  90. self,
  91. workspace: Workspace,
  92. label: str,
  93. description: str,
  94. save_now: bool=False,
  95. ) -> Workspace:
  96. """
  97. Update workspace
  98. :param workspace: workspace to update
  99. :param label: new label of workspace
  100. :param description: new description
  101. :param save_now: database flush
  102. :return: updated workspace
  103. """
  104. if not label:
  105. raise EmptyLabelNotAllowed('Workspace label cannot be empty')
  106. workspace.label = label
  107. workspace.description = description
  108. if save_now:
  109. self.save(workspace)
  110. return workspace
  111. def get_one(self, id):
  112. return self._base_query().filter(Workspace.workspace_id == id).one()
  113. def get_one_by_label(self, label: str) -> Workspace:
  114. return self._base_query().filter(Workspace.label == label).one()
  115. """
  116. def get_one_for_current_user(self, id):
  117. return self._base_query().filter(Workspace.workspace_id==id).\
  118. session.query(ZKContact).filter(ZKContact.groups.any(ZKGroup.id.in_([1,2,3])))
  119. filter(sqla.).one()
  120. """
  121. def get_all(self):
  122. return self._base_query().all()
  123. def get_all_for_user(self, user: User, ignored_ids=None):
  124. workspaces = []
  125. for role in user.roles:
  126. if not role.workspace.is_deleted:
  127. if not ignored_ids:
  128. workspaces.append(role.workspace)
  129. elif role.workspace.workspace_id not in ignored_ids:
  130. workspaces.append(role.workspace)
  131. else:
  132. pass # do not return workspace
  133. workspaces.sort(key=lambda workspace: workspace.label.lower())
  134. return workspaces
  135. def get_all_manageable(self) -> typing.List[Workspace]:
  136. """Get all workspaces the current user has manager rights on."""
  137. workspaces = [] # type: typing.List[Workspace]
  138. if self._user.profile.id == Group.TIM_ADMIN:
  139. workspaces = self._base_query().order_by(Workspace.label).all()
  140. elif self._user.profile.id == Group.TIM_MANAGER:
  141. workspaces = self._base_query() \
  142. .filter(
  143. UserRoleInWorkspace.role ==
  144. UserRoleInWorkspace.WORKSPACE_MANAGER
  145. ) \
  146. .order_by(Workspace.label) \
  147. .all()
  148. return workspaces
  149. def disable_notifications(self, user: User, workspace: Workspace):
  150. for role in user.roles:
  151. if role.workspace==workspace:
  152. role.do_notify = False
  153. def enable_notifications(self, user: User, workspace: Workspace):
  154. for role in user.roles:
  155. if role.workspace==workspace:
  156. role.do_notify = True
  157. def get_notifiable_roles(self, workspace: Workspace) -> [UserRoleInWorkspace]:
  158. roles = []
  159. for role in workspace.roles:
  160. if role.do_notify==True \
  161. and role.user!=self._user \
  162. and role.user.is_active:
  163. roles.append(role)
  164. return roles
  165. def save(self, workspace: Workspace):
  166. self._session.flush()
  167. def delete_one(self, workspace_id, flush=True):
  168. workspace = self.get_one(workspace_id)
  169. workspace.is_deleted = True
  170. if flush:
  171. self._session.flush()
  172. def restore_one(self, workspace_id, flush=True):
  173. workspace = self._session.query(Workspace)\
  174. .filter(Workspace.is_deleted==True)\
  175. .filter(Workspace.workspace_id==workspace_id).one()
  176. workspace.is_deleted = False
  177. if flush:
  178. self._session.flush()
  179. return workspace
  180. def execute_created_workspace_actions(self, workspace: Workspace) -> None:
  181. pass
  182. # TODO - G.M - 28-03-2018 - [Calendar] Re-enable this calendar stuff
  183. # self.ensure_calendar_exist(workspace)
  184. # TODO - G.M - 28-03-2018 - [Calendar] Re-enable this calendar stuff
  185. # def ensure_calendar_exist(self, workspace: Workspace) -> None:
  186. # # Note: Cyclic imports
  187. # from tracim.lib.calendar import CalendarManager
  188. # from tracim.model.organisational import WorkspaceCalendar
  189. #
  190. # calendar_manager = CalendarManager(self._user)
  191. #
  192. # try:
  193. # calendar_manager.enable_calendar_file(
  194. # calendar_class=WorkspaceCalendar,
  195. # related_object_id=workspace.workspace_id,
  196. # raise_=True,
  197. # )
  198. # # If previous calendar file no exist, calendar must be created
  199. # except FileNotFoundError:
  200. # self._user.ensure_auth_token()
  201. #
  202. # # Ensure database is up-to-date
  203. # self.session.flush()
  204. # transaction.commit()
  205. #
  206. # calendar_manager.create_then_remove_fake_event(
  207. # calendar_class=WorkspaceCalendar,
  208. # related_object_id=workspace.workspace_id,
  209. # )
  210. #
  211. # def disable_calendar(self, workspace: Workspace) -> None:
  212. # # Note: Cyclic imports
  213. # from tracim.lib.calendar import CalendarManager
  214. # from tracim.model.organisational import WorkspaceCalendar
  215. #
  216. # calendar_manager = CalendarManager(self._user)
  217. # calendar_manager.disable_calendar_file(
  218. # calendar_class=WorkspaceCalendar,
  219. # related_object_id=workspace.workspace_id,
  220. # raise_=False,
  221. # )
  222. def get_base_query(self) -> Query:
  223. return self._base_query()
  224. def generate_label(self) -> str:
  225. """
  226. :return: Generated workspace label
  227. """
  228. query = self._base_query_without_roles() \
  229. .filter(Workspace.label.ilike('{0}%'.format(
  230. _('Workspace'),
  231. )))
  232. return _('Workspace {}').format(
  233. query.count() + 1,
  234. )
  235. class UnsafeWorkspaceApi(WorkspaceApi):
  236. def _base_query(self):
  237. return self.session.query(Workspace).filter(Workspace.is_deleted==False)