2023-01-31 15:50:52 +00:00
|
|
|
from django.core.validators import RegexValidator
|
|
|
|
from django.db import models
|
|
|
|
from django.utils.translation import gettext, gettext_lazy as _
|
|
|
|
|
|
|
|
from judge.models import Contest
|
|
|
|
from judge.models.profile import Organization, Profile
|
|
|
|
|
|
|
|
__all__ = [
|
|
|
|
"Course",
|
|
|
|
"CourseRole",
|
|
|
|
"CourseResource",
|
|
|
|
"CourseAssignment",
|
|
|
|
]
|
|
|
|
|
|
|
|
course_directory_file = ""
|
|
|
|
|
2023-01-31 15:54:03 +00:00
|
|
|
|
2023-01-31 15:50:52 +00:00
|
|
|
class Course(models.Model):
|
2023-01-31 15:54:03 +00:00
|
|
|
name = models.CharField(
|
|
|
|
max_length=128,
|
|
|
|
verbose_name=_("course name"),
|
|
|
|
)
|
2023-01-31 15:50:52 +00:00
|
|
|
about = models.TextField(verbose_name=_("organization description"))
|
2023-01-31 15:54:03 +00:00
|
|
|
ending_time = models.DateTimeField(
|
|
|
|
verbose_name=_("ending time"),
|
|
|
|
)
|
|
|
|
is_public = models.BooleanField(
|
|
|
|
verbose_name=_("publicly visible"),
|
|
|
|
default=False,
|
|
|
|
)
|
2023-01-31 15:50:52 +00:00
|
|
|
organizations = models.ManyToManyField(
|
|
|
|
Organization,
|
|
|
|
blank=True,
|
|
|
|
verbose_name=_("organizations"),
|
|
|
|
help_text=_("If private, only these organizations may see the course"),
|
|
|
|
)
|
|
|
|
slug = models.SlugField(
|
|
|
|
max_length=128,
|
|
|
|
verbose_name=_("course slug"),
|
|
|
|
help_text=_("Course name shown in URL"),
|
|
|
|
unique=True,
|
|
|
|
validators=[
|
|
|
|
RegexValidator("^[-a-zA-Z0-9]+$", _("Only alphanumeric and hyphens"))
|
|
|
|
],
|
|
|
|
)
|
2023-01-31 15:54:03 +00:00
|
|
|
is_open = models.BooleanField(
|
|
|
|
verbose_name=_("public registration"),
|
|
|
|
default=False,
|
|
|
|
)
|
2023-01-31 15:50:52 +00:00
|
|
|
image_url = models.CharField(
|
2023-01-31 15:54:03 +00:00
|
|
|
verbose_name=_("course image"),
|
|
|
|
default="",
|
|
|
|
max_length=150,
|
2023-01-31 15:50:52 +00:00
|
|
|
blank=True,
|
|
|
|
)
|
2023-01-31 15:54:03 +00:00
|
|
|
|
2023-01-31 15:50:52 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
@classmethod
|
2023-03-01 13:40:49 +00:00
|
|
|
def is_editable_by(cls, course, profile):
|
2023-01-31 15:50:52 +00:00
|
|
|
userquery = CourseRole.objects.filter(course=course, user=profile)
|
|
|
|
if userquery.exists():
|
2023-01-31 15:54:03 +00:00
|
|
|
if userquery[0].role == "AS" or userquery[0].role == "TE":
|
2023-01-31 15:50:52 +00:00
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
@classmethod
|
2023-03-01 13:40:49 +00:00
|
|
|
def is_accessible_by(cls, course, profile):
|
2023-01-31 15:50:52 +00:00
|
|
|
userqueryset = CourseRole.objects.filter(course=course, user=profile)
|
|
|
|
if userqueryset.exists():
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
@classmethod
|
2023-03-01 13:40:49 +00:00
|
|
|
def get_students(cls, course):
|
2023-01-31 15:54:03 +00:00
|
|
|
return CourseRole.objects.filter(course=course, role="ST").values("user")
|
|
|
|
|
|
|
|
@classmethod
|
2023-03-01 13:40:49 +00:00
|
|
|
def get_assistants(cls, course):
|
2023-01-31 15:54:03 +00:00
|
|
|
return CourseRole.objects.filter(course=course, role="AS").values("user")
|
|
|
|
|
|
|
|
@classmethod
|
2023-03-01 13:40:49 +00:00
|
|
|
def get_teachers(cls, course):
|
2023-01-31 15:54:03 +00:00
|
|
|
return CourseRole.objects.filter(course=course, role="TE").values("user")
|
2023-01-31 15:50:52 +00:00
|
|
|
|
|
|
|
@classmethod
|
2023-03-01 13:40:49 +00:00
|
|
|
def add_student(cls, course, profiles):
|
2023-01-31 15:50:52 +00:00
|
|
|
for profile in profiles:
|
2023-01-31 15:54:03 +00:00
|
|
|
CourseRole.make_role(course=course, user=profile, role="ST")
|
|
|
|
|
|
|
|
@classmethod
|
2023-03-01 13:40:49 +00:00
|
|
|
def add_teachers(cls, course, profiles):
|
2023-01-31 15:50:52 +00:00
|
|
|
for profile in profiles:
|
2023-01-31 15:54:03 +00:00
|
|
|
CourseRole.make_role(course=course, user=profile, role="TE")
|
2023-01-31 15:50:52 +00:00
|
|
|
|
2023-01-31 15:54:03 +00:00
|
|
|
@classmethod
|
2023-03-01 13:40:49 +00:00
|
|
|
def add_assistants(cls, course, profiles):
|
2023-01-31 15:50:52 +00:00
|
|
|
for profile in profiles:
|
2023-01-31 15:54:03 +00:00
|
|
|
CourseRole.make_role(course=course, user=profile, role="AS")
|
|
|
|
|
|
|
|
|
2023-01-31 15:50:52 +00:00
|
|
|
class CourseRole(models.Model):
|
2023-03-01 13:40:49 +00:00
|
|
|
course = models.ForeignKey(
|
2023-01-31 15:50:52 +00:00
|
|
|
Course,
|
|
|
|
verbose_name=_("course"),
|
|
|
|
on_delete=models.CASCADE,
|
|
|
|
db_index=True,
|
|
|
|
)
|
|
|
|
user = models.ForeignKey(
|
|
|
|
Profile,
|
|
|
|
verbose_name=_("user"),
|
|
|
|
on_delete=models.CASCADE,
|
|
|
|
related_name=_("user_of_course"),
|
|
|
|
)
|
2023-01-31 15:54:03 +00:00
|
|
|
|
2023-01-31 15:50:52 +00:00
|
|
|
class RoleInCourse(models.TextChoices):
|
2023-01-31 15:54:03 +00:00
|
|
|
STUDENT = "ST", _("Student")
|
|
|
|
ASSISTANT = "AS", _("Assistant")
|
|
|
|
TEACHER = "TE", _("Teacher")
|
|
|
|
|
2023-01-31 15:50:52 +00:00
|
|
|
role = models.CharField(
|
|
|
|
max_length=2,
|
|
|
|
choices=RoleInCourse.choices,
|
|
|
|
default=RoleInCourse.STUDENT,
|
|
|
|
)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def make_role(self, course, user, role):
|
|
|
|
userqueryset = CourseRole.objects.filter(course=course, user=user)
|
|
|
|
if userqueryset.exists():
|
|
|
|
userqueryset[0].role = role
|
|
|
|
else:
|
|
|
|
couresrole = CourseRole()
|
|
|
|
couresrole.course = course
|
|
|
|
couresrole.user = user
|
|
|
|
couresrole.role = role
|
|
|
|
couresrole.save()
|
|
|
|
|
2023-01-31 15:54:03 +00:00
|
|
|
|
2023-01-31 15:50:52 +00:00
|
|
|
class CourseResource(models.Model):
|
2023-03-01 13:40:49 +00:00
|
|
|
course = models.ForeignKey(
|
2023-01-31 15:50:52 +00:00
|
|
|
Course,
|
|
|
|
verbose_name=_("course"),
|
|
|
|
on_delete=models.CASCADE,
|
|
|
|
db_index=True,
|
|
|
|
)
|
|
|
|
files = models.FileField(
|
|
|
|
verbose_name=_("course files"),
|
|
|
|
null=True,
|
|
|
|
blank=True,
|
|
|
|
upload_to=course_directory_file,
|
|
|
|
)
|
|
|
|
description = models.CharField(
|
|
|
|
verbose_name=_("description"),
|
|
|
|
blank=True,
|
|
|
|
max_length=150,
|
|
|
|
)
|
|
|
|
order = models.IntegerField(null=True, default=None)
|
2023-01-31 15:54:03 +00:00
|
|
|
is_public = models.BooleanField(
|
|
|
|
verbose_name=_("publicly visible"),
|
|
|
|
default=False,
|
|
|
|
)
|
|
|
|
|
2023-03-01 13:40:49 +00:00
|
|
|
def __str__(self):
|
|
|
|
return f"Resource - {self.pk}"
|
|
|
|
|
2023-01-31 15:50:52 +00:00
|
|
|
|
|
|
|
class CourseAssignment(models.Model):
|
2023-03-01 13:40:49 +00:00
|
|
|
course = models.ForeignKey(
|
2023-01-31 15:50:52 +00:00
|
|
|
Course,
|
|
|
|
verbose_name=_("course"),
|
|
|
|
on_delete=models.CASCADE,
|
|
|
|
db_index=True,
|
|
|
|
)
|
2023-03-01 13:40:49 +00:00
|
|
|
contest = models.ForeignKey(
|
2023-01-31 15:50:52 +00:00
|
|
|
Contest,
|
|
|
|
verbose_name=_("contest"),
|
|
|
|
on_delete=models.CASCADE,
|
|
|
|
)
|
2023-01-31 15:54:03 +00:00
|
|
|
points = models.FloatField(
|
|
|
|
verbose_name=_("points"),
|
|
|
|
)
|