Skip to content

Commit

Permalink
Enhanced import ui
Browse files Browse the repository at this point in the history
  • Loading branch information
magnified103 committed Oct 10, 2024
1 parent c091a07 commit 3fffb32
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 22 deletions.
3 changes: 3 additions & 0 deletions dmoj/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@
VNOJ_LONG_QUEUE_ALERT_THRESHOLD = 10

# Transfer host
VNOJ_PROBLEM_ENABLE_IMPORT = False
VNOJ_PROBLEM_ENABLE_EXPORT = False
VNOJ_PROBLEM_IMPORT_HOST = 'https://oj.vnoi.info'
VNOJ_PROBLEM_IMPORT_SECRET = ''
VNOJ_PROBLEM_IMPORT_TIMEOUT = 5 # in seconds
Expand Down Expand Up @@ -502,6 +504,7 @@
'judge.template_context.site_theme',
'judge.template_context.misc_config',
'judge.template_context.math_setting',
'judge.template_context.site_setting',
'social_django.context_processors.backends',
'social_django.context_processors.login_redirect',
],
Expand Down
11 changes: 6 additions & 5 deletions dmoj/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,6 @@ def paged_list_view(view, name):
path('/suggest', problem.ProblemSuggest.as_view(), name='problem_suggest'),
path('/create', problem.ProblemCreate.as_view(), name='problem_create'),
path('/import-polygon', problem.ProblemImportPolygon.as_view(), name='problem_import_polygon'),
re_path('/export/(?P<secret>[a-zA-Z0-9_-]{48})/', include([
path('', ProblemExportView.as_view(), name='problem_export'),
path('select/', ProblemExportSelect2View.as_view(), name='problem_export_select2_ajax'),
])),
path('/import', ProblemImportView.as_view(), name='problem_import'),
])),

path('problem/<str:problem>', include([
Expand Down Expand Up @@ -427,6 +422,12 @@ def paged_list_view(view, name):
])),

path('magazine/', MagazinePage.as_view(), name='magazine'),

re_path('^problem-export/(?P<secret>[a-zA-Z0-9_-]{48})', include([
path('', ProblemExportView.as_view(), name='problem_export'),
path('/select', ProblemExportSelect2View.as_view(), name='problem_export_select2_ajax'),
])),
path('problem-import', ProblemImportView.as_view(), name='problem_import'),
]

