Skip to content

Commit

Permalink
(no-ticket) Show the language (and compiler) to the user, based on th…
Browse files Browse the repository at this point in the history
…e extension of the uploaded file.

Change-Id: I2a811ccf4e632ec9afb832818db4e13ea69aaf48
  • Loading branch information
arturpragacz committed Jun 23, 2020
1 parent 027f0c3 commit e4dc9b9
Show file tree
Hide file tree
Showing 13 changed files with 106 additions and 55 deletions.
4 changes: 2 additions & 2 deletions oioioi/exportszu/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from oioioi.filetracker.utils import django_to_filetracker_path
from oioioi.participants.models import Participant
from oioioi.programs.models import ProgramSubmission
from oioioi.programs.utils import get_extension


class SubmissionData(object):
Expand Down Expand Up @@ -76,8 +77,7 @@ def collect_list(self):
data.last_name = s.user.last_name
data.problem_short_name = s.problem_instance.short_name
data.score = s.score
data.solution_language = ccontroller.get_extension(s.source_file,
s.problem_instance)
data.solution_language = get_extension(s.source_file.name)
data.source_file = s.source_file

# here we try to get some optional data, it just may not be there
Expand Down
2 changes: 1 addition & 1 deletion oioioi/portals/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ class MockRequest(object):
def __init__(self):
self.user = AnonymousUser()

# mocking up a request below becouse I am NOT testing whole view
# mocking up a request below because I am NOT testing the whole view
self.request = MockRequest()

