Example #1
0
class AbstractParticipant(polymorphic.models.PolymorphicModel,
                          drapo.models.ModelWithTimestamps):
    contest = models.ForeignKey(Contest, related_name='participants')

    is_approved = models.BooleanField(default=True)

    is_disqualified = models.BooleanField(default=False)

    is_visible_in_scoreboard = models.BooleanField(default=True)

    region = models.ForeignKey(ContestRegion,
                               null=True,
                               blank=True,
                               related_name='participants')

    @property
    def name(self):
        return self.get_real_instance().name

    def get_absolute_url(self):
        return self.get_real_instance().get_absolute_url()

    def get_current_score(self):
        correct_attempts = self.attempts.filter(is_correct=True)
        solved_tasks = correct_attempts.values('task').distinct()
        return solved_tasks.aggregate(sum=Sum('task__max_score'))['sum']

    def __str__(self):
        return self.name
Example #2
0
class EntranceExamTaskSolution(polymorphic.models.PolymorphicModel):
    task = models.ForeignKey(
        'EntranceExamTask',
        on_delete=models.CASCADE,
        related_name='solutions',
    )

    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='entrance_exam_solutions',
    )

    solution = models.TextField()

    ip = models.CharField(
        max_length=50,
        help_text='IP-адрес, с которого было отправлено решение',
        default='')

    created_at = models.DateTimeField(
        auto_now_add=True,
        db_index=True,
    )

    def __str__(self):
        return 'Решение %s по задаче %s' % (self.user, self.task)

    class Meta:
        ordering = ['-created_at']
        index_together = ('task', 'user')
Example #3
0
class EntranceLevelOverride(models.Model):
    """
    If present this level is used instead of dynamically computed one.
    """
    school = models.ForeignKey(
        'schools.School',
        on_delete=models.CASCADE,
        related_name='+',
    )

    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='entrance_level_overrides',
    )

    entrance_level = models.ForeignKey(
        'EntranceLevel',
        on_delete=models.CASCADE,
        related_name='overrides',
    )

    class Meta:
        unique_together = ('school', 'user')

    def __str__(self):
        return 'Уровень {} для {}'.format(self.entrance_level, self.user)

    def save(self, *args, **kwargs):
        if self.school != self.entrance_level.school:
            raise IntegrityError(
                'Entrance level override should belong to the same school as '
                'its entrance level')
        super().save(*args, **kwargs)
Example #4
0
class UserQuestionnaireStatus(models.Model):
    class Status(djchoices.DjangoChoices):
        NOT_FILLED = djchoices.ChoiceItem(1)
        FILLED = djchoices.ChoiceItem(2)

    user = models.ForeignKey(
        users.models.User,
        on_delete=models.CASCADE,
        related_name='+',
    )

    questionnaire = models.ForeignKey(
        Questionnaire,
        on_delete=models.CASCADE,
        related_name='statuses',
    )

    status = models.PositiveIntegerField(
        choices=Status.choices,
        validators=[Status.validator],
    )

    class Meta:
        verbose_name_plural = 'user questionnaire statuses'
        unique_together = ('user', 'questionnaire')

    def __str__(self):
        return 'Status {} of {} for {}'.format(self.status, self.questionnaire,
                                               self.user)
Example #5
0
class QuestionnaireAnswer(models.Model):
    questionnaire = models.ForeignKey(
        Questionnaire,
        on_delete=models.CASCADE,
        related_name='answers',
    )

    user = models.ForeignKey(
        users.models.User,
        on_delete=models.CASCADE,
        related_name='questionnaire_answers',
    )

    # TODO: may be ForeignKey is better?
    question_short_name = models.CharField(max_length=100)

    answer = models.TextField(blank=True)

    def __str__(self):
        return 'Ответ «%s» на вопрос %s анкеты %s' % (
            self.answer.replace('\n', '\\n'),
            self.question_short_name,
            self.questionnaire,
        )

    @property
    def question(self):
        return AbstractQuestionnaireQuestion.objects.filter(
            questionnaire=self.questionnaire,
            short_name=self.question_short_name).first()

    class Meta:
        index_together = ('questionnaire', 'user', 'question_short_name')