favicon_paths = ['apple-touch-icon-180x180.png', 'apple-touch-icon-114x114.png', 'android-chrome-72x72.png',
Expand Down
4 changes: 4 additions & 0 deletions judge/template_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,7 @@ def math_setting(request):
if engine == 'auto':
engine = 'mml' if bool(settings.MATHOID_URL) and caniuse.mathml == SUPPORT else 'jax'
return {'MATH_ENGINE': engine, 'REQUIRE_JAX': engine == 'jax', 'caniuse': caniuse}


def site_setting(request):
return {'VNOJ_PROBLEM_ENABLE_IMPORT': settings.VNOJ_PROBLEM_ENABLE_IMPORT}
22 changes: 15 additions & 7 deletions judge/views/problem_transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

class ProblemExportMixin:
def setup(self, request, *args, **kwargs):
if not settings.VNOJ_PROBLEM_ENABLE_EXPORT:
raise Http404()
super().setup(request, *args, **kwargs)
try:
id, secret = struct.unpack('>I32s', base64.urlsafe_b64decode(kwargs['secret']))
Expand Down Expand Up @@ -115,18 +117,19 @@ def get_problem_export_url(host=settings.VNOJ_PROBLEM_IMPORT_HOST, secret=settin
class ProblemImportForm(Form):
problem = CharField(max_length=32,
validators=[RegexValidator('^[a-z0-9_]+$', _('Problem code must be ^[a-z0-9_]+$'))])
code = CharField(max_length=32, validators=[RegexValidator('^[a-z0-9_]+$', _('Problem code must be ^[a-z0-9_]+$'))])
new_code = CharField(max_length=32, validators=[RegexValidator('^[a-z0-9_]+$',
_('Problem code must be ^[a-z0-9_]+$'))])

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['problem'].widget = HeavySelect2Widget(data_url=get_problem_export_select_url(),
attrs={'style': 'width: 100%'})

def clean_code(self):
code = self.cleaned_data['code']
if Problem.objects.filter(code=code).exists():
def clean_new_code(self):
new_code = self.cleaned_data['new_code']
if Problem.objects.filter(code=new_code).exists():
raise ValidationError(_('Problem with code already exists.'))
return code
return new_code

def clean(self):
key_info = requests.get(get_problem_export_url(), timeout=settings.VNOJ_PROBLEM_IMPORT_TIMEOUT).json()
Expand All @@ -142,12 +145,14 @@ class ProblemImportView(TitleMixin, FormView):
form_class = ProblemImportForm

def form_valid(self, form):
problem_info = requests.post(get_problem_export_url(), data={'code': form.cleaned_data['problem']}, timeout=settings.VNOJ_PROBLEM_IMPORT_TIMEOUT).json()
problem_info = requests.post(get_problem_export_url(),
data={'code': form.cleaned_data['problem']},
timeout=settings.VNOJ_PROBLEM_IMPORT_TIMEOUT).json()

if not problem_info:
raise Http404('Request timed out')
problem = Problem()
problem.code = form.cleaned_data['code']
problem.code = form.cleaned_data['new_code']
problem.name = problem_info['name']
problem.description = problem_info['description']
problem.time_limit = problem_info['time_limit']
Expand All @@ -157,6 +162,7 @@ def form_valid(self, form):
problem.short_circuit = problem_info['short_circuit']
problem.group = ProblemGroup.objects.order_by('id').first() # Uncategorized
problem.date = timezone.now()
problem.is_manually_managed = True
with revisions.create_revision(atomic=True):
problem.save()
problem.allowed_languages.set(Language.objects.filter(include_in_problem=True))
Expand All @@ -168,6 +174,8 @@ def form_valid(self, form):
return HttpResponseRedirect(reverse('problem_edit', args=(problem.code,)))

def dispatch(self, request, *args, **kwargs):
if not settings.VNOJ_PROBLEM_ENABLE_IMPORT:
raise Http404()
if not request.user.is_superuser:
raise PermissionDenied()
return super().dispatch(request, *args, **kwargs)
30 changes: 20 additions & 10 deletions templates/problem/import.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,31 @@

{% block media %}
{{ form.media.css }}
<link rel="stylesheet" type="text/css" href="{{ static('ui_form.css') }}">
{% endblock %}

{% block js_media %}
{{ form.media.js }}
{% endblock %}

{% block title_ruler %}{% endblock %}

{% block title_row %}
{% set tab = 'import' %}
{% include "problem/problem-list-tabs.html" %}
{% endblock %}

{% block body %}
<form method="post">
{% if form.errors %}
<div class="form-errors">
{{ form.non_field_errors() }}
</div>
{% endif %}
{% csrf_token %}
{{ form.as_p() }}
<p><input type="submit" value="Import"></p>
</form>
<div>
<form method="post" class="form-area" style="display: flex; justify-content: center; flex-direction: column;">
{% if form.non_field_errors() %}
<div class="form-errors">
{{ form.non_field_errors() }}
</div>
{% endif %}
{% csrf_token %}
<table class="django-as-table">{{ form.as_table() }}</table>
<p><input type="submit" value="Import"></p>
</form>
</div>
{% endblock %}
3 changes: 3 additions & 0 deletions templates/problem/problem-list-tabs.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
{{ make_tab('suggest', 'fa-list', url('problem_suggest_list'), _('Suggest')) }}
{% endif %}
{% if request.user.is_superuser %}
{% if VNOJ_PROBLEM_ENABLE_IMPORT %}
{{ make_tab('import', 'fa-cloud-download', url('problem_import'), _('Import')) }}
{% endif %}
{{ make_tab('admin', 'fa-edit', url('admin:judge_problem_changelist'), _('Admin')) }}
{% endif %}
{% endblock %}

0 comments on commit 3fffb32

Please sign in to comment.