Compare commits

...

1 commit

Author SHA1 Message Date
Luzivanlt
1797b9fe06 add CourseDetail, CourseStudentResults 2023-02-23 23:11:52 +07:00
10 changed files with 205 additions and 17 deletions

View file

@ -487,7 +487,6 @@ urlpatterns = [
), ),
), ),
url(r"^contests/", paged_list_view(contests.ContestList, "contest_list")), url(r"^contests/", paged_list_view(contests.ContestList, "contest_list")),
url(r"^course/", paged_list_view(course.CourseList, "course_list" )),
url( url(
r"^contests/(?P<year>\d+)/(?P<month>\d+)/$", r"^contests/(?P<year>\d+)/(?P<month>\d+)/$",
contests.ContestCalendar.as_view(), contests.ContestCalendar.as_view(),
@ -592,6 +591,24 @@ urlpatterns = [
] ]
), ),
), ),
url(r"^courses/", paged_list_view(course.CourseList, "course_list" )),
url(
r"^courses/(?P<slug>[\w-]*)",
include(
[
url(
r"^$",
course.CourseDetail.as_view(),
name="course_detail"
),
url(
r"^/grades$",
course.CourseStudentResults.as_view(),
name="grades"
),
]
)
),
url( url(
r"^organizations/$", r"^organizations/$",
organization.OrganizationList.as_view(), organization.OrganizationList.as_view(),

View file

@ -40,6 +40,7 @@ from judge.models import (
Ticket, Ticket,
VolunteerProblemVote, VolunteerProblemVote,
Course, Course,
course,
) )
@ -65,4 +66,5 @@ admin.site.register(Profile, ProfileAdmin)
admin.site.register(Submission, SubmissionAdmin) admin.site.register(Submission, SubmissionAdmin)
admin.site.register(Ticket, TicketAdmin) admin.site.register(Ticket, TicketAdmin)
admin.site.register(VolunteerProblemVote, VolunteerProblemVoteAdmin) admin.site.register(VolunteerProblemVote, VolunteerProblemVoteAdmin)
admin.site.register(Course) admin.site.register(course.Course)
admin.site.register(course.CourseAssignment)

View file

@ -0,0 +1,19 @@
# Generated by Django 3.2.17 on 2023-02-15 04:28
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('judge', '0150_alter_profile_timezone'),
]
operations = [
migrations.AlterField(
model_name='courseassignment',
name='course',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.course', verbose_name='course'),
),
]

View file

@ -0,0 +1,19 @@
# Generated by Django 3.2.17 on 2023-02-22 08:08
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('judge', '0151_alter_courseassignment_course'),
]
operations = [
migrations.AlterField(
model_name='courserole',
name='course',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='judge.course', verbose_name='course'),
),
]

View file

@ -449,6 +449,13 @@ class Contest(models.Model):
"profile_id", flat=True "profile_id", flat=True
) )
@cached_property
def total_points(self):
total = 0
for problem in self.problems.all():
total += problem.points
return total
def __str__(self): def __str__(self):
return self.name return self.name
@ -543,7 +550,7 @@ class Contest(models.Model):
return True return True
return False return False
@classmethod @classmethod
def get_visible_contests(cls, user, show_own_contests_only=False): def get_visible_contests(cls, user, show_own_contests_only=False):
if not user.is_authenticated: if not user.is_authenticated:

View file

