Repository: DDMAL/CantusDB

Issue:
Users assigned to Bower sources should be able to edit sequences in those sources
Currently, only project managers can edit sequences. Debra requests that editors should be able to be assigned to Bower sources and edit the sequences contained therein.


Discussion:
Most of the work to fix this will be in [`permissions.py`](https://github.com/DDMAL/CantusDB/blob/develop/django/cantusdb_project/main_app/permissions.py) - It will require changing `user_can_edit_sequences` to look more like `user_can_edit_chants_in_source`.
I didn't get any correspondence about this requested change. Does this seem more like a high-, medium- or low-priority issue, @dchiller?
Came out of something Debra requested yesterday...will forward now to you @jacobdgm and @lucasmarchd01 so you have the context.
Sorry, forgot to mention this 

> Does this seem more like a high-, medium- or low-priority issue, @dchiller?

I think high?
@jacobdgm I am pretty sure somebody is about to embark on a project to clean up some of the Bower stuff; they can probably postpone it some (since I think it is a side project) but better to have it sooner rather than later.
Yes, @annamorphism, per Debra's instructions I gave her Debra-level access yesterday so that she could start work. When we get this up we will remove her Debra-level access and just keep her on as an "editor" of the Bower sources.

Resolving patch:
diff --git a/django/cantusdb_project/main_app/permissions.py b/django/cantusdb_project/main_app/permissions.py
--- a/django/cantusdb_project/main_app/permissions.py
+++ b/django/cantusdb_project/main_app/permissions.py
@@ -82,12 +82,31 @@ def user_can_view_sequence(user: User, sequence: Sequence) -> bool:
     return (source is not None) and ((source.published) or (user_is_authenticated))
 
 
-def user_can_edit_sequences(user: User) -> bool:
+def user_can_edit_sequences(user: User, sequence: Sequence) -> bool:
     """
     Checks if the user has permission to edit a Sequence object.
     Used in SequenceDetail and SequenceEdit views.
     """
-    return user.groups.filter(name="project manager").exists()
+    source = sequence.source
+    if user.is_anonymous or (source is None):
+        return False
+
+    source_id = source.id
+    user_is_assigned_to_source: bool = user.sources_user_can_edit.filter(
+        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()
+
+    return (
+        (user_is_project_manager)
+        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)
+        or (user_is_contributor and source.created_by == user)
+    )
 
 
 def user_can_create_sources(user: User) -> bool:
diff --git a/django/cantusdb_project/main_app/views/sequence.py b/django/cantusdb_project/main_app/views/sequence.py
--- a/django/cantusdb_project/main_app/views/sequence.py
+++ b/django/cantusdb_project/main_app/views/sequence.py
@@ -36,7 +36,7 @@ def get_context_data(self, **kwargs):
             .select_related("source")
             .order_by("siglum")
         )
-        context["user_can_edit_sequence"] = user_can_edit_sequences(user)
+        context["user_can_edit_sequence"] = user_can_edit_sequences(user, sequence)
         return context
 
 
@@ -86,4 +86,5 @@ def form_valid(self, form):
 
     def test_func(self):
         user = self.request.user
-        return user_can_edit_sequences(user)
+        sequence = self.get_object()
+        return user_can_edit_sequences(user, sequence)


Test patch: