mirror of
https://github.com/postgres/pgweb.git
synced 2025-07-29 11:59:36 +00:00
Get rid of PgModel, replacing it with simple signals
We were already using signals for everything except delete, and even in our old version of django the delete signal exists (it didn't exist when this code was first written). Django doesn't really like models to be OOP like this, so keeping PgModel would cause issues with upcoming changes in django 1.8. Using simple functions is easier, and the actual functionality is replicated straight off.
This commit is contained in:
@ -38,13 +38,11 @@ not accidentally committed to the main repository, or cause merge conflicts.
|
||||
|
||||
Forms
|
||||
-----
|
||||
There are some special things to consider when dealing with forms. For
|
||||
here are some special things to consider when dealing with forms. For
|
||||
any objects that are going to be moderated, the Model that is used
|
||||
should inherit from the PgModel model, instead of just the regular
|
||||
django.db.models.Model. When this is done, the send_notification
|
||||
attribute should be set to True. This will cause the system to
|
||||
automatically send out notifications to the slaves list whenever a new
|
||||
object is created or an existing one is modified.
|
||||
should set the send_notification attribute to True. This will cause
|
||||
the system to automatically send out notifications to the slaves list
|
||||
whenever a new object is created or an existing one is modified.
|
||||
|
||||
If the form contains any text fields that accept markdown, the
|
||||
attribute markdown_fields should be set to a tuple containing a list
|
||||
@ -75,12 +73,6 @@ auth.py
|
||||
This module implements the community login provider for logging into
|
||||
both the website itself and the admin interface.
|
||||
|
||||
bases.py
|
||||
++++++++
|
||||
This module implements base classes to inherit from. Specifically, it
|
||||
implements the PgModel base class that is used to automatically
|
||||
generate notifications.
|
||||
|
||||
contexts.py
|
||||
+++++++++++
|
||||
This module implements custom contexts, which is used to implement the
|
||||
|
@ -45,7 +45,7 @@ done by using the @cache() decorator on the view method. Caching
|
||||
should be kept lower for pages that have frequently updating data,
|
||||
such as the front page or the survey results page.
|
||||
|
||||
Any model inheriting from PgModel can define a tuple or a function
|
||||
Any model can define a tuple or a function
|
||||
called *purge_urls* (if it's a function, it will be called and
|
||||
should return a tuple or a generator). Each entry is a regular
|
||||
expression, and this data will be automatically removed from the
|
||||
|
@ -1,9 +1,7 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from pgweb.util.bases import PgModel
|
||||
|
||||
class ContributorType(PgModel, models.Model):
|
||||
class ContributorType(models.Model):
|
||||
typename = models.CharField(max_length=32, null=False, blank=False)
|
||||
sortorder = models.IntegerField(null=False, default=100)
|
||||
extrainfo = models.TextField(null=True, blank=True)
|
||||
@ -17,7 +15,7 @@ class ContributorType(PgModel, models.Model):
|
||||
class Meta:
|
||||
ordering = ('sortorder',)
|
||||
|
||||
class Contributor(PgModel, models.Model):
|
||||
class Contributor(models.Model):
|
||||
ctype = models.ForeignKey(ContributorType)
|
||||
lastname = models.CharField(max_length=100, null=False, blank=False)
|
||||
firstname = models.CharField(max_length=100, null=False, blank=False)
|
||||
|
@ -1,6 +1,5 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from pgweb.util.bases import PgModel
|
||||
from pgweb.util.misc import varnish_purge
|
||||
|
||||
from datetime import datetime
|
||||
@ -13,7 +12,7 @@ TESTING_CHOICES = (
|
||||
)
|
||||
TESTING_SHORTSTRING = ('', 'rc', 'beta', 'alpha')
|
||||
|
||||
class Version(PgModel, models.Model):
|
||||
class Version(models.Model):
|
||||
tree = models.DecimalField(max_digits=3, decimal_places=1, null=False, blank=False, unique=True)
|
||||
latestminor = models.IntegerField(null=False, blank=False, default=0, help_text="For testing versions, latestminor means latest beta/rc number. For other releases, it's the latest minor release number in the tree.")
|
||||
reldate = models.DateField(null=False, blank=False)
|
||||
@ -113,7 +112,7 @@ class OrganisationType(models.Model):
|
||||
def __unicode__(self):
|
||||
return self.typename
|
||||
|
||||
class Organisation(PgModel, models.Model):
|
||||
class Organisation(models.Model):
|
||||
name = models.CharField(max_length=100, null=False, blank=False, unique=True)
|
||||
approved = models.BooleanField(null=False, default=False)
|
||||
address = models.TextField(null=False, blank=True)
|
||||
|
@ -1,6 +1,5 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from pgweb.util.bases import PgModel
|
||||
from pgweb.core.models import Version
|
||||
|
||||
from datetime import datetime
|
||||
@ -24,7 +23,7 @@ class DocPage(models.Model):
|
||||
# Index file first, because we want to list versions by file
|
||||
unique_together = [('file', 'version')]
|
||||
|
||||
class DocComment(PgModel, models.Model):
|
||||
class DocComment(models.Model):
|
||||
version = models.DecimalField(max_digits=3, decimal_places=1, null=False)
|
||||
file = models.CharField(max_length=64, null=False, blank=False)
|
||||
comment = models.TextField(null=False, blank=False)
|
||||
|
@ -1,5 +1,4 @@
|
||||
from django.db import models
|
||||
from pgweb.util.bases import PgModel
|
||||
|
||||
from pgweb.core.models import Organisation
|
||||
|
||||
@ -74,7 +73,7 @@ class LicenceType(models.Model):
|
||||
class Meta:
|
||||
ordering = ('typename',)
|
||||
|
||||
class Product(PgModel, models.Model):
|
||||
class Product(models.Model):
|
||||
name = models.CharField(max_length=100, null=False, blank=False, unique=True)
|
||||
approved = models.BooleanField(null=False, default=False)
|
||||
org = models.ForeignKey(Organisation, db_column="publisher_id", null=False, verbose_name="Organisation")
|
||||
|
@ -1,9 +1,8 @@
|
||||
from django.db import models
|
||||
from pgweb.util.bases import PgModel
|
||||
|
||||
from core.models import Country, Language, Organisation
|
||||
|
||||
class Event(PgModel, models.Model):
|
||||
class Event(models.Model):
|
||||
approved = models.BooleanField(null=False, blank=False, default=False)
|
||||
|
||||
org = models.ForeignKey(Organisation, null=False, blank=False, verbose_name="Organisation", help_text="If no organisations are listed, please check the <a href=\"/account/orglist/\">organisation list</a> and contact the organisation manager or webmaster@postgresql.org if none are listed.")
|
||||
|
@ -1,7 +1,5 @@
|
||||
from django.db import models
|
||||
|
||||
from pgweb.util.bases import PgModel
|
||||
|
||||
choices_map = {
|
||||
0: {'str': 'No', 'class': 'no', 'bgcolor': '#ffdddd'},
|
||||
1: {'str': 'Yes', 'class': 'yes', 'bgcolor': '#ddffdd'},
|
||||
@ -10,7 +8,7 @@ choices_map = {
|
||||
}
|
||||
choices = [(k, v['str']) for k,v in choices_map.items()]
|
||||
|
||||
class FeatureGroup(PgModel, models.Model):
|
||||
class FeatureGroup(models.Model):
|
||||
groupname = models.CharField(max_length=100, null=False, blank=False)
|
||||
groupsort = models.IntegerField(null=False, blank=False)
|
||||
|
||||
@ -29,7 +27,7 @@ class FeatureMatrixField(models.IntegerField):
|
||||
super(FeatureMatrixField, self).__init__(null=False, blank=False, default=0, verbose_name=verbose_name, choices=choices)
|
||||
self.visible_default = visible_default
|
||||
|
||||
class Feature(PgModel, models.Model):
|
||||
class Feature(models.Model):
|
||||
group = models.ForeignKey(FeatureGroup, null=False, blank=False)
|
||||
featurename = models.CharField(max_length=100, null=False, blank=False)
|
||||
featuredescription = models.TextField(null=False, blank=True)
|
||||
|
@ -1,8 +1,6 @@
|
||||
from django.db import models
|
||||
|
||||
from pgweb.util.bases import PgModel
|
||||
|
||||
class MailingListGroup(PgModel, models.Model):
|
||||
class MailingListGroup(models.Model):
|
||||
groupname = models.CharField(max_length=64, null=False, blank=False)
|
||||
sortkey = models.IntegerField(null=False, default=10)
|
||||
|
||||
@ -18,7 +16,7 @@ class MailingListGroup(PgModel, models.Model):
|
||||
class Meta:
|
||||
ordering = ('sortkey', )
|
||||
|
||||
class MailingList(PgModel, models.Model):
|
||||
class MailingList(models.Model):
|
||||
group = models.ForeignKey(MailingListGroup, null=False)
|
||||
listname = models.CharField(max_length=64, null=False, blank=False)
|
||||
active = models.BooleanField(null=False, default=False)
|
||||
|
@ -1,9 +1,8 @@
|
||||
from django.db import models
|
||||
from datetime import date
|
||||
from pgweb.core.models import Organisation
|
||||
from pgweb.util.bases import PgModel
|
||||
|
||||
class NewsArticle(PgModel, models.Model):
|
||||
class NewsArticle(models.Model):
|
||||
org = models.ForeignKey(Organisation, null=False, blank=False, verbose_name="Organisation", help_text="If no organisations are listed, please check the <a href=\"/account/orglist/\">organisation list</a> and contact the organisation manager or webmaster@postgresql.org if none are listed.")
|
||||
approved = models.BooleanField(null=False, blank=False, default=False)
|
||||
date = models.DateField(null=False, blank=False, default=date.today)
|
||||
|
@ -1,9 +1,8 @@
|
||||
from django.db import models
|
||||
|
||||
from pgweb.core.models import Organisation
|
||||
from pgweb.util.bases import PgModel
|
||||
|
||||
class ProfessionalService(PgModel, models.Model):
|
||||
class ProfessionalService(models.Model):
|
||||
approved = models.BooleanField(null=False, blank=False, default=False)
|
||||
|
||||
org = models.ForeignKey(Organisation, null=False, blank=False, unique=True,
|
||||
|
@ -1,7 +1,6 @@
|
||||
from django.db import models
|
||||
from pgweb.util.bases import PgModel
|
||||
|
||||
class PUG(PgModel, models.Model):
|
||||
class PUG(models.Model):
|
||||
"""
|
||||
contains information about a local PostgreSQL user group
|
||||
"""
|
||||
|
@ -1,10 +1,8 @@
|
||||
from django.db import models
|
||||
|
||||
from pgweb.util.bases import PgModel
|
||||
|
||||
from datetime import date
|
||||
|
||||
class PwnPost(PgModel, models.Model):
|
||||
class PwnPost(models.Model):
|
||||
date = models.DateField(null=False, blank=False, default=date.today, unique=True)
|
||||
intro = models.TextField(null=False, blank=False)
|
||||
content = models.TextField(null=False, blank=False)
|
||||
|
@ -1,7 +1,6 @@
|
||||
from django.db import models
|
||||
from pgweb.util.bases import PgModel
|
||||
|
||||
class Quote(PgModel, models.Model):
|
||||
class Quote(models.Model):
|
||||
approved = models.BooleanField(null=False, default=False)
|
||||
quote = models.TextField(null=False, blank=False)
|
||||
who = models.CharField(max_length=100, null=False, blank=False)
|
||||
|
@ -2,9 +2,7 @@ from django.db import models
|
||||
|
||||
from core.models import Country
|
||||
|
||||
from pgweb.util.bases import PgModel
|
||||
|
||||
class SponsorType(PgModel, models.Model):
|
||||
class SponsorType(models.Model):
|
||||
typename = models.CharField(max_length=32, null=False, blank=False)
|
||||
description = models.TextField(null=False, blank=False)
|
||||
sortkey = models.IntegerField(null=False, default=10)
|
||||
@ -18,7 +16,7 @@ class SponsorType(PgModel, models.Model):
|
||||
class Meta:
|
||||
ordering = ('sortkey', )
|
||||
|
||||
class Sponsor(PgModel, models.Model):
|
||||
class Sponsor(models.Model):
|
||||
sponsortype = models.ForeignKey(SponsorType, null=False)
|
||||
name = models.CharField(max_length=128, null=False, blank=False)
|
||||
url = models.URLField(null=False, blank=False)
|
||||
@ -33,7 +31,7 @@ class Sponsor(PgModel, models.Model):
|
||||
class Meta:
|
||||
ordering = ('name', )
|
||||
|
||||
class Server(PgModel, models.Model):
|
||||
class Server(models.Model):
|
||||
name = models.CharField(max_length=32, null=False, blank=False)
|
||||
sponsors = models.ManyToManyField(Sponsor)
|
||||
dedicated = models.BooleanField(null=False, default=True)
|
||||
|
@ -1,7 +1,5 @@
|
||||
from django.db import models
|
||||
|
||||
from pgweb.util.bases import PgModel
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
# internal text/value object
|
||||
@ -15,7 +13,7 @@ class SurveyAnswerValues(object):
|
||||
self.votes = votes
|
||||
self.votespercent = votespercent
|
||||
|
||||
class Survey(PgModel, models.Model):
|
||||
class Survey(models.Model):
|
||||
question = models.CharField(max_length=500, null=False, blank=False)
|
||||
opt1 = models.CharField(max_length=500, null=False, blank=False)
|
||||
opt2 = models.CharField(max_length=500, null=False, blank=False)
|
||||
@ -81,7 +79,7 @@ class Survey(PgModel, models.Model):
|
||||
# free to save this one.
|
||||
super(Survey, self).save()
|
||||
|
||||
class SurveyAnswer(PgModel, models.Model):
|
||||
class SurveyAnswer(models.Model):
|
||||
survey = models.ForeignKey(Survey, null=False, blank=False, primary_key=True)
|
||||
tot1 = models.IntegerField(null=False, default=0)
|
||||
tot2 = models.IntegerField(null=False, default=0)
|
||||
|
@ -2,7 +2,7 @@ from django.conf.urls.defaults import *
|
||||
from django.views.generic.simple import redirect_to
|
||||
|
||||
# Register our save signal handlers
|
||||
from pgweb.util.bases import register_basic_signal_handlers
|
||||
from pgweb.util.signals import register_basic_signal_handlers
|
||||
register_basic_signal_handlers()
|
||||
|
||||
# Uncomment the next two lines to enable the admin:
|
||||
|
@ -1,176 +0,0 @@
|
||||
from django.db.models.signals import pre_save, post_save
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
from util.middleware import get_current_user
|
||||
from util.misc import varnish_purge
|
||||
from mailqueue.util import send_simple_mail
|
||||
|
||||
class PgModel(object):
|
||||
send_notification = False
|
||||
purge_urls = ()
|
||||
notify_fields = None
|
||||
modifying_user = None
|
||||
|
||||
def PostSaveHandler(self):
|
||||
"""
|
||||
If a set of URLs are available as purge_urls, then send commands
|
||||
to the cache to purge those urls.
|
||||
"""
|
||||
if callable(self.purge_urls):
|
||||
purgelist = self.purge_urls()
|
||||
else:
|
||||
if not self.purge_urls: return
|
||||
purgelist = self.purge_urls
|
||||
map(varnish_purge, purgelist)
|
||||
|
||||
|
||||
def PreSaveHandler(self):
|
||||
"""If send_notification is set to True, send a default formatted notification mail"""
|
||||
|
||||
if not self.send_notification:
|
||||
return
|
||||
|
||||
(subj, cont) = self._get_changes_texts()
|
||||
|
||||
if not cont:
|
||||
# If any of these come back as None, it means that nothing actually changed,
|
||||
# or that we don't care to send out notifications about it.
|
||||
return
|
||||
|
||||
cont = self._build_url() + "\n\n" + cont
|
||||
|
||||
|
||||
# Build the mail text
|
||||
send_simple_mail(settings.NOTIFICATION_FROM,
|
||||
settings.NOTIFICATION_EMAIL,
|
||||
"%s by %s" % (subj, get_current_user()),
|
||||
cont)
|
||||
|
||||
def delete(self):
|
||||
# We can't compare the object, but we should be able to construct something anyway
|
||||
if self.send_notification:
|
||||
subject = "%s id %s has been deleted by %s" % (
|
||||
self._meta.verbose_name,
|
||||
self.id,
|
||||
get_current_user())
|
||||
|
||||
send_simple_mail(settings.NOTIFICATION_FROM,
|
||||
settings.NOTIFICATION_EMAIL,
|
||||
subject,
|
||||
self.full_text_representation())
|
||||
|
||||
# Now call our super to actually delete the object
|
||||
super(PgModel, self).delete()
|
||||
|
||||
def _get_changes_texts(self):
|
||||
try:
|
||||
oldobj = self.__class__.objects.get(pk=self.pk)
|
||||
except self.DoesNotExist:
|
||||
return ('A new %s has been added' % self._meta.verbose_name, self.full_text_representation())
|
||||
if hasattr(self,'approved'):
|
||||
# This object has the capability to do approving. Apply the following logic:
|
||||
# 1. If object was unapproved, and is still unapproved, don't send notification
|
||||
# 2. If object was unapproved, and is now approved, send "object approved" notification
|
||||
# 3. If object was approved, and is no longer approved, send "object unapproved" notification
|
||||
# 4. (FIXME: configurable?) If object was approved and is still approved, send changes notification
|
||||
if not self.approved:
|
||||
if not oldobj.approved:
|
||||
# Still unapproved, just accept the changes
|
||||
return (None, None)
|
||||
# Went from approved to unapproved
|
||||
return ('%s id %s has been unapproved' % (self._meta.verbose_name, self.id), self.full_text_representation())
|
||||
else:
|
||||
if not oldobj.approved:
|
||||
# Object went from unapproved to approved
|
||||
return ('%s id %s has been approved' % (self._meta.verbose_name, self.id),
|
||||
self.full_text_representation())
|
||||
# Object contents have changed. Generate a diff!
|
||||
diff = self.full_text_diff(oldobj)
|
||||
if not diff:
|
||||
return (None, None)
|
||||
return ('%s id %s has been modified' % (self._meta.verbose_name, self.id),
|
||||
"The following fields have been modified:\n\n%s" % diff)
|
||||
else:
|
||||
# If there is no approved field, but send_notifications was set
|
||||
# to True, we notify on all changes.
|
||||
diff = self.full_text_diff(oldobj)
|
||||
if not diff:
|
||||
return (None, None)
|
||||
return ('%s id %s has been modified' % (self._meta.verbose_name, self.id),
|
||||
"The following fields have been modified:\n\n%s" % diff)
|
||||
|
||||
def _get_all_notification_fields(self):
|
||||
if self.notify_fields:
|
||||
return self.notify_fields
|
||||
else:
|
||||
# Include all field names except specified ones, that are "direct" (by get_field_by_name()[2])
|
||||
return [n for n in self._meta.get_all_field_names() if not n in ('approved', 'submitter', 'id', ) and self._meta.get_field_by_name(n)[2]]
|
||||
|
||||
def full_text_representation(self):
|
||||
fieldlist = self._get_all_notification_fields()
|
||||
if not fieldlist:
|
||||
return "This object does not know how to express itself."
|
||||
|
||||
return "\n".join([u'%s: %s' % (n, self._get_attr_value(n)) for n in fieldlist])
|
||||
|
||||
def _get_attr_value(self, fieldname):
|
||||
try:
|
||||
# see if this is a Many-to-many field, if yes, we want to print out a pretty list
|
||||
value = getattr(self, fieldname)
|
||||
if isinstance(self._meta.get_field_by_name(fieldname)[0], models.ManyToManyField):
|
||||
return ", ".join(map(lambda x: unicode(x), value.all()))
|
||||
return value
|
||||
except ValueError, v:
|
||||
# NOTE! If the object is brand new, and it has a many-to-many relationship, we can't
|
||||
# access this data yet. So just return that it's not available yet.
|
||||
# XXX: This is an ugly way to find it out, and is dependent on
|
||||
# the version of django used. But I've found no better way...
|
||||
if v.message.find('" needs to have a value for field "') and v.message.find('" before this many-to-many relationship can be used.') > -1:
|
||||
return "<not available yet>"
|
||||
else:
|
||||
raise v
|
||||
|
||||
def _build_url(self):
|
||||
if self.id:
|
||||
return "%s/admin/%s/%s/%s/" % (
|
||||
settings.SITE_ROOT,
|
||||
self._meta.app_label,
|
||||
self._meta.module_name,
|
||||
self.id,
|
||||
)
|
||||
else:
|
||||
return "%s/admin/%s/%s/" % (
|
||||
settings.SITE_ROOT,
|
||||
self._meta.app_label,
|
||||
self._meta.module_name,
|
||||
)
|
||||
|
||||
def full_text_diff(self, oldobj):
|
||||
fieldlist = self._get_all_notification_fields()
|
||||
if not fieldlist:
|
||||
return "This object does not know how to express ifself."
|
||||
|
||||
s = "\n\n".join(["%s from: %s\n%s to: %s" % (
|
||||
n,
|
||||
oldobj._get_attr_value(n),
|
||||
n,
|
||||
self._get_attr_value(n),
|
||||
) for n in fieldlist if oldobj._get_attr_value(n) != self._get_attr_value(n)])
|
||||
if not s: return None
|
||||
return s
|
||||
|
||||
|
||||
def my_pre_save_handler(sender, **kwargs):
|
||||
instance = kwargs['instance']
|
||||
if isinstance(instance, PgModel):
|
||||
instance.PreSaveHandler()
|
||||
|
||||
def my_post_save_handler(sender, **kwargs):
|
||||
instance = kwargs['instance']
|
||||
if isinstance(instance, PgModel):
|
||||
instance.PostSaveHandler()
|
||||
|
||||
def register_basic_signal_handlers():
|
||||
pre_save.connect(my_pre_save_handler)
|
||||
post_save.connect(my_post_save_handler)
|
145
pgweb/util/signals.py
Normal file
145
pgweb/util/signals.py
Normal file
@ -0,0 +1,145 @@
|
||||
from django.db.models.signals import pre_save, post_save, pre_delete
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
from util.middleware import get_current_user
|
||||
from util.misc import varnish_purge
|
||||
from mailqueue.util import send_simple_mail
|
||||
|
||||
def _build_url(obj):
|
||||
if obj.id:
|
||||
return "%s/admin/%s/%s/%s/" % (
|
||||
settings.SITE_ROOT,
|
||||
obj._meta.app_label,
|
||||
obj._meta.module_name,
|
||||
obj.id,
|
||||
)
|
||||
else:
|
||||
return "%s/admin/%s/%s/" % (
|
||||
settings.SITE_ROOT,
|
||||
obj._meta.app_label,
|
||||
obj._meta.module_name,
|
||||
)
|
||||
|
||||
def _get_full_text_diff(obj, oldobj):
|
||||
fieldlist = _get_all_notification_fields(obj)
|
||||
if not fieldlist:
|
||||
return "This object does not know how to express ifself."
|
||||
|
||||
s = "\n\n".join(["%s from: %s\n%s to: %s" % (
|
||||
n,
|
||||
_get_attr_value(oldobj, n),
|
||||
n,
|
||||
_get_attr_value(obj, n),
|
||||
) for n in fieldlist if _get_attr_value(oldobj, n) != _get_attr_value(obj, n)])
|
||||
if not s: return None
|
||||
return s
|
||||
|
||||
def _get_all_notification_fields(obj):
|
||||
if hasattr(obj, 'notify_fields'):
|
||||
return obj.notify_fields
|
||||
else:
|
||||
# Include all field names except specified ones,
|
||||
# that are "direct" (by get_field_by_name()[2])
|
||||
return [n for n in obj._meta.get_all_field_names() if not n in ('approved', 'submitter', 'id', ) and obj._meta.get_field_by_name(n)[2]]
|
||||
|
||||
def _get_attr_value(obj, fieldname):
|
||||
try:
|
||||
# see if this is a Many-to-many field. If yes, we want to print
|
||||
# it out as a pretty list
|
||||
value = getattr(obj, fieldname)
|
||||
if isinstance(obj._meta.get_field_by_name(fieldname)[0], models.ManyToManyField):
|
||||
return ", ".join(map(lambda x: unicode(x), value.all()))
|
||||
return value
|
||||
except ValueError, v:
|
||||
# NOTE! If the object is brand new, and it has a many-to-many relationship, we can't
|
||||
# access this data yet. So just return that it's not available yet.
|
||||
# XXX: This is an ugly way to find it out, and is dependent on
|
||||
# the version of django used. But I've found no better way...
|
||||
if v.message.find('" needs to have a value for field "') and v.message.find('" before this many-to-many relationship can be used.') > -1:
|
||||
return "<not available yet>"
|
||||
else:
|
||||
raise v
|
||||
|
||||
def _get_full_text_representation(obj):
|
||||
fieldlist = _get_all_notification_fields(obj)
|
||||
if not fieldlist:
|
||||
return "This object does not know how to express itself."
|
||||
|
||||
return "\n".join([u'%s: %s' % (n, _get_attr_value(obj, n)) for n in fieldlist])
|
||||
|
||||
def _get_notification_text(obj):
|
||||
try:
|
||||
oldobj = obj.__class__.objects.get(pk=obj.pk)
|
||||
except obj.DoesNotExist:
|
||||
return ('A new {0} as been added'.format(obj._meta.verbose_name),
|
||||
_get_full_text_representation(obj))
|
||||
|
||||
if hasattr(obj, 'approved'):
|
||||
# This object has the capability to do approving. Apply the following logic:
|
||||
# 1. If object was unapproved, and is still unapproved, don't send notification
|
||||
# 2. If object was unapproved, and is now approved, send "object approved" notification
|
||||
# 3. If object was approved, and is no longer approved, send "object unapproved" notification
|
||||
# 4. (FIXME: configurable?) If object was approved and is still approved, send changes notification
|
||||
if not obj.approved:
|
||||
if not oldobj.approved:
|
||||
# Was approved, still approved -> no notification
|
||||
return (None, None)
|
||||
# From approved to unapproved
|
||||
return ('{0} id {1} has been unapproved'.format(obj._meta.verbose_name, obj.id),
|
||||
_get_full_text_representation(obj))
|
||||
else:
|
||||
if not oldobj.approved:
|
||||
# Object went from unapproved to approved
|
||||
return ('{0} id {1} has been approved'.format(obj._meta.verbose_name, obj.id),
|
||||
_get_full_text_representation(obj))
|
||||
# Object contents have changed. Generate a diff!
|
||||
diff = _get_full_text_diff(obj, oldobj)
|
||||
if not diff:
|
||||
return (None, None)
|
||||
return ('{0} id {1} has been modified'.format(obj._meta.verbose_name, obj.id),
|
||||
'The following fields have been modified:\n\n%s' % diff)
|
||||
else:
|
||||
# If there is no approved field, but send_notifications was set
|
||||
# to True, we notify on all changes.
|
||||
diff = _get_full_text_diff(obj, oldobj)
|
||||
if not diff:
|
||||
return (None, None)
|
||||
return ('{0} id {1} has been modified'.format(obj._meta.verbose_name, obj.id),
|
||||
'The following fields have been modified:\n\n%s' % diff)
|
||||
|
||||
def my_pre_save_handler(sender, **kwargs):
|
||||
instance = kwargs['instance']
|
||||
if getattr(instance, 'send_notification', False):
|
||||
(subj, cont) = _get_notification_text(instance)
|
||||
if cont:
|
||||
cont = _build_url(instance) + "\n\n" + cont
|
||||
send_simple_mail(settings.NOTIFICATION_FROM,
|
||||
settings.NOTIFICATION_EMAIL,
|
||||
"%s by %s" % (subj, get_current_user()),
|
||||
cont)
|
||||
|
||||
def my_pre_delete_handler(sender, **kwargs):
|
||||
instance = kwargs['instance']
|
||||
if getattr(instance, 'send_notification', False):
|
||||
send_simple_mail(settings.NOTIFICATION_FROM,
|
||||
settings.NOTIFICATION_EMAIL,
|
||||
"%s id %s has been deleted by %s" % (
|
||||
instance._meta.verbose_name,
|
||||
instance.id,
|
||||
get_current_user()),
|
||||
_get_full_text_representation(instance))
|
||||
|
||||
def my_post_save_handler(sender, **kwargs):
|
||||
instance = kwargs['instance']
|
||||
if hasattr(instance, 'purge_urls'):
|
||||
if callable(instance.purge_urls):
|
||||
purgelist = instance.purge_urls()
|
||||
else:
|
||||
purgelist = instance.purge_urls
|
||||
map(varnish_purge, purgelist)
|
||||
|
||||
def register_basic_signal_handlers():
|
||||
pre_save.connect(my_pre_save_handler)
|
||||
pre_delete.connect(my_pre_delete_handler)
|
||||
post_save.connect(my_post_save_handler)
|
Reference in New Issue
Block a user