Example #6
0
class TableCell(models.Model, ProcessedByVisitor):
    row = models.ForeignKey(
        TableRow,
        on_delete=models.CASCADE,
        related_name='cells',
    )

    block = models.ForeignKey(
        AbstractDocumentBlock,
        on_delete=models.CASCADE,
        related_name='+',
    )

    order = models.PositiveIntegerField(
        help_text='Ячейки упорядочиваются по возрастанию порядка')

    class Meta:
        ordering = ('row', 'order')
        unique_together = ('row', 'order')

    def __str__(self):
        return '%s[%d]: %s' % (self.row, self.order, self.block)

    def get_reportlab_block(self, visitor):
        self._process_by_visitor(visitor)
        return self.block.get_reportlab_block(visitor)
Example #7
0
class EntranceLevelUpgrade(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
    )

    upgraded_to = models.ForeignKey(
        'EntranceLevel',
        on_delete=models.CASCADE,
        related_name='+',
    )

    created_at = models.DateTimeField(auto_now_add=True)
Example #8
0
class InlineQuestionnaireBlockChild(models.Model):
    parent = models.ForeignKey(
        InlineQuestionnaireBlock,
        related_name='children',
        on_delete=models.CASCADE,
    )

    block = models.ForeignKey(
        # TODO (andgein): Maybe it should be foreign key
        # to AbstractQuestionnaireBlock, not to Question?
        # In future some blocks may nice fit in InlineQuestionnaireBlock.
        'AbstractQuestionnaireQuestion',
        related_name='+',
        on_delete=models.CASCADE,
        help_text='Вопрос, вложенный в InlineBlock')

    xs_width = models.IntegerField(validators=[
        validators.MinValueValidator(1),
        validators.MaxValueValidator(12)
    ],
                                   help_text='Размер на телефонах. От 1 до 12',
                                   default=12)

    sm_width = models.IntegerField(
        validators=[
            validators.MinValueValidator(1),
            validators.MaxValueValidator(12)
        ],
        help_text=
        'Размер на устройствах шириной от 768 до 992 пикселей. От 1 до 12',
        default=12)

    md_width = models.IntegerField(
        validators=[
            validators.MinValueValidator(1),
            validators.MaxValueValidator(12)
        ],
        help_text='Размер на остальных устройствах. От 1 до 12',
        default=6)

    def __str__(self):
        return str(self.block)

    def save(self, *args, **kwargs):
        if self.parent.questionnaire_id != self.block.questionnaire_id:
            raise IntegrityError('Selected questionnaire and block '
                                 'should belong to one school')
        super().save(*args, **kwargs)
Example #9
0
class GroupAccess(polymorphic.models.PolymorphicModel):
    class Type(djchoices.DjangoChoices):
        NONE = djchoices.ChoiceItem(
            value=0,
            label='Нет доступа, группа не видна',
        )

        LIST_MEMBERS = djchoices.ChoiceItem(
            value=10,
            label='Может просматривать участников',
        )
        EDIT_MEMBERS = djchoices.ChoiceItem(
            value=20,
            label='Может добавлять и удалять участников',
        )
        ADMIN = djchoices.ChoiceItem(
            value=30,
            label='Полный доступ',
        )

    to_group = models.ForeignKey(
        AbstractGroup,
        related_name='accesses',
        on_delete=models.CASCADE,
    )

    access_type = models.PositiveIntegerField(
        choices=Type.choices,
        validators=[Type.validator],
        db_index=True,
    )

    created_by = models.ForeignKey(
        users.models.User,
        related_name='+',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        help_text='Кем выдан доступ. Если None, то системой')

    created_at = models.DateTimeField(
        auto_now_add=True,
        db_index=True,
    )

    class Meta:
        verbose_name = 'group access'
        verbose_name_plural = 'group accesses'
