22from copy import deepcopy
33from typing import Any , Iterable , Optional , Union
44
5+ from courses .models import Task , TaskObject
56from django .db import transaction
67from django .db .models import QuerySet
7- from rest_framework import status
8-
9- from courses .models import TaskObject
108from progress .models import TaskObjUserResult , UserAnswersAttemptCounter
11- from questions .exceptions import (QustionConnectException ,
12- UserAlreadyAnsweredException )
9+ from questions .exceptions import QustionConnectException , UserAlreadyAnsweredException
1310from questions .mapping import TypeQuestionPoints
1411from questions .models .answers import AnswerConnect , AnswerSingle
15- from questions .models .questions import (InfoSlide , QuestionConnect ,
16- QuestionSingleAnswer , QuestionWrite )
12+ from questions .models .questions import (
13+ InfoSlide ,
14+ QuestionConnect ,
15+ QuestionSingleAnswer ,
16+ QuestionWrite ,
17+ )
18+ from rest_framework import status
1719
1820
1921class AbstractAnswersService (ABC ):
@@ -27,7 +29,9 @@ class AbstractAnswersService(ABC):
2729 def __init__ (
2830 self ,
2931 request_profile_id : int ,
30- request_question : Union [InfoSlide , QuestionWrite , QuestionConnect , QuestionSingleAnswer ],
32+ request_question : Union [
33+ InfoSlide , QuestionWrite , QuestionConnect , QuestionSingleAnswer
34+ ],
3135 request_task_object : TaskObject ,
3236 request_data : dict ,
3337 ) -> None :
@@ -90,9 +94,14 @@ def _process_answer_attempt_counter(self, question_answers: Any):
9094 counter .attempts_made_before += 1
9195
9296 # Проверка после подсказки, если counter `after` max, то сохранение без баллов:
93- if counter .is_take_hint and counter .attempts_made_after >= self .request_question .attempts_after_hint :
97+ if (
98+ counter .is_take_hint
99+ and counter .attempts_made_after >= self .request_question .attempts_after_hint
100+ ):
94101 counter .delete ()
95- self ._create_tast_obj_result (TypeQuestionPoints .QUESTION_WO_POINTS , correct_answer = False )
102+ self ._create_tast_obj_result (
103+ TypeQuestionPoints .QUESTION_WO_POINTS , correct_answer = False
104+ )
96105 question_answer_body = self ._create_answer_response_body (question_answers )
97106 question_answer_body ["hint" ] = self .request_question .hint_text
98107 return question_answer_body , status .HTTP_201_CREATED
@@ -105,13 +114,20 @@ def _process_answer_attempt_counter(self, question_answers: Any):
105114 counter .save ()
106115 response_body = deepcopy (self ._UNSUCCESS_RESPONSE_BODY )
107116
108- if self .request_question .attempts_after_hint and self .request_question .hint_text :
117+ if (
118+ self .request_question .attempts_after_hint
119+ and self .request_question .hint_text
120+ ):
109121 response_body ["hint" ] = self .request_question .hint_text
110122 return response_body , status .HTTP_400_BAD_REQUEST
111123 else :
112124 counter .delete ()
113- self ._create_tast_obj_result (TypeQuestionPoints .QUESTION_WO_POINTS , correct_answer = False )
114- question_answer_body = self ._create_answer_response_body (question_answers )
125+ self ._create_tast_obj_result (
126+ TypeQuestionPoints .QUESTION_WO_POINTS , correct_answer = False
127+ )
128+ question_answer_body = self ._create_answer_response_body (
129+ question_answers
130+ )
115131 if self .request_question .hint_text :
116132 question_answer_body ["hint" ] = self .request_question .hint_text
117133 return question_answer_body , status .HTTP_201_CREATED
@@ -125,7 +141,9 @@ def _handle_no_question_validation(
125141 required_data : Optional [Iterable ] = None ,
126142 ) -> tuple [dict , int ]:
127143 """Если у TaskObject отключена проверка (необходимо ответить хоть что-то/сопоставить все даже неправильно)."""
128- if (required_data and len (self .request_data ) < len (required_data )) or not self .request_data :
144+ if (
145+ required_data and len (self .request_data ) < len (required_data )
146+ ) or not self .request_data :
129147 return self ._WRONG_ANSWER_WO_VALIDATION , status .HTTP_400_BAD_REQUEST
130148 self ._create_tast_obj_result (point_type )
131149 return self ._SUCCESS_RESPONSE_BODY , status .HTTP_201_CREATED
@@ -145,7 +163,7 @@ def _create_tast_obj_result(
145163 points = 0
146164 else :
147165 skill = self .request_task_object .task .skill
148- tasks_count = skill . tasks . count () or 1 # защита от деления на 0
166+ tasks_count = Task . published . filter ( skill = skill ). count ()
149167 points = round (80 / tasks_count )
150168
151169 TaskObjUserResult .objects .create (
@@ -174,10 +192,7 @@ class SingleCorrectAnswerService(AbstractAnswersService):
174192 def _check_correct_answer (self ) -> tuple [dict [str , Any ], int ]:
175193 """Проверка на корректность ответа + формирование процесса с `couter` (если вопросом это предполагается)."""
176194 question_answer : QuerySet [AnswerSingle ] = (
177- self .request_question
178- .single_answers
179- .filter (is_correct = True )
180- .first ()
195+ self .request_question .single_answers .filter (is_correct = True ).first ()
181196 )
182197
183198 if self .request_data .get ("answer_id" ) == question_answer .id :
@@ -202,7 +217,9 @@ class QuestionExcludeAnswerService(AbstractAnswersService):
202217
203218 def _check_correct_answer (self ) -> tuple [dict [str , Any ], int ]:
204219 correct_answers_ids : set [int ] = set (
205- self .request_question .single_answers .filter (is_correct = False ).values_list ("id" , flat = True )
220+ self .request_question .single_answers .filter (is_correct = False ).values_list (
221+ "id" , flat = True
222+ )
206223 )
207224 given_answer_ids : set [int ] = set (self .request_data )
208225
@@ -228,18 +245,21 @@ class QuestionConnectAnswerService(AbstractAnswersService):
228245 _QUSTION_POINTS : TypeQuestionPoints = TypeQuestionPoints .QUESTION_CONNECT
229246
230247 def _check_correct_answer (self ) -> tuple [dict [str , Any ], int ]:
231- all_answer_options : QuerySet [AnswerConnect ] = self .request_question .connect_answers .all ()
248+ all_answer_options : QuerySet [AnswerConnect ] = (
249+ self .request_question .connect_answers .all ()
250+ )
232251
233252 answers_ids : list [int ] = set (all_answer_options .values_list ("id" , flat = True ))
234- user_answer_ids : set [int ] = (
235- {answer ["right_id" ] for answer in self .request_data }
236- | {answer ["left_id" ] for answer in self .request_data }
237- )
253+ user_answer_ids : set [int ] = {
254+ answer ["right_id" ] for answer in self .request_data
255+ } | {answer ["left_id" ] for answer in self .request_data }
238256
239257 if answers_ids != user_answer_ids :
240258 raise QustionConnectException ("Wrong ids or need more answers." )
241259
242- answer_is_correct : bool = all ([answer ["right_id" ] == answer ["left_id" ] for answer in self .request_data ])
260+ answer_is_correct : bool = all (
261+ [answer ["right_id" ] == answer ["left_id" ] for answer in self .request_data ]
262+ )
243263 if answer_is_correct :
244264 self ._create_tast_obj_result (self ._QUSTION_POINTS )
245265 self ._delete_self_counter ()
@@ -253,17 +273,14 @@ def _check_correct_answer(self) -> tuple[dict[str, Any], int]:
253273 def _create_answer_response_body (self , question_answer : AnswerSingle ):
254274 response_body = deepcopy (self ._UNSUCCESS_RESPONSE_BODY )
255275 response_body ["answer_ids" ] = [
256- {
257- "left_id" : answer .id ,
258- "right_id" : answer .id
259- }
260- for answer in question_answer
276+ {"left_id" : answer .id , "right_id" : answer .id } for answer in question_answer
261277 ]
262278 return response_body
263279
264280
265281class QuestionWriteAnswerService (AbstractAnswersService ):
266282 """Проверка (запись) ответа пользователя на вопрос с вводом ответа."""
283+
267284 _QUSTION_POINTS : TypeQuestionPoints = TypeQuestionPoints .QUESTION_WRITE
268285
269286 def create_answer (self ) -> tuple [dict [str , Any ], int ]:
@@ -282,6 +299,7 @@ def _create_answer_response_body(self) -> dict[str, Any]:
282299
283300class InfoSlideAnswerService (AbstractAnswersService ):
284301 """Проверка (запись) ответа пользователя инфо слайд."""
302+
285303 _QUSTION_POINTS : TypeQuestionPoints = TypeQuestionPoints .INFO_SLIDE
286304
287305 def create_answer (self ) -> tuple [dict [str , Any ], int ]:
0 commit comments