Skip to content

Commit abc449f

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 e1b351c commit abc449f

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
@@ -137,6 +137,7 @@ and this project adheres to
137137

138138
### Added
139139

140+
- ✨(backend) Comments on text editor #1309
140141
- 👷(CI) add bundle size check job #1268
141142
- ✨(frontend) use title first emoji as doc icon in tree #1289
142143

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
@@ -889,3 +889,47 @@ class MoveDocumentSerializer(serializers.Serializer):
889889
choices=enums.MoveNodePositionChoices.choices,
890890
default=enums.MoveNodePositionChoices.LAST_CHILD,
891891
)
892+
893+
894+
class CommentSerializer(serializers.ModelSerializer):
895+
"""Serialize comments."""
896+
897+
user = UserLightSerializer(read_only=True)
898+
abilities = serializers.SerializerMethodField(read_only=True)
899+
900+
class Meta:
901+
model = models.Comment
902+
fields = [
903+
"id",
904+
"content",
905+
"created_at",
906+
"updated_at",
907+
"user",
908+
"document",
909+
"abilities",
910+
]
911+
read_only_fields = [
912+
"id",
913+
"created_at",
914+
"updated_at",
915+
"user",
916+
"document",
917+
"abilities",
918+
]
919+
920+
def get_abilities(self, comment) -> dict:
921+
"""Return abilities of the logged-in user on the instance."""
922+
request = self.context.get("request")
923+
if request:
924+
return comment.get_abilities(request.user)
925+
return {}
926+
927+
def validate(self, attrs):
928+
"""Validate invitation data."""
929+
request = self.context.get("request")
930+
user = getattr(request, "user", None)
931+
932+
attrs["document_id"] = self.context["resource_id"]
933+
attrs["user_id"] = user.id if user else None
934+
935+
return attrs

src/backend/core/api/viewsets.py

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

22382238
return theme_customization
2239+
2240+
2241+
class CommentViewSet(
2242+
viewsets.ModelViewSet,
2243+
):
2244+
"""API ViewSet for comments."""
2245+
2246+
permission_classes = [permissions.CommentPermission]
2247+
queryset = models.Comment.objects.select_related("user", "document").all()
2248+
serializer_class = serializers.CommentSerializer
2249+
pagination_class = Pagination
2250+
_document = None
2251+
2252+
def get_document_or_404(self):
2253+
"""Get the document related to the viewset or raise a 404 error."""
2254+
if self._document is None:
2255+
try:
2256+
self._document = models.Document.objects.get(
2257+
pk=self.kwargs["resource_id"],
2258+
)
2259+
except models.Document.DoesNotExist as e:
2260+
raise drf.exceptions.NotFound("Document not found.") from e
2261+
return self._document
2262+
2263+
def get_serializer_context(self):
2264+
"""Extra context provided to the serializer class."""
2265+
context = super().get_serializer_context()
2266+
context["resource_id"] = self.kwargs["resource_id"]
2267+
return context
2268+
2269+
def get_queryset(self):
2270+
"""Return the queryset according to the action."""
2271+
return super().get_queryset().filter(document=self.kwargs["resource_id"])

0 commit comments

Comments
 (0)