request.py 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. # -*- coding: utf-8 -*-
  2. """
  3. TracimRequest and related functions
  4. """
  5. from pyramid.request import Request
  6. from sqlalchemy.orm.exc import NoResultFound
  7. from tracim.exceptions import NotAuthentificated, UserNotExist
  8. from tracim.exceptions import WorkspaceNotFound
  9. from tracim.exceptions import ImmutableAttribute
  10. from tracim.lib.core.user import UserApi
  11. from tracim.lib.core.workspace import WorkspaceApi
  12. from tracim.lib.utils.authorization import JSONDecodeError
  13. from tracim.models import User
  14. from tracim.models.data import Workspace
  15. class TracimRequest(Request):
  16. """
  17. Request with tracim specific params/methods
  18. """
  19. def __init__(
  20. self,
  21. environ,
  22. charset=None,
  23. unicode_errors=None,
  24. decode_param_names=None,
  25. **kw
  26. ):
  27. super().__init__(
  28. environ,
  29. charset,
  30. unicode_errors,
  31. decode_param_names,
  32. **kw
  33. )
  34. # Current workspace, found by request headers or content
  35. self._current_workspace = None # type: Workspace
  36. # Authenticated user
  37. self._current_user = None # type: User
  38. # User found from request headers, content, distinct from authenticated
  39. # user
  40. self._user_candidate = None # type: User
  41. @property
  42. def current_workspace(self) -> Workspace:
  43. """
  44. Get current workspace of the request according to authentification and
  45. request headers (to retrieve workspace). Setted by default value the
  46. first time if not configured.
  47. :return: Workspace of the request
  48. """
  49. if self._current_workspace is None:
  50. self.current_workspace = get_workspace(self.current_user, self)
  51. return self._current_workspace
  52. @current_workspace.setter
  53. def current_workspace(self, workspace: Workspace) -> None:
  54. """
  55. Setting current_workspace
  56. :param workspace:
  57. :return:
  58. """
  59. if self._current_workspace is not None:
  60. raise ImmutableAttribute(
  61. "Can't modify already setted current_workspace"
  62. )
  63. self._current_workspace = workspace
  64. @property
  65. def current_user(self) -> User:
  66. """
  67. Get user from authentication mecanism.
  68. """
  69. if self._current_user is None:
  70. self.current_user = get_auth_safe_user(self)
  71. return self._current_user
  72. @current_user.setter
  73. def current_user(self, user: User) -> None:
  74. if self._current_user is not None:
  75. raise ImmutableAttribute(
  76. "Can't modify already setted current_user"
  77. )
  78. self._current_user = user
  79. # TODO - G.M - 24-05-2018 - Find a better naming for this ?
  80. @property
  81. def candidate_user(self) -> User:
  82. """
  83. Get user from headers/body request. This user is not
  84. the one found by authentication mecanism. This user
  85. can help user to know about who one page is about in
  86. a similar way as current_workspace.
  87. """
  88. if self._user_candidate is None:
  89. self.candidate_user = get_candidate_user(self)
  90. return self._user_candidate
  91. @candidate_user.setter
  92. def candidate_user(self, user: User) -> None:
  93. if self._user_candidate is not None:
  94. raise ImmutableAttribute(
  95. "Can't modify already setted candidate_user"
  96. )
  97. self._user_candidate = user
  98. ###
  99. # Utils for TracimRequest
  100. ###
  101. def get_candidate_user(
  102. request: TracimRequest
  103. ) -> User:
  104. """
  105. Get candidate user
  106. :param request: pyramid request
  107. :return: user found from header/body
  108. """
  109. app_config = request.registry.settings['CFG']
  110. uapi = UserApi(None, session=request.dbsession, config=app_config)
  111. try:
  112. login = None
  113. if 'user_id' in request.matchdict:
  114. login = request.matchdict['user_id']
  115. if not login:
  116. raise UserNotExist('no user_id found, incorrect request ?')
  117. user = uapi.get_one(login)
  118. except NoResultFound:
  119. raise NotAuthentificated('User not found')
  120. return user
  121. def get_auth_safe_user(
  122. request: TracimRequest,
  123. ) -> User:
  124. """
  125. Get current pyramid authenticated user from request
  126. :param request: pyramid request
  127. :return: current authenticated user
  128. """
  129. app_config = request.registry.settings['CFG']
  130. uapi = UserApi(None, session=request.dbsession, config=app_config)
  131. try:
  132. login = request.authenticated_userid
  133. if not login:
  134. raise NotAuthentificated('not authenticated user_id,'
  135. 'Failed Authentification ?')
  136. user = uapi.get_one_by_email(login)
  137. except NoResultFound:
  138. raise NotAuthentificated('User not found')
  139. return user
  140. def get_workspace(
  141. user: User,
  142. request: TracimRequest
  143. ) -> Workspace:
  144. """
  145. Get current workspace from request
  146. :param user: User who want to check the workspace
  147. :param request: pyramid request
  148. :return: current workspace
  149. """
  150. workspace_id = ''
  151. try:
  152. if 'workspace_id' in request.matchdict:
  153. workspace_id = request.matchdict['workspace_id']
  154. if not workspace_id:
  155. raise WorkspaceNotFound('No workspace_id param')
  156. wapi = WorkspaceApi(
  157. current_user=user,
  158. session=request.dbsession,
  159. config=request.registry.settings['CFG']
  160. )
  161. workspace = wapi.get_one(workspace_id)
  162. except JSONDecodeError:
  163. raise WorkspaceNotFound('Bad json body')
  164. except NoResultFound:
  165. raise WorkspaceNotFound(
  166. 'Workspace {} does not exist '
  167. 'or is not visible for this user'.format(workspace_id)
  168. )
  169. return workspace