@ -77,7 +77,7 @@ class Course(models.Model):
@classmethod @classmethod
def get_students(cls,course): def get_students(cls,course):
return CourseRole.objects.filter(course=course, role="ST").values("user") return CourseRole.objects.filter(course=course, role="ST")
@classmethod @classmethod
def get_assistants(cls,course): def get_assistants(cls,course):
@ -104,7 +104,7 @@ class Course(models.Model):
class CourseRole(models.Model): class CourseRole(models.Model):
course = models.OneToOneField( course = models.ForeignKey(
Course, Course,
verbose_name=_("course"), verbose_name=_("course"),
on_delete=models.CASCADE, on_delete=models.CASCADE,
@ -167,7 +167,7 @@ class CourseResource(models.Model):
class CourseAssignment(models.Model): class CourseAssignment(models.Model):
course = models.OneToOneField( course = models.ForeignKey(
Course, Course,
verbose_name=_("course"), verbose_name=_("course"),
on_delete=models.CASCADE, on_delete=models.CASCADE,

View file

@ -1,6 +1,8 @@
from django.db import models from django.db import models
from judge.models.course import Course from judge.models.course import Course , CourseAssignment , CourseRole
from django.views.generic import ListView from judge.models.contest import ContestParticipation, Contest
from django.views.generic import ListView, DetailView
from django.utils import timezone
__all__ = [ __all__ = [
"CourseList", "CourseList",
@ -10,22 +12,19 @@ __all__ = [
"CourseStudentResults", "CourseStudentResults",
"CourseEdit", "CourseEdit",
"CourseResourceDetailEdit", "CourseResourceDetailEdit",
"CourseResourceEdit", "CourseResourceEdit",
] ]
course_directory_file = "" course_directory_file = ""
class CourseListMixin(object):
def get_queryset(self):
return Course.objects.filter(is_open = "true").values()
class CourseList(ListView): class CourseList(ListView):
model = Course model = Course
template_name = "course/list.html" template_name = "course/list.html"
queryset = Course.objects.filter(is_public=True).filter(is_open=True) queryset = Course.objects.filter(is_public=True).filter(is_open=True)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(CourseList,self).get_context_data(**kwargs) context = super(CourseList, self).get_context_data(**kwargs)
available , enrolling = [] , [] available, enrolling = [], []
for course in Course.objects.filter(is_public=True).filter(is_open=True): for course in Course.objects.filter(is_public=True).filter(is_open=True):
if Course.is_accessible_by(course, self.request.profile): if Course.is_accessible_by(course, self.request.profile):
enrolling.append(course) enrolling.append(course)
@ -34,4 +33,61 @@ class CourseList(ListView):
context["available"] = available context["available"] = available
context["enrolling"] = enrolling context["enrolling"] = enrolling
return context return context
class CourseDetail(ListView):
model = CourseAssignment
template_name = "course/course.html"
def get_queryset(self):
cur_course = Course.objects.get(slug=self.kwargs['slug'])
return CourseAssignment.objects.filter(course=cur_course)
def get_context_data(self, **kwargs):
context = super(CourseDetail, self).get_context_data(**kwargs)
context['slug'] = self.kwargs['slug']
return context
def best_score_user_contest(user , contest):
participated_contests = ContestParticipation.objects.filter(user=user, contest=contest)
progress_point = 0
for cur_contest in participated_contests:
progress_point = max( progress_point , cur_contest.score_final )
return progress_point
def progress_contest(user , contest):
return best_score_user_contest(user, contest) / contest.total_points
def progress_course(user , course):
assignments = CourseAssignment.objects.filter(course=course)
assignments_total_point = 0
for assignment in assignments:
assignments_total_point += assignment.points
progress = 0
for assignment in assignments:
progress += progress_contest(user,assignment.contest) * assignment.points / assignments_total_point
return progress
class CourseStudentResults(ListView):
model = ContestParticipation
template_name = "course/grades.html"
def get_queryset(self):
cur_course = Course.objects.get(slug=self.kwargs['slug'])
contests = CourseAssignment.objects.filter(course=cur_course)
students = Course.get_students(cur_course)
grades_table = []
for student in students:
grades_student = [student.user.user.username]
for contest in contests:
grades_student.append( round(progress_contest(student.user, contest.contest) * 100 ) )
grades_student.append( round(progress_course(student.user, cur_course) * 100) )
grades_table.append( grades_student )
return grades_table
def get_context_data(self, **kwargs):
context = super(CourseStudentResults, self).get_context_data(**kwargs)
cur_course = Course.objects.get(slug=self.kwargs['slug'])
contests = CourseAssignment.objects.filter(course=cur_course)
context['contests'] = contests
return context

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{% for course in object_list %}
<h1> {{ course.contest }} - {{ course.contest.start_time }} - {{ course.contest.end_time }} </h1>
{% endfor %}
<a href="{{ url('grades',slug) }}">View grades</a>
</body>
</html>

View file

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
table {
border: 1px solid black;
border-collapse: collapse;
}
table th {
border: 1px solid black;
padding: 5px;
}
table td {
border: 1px solid black;
text-align: center;
}
</style>
</head>
<body>
<h1>Grades</h1>
<!-- {% for something in object_list %}
<h2> {{ something }} </h2>
{% endfor %} -->
<table>
<tr>
<th>Name</th>
{% for contest in contests %}
<th>{{ contest }}(%)</th>
{% endfor %}
<th>Progress</th>
</tr>
{% for student in object_list %}
<tr>
{% for data in student %}
<td>{{ data }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
</body>
</html>

View file

@ -9,11 +9,11 @@
<body> <body>
<h1>Enrolling</h1> <h1>Enrolling</h1>
{% for course in enrolling %} {% for course in enrolling %}
<h2> {{ course }} </h2> <h2><a href="{{ url('course_detail',course.name) }}"> {{ course }} </a></h2>
{% endfor %} {% endfor %}
<h1> Available </h1> <h1> Available </h1>
{% for course in available %} {% for course in available %}
<h2> {{ course }} </h2> <h2><a href="{{ url('course_detail',course.name) }}"> {{ course }} </a></h2>
{% endfor %} {% endfor %}
</body> </body>
</html> </html>