Ejemplo n.º 1
0
class FriendshipStatus(models.StatusModel):
    """
    Defines the friendship status between two users.
    """
    STATUS_PENDING = 'pending'
    STATUS_FRIEND = 'friend'
    STATUS_UNFRIEND = 'unfriend'
    STATUS_COLLEAGUE = 'colleague'
    STATUS = models.Choices(
        (STATUS_PENDING, _('pending')), (STATUS_FRIEND, _('friend')),
        (STATUS_UNFRIEND, _('unfriend')), (STATUS_COLLEAGUE, _('colleague')))
    owner = models.ForeignKey(models.User, related_name='related_users')
    other = models.ForeignKey(models.User,
                              related_name='related_users_as_other')

    class Meta:
        unique_together = ('owner', 'other'),

    def save(self, *args, **kwds):
        super().save(*args, **kwds)

        try:
            FriendshipStatus.objects.get(owner=self.other, other=self.owner)
        except FriendshipStatus.DoesNotExist:
            reciprocal = FriendshipStatus(owner=self.other, other=self.owner)
            if self.status == self.STATUS_COLLEAGUE:
                reciprocal.status = self.STATUS_COLLEAGUE
            else:
                reciprocal.status = self.STATUS_PENDING
            reciprocal.save()
Ejemplo n.º 2
0
class Sentiment(models.TimeStampedModel):
    """
    Represents the sentiment of a user towards a feature in a given instant
    of time.
    """

    STATUS_VERY_HAPPY, STATUS_HAPPY, STATUS_NEUTRAL, STATUS_SAD = range(4)
    STATUS_CHOICES = [
        (STATUS_VERY_HAPPY, _('Very happy')),
        (STATUS_HAPPY, _('Happy')),
        (STATUS_NEUTRAL, _('Neutral')),
        (STATUS_SAD, _('Sad')),
    ]

    status = models.SmallIntegerField(
        _('status'),
        choices=STATUS_CHOICES,
    )
    user = models.ForeignKey(models.User, related_name='sentiments')
    feature = models.ForeignKey(
        Feature,
        related_name='sentiments',
    )
    board = models.ForeignKey(
        SentimentBoard,
        related_name='sentiments',
    )
Ejemplo n.º 3
0
class SourceItem(models.ListItemModel):
    """A file item for the FileDownloadActivity."""
    class Meta:
        root_field = 'activity'

    activity = models.ForeignKey('SourceCodeActivity')
    format = models.ForeignKey(
        'cs_core.models.fileformat.FileFormat',
        verbose_name=_('format'),
        default='txt',
        help_text=_('The file format for the source code.'),
    )
    name = models.CharField(
        _('name'),
        max_length=140,
        help_text='A short description of the given source code fragment')
    description = models.TextField(
        _('description'),
        blank=True,
        help_text=_(
            'A detailed description of the source code fragment. This field '
            'accepts Markdown.'))
    source = models.TextField(_('source'),
                              help_text=_('The source code fragment.'))
    visible = models.BooleanField(
        _('is visible'),
        default=True,
        help_text=_(
            'Non-visible source items are available for download, but are not '
            'included in the main page'),
    )

    def __str__(self):
        return self.name
Ejemplo n.º 4
0
class GivenBadge(models.TimeStampedModel):
    """
    Implements a M2M relationship between badges and users.
    """

    user = models.ForeignKey(models.User, related_name='+')
    badge = models.ForeignKey(Badge, related_name='+')
Ejemplo n.º 5
0
class Pair(TeamABC):
    """
    A pair of students.
    """

    first_user = models.ForeignKey(models.User)
    second_user = models.ForeignKey(models.User)
    objects = PairQuerySet.as_manager()
Ejemplo n.º 6
0
class QuizActivityItem(models.ListItemModel):
    """
    A question in a quiz.
    """
    class Meta:
        root_field = 'quiz'

    quiz = models.ForeignKey('QuizActivity')
    question = models.ForeignKey(Question)
Ejemplo n.º 7
0
class GivenBadge(models.TimeStampedModel):
    """
    Associate users with badges.
    """

    badge = models.ForeignKey(Badge)
    user = models.ForeignKey(models.User)

    # Delegate attributes
    track = delegate_to('badge')
    name = delegate_to('badge')
    image = delegate_to('badge')
    description = delegate_to('badge')
    details = delegate_to('badge')
