From c2b1e67be56b46412ce1b1ee111f53f5533891f3 Mon Sep 17 00:00:00 2001 From: Egor Matveev Date: Sat, 18 Dec 2021 10:21:13 +0300 Subject: [PATCH] solutions table --- Main/models/mixins.py | 4 +- Main/models/solution.py | 7 ++-- Main/views/SolutionsTableView.py | 63 ++++++++++++++++++++++++-------- Main/views/SolutionsView.py | 16 ++++++++ Main/views/TaskRuntimeView.py | 6 --- Main/views/__init__.py | 3 +- templates/solutions.html | 44 ++++++++++++++++++++++ templates/solutions_table.html | 31 +++++++++++++++- templates/task.html | 36 +++++------------- templates/tasks.html | 2 +- 10 files changed, 158 insertions(+), 54 deletions(-) create mode 100644 Main/views/SolutionsView.py create mode 100644 templates/solutions.html diff --git a/Main/models/mixins.py b/Main/models/mixins.py index 1b3aba7..7058a2a 100644 --- a/Main/models/mixins.py +++ b/Main/models/mixins.py @@ -1,8 +1,10 @@ +from functools import cached_property + from SprintLib.utils import get_bytes, write_bytes, delete_file class FileStorageMixin: - @property + @cached_property def text(self): return get_bytes(self.fs_id).decode("utf-8") diff --git a/Main/models/solution.py b/Main/models/solution.py index 73c4fa4..dad968e 100644 --- a/Main/models/solution.py +++ b/Main/models/solution.py @@ -1,4 +1,5 @@ -from os.path import join, exists +from functools import cached_property +from os.path import exists from shutil import rmtree from subprocess import call @@ -8,7 +9,7 @@ from django.utils import timezone from Main.models.solution_file import SolutionFile from Main.models.task import Task -from Sprint.settings import CONSTS, SOLUTIONS_ROOT, SOLUTIONS_ROOT_EXTERNAL +from Sprint.settings import CONSTS from SprintLib.language import languages @@ -28,7 +29,7 @@ class Solution(models.Model): rmtree(self.directory) super().delete(using=using, keep_parents=keep_parents) - @property + @cached_property def files(self): data = [] for file in SolutionFile.objects.filter(solution=self): diff --git a/Main/views/SolutionsTableView.py b/Main/views/SolutionsTableView.py index 2eea685..ba4c9be 100644 --- a/Main/views/SolutionsTableView.py +++ b/Main/views/SolutionsTableView.py @@ -1,25 +1,58 @@ -from django.http import HttpResponse +from django.db.models import QuerySet from Main.models import Solution -from Sprint.settings import CONSTS -from SprintLib.BaseView import BaseView +from SprintLib.BaseView import BaseView, AccessError class SolutionsTableView(BaseView): view_file = "solutions_table.html" required_login = True endpoint = "solutions_table" + page_size = 20 + page = None + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.filters = [ + self.filter_user, + self.filter_task, + self.filter_set, + ] + self.queryset = Solution.objects.all() + + def filter_user(self, queryset: QuerySet): + if 'username' in self.request.GET: + return queryset.filter(user__username=self.request.GET["username"]) + return queryset + + def filter_task(self, queryset: QuerySet): + if 'task_id' in self.request.GET: + return queryset.filter(task_id=int(self.request.GET['task_id'])) + return queryset + + def filter_set(self, queryset: QuerySet): + if 'set_id' in self.request.GET: + return queryset.filter() + return queryset + + def pre_handle(self): + if 'page' not in self.request.GET: + raise AccessError() + self.page = int(self.request.GET['page']) + if "username" in self.request.GET and self.request.user.username == self.request.GET['username']: + return + if hasattr(self.entities, "set"): + if self.entities.set.creator != self.request.user: + raise AccessError() + if hasattr(self.entities, "task"): + if self.entities.task.creator != self.request.user: + raise AccessError() def get(self): - self.context["solutions"] = Solution.objects.filter( - user=self.request.user, task=self.entities.task - ).order_by("-time_sent") - if "render" in self.request.GET.keys(): - return - for sol in self.context["solutions"]: - if ( - sol.result == CONSTS["testing_status"] - or sol.result == CONSTS["in_queue_status"] - ): - return - return HttpResponse("done") + for fltr in self.filters: + self.queryset = fltr(self.queryset) + offset = self.page_size * (self.page - 1) + limit = self.page_size + self.context["solutions"] = self.queryset.order_by("-id")[offset:offset + limit] + self.context["count_pages"] = range(1, (len(self.queryset) - 1) // self.page_size + 2) + self.context["need_pagination"] = len(self.context["count_pages"]) > 1 diff --git a/Main/views/SolutionsView.py b/Main/views/SolutionsView.py new file mode 100644 index 0000000..bdcd86b --- /dev/null +++ b/Main/views/SolutionsView.py @@ -0,0 +1,16 @@ +from SprintLib.BaseView import BaseView + + +class SolutionsView(BaseView): + required_login = True + endpoint = "solutions" + view_file = "solutions.html" + + def get(self): + self.context["username"] = self.request.GET.get("username") + self.context["task_id"] = self.request.GET.get("task_id") + if self.context["task_id"]: + self.context["task_id"] = int(self.context["task_id"]) + self.context["set_id"] = self.request.GET.get("set_id") + if self.context["set_id"]: + self.context["set_id"] = int(self.context["set_id"]) diff --git a/Main/views/TaskRuntimeView.py b/Main/views/TaskRuntimeView.py index 49138c2..6b9bc01 100644 --- a/Main/views/TaskRuntimeView.py +++ b/Main/views/TaskRuntimeView.py @@ -1,5 +1,3 @@ -from django.http import HttpResponse - from Main.models import Progress from SprintLib.BaseView import BaseView @@ -12,7 +10,3 @@ class TaskRuntimeView(BaseView): def get(self): progress = Progress.objects.get(task=self.entities.task, user=self.request.user) self.context["progress"] = progress - if "render" in self.request.GET.keys(): - return - if progress.finished: - return HttpResponse("done") diff --git a/Main/views/__init__.py b/Main/views/__init__.py index 50fc0a8..d1d6d1a 100644 --- a/Main/views/__init__.py +++ b/Main/views/__init__.py @@ -13,4 +13,5 @@ from Main.views.SolutionView import SolutionView from Main.views.ImageView import ImageView from Main.views.SendCodeView import SendCodeView from Main.views.SetSettingsView import SetSettingsView -from Main.views.UsersView import UsersView \ No newline at end of file +from Main.views.UsersView import UsersView +from Main.views.SolutionsView import SolutionsView diff --git a/templates/solutions.html b/templates/solutions.html new file mode 100644 index 0000000..942ceb2 --- /dev/null +++ b/templates/solutions.html @@ -0,0 +1,44 @@ +{% extends 'base_main.html' %} + +{% block scripts %} + var page = 1; + function setPage(number) { + page = number; + } + function doPoll() { + jQuery.get('/solutions_table?task_id={{ task.id }}&page=' + page.toString(), function(data) { + document.getElementById('solutions').innerHTML = data; + const name = "page_num_" + page.toString(); + document.getElementById(name).className = "btn btn-dark"; + setTimeout(function() {doPoll()}, 2000); + }) + } +{% endblock %} + +{% block onload %}doPoll(){% endblock %} + +{% block main %} +

Решения

+

Фильтр

+
+ + + +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/solutions_table.html b/templates/solutions_table.html index c998e22..67b5eb2 100644 --- a/templates/solutions_table.html +++ b/templates/solutions_table.html @@ -1,8 +1,24 @@ + + + + + + + + + + {% for solution in solutions %} + + @@ -16,4 +32,17 @@ -{% endfor %} \ No newline at end of file +{% endfor %} + +
idПользовательЗадачаВремя отправкиЯзыкРезультат
{{ solution.id }} + {{ solution.user }} + + {{ solution.task.name }} + {{ solution.time_sent }}
+{% if need_pagination %} +
+ + + {% for num in count_pages %} + + {% endfor %} + +
+
+{% endif %} \ No newline at end of file diff --git a/templates/task.html b/templates/task.html index 158bd99..adf0d6f 100644 --- a/templates/task.html +++ b/templates/task.html @@ -19,26 +19,20 @@ document.getElementById('file-upload').value = null; document.getElementById('input0').value = ""; } + var page = 1; + function setPage(number) { + page = number; + } function doPoll() { - jQuery.get('/solutions_table?task_id={{ task.id }}', function(data) { + jQuery.get('/solutions_table?task_id={{ task.id }}&username={{ user.username }}&page=' + page.toString(), function(data) { + document.getElementById('solutions').innerHTML = data; + const name = "page_num_" + page.toString(); + document.getElementById(name).className = "btn btn-dark"; jQuery.get('/task_runtime?task_id={{ task.id }}', function(data1) { - if (data == 'done' && data1 == 'done') - return - if (data != 'done') { - document.getElementById('solutions').innerHTML = data; - } - if (data1 != 'done') { - document.getElementById('runtime').innerHTML = data1; - } + document.getElementById('runtime').innerHTML = data1; setTimeout(function() {doPoll()}, 2000); }) }) - jQuery.get('/solutions_table?id={{ task.id }}&render=true', function(data) { - document.getElementById('solutions').innerHTML = data; - }) - jQuery.get('/task_runtime?id={{ task.id }}&render=true', function(data) { - document.getElementById('runtime').innerHTML = data; - }) } {% endblock %} @@ -134,15 +128,5 @@

Решения

- - - - - - - - - - -
idВремя отправкиЯзыкРезультат
+
{% endblock %} \ No newline at end of file diff --git a/templates/tasks.html b/templates/tasks.html index fd543b0..a4ec47d 100644 --- a/templates/tasks.html +++ b/templates/tasks.html @@ -44,6 +44,6 @@ {% for task in tasks %} - {{ task.name }} {% if task.creator == user %} {% endif %}
+ {{ task.name }} {% if task.creator == user %} {% endif %}
{% endfor %} {% endblock %} \ No newline at end of file