svthalia/concrexit

View on GitHub
website/newsletters/models.py

Summary

Maintainability
A
0 mins
Test Coverage
"""The models defined by the newsletters package."""
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from tinymce.models import HTMLField


def newsletter_filename(instance, filename):
    """Return path to store rendered newsletters."""
    return f"newsletters/{instance.pk}.html"


class Newsletter(models.Model):
    """Describes a newsletter."""

    title = models.CharField(
        max_length=150,
        verbose_name=_("Title"),
        help_text=_("The title is used for the email subject."),
        blank=False,
    )

    date = models.DateField(
        verbose_name=_("Date"),
        help_text=_(
            "This date is used to extract the week of this "
            "newsletter, best scenario:"
            "always use the monday of the week the newsletter is "
            "for. If you leave it empty no week is shown."
        ),
        blank=True,
        null=True,
    )

    send_date = models.DateTimeField(
        verbose_name=_("Send date"),
        blank=True,
        null=True,
    )

    description = HTMLField(
        verbose_name=_("Introduction"),
        help_text=_(
            "This is the text that starts the newsletter. It always "
            'begins with "Dear members" and you can append '
            "whatever you want."
        ),
        blank=False,
    )

    sent = models.BooleanField(default=False)

    rendered_file = models.FileField(
        upload_to=newsletter_filename,
        null=True,
    )

    def get_absolute_url(self):
        return reverse("newsletters:preview", args=(self.pk,))

    def clean(self):
        super().clean()

        errors = {}
        url = "admin/newsletters/"
        if url in self.description:
            errors.update(
                {
                    "description": _(
                        "Please make sure all urls are absolute "
                        "and contain http(s)://."
                    )
                }
            )
        if self.send_date and self.send_date <= timezone.now():
            errors.update(
                {"send_date": _("Please make sure the send date is not in the past.")}
            )

        if errors:
            raise ValidationError(errors)

    class Meta:
        permissions = (("send_newsletter", "Can send newsletter"),)

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


class NewsletterContent(models.Model):
    """Describes one piece of basic content of a newsletter."""

    title = models.CharField(
        max_length=150,
        verbose_name=_("Title"),
        blank=False,
        null=False,
    )

    url = models.URLField(
        verbose_name=_("URL"),
        blank=True,
        null=True,
        help_text=_("If filled, it will make the title a link to this URL"),
    )

    description = HTMLField(
        verbose_name=_("Description"),
        blank=False,
        null=False,
    )

    newsletter = models.ForeignKey(Newsletter, on_delete=models.CASCADE)

    order = models.PositiveIntegerField(
        verbose_name=_("order"), blank=False, null=True, default=0
    )

    def clean(self):
        super().clean()

        errors = {}
        url = "admin/newsletters/"
        if url in self.description:
            errors.update(
                {
                    "description": _(
                        "Please make sure all urls are absolute "
                        "and start with http(s)://."
                    )
                }
            )

        if errors:
            raise ValidationError(errors)

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

    class Meta:
        ordering = ("order",)


class NewsletterItem(NewsletterContent):
    """Describes one piece of text content of a newsletter."""


class NewsletterEvent(NewsletterContent):
    """Describes one piece of event content of a newsletter."""

    where = models.CharField(
        max_length=150,
        verbose_name=_("Where"),
        blank=False,
        null=False,
    )

    start_datetime = models.DateTimeField(
        verbose_name=_("Start date and time"),
        blank=False,
        null=False,
    )

    end_datetime = models.DateTimeField(
        verbose_name=_("End date and time"),
        blank=False,
        null=False,
    )

    show_costs_warning = models.BooleanField(
        verbose_name=_("Show warnings about costs"), default=True
    )

    price = models.DecimalField(
        verbose_name=_("Price (in Euro)"),
        max_digits=8,
        decimal_places=2,
        blank=True,
        null=True,
        default=None,
    )

    penalty_costs = models.DecimalField(
        verbose_name=_("Costs (in Euro)"),
        max_digits=8,
        decimal_places=2,
        blank=True,
        null=True,
        default=None,
        help_text=_(
            "This is the price that a member has to pay when he/she did not show up."
        ),
    )

    def clean(self):
        """Make sure that the event end date is after the start date."""
        super().clean()
        if (
            self.end_datetime is not None
            and self.start_datetime is not None
            and self.end_datetime < self.start_datetime
        ):
            raise ValidationError(
                {"end_datetime": _("Can't have an event travel back in time")}
            )