mirror of
https://github.com/postgres/pgweb.git
synced 2025-08-10 00:42:06 +00:00
Implement basic varnish purging
This allows all models inherited from PgModel to specify which URLs to purge by either setting a field or defining a function called purge_urls, at which point they will be purged whenever the save signal is fired. Also implements a form under /admin/purge/ that allows for manual purging. This should probably be extended in the future to show the status of the pgq slaves, but that will come later. Includes a SQL function that posts the expires to a pgq queue. For a local deployment, this can be replaced with a simple void function to turn off varnish purging.
This commit is contained in:
@ -1,19 +1,22 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
from pgweb.util.bases import PgModel
|
||||||
|
|
||||||
class ContributorType(models.Model):
|
class ContributorType(PgModel, models.Model):
|
||||||
typename = models.CharField(max_length=32, null=False, blank=False)
|
typename = models.CharField(max_length=32, null=False, blank=False)
|
||||||
sortorder = models.IntegerField(null=False, default=100)
|
sortorder = models.IntegerField(null=False, default=100)
|
||||||
extrainfo = models.TextField(null=True, blank=True)
|
extrainfo = models.TextField(null=True, blank=True)
|
||||||
detailed = models.BooleanField(null=False, default=True)
|
detailed = models.BooleanField(null=False, default=True)
|
||||||
|
|
||||||
|
purge_urls = ('community/contributors/', )
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.typename
|
return self.typename
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('sortorder',)
|
ordering = ('sortorder',)
|
||||||
|
|
||||||
class Contributor(models.Model):
|
class Contributor(PgModel, models.Model):
|
||||||
ctype = models.ForeignKey(ContributorType)
|
ctype = models.ForeignKey(ContributorType)
|
||||||
lastname = models.CharField(max_length=100, null=False, blank=False)
|
lastname = models.CharField(max_length=100, null=False, blank=False)
|
||||||
firstname = models.CharField(max_length=100, null=False, blank=False)
|
firstname = models.CharField(max_length=100, null=False, blank=False)
|
||||||
@ -23,6 +26,8 @@ class Contributor(models.Model):
|
|||||||
location = models.CharField(max_length=100, null=True, blank=True)
|
location = models.CharField(max_length=100, null=True, blank=True)
|
||||||
contribution = models.TextField(null=True, blank=True)
|
contribution = models.TextField(null=True, blank=True)
|
||||||
|
|
||||||
|
purge_urls = ('community/contributors/', )
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "%s %s" % (self.firstname, self.lastname)
|
return "%s %s" % (self.firstname, self.lastname)
|
||||||
|
|
||||||
|
@ -36,6 +36,11 @@ class Version(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('-tree', )
|
ordering = ('-tree', )
|
||||||
|
|
||||||
|
def purge_urls(self):
|
||||||
|
yield '/$'
|
||||||
|
yield 'versions.rss'
|
||||||
|
# FIXME: probably a lot more?
|
||||||
|
|
||||||
|
|
||||||
class Country(models.Model):
|
class Country(models.Model):
|
||||||
name = models.CharField(max_length=100, null=False, blank=False)
|
name = models.CharField(max_length=100, null=False, blank=False)
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
from django.shortcuts import render_to_response, get_object_or_404
|
from django.shortcuts import render_to_response, get_object_or_404
|
||||||
from django.http import HttpResponse, Http404
|
from django.http import HttpResponse, Http404, HttpResponseRedirect
|
||||||
from django.template import TemplateDoesNotExist, loader, Context
|
from django.template import TemplateDoesNotExist, loader, Context
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.db import connection
|
from django.db import connection, transaction
|
||||||
|
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
from os import uname
|
from os import uname
|
||||||
@ -12,7 +12,7 @@ from pgweb.util.decorators import ssl_required, cache
|
|||||||
from pgweb.util.contexts import NavContext
|
from pgweb.util.contexts import NavContext
|
||||||
from pgweb.util.helpers import simple_form, PgXmlHelper
|
from pgweb.util.helpers import simple_form, PgXmlHelper
|
||||||
from pgweb.util.moderation import get_all_pending_moderations
|
from pgweb.util.moderation import get_all_pending_moderations
|
||||||
from pgweb.util.misc import get_client_ip, is_behind_cache
|
from pgweb.util.misc import get_client_ip, is_behind_cache, varnish_purge
|
||||||
from pgweb.util.sitestruct import get_all_pages_struct
|
from pgweb.util.sitestruct import get_all_pages_struct
|
||||||
|
|
||||||
# models needed for the pieces on the frontpage
|
# models needed for the pieces on the frontpage
|
||||||
@ -147,3 +147,18 @@ def admin_pending(request):
|
|||||||
return render_to_response('core/admin_pending.html', {
|
return render_to_response('core/admin_pending.html', {
|
||||||
'app_list': get_all_pending_moderations(),
|
'app_list': get_all_pending_moderations(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Purge objects from varnish, for the admin pages
|
||||||
|
@login_required
|
||||||
|
def admin_purge(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
url = request.POST['url']
|
||||||
|
if url == '':
|
||||||
|
return HttpResponseRedirect('.')
|
||||||
|
varnish_purge(url)
|
||||||
|
transaction.commit_unless_managed()
|
||||||
|
return render_to_response('core/admin_purge.html', {
|
||||||
|
'purge_completed': '^%s' % url,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return render_to_response('core/admin_purge.html')
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from pgweb.util.bases import PgModel
|
from pgweb.util.bases import PgModel
|
||||||
|
from pgweb.core.models import Version
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
@ -24,6 +25,14 @@ class DocComment(PgModel, models.Model):
|
|||||||
|
|
||||||
send_notification = True
|
send_notification = True
|
||||||
|
|
||||||
|
def purge_urls(self):
|
||||||
|
yield '/docs/%s/interactive/%s' % (self.version, self.file)
|
||||||
|
try:
|
||||||
|
if Version.objects.get(tree=self.version).current:
|
||||||
|
yield '/docs/current/interactive/%s' % self.file
|
||||||
|
except Version.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('-posted_at',)
|
ordering = ('-posted_at',)
|
||||||
|
|
||||||
|
@ -24,6 +24,13 @@ class Event(models.Model, PgModel):
|
|||||||
send_notification = True
|
send_notification = True
|
||||||
markdown_fields = ('details', )
|
markdown_fields = ('details', )
|
||||||
|
|
||||||
|
def purge_urls(self):
|
||||||
|
yield '/about/event/%s/' % self.pk
|
||||||
|
yield '/about/eventarchive/'
|
||||||
|
yield 'events.rss'
|
||||||
|
# FIXME: when to expire the front page?
|
||||||
|
yield '/$'
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "%s: %s" % (self.startdate, self.title)
|
return "%s: %s" % (self.startdate, self.title)
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
from pgweb.util.bases import PgModel
|
||||||
|
|
||||||
choices_map = {
|
choices_map = {
|
||||||
0: {'str': 'No', 'class': 'no', 'bgcolor': '#ffdddd'},
|
0: {'str': 'No', 'class': 'no', 'bgcolor': '#ffdddd'},
|
||||||
1: {'str': 'Yes', 'class': 'yes', 'bgcolor': '#ddffdd'},
|
1: {'str': 'Yes', 'class': 'yes', 'bgcolor': '#ddffdd'},
|
||||||
@ -8,10 +10,12 @@ choices_map = {
|
|||||||
}
|
}
|
||||||
choices = [(k, v['str']) for k,v in choices_map.items()]
|
choices = [(k, v['str']) for k,v in choices_map.items()]
|
||||||
|
|
||||||
class FeatureGroup(models.Model):
|
class FeatureGroup(PgModel, models.Model):
|
||||||
groupname = models.CharField(max_length=100, null=False, blank=False)
|
groupname = models.CharField(max_length=100, null=False, blank=False)
|
||||||
groupsort = models.IntegerField(null=False, blank=False)
|
groupsort = models.IntegerField(null=False, blank=False)
|
||||||
|
|
||||||
|
purge_urls = ('about/featurematrix/', )
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.groupname
|
return self.groupname
|
||||||
|
|
||||||
@ -20,7 +24,7 @@ class FeatureGroup(models.Model):
|
|||||||
# Return a list of all the columns for the matrix
|
# Return a list of all the columns for the matrix
|
||||||
return [b for a,b in versions]
|
return [b for a,b in versions]
|
||||||
|
|
||||||
class Feature(models.Model):
|
class Feature(PgModel, models.Model):
|
||||||
group = models.ForeignKey(FeatureGroup, null=False, blank=False)
|
group = models.ForeignKey(FeatureGroup, null=False, blank=False)
|
||||||
featurename = models.CharField(max_length=100, null=False, blank=False)
|
featurename = models.CharField(max_length=100, null=False, blank=False)
|
||||||
featuredescription = models.TextField(null=False, blank=True)
|
featuredescription = models.TextField(null=False, blank=True)
|
||||||
@ -33,6 +37,8 @@ class Feature(models.Model):
|
|||||||
v84 = models.IntegerField(null=False, blank=False, default=0, verbose_name="8.4", choices=choices)
|
v84 = models.IntegerField(null=False, blank=False, default=0, verbose_name="8.4", choices=choices)
|
||||||
v85 = models.IntegerField(null=False, blank=False, default=0, verbose_name="8.5a3", choices=choices)
|
v85 = models.IntegerField(null=False, blank=False, default=0, verbose_name="8.5a3", choices=choices)
|
||||||
|
|
||||||
|
purge_urls = ('about/featurematrix/.*', )
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
# To make it look good in the admin interface, just don't render it
|
# To make it look good in the admin interface, just don't render it
|
||||||
return ''
|
return ''
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
class MailingListGroup(models.Model):
|
from pgweb.util.bases import PgModel
|
||||||
|
|
||||||
|
class MailingListGroup(PgModel, models.Model):
|
||||||
groupname = models.CharField(max_length=64, null=False, blank=False)
|
groupname = models.CharField(max_length=64, null=False, blank=False)
|
||||||
sortkey = models.IntegerField(null=False, default=10)
|
sortkey = models.IntegerField(null=False, default=10)
|
||||||
|
|
||||||
|
purge_urls = ('community/lists/', )
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.groupname
|
return self.groupname
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('sortkey', )
|
ordering = ('sortkey', )
|
||||||
|
|
||||||
class MailingList(models.Model):
|
class MailingList(PgModel, models.Model):
|
||||||
group = models.ForeignKey(MailingListGroup, null=False)
|
group = models.ForeignKey(MailingListGroup, null=False)
|
||||||
listname = models.CharField(max_length=64, null=False, blank=False)
|
listname = models.CharField(max_length=64, null=False, blank=False)
|
||||||
active = models.BooleanField(null=False, default=False)
|
active = models.BooleanField(null=False, default=False)
|
||||||
@ -18,6 +22,8 @@ class MailingList(models.Model):
|
|||||||
description = models.TextField(null=False, blank=True)
|
description = models.TextField(null=False, blank=True)
|
||||||
shortdesc = models.TextField(null=False, blank=True)
|
shortdesc = models.TextField(null=False, blank=True)
|
||||||
|
|
||||||
|
purge_urls = ('community/lists/', )
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def maybe_shortdesc(self):
|
def maybe_shortdesc(self):
|
||||||
if self.shortdesc:
|
if self.shortdesc:
|
||||||
|
@ -13,6 +13,13 @@ class NewsArticle(PgModel, models.Model):
|
|||||||
send_notification = True
|
send_notification = True
|
||||||
markdown_fields = ('content',)
|
markdown_fields = ('content',)
|
||||||
|
|
||||||
|
def purge_urls(self):
|
||||||
|
yield '/about/news/%s/' % self.pk
|
||||||
|
yield '/about/newsarchive/'
|
||||||
|
yield 'news.rss'
|
||||||
|
# FIXME: when to expire the front page?
|
||||||
|
yield '/$'
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "%s: %s" % (self.date, self.title)
|
return "%s: %s" % (self.date, self.title)
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ from django.contrib.auth.models import User
|
|||||||
from pgweb.core.models import Organisation
|
from pgweb.core.models import Organisation
|
||||||
from pgweb.util.bases import PgModel
|
from pgweb.util.bases import PgModel
|
||||||
|
|
||||||
class ProfessionalService(models.Model):
|
class ProfessionalService(PgModel, models.Model):
|
||||||
submitter = models.ForeignKey(User, null=False, blank=False)
|
submitter = models.ForeignKey(User, null=False, blank=False)
|
||||||
approved = models.BooleanField(null=False, blank=False, default=False)
|
approved = models.BooleanField(null=False, blank=False, default=False)
|
||||||
|
|
||||||
@ -28,6 +28,7 @@ class ProfessionalService(models.Model):
|
|||||||
provides_hosting = models.BooleanField(null=False, default=False)
|
provides_hosting = models.BooleanField(null=False, default=False)
|
||||||
interfaces = models.CharField(max_length=512, null=True, blank=True)
|
interfaces = models.CharField(max_length=512, null=True, blank=True)
|
||||||
|
|
||||||
|
purge_urls = ('support/professional_', )
|
||||||
|
|
||||||
send_notification = True
|
send_notification = True
|
||||||
|
|
||||||
|
@ -1,14 +1,21 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
from pgweb.util.bases import PgModel
|
||||||
|
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
||||||
class PwnPost(models.Model):
|
class PwnPost(PgModel, models.Model):
|
||||||
date = models.DateField(null=False, blank=False, default=date.today, unique=True)
|
date = models.DateField(null=False, blank=False, default=date.today, unique=True)
|
||||||
intro = models.TextField(null=False, blank=False)
|
intro = models.TextField(null=False, blank=False)
|
||||||
content = models.TextField(null=False, blank=False)
|
content = models.TextField(null=False, blank=False)
|
||||||
|
|
||||||
markdown_fields = ('intro', 'content',)
|
markdown_fields = ('intro', 'content',)
|
||||||
|
|
||||||
|
def purge_urls(self):
|
||||||
|
yield 'community/weeklynews/$'
|
||||||
|
yield 'community/weeklynews/pwn%s/' % self.linkdate()
|
||||||
|
yield 'weeklynews.rss'
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "PostgreSQL Weekly News %s" % self.date
|
return "PostgreSQL Weekly News %s" % self.date
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@ class Quote(models.Model, PgModel):
|
|||||||
|
|
||||||
send_notification = True
|
send_notification = True
|
||||||
|
|
||||||
|
purge_urls = ('about/quotesarchive/', '/$', )
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
if len(self.quote) > 75:
|
if len(self.quote) > 75:
|
||||||
return "%s..." % self.quote[:75]
|
return "%s..." % self.quote[:75]
|
||||||
|
@ -2,31 +2,37 @@ from django.db import models
|
|||||||
|
|
||||||
from core.models import Country
|
from core.models import Country
|
||||||
|
|
||||||
class SponsorType(models.Model):
|
from pgweb.util.bases import PgModel
|
||||||
|
|
||||||
|
class SponsorType(PgModel, models.Model):
|
||||||
typename = models.CharField(max_length=32, null=False, blank=False)
|
typename = models.CharField(max_length=32, null=False, blank=False)
|
||||||
description = models.TextField(null=False, blank=False)
|
description = models.TextField(null=False, blank=False)
|
||||||
sortkey = models.IntegerField(null=False, default=10)
|
sortkey = models.IntegerField(null=False, default=10)
|
||||||
|
|
||||||
|
purge_urls = ('about/servers/', 'about/sponsors/', )
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.typename
|
return self.typename
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('sortkey', )
|
ordering = ('sortkey', )
|
||||||
|
|
||||||
class Sponsor(models.Model):
|
class Sponsor(PgModel, models.Model):
|
||||||
sponsortype = models.ForeignKey(SponsorType, null=False)
|
sponsortype = models.ForeignKey(SponsorType, null=False)
|
||||||
name = models.CharField(max_length=128, null=False, blank=False)
|
name = models.CharField(max_length=128, null=False, blank=False)
|
||||||
url = models.URLField(null=False, blank=False)
|
url = models.URLField(null=False, blank=False)
|
||||||
logoname = models.CharField(max_length=64, null=False, blank=False)
|
logoname = models.CharField(max_length=64, null=False, blank=False)
|
||||||
country = models.ForeignKey(Country, null=False)
|
country = models.ForeignKey(Country, null=False)
|
||||||
|
|
||||||
|
purge_urls = ('about/sponsors/', )
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('name', )
|
ordering = ('name', )
|
||||||
|
|
||||||
class Server(models.Model):
|
class Server(PgModel, models.Model):
|
||||||
name = models.CharField(max_length=32, null=False, blank=False)
|
name = models.CharField(max_length=32, null=False, blank=False)
|
||||||
sponsors = models.ManyToManyField(Sponsor)
|
sponsors = models.ManyToManyField(Sponsor)
|
||||||
dedicated = models.BooleanField(null=False, default=True)
|
dedicated = models.BooleanField(null=False, default=True)
|
||||||
@ -35,6 +41,8 @@ class Server(models.Model):
|
|||||||
location = models.CharField(max_length=128, null=False, blank=False)
|
location = models.CharField(max_length=128, null=False, blank=False)
|
||||||
usage = models.TextField(null=False, blank=False)
|
usage = models.TextField(null=False, blank=False)
|
||||||
|
|
||||||
|
purge_urls = ('about/servers/', )
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
from pgweb.util.bases import PgModel
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
# internal text/value object
|
# internal text/value object
|
||||||
@ -14,7 +16,7 @@ class SurveyAnswerValues(object):
|
|||||||
self.votes = votes
|
self.votes = votes
|
||||||
self.votespercent = votespercent
|
self.votespercent = votespercent
|
||||||
|
|
||||||
class Survey(models.Model):
|
class Survey(PgModel, models.Model):
|
||||||
question = models.CharField(max_length=100, null=False, blank=False)
|
question = models.CharField(max_length=100, null=False, blank=False)
|
||||||
opt1 = models.CharField(max_length=100, null=False, blank=False)
|
opt1 = models.CharField(max_length=100, null=False, blank=False)
|
||||||
opt2 = models.CharField(max_length=100, null=False, blank=False)
|
opt2 = models.CharField(max_length=100, null=False, blank=False)
|
||||||
@ -27,6 +29,8 @@ class Survey(models.Model):
|
|||||||
posted = models.DateTimeField(null=False, default=datetime.now)
|
posted = models.DateTimeField(null=False, default=datetime.now)
|
||||||
current = models.BooleanField(null=False, default=False)
|
current = models.BooleanField(null=False, default=False)
|
||||||
|
|
||||||
|
purge_urls = ('community/survey', )
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.question
|
return self.question
|
||||||
|
|
||||||
@ -78,7 +82,7 @@ class Survey(models.Model):
|
|||||||
# free to save this one.
|
# free to save this one.
|
||||||
super(Survey, self).save()
|
super(Survey, self).save()
|
||||||
|
|
||||||
class SurveyAnswer(models.Model):
|
class SurveyAnswer(PgModel, models.Model):
|
||||||
survey = models.ForeignKey(Survey, null=False, blank=False, primary_key=True)
|
survey = models.ForeignKey(Survey, null=False, blank=False, primary_key=True)
|
||||||
tot1 = models.IntegerField(null=False, default=0)
|
tot1 = models.IntegerField(null=False, default=0)
|
||||||
tot2 = models.IntegerField(null=False, default=0)
|
tot2 = models.IntegerField(null=False, default=0)
|
||||||
@ -89,6 +93,8 @@ class SurveyAnswer(models.Model):
|
|||||||
tot7 = models.IntegerField(null=False, default=0)
|
tot7 = models.IntegerField(null=False, default=0)
|
||||||
tot8 = models.IntegerField(null=False, default=0)
|
tot8 = models.IntegerField(null=False, default=0)
|
||||||
|
|
||||||
|
purge_urls = ('community/survey', )
|
||||||
|
|
||||||
class SurveyLock(models.Model):
|
class SurveyLock(models.Model):
|
||||||
ipaddr = models.IPAddressField(null=False, blank=False)
|
ipaddr = models.IPAddressField(null=False, blank=False)
|
||||||
time = models.DateTimeField(null=False, default=datetime.now)
|
time = models.DateTimeField(null=False, default=datetime.now)
|
||||||
|
@ -108,6 +108,7 @@ urlpatterns = patterns('',
|
|||||||
|
|
||||||
# Override some URLs in admin, to provide our own pages
|
# Override some URLs in admin, to provide our own pages
|
||||||
(r'^admin/pending/$', 'pgweb.core.views.admin_pending'),
|
(r'^admin/pending/$', 'pgweb.core.views.admin_pending'),
|
||||||
|
(r'^admin/purge/$', 'pgweb.core.views.admin_purge'),
|
||||||
# Uncomment the next line to enable the admin:
|
# Uncomment the next line to enable the admin:
|
||||||
(r'^admin/(.*)', admin.site.root),
|
(r'^admin/(.*)', admin.site.root),
|
||||||
|
|
||||||
|
@ -1,17 +1,31 @@
|
|||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
|
|
||||||
from django.db.models.signals import pre_save
|
from django.db.models.signals import pre_save, post_save
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from util.middleware import get_current_user
|
from util.middleware import get_current_user
|
||||||
from util.misc import sendmail
|
from util.misc import sendmail, varnish_purge
|
||||||
|
|
||||||
class PgModel(object):
|
class PgModel(object):
|
||||||
send_notification = False
|
send_notification = False
|
||||||
|
purge_urls = ()
|
||||||
notify_fields = None
|
notify_fields = None
|
||||||
modifying_user = 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):
|
def PreSaveHandler(self):
|
||||||
"""If send_notification is set to True, send a default formatted notification mail"""
|
"""If send_notification is set to True, send a default formatted notification mail"""
|
||||||
|
|
||||||
@ -131,6 +145,11 @@ def my_pre_save_handler(sender, **kwargs):
|
|||||||
if isinstance(instance, PgModel):
|
if isinstance(instance, PgModel):
|
||||||
instance.PreSaveHandler()
|
instance.PreSaveHandler()
|
||||||
|
|
||||||
|
def my_post_save_handler(sender, **kwargs):
|
||||||
|
instance = kwargs['instance']
|
||||||
|
if isinstance(instance, PgModel):
|
||||||
|
instance.PostSaveHandler()
|
||||||
|
|
||||||
def register_basic_signal_handlers():
|
def register_basic_signal_handlers():
|
||||||
pre_save.connect(my_pre_save_handler)
|
pre_save.connect(my_pre_save_handler)
|
||||||
|
post_save.connect(my_post_save_handler)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
|
from django.db import connection
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from pgweb.util.helpers import template_to_string
|
from pgweb.util.helpers import template_to_string
|
||||||
@ -58,3 +59,14 @@ def get_client_ip(request):
|
|||||||
return request.META['REMOTE_ADDR']
|
return request.META['REMOTE_ADDR']
|
||||||
else:
|
else:
|
||||||
return request.META['REMOTE_ADDR']
|
return request.META['REMOTE_ADDR']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def varnish_purge(url):
|
||||||
|
"""
|
||||||
|
Purge the specified URL from Varnish. Will add initial anchor to the URL,
|
||||||
|
but no trailing one, so by default a wildcard match is done.
|
||||||
|
"""
|
||||||
|
url = '^%s' % url
|
||||||
|
connection.cursor().execute("SELECT varnish_purge(%s)", (url, ))
|
||||||
|
16
sql/varnish.sql
Normal file
16
sql/varnish.sql
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Create a function to purge from varnish cache
|
||||||
|
-- By defalut this adds the object to a pgq queue,
|
||||||
|
-- but this function can be replaced with a void one
|
||||||
|
-- when running a development version.
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION varnish_purge(url text)
|
||||||
|
RETURNS bigint
|
||||||
|
AS $$
|
||||||
|
SELECT pgq.insert_event('varnish', 'P', $1);
|
||||||
|
$$ LANGUAGE 'sql';
|
||||||
|
|
||||||
|
COMMIT;
|
@ -11,7 +11,8 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<p>
|
<p>
|
||||||
View <a href="/admin/pending/">pending</a> moderation requests.
|
View <a href="/admin/pending/">pending</a> moderation requests.<br/>
|
||||||
|
Purge contents from <a href="/admin/purge/">varnish</a>.
|
||||||
</p>
|
</p>
|
||||||
<div id="content-main">
|
<div id="content-main">
|
||||||
|
|
||||||
|
24
templates/core/admin_purge.html
Normal file
24
templates/core/admin_purge.html
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{%extends "admin/base_site.html"%}
|
||||||
|
|
||||||
|
{%block breadcrumbs%}
|
||||||
|
<div class="breadcrumbs"><a href="/admin/">Home</a> › Pending</div>
|
||||||
|
{%endblock%}
|
||||||
|
|
||||||
|
{% block bodyclass %}change-list{% endblock %}
|
||||||
|
{% block coltype %}flex{% endblock %}
|
||||||
|
|
||||||
|
{%block content%}
|
||||||
|
<h1>Purge URL from Varnish</h1>
|
||||||
|
|
||||||
|
<div id="content-main">
|
||||||
|
{%if purge_completed %}
|
||||||
|
<div class="module">
|
||||||
|
Purge completed: {{purge_completed}}
|
||||||
|
</div>
|
||||||
|
{%endif%}
|
||||||
|
<form method="POST" action=".">
|
||||||
|
URL (regex): <input type="text" name="url">
|
||||||
|
<input type="submit" value="Purge" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{%endblock%}
|
Reference in New Issue
Block a user