From 0c6de0babe0fc934b0feea6365d47848b5d19af6 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Thu, 23 Apr 2026 13:48:31 -0600 Subject: [PATCH] add fills --- CLAUDE.md | 4 + .../migrations/0005_alter_exercise_type.py | 18 +++ tutorial/models.py | 1 + tutorial/serializers.py | 4 +- tutorial/tests.py | 144 ------------------ 5 files changed, 25 insertions(+), 146 deletions(-) create mode 100644 tutorial/migrations/0005_alter_exercise_type.py delete mode 100644 tutorial/tests.py diff --git a/CLAUDE.md b/CLAUDE.md index fa0ad4b..19219c3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,6 +27,10 @@ python run_test.py # Run flake8 lint + coverage in one step python run_test.py -m account # Run flake8 + tests for a single module python run_test.py -c # Run flake8 + tests + open HTML coverage report +## Testing Policy + +Do not write tests + # Initial setup python manage.py inituser --username admin --password --action create_super_admin python manage.py inituser --username admin --password --action reset diff --git a/tutorial/migrations/0005_alter_exercise_type.py b/tutorial/migrations/0005_alter_exercise_type.py new file mode 100644 index 0000000..4090fd1 --- /dev/null +++ b/tutorial/migrations/0005_alter_exercise_type.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0 on 2026-04-23 19:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tutorial', '0004_exercise'), + ] + + operations = [ + migrations.AlterField( + model_name='exercise', + name='type', + field=models.CharField(choices=[('mcq', '选择题'), ('sort', '代码排序'), ('fill', '代码填空')], max_length=16), + ), + ] diff --git a/tutorial/models.py b/tutorial/models.py index 19e75e4..baff521 100644 --- a/tutorial/models.py +++ b/tutorial/models.py @@ -29,6 +29,7 @@ class Exercise(models.Model): TYPE_CHOICES = [ ("mcq", "选择题"), ("sort", "代码排序"), + ("fill", "代码填空"), ] tutorial = models.ForeignKey(Tutorial, on_delete=models.CASCADE, related_name="exercises") diff --git a/tutorial/serializers.py b/tutorial/serializers.py index 730c97a..0c5ef3a 100644 --- a/tutorial/serializers.py +++ b/tutorial/serializers.py @@ -63,13 +63,13 @@ class ExerciseSerializer(serializers.ModelSerializer): class CreateExerciseSerializer(serializers.Serializer): tutorial_id = serializers.IntegerField() - type = serializers.ChoiceField(choices=["mcq", "sort"]) + type = serializers.ChoiceField(choices=["mcq", "sort", "fill"]) data = serializers.JSONField() order = serializers.IntegerField(default=0) class EditExerciseSerializer(serializers.Serializer): id = serializers.IntegerField() - type = serializers.ChoiceField(choices=["mcq", "sort"]) + type = serializers.ChoiceField(choices=["mcq", "sort", "fill"]) data = serializers.JSONField() order = serializers.IntegerField(default=0) diff --git a/tutorial/tests.py b/tutorial/tests.py deleted file mode 100644 index 598fbf3..0000000 --- a/tutorial/tests.py +++ /dev/null @@ -1,144 +0,0 @@ -from django.test import TestCase, Client -from django.contrib.auth import get_user_model -import json - -from tutorial.models import Tutorial, Exercise - -User = get_user_model() - - -def _json(response): - return json.loads(response.content) - - -class ExerciseAPITest(TestCase): - def setUp(self): - self.client = Client() - self.admin = User.objects.create( - username="admin_test", admin_type="Super Admin", is_staff=True - ) - self.admin.set_password("password") - self.admin.save() - - self.tutorial = Tutorial.objects.create( - title="Test Tutorial", - content="Hello [[exercise:1]]", - type="python", - is_public=True, - order=0, - created_by=self.admin, - ) - self.exercise = Exercise.objects.create( - tutorial=self.tutorial, - type="mcq", - data={ - "question": "Which is valid?", - "options": ["A", "B"], - "answer": 1, - }, - order=0, - ) - - def test_get_exercises_for_tutorial(self): - resp = self.client.get(f"/api/exercises?tutorial_id={self.tutorial.id}") - self.assertEqual(resp.status_code, 200) - data = _json(resp)["data"] - self.assertEqual(len(data), 1) - self.assertEqual(data[0]["type"], "mcq") - - def test_get_exercises_missing_tutorial_id(self): - resp = self.client.get("/api/exercises") - self.assertEqual(_json(resp)["error"], "error") - - def test_get_exercises_nonexistent_tutorial(self): - resp = self.client.get("/api/exercises?tutorial_id=99999") - self.assertEqual(_json(resp)["error"], "error") - - -class ExerciseAdminAPITest(TestCase): - def setUp(self): - self.client = Client() - self.admin = User.objects.create( - username="admin2_test", admin_type="Super Admin", is_staff=True - ) - self.admin.set_password("password") - self.admin.save() - self.client.login(username="admin2_test", password="password") - - self.tutorial = Tutorial.objects.create( - title="T", - content="", - type="python", - is_public=False, - order=0, - created_by=self.admin, - ) - - def test_create_mcq(self): - resp = self.client.post( - "/api/admin/exercise", - data=json.dumps({ - "tutorial_id": self.tutorial.id, - "type": "mcq", - "data": {"question": "Q?", "options": ["A", "B"], "answer": 0}, - "order": 0, - }), - content_type="application/json", - ) - self.assertEqual(resp.status_code, 200) - self.assertIsNone(_json(resp)["error"]) - self.assertEqual(Exercise.objects.count(), 1) - - def test_create_invalid_type(self): - resp = self.client.post( - "/api/admin/exercise", - data=json.dumps({ - "tutorial_id": self.tutorial.id, - "type": "bad_type", - "data": {}, - "order": 0, - }), - content_type="application/json", - ) - self.assertEqual(_json(resp)["error"], "error") - - def test_edit_exercise(self): - ex = Exercise.objects.create( - tutorial=self.tutorial, - type="mcq", - data={"question": "Old", "options": ["A", "B"], "answer": 0}, - order=0, - ) - resp = self.client.put( - "/api/admin/exercise", - data=json.dumps({ - "id": ex.id, - "type": "mcq", - "data": {"question": "New", "options": ["A", "B"], "answer": 1}, - "order": 0, - }), - content_type="application/json", - ) - self.assertEqual(resp.status_code, 200) - ex.refresh_from_db() - self.assertEqual(ex.data["question"], "New") - - def test_delete_exercise(self): - ex = Exercise.objects.create( - tutorial=self.tutorial, - type="sort", - data={"question": "Q", "lines": ["a", "b"]}, - order=0, - ) - resp = self.client.delete(f"/api/admin/exercise?id={ex.id}") - self.assertEqual(resp.status_code, 200) - self.assertEqual(Exercise.objects.count(), 0) - - def test_requires_admin(self): - self.client.logout() - resp = self.client.post( - "/api/admin/exercise", - data=json.dumps({"tutorial_id": 1, "type": "mcq", "data": {}, "order": 0}), - content_type="application/json", - ) - self.assertEqual(resp.status_code, 403)