mirror of
https://github.com/ae-utbm/sith.git
synced 2025-01-22 06:51:09 +00:00
Improve pedagogy permissions
This commit is contained in:
parent
61170c0918
commit
0d95c3b9c9
@ -256,7 +256,7 @@ class ClubMembersView(ClubTabsMixin, CanViewMixin, DetailFormView):
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs["request_user"] = self.request.user
|
||||
kwargs["club"] = self.get_object()
|
||||
kwargs["club"] = self.object
|
||||
kwargs["club_members"] = self.members
|
||||
return kwargs
|
||||
|
||||
@ -273,9 +273,9 @@ class ClubMembersView(ClubTabsMixin, CanViewMixin, DetailFormView):
|
||||
users = data.pop("users", [])
|
||||
users_old = data.pop("users_old", [])
|
||||
for user in users:
|
||||
Membership(club=self.get_object(), user=user, **data).save()
|
||||
Membership(club=self.object, user=user, **data).save()
|
||||
for user in users_old:
|
||||
membership = self.get_object().get_membership_for(user)
|
||||
membership = self.object.get_membership_for(user)
|
||||
membership.end_date = timezone.now()
|
||||
membership.save()
|
||||
return resp
|
||||
@ -285,9 +285,7 @@ class ClubMembersView(ClubTabsMixin, CanViewMixin, DetailFormView):
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
return reverse_lazy(
|
||||
"club:club_members", kwargs={"club_id": self.get_object().id}
|
||||
)
|
||||
return reverse_lazy("club:club_members", kwargs={"club_id": self.object.id})
|
||||
|
||||
|
||||
class ClubOldMembersView(ClubTabsMixin, CanViewMixin, DetailView):
|
||||
|
@ -895,13 +895,16 @@ Welcome to the wiki page!
|
||||
|
||||
subscribers = Group.objects.create(name="Subscribers")
|
||||
subscribers.permissions.add(
|
||||
*list(perms.filter(codename__in=["add_news", "add_uvcommentreport"]))
|
||||
*list(perms.filter(codename__in=["add_news", "add_uvcomment"]))
|
||||
)
|
||||
old_subscribers = Group.objects.create(name="Old subscribers")
|
||||
old_subscribers.permissions.add(
|
||||
*list(
|
||||
perms.filter(
|
||||
codename__in=[
|
||||
"view_uv",
|
||||
"view_uvcomment",
|
||||
"add_uvcommentreport",
|
||||
"view_user",
|
||||
"view_picture",
|
||||
"view_album",
|
||||
@ -973,9 +976,9 @@ Welcome to the wiki page!
|
||||
)
|
||||
pedagogy_admin.permissions.add(
|
||||
*list(
|
||||
perms.filter(content_type__app_label="pedagogy").values_list(
|
||||
"pk", flat=True
|
||||
)
|
||||
perms.filter(content_type__app_label="pedagogy")
|
||||
.exclude(codename__in=["change_uvcomment"])
|
||||
.values_list("pk", flat=True)
|
||||
)
|
||||
)
|
||||
self.reset_index("core", "auth")
|
||||
|
@ -28,8 +28,7 @@ from django.http import (
|
||||
HttpResponseServerError,
|
||||
)
|
||||
from django.shortcuts import render
|
||||
from django.utils.functional import cached_property
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
from django.views.generic.detail import BaseDetailView
|
||||
from django.views.generic.edit import FormView
|
||||
from sentry_sdk import last_event_id
|
||||
|
||||
@ -54,17 +53,12 @@ def internal_servor_error(request):
|
||||
return HttpResponseServerError(render(request, "core/500.jinja"))
|
||||
|
||||
|
||||
class DetailFormView(SingleObjectMixin, FormView):
|
||||
class DetailFormView(FormView, BaseDetailView):
|
||||
"""Class that allow both a detail view and a form view."""
|
||||
|
||||
def get_object(self):
|
||||
"""Get current group from id in url."""
|
||||
return self.cached_object
|
||||
|
||||
@cached_property
|
||||
def cached_object(self):
|
||||
"""Optimisation on group retrieval."""
|
||||
return super().get_object()
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
|
||||
# F403: those star-imports would be hellish to refactor
|
||||
|
@ -66,7 +66,6 @@ from core.views.forms import (
|
||||
)
|
||||
from core.views.mixins import QuickNotifMixin, TabedViewMixin
|
||||
from counter.models import Refilling, Selling
|
||||
from counter.views.student_card import StudentCardFormView
|
||||
from eboutic.models import Invoice
|
||||
from subscription.models import Subscription
|
||||
from trombi.views import UserTrombiForm
|
||||
@ -566,6 +565,8 @@ class UserPreferencesView(UserTabsMixin, CanEditMixin, UpdateView):
|
||||
if not hasattr(self.object, "trombi_user"):
|
||||
kwargs["trombi_form"] = UserTrombiForm()
|
||||
if hasattr(self.object, "customer"):
|
||||
from counter.views.student_card import StudentCardFormView
|
||||
|
||||
kwargs["student_card_fragment"] = StudentCardFormView.get_template_data(
|
||||
self.object.customer
|
||||
).render(self.request)
|
||||
|
@ -20,10 +20,12 @@
|
||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
#
|
||||
from typing import Self
|
||||
|
||||
from django.conf import settings
|
||||
from django.core import validators
|
||||
from django.db import models
|
||||
from django.db.models import Exists, OuterRef
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.functional import cached_property
|
||||
@ -145,14 +147,6 @@ class UV(models.Model):
|
||||
def get_absolute_url(self):
|
||||
return reverse("pedagogy:uv_detail", kwargs={"uv_id": self.id})
|
||||
|
||||
def is_owned_by(self, user):
|
||||
"""Can be created by superuser, root or pedagogy admin user."""
|
||||
return user.is_in_group(pk=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
|
||||
|
||||
def can_be_viewed_by(self, user):
|
||||
"""Only visible by subscribers."""
|
||||
return user.is_subscribed
|
||||
|
||||
def __grade_average_generic(self, field):
|
||||
comments = self.comments.filter(**{field + "__gte": 0})
|
||||
if not comments.exists():
|
||||
@ -191,6 +185,22 @@ class UV(models.Model):
|
||||
return self.__grade_average_generic("grade_work_load")
|
||||
|
||||
|
||||
class UVCommentQuerySet(models.QuerySet):
|
||||
def viewable_by(self, user: User) -> Self:
|
||||
if user.has_perms(["pedagogy.view_uvcomment", "pedagogy.view_uvcommentreport"]):
|
||||
# the user can view uv comment reports,
|
||||
# so he can view non-moderated comments
|
||||
return self
|
||||
if user.has_perm("pedagogy.view_uvcomment"):
|
||||
return self.filter(reports=None)
|
||||
return self.filter(author=user)
|
||||
|
||||
def annotate_is_reported(self) -> Self:
|
||||
return self.annotate(
|
||||
is_reported=Exists(UVCommentReport.objects.filter(comment=OuterRef("pk")))
|
||||
)
|
||||
|
||||
|
||||
class UVComment(models.Model):
|
||||
"""A comment about an UV."""
|
||||
|
||||
@ -243,6 +253,8 @@ class UVComment(models.Model):
|
||||
)
|
||||
publish_date = models.DateTimeField(_("publish date"), blank=True)
|
||||
|
||||
objects = UVCommentQuerySet.as_manager()
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.uv} - {self.author}"
|
||||
|
||||
@ -251,15 +263,6 @@ class UVComment(models.Model):
|
||||
self.publish_date = timezone.now()
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def is_owned_by(self, user):
|
||||
"""Is owned by a pedagogy admin, a superuser or the author himself."""
|
||||
return self.author == user or user.is_owner(self.uv)
|
||||
|
||||
@cached_property
|
||||
def is_reported(self):
|
||||
"""Return True if someone reported this UV."""
|
||||
return self.reports.exists()
|
||||
|
||||
|
||||
# TODO : it seems that some views were meant to be implemented
|
||||
# to use this model.
|
||||
@ -323,7 +326,3 @@ class UVCommentReport(models.Model):
|
||||
@cached_property
|
||||
def uv(self):
|
||||
return self.comment.uv
|
||||
|
||||
def is_owned_by(self, user):
|
||||
"""Can be created by a pedagogy admin, a superuser or a subscriber."""
|
||||
return user.is_subscribed or user.is_owner(self.comment.uv)
|
||||
|
@ -19,7 +19,7 @@
|
||||
{% endblock head %}
|
||||
|
||||
{% block content %}
|
||||
{% if can_create_uv %}
|
||||
{% if user.has_perm("pedagogy.add_uv") %}
|
||||
<div class="action-bar">
|
||||
<p>
|
||||
<a href="{{ url('pedagogy:uv_create') }}">{% trans %}Create UV{% endtrans %}</a>
|
||||
@ -94,8 +94,10 @@
|
||||
<td>{% trans %}Credit type{% endtrans %}</td>
|
||||
<td><i class="fa fa-leaf"></i></td>
|
||||
<td><i class="fa-regular fa-sun"></i></td>
|
||||
{% if can_create_uv %}
|
||||
{%- if user.has_perm("pedagogy.change_uv") -%}
|
||||
<td>{% trans %}Edit{% endtrans %}</td>
|
||||
{%- endif -%}
|
||||
{%- if user.has_perm("pedagogy.delete_uv") -%}
|
||||
<td>{% trans %}Delete{% endtrans %}</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
@ -109,8 +111,10 @@
|
||||
<td x-text="uv.credit_type"></td>
|
||||
<td><i :class="uv.semester.includes('AUTUMN') && 'fa fa-leaf'"></i></td>
|
||||
<td><i :class="uv.semester.includes('SPRING') && 'fa-regular fa-sun'"></i></td>
|
||||
{% if can_create_uv -%}
|
||||
{%- if user.has_perm("pedagogy.change_uv") -%}
|
||||
<td><a :href="`/pedagogy/uv/${uv.id}/edit`">{% trans %}Edit{% endtrans %}</a></td>
|
||||
{%- endif -%}
|
||||
{%- if user.has_perm("pedagogy.delete_uv") -%}
|
||||
<td><a :href="`/pedagogy/uv/${uv.id}/delete`">{% trans %}Delete{% endtrans %}</a></td>
|
||||
{%- endif -%}
|
||||
</tr>
|
||||
|
@ -89,7 +89,7 @@
|
||||
<div id="leave_comment_not_allowed">
|
||||
<p>{% trans %}You already posted a comment on this UV. If you want to comment again, please modify or delete your previous comment.{% endtrans %}</p>
|
||||
</div>
|
||||
{% else %}
|
||||
{% elif user.has_perm("pedagogy.add_uvcomment") %}
|
||||
<div id="leave_comment">
|
||||
<h2>{% trans %}Leave comment{% endtrans %}</h2>
|
||||
<div>
|
||||
@ -146,9 +146,9 @@
|
||||
{% endif %}
|
||||
<br>
|
||||
|
||||
{% if object.comments.exists() %}
|
||||
{% if comments %}
|
||||
<h2>{% trans %}Comments{% endtrans %}</h2>
|
||||
{% for comment in object.comments.order_by("-publish_date").all() %}
|
||||
{% for comment in comments %}
|
||||
<div id="{{ comment.id }}" class="comment-container">
|
||||
|
||||
<div class="grade-block">
|
||||
@ -183,16 +183,28 @@
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if user.is_owner(comment) %}
|
||||
{% if comment.author_id == user.id or user.has_perm("pedagogy.change_comment") %}
|
||||
<p class="actions">
|
||||
<a href="{{ url('pedagogy:comment_update', comment_id=comment.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('pedagogy:comment_delete', comment_id=comment.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
<a href="{{ url('pedagogy:comment_update', comment_id=comment.id) }}">
|
||||
{% trans %}Edit{% endtrans %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if comment.author_id == user.id or user.has_perm("pedagogy.delete_comment") %}
|
||||
<a href="{{ url('pedagogy:comment_delete', comment_id=comment.id) }}">
|
||||
{% trans %}Delete{% endtrans %}
|
||||
</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="comment-end-bar">
|
||||
<div class="report"><p><a href="{{ url('pedagogy:comment_report', comment_id=comment.id) }}">{% trans %}Report this comment{% endtrans %}</a></p></div>
|
||||
<div class="report">
|
||||
<p>
|
||||
<a href="{{ url('pedagogy:comment_report', comment_id=comment.id) }}">
|
||||
{% trans %}Report this comment{% endtrans %}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="date"><p>{{ comment.publish_date.strftime('%d/%m/%Y') }}</p></div>
|
||||
|
||||
@ -209,7 +221,7 @@
|
||||
<script type="text/javascript">
|
||||
$("#return_noscript").hide();
|
||||
$("#return_js").show();
|
||||
var icons = {
|
||||
const icons = {
|
||||
header: "fa fa-toggle-right",
|
||||
activeHeader: "fa fa-toggle-down"
|
||||
};
|
||||
|
@ -20,14 +20,18 @@
|
||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
#
|
||||
from typing import Callable
|
||||
|
||||
import pytest
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from model_bakery import baker
|
||||
from pytest_django.asserts import assertRedirects
|
||||
|
||||
from core.baker_recipes import old_subscriber_user, subscriber_user
|
||||
from core.models import Notification, User
|
||||
from pedagogy.models import UV, UVComment, UVCommentReport
|
||||
|
||||
@ -144,17 +148,17 @@ class TestUVCreation(TestCase):
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
("username", "expected_code"),
|
||||
("user_factory", "expected_code"),
|
||||
[
|
||||
("root", 200),
|
||||
("tutu", 200),
|
||||
("sli", 200),
|
||||
("old_subscriber", 200),
|
||||
("public", 403),
|
||||
(subscriber_user.make, 200),
|
||||
(old_subscriber_user.make, 200),
|
||||
(lambda: baker.make(User), 403),
|
||||
],
|
||||
)
|
||||
def test_guide_permissions(client: Client, username: str, expected_code: int):
|
||||
client.force_login(User.objects.get(username=username))
|
||||
def test_guide_permissions(
|
||||
client: Client, user_factory: Callable[[], User], expected_code: int
|
||||
):
|
||||
client.force_login(user_factory())
|
||||
res = client.get(reverse("pedagogy:guide"))
|
||||
assert res.status_code == expected_code
|
||||
|
||||
@ -190,17 +194,12 @@ class TestUVDelete(TestCase):
|
||||
def test_uv_delete_pedagogy_unauthorized_fail(self):
|
||||
# Anonymous user
|
||||
response = self.client.post(self.delete_uv_url)
|
||||
assert response.status_code == 403
|
||||
assertRedirects(response, reverse("core:login") + f"?next={self.delete_uv_url}")
|
||||
assert UV.objects.filter(pk=self.uv.pk).exists()
|
||||
|
||||
# Not subscribed user
|
||||
self.client.force_login(self.guy)
|
||||
response = self.client.post(self.delete_uv_url)
|
||||
assert response.status_code == 403
|
||||
assert UV.objects.filter(pk=self.uv.pk).exists()
|
||||
|
||||
# Simply subscribed user
|
||||
self.client.force_login(self.sli)
|
||||
for user in baker.make(User), subscriber_user.make():
|
||||
with self.subTest():
|
||||
self.client.force_login(user)
|
||||
response = self.client.post(self.delete_uv_url)
|
||||
assert response.status_code == 403
|
||||
assert UV.objects.filter(pk=self.uv.pk).exists()
|
||||
@ -249,7 +248,7 @@ class TestUVUpdate(TestCase):
|
||||
response = self.client.post(
|
||||
self.update_uv_url, create_uv_template(self.bibou.id, code="PA00")
|
||||
)
|
||||
assert response.status_code == 403
|
||||
assertRedirects(response, reverse("core:login") + f"?next={self.update_uv_url}")
|
||||
|
||||
# Not subscribed user
|
||||
self.client.force_login(self.guy)
|
||||
@ -312,7 +311,7 @@ class TestUVCommentCreationAndDisplay(TestCase):
|
||||
response = self.client.post(
|
||||
self.uv_url, create_uv_comment_template(self.bibou.id)
|
||||
)
|
||||
self.assertRedirects(response, self.uv_url)
|
||||
assertRedirects(response, self.uv_url)
|
||||
response = self.client.get(self.uv_url)
|
||||
self.assertContains(response, text="Superbe UV")
|
||||
|
||||
@ -338,7 +337,7 @@ class TestUVCommentCreationAndDisplay(TestCase):
|
||||
nb_comments = self.uv.comments.count()
|
||||
# Test with anonymous user
|
||||
response = self.client.post(self.uv_url, create_uv_comment_template(0))
|
||||
assert response.status_code == 403
|
||||
assertRedirects(response, reverse("core:login") + f"?next={self.uv_url}")
|
||||
|
||||
# Test with non subscribed user
|
||||
self.client.force_login(self.guy)
|
||||
@ -405,61 +404,34 @@ class TestUVCommentDelete(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.bibou = User.objects.get(username="root")
|
||||
cls.tutu = User.objects.get(username="tutu")
|
||||
cls.sli = User.objects.get(username="sli")
|
||||
cls.guy = User.objects.get(username="guy")
|
||||
cls.krophil = User.objects.get(username="krophil")
|
||||
cls.comment = baker.make(UVComment)
|
||||
|
||||
def setUp(self):
|
||||
comment_kwargs = create_uv_comment_template(
|
||||
User.objects.get(username="krophil").id
|
||||
)
|
||||
comment_kwargs["author"] = User.objects.get(id=comment_kwargs["author"])
|
||||
comment_kwargs["uv"] = UV.objects.get(id=comment_kwargs["uv"])
|
||||
self.comment = UVComment(**comment_kwargs)
|
||||
self.comment.save()
|
||||
|
||||
def test_uv_comment_delete_root_success(self):
|
||||
self.client.force_login(self.bibou)
|
||||
self.client.post(
|
||||
reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
)
|
||||
assert not UVComment.objects.filter(id=self.comment.id).exists()
|
||||
|
||||
def test_uv_comment_delete_pedagogy_admin_success(self):
|
||||
self.client.force_login(self.tutu)
|
||||
self.client.post(
|
||||
reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
)
|
||||
assert not UVComment.objects.filter(id=self.comment.id).exists()
|
||||
|
||||
def test_uv_comment_delete_author_success(self):
|
||||
self.client.force_login(self.krophil)
|
||||
self.client.post(
|
||||
reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
)
|
||||
def test_uv_comment_delete_success(self):
|
||||
url = reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
for user in (
|
||||
baker.make(User, is_superuser=True),
|
||||
baker.make(
|
||||
User, user_permissions=[Permission.objects.get(codename="view_uv")]
|
||||
),
|
||||
self.comment.author,
|
||||
):
|
||||
with self.subTest():
|
||||
self.client.force_login(user)
|
||||
self.client.post(url)
|
||||
assert not UVComment.objects.filter(id=self.comment.id).exists()
|
||||
|
||||
def test_uv_comment_delete_unauthorized_fail(self):
|
||||
url = reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
|
||||
# Anonymous user
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
)
|
||||
assert response.status_code == 403
|
||||
response = self.client.post(url)
|
||||
assertRedirects(response, reverse("core:login") + f"?next={url}")
|
||||
|
||||
# Unsbscribed user
|
||||
self.client.force_login(self.guy)
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
)
|
||||
assert response.status_code == 403
|
||||
|
||||
# Subscribed user (not author of the comment)
|
||||
self.client.force_login(self.sli)
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_delete", kwargs={"comment_id": self.comment.id})
|
||||
)
|
||||
for user in baker.make(User), subscriber_user.make():
|
||||
with self.subTest():
|
||||
self.client.force_login(user)
|
||||
response = self.client.post(url)
|
||||
assert response.status_code == 403
|
||||
|
||||
# Check that the comment still exists
|
||||
@ -499,16 +471,6 @@ class TestUVCommentUpdate(TestCase):
|
||||
self.comment.refresh_from_db()
|
||||
self.assertEqual(self.comment.comment, self.comment_edit["comment"])
|
||||
|
||||
def test_uv_comment_update_pedagogy_admin_success(self):
|
||||
self.client.force_login(self.tutu)
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_update", kwargs={"comment_id": self.comment.id}),
|
||||
self.comment_edit,
|
||||
)
|
||||
assert response.status_code == 302
|
||||
self.comment.refresh_from_db()
|
||||
self.assertEqual(self.comment.comment, self.comment_edit["comment"])
|
||||
|
||||
def test_uv_comment_update_author_success(self):
|
||||
self.client.force_login(self.krophil)
|
||||
response = self.client.post(
|
||||
@ -520,25 +482,18 @@ class TestUVCommentUpdate(TestCase):
|
||||
self.assertEqual(self.comment.comment, self.comment_edit["comment"])
|
||||
|
||||
def test_uv_comment_update_unauthorized_fail(self):
|
||||
url = reverse("pedagogy:comment_update", kwargs={"comment_id": self.comment.id})
|
||||
# Anonymous user
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_update", kwargs={"comment_id": self.comment.id}),
|
||||
self.comment_edit,
|
||||
)
|
||||
assert response.status_code == 403
|
||||
response = self.client.post(url, self.comment_edit)
|
||||
assertRedirects(response, reverse("core:login") + f"?next={url}")
|
||||
|
||||
# Unsbscribed user
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_update", kwargs={"comment_id": self.comment.id}),
|
||||
self.comment_edit,
|
||||
)
|
||||
self.client.force_login(baker.make(User))
|
||||
response = self.client.post(url, self.comment_edit)
|
||||
assert response.status_code == 403
|
||||
|
||||
# Subscribed user (not author of the comment)
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_update", kwargs={"comment_id": self.comment.id}),
|
||||
self.comment_edit,
|
||||
)
|
||||
response = self.client.post(url, self.comment_edit)
|
||||
assert response.status_code == 403
|
||||
|
||||
# Check that the comment hasn't change
|
||||
@ -611,18 +566,19 @@ class TestUVModerationForm(TestCase):
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_access_unauthorized_fail(self):
|
||||
url = reverse("pedagogy:moderation")
|
||||
# Test with anonymous user
|
||||
response = self.client.get(reverse("pedagogy:moderation"))
|
||||
assert response.status_code == 403
|
||||
response = self.client.get(url)
|
||||
assertRedirects(response, reverse("core:login") + f"?next={url}")
|
||||
|
||||
# Test with unsubscribed user
|
||||
self.client.force_login(self.guy)
|
||||
response = self.client.get(reverse("pedagogy:moderation"))
|
||||
response = self.client.get(url)
|
||||
assert response.status_code == 403
|
||||
|
||||
# Test with subscribed user
|
||||
self.client.force_login(self.sli)
|
||||
response = self.client.get(reverse("pedagogy:moderation"))
|
||||
response = self.client.get(url)
|
||||
assert response.status_code == 403
|
||||
|
||||
def test_do_nothing(self):
|
||||
|
@ -22,8 +22,7 @@
|
||||
#
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||
from django.db.models import Exists, OuterRef
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.urls import reverse, reverse_lazy
|
||||
@ -35,7 +34,7 @@ from django.views.generic import (
|
||||
UpdateView,
|
||||
)
|
||||
|
||||
from core.auth.mixins import CanEditPropMixin, CanViewMixin, FormerSubscriberMixin
|
||||
from core.auth.mixins import PermissionOrAuthorRequiredMixin
|
||||
from core.models import Notification, User
|
||||
from core.views import DetailFormView
|
||||
from pedagogy.forms import (
|
||||
@ -47,7 +46,7 @@ from pedagogy.forms import (
|
||||
from pedagogy.models import UV, UVComment, UVCommentReport
|
||||
|
||||
|
||||
class UVDetailFormView(CanViewMixin, DetailFormView):
|
||||
class UVDetailFormView(PermissionRequiredMixin, DetailFormView):
|
||||
"""Display every comment of an UV and detailed infos about it.
|
||||
|
||||
Allow to comment the UV.
|
||||
@ -57,11 +56,21 @@ class UVDetailFormView(CanViewMixin, DetailFormView):
|
||||
pk_url_kwarg = "uv_id"
|
||||
template_name = "pedagogy/uv_detail.jinja"
|
||||
form_class = UVCommentForm
|
||||
permission_required = "pedagogy.view_uv"
|
||||
|
||||
def has_permission(self):
|
||||
if self.request.method == "POST" and not self.request.user.has_perm(
|
||||
"pedagogy.add_uvcomment"
|
||||
):
|
||||
# if it's a POST request, the user is trying to add a new UVComment
|
||||
# thus he also needs the "add_uvcomment" permission
|
||||
return False
|
||||
return super().has_permission()
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs["author_id"] = self.request.user.id
|
||||
kwargs["uv_id"] = self.get_object().id
|
||||
kwargs["uv_id"] = self.object.id
|
||||
kwargs["is_creation"] = True
|
||||
return kwargs
|
||||
|
||||
@ -69,66 +78,61 @@ class UVDetailFormView(CanViewMixin, DetailFormView):
|
||||
form.save()
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy(
|
||||
"pedagogy:uv_detail", kwargs={"uv_id": self.get_object().id}
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
user = self.request.user
|
||||
return super().get_context_data(**kwargs) | {
|
||||
"can_create_uv": (
|
||||
user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
|
||||
"comments": list(
|
||||
self.object.comments.viewable_by(self.request.user)
|
||||
.annotate_is_reported()
|
||||
.select_related("author")
|
||||
.order_by("-publish_date")
|
||||
)
|
||||
}
|
||||
|
||||
def get_success_url(self):
|
||||
# once the new uv comment has been saved
|
||||
# redirect to the same page we are currently
|
||||
return self.request.path
|
||||
|
||||
class UVCommentUpdateView(CanEditPropMixin, UpdateView):
|
||||
|
||||
class UVCommentUpdateView(PermissionOrAuthorRequiredMixin, UpdateView):
|
||||
"""Allow edit of a given comment."""
|
||||
|
||||
model = UVComment
|
||||
form_class = UVCommentForm
|
||||
pk_url_kwarg = "comment_id"
|
||||
template_name = "core/edit.jinja"
|
||||
permission_required = "pedagogy.change_uvcomment"
|
||||
author_field = "author"
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
obj = self.get_object()
|
||||
kwargs["author_id"] = obj.author.id
|
||||
kwargs["uv_id"] = obj.uv.id
|
||||
kwargs["author_id"] = self.object.author_id
|
||||
kwargs["uv_id"] = self.object.uv_id
|
||||
kwargs["is_creation"] = False
|
||||
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("pedagogy:uv_detail", kwargs={"uv_id": self.object.uv.id})
|
||||
return reverse("pedagogy:uv_detail", kwargs={"uv_id": self.object.uv_id})
|
||||
|
||||
|
||||
class UVCommentDeleteView(CanEditPropMixin, DeleteView):
|
||||
class UVCommentDeleteView(PermissionOrAuthorRequiredMixin, DeleteView):
|
||||
"""Allow delete of a given comment."""
|
||||
|
||||
model = UVComment
|
||||
pk_url_kwarg = "comment_id"
|
||||
template_name = "core/delete_confirm.jinja"
|
||||
permission_required = "pedagogy.delete_uvcomment"
|
||||
author_field = "author"
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("pedagogy:uv_detail", kwargs={"uv_id": self.object.uv.id})
|
||||
return reverse("pedagogy:uv_detail", kwargs={"uv_id": self.object.uv_id})
|
||||
|
||||
|
||||
class UVGuideView(LoginRequiredMixin, FormerSubscriberMixin, TemplateView):
|
||||
class UVGuideView(PermissionRequiredMixin, TemplateView):
|
||||
"""UV guide main page."""
|
||||
|
||||
template_name = "pedagogy/guide.jinja"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
user = self.request.user
|
||||
return super().get_context_data(**kwargs) | {
|
||||
"can_create_uv": (
|
||||
user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
|
||||
)
|
||||
}
|
||||
permission_required = "pedagogy.view_uv"
|
||||
|
||||
|
||||
class UVCommentReportCreateView(PermissionRequiredMixin, CreateView):
|
||||
@ -168,21 +172,16 @@ class UVCommentReportCreateView(PermissionRequiredMixin, CreateView):
|
||||
return resp
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy(
|
||||
"pedagogy:uv_detail", kwargs={"uv_id": self.uv_comment.uv.id}
|
||||
)
|
||||
return reverse("pedagogy:uv_detail", kwargs={"uv_id": self.uv_comment.uv_id})
|
||||
|
||||
|
||||
class UVModerationFormView(FormView):
|
||||
class UVModerationFormView(PermissionRequiredMixin, FormView):
|
||||
"""Moderation interface (Privileged)."""
|
||||
|
||||
form_class = UVCommentModerationForm
|
||||
template_name = "pedagogy/moderation.jinja"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_owner(UV()):
|
||||
raise PermissionDenied
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
permission_required = "pedagogy.delete_uvcomment"
|
||||
success_url = reverse_lazy("pedagogy:moderation")
|
||||
|
||||
def form_valid(self, form):
|
||||
form_clean = form.clean()
|
||||
@ -194,9 +193,6 @@ class UVModerationFormView(FormView):
|
||||
UVCommentReport.objects.filter(id__in={d.id for d in denied}).delete()
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("pedagogy:moderation")
|
||||
|
||||
|
||||
class UVCreateView(PermissionRequiredMixin, CreateView):
|
||||
"""Add a new UV (Privileged)."""
|
||||
@ -211,34 +207,28 @@ class UVCreateView(PermissionRequiredMixin, CreateView):
|
||||
kwargs["author_id"] = self.request.user.id
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("pedagogy:uv_detail", kwargs={"uv_id": self.object.id})
|
||||
|
||||
|
||||
class UVDeleteView(CanEditPropMixin, DeleteView):
|
||||
class UVDeleteView(PermissionRequiredMixin, DeleteView):
|
||||
"""Allow to delete an UV (Privileged)."""
|
||||
|
||||
model = UV
|
||||
pk_url_kwarg = "uv_id"
|
||||
template_name = "core/delete_confirm.jinja"
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("pedagogy:guide")
|
||||
permission_required = "pedagogy.delete_uv"
|
||||
success_url = reverse_lazy("pedagogy:guide")
|
||||
|
||||
|
||||
class UVUpdateView(CanEditPropMixin, UpdateView):
|
||||
class UVUpdateView(PermissionRequiredMixin, UpdateView):
|
||||
"""Allow to edit an UV (Privilegied)."""
|
||||
|
||||
model = UV
|
||||
form_class = UVForm
|
||||
pk_url_kwarg = "uv_id"
|
||||
template_name = "pedagogy/uv_edit.jinja"
|
||||
permission_required = "pedagogy.change_uv"
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
obj = self.get_object()
|
||||
kwargs["author_id"] = obj.author.id
|
||||
kwargs["author_id"] = obj.author_id
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("pedagogy:uv_detail", kwargs={"uv_id": self.object.id})
|
||||
|
Loading…
Reference in New Issue
Block a user