Skip to content

Commit 0a53ca5

Browse files
lunikaAntoLC
authored andcommitted
✨(backend) add comment viewset
This commit add the CRUD part to manage comment lifeycle. Permissions are relying on the Document and Comment abilities. Comment viewset depends on the Document route and is added to the document_related_router. Dedicated serializer and permission are created.
1 parent fdecd7b commit 0a53ca5

File tree

6 files changed

+687
-1
lines changed

6 files changed

+687
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ and this project adheres to
2121

2222
### Added
2323

24+
- ✨(backend) Comments on text editor #1309
2425
- 👷(CI) add bundle size check job #1268
2526
- ✨(frontend) use title first emoji as doc icon in tree #1289
2627

src/backend/core/api/permissions.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,19 @@ def has_object_permission(self, request, view, obj):
171171

172172
action = view.action
173173
return abilities.get(action, False)
174+
175+
176+
class CommentPermission(permissions.BasePermission):
177+
"""Permission class for comments."""
178+
179+
def has_permission(self, request, view):
180+
"""Check permission for a given object."""
181+
if view.action in ["create", "list"]:
182+
document_abilities = view.get_document_or_404().get_abilities(request.user)
183+
return document_abilities["comment"]
184+
185+
return True
186+
187+
def has_object_permission(self, request, view, obj):
188+
"""Check permission for a given object."""
189+
return obj.get_abilities(request.user).get(view.action, False)

src/backend/core/api/serializers.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,3 +821,47 @@ class MoveDocumentSerializer(serializers.Serializer):
821821
choices=enums.MoveNodePositionChoices.choices,
822822
default=enums.MoveNodePositionChoices.LAST_CHILD,
823823
)
824+
825+
826+
class CommentSerializer(serializers.ModelSerializer):
827+
"""Serialize comments."""
828+
829+
user = UserLightSerializer(read_only=True)
830+
abilities = serializers.SerializerMethodField(read_only=True)
831+
832+
class Meta:
833+
model = models.Comment
834+
fields = [
835+
"id",
836+
"content",
837+
"created_at",
838+
"updated_at",
839+
"user",
840+
"document",
841+
"abilities",
842+
]
843+
read_only_fields = [
844+
"id",
845+
"created_at",
846+
"updated_at",
847+
"user",
848+
"document",
849+
"abilities",
850+
]
851+
852+
def get_abilities(self, comment) -> dict:
853+
"""Return abilities of the logged-in user on the instance."""
854+
request = self.context.get("request")
855+
if request:
856+
return comment.get_abilities(request.user)
857+
return {}
858+
859+
def validate(self, attrs):
860+
"""Validate invitation data."""
861+
request = self.context.get("request")
862+
user = getattr(request, "user", None)
863+
864+
attrs["document_id"] = self.context["resource_id"]
865+
attrs["user_id"] = user.id if user else None
866+
867+
return attrs

src/backend/core/api/viewsets.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2168,3 +2168,36 @@ def _load_theme_customization(self):
21682168
)
21692169

21702170
return theme_customization
2171+
2172+
2173+
class CommentViewSet(
2174+
viewsets.ModelViewSet,
2175+
):
2176+
"""API ViewSet for comments."""
2177+
2178+
permission_classes = [permissions.CommentPermission]
2179+
queryset = models.Comment.objects.select_related("user", "document").all()
2180+
serializer_class = serializers.CommentSerializer
2181+
pagination_class = Pagination
2182+
_document = None
2183+
2184+
def get_document_or_404(self):
2185+
"""Get the document related to the viewset or raise a 404 error."""
2186+
if self._document is None:
2187+
try:
2188+
self._document = models.Document.objects.get(
2189+
pk=self.kwargs["resource_id"],
2190+
)
2191+
except models.Document.DoesNotExist as e:
2192+
raise drf.exceptions.NotFound("Document not found.") from e
2193+
return self._document
2194+
2195+
def get_serializer_context(self):
2196+
"""Extra context provided to the serializer class."""
2197+
context = super().get_serializer_context()
2198+
context["resource_id"] = self.kwargs["resource_id"]
2199+
return context
2200+
2201+
def get_queryset(self):
2202+
"""Return the queryset according to the action."""
2203+
return super().get_queryset().filter(document=self.kwargs["resource_id"])

0 commit comments

Comments
 (0)