Ejemplo n.º 8
0
class Event(models.Model):
    """
    Represents an event that we want to confirm attendance.
    """

    sheet = models.ForeignKey(AttendanceSheet, related_name='events')
    date = models.DateField()
    created = models.DateTimeField()
    expires = models.DateTimeField()
    passphrase = models.CharField(
        _('Passphrase'),
        max_length=200,
        help_text=_(
            'The passphrase is case-insensitive. We tolerate small typing '
            'errors.'
        ),
    )

    def update(self, commit=True):
        """
        Regenerate passphrase and increases expiration time.
        """

        new = self.passphrase
        while new == self.passphrase:
            new = phrase()
        self.passphrase = new
        self.expires += self.sheet.expiration_interval
        if commit:
            self.save()
Ejemplo n.º 9
0
class BadgeTrack(models.Model):
    """
    A badge track represents a single type of action that can give an increasing
    number of badges for different levels of accomplishment.
    """

    name = models.CharField(_('name'), max_length=200)
    entry_point = models.ForeignKey(models.Page, related_name='badge_tracks')

    @lazy
    def badges_list(self):
        """
        A list of all badges in the track sorted by difficulty.
        """
        badges = list(self.badges.all())
        badges.sort(key=lambda x: x.value)
        return badges

    def issue_badges(self, user, **kwargs):
        """
        Issue all badges for the given
        """

        for badge in self.badges_list:
            badge.update_for_user(user, **kwargs)