for i in range(1, 5):
Expand Down
2 changes: 1 addition & 1 deletion oioioi/problems/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ProblemController(RegisteredSubclassesBase, ObjectWithMixins):
Please note that a global problem instance exists for each problem.
That problem instance has no contest (``contest`` is ``None``),
so methods can't be overridden by contest controller what means they
so methods can't be overridden by a contest controller which means they
behave in a default way.
"""

Expand Down
14 changes: 9 additions & 5 deletions oioioi/problems/problem_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from operator import itemgetter # pylint: disable=E0611

from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404, redirect
from django.template.loader import render_to_string
Expand All @@ -13,12 +14,12 @@
from oioioi.base.menu import OrderedRegistry
from oioioi.contests.controllers import submission_template_context
from oioioi.contests.forms import SubmissionFormForProblemInstance
from oioioi.contests.models import Submission
from oioioi.contests.models import (ProblemInstance, Submission)
from oioioi.contests.utils import administered_contests
from oioioi.problems.models import (Problem, ProblemAttachment, ProblemPackage, AlgorithmTagProposal,
ProblemStatement)
from oioioi.problems.utils import (query_statement, query_zip, generate_add_to_contest_metadata,
generate_model_solutions_context, can_admin_problem)
generate_model_solutions_context, can_admin_problem, can_admin_problem_instance)
from oioioi.contests.attachment_registration import attachment_registry_problemset

problem_site_tab_registry = OrderedRegistry()
Expand Down Expand Up @@ -151,17 +152,20 @@ def problem_site_submit(request, problem):
{'problem': problem, 'form': form})


@problem_site_tab(_("Secret key"), key='secret_key', order=500)
@problem_site_tab(_("Secret key"), key='secret_key', order=500,
condition=lambda request, problem: problem.visibility != problem.VISIBILITY_PUBLIC)
def problem_site_secret_key(request, problem):
return TemplateResponse(request, 'problems/secret-key.html',
{'site_key': problem.problemsite.url_key})


@problem_site_tab(_("Settings"), key='settings', order=600)
@problem_site_tab(_("Settings"), key='settings', order=600,
condition=can_admin_problem)
def problem_site_settings(request, problem):
show_add_button, administered_recent_contests = generate_add_to_contest_metadata(request)
package = ProblemPackage.objects.filter(problem=problem).first()
model_solutions = generate_model_solutions_context(request, problem.main_problem_instance_id)
problem_instance = get_object_or_404(ProblemInstance, id=problem.main_problem_instance_id)
model_solutions = generate_model_solutions_context(request, problem_instance)
extra_actions = problem.controller.get_extra_problem_site_actions(problem)
algorithm_tag_proposals = AlgorithmTagProposal.objects.all().filter(problem=problem).order_by('-pk')[:25]
return TemplateResponse(request, 'problems/settings.html',
Expand Down
21 changes: 9 additions & 12 deletions oioioi/problems/templates/problems/problemset/problem-site.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,14 @@ <h1>{{ problem }}</h1>

<ul class="nav nav-tabs">
{% for tab in tabs %}
{% if tab.obj.key != "secret_key" or problem.visibility != problem.VISIBILITY_PUBLIC %}
{% if tab.obj.key != 'settings' or can_admin_problem %}
{% if tab.obj.key != 'add_to_contest' %}
<li {% if tab.obj == current_tab %}class="active"{% endif %}>
<a href="{{ tab.link }}">{{ tab.obj.title }}</a>
</li>
{% elif show_add_button and not can_admin_problem %}
<li {% if tab.obj == current_tab %}class="active"{% endif %}>
<a href="{{ tab.link }}">{{ tab.obj.title }}</a>
</li>
{% endif %}
{% endif %}
{% if tab.obj.key != 'add_to_contest' %}
<li {% if tab.obj == current_tab %}class="active"{% endif %}>
<a href="{{ tab.link }}">{{ tab.obj.title }}</a>
</li>
{% elif show_add_button and not can_admin_problem %}
<li {% if tab.obj == current_tab %}class="active"{% endif %}>
<a href="{{ tab.link }}">{{ tab.obj.title }}</a>
</li>
{% endif %}
{% endfor %}
</ul>
Expand All @@ -46,5 +42,6 @@ <h1>{{ problem }}</h1>

<script type="text/javascript" src="{{ STATIC_URL }}problems/problemset/add-to-contest.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}problems/problemset/tag-form.js"></script>
<script type="text/javascript">var problemsiteKey = "{{ problemsite_key }}"; </script>

{% endblock %}
13 changes: 6 additions & 7 deletions oioioi/problems/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ def can_add_problems(request):
return request.user.has_perm('problems.problems_db_admin') \
or is_contest_basicadmin(request)


def can_upload_problems(request):
if not request.user.is_authenticated:
return False
if is_contest_admin(request):
return True
return can_add_to_problemset(request)


def can_admin_problem(request, problem):
if request.user.has_perm('problems.problems_db_admin'):
return True
Expand Down Expand Up @@ -189,16 +191,11 @@ def generate_add_to_contest_metadata(request):
return show_add_button, administered_recent_contests


def generate_model_solutions_context(request, problem_instance_id):
def generate_model_solutions_context(request, problem_instance):
""" Generates context dictionary for model solutions view
for "problem_instance_id"'s package.
for "problem_instance"'s package.
"""

problem_instance = \
get_object_or_404(ProblemInstance, id=problem_instance_id)
if not can_admin_problem_instance(request, problem_instance):
raise PermissionDenied

filter_kwargs = {
'test__isnull': False,
'submission_report__submission__problem_instance':
Expand Down Expand Up @@ -292,6 +289,7 @@ def generate_model_solutions_context(request, problem_instance_id):
'total_row': total_row
}


def get_prefetched_value(problem, category):
"""Returns OriginInfoValue for the given Problem and OriginInfoCategory.
Expand Down Expand Up @@ -338,6 +336,7 @@ def show_proposal_form(problem, user):

return True


