From 01986c82a4858e93ed931eeceb95ec9469b0ef4f Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Sat, 4 Jul 2020 17:58:28 +0200 Subject: [PATCH] Implement permissions on news tags This makes it possible to limit which organisations can use specific tags in news, and verify those as news is submitted. Administrators can, as always, override. In passing also add a sortkey field to newstags to make them, well, sortable and include urlname in the json output. --- pgweb/news/admin.py | 1 + pgweb/news/forms.py | 18 +++++++++++ pgweb/news/migrations/0004_tag_permissions.py | 30 +++++++++++++++++++ pgweb/news/models.py | 5 +++- pgweb/news/views.py | 7 ++++- 5 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 pgweb/news/migrations/0004_tag_permissions.py diff --git a/pgweb/news/admin.py b/pgweb/news/admin.py index 0e935860..5b1f5512 100644 --- a/pgweb/news/admin.py +++ b/pgweb/news/admin.py @@ -21,6 +21,7 @@ class NewsArticleAdmin(PgwebAdmin): class NewsTagAdmin(PgwebAdmin): list_display = ('urlname', 'name', 'description') + filter_horizontal = ('allowed_orgs', ) admin.site.register(NewsArticle, NewsArticleAdmin) diff --git a/pgweb/news/forms.py b/pgweb/news/forms.py index 4fbeedbd..648bf411 100644 --- a/pgweb/news/forms.py +++ b/pgweb/news/forms.py @@ -25,6 +25,24 @@ class NewsArticleForm(forms.ModelForm): 'tags': {t.id: t.description for t in NewsTag.objects.all()} } + def clean(self): + data = super().clean() + + if 'tags' not in data: + self.add_error('tags', 'Select one or more tags') + else: + for t in data['tags']: + # Check each tag for permissions. This is not very db-efficient, but people + # don't save news articles that often... + if t.allowed_orgs.exists() and not t.allowed_orgs.filter(pk=data['org'].pk).exists(): + self.add_error('tags', + 'The organisation {} is not allowed to use the tag {}.'.format( + data['org'], + t, + )) + + return data + class Meta: model = NewsArticle exclude = ('submitter', 'approved', 'tweeted') diff --git a/pgweb/news/migrations/0004_tag_permissions.py b/pgweb/news/migrations/0004_tag_permissions.py new file mode 100644 index 00000000..7d89334e --- /dev/null +++ b/pgweb/news/migrations/0004_tag_permissions.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.27 on 2020-07-04 15:47 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0002_block_oauth'), + ('news', '0003_news_tags'), + ] + + operations = [ + migrations.AddField( + model_name='newstag', + name='allowed_orgs', + field=models.ManyToManyField(blank=True, help_text='Organisations allowed to use this tag', to='core.Organisation'), + ), + migrations.AddField( + model_name='newstag', + name='sortkey', + field=models.IntegerField(default=100), + ), + migrations.AlterModelOptions( + name='newstag', + options={'ordering': ('sortkey', 'urlname', )}, + ) + ] diff --git a/pgweb/news/models.py b/pgweb/news/models.py index 296a11d9..79108396 100644 --- a/pgweb/news/models.py +++ b/pgweb/news/models.py @@ -7,12 +7,15 @@ 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) + allowed_orgs = models.ManyToManyField(Organisation, blank=True, + help_text="Organisations allowed to use this tag") + sortkey = models.IntegerField(null=False, blank=False, default=100) def __str__(self): return self.name class Meta: - ordering = ('urlname', ) + ordering = ('sortkey', 'urlname', ) class NewsArticle(models.Model): diff --git a/pgweb/news/views.py b/pgweb/news/views.py index 8258ca5d..adcc7859 100644 --- a/pgweb/news/views.py +++ b/pgweb/news/views.py @@ -37,7 +37,12 @@ def item(request, itemid, throwaway=None): def taglist_json(request): return HttpResponse(json.dumps({ - 'tags': [{'name': t.urlname, 'description': t.description} for t in NewsTag.objects.distinct('urlname')], + 'tags': [{ + 'urlname': t.urlname, + 'name': t.name, + 'description': t.description, + 'sortkey': t.sortkey, + } for t in NewsTag.objects.order_by('urlname').distinct('urlname')], }), content_type='application/json') -- 2.39.5