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
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)]
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)
class PollChoice(models.Model): title = models.TitleField() poll = models.ForeignKey('Poll', on_delete=models.CASCADE) index = models.PositiveSmallIntegerField(default=0)