workspace.py 9.5KB

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