Example #10
0
class UserListQuestionnaireQuestion(AbstractQuestionnaireQuestion):
    block_name = 'user_list_question'

    group = models.ForeignKey(
        'groups.AbstractGroup',
        null=True,
        on_delete=models.CASCADE,
        related_name='+',
        help_text="Группа, пользователей которой можно выбирать",
    )

    placeholder = models.TextField(
        blank=True,
        help_text='Подсказка, показываемая в поле для ввода; пример',
    )

    def get_form_field(self, attrs=None):
        return forms.ChooseUsersFromGroupField(
            group=self.group,
            required=self.is_required,
            disabled=self.is_disabled,
            label=self.text,
            help_text=self.help_text,
            placeholder=self.placeholder,
        )
Example #11
0
class AbstractTableStyleCommand(polymorphic.models.PolymorphicModel):
    table = models.ForeignKey(
        Table,
        on_delete=models.CASCADE,
        related_name='style_commands',
    )

    start_column = models.IntegerField(
        default=0,
        help_text='Координаты начала: столбец',
    )

    start_row = models.IntegerField(
        default=0,
        help_text='Координаты начала: строка',
    )

    stop_column = models.IntegerField(
        default=-1,
        help_text='Координаты конца: столбец',
    )

    stop_row = models.IntegerField(
        help_text='Координаты конца: строка',
        default=-1,
    )

    class Meta:
        verbose_name = 'table style command'

    @property
    def start(self):
        return self.start_column, self.start_row

    @property
    def stop(self):
        return self.stop_column, self.stop_row

    @property
    def params(self):
        # param can be dotted path to the nested attribute, i.e. "font.name".
        # In this case we need get self.font.name, so we split param by "." and apply
        # functools.reduce with getattr
        return [
            functools.reduce(getattr, [self] + param.split('.'))
            for param in self.command_params
        ]

    def __str__(self):
        return '%s[%s:%s].%s(%s)' % (
            self.table,
            self.start,
            self.stop,
            self.command_name,
            ', '.join(map(str, self.params)),
        )

    def get_reportlab_style_command(self):
        return (self.command_name, self.start, self.stop) + tuple(self.params)
Example #12
0
class QuestionnaireBlockShowCondition(models.Model):
    # If there is at least one conditions for `block`,
    # it will be visible only if one `need_to_be_checked` is checked
    block = models.ForeignKey(
        AbstractQuestionnaireBlock,
        on_delete=models.CASCADE,
        related_name='show_conditions',
    )

    need_to_be_checked = models.ForeignKey(
        ChoiceQuestionnaireQuestionVariant,
        on_delete=models.CASCADE,
        related_name='+',
    )

    def __str__(self):
        return 'Show %s only if %s' % (self.block, self.need_to_be_checked)
Example #13
0
class FontTableStyleCommand(CellFormattingTableStyleCommand):
    command_name = 'FONT'

    command_params = ['font.name', 'size']

    font = models.ForeignKey(Font, on_delete=models.CASCADE)

    size = models.PositiveIntegerField(null=True, default=None, blank=True)
Example #14
0
class QuestionnaireTypingDynamics(models.Model):
    user = models.ForeignKey(
        users.models.User,
        on_delete=models.CASCADE,
        related_name='+',
    )

    questionnaire = models.ForeignKey(
        Questionnaire,
        on_delete=models.CASCADE,
        related_name='+',
    )

    typing_data = sistema.models.CompressedTextField(
        help_text='JSON с данными о нажатиях клавиш')

    created_at = models.DateTimeField(auto_now_add=True)
