From 9bd151082e045d613ac2ae889f8a62125d71d452 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Wed, 13 Dec 2017 20:55:07 +0100 Subject: [PATCH] Add tag support for news items This lets us separate things like project news from other OSS and from commercial postings, for example, allowing for people to subscribe to different feeds with just the parts they are interested in. --- media/css/text.css | 17 +++++++++++++++++ pgweb/core/views.py | 3 ++- pgweb/news/admin.py | 4 +++- pgweb/news/feeds.py | 10 ++++++++-- pgweb/news/forms.py | 11 ++++++++++- pgweb/news/migrations/0003_news_tags.py | 33 +++++++++++++++++++++++++++++++++ pgweb/news/models.py | 11 +++++++++++ pgweb/news/views.py | 14 +++++++++++--- pgweb/urls.py | 4 ++-- templates/base/base.html | 8 +++++++- templates/news/item.html | 3 +++ templates/news/newsarchive.html | 9 +++++++-- 12 files changed, 114 insertions(+), 13 deletions(-) create mode 100644 pgweb/news/migrations/0003_news_tags.py diff --git a/media/css/text.css b/media/css/text.css index 5a1f666e..afaccf4d 100644 --- a/media/css/text.css +++ b/media/css/text.css @@ -178,3 +178,20 @@ a:hover { color:#000000; text-decoration: underline; } #pgFrontNewsEventsContainer h3 img { margin-bottom: 10px; } + +/* + * News items tag list + */ +span.newstag { + background-color: #336791; + color: white; + padding: 4px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +span.newstag a { + color: white; + text-decoration: none; +} diff --git a/pgweb/core/views.py b/pgweb/core/views.py index 4bdb35a5..70f1dd54 100644 --- a/pgweb/core/views.py +++ b/pgweb/core/views.py @@ -24,7 +24,7 @@ from pgweb.util.misc import get_client_ip, varnish_purge from pgweb.util.sitestruct import get_all_pages_struct # models needed for the pieces on the frontpage -from pgweb.news.models import NewsArticle +from pgweb.news.models import NewsArticle, NewsTag from pgweb.events.models import Event from pgweb.quotes.models import Quote from models import Version, ImportedRSSItem @@ -63,6 +63,7 @@ def home(request): return render_to_response('index.html', { 'title': 'The world\'s most advanced open source database', 'news': news, + 'newstags': NewsTag.objects.all(), 'community_events': community_events, 'other_events': other_events, 'traininginfo': traininginfo, diff --git a/pgweb/news/admin.py b/pgweb/news/admin.py index 2ebe0614..a4146ba2 100644 --- a/pgweb/news/admin.py +++ b/pgweb/news/admin.py @@ -1,11 +1,12 @@ from django.contrib import admin from pgweb.util.admin import PgwebAdmin -from models import NewsArticle +from models import NewsArticle, NewsTag class NewsArticleAdmin(PgwebAdmin): list_display = ('title', 'org', 'date', 'approved', ) list_filter = ('approved', ) + filter_horizontal = ('tags', ) search_fields = ('content', 'title', ) change_form_template = 'admin/news/newsarticle/change_form.html' @@ -17,3 +18,4 @@ class NewsArticleAdmin(PgwebAdmin): return super(NewsArticleAdmin, self).change_view(request, object_id, extra_context=my_context) admin.site.register(NewsArticle, NewsArticleAdmin) +admin.site.register(NewsTag) diff --git a/pgweb/news/feeds.py b/pgweb/news/feeds.py index 3bd563d2..6c77fe3c 100644 --- a/pgweb/news/feeds.py +++ b/pgweb/news/feeds.py @@ -11,8 +11,14 @@ class NewsFeed(Feed): description_template = 'news/rss_description.html' title_template = 'news/rss_title.html' - def items(self): - return NewsArticle.objects.filter(approved=True)[:10] + def get_object(self, request, tagurl=None): + return tagurl + + def items(self, obj): + if obj: + return NewsArticle.objects.filter(approved=True, tags__urlname=obj)[:10] + else: + return NewsArticle.objects.filter(approved=True)[:10] def item_link(self, obj): return "https://www.postgresql.org/about/news/%s/" % obj.id diff --git a/pgweb/news/forms.py b/pgweb/news/forms.py index 6173cc2b..565a0aa1 100644 --- a/pgweb/news/forms.py +++ b/pgweb/news/forms.py @@ -2,7 +2,7 @@ from django import forms from django.forms import ValidationError from pgweb.core.models import Organisation -from models import NewsArticle +from models import NewsArticle, NewsTag class NewsArticleForm(forms.ModelForm): def __init__(self, *args, **kwargs): @@ -15,6 +15,15 @@ class NewsArticleForm(forms.ModelForm): raise ValidationError("You cannot change the date on an article that has been approved") return self.cleaned_data['date'] + @property + def described_checkboxes(self): + return { + 'tags': [(t.id, t.description) for t in NewsTag.objects.all()] + } + class Meta: model = NewsArticle exclude = ('submitter', 'approved', 'tweeted') + widgets = { + 'tags': forms.CheckboxSelectMultiple, + } diff --git a/pgweb/news/migrations/0003_news_tags.py b/pgweb/news/migrations/0003_news_tags.py new file mode 100644 index 00000000..3243a432 --- /dev/null +++ b/pgweb/news/migrations/0003_news_tags.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0002_news_tweet'), + ] + + operations = [ + migrations.CreateModel( + name='NewsTag', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('urlname', models.CharField(unique=True, max_length=20)), + ('name', models.CharField(max_length=32)), + ('description', models.CharField(max_length=200)), + ], + ), + migrations.AlterField( + model_name='newsarticle', + name='tweeted', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='newsarticle', + name='tags', + field=models.ManyToManyField(help_text=b'Hover mouse over tags to view full description', to='news.NewsTag'), + ), + ] diff --git a/pgweb/news/models.py b/pgweb/news/models.py index 22deee7e..5c383382 100644 --- a/pgweb/news/models.py +++ b/pgweb/news/models.py @@ -2,6 +2,14 @@ from django.db import models from datetime import date from pgweb.core.models import Organisation +class NewsTag(models.Model): + urlname = models.CharField(max_length=20, null=False, blank=False, unique=True) + name = models.CharField(max_length=32, null=False, blank=False) + description = models.CharField(max_length=200, null=False, blank=False) + + def __unicode__(self): + return self.name + 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 organisation list and contact the organisation manager or webmaster@postgresql.org if none are listed.") approved = models.BooleanField(null=False, blank=False, default=False) @@ -9,14 +17,17 @@ class NewsArticle(models.Model): title = models.CharField(max_length=200, null=False, blank=False) content = models.TextField(null=False, blank=False) tweeted = models.BooleanField(null=False, blank=False, default=False) + tags = models.ManyToManyField(NewsTag, blank=False, help_text="Hover mouse over tags to view full description") send_notification = True + send_m2m_notification = True markdown_fields = ('content',) def purge_urls(self): yield '/about/news/%s/' % self.pk yield '/about/newsarchive/' yield '/news.rss' + yield '/news/.*.rss' # FIXME: when to expire the front page? yield '/$' diff --git a/pgweb/news/views.py b/pgweb/news/views.py index 37a731ff..a20f456b 100644 --- a/pgweb/news/views.py +++ b/pgweb/news/views.py @@ -5,13 +5,20 @@ from pgweb.util.decorators import login_required from pgweb.util.contexts import NavContext from pgweb.util.helpers import simple_form -from models import NewsArticle +from models import NewsArticle, NewsTag from forms import NewsArticleForm -def archive(request, paging=None): - news = NewsArticle.objects.filter(approved=True) +def archive(request, tag=None, paging=None): + if tag: + tag = get_object_or_404(NewsTag,urlname=tag.strip('/')) + news = NewsArticle.objects.filter(approved=True, tags=tag) + else: + tag = None + news = NewsArticle.objects.filter(approved=True) return render_to_response('news/newsarchive.html', { 'news': news, + 'tag': tag, + 'newstags': NewsTag.objects.all(), }, NavContext(request, 'about')) def item(request, itemid, throwaway=None): @@ -20,6 +27,7 @@ def item(request, itemid, throwaway=None): raise Http404 return render_to_response('news/item.html', { 'obj': news, + 'newstags': NewsTag.objects.all(), }, NavContext(request, 'about')) @login_required diff --git a/pgweb/urls.py b/pgweb/urls.py index 63724eef..04e6d610 100644 --- a/pgweb/urls.py +++ b/pgweb/urls.py @@ -19,7 +19,7 @@ urlpatterns = patterns('', (r'^$', 'pgweb.core.views.home'), (r'^dyncss/(?Pbase|docs).css$', 'pgweb.core.views.dynamic_css'), - (r'^about/newsarchive/$', 'pgweb.news.views.archive'), + (r'^about/newsarchive/([^/]+/)?$', 'pgweb.news.views.archive'), (r'^about/news/(\d+)(-.*)?/$', 'pgweb.news.views.item'), (r'^about/events/$', 'pgweb.events.views.main'), (r'^about/eventarchive/$', 'pgweb.events.views.archive'), @@ -72,7 +72,7 @@ urlpatterns = patterns('', # RSS feeds ### (r'^versions.rss$', VersionFeed()), - (r'^news.rss$', NewsFeed()), + (r'^news(/(?P[^/]+))?.rss$', NewsFeed()), (r'^events.rss$', EventFeed()), ### diff --git a/templates/base/base.html b/templates/base/base.html index 6f742da1..1143e0f4 100644 --- a/templates/base/base.html +++ b/templates/base/base.html @@ -8,8 +8,14 @@ - +{%if newstags %} +{%comment%}Default RSS links are only shown on pages that have newstags set{%endcomment%} + +{%for t in newstags%} + +{%endfor%} +{%endif%}