view PersonasBackend/personas/models.py @ 10:fd3e24f5ba18

Added some meta information to models, made save() method of Revision raise an error if client code attempts to modify a revision.
author Atul Varma <varmaa@toolness.com>
date Fri, 15 Feb 2008 04:24:00 -0600
parents d7e7916c7c34
children 2b9ce9a2ba72
line wrap: on
line source

from django.db import models

class User(models.Model):
    name = models.CharField(
        "Name of the user",
        maxlength=100,
        help_text="This is the user's Mozilla ID.",
        )

    def __str__(self):
        return self.name

class Category(models.Model):
    class Meta:
        verbose_name_plural = "categories"

    name = models.CharField(
        "Category name",
        maxlength=50,
        unique=True,
        )

    def __str__(self):
        return self.name

class Persona(models.Model):
    MAX_NAME_LENGTH = 50

    name = models.CharField(
        "Title of the Persona",
        maxlength=MAX_NAME_LENGTH,
        blank=False,
        )

    category = models.ForeignKey(
        Category,
        verbose_name="Category that the Persona is filed under",
        related_name="personas",
        null=False,
        )

    description = models.TextField(
        "Description of the Persona",
        help_text = "HTML is allowed.",
        # TODO: Really allow blank descriptions?
        blank=True,
        )

    header_img = models.URLField(
        "Header image for the Persona",
        help_text=("URL for the image that will be placed behind "
                   "the browser's top chrome.  Only needs to be "
                   "provided if no URL for the Persona is supplied."),
        verify_exists=True,
        blank=True,
        )

    footer_img = models.URLField(
        "Footer image for the Persona",
        help_text=("URL for the image that will be placed behind "
                   "the browser's bottom chrome.  Only needs to be "
                   "provided if no URL for the Persona is supplied."),
        verify_exists=True,
        blank=True,
        )

    url = models.URLField(
        "URL for the Persona",
        help_text=("URL for the Persona.  Only needs to be provided "
                   "if no header/footer image for the Persona is "
                   "supplied."),
        verify_exists=True,
        blank=True,
        )

    update_interval = models.TimeField(
        "Update interval for the Persona's URL",
        help_text=("The time interval between which the Persona's "
                    "URL will be refreshed.  This field only needs to "
                    "be provided if the URL for the Persona is "
                    "supplied."),
        null=True,
        )

    MAX_COLOR_SCHEME_LENGTH = 10

    color_scheme = models.CharField(
        "The Persona's color scheme",
        help_text=("If 'light', any text displayed over the "
                   "Persona will be dark.  If 'dark', any text "
                   "displayed over the Persona will be light."),
        maxlength=MAX_COLOR_SCHEME_LENGTH,
        choices=(("light", "Light"),
                 ("dark", "Dark")),
        blank=False,
        )

    date_updated = models.DateTimeField(
        "Update date for this revision",
        auto_now=True,
        null=False,
        )

    updater = models.ForeignKey(
        User,
        verbose_name="User who made this revision",
        related_name="personas",
        null=True,
        )

    revision = models.PositiveIntegerField(
        "Revision number for the Persona",
        help_text=("This number is incremented whenever the Persona "
                   "is changed."),
        null=False,
        )

    MAX_STATUS_LENGTH = 10

    status = models.CharField(
        "Current status of the Persona",
        maxlength=MAX_STATUS_LENGTH,
        choices=(("published", "Published"),
                 ("deleted", "Deleted")),
        blank=False,
        default="published",
        )

    def __str__(self):
        return self.name

    VERSIONED_PROPERTIES = [
        "name",
        "category",
        "description",
        "header_img",
        "footer_img",
        "url",
        "update_interval",
        "color_scheme",
        "status",
        ]

    def __makeNewRevision(self):
        """
        Detect if any of our versioned properties have changed, and if
        so, make a new revision.
        """

        original = Persona.objects.get(id=self.id)

        assert original.revision == self.revision
        assert original.date_updated == self.date_updated

        delta = {}
        for attr in self.VERSIONED_PROPERTIES:
            origValue = getattr(original, attr)
            newValue = getattr(self, attr)
            if origValue != newValue:
                delta[attr] = origValue
        if delta:
            rev = Revision(
                revision_of = original,
                date_updated = original.date_updated,
                updater = original.updater,
                revision = original.revision
                )

            for attr in delta:
                setattr(rev, attr, delta[attr])
            rev.save()

            self.revision += 1

    def save(self):
        """
        Saves the object.  If a versioned property is changed, a new
        revision is generated automatically.

        Example:

          >>> p = Persona(name='Test Persona',
          ...             description='Thos is a test.',
          ...             category=Category.objects.get(name='General'))
          >>> p.save()
          >>> p.revision
          0
          >>> p.revisions.all()
          []

          >>> p.description = 'This is a test.'
          >>> p.save()
          >>> p.revision
          1
          >>> p.revisions.all()
          [<Revision: Test Persona - r0>]
          >>> p.revisions.get(revision=0).description
          'Thos is a test.'
        """

        if self.id == None:
            self.revision = 0
        else:
            self.__makeNewRevision()

        super(Persona, self).save()

class Revision(models.Model):
    class Meta:
        unique_together = (("revision_of", "revision"),)

    # Auto-generated fields

    revision_of = models.ForeignKey(
        Persona,
        verbose_name="The Persona that this record is an old revision of",
        related_name="revisions",
        null=False,
        )

    date_updated = models.DateTimeField(
        null=False,
        )

    updater = models.ForeignKey(
        User,
        related_name="revisions",
        null=True,
        )

    revision = models.PositiveIntegerField(
        null=False,
        )

    # Versioned fields

    name = models.CharField(
        maxlength=Persona.MAX_NAME_LENGTH,
        null=True,
        )

    category = models.ForeignKey(
        Category,
        related_name="revisions",
        null=True,
        )

    description = models.TextField(
        null=True,
        )

    header_img = models.URLField(
        null=True,
        )

    footer_img = models.URLField(
        null=True,
        )

    url = models.URLField(
        null=True,
        )

    update_interval = models.TimeField(
        null=True,
        )

    color_scheme = models.CharField(
        maxlength=Persona.MAX_COLOR_SCHEME_LENGTH,
        null=True,
        )

    status = models.CharField(
        maxlength=Persona.MAX_STATUS_LENGTH,
        null=True,
        )

    def __str__(self):
        return "%s - r%s" % (self.revision_of.name, self.revision)

    def save(self):
        """
        The save method for a Revision can only be called once,
        because Revision objects are meant to be immutable:

          >>> p = Persona(name='Test Persona',
          ...             category=Category.objects.get(name='General'))
          >>> p.save()
          >>> p.description = 'This is a test.'
          >>> p.save()
          >>> r = p.revisions.get(revision=0)
          >>> r.status = "deleted"
          >>> r.save()
          Traceback (most recent call last):
          ...
          AssertionError: Revisions are immutable
        """

        if self.id == None:
            super(Revision, self).save()
        else:
            raise AssertionError( "Revisions are immutable" )