44from django .utils .decorators import method_decorator
55from django .utils .functional import cached_property
66from drf_spectacular .utils import extend_schema
7- from rest_framework .exceptions import MethodNotAllowed
7+ from rest_framework .exceptions import MethodNotAllowed , PermissionDenied
88from rest_framework .generics import get_object_or_404
99from rest_framework .permissions import IsAuthenticated
1010from rest_framework .request import Request
1111from rest_framework .response import Response
1212
1313from apps .homework .api .filtersets import AnswerFilterSet
1414from apps .homework .api .permissions import (
15- AnswerShouldBeEditable ,
16- MayChangeAnswerOnlyWithoutDescendants ,
17- ShouldBeAuthorOrReadOnly ,
18- ShouldHavePurchasedQuestionCoursePermission ,
15+ AuthorOrReadonly ,
16+ IsEditable ,
1917)
2018from apps .homework .api .serializers import (
2119 AnswerCreateSerializer ,
2523 ReactionCreateSerializer ,
2624 ReactionDetailedSerializer ,
2725)
28- from apps .homework .models import Answer
26+ from apps .homework .models import Answer , Question
2927from apps .homework .models .answer import AnswerQuerySet
3028from apps .homework .models .reaction import Reaction
3129from apps .homework .services import ReactionCreator
3230from apps .homework .services .answer_creator import AnswerCreator
3331from apps .homework .services .answer_remover import AnswerRemover
32+ from apps .users .models import User
3433from core .api .mixins import DisablePaginationWithQueryParamMixin
3534from core .viewsets import AppViewSet , CreateDeleteAppViewSet
3635
@@ -60,17 +59,15 @@ class AnswerViewSet(DisablePaginationWithQueryParamMixin, AppViewSet):
6059
6160 lookup_field = "slug"
6261 permission_classes = [
63- IsAuthenticated
64- & ShouldHavePurchasedQuestionCoursePermission
65- & ShouldBeAuthorOrReadOnly
66- & AnswerShouldBeEditable
67- & MayChangeAnswerOnlyWithoutDescendants ,
62+ IsAuthenticated & AuthorOrReadonly & IsEditable ,
6863 ]
6964 filterset_class = AnswerFilterSet
7065
7166 @extend_schema (request = AnswerCreateSerializer , responses = AnswerTreeSerializer )
7267 def create (self , request : Request , * args : Any , ** kwargs : dict [str , Any ]) -> Response :
7368 """Create an answer"""
69+ self ._check_question_permissions (user = self .user , question_slug = request .data ["question" ])
70+
7471 answer = AnswerCreator (
7572 question_slug = request .data ["question" ],
7673 parent_slug = request .data .get ("parent" ),
@@ -119,9 +116,9 @@ def get_queryset(self) -> AnswerQuerySet:
119116 return queryset .with_children_count ().order_by ("created" ).prefetch_reactions ()
120117
121118 def limit_queryset_to_user (self , queryset : AnswerQuerySet ) -> AnswerQuerySet :
122- if self .action != "retrieve" and not self .request . user .has_perm ("homework.see_all_answers" ):
119+ if self .action != "retrieve" and not self .user .has_perm ("homework.see_all_answers" ):
123120 # Each user may access any answer knowing its slug
124- return queryset .for_user (self .request . user ) # type: ignore
121+ return queryset .for_user (self .user )
125122
126123 return queryset
127124
@@ -131,14 +128,23 @@ def limit_queryset_for_list(self, queryset: AnswerQuerySet) -> AnswerQuerySet:
131128
132129 return queryset
133130
131+ @staticmethod
132+ def _check_question_permissions (user : User , question_slug : str ) -> None :
133+ if not Question .objects .for_user (user ).filter (slug = question_slug ).exists ():
134+ raise PermissionDenied ()
135+
136+ @property
137+ def user (self ) -> User :
138+ return self .request .user # type: ignore
139+
134140
135141class ReactionViewSet (CreateDeleteAppViewSet ):
136142 queryset = Reaction .objects .for_viewset ()
137143 serializer_class = ReactionDetailedSerializer
138144 serializer_action_classes = {
139145 "create" : ReactionCreateSerializer ,
140146 }
141- permission_classes = [IsAuthenticated & ShouldBeAuthorOrReadOnly ]
147+ permission_classes = [IsAuthenticated & AuthorOrReadonly ]
142148
143149 lookup_field = "slug"
144150
0 commit comments