Repository: DDMAL/CantusDB

Issue:
Lists of users in admin area are weird
In investigating #1000, I came again across some weird behavior - I'd noted it in the past, and didn't open an issue because it seemed pretty minor. But since it's actually starting to cause problems/confusion, it would be worth properly sorting out.

On the Change Source page (https://cantusdatabase.org/admin/main_app/source/714807/change/), in the "Current Editors" widget, Hilkka-Liisa Vuori's name appears twice.
![Screenshot 2023-09-05 at 9 21 57 AM](https://github.com/DDMAL/CantusDB/assets/58090591/3ecbdfee-7722-47d3-a89c-e78cbb0b6ddd)

This does not seem to affect any of the other User List widgets ("Inventoried by", "Full text entered by", ..., "Other editors").

On Production, she is currently listed twice among the "Chosen current editors". I tried selecting the first instance of her name, moving it back to the "Available current editors", and saving. Two instances of her name still appeared among the chosen editors. Trying to select the second instance and moving it back to available editors had the same (non-) effect. But if I selected both copies of her name, moved them back to "Available current editors", and pressed save, both instances were successfully moved from "chosen" to "available". From here, picking a single instance of her name among available and moving it to "chosen" was sufficient to cause both instances of her name to move to "chosen".


Discussion:
Looking at `main_app/forms.py`, I see that the Current Editors form we use for the admin area is set up a bit differently from the others:

```python
current_editors = forms.ModelMultipleChoiceField(
    queryset=get_user_model()
    .objects.filter(
        Q(groups__name="project manager") # note the filtering by multiple Q objects
        | Q(groups__name="editor")
        | Q(groups__name="contributor")
    )
    .order_by("full_name"),
    required=False,
    widget=FilteredSelectMultiple(verbose_name="current editors", is_stacked=False),
)

inventoried_by = forms.ModelMultipleChoiceField(
    queryset=get_user_model().objects.all().order_by("full_name"), # no Q objects
    required=False,
    widget=FilteredSelectMultiple(verbose_name="inventoried by", is_stacked=False),
)
```

Looking at the groups Hilkka is assigned to, she is indeed both an "editor" and a "contributor". Let me do a bit more investigation to see whether I can recreate this behavior locally by assigning a user to multiple user groups.

It seems possible that the union `|` operator is causing users to be listed multiple times if they appear in multiple querysets. This suggests a possible solution - I think `.filter()` has an optional `unique` parameter, which we could use to ensure users appear only once (it would also likely make the page load more slowly).

**This raises a larger question, though - why do we need to filter users for the "Current Editors" widget?** Can we not just have all the users appear in this list? There's only one reason I can think to do it the current way: I can imagine an administrator adding a user, adding them as a "current editor" for a source, but forgetting to add them to any group, and then being confused when that user cannot edit the sources because they are not a member of the "contributor" group. By filtering as we do currently, the newly created user doesn't appear in the list until they've been added to the "contributor" group, meaning the administrator can catch this oversight earlier.

One other important thing to note with this: "current editors" affects permissions, while I believe all the other widgets are just for giving people credit for work they've done.

So, question: can we just list all the users in the "Current Editors" widget, as we do for the other user list widgets?
> I can imagine an administrator adding a user, adding them as a "current editor" for a source, but forgetting to add them to any group, and then being confused when that user cannot edit the sources because they are not a member of the "contributor" group. 

For this reason, I think it makes more sense to use the `unique` filter you suggested from the queryset that contains duplicate users. This would avoid any possible confusion in the future about adding editors to sources. 

Another question, why should users belong to multiple groups? For example, if a user is both a contributor and and editor, are there any specific permissions that a contributor has that an editor does not?

> Another question, why should users belong to multiple groups? For example, if a user is both a contributor and and editor, are there any specific permissions that a contributor has that an editor does not?


I've wondered this myself...aren't the permissions all subsets/supersets of other categories?


Resolving patch:
diff --git a/django/cantusdb_project/main_app/forms.py b/django/cantusdb_project/main_app/forms.py
--- a/django/cantusdb_project/main_app/forms.py
+++ b/django/cantusdb_project/main_app/forms.py
@@ -838,6 +838,7 @@ class Meta:
             | Q(groups__name="editor")
             | Q(groups__name="contributor")
         )
+        .distinct()
         .order_by("full_name"),
         required=False,
         widget=FilteredSelectMultiple(verbose_name="current editors", is_stacked=False),


Test patch: