Skip to content

Commit

Permalink
SIO-1990 Move allowed programming languages logic from configuration …
Browse files Browse the repository at this point in the history
…to contest and problem controllers.

Change-Id: I904aafbfe10267b472d46489051d2d6761d1e963
  • Loading branch information
mrowqa committed May 23, 2017
1 parent fd8597c commit a3403ab
Show file tree
Hide file tree
Showing 15 changed files with 82 additions and 73 deletions.
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,8 @@ List of changes since the *CONFIG_VERSION* numbering was introduced:

#. * Added `PUBLIC_ROOT_URL` to `deployment/settings.py`

#. * Removed *SUBMITTABLE_EXTENSIONS* from *deployment/settings.py*.

Usage
-----

Expand Down
5 changes: 5 additions & 0 deletions oioioi/contests/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,11 @@ def get_safe_exec_mode(self):
"""
return 'vcpu'

def get_allowed_languages(self):
"""Determines which languages are allowed for submissions.
"""
return ['C', 'C++', 'Pascal']


class PastRoundsHiddenContestControllerMixin(object):
"""ContestController mixin that hides past rounds
Expand Down
8 changes: 8 additions & 0 deletions oioioi/contests/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ def clean(self, check_submission_limit=True, check_round_times=True):
raise ValidationError(str(getattr(decision, 'exc',
_("Permission denied"))))

if cleaned_data['prog_lang'] and \
cleaned_data['prog_lang'] not in \
pi.controller.get_allowed_languages():
self._errors['prog_lang'] = \
self.error_class([_("Disallowed language")])
del cleaned_data['prog_lang']
return cleaned_data

return pi.controller.validate_submission_form(self.request, pi, self,
cleaned_data)

Expand Down
10 changes: 6 additions & 4 deletions oioioi/default_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import oioioi
from oioioi.contests.current_contest import ContestMode

INSTALLATION_CONFIG_VERSION = 14
INSTALLATION_CONFIG_VERSION = 15

DEBUG = False
TEMPLATE_DEBUG = DEBUG
Expand Down Expand Up @@ -262,7 +262,11 @@
'oioioi.sinolpack.package.SinolPackageBackend',
)

SUBMITTABLE_EXTENSIONS = {'C': ['c'], 'C++': ['cpp', 'cc'], 'Pascal': ['pas']}
# This setting is used for associating allowed programming languages with file
# extensions. Allowed languages are determined by contest and problem
# controllers.
SUBMITTABLE_EXTENSIONS = {'C': ['c'], 'C++': ['cpp', 'cc'], 'Pascal': ['pas'],
'Java': ['java']}
USE_UNSAFE_EXEC = False
USE_LOCAL_COMPILERS = False
RUN_LOCAL_WORKERS = False
Expand Down Expand Up @@ -409,8 +413,6 @@
ZEUS_INSTANCES = {
}

ZEUS_ALLOWED_LANGUAGES = ['C', 'C++']

# URL prefix (protocol, hostname and port)
# hit by the Zeus callback after a submission is judged
ZEUS_PUSH_GRADE_CALLBACK_URL = 'https://sio2.dasie.mimuw.edu.pl'
Expand Down
3 changes: 0 additions & 3 deletions oioioi/deployment/settings.py.template
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,6 @@ USE_SINOLPACK_MAKEFILES = False
MAX_TEST_TIME_LIMIT_PER_PROBLEM = 1000 * 60 * 60 * 30
MAX_MEMORY_LIMIT_FOR_TEST = 256 * 1024

# Uncomment and edit this line to limit availability of programming languages.
#SUBMITTABLE_EXTENSIONS = {'C': ['c'], 'C++': ['cpp', 'cc'], 'Pascal': ['pas']}

# Controls if uwsgi in default configuration shall use gevent loop.
# To use it, you have to install gevent - please consult
# https://github.com/surfly/gevent
Expand Down
8 changes: 8 additions & 0 deletions oioioi/mailsubmit/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ def clean(self):
raise ValidationError(getattr(decision, 'exc',
_("Permission denied")))

if cleaned_data['prog_lang'] and \
cleaned_data['prog_lang'] not in \
pi.controller.get_allowed_languages():
self._errors['prog_lang'] = \
self.error_class([_("Disallowed language")])
del cleaned_data['prog_lang']
return cleaned_data

return ccontroller.validate_submission_form(self.request, pi, self,
cleaned_data)

Expand Down
3 changes: 3 additions & 0 deletions oioioi/pa/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ def fill_upload_environ(self, request, form, env):
def get_safe_exec_mode(self):
return 'cpu'

def get_allowed_languages(self):
return ['C', 'C++', 'Pascal', 'Java']