Ejemplo n.º 10
0
class Badge(models.Model):
    """
    Represents an abstract badge.

    Instances of these class are not associated to specific users. GivenBadge
    makes the association between badges and users.
    """

    track = models.ForeignKey(BadgeTrack, related_name='badges')
    name = models.CharField(max_length=200)
    image = models.ImageField(
        upload_to='gamification/badges/',
        blank=True,
        null=True,
    )
    required_points = models.PositiveIntegerField(default=0)
    required_score = models.PositiveIntegerField(default=0)
    required_stars = models.PositiveIntegerField(default=0)
    description = models.TextField()
    details = models.RichTextField(blank=True)

    @property
    def value(self):
        """
        A sortable element that describes the overall badge difficulty.
        """
        return self.required_stars, self.required_points, self.required_score

    @classmethod
    def update_for_user(cls, user, **kwargs):
        """
Ejemplo n.º 11
0
class Sprint(models.Model):
    """
    A sprint
    """

    project = models.ForeignKey(ScrumProject, related_name='sprints')
    description = models.RichTextField(blank=True)
    start_date = models.DateTimeField()
    due_date = models.DateTimeField()
    duration_weeks = models.PositiveIntegerField(default=1,
                                                 validators=[non_null])

    def next_start_date(self, date=None):
        """
        Return the next valid date that the sprint could start after the given.

        If no arguments are given, consider the current time.
        """

        date = date or now()
        return date

    def attach(self, project, commit=True):
        """
        Associate sprint to project, updating required values.
        """

        date = project.finish_date()
        self.project = project
        self.start_date = self.next_start_date(date)
        self.due_date = self.start_date + one_week * self.duration_weeks
        if commit:
            self.save()
Ejemplo n.º 12
0
class CodePost(Post):
    """
    Post some code.
    """

    language = models.ForeignKey('core.ProgrammingLanguage', related_name='+')
    source = models.TextField()
Ejemplo n.º 13
0
class CustomFieldDefinition(models.Model):
    """
    Define a custom site-specific field for the user profile.
    """
    name = models.CharField(max_length=40)
    description = models.CharField(max_length=140)
    category = models.ForeignKey(CustomFieldCategory)
    enabled = models.BooleanField(
        _('enabled'),
        help_text=_('Enable or disable a custom field'),
        default=True,
    )
    type = models.CharField(default='text',
                            blank=True,
                            max_length=10,
                            choices=[('text', _('text')), ('int', _('int')),
                                     ('float', _('float')),
                                     ('date', _('date')),
                                     ('datetime', _('datetime'))])

    from_db_conversions = {
        'text': lambda x: x,
        'int': int,
        'float': float,
        'date': lambda x: datetime.date(*map(int, x.split('-'))),
        'datetime': lambda x: strptime("%Y-%m-%dT%H:%M:%S.%f%z", x),
    }

    to_db_conversions = {
        'date': lambda x: x.isoformat(),
        'datetime': lambda x: x.strftime("%Y-%m-%dT%H:%M:%S.%f%z"),
    }
Ejemplo n.º 14
0
class ExtraEmail(models.Model):
    """
    Extra e-mails assigned to a Codeschool account.
    """

    user = models.ForeignKey(User)
    email = models.EmailField(unique=True)
Ejemplo n.º 15
0
class Pairing(models.Model):
    """
    A single pairing done in a sprint.
    """

    sprint = models.ForeignKey(Sprint, related_name='pairings')
    members = models.ManyToManyField(models.User, related_name='+')
Ejemplo n.º 16
0
class ExpectedUsername(models.Model):
    """A string of an allowed value for e.g., white listing user names that
    can enroll in a specific course/activity/event etc.

    This class is used to create white lists of users that might not exist yet
    in the database. If you are sure that your users exist, maybe it is more
    convenient to create a regular Group."""

    username = models.CharField(max_length=100, )
    listener_id = models.IntegerField(
        null=True,
        blank=True,
    )
    listener_type = models.ForeignKey(
        models.ContentType,
        null=True,
        blank=True,
    )
    listener_action = models.CharField(
        max_length=30,
        blank=True,
    )

    @property
    def exists(self):
        return models.User.objects.filter(username=self.username).size() == 1

    @property
    def is_active(self):
        try:
            return models.User.objects.get(username=self.username).is_active
        except models.User.DoesNotExist:
            return False

    @property
    def listener(self):
        ctype = models.ContentType.objects.get(pk=self.listener_type)
        cls = ctype.model_class()
        try:
            return cls.objects.get(pk=self.listener_id)
        except cls.DoesNotExist:
            return None

    @property
    def user(self):
        return models.User.objects.get(username=self.username)

    def notify(self, user=None):
        """
        Notify that user with the given username was created.
        """

        if self.action:
            listener = self.listener
            if listener is not None:
                callback = getattr(listener, action)
                callback(user or self.user)

    def __str__(self):
        return self.username
Ejemplo n.º 17
0
class CodingIoResponse(QuestionResponse):
    source = models.TextField(blank=True)
    language = models.ForeignKey(ProgrammingLanguage)

    # Feedback properties
    feedback = property(lambda x: x.feedback_data)
    feedback_title = property(lambda x: x.feedback_data.title)
    testcase = property(lambda x: x.feedback_data.testcase)
    answer_key = property(lambda x: x.feedback_data.answer_key)
    is_correct = property(lambda x: x.feedback_data.is_correct)

    def autograde_compute(self):
        self.feedback_data = self.question.grade(self)
        return self.feedback_data.grade * 100

    def html_feedback(self):
        if self.is_done:
            return render_html(
                self.feedback,
                template_name='cs_questions/render/feedback.jinja2')
        else:
            return super().html_feedback()

    @classmethod
    def _recompute_all_responses(cls):
        for r in cls.objects.all():
            r.grade = r.get_grade_from_feedback()
            r.save()
Ejemplo n.º 18
0
class QuizItem(models.Orderable):
    """
    A question in a quiz.
    """

    quiz = models.ParentalKey(
        'cs_questions.Quiz',
        related_name='quiz_items',
    )
    question = models.ForeignKey(
        'wagtailcore.Page',
        related_name='+',
    )
    weight = models.FloatField(
        _('value'),
        default=1.0,
        help_text=_(
            'The non-normalized weight of this item in the total quiz grade.'),
    )

    # Wagtail admin
    panels = [
        panels.PageChooserPanel('question', [
            'cs_questions.CodingIoQuestion',
            'cs_questions.FormQuestion',
        ]),
        panels.FieldPanel('weight'),
    ]
Ejemplo n.º 19
0
class Response(models.InheritableModel, models.TimeStampedStatusModel):
    """
    Represents a student's response to some activity. The student may submit
    many responses for the same object. It is also possible to submit
    different responses with different students.
    """

    STATUS_PENDING = 'pending'
    STATUS_WAITING = 'waiting'
    STATUS_INVALID = 'invalid'
    STATUS_DONE = 'done'
    STATUS = models.Choices(
        (STATUS_PENDING, _('pending')),
        (STATUS_WAITING, _('waiting')),
        (STATUS_DONE, _('done')),
    )
    activity = models.ForeignKey(Activity, blank=True, null=True)
    user = models.ForeignKey(models.User)
    grade = models.DecimalField(
        'Percentage of maximum grade',
        max_digits=6,
        decimal_places=3,
        blank=True,
        null=True,
    )
    data = models.PickledObjectField(blank=True, null=True)

    #
    # Visualization
    #
    ok_message = '*Contratulations!* Your response is correct!'
    wrong_message = 'I\'m sorry, your response is wrong.'
    partial_message = 'Your answer is partially correct: you made %(grade)d%% of the total grade.'

    def as_html(self):
        data = {'grade': self.grade * 100}
        if self.grade == 1:
            return markdown(self.ok_message)
        elif self.grade == 0:
            return markdown(self.wrong_message)
        else:
            return markdown(self.partial_message % data)

    def __str__(self):
        tname = type(self).__name__
        return '%s(%s, grade=%s)' % (tname, self.activity, self.grade)
Ejemplo n.º 20
0
class ResponseModel(models.Model):
    class Meta:
        abstract = True

    language = models.ForeignKey(
        ProgrammingLanguage,
        verbose_name=_('Programming language'),
        help_text=_('The programming language for your code'))
Ejemplo n.º 21
0
class FriendshipStatus(models.StatusModel):
    STATUS = models.Choices(('pending', _('pending')), ('friend', _('friend')),
                            ('acquaintance', _('acquaintance')),
                            ('unfriend', _('unfriend')))

    owner = models.ForeignKey(models.User, related_name='associated')
    other = models.ForeignKey(models.User, related_name='associated_as_other')

    class Meta:
        unique_together = ('owner', 'other'),

    def save(self, *args, **kwds):
        super().save(*args, **kwds)

        try:
            FriendshipStatus.objects.get(owner=self.other, other=self.owner)
        except FriendshipStatus.DoesNotExist:
            FriendshipStatus(owner=self.other,
                             other=self.owner,
                             status='pending').save()
Ejemplo n.º 22
0
class UrlItem(models.ListItemModel):
    """
    An URL item for the UrlActivity.
    """
    class Meta:
        root_field = 'activity'

    activity = models.ForeignKey('UrlActivity')
    url = models.URLField()
    name = models.CharField(max_length=50, blank=True)
    alt = models.CharField(max_length=50, blank=True)
Ejemplo n.º 23
0
class Gradebook(models.CodeschoolPage):
    """
    The gradebook page for each student.

    Each student have a gradebook object for each of its enrolled courses.
    """

    user = models.ForeignKey(
        'auth.User',
        verbose_name=_('Student name'),
        on_delete=models.PROTECT,
    )
    course = models.ForeignKey(
        'cs_core.Course',
        on_delete=models.SET_NULL,
        null=True,
    )

    # Wagtail admin
    parent_page_types = ['cs_core.Profile']
Ejemplo n.º 24
0
class CodingIoSubmission(QuestionSubmission):
    """
    A response proxy class specialized in CodingIoQuestion responses.
    """

    source = models.TextField(blank=True)
    language = models.ForeignKey(ProgrammingLanguage)

    objects = manager_instance(QuestionSubmission,
                               CodingIoSubmissionQuerySet,
                               use_for_related_fields=True)
Ejemplo n.º 25
0
class CustomFieldValue(models.Model):
    """
    Represents a value of a custom field.

    Since custom fields can have many different types, we store all of them
    as a TextField and provide serializers for each type in order to convert
    each field to the correct type. The ``value`` attribute is always converted
    to the correct type.
    """

    definition = models.ForeignKey(CustomFieldDefinition)
    profile = models.ForeignKey(Profile, related_name='custom_field_values')
    db_value = models.TextField()

    @property
    def value(self):
        tt = self.definition.type
        if tt == 'text':
            return self.db_value
        elif tt == 'float':
            return float(self.db_value)
Ejemplo n.º 26
0
class ExhibitEntry(models.ClusterableModel):
    """
    Each user submission
    """
    class Meta:
        unique_together = [('user', 'exhibit')]

    exhibit = models.ParentalKey(CodeExhibit, related_name='entries')
    user = models.ForeignKey(models.User,
                             related_name='+',
                             on_delete=models.CASCADE)
    name = models.CharField(max_length=200)
    source = models.TextField()
    image = models.ImageField(upload_to='images/code_exhibit/')
    # image = models.FileField(upload_to='images/code_exhibit/')
    votes_from = models.ManyToManyField(models.User, related_name='+')
    num_votes = models.IntegerField(default=int)
    objects = ExhibitEntryQuerySet.as_manager()

    def vote(self, user):
        """
        Register a vote from user.
        """

        if not self.votes_from.filter(id=user.id).count():
            self.votes_from.add(user)
            self.num_votes += 1
            self.save(update_fields=['num_votes'])

    def unvote(self, user):
        """
        Remove a vote from user.
        """

        if self.votes_from.filter(id=user.id).count():
            self.votes_from.remove(user)
            self.num_votes -= 1
            self.save(update_fields=['num_votes'])

    def icon_for_user(self, user):
        if user in self.votes_from.all():
            return 'star'
        return 'start_border'

    # Wagtail admin
    panels = [
        panels.FieldPanel('user'),
        panels.FieldPanel('source'),
        panels.FieldPanel('image'),
        panels.FieldPanel('num_votes'),
    ]
Ejemplo n.º 27
0
class Badge(models.TimeStampedModel, models.PolymorphicModel):
    """
    An abstract badge that marks an accomplishment in a given badge track.
    """

    track = models.ForeignKey(BadgeTrack, related_name='badges')
    name = models.CharField(
        _('name'),
        max_length=200,
    )
    slug = models.CharField(unique=True)
    description = models.TextField(
        _('description'),
        help_text=_(
            'A detailed description of the accomplishment required to receive '
            'the badge.'),
    )
    message = models.TextField(
        _('message'),
        help_text=_(
            'The message displayed when users receive the given badge'))
    image = models.ImageField(
        upload_to='gamification/badges/',
        blank=True,
        null=True,
    )
    required_achievement = models.PositiveIntegerField(
        default=0,
        help_text=_(
            'Abstract quantity that associated with linear badge tracks.'),
    )
    level = models.PositiveIntegerField(
        _('Badge level'),
        help_text=_(
            'The badge level: for linear badge tracks, it defines the ordering'
            'between different badges.'),
    )
    extra = models.JSONField(default=dict, )
    users = models.ManyToManyField(
        models.User,
        through='GivenBadge',
        related_name='badges',
    )

    def issue_badge(self, user):
        """
        Issue badge for the given user.
        """

        self.users.add(user)
Ejemplo n.º 28
0
class Task(models.Model):
    """
    A task that can be on the backlog or on a sprint.
    """

    STATUS_BACKLOG = 0
    STATUS_TODO = 1
    STATUS_DOING = 2
    STATUS_DONE = 3
    STATUS = models.Choices(
        (STATUS_BACKLOG, 'backlog'),
        (STATUS_TODO, 'todo'),
        (STATUS_DOING, 'doing'),
        (STATUS_DONE, 'done'),
    )
    sprint = models.ForeignKey(Sprint, related_name='tasks')
    project = models.ForeignKey(ScrumProject, related_name='tasks')
    status = models.StatusField()
    created_by = models.ForeignKey(models.User, related_name='+')
    assigned_to = models.ManyToManyField(models.User, related_name='+')
    description = models.RichTextField()
    duration_hours = models.IntegerField()
    objects = TaskQuerySet.as_manager()
Ejemplo n.º 29
0
class AttendanceCheck(models.Model):
    """
    Confirms attendance by an user.
    """

    user = models.ForeignKey(models.User)
    event = models.ForeignKey(Event)
    has_attended = models.BooleanField(default=bool)
    attempts = models.SmallIntegerField(default=int)

    def update(self, phrase):
        """
        Update check with the given passphrase.
        """

        sheet = self.event.sheet
        if self.attempts > sheet.max_attempts:
            return
        if string_distance(phrase,
                           self.event.passphrase) <= sheet.max_string_distance:
            self.has_attended = True
        self.attempts += 1
        self.save()
Ejemplo n.º 30
0
class CodingIoSubmission(QuestionSubmission):
    """
    A response proxy class specialized in CodingIoQuestion responses.
    """

    source = models.TextField(blank=True)
    language = models.ForeignKey('core.ProgrammingLanguage')

    objects = manager_instance(QuestionSubmission,
                               CodingIoSubmissionQuerySet,
                               use_for_related_fields=True)

    def compute_hash(self):
        return md5hash(self.source + self.language.ref)