Skip to content

Add copying problems in bulk #505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion oioioi/contests/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from django.urls import re_path, reverse
from django.utils.encoding import force_str
from django.utils.html import format_html
from django.utils.http import urlencode
from django.utils.translation import get_language
from django.utils.translation import gettext_lazy as _
from django.utils.translation import ngettext_lazy
Expand Down Expand Up @@ -379,6 +380,20 @@ class ProblemInstanceAdmin(admin.ModelAdmin):
list_display = ('name_link', 'short_name_link', 'round', 'package', 'actions_field')
readonly_fields = ('contest', 'problem')
ordering = ('-round__start_date', 'short_name')
actions = ['attach_problems_to_another_contest']

def attach_problems_to_another_contest(self, request, queryset):
print("self: ", self)
print("request: ", request)
print("queryset: ", queryset)

ids = [problem.id for problem in queryset]

# Attach problem ids as arguments to the URL
base_url = reverse('reattach_problem_contest_list')
query_string = urlencode({'ids': ','.join(str(i) for i in ids)}, doseq=True)

return redirect('%s?%s' % (base_url, query_string))

def __init__(self, *args, **kwargs):
# creating a thread local variable to store the request
Expand Down Expand Up @@ -428,7 +443,10 @@ def _reset_limits_href(self, instance):
return reverse('reset_tests_limits_for_probleminstance', args=(instance.id,))

def _reattach_problem_href(self, instance):
return reverse('reattach_problem_contest_list', args=(instance.id,))
base_url = reverse('reattach_problem_contest_list')
query_string = urlencode({'ids': instance.id})
# Attach problem id as an argument to the URL
return '%s?%s' % (base_url, query_string)

def _add_or_update_href(self, instance):
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
{% block main-content %}

<h1>{% trans "Confirm attachement" %}</h1>

<p>
{% blocktrans %}
You are going to attach problem {{ problem_instance }}
to contest {{ destination_contest }}
You are going to attach the following problems to the contest
{% endblocktrans %}
<strong>{{ contest.name }}</strong>:
<ul class="list-group d-inline-block">
{% for problem in problem_instances %}
<li class="list-group-item">{{ problem }}</li>
{% endfor %}
</ul>
</p>

<form method="post">
Expand All @@ -20,7 +24,7 @@ <h1>{% trans "Confirm attachement" %}</h1>
<div class="form-group">
<div class="checkbox"><label for="copy-limits">
<input type="checkbox" id="copy-limits" name="copy-limits" />
{% trans "Copy limits from source contest" %}
{% trans "Copy limits from the source contest" %}
</label></div>
</div>
<div class="form-group">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@

{% block main-content %}
<h2>
{% blocktrans %}Choose a contest to attach the problem to {{ problem_instance }}: {% endblocktrans %}
{% blocktrans %} Contest choice {% endblocktrans %}
</h2>
<p>
{% blocktrans %}Choose a contest to attach the following problems to: {% endblocktrans %}
<ul class="list-group d-inline-block">
{% for problem in problem_instances %}
<li class="list-group-item">{{ problem }}</li>
{% endfor %}
</ul>
</p>

<div class="table-responsive-md row">
<div class="col-md-6">
Expand All @@ -21,7 +29,7 @@ <h2>
{% for contest in contest_list %}
<tr>
<td>{{ contest.id }}</td>
<td><a href="{% url 'reattach_problem_confirm' problem_instance.id contest.id %}">
<td><a href="{% url 'reattach_problem_confirm' contest.id %}/?ids={{ problem_ids }}">
{{ contest.name }}
</a>
{% if contest.is_archived %}
Expand All @@ -36,7 +44,7 @@ <h2>
</div>
{% if not full_list %}
<a class="btn btn-outline-secondary"
href="{% url 'reattach_problem_contest_list' problem_instance.id 'full' %}">
href="{% url 'reattach_problem_contest_list' 'full' %}/?ids={{ problem_ids }}">
{% trans "More" %}
</a>
{% endif %}
Expand Down
4 changes: 2 additions & 2 deletions oioioi/contests/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,13 @@ def glob_namespaced_patterns(namespace):
name='report',
),
re_path(
r'^reattach/(?P<problem_instance_id>\d+)/contest_list/'
r'^reattach/contest_list/'
'((?P<full_list>full))?',
views.reattach_problem_contest_list_view,
name='reattach_problem_contest_list',
),
re_path(
r'^reattach/(?P<problem_instance_id>\d+)/'
r'^reattach/'
'(?P<contest_id>[a-z0-9_-]+)/confirm',
views.reattach_problem_confirm_view,
name='reattach_problem_confirm',
Expand Down
44 changes: 32 additions & 12 deletions oioioi/contests/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.http import urlencode
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from django.utils.translation import ngettext_lazy
Expand Down Expand Up @@ -774,8 +775,14 @@ def reset_tests_limits_for_probleminstance_view(request, problem_instance_id):


@enforce_condition(contest_exists & is_contest_basicadmin)
def reattach_problem_contest_list_view(request, problem_instance_id, full_list=False):
problem_instance = get_object_or_404(ProblemInstance, id=problem_instance_id)
def reattach_problem_contest_list_view(request, full_list=False):
problem_ids = request.GET.get('ids')
if problem_ids:
problem_ids = [int(i) for i in problem_ids.split(',') if i.isdigit()]
else:
pass # TODO

problem_instances = ProblemInstance.objects.filter(id__in=problem_ids)

if full_list:
contests = Contest.objects.all()
Expand All @@ -787,27 +794,37 @@ def reattach_problem_contest_list_view(request, problem_instance_id, full_list=F
request,
'contests/reattach_problem_contest_list.html',
{
'problem_instance': problem_instance,
'problem_instances': problem_instances,
'contest_list': contests,
'full_list': full_list,
'problem_ids': '%2C'.join(str(i) for i in problem_ids), # Separate the problem ids with a comma (%2C)
},
)


@enforce_condition(contest_exists & is_contest_basicadmin)
def reattach_problem_confirm_view(request, problem_instance_id, contest_id):
def reattach_problem_confirm_view(request, contest_id):
contest = get_object_or_404(Contest, id=contest_id)
if not can_admin_contest(request.user, contest):
raise PermissionDenied
problem_instance = get_object_or_404(ProblemInstance, id=problem_instance_id)

problem_ids = request.GET.get('ids')
if problem_ids:
problem_ids = [int(i) for i in problem_ids.split(',')]
else:
pass # TODO

if request.method == 'POST':
if request.POST.get('copy-limits', '') == 'on':
pi = copy_problem_instance(problem_instance, contest)
else:
pi = get_new_problem_instance(problem_instance.problem, contest)
problem_instances = ProblemInstance.objects.filter(id__in=problem_ids)

messages.success(request, _(u"Problem {} added successfully.".format(pi)))
if request.method == 'POST':
copied_instances = (
[copy_problem_instance(problem_instance, contest)
for problem_instance in problem_instances]
if request.POST.get('copy-limits', '') == 'on'
else [get_new_problem_instance(problem_instance.problem, contest)
for problem_instance in problem_instances]
)
messages.success(request, _(u"Problems {} added successfully.".format(', '.join(map(str, copied_instances)))))
return safe_redirect(
request,
reverse(
Expand All @@ -818,7 +835,10 @@ def reattach_problem_confirm_view(request, problem_instance_id, contest_id):
return TemplateResponse(
request,
'contests/reattach_problem_confirm.html',
{'problem_instance': problem_instance, 'destination_contest': contest},
{
'problem_instances': problem_instances,
'destination_contest': contest
},
)


Expand Down
Loading