Skip to content
Snippets Groups Projects
Commit d9413c9f authored by Nik | Klampfradler's avatar Nik | Klampfradler
Browse files

Merge branch '243-rewrite-notification_mark_read-with-rules-and-permissions' into 'master'

Resolve "Rewrite notification_mark_read with rules and permissions"

Closes #243

See merge request AlekSIS!243
parents ce812669 e9a035da
No related branches found
No related tags found
1 merge request!243Resolve "Rewrite notification_mark_read with rules and permissions"
Pipeline #1891 failed
...@@ -8,6 +8,7 @@ from .util.predicates import ( ...@@ -8,6 +8,7 @@ from .util.predicates import (
is_current_person, is_current_person,
has_object_perm, has_object_perm,
is_group_owner, is_group_owner,
is_notification_recipient,
) )
...@@ -104,6 +105,10 @@ add_perm("core.manage_school", manage_school_predicate) ...@@ -104,6 +105,10 @@ add_perm("core.manage_school", manage_school_predicate)
manage_data_predicate = has_person & has_global_perm("core.manage_data") manage_data_predicate = has_person & has_global_perm("core.manage_data")
add_perm("core.manage_data", manage_data_predicate) add_perm("core.manage_data", manage_data_predicate)
# Mark notification as read
mark_notification_as_read_predicate = has_person & is_notification_recipient
add_perm("core.mark_notification_as_read", mark_notification_as_read_predicate)
# View announcements # View announcements
view_announcements_predicate = has_person & ( view_announcements_predicate = has_person & (
has_global_perm("core.view_announcement") | has_any_object("core.view_announcement", Announcement) has_global_perm("core.view_announcement") | has_any_object("core.view_announcement", Announcement)
......
...@@ -4,7 +4,7 @@ from operator import itemgetter ...@@ -4,7 +4,7 @@ from operator import itemgetter
import os import os
import pkgutil import pkgutil
from importlib import import_module from importlib import import_module
from typing import Any, Callable, Sequence, Union, List from typing import Any, Callable, Sequence, Union, List, Optional
from uuid import uuid4 from uuid import uuid4
from django.conf import settings from django.conf import settings
...@@ -192,30 +192,13 @@ def now_tomorrow() -> datetime: ...@@ -192,30 +192,13 @@ def now_tomorrow() -> datetime:
return timezone.now() + timedelta(days=1) return timezone.now() + timedelta(days=1)
def get_person_by_pk(request: HttpRequest, id_: Optional[int] = None): def objectgetter_optional(model: Model, default: Optional[Any] = None, default_eval: bool = False) -> Callable[[HttpRequest, Optional[int]], Model]:
""" Get a person by its ID, defaulting to person in request's user """ """ Get an object by pk, defaulting to None """
from ..models import Person # noqa def get_object(request: HttpRequest, id_: Optional[int] = None) -> Model:
if id_ is not None:
if id_: return get_object_or_404(model, pk=id_)
return get_object_or_404(Person, pk=id_) else:
else: return eval(default) if default_eval else default
return request.user.person
def get_group_by_pk(request: HttpRequest, id_: Optional[int] = None) -> Group:
""" Get a group by its ID, defaulting to None """
if id_:
return get_object_or_404(Group, id=id_)
return None
def get_announcement_by_pk(request: HttpRequest, id_: Optional[int] = None):
""" Get an announcement by its ID; defaulting to None """
if id_:
return get_object_or_404(Announcement, pk=pk)
return None return get_object
...@@ -90,3 +90,9 @@ def is_group_owner(user: User, group: Group) -> bool: ...@@ -90,3 +90,9 @@ def is_group_owner(user: User, group: Group) -> bool:
return group.owners.filter(owners=user.person).exists() return group.owners.filter(owners=user.person).exists()
@predicate
def is_notification_recipient(user: User, obj: Model) -> bool:
""" Predicate which checks whether the recipient of the notification a user wants to mark read is this user """
return user == obj.recipient.user
...@@ -33,7 +33,7 @@ from .registries import site_preferences_registry, group_preferences_registry, p ...@@ -33,7 +33,7 @@ from .registries import site_preferences_registry, group_preferences_registry, p
from .tables import GroupsTable, PersonsTable from .tables import GroupsTable, PersonsTable
from .util import messages from .util import messages
from .util.apps import AppConfig from .util.apps import AppConfig
from .util.core_helpers import get_announcement_by_pk, get_group_by_pk, get_person_by_pk from .util.core_helpers import objectgetter_optional
@permission_required("core.view_dashboard") @permission_required("core.view_dashboard")
...@@ -97,13 +97,13 @@ def persons(request: HttpRequest) -> HttpResponse: ...@@ -97,13 +97,13 @@ def persons(request: HttpRequest) -> HttpResponse:
return render(request, "core/persons.html", context) return render(request, "core/persons.html", context)
@permission_required("core.view_person", fn=get_person_by_pk) @permission_required("core.view_person", fn=objectgetter_optional(Person, "request.user.person", True))
def person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse: def person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
""" Detail view for one person; defaulting to logged-in person """ """ Detail view for one person; defaulting to logged-in person """
context = {} context = {}
person = get_person_by_pk(request, id_) person = objectgetter_optional(Person, "request.user.person", True)(request, id_)
context["person"] = person context["person"] = person
# Get groups where person is member of # Get groups where person is member of
...@@ -117,13 +117,13 @@ def person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse: ...@@ -117,13 +117,13 @@ def person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
return render(request, "core/person_full.html", context) return render(request, "core/person_full.html", context)
@permission_required("core.view_group", fn=get_group_by_pk) @permission_required("core.view_group", fn=objectgetter_optional(Group, None, False))
def group(request: HttpRequest, id_: int) -> HttpResponse: def group(request: HttpRequest, id_: int) -> HttpResponse:
""" Detail view for one group """ """ Detail view for one group """
context = {} context = {}
group = get_group_by_pk(request, id_) group = objectgetter_optional(Group, None, False)(request, id_)
context["group"] = group context["group"] = group
# Get group # Get group
...@@ -224,13 +224,13 @@ def groups_child_groups(request: HttpRequest) -> HttpResponse: ...@@ -224,13 +224,13 @@ def groups_child_groups(request: HttpRequest) -> HttpResponse:
return render(request, "core/groups_child_groups.html", context) return render(request, "core/groups_child_groups.html", context)
@permission_required("core.edit_person", fn=get_person_by_pk) @permission_required("core.edit_person", fn=objectgetter_optional(Person, "request.user.person", True))
def edit_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse: def edit_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
""" Edit view for a single person, defaulting to logged-in person """ """ Edit view for a single person, defaulting to logged-in person """
context = {} context = {}
person = get_person_by_pk(request, id_) person = objectgetter_optional(Person, "request.user.person", True)(request, id_)
context["person"] = person context["person"] = person
edit_person_form = EditPersonForm(request.POST or None, request.FILES or None, instance=person) edit_person_form = EditPersonForm(request.POST or None, request.FILES or None, instance=person)
...@@ -255,13 +255,13 @@ def get_group_by_id(request: HttpRequest, id_: Optional[int] = None): ...@@ -255,13 +255,13 @@ def get_group_by_id(request: HttpRequest, id_: Optional[int] = None):
return None return None
@permission_required("core.edit_group", fn=get_group_by_pk) @permission_required("core.edit_group", fn=objectgetter_optional(Group, None, False))
def edit_group(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse: def edit_group(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
""" View to edit or create a group """ """ View to edit or create a group """
context = {} context = {}
group = get_group_by_pk(request, id_) group = objectgetter_optional(Group, None, False)(request, id_)
context["group"] = group context["group"] = group
if id_: if id_:
...@@ -301,18 +301,16 @@ def system_status(request: HttpRequest) -> HttpResponse: ...@@ -301,18 +301,16 @@ def system_status(request: HttpRequest) -> HttpResponse:
return render(request, "core/system_status.html", context) return render(request, "core/system_status.html", context)
@permission_required("core.mark_notification_as_read", fn=objectgetter_optional(Notification, None, False))
def notification_mark_read(request: HttpRequest, id_: int) -> HttpResponse: def notification_mark_read(request: HttpRequest, id_: int) -> HttpResponse:
""" Mark a notification read """ """ Mark a notification read """
context = {} context = {}
notification = get_object_or_404(Notification, pk=id_) notification = objectgetter_optional(Notification, None, False)(request, id_)
if notification.recipient.user == request.user: notification.read = True
notification.read = True notification.save()
notification.save()
else:
raise PermissionDenied(_("You are not allowed to mark notifications from other users as read!"))
# Redirect to dashboard as this is only used from there if JavaScript is unavailable # Redirect to dashboard as this is only used from there if JavaScript is unavailable
return redirect("index") return redirect("index")
...@@ -331,13 +329,13 @@ def announcements(request: HttpRequest) -> HttpResponse: ...@@ -331,13 +329,13 @@ def announcements(request: HttpRequest) -> HttpResponse:
return render(request, "core/announcement/list.html", context) return render(request, "core/announcement/list.html", context)
@permission_required("core.create_or_edit_announcement", fn=get_announcement_by_pk) @permission_required("core.create_or_edit_announcement", fn=objectgetter_optional(Announcement, None, False))
def announcement_form(request: HttpRequest, pk: Optional[int] = None) -> HttpResponse: def announcement_form(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
""" View to create or edit an announcement """ """ View to create or edit an announcement """
context = {} context = {}
announcement = get_announcement_by_pk(request, pk) announcement = objectgetter_optional(Announcement, None, False)(request, id_)
if announcement: if announcement:
# Edit form for existing announcement # Edit form for existing announcement
...@@ -363,12 +361,12 @@ def announcement_form(request: HttpRequest, pk: Optional[int] = None) -> HttpRes ...@@ -363,12 +361,12 @@ def announcement_form(request: HttpRequest, pk: Optional[int] = None) -> HttpRes
return render(request, "core/announcement/form.html", context) return render(request, "core/announcement/form.html", context)
@permission_required("core.delete_announcement", fn=get_announcement_by_pk) @permission_required("core.delete_announcement", fn=objectgetter_optional(Announcement, None, False))
def delete_announcement(request: HttpRequest, pk: int) -> HttpResponse: def delete_announcement(request: HttpRequest, id_: int) -> HttpResponse:
""" View to delete an announcement """ """ View to delete an announcement """
if request.method == "POST": if request.method == "POST":
announcement = get_announcement_by_pk(request, pk) announcement = objectgetter_optional(Announcement, None, False)(request, id_)
announcement.delete() announcement.delete()
messages.success(request, _("The announcement has been deleted.")) messages.success(request, _("The announcement has been deleted."))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment