comment_controller.py 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. # coding=utf-8
  2. import transaction
  3. from pyramid.config import Configurator
  4. try: # Python 3.5+
  5. from http import HTTPStatus
  6. except ImportError:
  7. from http import client as HTTPStatus
  8. from tracim import TracimRequest
  9. from tracim.extensions import hapic
  10. from tracim.lib.core.content import ContentApi
  11. from tracim.lib.core.workspace import WorkspaceApi
  12. from tracim.lib.utils.authorization import require_workspace_role
  13. from tracim.lib.utils.authorization import require_comment_ownership_or_role
  14. from tracim.views.controllers import Controller
  15. from tracim.views.core_api.schemas import CommentSchema
  16. from tracim.views.core_api.schemas import CommentsPathSchema
  17. from tracim.views.core_api.schemas import SetCommentSchema
  18. from tracim.views.core_api.schemas import WorkspaceAndContentIdPathSchema
  19. from tracim.views.core_api.schemas import NoContentSchema
  20. from tracim.exceptions import WorkspaceNotFound
  21. from tracim.exceptions import InsufficientUserWorkspaceRole
  22. from tracim.exceptions import NotAuthenticated
  23. from tracim.exceptions import AuthenticationFailed
  24. from tracim.models.contents import ContentTypeLegacy as ContentType
  25. from tracim.models.revision_protection import new_revision
  26. from tracim.models.data import UserRoleInWorkspace
  27. COMMENT_ENDPOINTS_TAG = 'Comments'
  28. class CommentController(Controller):
  29. @hapic.with_api_doc(tags=[COMMENT_ENDPOINTS_TAG])
  30. @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
  31. @hapic.handle_exception(InsufficientUserWorkspaceRole, HTTPStatus.FORBIDDEN)
  32. @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
  33. @hapic.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
  34. @require_workspace_role(UserRoleInWorkspace.READER)
  35. @hapic.input_path(WorkspaceAndContentIdPathSchema())
  36. @hapic.output_body(CommentSchema(many=True),)
  37. def content_comments(self, context, request: TracimRequest, hapic_data=None):
  38. """
  39. Get all comments related to a content in asc order (first is the oldest)
  40. """
  41. # login = hapic_data.body
  42. app_config = request.registry.settings['CFG']
  43. api = ContentApi(
  44. current_user=request.current_user,
  45. session=request.dbsession,
  46. config=app_config,
  47. )
  48. content = api.get_one(
  49. hapic_data.path.content_id,
  50. content_type=ContentType.Any
  51. )
  52. comments = content.get_comments()
  53. comments.sort(key=lambda comment: comment.created)
  54. return [api.get_content_in_context(comment)
  55. for comment in comments
  56. ]
  57. @hapic.with_api_doc(tags=[COMMENT_ENDPOINTS_TAG])
  58. @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
  59. @hapic.handle_exception(InsufficientUserWorkspaceRole, HTTPStatus.FORBIDDEN)
  60. @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
  61. @hapic.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
  62. @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
  63. @hapic.input_path(WorkspaceAndContentIdPathSchema())
  64. @hapic.input_body(SetCommentSchema())
  65. @hapic.output_body(CommentSchema(),)
  66. def add_comment(self, context, request: TracimRequest, hapic_data=None):
  67. """
  68. Add new comment
  69. """
  70. # login = hapic_data.body
  71. app_config = request.registry.settings['CFG']
  72. api = ContentApi(
  73. current_user=request.current_user,
  74. session=request.dbsession,
  75. config=app_config,
  76. )
  77. content = api.get_one(
  78. hapic_data.path.content_id,
  79. content_type=ContentType.Any
  80. )
  81. comment = api.create_comment(
  82. content.workspace,
  83. content,
  84. hapic_data.body.raw_content,
  85. do_save=True,
  86. )
  87. return api.get_content_in_context(comment)
  88. @hapic.with_api_doc(tags=[COMMENT_ENDPOINTS_TAG])
  89. @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
  90. @hapic.handle_exception(InsufficientUserWorkspaceRole, HTTPStatus.FORBIDDEN)
  91. @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
  92. @hapic.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
  93. @require_comment_ownership_or_role(
  94. minimal_required_role_for_anyone=UserRoleInWorkspace.WORKSPACE_MANAGER,
  95. minimal_required_role_for_owner=UserRoleInWorkspace.CONTRIBUTOR,
  96. )
  97. @hapic.input_path(CommentsPathSchema())
  98. @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT) # nopep8
  99. def delete_comment(self, context, request: TracimRequest, hapic_data=None):
  100. """
  101. Delete comment
  102. """
  103. app_config = request.registry.settings['CFG']
  104. api = ContentApi(
  105. current_user=request.current_user,
  106. session=request.dbsession,
  107. config=app_config,
  108. )
  109. wapi = WorkspaceApi(
  110. current_user=request.current_user,
  111. session=request.dbsession,
  112. config=app_config,
  113. )
  114. workspace = wapi.get_one(hapic_data.path.workspace_id)
  115. parent = api.get_one(
  116. hapic_data.path.content_id,
  117. content_type=ContentType.Any,
  118. workspace=workspace
  119. )
  120. comment = api.get_one(
  121. hapic_data.path.comment_id,
  122. content_type=ContentType.Comment,
  123. workspace=workspace,
  124. parent=parent,
  125. )
  126. with new_revision(
  127. session=request.dbsession,
  128. tm=transaction.manager,
  129. content=comment
  130. ):
  131. api.delete(comment)
  132. return
  133. def bind(self, configurator: Configurator):
  134. # Get comments
  135. configurator.add_route(
  136. 'content_comments',
  137. '/workspaces/{workspace_id}/contents/{content_id}/comments',
  138. request_method='GET'
  139. )
  140. configurator.add_view(self.content_comments, route_name='content_comments')
  141. # Add comments
  142. configurator.add_route(
  143. 'add_comment',
  144. '/workspaces/{workspace_id}/contents/{content_id}/comments',
  145. request_method='POST'
  146. ) # nopep8
  147. configurator.add_view(self.add_comment, route_name='add_comment')
  148. # delete comments
  149. configurator.add_route(
  150. 'delete_comment',
  151. '/workspaces/{workspace_id}/contents/{content_id}/comments/{comment_id}', # nopep8
  152. request_method='DELETE'
  153. )
  154. configurator.add_view(self.delete_comment, route_name='delete_comment')