Implement permissions on news tags
authorMagnus Hagander <magnus@hagander.net>
Sat, 4 Jul 2020 15:58:28 +0000 (17:58 +0200)
committerMagnus Hagander <magnus@hagander.net>
Wed, 15 Jul 2020 16:39:55 +0000 (18:39 +0200)
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
pgweb/news/forms.py
pgweb/news/migrations/0004_tag_permissions.py [new file with mode: 0644]
pgweb/news/models.py
pgweb/news/views.py

index 0e935860d344f44ebefa9d90309df05238f6258a..5b1f5512e3f83bfa057e0225c0347c449db60fc9 100644 (file)
@@ -21,6 +21,7 @@ class NewsArticleAdmin(PgwebAdmin):
 
 class NewsTagAdmin(PgwebAdmin):
     list_display = ('urlname', 'name', 'description')
+    filter_horizontal = ('allowed_orgs', )
 
 
 admin.site.register(NewsArticle, NewsArticleAdmin)
index 4fbeedbde48e3951eec731412c00797969a2055e..648bf4115a4bfa329eea4ca3ce06eea8bbc6df3c 100644 (file)
@@ -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 (file)
index 0000000..7d89334
--- /dev/null
@@ -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', )},
+        )
+    ]
index 296a11d9417cb724172d43f19399a0b4840f391a..79108396b3aace52d5837485f93584a26b0bccbe 100644 (file)
@@ -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):
index 8258ca5d8aa312e4c0b710f3c415be76e975de28..adcc785903aa501bcc89b9d9929b7329476ee9f2 100644 (file)
@@ -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')