Newer
Older
__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
__license__ = "AGPL v3"
from django.contrib import messages
from django.contrib.auth.models import Group
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
from django.http import Http404
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse, reverse_lazy
from django.views.generic.edit import CreateView, UpdateView, DeleteView
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 .forms import (ForumForm, ForumGroupPermissionsForm, ForumOrganizationPermissionsForm,
PostForm, PostFormHidden)
from scipost.mixins import PermissionsMixin
class ForumCreateView(PermissionsMixin, CreateView):
permission_required = 'forums.add_forum'
model = Forum
form_class = ForumForm
template_name = 'forums/forum_form.html'
success_url = reverse_lazy('forums:forums')
def get_initial(self):
initial = super().get_initial()
parent_model = self.kwargs.get('parent_model')
parent_content_type = None
parent_object_id = self.kwargs.get('parent_id')
if parent_model == 'forum':
parent_content_type = ContentType.objects.get(app_label='forums', model='forum')
'moderators': self.request.user,
'parent_content_type': parent_content_type,
'parent_object_id': parent_object_id,
class ForumDeleteView(PermissionRequiredMixin, DeleteView):
permission_required = 'forums.delete_forum'
model = Forum
success_url = reverse_lazy('forums:forums')
def delete(self, request, *args, **kwargs):
"""
A Forum can only be deleted if it does not have any descendants.
Upon deletion, all object-level permissions associated to the
Forum are explicitly removed, to avoid orphaned permissions.
"""
forum = get_object_or_404(Forum, slug=self.kwargs.get('slug'))
groups_perms_dict = get_groups_with_perms(forum, attach_perms=True)
if forum.child_forums.all().count() > 0:
messages.warning(request, 'A Forum with descendants cannot be deleted.')
return redirect(forum.get_absolute_url())
for group, perms_list in groups_perms_dict.items():
for perm in perms_list:
remove_perm(perm, group, forum)
return super().delete(request, *args, **kwargs)
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)
try:
context['group'] = Group.objects.get(pk=self.kwargs.get('group_id'))
except Group.DoesNotExist:
pass
return context
def get_initial(self, *args, **kwargs):
initial = super().get_initial(*args, **kwargs)
try:
group = Group.objects.get(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
except Group.DoesNotExist:
pass
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(LoginRequiredMixin, ListView):
queryset = get_objects_for_user(self.request.user, 'forums.can_view_forum').anchors()
class PostCreateView(UserPassesTestMixin, CreateView):
def test_func(self):
if self.request.user.has_perm('forums.add_forum'):
return True
forum = get_object_or_404(Forum, slug=self.kwargs.get('slug'))
if self.request.user.has_perm('can_post_to_forum', forum):
return True
else:
raise PermissionDenied
def get_initial(self, *args, **kwargs):
initial = super().get_initial(*args, **kwargs)
parent_model = self.kwargs.get('parent_model')
parent_object_id = self.kwargs.get('parent_id')
subject = ''
if parent_model == 'forum':
parent_content_type = ContentType.objects.get(app_label='forums', model='forum')
parent_content_type = ContentType.objects.get(app_label='forums', model='post')
parent = parent_content_type.get_object_for_this_type(pk=parent_object_id)
subject = 'Reply to %s' % parent.subject
else:
raise Http404
initial.update({
'posted_by': self.request.user,
'posted_on': timezone.now(),
'parent_content_type': parent_content_type,
'parent_object_id': parent_object_id,
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def form_valid(self, form):
"""
Save the form data to session variables only, redirect to confirmation view.
"""
self.request.session['post_subject'] = form.cleaned_data['subject']
self.request.session['post_text'] = form.cleaned_data['text']
return redirect(reverse('forums:post_confirm_create',
kwargs={'slug': self.kwargs.get('slug'),
'parent_model': self.kwargs.get('parent_model'),
'parent_id': self.kwargs.get('parent_id')}))
class PostConfirmCreateView(UserPassesTestMixin, CreateView):
form_class = PostFormHidden
template_name = 'forums/post_confirm_create.html'
def test_func(self):
if self.request.user.has_perm('forums.add_forum'):
return True
forum = get_object_or_404(Forum, slug=self.kwargs.get('slug'))
if self.request.user.has_perm('can_post_to_forum', forum):
return True
else:
raise PermissionDenied
def get_initial(self, *args, **kwargs):
initial = super().get_initial(*args, **kwargs)
parent_model = self.kwargs.get('parent_model')
parent_object_id = self.kwargs.get('parent_id')
if parent_model == 'forum':
parent_content_type = ContentType.objects.get(app_label='forums', model='forum')
elif parent_model == 'post':
parent_content_type = ContentType.objects.get(app_label='forums', model='post')
parent = parent_content_type.get_object_for_this_type(pk=parent_object_id)
else:
raise Http404
initial.update({
'posted_by': self.request.user,
'posted_on': timezone.now(),
'parent_content_type': parent_content_type,
'parent_object_id': parent_object_id,
'subject': self.request.session['post_subject'],
'text': self.request.session['post_text'],
})
return initial