mirror of
				https://github.com/Alexander-D-Karpov/akarpov
				synced 2025-10-30 19:17:25 +03:00 
			
		
		
		
	added test forms
This commit is contained in:
		
							parent
							
								
									4a70342669
								
							
						
					
					
						commit
						902408ca9d
					
				
							
								
								
									
										0
									
								
								akarpov/test_platform/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								akarpov/test_platform/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										21
									
								
								akarpov/test_platform/admin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								akarpov/test_platform/admin.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| from django.contrib import admin | ||||
| 
 | ||||
| from akarpov.test_platform.models import ( | ||||
|     Form, | ||||
|     FormHistory, | ||||
|     FormPermission, | ||||
|     NumberQuestion, | ||||
|     NumberRangeQuestion, | ||||
|     SelectAnswerQuestion, | ||||
|     SelectQuestion, | ||||
|     TextQuestion, | ||||
| ) | ||||
| 
 | ||||
| admin.site.register(Form) | ||||
| admin.site.register(TextQuestion) | ||||
| admin.site.register(NumberQuestion) | ||||
| admin.site.register(NumberRangeQuestion) | ||||
| admin.site.register(SelectQuestion) | ||||
| admin.site.register(SelectAnswerQuestion) | ||||
| admin.site.register(FormPermission) | ||||
| admin.site.register(FormHistory) | ||||
							
								
								
									
										7
									
								
								akarpov/test_platform/apps.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								akarpov/test_platform/apps.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | |||
| from django.apps import AppConfig | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| 
 | ||||
| 
 | ||||
| class TestPlatformConfig(AppConfig): | ||||
|     name = "akarpov.test_platform" | ||||
|     verbose_name = _("Test platform") | ||||
							
								
								
									
										270
									
								
								akarpov/test_platform/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								akarpov/test_platform/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,270 @@ | |||
| # Generated by Django 4.1.5 on 2023-02-24 16:18 | ||||
| 
 | ||||
