diff --git a/forums/forms.py b/forums/forms.py index 0eef8f22271fb1cac8565ea263ad4f13f6cebb9c..0a484adc242690658c3adbf62df54df3ada72e4b 100644 --- a/forums/forms.py +++ b/forums/forms.py @@ -4,6 +4,8 @@ __license__ = "AGPL v3" from django import forms +from ajax_select.fields import AutoCompleteSelectField + from .models import Forum, Post @@ -13,6 +15,25 @@ class ForumForm(forms.ModelForm): fields = ['name', 'slug', 'publicly_visible', 'moderators'] +class ForumGroupPermissionsForm(forms.ModelForm): + """ + Used for granting a specific Group access to a given Forum. + """ + group = AutoCompleteSelectField('group_lookup') + can_view = forms.BooleanField(required=False) + can_post = forms.BooleanField(required=False) + + class Meta: + model = Forum + fields = [] + + +class ForumOrganizationPermissionsForm(forms.Form): + organization = AutoCompleteSelectField('organization_lookup') + can_view = forms.BooleanField() + can_post = forms.BooleanField() + + class PostForm(forms.ModelForm): """ Create a new Post. The parent must be defined, the model class and diff --git a/forums/migrations/0003_auto_20190307_0908.py b/forums/migrations/0003_auto_20190307_0908.py new file mode 100644 index 0000000000000000000000000000000000000000..955e9d1d2151c6289e5e6966fee6eac99d34f55d --- /dev/null +++ b/forums/migrations/0003_auto_20190307_0908.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2019-03-07 08:08 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('forums', '0002_auto_20190306_0807'), + ] + + operations = [ + migrations.AlterModelOptions( + name='forum', + options={'ordering': ['name'], 'permissions': [('can_view_forum', 'Can view Forum'), ('can_post_to_forum', 'Can add Post to Forum')]}, + ), + ] diff --git a/forums/models.py b/forums/models.py index dcd9dc75bb7c4879fc31b1c9511a146596c3e556..0bbfde363bee40c3999eb8eda741157a3d9abfb2 100644 --- a/forums/models.py +++ b/forums/models.py @@ -50,6 +50,7 @@ class Forum(models.Model): ordering = ['name',] permissions = [ ('can_view_forum', 'Can view Forum'), + ('can_post_to_forum', 'Can add Post to Forum'), ] def __str__(self): diff --git a/forums/templates/forums/forum_detail.html b/forums/templates/forums/forum_detail.html index 0c9f47b070c4aa233340d1922b137bb74b01207b..7ffaf8e84754abd66283d5d6e28bb6e2df289164 100644 --- a/forums/templates/forums/forum_detail.html +++ b/forums/templates/forums/forum_detail.html @@ -1,6 +1,7 @@ {% extends 'forums/base.html' %} {% load bootstrap %} +{% load guardian_tags %} {% block breadcrumb_items %} {{ block.super }} @@ -11,12 +12,36 @@ {% block pagetitle %}: Forum details{% endblock pagetitle %} +{% get_obj_perms request.user for forum as "user_perms" %} + {% block content %} <div class="row"> <div class="col-12"> <h3 class="highlight">{{ forum.name }}</h3> - <p>Visible to:</p> - {% if perms.forums.can_add_forum %} + + <div> + {% if perms.forums.add_forum or "can_change_forum" in user_perms %} + <h4 class="highlight">Permissions on this Forum instance</h4> + + <p>Groups with permissions [click on the Group's name to manage permissions]:</p> + <ul> + {% for group in groups_with_perms %} + {% get_obj_perms group for forum as "group_perms" %} + <li><a href="{% url 'forums:forum_permissions' slug=forum.slug group_id=group.id %}">{{ group.name }}</a>: {{ group_perms }}</li> + {% empty %} + <li>No group has permissions on this Forum</li> + {% endfor %} + </ul> + + <p>Users with permissions:</p> + <ul> + {% for u in users_with_perms %} + {% get_obj_perms u for forum as "u_perms" %} + <li>{{ u.first_name }} {{ u.last_name }}: {{ u_perms }}</li> + {% endfor %} + </ul> + </div> + <ul> <li><a href="{% url 'forums:forum_create' parent_model='forum' parent_id=forum.id %}">Create a (sub)Forum within this one</a></li> </ul> diff --git a/forums/templates/forums/forum_permissions.html b/forums/templates/forums/forum_permissions.html new file mode 100644 index 0000000000000000000000000000000000000000..5a4ed9333823c02da1d669882cd7ed96e29017a9 --- /dev/null +++ b/forums/templates/forums/forum_permissions.html @@ -0,0 +1,37 @@ +{% extends 'forums/base.html' %} + +{% load bootstrap %} +{% load guardian_tags %} + +{% block breadcrumb_items %} + {{ block.super }} +<span class="breadcrumb-item">Forum permissions</span> +{% endblock %} + +{% load scipost_extras %} + +{% block pagetitle %}: Forum permissions{% endblock pagetitle %} + + +{% block content %} + +<div class="row"> + <div class="col-12"> + + <h3 class="highlight">{{ forum.name }}: permissions for Group {{ group.name }}</h3> + + <form action="{% url 'forums:forum_permissions' slug=forum.slug group_id=group.id %}" method="post"> + {% csrf_token %} + {{ form|bootstrap }} + <input type="submit" value="Assign permissions" class="btn btn-primary"> + </form> + + </div> +</div> + +{% endblock content %} + +{% block footer_script %} +{{ block.super }} +{{ form.media }} +{% endblock footer_script %} diff --git a/forums/urls.py b/forums/urls.py index e02b42f3be6e2d471df7a880b16e53a54943b94d..486cbdeecd37c72e0ecff7ec62f76b81bffea537 100644 --- a/forums/urls.py +++ b/forums/urls.py @@ -22,6 +22,11 @@ urlpatterns = [ views.ForumDetailView.as_view(), name='forum_detail' ), + url( + r'^(?P<slug>[\w-]+)/permissions/(?P<group_id>[0-9]+)/$', + views.ForumPermissionsView.as_view(), + name='forum_permissions' + ), url( r'^$', views.ForumListView.as_view(), diff --git a/forums/views.py b/forums/views.py index 99402400b2cd5889b6dbc57d9440f218e2d1a7b2..cb7093352b14197b7737d6a194999408aaaa0ce2 100644 --- a/forums/views.py +++ b/forums/views.py @@ -2,23 +2,28 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" +from django.contrib.auth.models import Group from django.contrib.contenttypes.models import ContentType from django.core.urlresolvers import reverse_lazy +from django.shortcuts import get_object_or_404 from django.utils import timezone from django.views.generic.detail import DetailView -from django.views.generic.edit import CreateView +from django.views.generic.edit import CreateView, UpdateView from django.views.generic.list import ListView -from guardian.shortcuts import get_objects_for_user +from guardian.decorators import permission_required_or_403 +from guardian.mixins import PermissionRequiredMixin +from guardian.shortcuts import (assign_perm, remove_perm, + get_objects_for_user, get_perms, get_users_with_perms, get_groups_with_perms) from .models import Forum, Post -from .forms import ForumForm, PostForm +from .forms import ForumForm, ForumGroupPermissionsForm, ForumOrganizationPermissionsForm, PostForm from scipost.mixins import PermissionsMixin class ForumCreateView(PermissionsMixin, CreateView): - permission_required = 'forums.can_add_forum' + permission_required = 'forums.add_forum' model = Forum form_class = ForumForm template_name = 'forums/forum_form.html' @@ -38,10 +43,51 @@ class ForumCreateView(PermissionsMixin, CreateView): return initial -class ForumDetailView(DetailView): +class ForumDetailView(PermissionRequiredMixin, DetailView): + permission_required = 'forums.can_view_forum' model = Forum template_name = 'forums/forum_detail.html' + def get_context_data(self, *args, **kwargs): + context = super().get_context_data(*args, **kwargs) + context['groups_with_perms'] = get_groups_with_perms(self.object).order_by('name') + context['users_with_perms'] = get_users_with_perms(self.object) + context['group_permissions_form'] = ForumGroupPermissionsForm() + context['organization_permissions_form'] = ForumOrganizationPermissionsForm() + return context + + +class ForumPermissionsView(PermissionRequiredMixin, UpdateView): + permission_required = 'forums.can_change_forum' + model = Forum + form_class = ForumGroupPermissionsForm + template_name = 'forums/forum_permissions.html' + + def get_context_data(self, *args, **kwargs): + context = super().get_context_data(*args, **kwargs) + context['group'] = get_object_or_404(Group, pk=self.kwargs.get('group_id')) + return context + + def get_initial(self, *args, **kwargs): + initial = super().get_initial(*args, **kwargs) + group = get_object_or_404(Group, pk=self.kwargs.get('group_id')) + perms = get_perms (group, self.object) + initial['group'] = group.id + initial['can_view'] = 'can_view_forum' in perms + initial['can_post'] = 'can_post_to_forum' in perms + return initial + + def form_valid(self, form): + if form.cleaned_data['can_view']: + assign_perm('can_view_forum', form.cleaned_data['group'], self.object) + else: + remove_perm('can_view_forum', form.cleaned_data['group'], self.object) + if form.cleaned_data['can_post']: + assign_perm('can_post_to_forum', form.cleaned_data['group'], self.object) + else: + remove_perm('can_post_to_forum', form.cleaned_data['group'], self.object) + return super().form_valid(form) + class ForumListView(ListView): model = Forum diff --git a/scipost/templatetags/lookup.py b/scipost/templatetags/lookup.py new file mode 100644 index 0000000000000000000000000000000000000000..5f481a1426a96e34f77660436cf5f96600eefdf6 --- /dev/null +++ b/scipost/templatetags/lookup.py @@ -0,0 +1,35 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from django.contrib.auth.models import User, Group + +from ajax_select import register, LookupChannel + + +@register('user_lookup') +class UserLookup(LookupChannel): + model = User + + def get_query(self, q, request): + return self.model.objects.filter(last_name__icontains=q)[:10] + + def format_item_display(self, item): + return "<span class='auto_lookup_display'>%s, %s</span>" % (item.last_name, item.first_name) + + def format_match(self, item): + return "%s, %s" % (item.last_name, item.first_name) + + +@register('group_lookup') +class GroupLookup(LookupChannel): + model = Group + + def get_query(self, q, request): + return self.model.objects.filter(name__icontains=q)[:10] + + def format_item_display(self, item): + return "<span class='auto_lookup_display'>%s</span>" % item.name + + def format_match(self, item): + return item.name