Example #15
0
class ParagraphStyle(models.Model):
    name = models.CharField(max_length=100)

    leading = models.FloatField()

    alignment = models.PositiveIntegerField(
        choices=Alignment.choices,
        validators=[Alignment.validator],
    )

    font = models.ForeignKey(
        Font,
        on_delete=models.CASCADE,
        related_name='+',
    )

    font_size = models.PositiveIntegerField()

    bullet_font = models.ForeignKey(
        Font,
        on_delete=models.CASCADE,
        related_name='+',
    )

    space_before = models.PositiveIntegerField()

    space_after = models.PositiveIntegerField()

    left_indent = models.PositiveIntegerField()

    def __str__(self):
        return self.name

    def get_reportlab_style(self):
        return reportlab.lib.styles.ParagraphStyle(
            name=self.name,
            leading=self.leading,
            fontName=self.font.name,
            fontSize=self.font_size,
            bulletFontName=self.bullet_font.name,
            alignment=self.alignment,
            spaceBefore=self.space_before,
            spaceAfter=self.space_after,
            leftIndent=self.left_indent,
        )
Example #16
0
class GroupInGroupMembership(GroupMembership):
    member = models.ForeignKey(
        AbstractGroup,
        related_name='member_in_groups',
        on_delete=models.CASCADE,
    )

    def __str__(self):
        return 'Участники %s входят в %s' % (self.member.name, self.group.name)
Example #17
0
class GroupAccessForGroup(GroupAccess):
    group = models.ForeignKey(
        AbstractGroup,
        related_name='+',
        on_delete=models.CASCADE,
    )

    def __str__(self):
        return 'Доступ участников %s к %s' % (self.group, self.to_group)
Example #18
0
class GroupAccessForUser(GroupAccess):
    user = models.ForeignKey(
        users.models.User,
        related_name='+',
        on_delete=models.CASCADE,
    )

    def __str__(self):
        return 'Доступ %s к %s' % (self.user.get_full_name(), self.to_group)
Example #19
0
class UserInGroupMembership(GroupMembership):
    member = models.ForeignKey(
        users.models.User,
        related_name='member_in_groups',
        on_delete=models.CASCADE,
    )

    def __str__(self):
        return '%s в %s' % (self.member, self.group.name)
Example #20
0
class News(ModelWithTimestamps):
    contest = models.ForeignKey(Contest, related_name='news')

    author = models.ForeignKey(users.models.User, related_name='+')

    title = models.CharField(max_length=1000, help_text='Title')

    text = models.TextField(help_text='Supports markdown')

    is_published = models.BooleanField(default=False)

    publish_time = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = 'News'

    def get_absolute_url(self):
        return urlresolvers.reverse('contests:news',
                                    args=[self.contest_id, self.id])
Example #21
0
class SolveTaskEntranceLevelUpgradeRequirement(EntranceLevelUpgradeRequirement
                                               ):
    task = models.ForeignKey(
        'EntranceExamTask',
        on_delete=models.CASCADE,
        related_name='+',
    )

    def is_met_by_user(self, user):
        return self.task.is_solved_by_user(user)
Example #22
0
class AbstractAbsenceReason(polymorphic.models.PolymorphicModel):
    school = models.ForeignKey('schools.School',
                               on_delete=models.CASCADE,
                               related_name='absence_reasons')

    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='absence_reasons',
    )

    private_comment = models.TextField(blank=True,
                                       help_text='Не показывается школьнику')

    public_comment = models.TextField(blank=True,
                                      help_text='Показывается школьнику')

    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='+',
        null=True,
        default=None,
        blank=True,
    )

    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = 'Absence reason'

    @classmethod
    def for_user_in_school(cls, user, school):
        """
        Returns absence reason for specified user
        or None if user has not declined.
        """
        return cls.objects.filter(user=user, school=school).first()

    def default_public_comment(self):
        raise NotImplementedError()
Example #23
0
class TeamParticipant(AbstractParticipant):
    team = models.ForeignKey(teams.models.Team, related_name='participant_in')

    def __str__(self):
        return str(self.team)

    @property
    def name(self):
        return self.team.name

    def get_absolute_url(self):
        return self.team.get_absolute_url()
Example #24
0
class EntranceLevelUpgradeRequirement(polymorphic.models.PolymorphicModel):
    base_level = models.ForeignKey(
        'EntranceLevel',
        on_delete=models.CASCADE,
        related_name='+',
    )

    created_at = models.DateTimeField(auto_now_add=True)

    def is_met_by_user(self, user):
        # Always met by default. Override when subclassing.
        return True
