def _clone_solution_comments( from_solution: models.Solution, to_solution: models.Solution, ) -> None: user_comments = models.Comment.by_solution( from_solution.id, ).filter(~models.Comment.is_auto) for comment in user_comments: models.Comment.create_comment( commenter=models.User.get_system_user(), line_number=comment.line_number, comment_text=comment.comment, file=to_solution.solution_files.get(), is_auto=True, ) to_solution.checker = from_solution.checker to_solution.state = from_solution.state to_solution.save() notifications.send( kind=notifications.NotificationKind.CHECKED, user=to_solution.solver, related_id=to_solution, message=_( 'הפתרון שלך לתרגיל %(subject)s נבדק.', subject=to_solution.exercise.subject, ), action_url=f'{routes.SOLUTIONS}/{to_solution.id}', )
def _populate_junit_results(self, raw_results: str) -> None: assert self._solution is not None # noqa: S101 suites = () if raw_results: suites = junitparser.TestSuite.fromstring(raw_results).testsuites() tests_ran = False number_of_failures = 0 for test_suite in suites: failures, ran = self._handle_test_suite(test_suite) number_of_failures += failures if ran and not tests_ran: tests_ran = ran if not tests_ran: self._handle_failed_to_execute_tests(raw_results) return if not number_of_failures: return fail_message = _( 'הבודק האוטומטי נכשל ב־ %(number)d דוגמאות בתרגיל "%(subject)s".', number=number_of_failures, subject=self._solution.exercise.subject, ) notifications.send( kind=notifications.NotificationKind.UNITTEST_ERROR, user=self._solution.solver, related_id=self._solution.id, message=fail_message, action_url=f'{routes.SOLUTIONS}/{self._solution_id}', )
def _populate_junit_results(self, junit_results: str): assert self._solution is not None # noqa: S101 results = None if junit_results: results = junitparser.TestSuite.fromstring(junit_results) if not results: self._logger.info('junit invalid results (%s) on solution %s', junit_results, self._solution_id) fail_user_message = 'הבודק האוטומטי לא הצליח להריץ את הקוד שלך.' models.SolutionExerciseTestExecution.create_execution_result( solution=self._solution, test_name=models.ExerciseTestName.FATAL_TEST_NAME, user_message=fail_user_message, staff_message='אחי, בדקת את הקוד שלך?', ) notifications.send( kind=notifications.NotificationKind.UNITTEST_ERROR, user=self._solution.solver, related_id=self._solution.id, message=fail_user_message, action_url=f'{routes.SOLUTIONS}/{self._solution_id}', ) return number_of_failures = 0 for case in results: result = case.result if result is None: self._logger.info( 'Case %s passed for solution %s.', case.name, self._solution, ) continue # invalid case message = '\n'.join([elem[1] for elem in result._elem.items()]) self._logger.info('Create comment on test %s solution %s.', case.name, self._solution_id) number_of_failures += 1 models.SolutionExerciseTestExecution.create_execution_result( solution=self._solution, test_name=case.name, user_message=message, staff_message=result._elem.text, ) if not number_of_failures: return fail_message = ( f'הבודק האוטומטי נכשל ב־{number_of_failures} ' f'דוגמאות בתרגיל "{self._solution.exercise.subject}".' ) notifications.send( kind=notifications.NotificationKind.UNITTEST_ERROR, user=self._solution.solver, related_id=self._solution.id, message=fail_message, action_url=f'{routes.SOLUTIONS}/{self._solution_id}', )
def notify_comment_after_check(user: User, solution: Solution) -> bool: is_checked = solution.is_checked if is_checked: msg, addressee = get_message_and_addressee(user, solution) if is_last_to_reply(user, solution): notifications.send( kind=notifications.NotificationKind.USER_RESPONSE, user=addressee, related_id=solution.id, message=msg, action_url=f'{routes.SOLUTIONS}/{solution.id}', ) return True return False
def mark_as_checked(solution_id: int, checker_id: int) -> bool: checked_solution: Solution = Solution.get_by_id(solution_id) is_updated = checked_solution.mark_as_checked(by=checker_id) msg = f'הפתרון שלך לתרגיל "{checked_solution.exercise.subject}" נבדק.' if is_updated: notifications.send( kind=notifications.NotificationKind.CHECKED, user=checked_solution.solver, related_id=solution_id, message=msg, action_url=f'{routes.SOLUTIONS}/{solution_id}', ) if config.FEATURE_FLAG_CHECK_IDENTICAL_CODE_ON: (identical_tests_tasks.check_if_other_solutions_can_be_solved. apply_async(args=(solution_id, ))) return is_updated
def test_auto_deletion(self, student_user: User): extra = 3 start = Notification.MAX_PER_USER for _ in range(Notification.MAX_PER_USER + extra - 1): notifications.send( user=student_user, kind=notifications.NotificationKind.CHECKED, message='', related_id=1, action_url='/view/1', ) assert Notification.select().count() == start expected = start + extra - 1 actual = Notification.select().order_by( Notification.created.desc()).get().id assert expected == actual
def test_send(self, student_user: User): another_user = conftest.create_student_user(index=1) params = self.generate_params() n1 = notifications.send(student_user, **params) n2 = notifications.send(another_user, self.kind_checked, 'yoyo2') n3 = notifications.send(student_user, self.kind_flake8, 'yoyo3') assert n1.user == student_user assert n1.kind == params['kind'].value assert n1.message == params['message'] assert n1.related_id == params['related_id'] assert n1.action_url == params['action_url'] assert n2.kind != n3.kind assert n2.message == 'yoyo2' assert n2.user == another_user assert len(list(notifications.get(student_user))) == 2 assert len(list(notifications.get(another_user))) == 1
def _handle_failed_to_execute_tests(self, raw_results: str) -> None: self._logger.info('junit invalid results (%s) on solution %s', raw_results, self._solution_id) fail_user_message = _('הבודק האוטומטי לא הצליח להריץ את הקוד שלך.', ) models.SolutionExerciseTestExecution.create_execution_result( solution=self._solution, test_name=models.ExerciseTestName.FATAL_TEST_NAME, user_message=fail_user_message, staff_message=_('אחי, בדקת את הקוד שלך?'), ) notifications.send( kind=notifications.NotificationKind.UNITTEST_ERROR, user=self._solution.solver, related_id=self._solution.id, message=fail_user_message, action_url=f'{routes.SOLUTIONS}/{self._solution_id}', )
def _handle_failed_to_execute_tests(self, raw_results: bytes) -> None: self._logger.info(b'junit invalid results (%s) on solution %s', raw_results, self._solution_id) fail_user_message = CANT_EXECUTE_CODE_MESSAGE models.SolutionExerciseTestExecution.create_execution_result( solution=self._solution, test_name=models.ExerciseTestName.FATAL_TEST_NAME, user_message=fail_user_message, staff_message=_('Bro, did you check your code?'), ) notifications.send( kind=notifications.NotificationKind.UNITTEST_ERROR, user=self._solution.solver, related_id=self._solution.id, message=fail_user_message, action_url=f'{routes.SOLUTIONS}/{self._solution_id}', )
def _populate_junit_results(self, raw_results: bytes) -> None: assert self._solution is not None # noqa: S101 if not raw_results: return None suites = self._get_parsed_suites(raw_results) if not suites: return None tests_ran = False number_of_failures = 0 for test_suite in suites: failures, ran = self._handle_test_suite(test_suite) number_of_failures += failures if ran and not tests_ran: tests_ran = ran if not tests_ran: self._handle_failed_to_execute_tests(raw_results) return None if not number_of_failures: return None fail_message = _( 'The automatic checker failed in %(number)d examples in your ' '"%(subject)s" solution.', number=number_of_failures, subject=self._solution.exercise.subject, ) notifications.send( kind=notifications.NotificationKind.UNITTEST_ERROR, user=self._solution.solver, related_id=self._solution.id, message=fail_message, action_url=f'{routes.SOLUTIONS}/{self._solution_id}', )
def _fire_notification_if_needed(self): if not self._errors: return errors_len = len(self._errors) exercise_name = self.solution.exercise.subject msg = ( f'הבודק האוטומטי נתן {errors_len} ' f'הערות על תרגילך "{exercise_name}".' ) return notifications.send( kind=notifications.NotificationKind.FLAKE8_ERROR, user=self.solution.solver, related_id=self.solution, message=msg, action_url=f'{routes.SOLUTIONS}/{self.solution.id}', )
def _fire_notification_if_needed(self): if not self._errors: return errors_len = len(self._errors) exercise_name = self.solution.exercise.subject msg = _( 'The automatic checker gave you %(errors_num)d for your ' '%(name)s solution.', errors_num=errors_len, name=exercise_name, ) return notifications.send( kind=notifications.NotificationKind.FLAKE8_ERROR, user=self.solution.solver, related_id=self.solution, message=msg, action_url=f'{routes.SOLUTIONS}/{self.solution.id}', )