From fe5e7198ee9ce11ae442eaea3edcac391ab3d5d7 Mon Sep 17 00:00:00 2001 From: cuom1999 Date: Thu, 22 Sep 2022 17:33:14 -0500 Subject: [PATCH] Change lang stat page --- dmoj/urls.py | 22 +---- judge/views/stats.py | 148 ++++++++++++++++++---------------- templates/stats/base.html | 9 +-- templates/stats/language.html | 18 +---- templates/stats/tab.html | 5 ++ 5 files changed, 90 insertions(+), 112 deletions(-) create mode 100644 templates/stats/tab.html diff --git a/dmoj/urls.py b/dmoj/urls.py index 68e691a..3468a19 100644 --- a/dmoj/urls.py +++ b/dmoj/urls.py @@ -886,27 +886,7 @@ urlpatterns = [ "^language/", include( [ - url("^$", stats.language, name="language_stats"), - url( - "^data/all/$", - stats.language_data, - name="language_stats_data_all", - ), - url( - "^data/ac/$", - stats.ac_language_data, - name="language_stats_data_ac", - ), - url( - "^data/status/$", - stats.status_data, - name="stats_data_status", - ), - url( - "^data/ac_rate/$", - stats.ac_rate, - name="language_stats_data_ac_rate", - ), + url("^$", stats.StatLanguage.as_view(), name="language_stats"), ] ), ), diff --git a/judge/views/stats.py b/judge/views/stats.py index e8c74ef..640088e 100644 --- a/judge/views/stats.py +++ b/judge/views/stats.py @@ -1,5 +1,6 @@ from itertools import chain, repeat from operator import itemgetter +import json from django.conf import settings from django.db.models import Case, Count, FloatField, IntegerField, Value, When @@ -7,6 +8,9 @@ from django.db.models.expressions import CombinedExpression from django.http import JsonResponse from django.shortcuts import render from django.utils.translation import gettext as _ +from django.http import Http404 +from django.views.generic import TemplateView +from django.utils.safestring import mark_safe from judge.models import Language, Submission from judge.utils.stats import ( @@ -17,86 +21,88 @@ from judge.utils.stats import ( ) -ac_count = Count( - Case(When(submission__result="AC", then=Value(1)), output_field=IntegerField()) -) +class StatViewBase(TemplateView): + def get(self, request, *args, **kwargs): + if not request.user.is_superuser: + raise Http404 + return super().get(request, *args, **kwargs) -def repeat_chain(iterable): - return chain.from_iterable(repeat(iterable)) - - -def language_data( - request, language_count=Language.objects.annotate(count=Count("submission")) -): - languages = ( - language_count.filter(count__gt=0) - .values("key", "name", "count") - .order_by("-count") - ) - num_languages = min(len(languages), settings.DMOJ_STATS_LANGUAGE_THRESHOLD) - other_count = sum(map(itemgetter("count"), languages[num_languages:])) - - return JsonResponse( - { - "labels": list(map(itemgetter("name"), languages[:num_languages])) - + ["Other"], - "datasets": [ - { - "backgroundColor": chart_colors[:num_languages] + ["#FDB45C"], - "highlightBackgroundColor": highlight_colors[:num_languages] - + ["#FFC870"], - "data": list(map(itemgetter("count"), languages[:num_languages])) - + [other_count], - }, - ], - }, - safe=False, +class StatLanguage(StatViewBase): + template_name = "stats/language.html" + ac_count = Count( + Case(When(submission__result="AC", then=Value(1)), output_field=IntegerField()) ) + def repeat_chain(iterable): + return chain.from_iterable(repeat(iterable)) -def ac_language_data(request): - return language_data(request, Language.objects.annotate(count=ac_count)) - - -def status_data(request, statuses=None): - if not statuses: - statuses = ( - Submission.objects.values("result") - .annotate(count=Count("result")) - .values("result", "count") + def language_data( + self, language_count=Language.objects.annotate(count=Count("submission")) + ): + languages = ( + language_count.filter(count__gt=0) + .values("key", "name", "count") .order_by("-count") ) - data = [] - for status in statuses: - res = status["result"] - if not res: - continue - count = status["count"] - data.append((str(Submission.USER_DISPLAY_CODES[res]), count)) + num_languages = min(len(languages), settings.DMOJ_STATS_LANGUAGE_THRESHOLD) + other_count = sum(map(itemgetter("count"), languages[num_languages:])) - return JsonResponse(get_pie_chart(data), safe=False) + return { + "labels": list(map(itemgetter("name"), languages[:num_languages])) + + ["Other"], + "datasets": [ + { + "backgroundColor": chart_colors[:num_languages] + ["#FDB45C"], + "highlightBackgroundColor": highlight_colors[:num_languages] + + ["#FFC870"], + "data": list(map(itemgetter("count"), languages[:num_languages])) + + [other_count], + }, + ], + } + + def ac_language_data(self): + return self.language_data(Language.objects.annotate(count=self.ac_count)) + + def status_data(self, statuses=None): + if not statuses: + statuses = ( + Submission.objects.values("result") + .annotate(count=Count("result")) + .values("result", "count") + .order_by("-count") + ) + data = [] + for status in statuses: + res = status["result"] + if not res: + continue + count = status["count"] + data.append((str(Submission.USER_DISPLAY_CODES[res]), count)) + + return get_pie_chart(data) -def ac_rate(request): - rate = CombinedExpression( - ac_count / Count("submission"), "*", Value(100.0), output_field=FloatField() - ) - data = ( - Language.objects.annotate(total=Count("submission"), ac_rate=rate) - .filter(total__gt=0) - .order_by("total") - .values_list("name", "ac_rate") - ) - return JsonResponse(get_bar_chart(list(data))) + def ac_rate(self): + rate = CombinedExpression( + self.ac_count / Count("submission"), "*", Value(100.0), output_field=FloatField() + ) + data = ( + Language.objects.annotate(total=Count("submission"), ac_rate=rate) + .filter(total__gt=0) + .order_by("total") + .values_list("name", "ac_rate") + ) + return get_bar_chart(list(data)) -def language(request): - return render( - request, - "stats/language.html", - { - "title": _("Language statistics"), - "tab": "language", - }, - ) + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["title"] = _("Language statistics") + context["tab"] = "language" + context["data_all"] = mark_safe(json.dumps(self.language_data())) + context["lang_ac"] = mark_safe(json.dumps(self.ac_language_data())) + context["status_counts"] = mark_safe(json.dumps(self.status_data())) + context["ac_rate"] = mark_safe(json.dumps(self.ac_rate())) + return context \ No newline at end of file diff --git a/templates/stats/base.html b/templates/stats/base.html index d83ac96..6e72989 100644 --- a/templates/stats/base.html +++ b/templates/stats/base.html @@ -6,13 +6,10 @@ {% endcompress %} {% endblock %} -{% block content_title %}{{ _('Statistics') }}{% endblock %} +{% block content_title %}{% endblock %} +{% block title_ruler %}{% endblock %} {% block body %} -
- - {{ _('Language') }} - -
+ {% include "stats/tab.html" %} {% block chart_body %}{% endblock %} {% endblock %} diff --git a/templates/stats/language.html b/templates/stats/language.html index d142c62..70ec589 100644 --- a/templates/stats/language.html +++ b/templates/stats/language.html @@ -36,20 +36,10 @@ Chart.defaults.global.tooltipFontFamily = Chart.defaults.global.tooltipTitleFontFamily = $('body').css('font-family'); - - function pie_chart(url, $chart) { - $.getJSON(url, function (data) { - draw_pie_chart(data, $chart); - }); - } - - pie_chart('{{ url('language_stats_data_all') }}', $('#lang-all')); - pie_chart('{{ url('language_stats_data_ac') }}', $('#lang-ac')); - pie_chart('{{ url('stats_data_status') }}', $('#status-counts')); - - $.getJSON('{{ url('language_stats_data_ac_rate') }}', function (data) { - draw_bar_chart(data, $('#ac-rate')); - }); + draw_pie_chart({{ data_all }}, $('#lang-all')); + draw_pie_chart({{ lang_ac }}, $('#lang-ac')); + draw_pie_chart({{ status_counts }}, $('#status-counts')); + draw_bar_chart({{ ac_rate }}, $('#ac-rate')); }); {% endblock %} diff --git a/templates/stats/tab.html b/templates/stats/tab.html new file mode 100644 index 0000000..0b7a1d7 --- /dev/null +++ b/templates/stats/tab.html @@ -0,0 +1,5 @@ +{% extends "tabs-base.html" %} + +{% block tabs %} + {{ make_tab('language', 'fa-list', url('language_stats'), _('Language')) }} +{% endblock %} \ No newline at end of file