Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge remote-tracking branch 'justinlilly/community-moderation'

  • Loading branch information...
commit b2dda8bdb51380ce4b5596e1d3b74e7283e97e0d 2 parents 49992a3 + 9047aad
@jacobian jacobian authored
View
7 README.txt
@@ -1,4 +1,4 @@
-To run locally, do the usual:
+To run locally, do the usual::
1. Create a virtualenv
2. Install dependencies::
@@ -13,7 +13,8 @@ To run locally, do the usual:
4. Create a 'secrets.json' file in the directoy above the checkout, containing
something like::
- { "secret_key": "xyz" }
+ { "secret_key": "xyz",
+ "superfeedr_creds": ["any@email.com", "some_string"] }
5. Set up DB::
@@ -22,7 +23,7 @@ To run locally, do the usual:
and::
- ./manage.py sycndb --docs
+ ./manage.py syncdb --docs
if you want to run docs site.
View
21 django_website/aggregator/admin.py
@@ -1,18 +1,29 @@
from __future__ import absolute_import
from django.contrib import admin
-from .models import Feed, FeedItem, FeedType
+from .models import Feed, FeedItem, FeedType, APPROVED_FEED, DENIED_FEED
-admin.site.register(Feed,
- list_display = ["title", "feed_type", "public_url"],
- list_filter = ["feed_type", "is_defunct"],
+
+def mark_approved(modeladmin, request, queryset):
+ queryset.update(approval_status=APPROVED_FEED)
+mark_approved.short_description = "Mark selected feeds as approved."
+
+def mark_denied(modeladmin, request, queryset):
+ queryset.update(approval_status=DENIED_FEED)
+mark_denied.short_description = "Mark selected feeds as denied."
+
+admin.site.register(Feed,
+ list_display = ["title", "feed_type", "public_url", "approval_status"],
+ list_filter = ["feed_type", "is_defunct", "approval_status"],
ordering = ["title"],
search_fields = ["title", "public_url"],
raw_id_fields = ['owner'],
+ list_editable = ["approval_status"],
list_per_page = 500,
+ actions = [mark_approved, mark_denied],
)
-admin.site.register(FeedItem,
+admin.site.register(FeedItem,
list_display = ['title', 'feed', 'date_modified'],
list_filter = ['feed'],
search_fields = ['feed__title', 'feed__public_url', 'title'],
View
2  django_website/aggregator/forms.py
@@ -14,4 +14,4 @@ class FeedModelForm(forms.ModelForm):
class Meta:
model = Feed
- exclude = ('is_defunct', 'feed_type', 'owner')
+ exclude = ('is_defunct', 'feed_type', 'owner', 'approval_status')
View
0  django_website/aggregator/management/__init__.py
No changes.
View
0  django_website/aggregator/management/commands/__init__.py
No changes.
View
49 django_website/aggregator/management/commands/send_pending_approval_email.py
@@ -0,0 +1,49 @@
+"""
+Send an email to settings.FEED_APPROVERS with the feeds that need to
+be manually approved.
+"""
+from __future__ import absolute_import
+
+from django.conf import settings
+from django.contrib.auth.models import User
+from django.core import mail
+from django.core.management.base import NoArgsCommand
+from django.template import Context, Template
+from ...models import Feed, PENDING_FEED
+
+class Command(NoArgsCommand):
+
+ def handle_noargs(self, **kwargs):
+ try:
+ verbosity = int(kwargs['verbosity'])
+ except (KeyError, TypeError, ValueError):
+ verbosity = 1
+
+ feeds = Feed.objects.filter(approval_status=PENDING_FEED)
+ to_email = [x.email for x in User.objects.filter(groups__name=settings.FEED_APPROVERS_GROUP_NAME)]
+
+ if len(feeds) == 0:
+ if verbosity >= 1:
+ print "There are no pending feeds. Skipping the email."
+ return
+
+ email = """The following feeds are pending approval:
+{% regroup feeds by feed_type as feed_grouping %}{% for group in feed_grouping %}
+{{ group.grouper }} {% for feed in group.list %}
+ - {{ feed.title }} ( {{ feed.feed_url }} ) {% endfor %}
+{% endfor %}
+
+To approve them, visit: http://djangoproject.com{% url admin:aggregator_feed_changelist %}
+"""
+
+ message = Template(email).render(Context({'feeds': feeds}))
+ if verbosity >= 2:
+ print "Pending approval email:\n"
+ print message
+
+ mail.send_mail("django community feeds pending approval", message,
+ 'nobody@djangoproject.com', to_email,
+ fail_silently=False)
+
+ if verbosity >= 1:
+ print "Sent pending approval email to: %s" % (', '.join(to_email))
View
84 django_website/aggregator/migrations/0004_add_approval_status_field.py
@@ -0,0 +1,84 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Create approval status field. All feeds default to approved.
+ db.add_column('aggregator_feed', 'approval_status', self.gf('django.db.models.fields.CharField')(default='A', max_length=1), keep_default=False)
+
+
+ def backwards(self, orm):
+ db.delete_column('aggregator_feed', 'approval_status')
+
+ models = {
+ 'aggregator.feed': {
+ 'Meta': {'object_name': 'Feed'},
+ 'approval_status': ('django.db.models.fields.CharField', [], {'default': "'P'", 'max_length': '1'}),
+ 'feed_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['aggregator.FeedType']"}),
+ 'feed_url': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '500'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_defunct': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'owned_feeds'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'public_url': ('django.db.models.fields.URLField', [], {'max_length': '500'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'aggregator.feeditem': {
+ 'Meta': {'ordering': "('-date_modified',)", 'object_name': 'FeedItem'},
+ 'date_modified': ('django.db.models.fields.DateTimeField', [], {}),
+ 'feed': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['aggregator.Feed']"}),
+ 'guid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500', 'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'link': ('django.db.models.fields.URLField', [], {'max_length': '500'}),
+ 'summary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'aggregator.feedtype': {
+ 'Meta': {'object_name': 'FeedType'},
+ 'can_self_add': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '250', 'db_index': 'True'})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['aggregator']
View
84 django_website/aggregator/migrations/0005_add_feed_approver_auth_group.py
@@ -0,0 +1,84 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from django.conf import settings
+
+class Migration(DataMigration):
+ def forwards(self, orm):
+ group = orm['auth.Group'](name=settings.FEED_APPROVERS_GROUP_NAME)
+ group.save()
+
+ def backwards(self, orm):
+ group = orm['auth.Group'].objects.get(name=settings.FEED_APPROVERS_GROUP_NAME)
+ group.delete()
+
+ models = {
+ 'aggregator.feed': {
+ 'Meta': {'object_name': 'Feed'},
+ 'approval_status': ('django.db.models.fields.CharField', [], {'default': "'P'", 'max_length': '1'}),
+ 'feed_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['aggregator.FeedType']"}),
+ 'feed_url': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '500'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_defunct': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'owned_feeds'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'public_url': ('django.db.models.fields.URLField', [], {'max_length': '500'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'aggregator.feeditem': {
+ 'Meta': {'ordering': "('-date_modified',)", 'object_name': 'FeedItem'},
+ 'date_modified': ('django.db.models.fields.DateTimeField', [], {}),
+ 'feed': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['aggregator.Feed']"}),
+ 'guid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500', 'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'link': ('django.db.models.fields.URLField', [], {'max_length': '500'}),
+ 'summary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'aggregator.feedtype': {
+ 'Meta': {'object_name': 'FeedType'},
+ 'can_self_add': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '250', 'db_index': 'True'})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['aggregator']
View
19 django_website/aggregator/models.py
@@ -5,6 +5,7 @@
from django.conf import settings
from django_push.subscriber import signals as push_signals
from django_push.subscriber.models import Subscription
+from django.conf import settings
log = logging.getLogger(__name__)
@@ -19,11 +20,23 @@ def __unicode__(self):
def items(self):
return FeedItem.objects.filter(feed__feed_type=self)
+APPROVED_FEED='A'
+DENIED_FEED='D'
+PENDING_FEED='P'
+
+STATUS_CHOICES = (
+ (PENDING_FEED, 'Pending'),
+ (DENIED_FEED, 'Denied'),
+ (APPROVED_FEED, 'Approved')
+)
+
+
class Feed(models.Model):
title = models.CharField(max_length=500)
feed_url = models.URLField(unique=True, max_length=500)
public_url = models.URLField(max_length=500)
is_defunct = models.BooleanField()
+ approval_status = models.CharField(max_length=1, choices=STATUS_CHOICES, default=PENDING_FEED)
feed_type = models.ForeignKey(FeedType)
owner = models.ForeignKey(User, blank=True, null=True, related_name='owned_feeds')
@@ -32,11 +45,13 @@ def __unicode__(self):
def save(self, **kwargs):
super(Feed, self).save(**kwargs)
- Subscription.objects.subscribe(self.feed_url, settings.PUSH_HUB)
+ if settings.SUPERFEEDR_CREDS != None and self.approval_status == APPROVED_FEED:
+ Subscription.objects.subscribe(self.feed_url, settings.PUSH_HUB)
def delete(self, **kwargs):
super(Feed, self).delete(**kwargs)
- Subscription.objects.unsubscribe(self.feed_url, settings.PUSH_HUB)
+ if settings.SUPERFEEDR_CREDS != None:
+ Subscription.objects.unsubscribe(self.feed_url, settings.PUSH_HUB)
class FeedItemManager(models.Manager):
def create_or_update_by_guid(self, guid, **kwargs):
View
62 django_website/aggregator/tests.py
@@ -0,0 +1,62 @@
+# email test
+# https://docs.djangoproject.com/en/dev/topics/testing/#email-services
+from __future__ import absolute_import
+
+import datetime
+from django.conf import settings
+from django.contrib.auth.models import Group, User
+from django.core import mail
+from django.core.urlresolvers import reverse
+from django.test import TestCase
+from django.test.client import Client
+from .management.commands import send_pending_approval_email
+from . import models
+from ..docs.models import DocumentRelease
+
+class AggregatorTests(TestCase):
+
+ def setUp(self):
+ # document release necessary to fetch main page
+ DocumentRelease(version="1.4", scm="svn", scm_url="/path/to/svn", is_default=True).save()
+
+ # Set up users who will get emailed
+ g = Group.objects.create(name=settings.FEED_APPROVERS_GROUP_NAME)
+ self.user = User.objects.create(username="Mr. Potato", email="mr@potato.com")
+ self.user.groups.add(g)
+
+
+ self.feed_type = models.FeedType(name="Test Feed Type", slug="test-feed-type", can_self_add=True)
+ self.feed_type.save()
+
+ self.approved_feed = models.Feed(title="Approved", feed_url="foo.com/rss/", public_url="foo.com/", is_defunct=False,
+ approval_status=models.APPROVED_FEED, feed_type=self.feed_type)
+ self.denied_feed = models.Feed(title="Denied", feed_url="bar.com/rss/", public_url="bar.com/", is_defunct=False,
+ approval_status=models.DENIED_FEED, feed_type=self.feed_type)
+ self.pending_feed = models.Feed(title="Pending", feed_url="baz.com/rss/", public_url="baz.com/", is_defunct=False,
+ approval_status=models.PENDING_FEED, feed_type=self.feed_type)
+ self.defunct_feed = models.Feed(title="Defunct", feed_url="zot.com/rss/", public_url="zot.com/", is_defunct=True,
+ approval_status=models.APPROVED_FEED, feed_type=self.feed_type)
+
+ for feed in [self.approved_feed, self.denied_feed, self.pending_feed, self.defunct_feed]:
+ feed.save()
+ feed_item = models.FeedItem(feed=feed, title="%s Item" % feed.title, link=feed.public_url,
+ date_modified=datetime.datetime.now(), guid=feed.title)
+ feed_item.save()
+
+ self.client = Client()
+
+ def test_feed_list_only_approved_and_active(self):
+ response = self.client.get(reverse('community-feed-list', kwargs={'feed_type_slug': self.feed_type.slug}));
+ for item in response.context['object_list']:
+ self.assertEqual(models.APPROVED_FEED, item.feed.approval_status)
+
+ def test_management_command_sends_no_email_with_no_pending_feeds(self):
+ self.pending_feed.delete()
+ send_pending_approval_email.Command().handle_noargs()
+ self.assertEqual(0, len(mail.outbox))
+
+ def test_management_command_sends_email_with_pending_feeds(self):
+ send_pending_approval_email.Command().handle_noargs()
+
+ self.assertEqual(1, len(mail.outbox))
+ self.assertEqual(mail.outbox[0].to, [self.user.email])
View
4 django_website/aggregator/utils.py
@@ -3,7 +3,7 @@
def push_credentials(hub_url):
"""
Callback for django_push to get a hub's credentials.
-
+
We always use superfeedr so this is easy.
"""
- return tuple(settings.SECRETS['superfeedr_creds'])
+ return tuple(settings.SUPERFEEDR_CREDS)
View
15 django_website/aggregator/views.py
@@ -3,11 +3,12 @@
import logging
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext
+from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.views.generic.list_detail import object_list
-from .models import FeedItem, Feed, FeedType
+from .models import FeedItem, Feed, FeedType, APPROVED_FEED
from .forms import FeedModelForm
from ..shortcuts import render
@@ -23,8 +24,8 @@ def feed_list(request, feed_type_slug):
Shows the latest feeds for the given type.
"""
feed_type = get_object_or_404(FeedType, slug=feed_type_slug)
- return object_list(request,
- queryset = FeedItem.objects.filter(feed__feed_type=feed_type),
+ return object_list(request,
+ queryset = FeedItem.objects.filter(feed__feed_type=feed_type, feed__approval_status=APPROVED_FEED),
paginate_by = 25,
extra_context = {'feed_type': feed_type},
)
@@ -54,11 +55,13 @@ def add_feed(request, feed_type_slug):
ft = get_object_or_404(FeedType, slug=feed_type_slug, can_self_add=True)
if not ft.can_self_add and not request.user.is_superuser:
return render(request, 'aggregator/denied.html')
-
+
instance = Feed(feed_type=ft, owner=request.user)
f = FeedModelForm(request.POST or None, instance=instance)
if f.is_valid():
f.save()
+ messages.add_message(
+ request, messages.INFO, 'Your feed has entered moderation. Please allow up to 1 week for processing.')
return redirect('community-index')
ctx = {'form': f, 'feed_type': ft, 'adding': True}
@@ -76,7 +79,7 @@ def edit_feed(request, feed_id):
if f.is_valid():
f.save()
return redirect('community-my-feeds')
-
+
ctx = {'form': f, 'feed': feed, 'adding': False}
return render(request, 'aggregator/edit-feed.html', ctx)
@@ -91,4 +94,4 @@ def delete_feed(request, feed_id):
if request.method == 'POST':
feed.delete()
return redirect('community-my-feeds')
- return render(request, 'aggregator/delete-confirm.html', {'feed': feed})
+ return render(request, 'aggregator/delete-confirm.html', {'feed': feed})
View
10 django_website/settings/www.py
@@ -14,9 +14,12 @@
# It's a secret to everybody
SECRETS = json.load(open(BASE.ancestor(2).child('secrets.json')))
SECRET_KEY = str(SECRETS['secret_key'])
+# SUPERFEEDR_CREDS is a 2 element list in the form of [email,secretkey]
+SUPERFEEDR_CREDS = SECRETS.get('superfeedr_creds')
ADMINS = (('Adrian Holovaty','holovaty@gmail.com'),('Jacob Kaplan-Moss', 'jacob@jacobian.org'))
MANAGERS = (('Jacob Kaplan-Moss','jacob@jacobian.org'),)
+FEED_APPROVERS_GROUP_NAME = "feed-approver"
TIME_ZONE = 'America/Chicago'
SERVER_EMAIL = 'root@djangoproject.com'
@@ -64,6 +67,7 @@
'django.contrib.contenttypes',
'django.contrib.flatpages',
'django.contrib.humanize',
+ 'django.contrib.messages',
'django.contrib.redirects',
'django.contrib.sessions',
'django.contrib.sitemaps',
@@ -79,6 +83,8 @@
'djangosecure',
]
+MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
+
CACHE_MIDDLEWARE_SECONDS = 60 * 5 # 5 minutes
CACHE_MIDDLEWARE_KEY_PREFIX = 'djangoproject'
CACHE_MIDDLEWARE_GZIP = True
@@ -87,6 +93,7 @@
MIDDLEWARE_CLASSES = [
'djangosecure.middleware.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.common.CommonMiddleware',
@@ -107,7 +114,8 @@
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django_website.context_processors.recent_release",
-]
+ "django.contrib.messages.context_processors.messages",
+ ]
DEFAULT_FROM_EMAIL = "noreply@djangoproject.com"
View
20 django_website/templates/aggregator/index.html
@@ -1,9 +1,27 @@
{% extends "base_community.html" %}
+{% block extrahead %}
+{{ block.super }}
+<style type="text/css">
+ul.messages li {
+ font-weight: 600;
+ list-style: none;
+ padding: 20px 0;
+</style>
+{% endblock %}
+
{% block content %}
<h1>Community</h1>
<h2 class="deck">This page, updated regularly, aggregates what's going on in the community.</h2>
+{% if messages %}
+<ul class="messages">
+ {% for message in messages %}
+ <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
+ {% endfor %}
+</ul>
+{% endif %}
+
{% for feedtype in feedtype_list %}
<div id="{{ feedtype.slug }}" class="module {% cycle "first" "last" %}">
<h3 class="header">
@@ -19,7 +37,7 @@ <h3 class="header">
<a href="{% url community-feed-list feedtype.slug %}">View more</a>
{% endif %}
{% if feedtype.items and feedtype.can_self_add %}
- or
+ or
{% endif %}
{% if feedtype.can_self_add %}
<a href="{% url community-add-feed feedtype.slug %}">Add your feed</a>
View
8 django_website/templates/aggregator/my-feeds.html
@@ -8,12 +8,12 @@ <h2 class="deck">Manage your community aggregator feeds:</h2>
<ul>
{% for feed in feeds %}
<li>
- {{ feed }} (<code>{{ feed.feed_url }}</code>) —
- <a href="{% url community-edit-feed feed.id %}">edit</a> |
+ {{ feed }} (<code>{{ feed.feed_url }}</code> — <strong>{{ feed.get_approval_status_display }}</strong>) —
+ <a href="{% url community-edit-feed feed.id %}">edit</a> |
<a href="{% url community-delete-feed feed.id %}">delete</a>
</li>
{% endfor %}
- <li>Add a new feed:
+ <li>Add a new feed:
{% for t in feed_types %}
<a href="{% url community-add-feed t.slug %}">{{ t }}</a>
{% if not forloop.last %}|{% endif %}
@@ -21,4 +21,4 @@ <h2 class="deck">Manage your community aggregator feeds:</h2>
</li>
{# <li>Claim a feed already in the system.</li> #}
</ul>
-{% endblock %}
+{% endblock %}
Please sign in to comment.
Something went wrong with that request. Please try again.