def filter_my_all_visible_submissions(request, queryset):
""" Filters all solusion visible for the currently logged in user
from the given queryset. Returns the result as a list (Django
Expand Down
9 changes: 8 additions & 1 deletion oioioi/problems/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
from oioioi.problems.utils import (can_add_to_problemset,
can_admin_instance_of_problem,
can_admin_problem,
can_admin_problem_instance,
generate_add_to_contest_metadata,
generate_model_solutions_context,
query_statement, get_prefetched_value, show_proposal_form)
Expand Down Expand Up @@ -432,6 +433,7 @@ def problemset_my_problems_view(request):
problems = problems_pool.filter(author=request.user, problemsite__isnull=False)
return problemset_generate_view(request, page_title, problems, "my")


def problemset_shared_with_me_view(request):
from oioioi.problemsharing.models import Friendship
page_title = _("Shared with me")
Expand Down Expand Up @@ -461,6 +463,7 @@ def problem_site_view(request, site_key):
problemset_tabs = generate_problemset_tabs(request)
problemset_tabs.append({'name': _('Problem view'), 'url': reverse('problem_site', kwargs={'site_key': site_key})})
context = {'problem': problem,
'problemsite_key': site_key,
'package': package if package and package.package_file
else None,
'extra_actions': extra_actions,
Expand Down Expand Up @@ -751,7 +754,11 @@ def task_archive_tag_view(request, origin_tag):


def model_solutions_view(request, problem_instance_id):
context = generate_model_solutions_context(request, problem_instance_id)
problem_instance = \
get_object_or_404(ProblemInstance, id=problem_instance_id)
if not can_admin_problem_instance(request, problem_instance):
raise PermissionDenied
context = generate_model_solutions_context(request, problem_instance)

return TemplateResponse(request, 'programs/admin/model_solutions.html',
context)
Expand Down
24 changes: 9 additions & 15 deletions oioioi/programs/controllers.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import hashlib
import itertools
import logging
import os.path
from operator import attrgetter # pylint: disable=E0611

from django import forms
from django.conf import settings
from django.core.exceptions import (ValidationError, SuspiciousOperation)
from django.core.files.base import ContentFile
from django.template.loader import render_to_string
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _

Expand All @@ -35,7 +35,8 @@
is_model_submission,
filter_model_submissions,
form_field_id_for_langs,
get_problem_link_or_name)
get_problem_link_or_name,
get_extension)
from oioioi.programs.widgets import CancellableFileInput

def get_report_display_type(request, test_report):
Expand Down Expand Up @@ -76,8 +77,7 @@ class ProgrammingProblemController(ProblemController):

def get_compiler_for_submission(self, submission):
problem_instance = submission.problem_instance
extension = problem_instance.controller \
.get_extension(submission.source_file, problem_instance)
extension = get_extension(submission.source_file.name)
language = get_language_by_extension(problem_instance, extension)
assert language

Expand Down Expand Up @@ -114,8 +114,7 @@ def generate_initial_evaluation_environ(self, environ, submission,
submission = submission.programsubmission
environ['source_file'] = \
django_to_filetracker_path(submission.source_file)
environ['language'] = problem_instance.controller \
.get_extension(submission.source_file, problem_instance)
environ['language'] = get_extension(submission.source_file.name)
environ['compilation_result_size_limit'] = \
problem_instance.controller \
.get_compilation_result_size_limit(submission)
Expand Down Expand Up @@ -289,9 +288,6 @@ def generate_recipe(self, kinds):
def get_compilation_result_size_limit(self, submission):
return 10 * 1024 * 1024

def get_extension(self, source_file, problem_instance):
return os.path.splitext(source_file.name)[1][1:]

def fill_evaluation_environ(self, environ, submission, **kwargs):
self.generate_base_environ(environ, submission, **kwargs)

Expand Down Expand Up @@ -388,7 +384,7 @@ def validate_submission_form(self, request, problem_instance, form,
cleaned_data[langs_field_name] = None

if not cleaned_data[langs_field_name] and is_file_chosen:
ext = os.path.splitext(cleaned_data['file'].name)[1].strip('.')
ext = get_extension(cleaned_data['file'].name)
cleaned_data[langs_field_name] = \
get_language_by_extension(problem_instance, ext)

Expand Down Expand Up @@ -504,7 +500,7 @@ def validate_code_length(code):
raise ValidationError(_("Code length limit exceeded."))

def validate_language(file):
ext = controller.get_extension(file, problem_instance)
ext = get_extension(file.name)
if ext not in get_allowed_languages_extensions(problem_instance):
raise ValidationError(_(
"Unknown or not supported file extension."))
Expand Down Expand Up @@ -535,6 +531,8 @@ def parse_problem(problem):
) % (', '.join(get_allowed_languages_extensions(
problem_instance))))
)
form.fields['file'].widget.attrs.update(
{'data-languagehintsurl': reverse('get_language_hints')})
form.fields['code'] = forms.CharField(required=False,
label=_("Code"),
validators=[validate_code_length],
Expand Down Expand Up @@ -776,10 +774,6 @@ def get_compilation_result_size_limit(self, submission):
return submission.problem_instance.problem.controller \
.get_compilation_result_size_limit(submission)

def get_extension(self, source_file, problem_instance):
return problem_instance.problem.controller \
.get_extension(source_file, problem_instance)

def fill_evaluation_environ(self, environ, submission):
problem = submission.problem_instance.problem
problem.controller.fill_evaluation_environ(environ, submission)
Expand Down
26 changes: 19 additions & 7 deletions oioioi/programs/static/common/submit_view.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
function getAllPiIds() {
const piField = $('#id_problem_instance_id option');
let piIds = piField.map(function() { return $(this).val() }).get();
const piFields = $('#id_problem_instance_id option');
let piIds = piFields.map(function() { return $(this).val(); }).get();
piIds = piIds.filter(i => i !== "");
return piIds;
}
Expand All @@ -13,19 +13,31 @@ $(function() {
const piIds = getAllPiIds();
const fileField = $('#id_file');
const codeField = $('#id_code');
const progLangs = piIds.map(x => '#id_prog_lang_' + x).join()
const languageFields = $(progLangs);
const progLangs = new Map(Array.from(piIds, x => [x, '#id_prog_lang_' + x]));
const languageFields = $(Array.from(progLangs.values()).join());

function userInput() {
if (fileField.val())
const fileFieldVal = fileField.val();

if (fileFieldVal)
codeField.prop('disabled', true);
else
codeField.prop('disabled', false)
codeField.prop('disabled', false);

if (fileField.val() || !codeField.val())
if (fileFieldVal || !codeField.val())
languageFields.prop('disabled', true);
else
languageFields.prop('disabled', false);

if (fileFieldVal) {
const hints_url = fileField.data("languagehintsurl");
const dict = {pi_ids: piIds, filename: fileFieldVal, problemsite_key: window.problemsiteKey};
$.getJSON(hints_url, dict, function(data) {
progLangs.forEach(function(progLang, piId) {
$(progLang).val(data[piId]);
});
});
}
}

if(fileField.length && codeField.length && languageFields.length) {
Expand Down
2 changes: 2 additions & 0 deletions oioioi/programs/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@
views.source_diff_view, name='source_diff'),
url(r'^get_compiler_hints/$', views.get_compiler_hints_view,
name='get_compiler_hints'),
url(r'^get_language_hints/$', views.get_language_hints_view,
name='get_language_hints'),
]
9 changes: 9 additions & 0 deletions oioioi/programs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404
from django.urls import reverse
import os.path

from oioioi.base.utils import make_html_link
from oioioi.contests.models import Submission
Expand Down Expand Up @@ -156,16 +157,20 @@ def is_problem_with_library(problem):
except LibraryProblemData.DoesNotExist:
return False


def is_model_submission(submission):
return ModelProgramSubmission.objects.filter(pk=submission.id).exists()


def filter_model_submissions(queryset):
model_ids = ModelProgramSubmission.objects.values_list('id', flat=True)
return queryset.exclude(pk__in=model_ids)


def form_field_id_for_langs(problem_instance):
return 'prog_lang_' + str(problem_instance.id)


def get_problem_link_or_name(request, submission):
pi = submission.problem_instance
if pi.contest is None:
Expand All @@ -179,3 +184,7 @@ def get_problem_link_or_name(request, submission):
return make_html_link(href, pi)
else:
return pi


def get_extension(file_name):
return os.path.splitext(file_name)[1][1:]
Loading

0 comments on commit e4dc9b9

Please sign in to comment.