diff --git a/django/cantusdb_project/main_app/permissions.py b/django/cantusdb_project/main_app/permissions.py index 6b48b7253..c5c647485 100644 --- a/django/cantusdb_project/main_app/permissions.py +++ b/django/cantusdb_project/main_app/permissions.py @@ -1,15 +1,18 @@ +from typing import Optional, Union from django.db.models import Q -from typing import Optional +from django.core.exceptions import PermissionDenied +from django.contrib.auth.models import AnonymousUser from main_app.models import ( Source, Chant, Sequence, ) from users.models import User -from django.core.exceptions import PermissionDenied -def user_can_edit_chants_in_source(user: User, source: Optional[Source]) -> bool: +def user_can_edit_chants_in_source( + user: Union[User, AnonymousUser], source: Optional[Source] +) -> bool: """ Checks if the user can edit Chants in a given Source. Used in ChantDetail, ChantList, ChantCreate, ChantDelete, ChantEdit, @@ -22,16 +25,17 @@ def user_can_edit_chants_in_source(user: User, source: Optional[Source]) -> bool return False source_id = source.id - user_is_assigned_to_source: bool = user.sources_user_can_edit.filter( # noqa + user_is_assigned_to_source = user.sources_user_can_edit.filter( # type: ignore[attr-defined] id=source_id ).exists() - user_is_project_manager: bool = user.groups.filter(name="project manager").exists() - user_is_editor: bool = user.groups.filter(name="editor").exists() - user_is_contributor: bool = user.groups.filter(name="contributor").exists() + user_groups = user.groups.all().values_list("name", flat=True) + user_is_pm = "project manager" in user_groups + user_is_editor = "editor" in user_groups + user_is_contributor = "contributor" in user_groups return ( - user_is_project_manager + user_is_pm or (user_is_editor and user_is_assigned_to_source) or (user_is_editor and source.created_by == user) or (user_is_contributor and user_is_assigned_to_source) @@ -51,14 +55,15 @@ def user_can_proofread_chant(user: User, chant: Chant) -> bool: return False source_id = chant.source.id - user_is_assigned_to_source: bool = user.sources_user_can_edit.filter( # noqa + user_is_assigned_to_source = user.sources_user_can_edit.filter( # type: ignore[attr-defined] id=source_id ).exists() - user_is_project_manager: bool = user.groups.filter(name="project manager").exists() - user_is_editor: bool = user.groups.filter(name="editor").exists() + user_groups = user.groups.all().values_list("name", flat=True) + user_is_pm = "project manager" in user_groups + user_is_editor = "editor" in user_groups - return user_is_project_manager or (user_is_editor and user_is_assigned_to_source) + return user_is_pm or (user_is_editor and user_is_assigned_to_source) def user_can_view_source(user: User, source: Source) -> bool: @@ -100,16 +105,17 @@ def user_can_edit_sequences(user: User, sequence: Sequence) -> bool: return False source_id = source.id - user_is_assigned_to_source: bool = user.sources_user_can_edit.filter( # noqa + user_is_assigned_to_source = user.sources_user_can_edit.filter( # type: ignore[attr-defined] id=source_id ).exists() - user_is_project_manager: bool = user.groups.filter(name="project manager").exists() - user_is_editor: bool = user.groups.filter(name="editor").exists() - user_is_contributor: bool = user.groups.filter(name="contributor").exists() + user_groups = user.groups.all().values_list("name", flat=True) + user_is_pm = "project manager" in user_groups + user_is_editor = "editor" in user_groups + user_is_contributor = "contributor" in user_groups return ( - user_is_project_manager + user_is_pm or (user_is_editor and user_is_assigned_to_source) or (user_is_editor and source.created_by == user) or (user_is_contributor and user_is_assigned_to_source) @@ -136,11 +142,14 @@ def user_can_edit_source(user: User, source: Source) -> bool: if user.is_anonymous: return False source_id = source.id - assigned_to_source = user.sources_user_can_edit.filter(id=source_id) # noqa + assigned_to_source = user.sources_user_can_edit.filter( # type: ignore[attr-defined] + id=source_id + ) - is_project_manager: bool = user.groups.filter(name="project manager").exists() - is_editor: bool = user.groups.filter(name="editor").exists() - is_contributor: bool = user.groups.filter(name="contributor").exists() + user_groups = user.groups.all().values_list("name", flat=True) + is_project_manager: bool = "project manager" in user_groups + is_editor: bool = "editor" in user_groups + is_contributor: bool = "contributor" in user_groups return ( is_project_manager @@ -152,8 +161,8 @@ def user_can_edit_source(user: User, source: Source) -> bool: def user_can_view_user_detail(viewing_user: User, user: User) -> bool: """ - Checks if the user can view the user detail pages of regular users in the database or just indexers. - Used in UserDetailView. + Checks if the user can view the user detail pages of regular users in + the database or just indexers. Used in UserDetailView. """ return viewing_user.is_authenticated or user.is_indexer diff --git a/django/cantusdb_project/main_app/views/source.py b/django/cantusdb_project/main_app/views/source.py index c2d79d0c5..49b261218 100644 --- a/django/cantusdb_project/main_app/views/source.py +++ b/django/cantusdb_project/main_app/views/source.py @@ -61,6 +61,7 @@ class SourceBrowseChantsView(ListView): context_object_name = "chants" template_name = "browse_chants.html" pk_url_kwarg = "source_id" + source: Source def get_queryset(self): """Gather the chants to be displayed. @@ -73,6 +74,7 @@ def get_queryset(self): """ source_id = self.kwargs.get(self.pk_url_kwarg) source = get_object_or_404(Source, id=source_id) + self.source = source display_unpublished = self.request.user.is_authenticated if (source.published is False) and (not display_unpublished): @@ -104,8 +106,7 @@ def get_queryset(self): def get_context_data(self, **kwargs): context: dict = super().get_context_data(**kwargs) - source_id: int = self.kwargs.get(self.pk_url_kwarg) - source: Source = get_object_or_404(Source, id=source_id) + source: Source = self.source if source.segment_id != CANTUS_SEGMENT_ID: # the chant list ("Browse Chants") page should only be visitable # for sources in the CANTUS Database segment, as sources in the Bower @@ -175,11 +176,11 @@ class SourceDetailView(DetailView): def get_queryset(self): return self.model.objects.select_related( - "holding_institution", "segment", "provenance" + "holding_institution", "segment", "provenance", "created_by" ).all() def get_context_data(self, **kwargs): - source = self.get_object() + source = self.object user = self.request.user if not user_can_view_source(user, source):