From 43947a303b3133f3459142f753b332202901e87f Mon Sep 17 00:00:00 2001 From: Joona Yoon Date: Wed, 24 Jan 2018 18:54:40 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EC=B6=9C=EC=B2=98?= =?UTF-8?q?=EB=A5=BC=20=ED=8A=B8=EB=A6=AC=20=EA=B5=AC=EC=A1=B0=EB=A1=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge/admin/__init__.py | 9 +++++---- judge/admin/taxon.py | 32 ++++++++++++++++++++++++++++++-- judge/models/__init__.py | 4 ++-- judge/models/problem.py | 23 ++++++++++++++++++++++- 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/judge/admin/__init__.py b/judge/admin/__init__.py index 878b3749..de1d0f0a 100644 --- a/judge/admin/__init__.py +++ b/judge/admin/__init__.py @@ -8,11 +8,11 @@ from judge.admin.profile import ProfileAdmin from judge.admin.runtime import JudgeAdmin, LanguageAdmin from judge.admin.submission import SubmissionAdmin -from judge.admin.taxon import ProblemGroupAdmin, ProblemTypeAdmin +from judge.admin.taxon import ProblemGroupAdmin, ProblemTypeAdmin, ProblemSourceAdmin from judge.admin.ticket import TicketAdmin -from judge.models import Language, Profile, Problem, ProblemGroup, ProblemType, Submission, Comment, \ - MiscConfig, Judge, NavigationBar, Contest, ContestParticipation, Organization, BlogPost, \ - License, OrganizationRequest, ContestTag, Ticket +from judge.models import Language, Profile, Problem, ProblemGroup, ProblemType, ProblemSource, \ + Submission, Comment, MiscConfig, Judge, NavigationBar, Contest, ContestParticipation, \ + Organization, BlogPost, License, OrganizationRequest, ContestTag, Ticket admin.site.register(Language, LanguageAdmin) admin.site.register(Comment, CommentAdmin) @@ -20,6 +20,7 @@ admin.site.register(Problem, ProblemAdmin) admin.site.register(ProblemGroup, ProblemGroupAdmin) admin.site.register(ProblemType, ProblemTypeAdmin) +admin.site.register(ProblemSource, ProblemSourceAdmin) admin.site.register(Submission, SubmissionAdmin) admin.site.register(MiscConfig) admin.site.register(NavigationBar, NavigationBarAdmin) diff --git a/judge/admin/taxon.py b/judge/admin/taxon.py index 9471c3ea..df86b94d 100644 --- a/judge/admin/taxon.py +++ b/judge/admin/taxon.py @@ -2,7 +2,9 @@ from django.forms import ModelForm, ModelMultipleChoiceField from django.utils.translation import ugettext_lazy as _ -from judge.models import Problem +from mptt.admin import DraggableMPTTAdmin + +from judge.models import Problem, ProblemSource from judge.widgets import HeavySelect2MultipleWidget @@ -49,4 +51,30 @@ def save_model(self, request, obj, form, change): def get_form(self, request, obj=None, **kwargs): self.form.base_fields['problems'].initial = [o.pk for o in obj.problem_set.all()] if obj else [] - return super(ProblemTypeAdmin, self).get_form(request, obj, **kwargs) \ No newline at end of file + return super(ProblemTypeAdmin, self).get_form(request, obj, **kwargs) + + +class ProblemSourceAdmin(DraggableMPTTAdmin): + list_display = DraggableMPTTAdmin.list_display + ('key', 'name') + fields = ('name', 'order', 'parent') + list_editable = () # Bug in SortableModelAdmin: 500 without list_editable being set + mptt_level_indent = 20 + sortable = 'order' + + def __init__(self, *args, **kwargs): + super(ProblemSourceAdmin, self).__init__(*args, **kwargs) + self.__save_model_calls = 0 + + def save_model(self, request, obj, form, change): + self.__save_model_calls += 1 + return super(ProblemSourceAdmin, self).save_model(request, obj, form, change) + + def changelist_view(self, request, extra_context=None): + self.__save_model_calls = 0 + with ProblemSource.objects.disable_mptt_updates(): + result = super(ProblemSourceAdmin, self).changelist_view(request, extra_context) + if self.__save_model_calls: + with LockModel(write=(ProblemSource,)): + ProblemSource.objects.rebuild() + return result + diff --git a/judge/models/__init__.py b/judge/models/__init__.py index 254046f5..68db98f6 100644 --- a/judge/models/__init__.py +++ b/judge/models/__init__.py @@ -5,8 +5,8 @@ from judge.models.contest import Contest, ContestTag, ContestParticipation, ContestProblem, ContestSubmission, Rating from judge.models.interface import MiscConfig, validate_regex, NavigationBar, BlogPost from judge.models.message import PrivateMessage, PrivateMessageThread -from judge.models.problem import ProblemGroup, ProblemType, Problem, ProblemClarification, ProblemTranslation, \ - TranslatedProblemQuerySet, TranslatedProblemForeignKeyQuerySet, License, LanguageLimit, Solution +from judge.models.problem import ProblemGroup, ProblemType, ProblemSource, Problem, ProblemClarification, \ + ProblemTranslation, TranslatedProblemQuerySet, TranslatedProblemForeignKeyQuerySet, License, LanguageLimit, Solution from judge.models.problem_data import problem_data_storage, problem_directory_file, ProblemData, ProblemTestCase, \ CHECKERS from judge.models.profile import Profile, Organization, OrganizationRequest diff --git a/judge/models/problem.py b/judge/models/problem.py index fec0d388..e9bcbf20 100644 --- a/judge/models/problem.py +++ b/judge/models/problem.py @@ -12,13 +12,17 @@ from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ +from mptt.fields import TreeForeignKey +from mptt.models import MPTTModel + from judge.fulltext import SearchQuerySet from judge.models.profile import Profile from judge.models.runtime import Language from judge.user_translations import ugettext as user_ugettext from judge.utils.raw_sql import unique_together_left_join, RawSQLColumn -__all__ = ['ProblemGroup', 'ProblemType', 'Problem', 'ProblemTranslation', 'ProblemClarification', +__all__ = ['ProblemGroup', 'ProblemType', 'ProblemSource', + 'Problem', 'ProblemTranslation', 'ProblemClarification', 'TranslatedProblemQuerySet', 'TranslatedProblemForeignKeyQuerySet', 'License'] @@ -48,6 +52,23 @@ class Meta: verbose_name_plural = _('problem groups') +class ProblemSource(MPTTModel): + class Meta: + verbose_name = _('problem source item') + verbose_name_plural = _('problem sources') + + class MPTTMeta: + order_insertion_by = ['order'] + + order = models.PositiveIntegerField(db_index=True, verbose_name=_('order')) + key = models.AutoField(primary_key=True, verbose_name=_('key')) + name = models.CharField(max_length=20, verbose_name=_('name')) + parent = TreeForeignKey('self', verbose_name=_('parent item'), null=True, blank=True, related_name='children') + + def __unicode__(self): + return self.name + + class License(models.Model): key = models.CharField(max_length=20, unique=True, verbose_name=_('key'), validators=[RegexValidator(r'^[-\w.]+$', r'License key must be ^[-\w.]+$')]) From e53fe887bb6596b018d34220f8e53ca80809a710 Mon Sep 17 00:00:00 2001 From: Joona Yoon Date: Wed, 24 Jan 2018 18:54:58 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20=EC=82=AC?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=EB=A9=94=EB=89=B4=EC=97=90=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dmoj/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dmoj/settings.py b/dmoj/settings.py index ada372c5..075616b4 100644 --- a/dmoj/settings.py +++ b/dmoj/settings.py @@ -61,6 +61,7 @@ 'children': [ 'judge.ProblemGroup', 'judge.ProblemType', + 'judge.ProblemSource', ], }, { From 01ad0d5dd653abbe1bf56f3ef3122280f62c9730 Mon Sep 17 00:00:00 2001 From: Joona Yoon Date: Wed, 24 Jan 2018 18:55:27 +0000 Subject: [PATCH 3/3] =?UTF-8?q?migrate=20=EB=AC=B8=EC=A0=9C=20=EC=B6=9C?= =?UTF-8?q?=EC=B2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge/migrations/0070_auto_20180125_0321.py | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 judge/migrations/0070_auto_20180125_0321.py diff --git a/judge/migrations/0070_auto_20180125_0321.py b/judge/migrations/0070_auto_20180125_0321.py new file mode 100644 index 00000000..d0316188 --- /dev/null +++ b/judge/migrations/0070_auto_20180125_0321.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.8 on 2018-01-24 18:21 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import mptt.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('judge', '0069_auto_20180120_2033'), + ] + + operations = [ + migrations.CreateModel( + name='ProblemSource', + fields=[ + ('order', models.PositiveIntegerField(db_index=True, verbose_name='order')), + ('key', models.AutoField(primary_key=True, serialize=False, verbose_name='identifier')), + ('name', models.CharField(max_length=20, verbose_name='name')), + ('lft', models.PositiveIntegerField(db_index=True, editable=False)), + ('rght', models.PositiveIntegerField(db_index=True, editable=False)), + ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), + ('level', models.PositiveIntegerField(db_index=True, editable=False)), + ('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='judge.ProblemSource', verbose_name='parent item')), + ], + options={ + 'verbose_name': 'problem source item', + 'verbose_name_plural': 'problem sources', + }, + ), + migrations.AlterField( + model_name='organization', + name='key', + field=models.CharField(default=b'2018AZ', help_text='Organization name shows in URL', max_length=6, unique=True, validators=[django.core.validators.RegexValidator(b'^[A-Za-z0-9]+$', b'Identifier must contain letters and numbers only')], verbose_name='identifier'), + ), + ]