| import akarpov.utils.files | ||||
| from django.conf import settings | ||||
| from django.db import migrations, models | ||||
| import django.db.models.deletion | ||||
| import uuid | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     initial = True | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||||
|         ("contenttypes", "0002_remove_content_type_name"), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.CreateModel( | ||||
|             name="BaseQuestion", | ||||
|             fields=[ | ||||
|                 ( | ||||
|                     "id", | ||||
|                     models.BigAutoField( | ||||
|                         auto_created=True, | ||||
|                         primary_key=True, | ||||
|                         serialize=False, | ||||
|                         verbose_name="ID", | ||||
|                     ), | ||||
|                 ), | ||||
|                 ("question", models.CharField(max_length=250)), | ||||
|                 ("help", models.CharField(blank=True, max_length=200)), | ||||
|                 ("required", models.BooleanField(default=True)), | ||||
|             ], | ||||
|             options={ | ||||
|                 "abstract": False, | ||||
|                 "base_manager_name": "objects", | ||||
|             }, | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name="Form", | ||||
|             fields=[ | ||||
|                 ( | ||||
|                     "id", | ||||
|                     models.BigAutoField( | ||||
|                         auto_created=True, | ||||
|                         primary_key=True, | ||||
|                         serialize=False, | ||||
|                         verbose_name="ID", | ||||
|                     ), | ||||
|                 ), | ||||
|                 ("name", models.CharField(max_length=200)), | ||||
|                 ("description", models.TextField(blank=True)), | ||||
|                 ("slug", models.SlugField(blank=True, max_length=20)), | ||||
|                 ("public", models.BooleanField(default=True)), | ||||
|                 ("anyone_can_access", models.BooleanField(default=True)), | ||||
|                 ("created", models.DateTimeField(auto_now_add=True)), | ||||
|                 ("updated", models.DateTimeField(auto_now=True)), | ||||
|                 ( | ||||
|                     "image", | ||||
|                     models.ImageField( | ||||
|                         blank=True, upload_to=akarpov.utils.files.user_file_upload_mixin | ||||
|                     ), | ||||
|                 ), | ||||
|                 ("image_cropped", models.ImageField(blank=True, upload_to="cropped/")), | ||||
|                 ("passed", models.IntegerField(default=0)), | ||||
|                 ("time_till", models.DateTimeField(blank=True, null=True)), | ||||
|                 ( | ||||
|                     "creator", | ||||
|                     models.ForeignKey( | ||||
|                         on_delete=django.db.models.deletion.CASCADE, | ||||
|                         to=settings.AUTH_USER_MODEL, | ||||
|                     ), | ||||
|                 ), | ||||
|             ], | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name="SelectAnswerQuestion", | ||||
|             fields=[ | ||||
|                 ( | ||||
|                     "id", | ||||
|                     models.UUIDField( | ||||
|                         default=uuid.uuid4, | ||||
|                         editable=False, | ||||
|                         primary_key=True, | ||||
|                         serialize=False, | ||||
|                     ), | ||||
|                 ), | ||||
|                 ("value", models.CharField(max_length=150)), | ||||
|                 ("correct", models.BooleanField(null=True)), | ||||
|             ], | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name="NumberQuestion", | ||||
|             fields=[ | ||||
|                 ( | ||||
|                     "basequestion_ptr", | ||||
|                     models.OneToOneField( | ||||
|                         auto_created=True, | ||||
|                         on_delete=django.db.models.deletion.CASCADE, | ||||
|                         parent_link=True, | ||||
|                         primary_key=True, | ||||
|                         serialize=False, | ||||
|                         to="test_platform.basequestion", | ||||
|                     ), | ||||
|                 ), | ||||
|                 ("correct_answer", models.IntegerField()), | ||||
|             ], | ||||
|             options={ | ||||
|                 "abstract": False, | ||||
|                 "base_manager_name": "objects", | ||||
|             }, | ||||
|             bases=("test_platform.basequestion",), | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name="NumberRangeQuestion", | ||||
|             fields=[ | ||||
|                 ( | ||||
|                     "basequestion_ptr", | ||||
|                     models.OneToOneField( | ||||
|                         auto_created=True, | ||||
|                         on_delete=django.db.models.deletion.CASCADE, | ||||
|                         parent_link=True, | ||||
|                         primary_key=True, | ||||
|                         serialize=False, | ||||
|                         to="test_platform.basequestion", | ||||
|                     ), | ||||
|                 ), | ||||
|                 ("number_range_min", models.IntegerField()), | ||||
|                 ("number_range_max", models.IntegerField()), | ||||
|             ], | ||||
|             options={ | ||||
|                 "abstract": False, | ||||
|                 "base_manager_name": "objects", | ||||
|             }, | ||||
|             bases=("test_platform.basequestion",), | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name="SelectQuestion", | ||||
|             fields=[ | ||||
|                 ( | ||||
|                     "basequestion_ptr", | ||||
|                     models.OneToOneField( | ||||
|                         auto_created=True, | ||||
|                         on_delete=django.db.models.deletion.CASCADE, | ||||
|                         parent_link=True, | ||||
|                         primary_key=True, | ||||
|                         serialize=False, | ||||
|                         to="test_platform.basequestion", | ||||
|                     ), | ||||
|                 ), | ||||
|                 ("min_required_answers", models.IntegerField()), | ||||
|                 ("max_required_answers", models.IntegerField()), | ||||
|             ], | ||||
|             options={ | ||||
|                 "abstract": False, | ||||
|                 "base_manager_name": "objects", | ||||
|             }, | ||||
|             bases=("test_platform.basequestion",), | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name="TextQuestion", | ||||
|             fields=[ | ||||
|                 ( | ||||
|                     "basequestion_ptr", | ||||
|                     models.OneToOneField( | ||||
|                         auto_created=True, | ||||
|                         on_delete=django.db.models.deletion.CASCADE, | ||||
|                         parent_link=True, | ||||
|                         primary_key=True, | ||||
|                         serialize=False, | ||||
|                         to="test_platform.basequestion", | ||||
|                     ), | ||||
|                 ), | ||||
|                 ("correct_answer", models.CharField(max_length=250)), | ||||
|                 ("answer_should_contain", models.CharField(max_length=250)), | ||||
|                 ("answer_should_not_contain", models.CharField(max_length=250)), | ||||
|             ], | ||||
|             options={ | ||||
|                 "abstract": False, | ||||
|                 "base_manager_name": "objects", | ||||
|             }, | ||||
|             bases=("test_platform.basequestion",), | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name="FormHistory", | ||||
|             fields=[ | ||||
|                 ( | ||||
|                     "id", | ||||
|                     models.BigAutoField( | ||||
|                         auto_created=True, | ||||
|                         primary_key=True, | ||||
|                         serialize=False, | ||||
|                         verbose_name="ID", | ||||
|                     ), | ||||
|                 ), | ||||
|                 ("opened", models.DateTimeField(auto_now_add=True)), | ||||
|                 ( | ||||
|                     "form", | ||||
|                     models.ForeignKey( | ||||
|                         on_delete=django.db.models.deletion.CASCADE, | ||||
|                         related_name="users_opened", | ||||
|                         to="test_platform.form", | ||||
|                     ), | ||||
|                 ), | ||||
|                 ( | ||||
|                     "user", | ||||
|                     models.ForeignKey( | ||||
|                         on_delete=django.db.models.deletion.CASCADE, | ||||
|                         related_name="opened_test_platform", | ||||
|                         to=settings.AUTH_USER_MODEL, | ||||
|                     ), | ||||
|                 ), | ||||
|             ], | ||||
|         ), | ||||
|         migrations.AddField( | ||||
|             model_name="basequestion", | ||||
|             name="form", | ||||
|             field=models.ForeignKey( | ||||
|                 on_delete=django.db.models.deletion.CASCADE, | ||||
|                 related_name="fields", | ||||
|                 to="test_platform.form", | ||||
|             ), | ||||
|         ), | ||||
|         migrations.AddField( | ||||
|             model_name="basequestion", | ||||
|             name="polymorphic_ctype", | ||||
|             field=models.ForeignKey( | ||||
|                 editable=False, | ||||
|                 null=True, | ||||
|                 on_delete=django.db.models.deletion.CASCADE, | ||||
|                 related_name="polymorphic_%(app_label)s.%(class)s_set+", | ||||
|                 to="contenttypes.contenttype", | ||||
|             ), | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name="FormPermission", | ||||
|             fields=[ | ||||
|                 ( | ||||
|                     "id", | ||||
|                     models.BigAutoField( | ||||
|                         auto_created=True, | ||||
|                         primary_key=True, | ||||
|                         serialize=False, | ||||
|                         verbose_name="ID", | ||||
|                     ), | ||||
|                 ), | ||||
|                 ( | ||||
|                     "form", | ||||
|                     models.ForeignKey( | ||||
|                         on_delete=django.db.models.deletion.CASCADE, | ||||
|                         related_name="allowed", | ||||
|                         to="test_platform.form", | ||||
|                     ), | ||||
|                 ), | ||||
|                 ( | ||||
|                     "user", | ||||
|                     models.ForeignKey( | ||||
|                         on_delete=django.db.models.deletion.CASCADE, | ||||
|                         related_name="allowed_test_platform", | ||||
|                         to=settings.AUTH_USER_MODEL, | ||||
|                     ), | ||||
|                 ), | ||||
|             ], | ||||
|             options={ | ||||
|                 "unique_together": {("form", "user")}, | ||||
|             }, | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										0
									
								
								akarpov/test_platform/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								akarpov/test_platform/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										114
									
								
								akarpov/test_platform/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								akarpov/test_platform/models.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,114 @@ | |||
| import uuid | ||||
| 
 | ||||
| from django.db import models | ||||
| from django.utils import timezone | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| from polymorphic.models import PolymorphicModel | ||||
| 
 | ||||
| from akarpov.users.models import User | ||||
| from akarpov.utils.files import user_file_upload_mixin | ||||
| 
 | ||||
| 
 | ||||
| class Form(models.Model): | ||||
|     name = models.CharField(max_length=200, blank=False) | ||||
|     description = models.TextField(blank=True) | ||||
| 
 | ||||
|     creator = models.ForeignKey("users.User", on_delete=models.CASCADE) | ||||
|     slug = models.SlugField(max_length=20, blank=True) | ||||
| 
 | ||||
|     public = models.BooleanField(default=True) | ||||
|     anyone_can_access = models.BooleanField(default=True) | ||||
| 
 | ||||
|     created = models.DateTimeField(auto_now_add=True) | ||||
|     updated = models.DateTimeField(auto_now=True) | ||||
| 
 | ||||
|     image = models.ImageField(upload_to=user_file_upload_mixin, blank=True) | ||||
|     image_cropped = models.ImageField(upload_to="cropped/", blank=True) | ||||
| 
 | ||||
|     passed = models.IntegerField(default=0) | ||||
|     time_till = models.DateTimeField(null=True, blank=True) | ||||
| 
 | ||||
|     @property | ||||
|     def available(self) -> bool: | ||||
|         return ( | ||||
|             self.time_till.timestamp() >= timezone.now().timestamp() | ||||
|             if self.time_till | ||||
|             else True | ||||
|         ) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return f"form: {self.name}" | ||||
| 
 | ||||
| 
 | ||||
| class BaseQuestion(PolymorphicModel): | ||||
|     type = _("No type") | ||||
|     form: Form = models.ForeignKey( | ||||
|         "test_platform.Form", related_name="fields", on_delete=models.CASCADE | ||||
|     ) | ||||
|     question = models.CharField(max_length=250, blank=False) | ||||
|     help = models.CharField(max_length=200, blank=True) | ||||
|     required = models.BooleanField(default=True) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return f"{self.type} - {self.question}" | ||||
| 
 | ||||
| 
 | ||||
| class TextQuestion(BaseQuestion): | ||||
|     type = _("Text question") | ||||
|     correct_answer = models.CharField(max_length=250, blank=False) | ||||
|     answer_should_contain = models.CharField(max_length=250, blank=False) | ||||
|     answer_should_not_contain = models.CharField(max_length=250, blank=False) | ||||
| 
 | ||||
| 
 | ||||
| class NumberQuestion(BaseQuestion): | ||||
|     type = _("Number question") | ||||
|     correct_answer = models.IntegerField() | ||||
| 
 | ||||
| 
 | ||||
| class NumberRangeQuestion(BaseQuestion): | ||||
|     type = _("Number question") | ||||
|     number_range_min = models.IntegerField(blank=False) | ||||
|     number_range_max = models.IntegerField(blank=False) | ||||
| 
 | ||||
| 
 | ||||
| class SelectQuestion(BaseQuestion): | ||||
|     min_required_answers = models.IntegerField(blank=False) | ||||
|     max_required_answers = models.IntegerField(blank=False) | ||||
| 
 | ||||
| 
 | ||||
| class SelectAnswerQuestion(models.Model): | ||||
|     id: uuid.UUID = models.UUIDField( | ||||
|         primary_key=True, default=uuid.uuid4, editable=False | ||||
|     ) | ||||
|     value = models.CharField(max_length=150) | ||||
|     correct = models.BooleanField(null=True) | ||||
| 
 | ||||
| 
 | ||||
| class FormPermission(models.Model): | ||||
|     form: Form = models.ForeignKey( | ||||
|         "test_platform.Form", related_name="allowed", on_delete=models.CASCADE | ||||
|     ) | ||||
|     user: User = models.ForeignKey( | ||||
|         "users.User", related_name="allowed_test_platform", on_delete=models.CASCADE | ||||
|     ) | ||||
| 
 | ||||
|     class Meta: | ||||
|         unique_together = ["form", "user"] | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return f"user {self.user.username} can access {self.form.name}" | ||||
| 
 | ||||
| 
 | ||||
| class FormHistory(models.Model): | ||||
|     form: Form = models.ForeignKey( | ||||
|         "test_platform.Form", related_name="users_opened", on_delete=models.CASCADE | ||||
|     ) | ||||
|     user: User = models.ForeignKey( | ||||
|         "users.User", related_name="opened_test_platform", on_delete=models.CASCADE | ||||
|     ) | ||||
|     opened = models.DateTimeField(auto_now_add=True) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return ( | ||||
|             f"user {self.user.username} opened form {self.form.name} at {self.opened}" | ||||
|         ) | ||||
							
								
								
									
										0
									
								
								akarpov/test_platform/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								akarpov/test_platform/views.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -142,6 +142,7 @@ | |||
|     "akarpov.blog", | ||||
|     "akarpov.files", | ||||
|     "akarpov.pipeliner", | ||||
|     "akarpov.test_platform", | ||||
|     "akarpov.tools.shortener", | ||||
|     "akarpov.tools.qr", | ||||
| ] | ||||
|  |  | |||
							
								
								
									
										601
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										601
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user