Source code for oioioi.contestexcl.admin

from django.contrib import messages
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from oioioi.base import admin
from oioioi.contestexcl.forms import ExclusivenessConfigForm
from oioioi.contestexcl.models import ExclusivenessConfig
from oioioi.contests.admin import ContestAdmin


[docs]class ExclusivenessConfigInline(admin.TabularInline):
[docs] model = ExclusivenessConfig
[docs] extra = 0
[docs] form = ExclusivenessConfigForm
[docs] fields = ('enabled', 'start_date', 'end_date', 'disable')
[docs] category = _("Advanced")
[docs] def get_fields(self, request, obj=None): fields = super(ExclusivenessConfigInline, self).get_fields(request, obj) # Superadmins don't need to see the disable field if obj and request.user.is_superuser: return [f for f in fields if f != 'disable'] return fields
[docs] def get_readonly_fields(self, request, obj=None): # Contest admins should only be able to change the disable field if obj and not request.user.is_superuser: return [f for f in self.get_fields(request, obj) if f != 'disable'] return []
[docs] def has_add_permission(self, request, obj=None): return request.user.is_superuser
[docs] def has_change_permission(self, request, obj=None): # Most fields are protected by get_readonly_fields return ( request.user.is_superuser or not obj # This is confusing but for some reason is correct or obj.exclusivenessconfig_set.filter(enabled=True).exists() )
[docs] def has_delete_permission(self, request, obj=None): return request.user.is_superuser
[docs]class ContestAdminWithExclusivenessInlineMixin(object): """Adds :class:`~oioioi.contestexcl.models.ExclusivenessConfig` to an admin panel. """ def __init__(self, *args, **kwargs): super(ContestAdminWithExclusivenessInlineMixin, self).__init__(*args, **kwargs) self.inlines = tuple(self.inlines) + (ExclusivenessConfigInline,)
[docs] def _warn_on_contestexcl_overlap(self, request, ex_confs): for obj in ex_confs: qs = ExclusivenessConfig.objects.get_active_between( obj.start_date, obj.end_date ).select_related('contest') qs = [ex_conf for ex_conf in qs if ex_conf.contest != request.contest] if qs: contest_names = ', '.join([ex_conf.contest.name for ex_conf in qs]) msg = ( _( "The following contests' exclusion times" " overlap with the current one: %s. Watch out, because" " it may cause conflicts!" ) % contest_names ) messages.warning(request, msg)
[docs] def _warn_on_not_exclusive_rounds(self, request, ex_confs): ex_confs.sort(key=lambda ex_conf: ex_conf.start_date) # For each round check separately that it is entirely exclusive for round in request.contest.round_set.all(): round_not_excl_dates = [] round_excl_end_date = round.start_date for ex_conf in ex_confs: # Check if there's a gap before the next excl config if ex_conf.start_date > round_excl_end_date: round_not_excl_dates.append( (round_excl_end_date, ex_conf.start_date) ) round_excl_end_date = ex_conf.start_date # Update how much of the round is covered by the next config if ex_conf.end_date: round_excl_end_date = max(round_excl_end_date, ex_conf.end_date) else: break # Check if the round was covered entirely if round.end_date and round_excl_end_date >= round.end_date: break else: round_not_excl_dates.append((round_excl_end_date, round.end_date)) if round_not_excl_dates: # Default to first date if there are no future dates first_future_date = round_not_excl_dates[0] for date in round_not_excl_dates: if not date[1] or date[1] >= timezone.now(): first_future_date = date break if not first_future_date[1]: msg = _( "Exclusiveness configs usually cover entire rounds," " but currently round \"%s\" is not exclusive from" " %s! Please verify that your exclusiveness" " configs are correct." ) % (round.name, first_future_date[0]) else: msg = _( "Exclusiveness configs usually cover entire rounds," " but currently round \"%s\" is not exclusive from" " %s to %s! Please verify that your exclusiveness" " configs are correct." ) % (round.name, first_future_date[0], first_future_date[1]) messages.warning(request, msg)
[docs] def save_formset(self, request, form, formset, change): instances = formset.save() ex_confs = [] for obj in instances: if isinstance(obj, ExclusivenessConfig) and obj.enabled: ex_confs.append(obj) if ex_confs: self._warn_on_contestexcl_overlap(request, ex_confs) self._warn_on_not_exclusive_rounds(request, ex_confs)
ContestAdmin.mix_in(ContestAdminWithExclusivenessInlineMixin)