Beispiel #1
0
class Topic(models.Model):
    """
    A topic in a classroom
    """

    name = models.NameField()
    index = models.PositiveSmallIntegerField()
    classroom = models.ForeignKey('Classroom', on_delete=models.CASCADE)

    class Meta:
        unique_together = [('name', 'classroom')]

    def __str__(self):
        return self.name
Beispiel #2
0
class SocialIcon(models.Model):
    """
    Configurable reference to a social media icon.
    """

    social_network = models.CharField(
        _("Social network"),
        max_length=50,
        unique=True,
        help_text=_("Name of the social network (e.g., Facebook)"),
    )
    icon_name = models.CharField(
        _("Icon name"),
        max_length=50,
        help_text=_("Icon name in font-awesome. Use short version like "
                    '"google", "facebook-f", etc.'),
        validators=[validate_icon_name],
    )
    index = models.PositiveSmallIntegerField(
        _("Ordering"),
        default=0,
        help_text=_(
            "You can manually define the ordering that each icon should "
            "appear in the interface. Otherwise, icons will be shown in "
            "insertion order."),
    )
    url = models.URLField(_("URL"),
                          help_text=_("Link to your social account page."))

    @property
    def fa_class(self):
        collection = FA_COLLECTIONS.get(self.icon_name)
        return collection and f"{collection} fa-{self.icon_name}"

    class Meta:
        ordering = ["index", "id"]
        verbose_name = _("Social media icon")
        verbose_name_plural = _("Social media icons")

    def __str__(self):
        return self.social_network

    def __html__(self):
        if self.url:
            return str(self.link_tag())
        else:
            return str(self.icon_tag())

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._fill_social_icon()

    def _fill_social_icon(self):
        if not self.icon_name:
            self.icon_name = default_icon_name(self.social_network.casefold())

    def icon_tag(self, classes=()):
        """
        Render an icon tag for the given icon.

        >>> print(icon.icon_tag(classes=['header-icon']))       # doctest: +SKIP
        <i class="fa fa-icon header-icon"></i>
        """
        return fa_icon(self.icon_name, class_=classes)

    def link_tag(self, classes=(), icon_classes=()):
        """
        Render an anchor tag with the link for the social network.

        >>> print(icon.link_tag(classes=['header-icon']))       # doctest: +SKIP
        <a href="url"><i class="fa fa-icon header-icon"></i></a>
        """
        return a(href=self.url, class_=classes)[self.icon_tag(icon_classes)]
Beispiel #3
0
class ProgressBase(models.Model):
    """
    Common features of all Progress models.
    """

    score = models.PositiveSmallIntegerField(default=0)
    score_bias = models.SmallIntegerField(default=0)

    @classmethod
    def level_fields(cls):
        try:
            return cls.__dict__["_level_fields"]
        except KeyError:
            fields = {}
            for field in cls._meta.fields:
                if field.name.endswith(
                        "_level") and not field.name.startswith("max_"):
                    fields[field.name[:-6]] = field.enum
            setattr(cls, "_level_fields", fields)
            return fields

    @property
    def level_achievement_signal(self):
        raise NotImplementedError("must be defined in subclass")

    @lazy
    def position(self):
        return len(
            type(self).objects.order_by("-score").filter(score__gt=self.score))

    class Meta:
        abstract = True

    def sync(self):
        self.score = self.compute_score()
        self.update_levels(commit=False)
        return self

    def update_level(self, name, commit=True):
        """
        Update given level and possibly save modification, if necessary.

        Return True, if level was changed and False otherwise.
        """
        level_attr = name + "_level"
        max_level_attr = f"max_{name}_level"

        current = getattr(self, level_attr)
        new_level = current.check_level(self)
        max_level = getattr(self, max_level_attr)

        if new_level != current:
            update_fields = [level_attr]
            setattr(self, level_attr, new_level)
            if new_level > max_level:
                setattr(self, max_level_attr, new_level)
                update_fields.append(max_level_attr)

            self.notify_achievement(new_level, name, new_level > current)

            if commit:
                self.save(update_fields=update_fields)
            return True

        return False

    def update_levels(self, commit=True):
        """
        Update all levels in model.

        Return a list with all updated levels.
        """

        updated = []
        for name in self.level_fields():
            if self.update_level(name, commit=False):
                updated.append(name)

        if commit and updated:
            fields = [
                *(f"{name}_level" for name in updated),
                *(f"max_{name}_level" for name in updated),
            ]
            self.save(update_fields=fields)

        return updated

    def compute_score(self):
        """
        Return score computed from user achievements.
        """
        raise NotImplementedError("must be implemented in subclass")

    def notify_achievement(self, level, track, is_improvement):
        """
        Send the proper signal to notify a new user achievement.
        """
        signal = self.level_achievement_signal
        args = {
            "progress": self,
            "level": level,
            "track": track,
            "is_improvement": is_improvement,
        }
        if "user" in signal.providing_args:
            args["user"] = self.user
        if "conversation" in signal.providing_args:
            args["conversation"] = self.conversation
        return signal.send_robust(type(self), **args)
Beispiel #4
0
class PollChoice(models.Model):
    title = models.TitleField()
    poll = models.ForeignKey('Poll', on_delete=models.CASCADE)
    index = models.PositiveSmallIntegerField(default=0)