11import contextlib
22from dataclasses import dataclass
3+ from typing import Callable
34
45from django .db import transaction
56from django .utils import timezone
67from django .utils .functional import cached_property
7- from rest_framework .exceptions import NotAuthenticated
8+ from rest_framework .exceptions import NotAuthenticated , NotFound , ValidationError
89
910from apps .homework .models import Answer , Question
1011from apps .studying .models import Study
1718@dataclass
1819class AnswerCreator (BaseService ):
1920 text : str
21+ content : dict
2022 question_slug : str
2123 parent_slug : str | None = None
2224
@@ -29,13 +31,21 @@ def act(self) -> Answer:
2931
3032 return instance
3133
34+ def get_validators (self ) -> list [Callable ]:
35+ return [
36+ self .validate_question_slug ,
37+ self .validate_parent_slug ,
38+ self .validate_json_or_text ,
39+ ]
40+
3241 def create (self ) -> Answer :
3342 return Answer .objects .create (
3443 parent = self .parent ,
3544 question = self .question ,
3645 author = self .author ,
3746 study = self .study ,
3847 text = self .text ,
48+ content = self .content ,
3949 )
4050
4151 @cached_property
@@ -48,15 +58,23 @@ def author(self) -> User:
4858
4959 @cached_property
5060 def parent (self ) -> Answer | None :
51- if not is_valid_uuid (self .parent_slug ):
61+ if self . parent_slug is None or len (self .parent_slug ) == 0 :
5262 return None
5363
5464 with contextlib .suppress (Answer .DoesNotExist ):
5565 return Answer .objects .get (slug = self .parent_slug )
5666
5767 @cached_property
5868 def question (self ) -> Question :
59- return Question .objects .get (slug = self .question_slug )
69+ try :
70+ return Question .objects .for_user (
71+ self .author ,
72+ ).get (
73+ slug = self .question_slug ,
74+ )
75+
76+ except Question .DoesNotExist :
77+ raise NotFound ()
6078
6179 @cached_property
6280 def study (self ) -> Study | None :
@@ -74,3 +92,24 @@ def is_answer_to_crosscheck(self, instance: Answer) -> bool:
7492
7593 def complete_crosscheck (self , instance : Answer ) -> None :
7694 instance .parent .answercrosscheck_set .filter (checker = self .author ).update (checked = timezone .now ())
95+
96+ def validate_json_or_text (self ) -> None :
97+ """Remove it after frontend migration"""
98+ if self .text is None or len (self .text ) == 0 : # validating json
99+ if not isinstance (self .content , dict ) or not len (self .content .keys ()):
100+ raise ValidationError ("Please provide text or content field" )
101+
102+ def validate_question_slug (self ) -> None :
103+ """Validate only format, database validation is performed later"""
104+ if not is_valid_uuid (self .question_slug ):
105+ raise ValidationError ("Question should be a valid uuid" )
106+
107+ def validate_parent_slug (self ) -> None :
108+ if self .parent_slug is None or not len (self .parent_slug ): # adding a root answer
109+ return
110+
111+ if not is_valid_uuid (self .parent_slug ):
112+ raise ValidationError ("Question should be a valid uuid" )
113+
114+ if not Answer .objects .filter (slug = self .parent_slug ).exists ():
115+ raise ValidationError ("Answer does not exist" )
0 commit comments