diff --git a/oioioi/base/templates/admin/edit_inline/tabular.html b/oioioi/base/templates/admin/edit_inline/tabular.html index 2a027bada..b7ecca82f 100644 --- a/oioioi/base/templates/admin/edit_inline/tabular.html +++ b/oioioi/base/templates/admin/edit_inline/tabular.html @@ -8,12 +8,28 @@
{% if inline_admin_formset.formset.max_num == 1 %} -
{{ inline_admin_formset.opts.verbose_name|capfirst }}
+
+ {{ inline_admin_formset.opts.verbose_name|capfirst }} + {% if inline_admin_formset.formset.disable_config %} + + {% endif %} +
+ {% else %} -
{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}
+
+ {{ inline_admin_formset.opts.verbose_name_plural|capfirst }} + {% if inline_admin_formset.formset.disable_config %} + + {% endif %} +
{% endif %}
-
+
{{ inline_admin_formset.formset.non_form_errors }} diff --git a/oioioi/contests/admin.py b/oioioi/contests/admin.py index f39f094c4..e2749667a 100644 --- a/oioioi/contests/admin.py +++ b/oioioi/contests/admin.py @@ -206,6 +206,13 @@ class ContestAdmin(admin.ModelAdmin): list_display_links = ['id', 'name'] ordering = ['-creation_date'] + """ todo: add a js to change + class Media: + js = [ + 'js/contest_admin.js', #todo! + ] + """ + def has_add_permission(self, request): return request.user.is_superuser diff --git a/oioioi/contests/controllers.py b/oioioi/contests/controllers.py index 48c1bc6b3..64f518c96 100644 --- a/oioioi/contests/controllers.py +++ b/oioioi/contests/controllers.py @@ -272,7 +272,6 @@ def filter_users_with_accessible_personal_data(self, queryset): """ raise NotImplementedError - class PublicContestRegistrationController(RegistrationController): description = _("Public contest") @@ -974,6 +973,9 @@ def _is_partial_score(self, test_report): def show_default_fields(self, problem_instance): return problem_instance.problem.controller.show_default_fields(problem_instance) + def registration_is_enabeld(self): + return False + class PastRoundsHiddenContestControllerMixin(object): """ContestController mixin that hides past rounds diff --git a/oioioi/contests/static/contests/registration_config.js b/oioioi/contests/static/contests/registration_config.js new file mode 100644 index 000000000..c7ef153ff --- /dev/null +++ b/oioioi/contests/static/contests/registration_config.js @@ -0,0 +1,7 @@ +document.addEventListener('DOMContentLoaded', function() { + const contestTypeField = document.querySelector('#id_controller_name'); + const registrationAlert = document.querySelector('#registration_alert'); + const registrationInlineBody = document.querySelector('#registration_inline_body'); + //... + +}); \ No newline at end of file diff --git a/oioioi/contests/templates/admin/contests/contest/registrationavailabilityconfig_tabular.html b/oioioi/contests/templates/admin/contests/contest/registrationavailabilityconfig_tabular.html new file mode 100644 index 000000000..3f278c558 --- /dev/null +++ b/oioioi/contests/templates/admin/contests/contest/registrationavailabilityconfig_tabular.html @@ -0,0 +1,136 @@ +{% load i18n admin_urls static admin_modify %} + +
+ +
+ + + + {% for field in inline_admin_formset.fields %} + {% if not field.widget.is_hidden %} + + {% endif %} + {% endfor %} + {% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission %} + + {% endif %} + + + + + {% for inline_admin_form in inline_admin_formset %} + {% if inline_admin_form.form.non_field_errors %} + + + + {% endif %} + + + + + + {% for fieldset in inline_admin_form %} + {% for line in fieldset %} + {% for field in line %} + {% if field.is_readonly or not field.field.is_hidden %} + + {% if field.is_readonly %} + {{ field.contents }} + {% else %} + {{ field.field.errors.as_ul }} + {{ field.field }} + {% endif %} + + {% endif %} + {% endfor %} + {% endfor %} + {% endfor %} + + {% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission %} + + {% endif %} + + {% endfor %} + +
+ {{ field.label|capfirst }} + {% if field.help_text %} + ({{ field.help_text|striptags }}) + {% endif %} + {% translate "Delete?" %}
+ {{ inline_admin_form.form.non_field_errors }} +
+ {% if inline_admin_form.original or inline_admin_form.show_url %} + {% if inline_admin_form.original %} + {{ inline_admin_form.original }} + {% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} + + {% if inline_admin_formset.has_change_permission %} + {% translate "Change" %} + {% else %} + {% translate "View" %} + {% endif %} + + {% endif %} + {% endif %} + {% if inline_admin_form.show_url %} + {% translate "View on site" %} + {% endif %} + {% endif %} + {% if inline_admin_form.needs_explicit_pk_field %} + {{ inline_admin_form.pk_field.field }} + {% endif %} + {% if inline_admin_form.fk_field %} + {{ inline_admin_form.fk_field.field }} + {% endif %} + {% spaceless %} + {% for fieldset in inline_admin_form %} + {% for line in fieldset %} + {% for field in line %} + {% if not field.is_readonly and field.field.is_hidden %} + {{ field.field }} + {% endif %} + {% endfor %} + {% endfor %} + {% endfor %} + {% endspaceless %} + + {% if inline_admin_form.original %} + {{ inline_admin_form.deletion_field.field }} + {% endif %} +
+
+
+
+ + + diff --git a/oioioi/contests/templates/contests/registration_closed.html b/oioioi/contests/templates/contests/registration_closed.html new file mode 100644 index 000000000..15d2343e4 --- /dev/null +++ b/oioioi/contests/templates/contests/registration_closed.html @@ -0,0 +1,9 @@ +{% extends "base-with-menu.html" %} +{% load i18n %} + +{% block title %}{% trans "Registration Form" %}{% endblock %} + +{% block main-content %} +

{% trans "Registration Closed" %}

+

{% trans "Contact organizers if this is a bug" %}

+{% endblock %} \ No newline at end of file diff --git a/oioioi/contests/utils.py b/oioioi/contests/utils.py index 05afdffd9..b3b0374fc 100755 --- a/oioioi/contests/utils.py +++ b/oioioi/contests/utils.py @@ -27,15 +27,16 @@ from oioioi.programs.models import ProgramsConfig from oioioi.participants.models import TermsAcceptedPhrase + class RoundTimes(object): def __init__( - self, - start, - end, - contest, - show_results=None, - show_public_results=None, - extra_time=0, + self, + start, + end, + contest, + show_results=None, + show_public_results=None, + extra_time=0, ): self.start = start self.end = end @@ -75,7 +76,7 @@ def results_visible(self, current_datetime): ) return current_datetime >= self.show_results - + def results_date(self): return self.show_results @@ -96,7 +97,7 @@ def public_results_visible(self, current_datetime): return False return current_datetime >= self.show_public_results - + def public_results_date(self): if not self.contest.controller.separate_public_results(): return self.results_date() @@ -263,25 +264,27 @@ def visible_rounds(request, no_admin=False): request, r, no_admin=no_admin, )] + @make_request_condition @request_cached def are_rules_visible(request): return ( - hasattr(request, 'contest') - and request.contest.show_contest_rules + hasattr(request, 'contest') + and request.contest.show_contest_rules ) + @request_cached def get_number_of_rounds(request): """Returns the number of rounds in the current contest. - """ + """ return Round.objects.filter(contest=request.contest).count() def get_contest_dates(request): """Returns the end_date of the latest round and the start_date of the earliest round. - """ + """ rtimes = rounds_times(request, request.contest) ends = [ @@ -293,14 +296,14 @@ def get_contest_dates(request): for rt in rtimes.values() ] - if starts and None not in starts: - min_start = min(starts) - else: + if starts and None not in starts: + min_start = min(starts) + else: min_start = None - if ends and None not in ends: + if ends and None not in ends: max_end = max(ends) - else: + else: max_end = None return min_start, max_end @@ -309,7 +312,7 @@ def get_contest_dates(request): def get_scoring_desription(request): """Returns the scoring description of the current contest. """ - if (hasattr(request.contest.controller, 'scoring_description') and + if (hasattr(request.contest.controller, 'scoring_description') and request.contest.controller.scoring_description is not None): return request.contest.controller.scoring_description else: @@ -330,7 +333,7 @@ def get_problems_sumbmission_limit(request): if queryset is None or not queryset.exists(): return [Contest.objects.get(id=request.contest.id).default_submissions_limit] - + limits = set() for p in queryset: limits.add(controller.get_submissions_limit(request, p, noadmin=True)) @@ -374,9 +377,9 @@ def get_results_visibility(request): ranking = _('after %(date)s') % {"date": public_results_date.strftime("%Y-%m-%d %H:%M:%S")} dates.append({ - 'name' : r.name, - 'results' : results, - 'ranking' : ranking + 'name': r.name, + 'results': results, + 'ranking': ranking }) return dates @@ -463,6 +466,18 @@ def can_admin_contest(user, contest): return user.has_perm('contests.contest_basicadmin', contest) +@make_request_condition +@request_cached +def contest_has_registration(request): + """Check if the contests has registration config""" + return ( + hasattr(request, 'contest') and ( + not (request.contest is not None) + or (request.contest.controller.registration_is_enabeld()) + ) + ) + + @make_request_condition @request_cached def is_contest_basicadmin(request): @@ -615,9 +630,9 @@ def get_submission_message(request): @request_cached def is_contest_archived(request): return ( - hasattr(request, 'contest') - and (request.contest is not None) - and request.contest.is_archived + hasattr(request, 'contest') + and (request.contest is not None) + and request.contest.is_archived ) @@ -650,6 +665,7 @@ def has_view_permission(self, request, obj=None): return ArchivedInlineWrapper + # The whole section below requires refactoring, # may include refactoring the models of `Contest`, `ProgramsConfig` and `TermsAcceptedPhrase` @@ -668,8 +684,8 @@ def create_programs_config(request, adding): execution_mode = extract_programs_config_execution_mode(request) if ( - execution_mode and - execution_mode != 'AUTO' + execution_mode and + execution_mode != 'AUTO' ): if adding and requested_contest_id: ProgramsConfig.objects.create(contest_id=requested_contest_id, execution_mode=execution_mode) @@ -712,6 +728,7 @@ def create_contest_attributes(request, adding): create_programs_config(request, adding) create_terms_accepted_phrase(request, adding) + def get_problem_statements(request, controller, problem_instances): # Problem statements in order # 1) problem instance @@ -736,13 +753,13 @@ def get_problem_statements(request, controller, problem_instances): ( r for r in UserResultForProblem.objects.filter( - user__id=request.user.id, problem_instance=pi - ) + user__id=request.user.id, problem_instance=pi + ) if r - and r.submission_report - and controller.can_see_submission_score( - request, r.submission_report.submission - ) + and r.submission_report + and controller.can_see_submission_score( + request, r.submission_report.submission + ) ), None, ), diff --git a/oioioi/deployment/settings.py.template b/oioioi/deployment/settings.py.template index 52d1c0c2a..884906819 100755 --- a/oioioi/deployment/settings.py.template +++ b/oioioi/deployment/settings.py.template @@ -33,7 +33,7 @@ TEMPLATES[0]['APP_DIRS'] = False # PUBLIC_ROOT_URL = 'http://enter-your-domain-name-here.com/' # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts -ALLOWED_HOSTS = ['oioioi', '127.0.0.1', 'localhost', 'web'] +ALLOWED_HOSTS = ['oioioi', '127.0.0.1', 'localhost', 'web', '0.0.0.0'] # The server to be run. Options are: # 'django' - django's http server diff --git a/oioioi/mp/controllers.py b/oioioi/mp/controllers.py index b720081c1..0e77817c5 100644 --- a/oioioi/mp/controllers.py +++ b/oioioi/mp/controllers.py @@ -58,6 +58,8 @@ def registration_view(self, request): registration_status = self.get_registration_status(request) if registration_status == RegistrationStatus.NOT_OPEN_YET: return TemplateResponse(request, 'contests/registration_not_open_yet.html') + if registration_status == RegistrationStatus.CLOSED: + return TemplateResponse(request, 'contests/registration_closed.html') participant = self._get_participant_for_form(request) diff --git a/oioioi/oi/controllers.py b/oioioi/oi/controllers.py index 3ff4cd69f..f95924eeb 100644 --- a/oioioi/oi/controllers.py +++ b/oioioi/oi/controllers.py @@ -68,9 +68,12 @@ def can_unregister(self, request, participant): def registration_view(self, request): + #make one html - easy for latter registration_status = self.get_registration_status(request) if registration_status == RegistrationStatus.NOT_OPEN_YET: return TemplateResponse(request, 'contests/registration_not_open_yet.html') + if registration_status == RegistrationStatus.CLOSED: + return TemplateResponse(request, 'contests/registration_closed.html') participant = self._get_participant_for_form(request) @@ -155,7 +158,7 @@ class OIContestController(ProgrammingContestController): "The ranking is determined by the total score.\n" "Until the end of the contest, participants can only see scoring of their submissions on example test cases. " "Full scoring is available after the end of the contest." - ) + ) def fill_evaluation_environ(self, environ, submission): super(OIContestController, self).fill_evaluation_environ(environ, submission) @@ -220,6 +223,9 @@ def default_contesticons_urls(self): for i in range(1, 4) ] + def registration_is_enabeld(self): + return True + class OIOnsiteContestController(OIContestController): description = _("Polish Olympiad in Informatics - Onsite") @@ -230,7 +236,9 @@ class OIOnsiteContestController(OIContestController): "The ranking is determined by the total score.\n" "Until the end of the contest, participants can only see scoring of their submissions on example test cases. " "Full scoring is available after the end of the contest." - ) + ) + def registration_is_enabeld(self): + return False OIOnsiteContestController.mix_in(OnsiteContestControllerMixin) @@ -245,7 +253,7 @@ class OIFinalOnsiteContestController(OIOnsiteContestController): "The score for a group of test cases is the minimum score for any of the test cases\n." "The ranking is determined by the total score.\n" "Full scoring of the submissions can be revealed during the contest." - ) + ) def can_see_submission_score(self, request, submission): return True @@ -277,6 +285,9 @@ def update_user_result_for_problem(self, result): result.status = None result.submission_report = None + def registration_is_enabeld(self): + return False + class BOIOnsiteContestController(OIOnsiteContestController): description = _("Baltic Olympiad in Informatics") @@ -345,6 +356,9 @@ def fill_evaluation_environ(self, environ, submission): environ['test_scorer'] = 'oioioi.programs.utils.discrete_test_scorer' + def registration_is_enabeld(self): + return False + class BOIOnlineContestController(BOIOnsiteContestController): description = _("Baltic Olympiad in Informatics - online") @@ -355,3 +369,6 @@ def registration_controller(self): def is_onsite(self): return False + + def registration_is_enabeld(self): + return False diff --git a/oioioi/pa/controllers.py b/oioioi/pa/controllers.py index bceb0c803..7e5dff25c 100644 --- a/oioioi/pa/controllers.py +++ b/oioioi/pa/controllers.py @@ -74,6 +74,8 @@ def registration_view(self, request): registration_status = self.get_registration_status(request) if registration_status == RegistrationStatus.NOT_OPEN_YET: return TemplateResponse(request, 'contests/registration_not_open_yet.html') + if registration_status == RegistrationStatus.CLOSED: + return TemplateResponse(request, 'contests/registration_closed.html') participant = self._get_participant_for_form(request) diff --git a/oioioi/participants/utils.py b/oioioi/participants/utils.py index 08d1f0d1a..00a897d35 100644 --- a/oioioi/participants/utils.py +++ b/oioioi/participants/utils.py @@ -7,6 +7,7 @@ from oioioi.base.utils import request_cached from oioioi.participants.controllers import ParticipantsController from oioioi.participants.models import Participant +from oioioi.contests.models import RegistrationStatus def is_contest_with_participants(contest): @@ -54,7 +55,9 @@ def can_register(request): if get_participant(request) is not None: return False rcontroller = request.contest.controller.registration_controller() - return rcontroller.can_register(request) + # td: needs adding Registration_Status to all type of contest after this delete can_register + #return rcontroller.registration_status(request) == RegistrationStatus.OPEN + return rcontroller.can_register() @make_request_condition diff --git a/oioioi/problems/admin.py b/oioioi/problems/admin.py index 3023ef1f7..8d63f7a4f 100644 --- a/oioioi/problems/admin.py +++ b/oioioi/problems/admin.py @@ -23,7 +23,7 @@ ProblemStatementConfig, RankingVisibilityConfig, RegistrationAvailabilityConfig, ) -from oioioi.contests.utils import is_contest_admin, is_contest_basicadmin +from oioioi.contests.utils import is_contest_admin, is_contest_basicadmin, contest_has_registration from oioioi.problems.forms import ( AlgorithmTagThroughForm, DifficultyTagThroughForm, @@ -124,9 +124,19 @@ class RegistrationAvailabilityConfigInline(admin.TabularInline): form = RegistrationAvailabilityConfigForm category = _("Advanced") + def get_formset(self, request, obj=None, **kwargs): + formset = super().get_formset(request, obj, **kwargs) + if contest_has_registration(request): + formset.disable_config = False + else: + formset.disable_config = True + return formset + def get_readonly_fields(self, request, obj=None): + if not contest_has_registration(request): + return [field.name for field in self.model._meta.fields] + return super().get_readonly_fields(request, obj) def has_add_permission(self, request, obj=None): return is_contest_admin(request) - def has_change_permission(self, request, obj=None): return is_contest_admin(request)