Like/dislike + report under every question and lesson, lesson reports and vote columns in admin; practice islands refresh from file; audit fixes

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 12:56:47 +03:30
parent b075b93f2a
commit 2e0753587c
12 changed files with 1331 additions and 951 deletions

View File

@@ -287,3 +287,35 @@ class SeedFilesInRepoTests(TestCase):
positions = {row['correct'] for row in rows}
self.assertGreater(len(positions), 2)
class PracticeRefreshTests(TestCase):
"""اصلاحِ فایلِ جزیره‌ی تمرین به سوالِ موجود می‌رسد؛ سوالِ دستیِ ادمین دست نمی‌خورد."""
def _rows(self, choices, correct, prompt='۲ + ۳ = ؟'):
return [{'path': ['پایه سوم', 'فصل ۱', 'تمرین: جمع', 'درس'], 'prompt': prompt, 'type': 'multiple_choice',
'choices': choices, 'correct': correct}]
def _grades(self):
return [{'title': 'پایه سوم', 'icon': '', 'color': '', 'units': [{
'title': 'فصل ۱', 'order': 1, 'subject': 'ریاضی', 'blurb': '', 'nodes': [{
'title': 'تمرین: جمع', 'order': 1, 'lessons': [{
'title': 'درس', 'intro_text': 'متن', 'example': '', 'steps': []}]}]}]}]
def test_changed_choices_update_in_place_and_stale_is_removed(self):
from content import seed_sync
from content.models import Choice, Question
seed_sync.sync(self._grades(), self._rows(['۴', '۵', '۶', '۷'], 1))
q = Question.objects.get()
ids = list(q.choices.order_by('pk').values_list('pk', flat=True))
seed_sync.sync(self._grades(), self._rows(['۴', '۵', '۸', '۷'], 3))
q.refresh_from_db()
got = list(q.choices.order_by('pk').values_list('pk', 'value', 'is_correct'))
self.assertEqual([g[0] for g in got], ids)
self.assertEqual(got[3][1:], ('۷', True))
# سوالی که از فایل رفته و جوابی ندارد پاک می‌شود؛ سوالِ دستی نه
manual = Question.objects.create(lesson=q.lesson, type='multiple_choice', prompt='دستی')
Choice.objects.create(question=manual, value='الف', is_correct=True)
seed_sync.sync(self._grades(), self._rows(['۱', '۲'], 0, prompt='سوالِ دیگر'))
self.assertFalse(Question.objects.filter(prompt='۲ + ۳ = ؟').exists())
self.assertTrue(Question.objects.filter(prompt='دستی').exists())