Files
MathApp/content/tests_grade_number.py
Zareian 0c6b08c9ff make every grade's id its class number and sort grades by it everywhere
Grade ids were the order the books were imported in (ninth=1, eighth=5), so
gradeId: 5 meant eighth grade and the admin, the question filter and the API
all listed grades out of order. Grade.number (1-12) is now read from the title,
new grades take it as their id, and migration 0008 moves existing ids plus every
reference to them: Unit, the loose grade_id in accounts/ai_tutor/rag, and the
grade target inside campaign JSON. Unnumbered demo grades move above 100 and the
id sequence is raised past 12 so they never collide with a real grade.

The frontend needs no change: it always reads gradeId from the server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 22:47:02 +03:30

83 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import importlib
from types import SimpleNamespace
from django.apps import apps
from django.db import connection
from django.test import TestCase
from accounts.models import User
from ai_tutor.models import Conversation
from campaigns.models import MessageCampaign
from content.models import Grade, Unit, grade_number_from_title
migration = importlib.import_module('content.migrations.0008_grade_id_equals_number')
class GradeNumberTests(TestCase):
def test_number_is_read_from_title(self):
self.assertEqual(grade_number_from_title('پایه هشتم'), 8)
self.assertEqual(grade_number_from_title('پایه دوازدهم'), 12)
self.assertEqual(grade_number_from_title('پایهٔ یازدهم'), 11)
self.assertIsNone(grade_number_from_title('[SEED] پایه سوم'))
self.assertIsNone(grade_number_from_title('ریاضی'))
def test_new_grade_takes_its_number_as_id(self):
# بدونِ این، «پایه چهارم»ی که بعداً اضافه شود id=13 می‌گرفت.
grade = Grade.objects.create(title='پایه چهارم', icon='g', color='#000')
self.assertEqual((grade.number, grade.pk), (4, 4))
def test_unnumbered_grade_stays_out_of_one_to_twelve(self):
grade = Grade.objects.create(title='[DEMO] نمونه', icon='g', color='#000')
self.assertIsNone(grade.number)
self.assertGreater(grade.pk, 12)
# و بعدش هنوز جا برای پایه‌ی واقعی هست
self.assertEqual(Grade.objects.create(title='پایه نهم', icon='g', color='#000').pk, 9)
def test_duplicate_title_does_not_break_save(self):
Grade.objects.create(title='پایه دهم', icon='g', color='#000')
second = Grade.objects.create(title='پایه دهم', icon='g', color='#000')
self.assertIsNone(second.number)
def test_grades_api_is_ordered_by_number(self):
for title in ('پایه نهم', 'پایه سوم', 'پایه دوازدهم', 'پایه هشتم'):
Grade.objects.create(title=title, icon='g', color='#000')
rows = self.client.get('/api/grades').json()['grades']
self.assertEqual([r['number'] for r in rows], [3, 8, 9, 12])
self.assertEqual([r['id'] for r in rows], [3, 8, 9, 12])
class GradeRenumberMigrationTests(TestCase):
"""همان وضعیتِ سرور پیش از migration: idها به ترتیبِ واردشدنِ کتاب‌ها."""
def _grade(self, pk, title):
# save() را دور می‌زنیم تا idِ قدیمی و بی‌شماره بسازیم، مثلِ دیتای واقعی
Grade.objects.bulk_create([Grade(pk=pk, title=title, icon='g', color='#000')])
return pk
def test_ids_become_numbers_and_every_reference_follows(self):
old = { # id قدیمی → عنوان (ترتیبِ سرورِ واقعی)
1: 'پایه نهم', 2: 'پایه ششم', 5: 'پایه هشتم', 8: 'پایه دوازدهم', 9: '[DEMO] نمونه',
}
for pk, title in old.items():
self._grade(pk, title)
Unit.objects.create(grade_id=pk, title=f'فصلِ {title}')
student = User.objects.create(grade_id=5) # هشتم
conversation = Conversation.objects.create(user_id=student.id, grade_id=8) # دوازدهم
campaign = MessageCampaign.objects.create(
title='t', body='b', channel='sms', target_filter={'type': 'grade', 'grade_id': 1}) # نهم
migration.forwards(apps, SimpleNamespace(connection=connection))
by_title = {g.title: g for g in Grade.objects.all()}
self.assertEqual({t: (g.pk, g.number) for t, g in by_title.items() if g.number}, {
'پایه نهم': (9, 9), 'پایه ششم': (6, 6), 'پایه هشتم': (8, 8), 'پایه دوازدهم': (12, 12),
})
self.assertGreater(by_title['[DEMO] نمونه'].pk, 12)
for grade in by_title.values():
self.assertEqual(list(grade.units.values_list('title', flat=True)), [f'فصلِ {grade.title}'])
student.refresh_from_db()
conversation.refresh_from_db()
campaign.refresh_from_db()
self.assertEqual((student.grade_id, conversation.grade_id), (8, 12))
self.assertEqual(campaign.target_filter, {'type': 'grade', 'grade_id': 9})