mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2025-02-16 21:20:32 +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.blog",
|
||||||
"akarpov.files",
|
"akarpov.files",
|
||||||
"akarpov.pipeliner",
|
"akarpov.pipeliner",
|
||||||
|
"akarpov.test_platform",
|
||||||
"akarpov.tools.shortener",
|
"akarpov.tools.shortener",
|
||||||
"akarpov.tools.qr",
|
"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