A_PLUS_B_RANKING_KEY = 'ab'
B_RANKING_KEY = 'b'
Expand Down
5 changes: 5 additions & 0 deletions oioioi/problems/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ def get_safe_exec_mode(self):
"""
return 'vcpu'

def get_allowed_languages(self):
"""Determines which languages are allowed for submissions.
"""
return ['C', 'C++', 'Pascal']

def judge(self, submission, extra_args=None, is_rejudge=False):
environ = evalmgr.create_environ()
environ['extra_args'] = extra_args or {}
Expand Down
70 changes: 14 additions & 56 deletions oioioi/programs/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
from oioioi.programs.models import ProgramSubmission, OutputChecker, \
CompilationReport, TestReport, GroupReport, ModelProgramSubmission, \
Submission, UserOutGenStatus
from oioioi.programs.problem_instance_utils import \
get_allowed_languages_dict, get_allowed_languages_extensions, \
get_language_by_extension
from oioioi.programs.utils import has_report_actions_config
from oioioi.filetracker.utils import django_to_filetracker_path
from oioioi.evalmgr import recipe_placeholder, add_before_placeholder, \
Expand Down Expand Up @@ -295,31 +298,9 @@ def update_submission_score(self, submission):

submission.save()

def filter_allowed_languages_dict(self, languages, problem_instance):
return languages

def get_submission_size_limit(self, problem_instance):
return 102400 # in bytes

def get_allowed_languages_dict(self, problem_instance):
return getattr(settings, 'SUBMITTABLE_EXTENSIONS', {})

def get_allowed_languages(self, problem_instance):
return problem_instance.controller \
.get_allowed_languages_dict(problem_instance).keys()

def get_allowed_extensions(self, problem_instance):
lang_exts = problem_instance.controller \
.get_allowed_languages_dict(problem_instance).values()
return [ext for lang in lang_exts for ext in lang]

def parse_language_by_extension(self, ext, problem_instance):
for lang, extension_list in problem_instance.controller \
.get_allowed_languages_dict(problem_instance).items():
if ext in extension_list:
return lang
return None

def check_repeated_submission(self, request, problem_instance, form):
return not can_admin_problem(request, problem_instance.problem) \
and form.kind == 'NORMAL' and \
Expand All @@ -344,21 +325,19 @@ def validate_submission_form(self, request, problem_instance, form,

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

if not cleaned_data['prog_lang']:
if is_code_pasted:
raise ValidationError(_("You have to choose programming "
"language."))
raise ValidationError(
_("You have to choose programming language."))
else:
raise ValidationError(_("Unrecognized file extension."))

problem_instance = cleaned_data['problem_instance']
controller = problem_instance.controller
langs = controller.filter_allowed_languages_dict(
controller.get_allowed_languages_dict(problem_instance),
problem_instance)
langs = get_allowed_languages_dict(problem_instance)
if cleaned_data['prog_lang'] not in langs.keys():
raise ValidationError(_("This language is not allowed for selected"
" problem."))
Expand Down Expand Up @@ -409,7 +388,7 @@ def create_submission(self, request, problem_instance, form_data,

file = form_data['file']
if file is None:
lang_exts = getattr(settings, 'SUBMITTABLE_EXTENSIONS', {})
lang_exts = get_allowed_languages_dict(problem_instance)
extension = lang_exts[form_data['prog_lang']][0]
file = ContentFile(form_data['code'], '__pasted_code.' + extension)

Expand All @@ -433,7 +412,7 @@ def validate_code_length(code):

def validate_language(file):
ext = controller._get_language(file, problem_instance)
if ext not in controller.get_allowed_extensions(problem_instance):
if ext not in get_allowed_languages_extensions(problem_instance):
raise ValidationError(_(
"Unknown or not supported file extension."))

Expand All @@ -459,7 +438,7 @@ def parse_problem(problem):
" You can paste the code below instead of"
" choosing file."
" <strong>Try drag-and-drop too!</strong>"
) % (', '.join(controller.get_allowed_extensions(
) % (', '.join(get_allowed_languages_extensions(
problem_instance))))
)
form.fields['code'] = forms.CharField(required=False,
Expand All @@ -470,8 +449,8 @@ def parse_problem(problem):
)

choices = [('', '')]
choices += [(lang, lang) for lang in controller.get_allowed_languages(
problem_instance)]
choices += [(lang, lang) for lang
in problem_instance.controller.get_allowed_languages()]
form.fields['prog_lang'] = forms.ChoiceField(required=False,
label=_("Programming language"),
choices=choices,
Expand All @@ -494,8 +473,7 @@ def parse_problem(problem):
parse_problem(problem)
if 'prog_lang' not in request.POST:
form.fields['prog_lang'].initial = \
controller.parse_language_by_extension(ext,
problem_instance)
get_language_by_extension(problem_instance, ext)

if request.contest and is_contest_admin(request):
form.fields['user'] = UserSelectionField(
Expand Down Expand Up @@ -637,10 +615,6 @@ def _map_report_to_submission_status(self, status, problem_instance,
return problem_instance.problem.controller \
._map_report_to_submission_status(status, problem_instance, kind)

def filter_allowed_languages_dict(self, languages, problem_instance):
return problem_instance.problem.controller \
.filter_allowed_languages_dict(languages, problem_instance)

def get_compilation_result_size_limit(self, submission):
return submission.problem_instance.problem.controller \
.get_compilation_result_size_limit(submission)
Expand Down Expand Up @@ -674,22 +648,6 @@ def get_submission_size_limit(self, problem_instance):
return problem_instance.problem.controller \
.get_submission_size_limit(problem_instance)

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

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

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

def parse_language_by_extension(self, ext, problem_instance):
return problem_instance.problem.controller \
.parse_language_by_extension(ext, problem_instance)

def adjust_submission_form(self, request, form, problem_instance):
super(ProgrammingContestController, self) \
.adjust_submission_form(request, form, problem_instance)
Expand Down
4 changes: 2 additions & 2 deletions oioioi/programs/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
submission_statuses, submission_report_kinds, ProblemInstance, \
submission_kinds
from oioioi.contests.fields import ScoreField
from oioioi.programs.problem_instance_utils import get_language_by_extension

import os.path

Expand Down Expand Up @@ -189,8 +190,7 @@ def extension(self):
return os.path.splitext(self.source_file.name)[1][1:]

def get_language_display(self):
return self.problem.controller.parse_language_by_extension(
self.extension, self.problem_instance)
return get_language_by_extension(self.problem_instance, self.extension)


class ModelProgramSubmission(ProgramSubmission):
Expand Down
20 changes: 20 additions & 0 deletions oioioi/programs/problem_instance_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from django.conf import settings


def get_allowed_languages_dict(problem_instance):
lang_dict = getattr(settings, 'SUBMITTABLE_EXTENSIONS', {})
return {lang: lang_dict[lang] for lang
in problem_instance.controller.get_allowed_languages()}


def get_allowed_languages_extensions(problem_instance):
lang_exts = get_allowed_languages_dict(problem_instance).values()
return [ext for lang in lang_exts for ext in lang]


def get_language_by_extension(problem_instance, ext):
for lang, extension_list in get_allowed_languages_dict(
problem_instance).items():
if ext in extension_list:
return lang
return None
3 changes: 1 addition & 2 deletions oioioi/programs/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,12 +479,11 @@ def test_pasting_unicode_code(self):
user='test_user')
self._assertSubmitted(contest, response)

@override_settings(SUBMITTABLE_EXTENSIONS={'C': ['c']})
def test_limiting_extensions(self):
contest = Contest.objects.get()
problem_instance = ProblemInstance.objects.get(pk=1)
self._assertUnsupportedExtension(contest, problem_instance,
'xxx', 'cpp')
'xxx', 'inv4l1d_3xt')
response = self.submit_file(contest, problem_instance, file_name='a.c')
self._assertSubmitted(contest, response)

Expand Down
5 changes: 3 additions & 2 deletions oioioi/submitservice/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
from oioioi.base.permissions import enforce_condition, not_anonymous
from oioioi.contests.utils import contest_exists, can_enter_contest, \
visible_problem_instances
from oioioi.programs.problem_instance_utils import \
get_allowed_languages_extensions


class SubmitServiceException(Exception):
Expand Down Expand Up @@ -59,8 +61,7 @@ def submit_view(request):
raise SubmitServiceException('NO_SUCH_PROBLEM', ', '.join([
x.short_name for x in visible_problem_instances(request)]))

lang_exts = sum(
getattr(settings, 'SUBMITTABLE_EXTENSIONS', {}).values(), [])
lang_exts = get_allowed_languages_extensions(pi)
if file_extension[1:] not in lang_exts:
raise ValueError('UNSUPPORTED_EXTENSION')

Expand Down
4 changes: 3 additions & 1 deletion oioioi/testrun/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from oioioi.evalmgr import extend_after_placeholder
from oioioi.programs.models import CompilationReport
from oioioi.base.utils.archive import Archive, ArchiveException
from oioioi.programs.problem_instance_utils import \
get_allowed_languages_extensions

class TestRunProblemControllerMixin(object):
def fill_evaluation_environ(self, environ, submission, **kwargs):
Expand Down Expand Up @@ -134,7 +136,7 @@ def validate_zip(file):
" extension. The following are recognized: %s, but allowed"
" languages may vary. You can paste the code below instead of"
" choosing file.") % (', '.join(
self.get_allowed_extensions(problem_instance)))
get_allowed_languages_extensions(problem_instance)))

if 'kind' in form.fields:
form.fields['kind'].choices = [('TESTRUN', _("Test run")), ]
Expand Down
5 changes: 2 additions & 3 deletions oioioi/zeus/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,5 @@ def fill_evaluation_environ(self, environ, submission, **kwargs):
environ.setdefault('score_aggregator',
'oioioi.programs.utils.sum_score_aggregator')

def filter_allowed_languages_dict(self, languages, problem_instance):
return {k: languages[k] for k in languages
if k in settings.ZEUS_ALLOWED_LANGUAGES}
def get_allowed_languages(self):
return ['C', 'C++']

0 comments on commit a3403ab

Please sign in to comment.