def test_dotted_name_field(self): field = DottedNameField('oioioi.base.tests.tests.TestDottedFieldClass') field.validate('oioioi.base.tests.tests.TestDottedFieldSubclass', None) with self.assertRaises(ValidationError): field.validate('something.stupid', None) with self.assertRaises(ValidationError): field.validate('oioioi.base.tests.tests.TestDottedFieldClass', None) self.assertEqual(list(field.get_choices(include_blank=False)), [('oioioi.base.tests.tests.TestDottedFieldSubclass', TestDottedFieldSubclass.description)])
class Contest(models.Model): id = models.CharField(max_length=32, primary_key=True, validators=[validate_slug], verbose_name=_("ID")) name = models.CharField(max_length=255, verbose_name=_("full name")) controller_name = DottedNameField( 'oioioi.contests.controllers.ContestController', verbose_name=_("type")) creation_date = models.DateTimeField(auto_now_add=True, editable=False, verbose_name=_("creation date")) class Meta: verbose_name = _("contest") verbose_name_plural = _("contests") get_latest_by = 'creation_date' permissions = ( ('contest_admin', _("Can administer the contest")), ('enter_contest', _("Can enter the contest")), ) @property def controller(self): if not self.controller_name: return None return get_object_by_dotted_name(self.controller_name)(self) def __unicode__(self): return self.name
class Contest(models.Model): id = models.CharField(max_length=32, primary_key=True, verbose_name=_("ID"), validators=[validate_db_string_id]) name = models.CharField(max_length=255, verbose_name=_("full name"), validators=[validate_whitespaces]) # The controller_name field is deliberately lacking default value. This # ensures that the contest type is explicitly set when persisting # an object to the database. controller_name = DottedNameField( 'oioioi.contests.controllers.ContestController', verbose_name=_("type")) creation_date = models.DateTimeField(auto_now_add=True, editable=False, db_index=True, verbose_name=_("creation date")) default_submissions_limit = models.IntegerField( verbose_name=_("default submissions limit"), default=settings.DEFAULT_SUBMISSIONS_LIMIT, blank=True) contact_email = models.EmailField( blank=True, verbose_name=_("contact email"), help_text=_("Address of contest owners. Sent emails related " "to this contest (i.e. submission confirmations) " "will have the return address set to this value. " "Defaults to system admins address if left empty.")) judging_priority = models.IntegerField( verbose_name=_("judging priority"), default=settings.DEFAULT_CONTEST_PRIORITY, help_text=_("Contest with higher judging priority is always judged " "before contest with lower judging priority.")) judging_weight = models.IntegerField( verbose_name=_("judging weight"), default=settings.DEFAULT_CONTEST_WEIGHT, validators=[MinValueValidator(1)], help_text=_("If some contests have the same judging priority, the " "judging resources are allocated proportionally to " "their weights.")) @property def controller(self): if not self.controller_name: return None return import_string(self.controller_name)(self) class Meta(object): verbose_name = _("contest") verbose_name_plural = _("contests") get_latest_by = 'creation_date' permissions = (('contest_admin', _("Can administer the contest")), ('contest_observer', _("Can observe the contest")), ('enter_contest', _("Can enter the contest")), ('personal_data', _("Has access to the private data of users"))) def __unicode__(self): return self.name
class Problem(models.Model): """Represents a problem in the problems database. Instances of :cls:`Problem` do not represent problems in contests, see :cls:`oioioi.contests.models.ProblemInstance` for those. """ name = models.CharField(max_length=255, verbose_name=_("full name")) short_name = models.CharField(max_length=30, validators=[validate_slug], verbose_name=_("short name")) controller_name = DottedNameField( 'oioioi.problems.controllers.ProblemController', verbose_name=_("type")) contest = models.ForeignKey('contests.Contest', null=True, blank=True, verbose_name=_("contest")) package_backend_name = \ DottedNameField('oioioi.problems.package.ProblemPackageBackend', null=True, blank=True, verbose_name=_("package type")) @property def controller(self): return get_object_by_dotted_name(self.controller_name)(self) @property def package_backend(self): return get_object_by_dotted_name(self.package_backend_name)() class Meta: verbose_name = _("problem") verbose_name_plural = _("problems") permissions = ( ('problems_db_admin', _("Can administer the problems database")), ('problem_admin', _("Can administer the problem")), ) def __unicode__(self): return '%(name)s (%(short_name)s)' % \ dict(short_name=self.short_name, name=self.name)
class Contest(models.Model): id = models.CharField(max_length=32, primary_key=True, verbose_name=_("ID"), validators=[validate_db_string_id]) name = models.CharField(max_length=255, verbose_name=_("full name"), validators=[validate_whitespaces]) controller_name = DottedNameField( 'oioioi.contests.controllers.ContestController', verbose_name=_("type")) creation_date = models.DateTimeField(auto_now_add=True, editable=False, db_index=True, verbose_name=_("creation date")) default_submissions_limit = models.IntegerField( verbose_name=_("default submissions limit"), default=settings.DEFAULT_SUBMISSIONS_LIMIT, blank=True) @property def controller(self): if not self.controller_name: return None return get_object_by_dotted_name(self.controller_name)(self) class Meta(object): verbose_name = _("contest") verbose_name_plural = _("contests") get_latest_by = 'creation_date' permissions = ( ('contest_admin', _("Can administer the contest")), ('contest_observer', _("Can observe the contest")), ('enter_contest', _("Can enter the contest")), ) def __unicode__(self): return self.name
class Problem(models.Model): """Represents a problem in the problems database. Instances of :class:`Problem` do not represent problems in contests, see :class:`oioioi.contests.models.ProblemInstance` for those. Each :class:`Problem` has associated main :class:`oioioi.contests.models.ProblemInstance`, called main_problem_instance: 1) It is not assigned to any contest. 2) It allows sending submissions aside from contests. 3) It is a base to create another instances. """ name = models.CharField(max_length=255, verbose_name=_("full name")) short_name = models.CharField(max_length=30, validators=[validate_slug], verbose_name=_("short name")) controller_name = DottedNameField( 'oioioi.problems.controllers.ProblemController', verbose_name=_("type")) contest = models.ForeignKey('contests.Contest', null=True, blank=True, verbose_name=_("contest")) author = models.ForeignKey(User, null=True, blank=True, verbose_name=_("author")) is_public = models.BooleanField(default=False, verbose_name=_("is public")) package_backend_name = \ DottedNameField('oioioi.problems.package.ProblemPackageBackend', null=True, blank=True, verbose_name=_("package type")) # main_problem_instance: # null=True, because there is a cyclic dependency # and during creation of any Problem, main_problem_instance # must be temporarily set to Null # (ProblemInstance has ForeignKey to Problem # and Problem has ForeignKey to ProblemInstance) main_problem_instance = models.ForeignKey( 'contests.ProblemInstance', null=True, blank=False, verbose_name=_("main problem instance"), related_name='main_problem_instance') @property def controller(self): return import_string(self.controller_name)(self) @property def package_backend(self): return import_string(self.package_backend_name)() @classmethod def create(cls, *args, **kwargs): """Creates a new :class:`Problem` object, with associated main_problem_instance. After the call, the :class:`Problem` and the :class:`ProblemInstance` objects will be saved in the database. """ problem = cls(*args, **kwargs) problem.save() import oioioi.contests.models pi = oioioi.contests.models.ProblemInstance(problem=problem) pi.save() pi.short_name += "_main" pi.save() problem.main_problem_instance = pi problem.save() return problem class Meta(object): verbose_name = _("problem") verbose_name_plural = _("problems") permissions = ( ('problems_db_admin', _("Can administer the problems database")), ('problem_admin', _("Can administer the problem")), ) def __unicode__(self): return '%(name)s (%(short_name)s)' % \ dict(short_name=self.short_name, name=self.name)
class Problem(models.Model): """Represents a problem in the problems database. Instances of :class:`Problem` do not represent problems in contests, see :class:`oioioi.contests.models.ProblemInstance` for those. Each :class:`Problem` has associated main :class:`oioioi.contests.models.ProblemInstance`, called main_problem_instance: 1) It is not assigned to any contest. 2) It allows sending submissions aside from contests. 3) It is a base to create another instances. """ name = models.CharField(max_length=255, verbose_name=_("full name")) short_name = models.CharField( max_length=30, validators=[validate_slug], verbose_name=_("short name") ) controller_name = DottedNameField( 'oioioi.problems.controllers.ProblemController', verbose_name=_("type") ) contest = models.ForeignKey( 'contests.Contest', null=True, blank=True, verbose_name=_("contest"), on_delete=models.SET_NULL, ) author = models.ForeignKey( User, null=True, blank=True, verbose_name=_("author"), on_delete=models.SET_NULL ) # visibility defines read access to all of problem data (this includes # the package, all tests and attackments) VISIBILITY_PUBLIC = 'PU' VISIBILITY_FRIENDS = 'FR' VISIBILITY_PRIVATE = 'PR' VISIBILITY_LEVELS_CHOICES = [ (VISIBILITY_PUBLIC, 'Public'), (VISIBILITY_FRIENDS, 'Friends'), (VISIBILITY_PRIVATE, 'Private'), ] visibility = models.CharField( max_length=2, verbose_name=_("visibility"), choices=VISIBILITY_LEVELS_CHOICES, default=VISIBILITY_FRIENDS, ) package_backend_name = DottedNameField( 'oioioi.problems.package.ProblemPackageBackend', null=True, blank=True, verbose_name=_("package type"), ) ascii_name = models.CharField( max_length=255, null=True ) # autofield, no polish characters # main_problem_instance: # null=True, because there is a cyclic dependency # and during creation of any Problem, main_problem_instance # must be temporarily set to Null # (ProblemInstance has ForeignKey to Problem # and Problem has ForeignKey to ProblemInstance) main_problem_instance = models.ForeignKey( 'contests.ProblemInstance', null=True, blank=False, verbose_name=_("main problem instance"), related_name='main_problem_instance', on_delete=models.CASCADE, ) @property def controller(self): return import_string(self.controller_name)(self) @property def package_backend(self): return import_string(self.package_backend_name)() @classmethod def create(cls, *args, **kwargs): """Creates a new :class:`Problem` object, with associated main_problem_instance. After the call, the :class:`Problem` and the :class:`ProblemInstance` objects will be saved in the database. """ problem = cls(*args, **kwargs) problem.save() import oioioi.contests.models pi = oioioi.contests.models.ProblemInstance(problem=problem) pi.save() pi.short_name += "_main" pi.save() problem.main_problem_instance = pi problem.save() return problem class Meta(object): verbose_name = _("problem") verbose_name_plural = _("problems") permissions = ( ('problems_db_admin', _("Can administer the problems database")), ('problem_admin', _("Can administer the problem")), ) def __str__(self): return u'%(name)s (%(short_name)s)' % { u'short_name': self.short_name, u'name': self.name, } def save(self, *args, **kwargs): self.ascii_name = unidecode(self.name) super(Problem, self).save(*args, **kwargs)