Example #25
0
class QuestionnaireBlockGroupMemberShowCondition(
        AbstractQuestionnaireBlockShowCondition):
    # TODO: Maybe it will be a good idea to extract ServerSideShowCondition as
    # a polymorphic parent.
    group = models.ForeignKey(
        'groups.AbstractGroup',
        on_delete=models.CASCADE,
        related_name='+',
        help_text='Группа, участником которой должен быть пользователь')

    def is_satisfied(self, user):
        return self.group.is_user_in_group(user)

    def __str__(self):
        return 'Show %s only if user is a member of %s' % (self.block,
                                                           self.group)

    def copy_condition_to_questionnaire(self, to_questionnaire):
        """
        Copy block show condition to the specified questionnaire. Shouldn't be
        used outside questionnaire.models.

        Target questionnaire should have a block with the same `short_name`.
        Otherwise the copy is not created.

        Also if `group` is school-related group then
        target questionnaire's school should have a group with the same `short_name`.
        Otherwise the copy is not created.

        :param to_questionnaire: The questionnaire to copy the condition to.
        :return: The new `QuestionnaireBlockGroupMemberShowCondition` on success
            or `None` on failure.
        """
        if self.group.school is None:
            target_group = self.group
        else:
            if to_questionnaire.school is None:
                return None

            target_group = groups.models.AbstractGroup.objects.filter(
                school=to_questionnaire.school,
                short_name=self.group.short_name).first()
            if target_group is None:
                return None

        target_block = (to_questionnaire.blocks.filter(
            short_name=self.block.short_name).first())
        if target_block is None:
            return None

        return self.__class__.objects.create(block=target_block,
                                             group=target_group)
Example #26
0
class IndividualParticipant(AbstractParticipant):
    user = models.ForeignKey(users.models.User,
                             related_name='individual_participant_in')

    def __str__(self):
        return str(self.user)

    @property
    def name(self):
        return self.user.get_full_name()

    def get_absolute_url(self):
        return self.user.get_absolute_url()
Example #27
0
class GroupMembership(models.Model):
    group = models.ForeignKey(
        ManuallyFilledGroup,
        related_name='+',
        on_delete=models.CASCADE,
    )

    added_by = models.ForeignKey(
        users.models.User,
        null=True,
        blank=True,
        related_name='+',
        on_delete=models.CASCADE,
        help_text='Кем добавлен участник группы. None, если добавлено системой.'
    )

    created_at = models.DateTimeField(
        auto_now_add=True,
        db_index=True,
    )

    class Meta:
        abstract = True
Example #28
0
class Paragraph(AbstractDocumentBlock):
    text = models.TextField()

    style = models.ForeignKey(ParagraphStyle, on_delete=models.CASCADE)

    bulletText = models.TextField(default=None, null=True, blank=True)

    def __str__(self):
        return self.text[:80]

    def get_reportlab_block(self, visitor=None):
        self._process_by_visitor(visitor)
        return reportlab.platypus.Paragraph(self.text,
                                            self.style.get_reportlab_style(),
                                            self.bulletText)
Example #29
0
class AbstractParticipant(polymorphic.models.PolymorphicModel,
                          drapo.models.ModelWithTimestamps):
    contest = models.ForeignKey(Contest, related_name='participants')

    is_approved = models.BooleanField(default=True)

    is_disqualified = models.BooleanField(default=False)

    is_visible_in_scoreboard = models.BooleanField(default=True)

    @property
    def name(self):
        return self.get_real_instance().name

    def get_absolute_url(self):
        return self.get_real_instance().get_absolute_url()
Example #30
0
class ContestRegion(models.Model):
    contest = models.ForeignKey(Contest, related_name='regions')

    name = models.TextField(help_text='Region name')

    start_time = models.DateTimeField(
        help_text='Contest start time for this region')

    finish_time = models.DateTimeField(
        help_text='Contest finish time for this region')

    timezone = models.TextField(default='UTC',
                                help_text='Timezone for the region')

    def __str__(self):
        return self.name