file_controller.py 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. # coding=utf-8
  2. import typing
  3. import transaction
  4. from pyramid.config import Configurator
  5. from tracim.models.data import UserRoleInWorkspace
  6. try: # Python 3.5+
  7. from http import HTTPStatus
  8. except ImportError:
  9. from http import client as HTTPStatus
  10. from tracim import TracimRequest
  11. from tracim.extensions import hapic
  12. from tracim.lib.core.content import ContentApi
  13. from tracim.views.controllers import Controller
  14. from tracim.views.core_api.schemas import FileContentSchema
  15. from tracim.views.core_api.schemas import FileRevisionSchema
  16. from tracim.views.core_api.schemas import SetContentStatusSchema
  17. from tracim.views.core_api.schemas import FileModifySchema
  18. from tracim.views.core_api.schemas import WorkspaceAndContentIdPathSchema
  19. from tracim.views.core_api.schemas import NoContentSchema
  20. from tracim.lib.utils.authorization import require_content_types
  21. from tracim.lib.utils.authorization import require_workspace_role
  22. from tracim.exceptions import WorkspaceNotFound, ContentTypeNotAllowed
  23. from tracim.exceptions import InsufficientUserRoleInWorkspace
  24. from tracim.exceptions import NotAuthenticated
  25. from tracim.exceptions import AuthenticationFailed
  26. from tracim.models.context_models import ContentInContext
  27. from tracim.models.context_models import RevisionInContext
  28. from tracim.models.contents import ContentTypeLegacy as ContentType
  29. from tracim.models.contents import file_type
  30. from tracim.models.revision_protection import new_revision
  31. FILE_ENDPOINTS_TAG = 'Files'
  32. class FileController(Controller):
  33. @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
  34. @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
  35. @hapic.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)
  36. @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
  37. @hapic.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
  38. @hapic.handle_exception(ContentTypeNotAllowed, HTTPStatus.BAD_REQUEST)
  39. @require_workspace_role(UserRoleInWorkspace.READER)
  40. @require_content_types([file_type])
  41. @hapic.input_path(WorkspaceAndContentIdPathSchema())
  42. @hapic.output_body(FileContentSchema())
  43. def get_file(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext: # nopep8
  44. """
  45. Get thread content
  46. """
  47. app_config = request.registry.settings['CFG']
  48. api = ContentApi(
  49. current_user=request.current_user,
  50. session=request.dbsession,
  51. config=app_config,
  52. )
  53. content = api.get_one(
  54. hapic_data.path.content_id,
  55. content_type=ContentType.Any
  56. )
  57. return api.get_content_in_context(content)
  58. @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
  59. @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
  60. @hapic.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)
  61. @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
  62. @hapic.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
  63. @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
  64. @require_content_types([file_type])
  65. @hapic.input_path(WorkspaceAndContentIdPathSchema())
  66. @hapic.input_body(FileModifySchema())
  67. @hapic.output_body(FileContentSchema())
  68. def update_file(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext: # nopep8
  69. """
  70. update thread
  71. """
  72. app_config = request.registry.settings['CFG']
  73. api = ContentApi(
  74. current_user=request.current_user,
  75. session=request.dbsession,
  76. config=app_config,
  77. )
  78. content = api.get_one(
  79. hapic_data.path.content_id,
  80. content_type=ContentType.Any
  81. )
  82. with new_revision(
  83. session=request.dbsession,
  84. tm=transaction.manager,
  85. content=content
  86. ):
  87. api.update_content(
  88. item=content,
  89. new_label=hapic_data.body.label,
  90. new_content=hapic_data.body.raw_content,
  91. )
  92. api.save(content)
  93. return api.get_content_in_context(content)
  94. @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
  95. @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
  96. @hapic.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)
  97. @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
  98. @hapic.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
  99. @require_workspace_role(UserRoleInWorkspace.READER)
  100. @require_content_types([file_type])
  101. @hapic.input_path(WorkspaceAndContentIdPathSchema())
  102. @hapic.output_body(FileRevisionSchema(many=True))
  103. def get_file_revisions(
  104. self,
  105. context,
  106. request: TracimRequest,
  107. hapic_data=None
  108. ) -> typing.List[RevisionInContext]:
  109. """
  110. get file revisions
  111. """
  112. app_config = request.registry.settings['CFG']
  113. api = ContentApi(
  114. current_user=request.current_user,
  115. session=request.dbsession,
  116. config=app_config,
  117. )
  118. content = api.get_one(
  119. hapic_data.path.content_id,
  120. content_type=ContentType.Any
  121. )
  122. revisions = content.revisions
  123. return [
  124. api.get_revision_in_context(revision)
  125. for revision in revisions
  126. ]
  127. @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
  128. @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
  129. @hapic.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)
  130. @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
  131. @hapic.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
  132. @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
  133. @require_content_types([file_type])
  134. @hapic.input_path(WorkspaceAndContentIdPathSchema())
  135. @hapic.input_body(SetContentStatusSchema())
  136. @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT) # nopep8
  137. def set_file_status(self, context, request: TracimRequest, hapic_data=None) -> None: # nopep8
  138. """
  139. set file status
  140. """
  141. app_config = request.registry.settings['CFG']
  142. api = ContentApi(
  143. current_user=request.current_user,
  144. session=request.dbsession,
  145. config=app_config,
  146. )
  147. content = api.get_one(
  148. hapic_data.path.content_id,
  149. content_type=ContentType.Any
  150. )
  151. with new_revision(
  152. session=request.dbsession,
  153. tm=transaction.manager,
  154. content=content
  155. ):
  156. api.set_status(
  157. content,
  158. hapic_data.body.status,
  159. )
  160. api.save(content)
  161. return
  162. def bind(self, configurator: Configurator) -> None:
  163. # Get file
  164. configurator.add_route(
  165. 'file',
  166. '/workspaces/{workspace_id}/files/{content_id}',
  167. request_method='GET'
  168. )
  169. configurator.add_view(self.get_file, route_name='file') # nopep8
  170. # update file
  171. configurator.add_route(
  172. 'update_file',
  173. '/workspaces/{workspace_id}/files/{content_id}',
  174. request_method='PUT'
  175. ) # nopep8
  176. configurator.add_view(self.update_file, route_name='update_file') # nopep8
  177. # get file revisions
  178. configurator.add_route(
  179. 'file_revisions',
  180. '/workspaces/{workspace_id}/files/{content_id}/revisions', # nopep8
  181. request_method='GET'
  182. )
  183. configurator.add_view(self.get_file_revisions, route_name='file_revisions') # nopep8
  184. # get file revisions
  185. configurator.add_route(
  186. 'set_file_status',
  187. '/workspaces/{workspace_id}/files/{content_id}/status', # nopep8
  188. request_method='PUT'
  189. )
  190. configurator.add_view(self.set_file_status, route_name='set_file_status') # nopep8