class UserAgreement(models.TimestampModel): tos = models.ForeignKey( TermsOfService, db_index=True, on_delete=models.CASCADE, related_name='terms', verbose_name=_('tos'), ) user = models.ForeignKey( settings.AUTH_USER_MODEL, db_index=True, on_delete=models.CASCADE, related_name='user_agreements', verbose_name=_('user'), ) class Meta: unique_together = ('user', 'tos') ordering = ["-created_at"] def __str__(self): return '%(user)s agreed to TermsOfService %(tos)s at %(when)s' % { 'user': self.user.username, 'tos': self.tos, 'when': self.created_at, }
class UserAgreementOption(models.Model): parent = models.ForeignKey( UserAgreement, db_index=True, on_delete=models.CASCADE, related_name='options', verbose_name=_('user agreement'), ) option = models.ForeignKey( Option, db_index=True, on_delete=models.CASCADE, related_name='user_agreements', verbose_name=_('user agreement'), ) value = models.BooleanField( default=False, verbose_name=_('value'), ) def __str__(self): return '%(version)s %(option)s: %(value)s' % { 'version': self.parent.tos.version, 'option': self.option, 'value': self.value, }
class OptionTranslation(models.TranslationModel): parent = models.ForeignKey( Option, db_index=True, on_delete=models.CASCADE, related_name='translations', verbose_name=_('option'), ) label = models.TextField(verbose_name=_('label'), ) description = models.TextField( null=True, blank=True, verbose_name=_('description'), ) error_message = models.TextField( blank=True, default='', verbose_name=_('error message'), ) class Meta: unique_together = ('parent', 'language') verbose_name = _('translation') verbose_name_plural = _('translations') def __str__(self): return "%s %s translation" % (self.language, self.parent)
class Email(models.Model): service = models.ForeignKey( Service, related_name="emails", verbose_name=_("service"), ) name = models.CharField( max_length=255, blank=True, null=True, verbose_name=_("name"), ) email = models.EmailField( max_length=255, verbose_name=_("email"), ) class Meta: unique_together = [("service", "email")] verbose_name = _("Service email") verbose_name_plural = _("Service email") def __str__(self): return _("Email for {name}: {email}").format( name=self.service.name, email=self.email, )
class AdministrativeArea(models.Model): """ Administrative Area level 1 for a country. For the US, this would be the states. """ status = models.StatusField( verbose_name=_('Area is active'), ) country = models.ForeignKey( Country, related_name='administrative_areas', ) name = models.CharField( max_length=60, db_index=True, verbose_name=_('Admin Area name'), ) abbrev = models.CharField( max_length=3, blank=True, null=True, verbose_name=_('Postal Abbreviation'), ) def __str__(self): return self.name class Meta: verbose_name = _('Administrative Area') verbose_name_plural = _('Administrative Areas') ordering = ('name',)
class CountryTranslation(models.TranslationModel): country = models.ForeignKey( Country, related_name='translations', ) name = models.CharField( max_length=128, db_index=True, verbose_name=_('Official name (CAPS)'), ) printable_name = models.CharField( max_length=128, db_index=True, verbose_name=_('Country name'), ) class Meta: verbose_name = _('Country Name Translation') verbose_name_plural = _('Country Name Translations') unique_together = (('language', 'country',),) def __str__(self): return '%(translation)s (%(country)s)' % { 'country': self.country.printable_name, 'translation': self.printable_name, }
class CouponUser(models.TimestampModel): coupon = models.ForeignKey( Coupon, on_delete=models.CASCADE, related_name="users", verbose_name=_("Coupon"), ) user = models.ForeignKey( settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, verbose_name=_("User"), ) redeemed_at = models.DateTimeField( blank=True, null=True, verbose_name=_("Redeemed at"), ) source_type = models.ForeignKey( models.ContentType, db_index=True, blank=True, null=True, on_delete=models.SET_NULL, verbose_name=_("source content type"), ) source_id = models.PositiveIntegerField( blank=True, null=True, verbose_name=_("source id"), ) source = models.GenericForeignKey( "source_type", "source_id", ) class Meta: verbose_name = _("Coupon") verbose_name_plural = _("Coupons") def __str__(self): return str(self.user)
class TermsOfServiceTranslation(models.TranslationModel): parent = models.ForeignKey( TermsOfService, db_index=True, on_delete=models.CASCADE, related_name='translations', verbose_name=_('TermsOfService'), ) label = models.TextField( blank=True, default='', verbose_name=_('label'), ) title = models.CharField( max_length=255, blank=True, default='', verbose_name=_('legal title'), help_text=_('legal tos title'), ) text = models.TextField( blank=True, default='', verbose_name=_('legal text'), help_text=_('legal tos text'), ) human_title = models.CharField( max_length=255, blank=True, default='', verbose_name=_('human title'), help_text=_('human readable tos title'), ) human_text = models.TextField( blank=True, default='', verbose_name=_('human text'), help_text=_('human readable tos text'), ) changelog = models.TextField( blank=True, default='', verbose_name=_('changelog'), help_text=_('difference(s) from previous version'), ) class Meta: unique_together = (('language', 'parent'), ('human_title', 'human_text')) verbose_name = _('TermsOfService Translation') verbose_name_plural = _('TermsOfService Translations') def __str__(self): return self.title
class Attachment(models.Model): email = models.ForeignKey(Email, on_delete=models.CASCADE, related_name="attachments", verbose_name=_("email")) filename = models.StringField(blank=True, verbose_name=_("filename")) content = models.BinaryField(null=True, blank=True, default=None, verbose_name=_("content")) mimetype = models.StringField(blank=True, verbose_name=_("mimetype")) class Meta: verbose_name = _("attachment") verbose_name_plural = _("attachments")
class FaqTranslation(PostModelTranslation): parent = models.ForeignKey( Faq, on_delete=models.CASCADE, related_name='translations', verbose_name=_('faq'), ) class Meta: unique_together = (('parent', 'language'), ('title', 'slug')) verbose_name = _('faq translation') verbose_name_plural = _('faq translations') def __str__(self): return '%(parent)s [%(language)s]' % { 'parent': self.parent, 'language': self.language, }
class EmailTemplateTranslation(models.TranslationModel): parent = models.ForeignKey( EmailTemplate, on_delete=models.CASCADE, related_name="translations", verbose_name=_("parent"), ) subject = models.StringField(verbose_name=_("subject")) body = models.TextField(verbose_name=_("body")) body_html = models.TextField(blank=True, verbose_name=_("body")) class Meta: unique_together = [("language", "parent")] verbose_name = _("mail translation") verbose_name_plural = _("mail translations") def __str__(self): return "%(name)s [%(lang)s]" % { "name": self.parent.name, "lang": self.language[:2], }
class CommentModel(models.TimestampModel): """ A user comment about some object. """ objects = CommentManager() site = models.ForeignKey( Site, default=get_current_site, on_delete=models.CASCADE, related_name="comments", verbose_name=_("site"), ) parent = models.ForeignKey( "self", blank=True, null=True, on_delete=models.SET_NULL, related_name="children", verbose_name=_("parent comment"), ) user = models.ForeignKey( settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL, related_name="%(app_label)s_%(class)s_comments", verbose_name=_("user"), ) user_name = models.CharField(max_length=255, blank=True, verbose_name=_("user's name")) user_email = models.EmailField(max_length=255, blank=True, verbose_name=_("user's email address")) user_url = models.URLField(blank=True, verbose_name=_("user's URL")) comment = models.TextField(max_length=settings.MAX_LENGTH, verbose_name=_("comment")) notify_by_email = models.BooleanField(default=True, verbose_name=_("notify by email for updates")) ip_address = models.GenericIPAddressField(blank=True, null=True, verbose_name=_("IP address")) is_public = models.BooleanField( default=True, help_text=_("Uncheck this box to make the comment effectively disappear from the site."), verbose_name=_("is public"), ) is_removed = models.BooleanField( default=False, help_text=_( "Check this box if the comment is inappropriate. A " '"This comment has been removed" message will be displayed instead.' ), verbose_name=_("is removed"), ) class Meta: abstract = True ordering = ["created_at"] permissions = [("can_moderate", "Can moderate comments")] verbose_name = _("comment") verbose_name_plural = _("comments") def __str__(self): return "{name}: {comment}...".format(name=self.name, comment=self.comment[:50]) @property def name(self): return self.userinfo["name"] @name.setter def name(self, val): if self.user_id: raise AttributeError(_("This comment was posted by an authenticated user and thus the name is read-only.")) self.user_name = val @property def email(self): return self.userinfo["email"] @email.setter def email(self, val): if self.user_id: raise AttributeError(_("This comment was posted by an authenticated user and thus the email is read-only.")) self.user_email = val @property def url(self): return self.userinfo["url"] @url.setter def url(self, val): self.user_url = val @property def userinfo(self): if not hasattr(self, "_userinfo"): userinfo = {"name": self.user_name, "email": self.user_email, "url": self.user_url} if self.user_id: u = self.user if u.email: userinfo["email"] = u.email # If the user has a full name, use that for the user name. # However, a given user_name overrides the raw user.username, # so only use that if this comment has no associated name. if u.get_full_name(): userinfo["name"] = self.user.get_full_name() elif not self.user_name: userinfo["name"] = u.get_username() self._userinfo = userinfo return self._userinfo
class Coupon(models.TimestampModel): Error = exceptions.CouponError ExpiredError = exceptions.CouponExpiredError IsUsableError = exceptions.CouponIsUsableError objects = CouponManager() value = models.IntegerField( verbose_name=_("Value"), help_text=_("Arbitrary coupon value"), ) code = models.CharField( max_length=30, unique=True, blank=True, verbose_name=_("Code"), help_text=_("Leaving this field empty will generate a random code."), ) type = models.CharField( choices=COUPON_TYPES, max_length=20, verbose_name=_("Type"), ) action = models.CharField( choices=ACTION_TYPES, max_length=20, blank=True, default=DEFAULT_ACTION_TYPE, verbose_name=_("Action"), ) user_limit = models.PositiveIntegerField( default=1, verbose_name=_("User limit"), ) valid_from = models.DateTimeField( blank=True, null=True, verbose_name=_("Valid from"), help_text=_("Coupons are valid from this date"), ) valid_until = models.DateTimeField( blank=True, null=True, verbose_name=_("Valid until"), help_text=_("Coupons expire at this date"), ) campaign = models.ForeignKey( Campaign, blank=True, null=True, on_delete=models.CASCADE, related_name="coupons", verbose_name=_("Campaign"), ) class Meta: ordering = ["created_at"] verbose_name = _("Coupon") verbose_name_plural = _("Coupons") def __str__(self): return self.code def save(self, *args, **kwargs): if not self.code: self.code = Coupon.generate_code() super().save(*args, **kwargs) def expired(self): return self.is_expired @property def is_expired(self): return self.valid_until is not None and self.valid_until < timezone.now() @property def is_redeemed(self): """ Returns true is a coupon is redeemed (completely for all users) otherwise returns false. """ return self.users.filter( redeemed_at__isnull=False ).count() >= self.user_limit and self.user_limit is not 0 @property def redeemed_at(self): try: return self.users.filter(redeemed_at__isnull=False).order_by('redeemed_at').last().redeemed_at except self.users.through.DoesNotExist: return None @classmethod def generate_code(cls, prefix="", segmented=SEGMENTED_CODES, code_chars=CODE_CHARS, code_length=CODE_LENGTH): code = "".join(random.choice(code_chars) for i in range(code_length)) if segmented: code = SEGMENT_SEPARATOR.join([code[i:i + SEGMENT_LENGTH] for i in range(0, len(code), SEGMENT_LENGTH)]) return prefix + code else: return prefix + code @property def is_usable(self): user_limit = self.user_limit is_usable = -1 < CouponUser.objects.filter(coupon=self).count() < user_limit if is_usable: is_usable = self.do_is_usable_pipeline() return is_usable @transaction.atomic def redeem(self, user=None, source=None, **kwargs): if not self.is_usable: raise Coupon.IsUsableError() coupon_user = CouponUser(coupon=self, user=user) coupon_user.redeemed_at = timezone.now() if source is not None: coupon_user.source_type = models.ContentType.objects.get_for_model(source) coupon_user.source_id = source.pk coupon_user.save() self.do_redeem_pipeline(coupon_user=coupon_user, user=user, source=source, **kwargs) return coupon_user def do_is_usable_pipeline(self, **kwargs): coupon = self for name in getattr(settings, "COUPONS_IS_USABLE_PIPELINE", []): pipeline = import_string(name) coupon, is_usable = pipeline(coupon=coupon, **kwargs) if not is_usable: return False return True def do_redeem_pipeline(self, **kwargs): coupon = self for name in getattr(settings, "COUPONS_REDEEM_PIPELINE", []): pipeline = import_string(name) coupon = pipeline(coupon=coupon, **kwargs)
class PostModel(models.TimestampModel, models.OrderedModel, models.I18NModel): STATUS_DRAFT = "draft" STATUS_PUBLISHED = "published" STATUS_CHOICES = [ (STATUS_DRAFT, _("Draft")), (STATUS_PUBLISHED, _("Published")), ] objects = PostModelManager() uuid = models.StringField( max_length=36, blank=True, verbose_name=_("uuid field"), help_text=_("for preview."), ) status = models.StatusField( choices=STATUS_CHOICES, default=STATUS_DRAFT, help_text=_("If should be displayed or not."), ) owner = models.ForeignKey( settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.CASCADE, related_name="%(app_label)s_%(class)s_owned", verbose_name=_("owned by"), help_text=_("Post owner."), ) users = models.ManyToManyField( settings.AUTH_USER_MODEL, blank=True, related_name="%(app_label)s_%(class)s_visible", verbose_name=_("Visible only to"), help_text=_( "Post visible to these users, if empty is visible to all users."), ) event_date = models.DateTimeField( blank=True, null=True, verbose_name=_("Post date"), help_text=_("Date which post refers to."), ) pub_date_begin = models.DateTimeField( blank=True, null=True, verbose_name=_("Publication date begin"), help_text=_("When post publication date begins."), ) pub_date_end = models.DateTimeField( blank=True, null=True, verbose_name=_("Publication date end"), help_text=_("When post publication date ends."), ) title = models.StringField(unique=True, verbose_name=_("Title")) slug = models.SlugField(unique=True, verbose_name=_("Slug field")) abstract = models.TextField( blank=True, verbose_name=_("Abstract"), help_text=_("A brief description of the post"), ) text = models.TextField(blank=True, verbose_name=_("Default text")) note = models.TextField(blank=True, verbose_name=_("Note")) class Meta: abstract = True unique_together = [("title", "slug")] def __str__(self): return self.title def save(self, *args, **kwargs): self.slug = slugify(self.title) now = timezone.now() if not self.event_date and self.status == PostModel.STATUS_PUBLISHED: self.event_date = now if not self.pub_date_begin and self.status == PostModel.STATUS_PUBLISHED: self.pub_date_begin = now if not self.uuid: self.uuid = uuid1() super().save(*args, **kwargs) @property def next(self): return (self._meta.model.objects.filter( status=self.status, pub_date_begin__gt=self.pub_date_begin).order_by( "pub_date_begin").first()) @property def prev(self): return (self._meta.model.objects.filter( status=self.status, pub_date_begin__lt=self.pub_date_begin).order_by( "pub_date_begin").first())
class Log(models.Model): NOTSET = "notset" DEBUG = "debug" INFO = "info" WARNING = "warning" ERROR = "error" CRITICAL = "critical" objects = LogManager() user = models.ForeignKey( settings.AUTH_USER_MODEL, blank=True, null=True, verbose_name=_("user"), ) timestamp = models.CreationDateTimeField( null=True, blank=True, verbose_name=_("timestamp"), ) level = models.CharField( max_length=255, default=NOTSET, choices=( (NOTSET, _("Not set")), (DEBUG, _("Debug")), (INFO, _("Info")), (WARNING, _("Warning")), (ERROR, _("Error")), (CRITICAL, _("Critical")), ), verbose_name=_("level"), ) content_type = models.ForeignKey( ContentType, blank=True, null=True, verbose_name=_("content type"), ) object_id = models.TextField( default="", blank=True, #null=True, verbose_name=_("object id"), ) object_repr = models.CharField( max_length=255, default="", blank=True, verbose_name=_("object repr"), ) message = models.TextField( default="", blank=True, verbose_name=_("message"), ) realm = models.TextField( blank=True, null=True, verbose_name=_("realm"), help_text=_("realm"), ) class Meta: ordering = ["-timestamp"] verbose_name = _("log") verbose_name_plural = _("logs") def __str__(self): msg = ugettext("{timestamp} {level} {message}") return msg.format( timestamp=self.timestamp, level=self.level, message=self.message[:255], )