We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Unassigned permissions not working
Non-admin accounts are seeing an incorrect amount of spatial entries in the search results. Here are two results: 1) from my `@kitwar`e account which is an admin and one from my `@gmail` account that has no permissions. Using the changes from #401: 

https://github.com/ResonantGeoData/ResonantGeoData/blob/014ce2693a0a3e899d6af0a9d7822a5f1327268c/rgd/geodata/permissions.py#L108

You can see 475 results with the admin account (which is the correct amount) and 4949 results with the nonadmin account which hits that new code (this number is wildly incorrect): 

| admin | nonadmin |
| --- | --- |
| ![Screen Shot 2021-05-25 at 8 14 00 AM](https://user-images.githubusercontent.com/22067021/119513980-e9e3ce00-bd31-11eb-8a27-44c49b20d1d4.png) | ![Screen Shot 2021-05-25 at 8 13 51 AM](https://user-images.githubusercontent.com/22067021/119514301-21eb1100-bd32-11eb-941c-96ecd6b18a31.png) |



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `rgd/geodata/permissions.py`
Content:
```
1 from typing import Optional
2 
3 from django.conf import settings
4 from django.contrib.auth.backends import BaseBackend
5 from django.core.exceptions import PermissionDenied
6 from django.db.models.functions import Coalesce
7 
8 from rgd.geodata import models
9 
10 
11 def annotate_queryset(queryset):
12     """Annotate the queryset to include a path to a collection.
13 
14     Some models don't have a direct path to `collection`
15     and must be annotated to include it.
16     """
17     model = queryset.model
18     if model == models.SpatialEntry:
19         return queryset.annotate(
20             _collection_permissions__user=Coalesce(
21                 'fmventry__fmv_file__file__collection__collection_permissions__user',
22                 'geometryentry__geometry_archive__file__collection__collection_permissions__user',
23                 'rastermetaentry__parent_raster__image_set__images__image_file__file__collection__collection_permissions__user',
24             ),
25             _collection_permissions__role=Coalesce(
26                 'fmventry__fmv_file__file__collection__collection_permissions__role',
27                 'geometryentry__geometry_archive__file__collection__collection_permissions__role',
28                 'rastermetaentry__parent_raster__image_set__images__image_file__file__collection__collection_permissions__role',
29             ),
30         )
31     return queryset
32 
33 
34 def get_collection_membership_path(model) -> Optional[str]:
35     """Get the path to the 'CollectionPermission' model.
36 
37     Relationships are represented as 'dunder's ('__'). Returning `None`
38     means the model is explicitly unprotected.
39     """
40     # Collection
41     if issubclass(model, models.CollectionPermission):
42         return ''
43     if issubclass(model, models.Collection):
44         return 'collection_permissions'
45     # Common
46     if issubclass(model, models.ChecksumFile):
47         return 'collection__collection_permissions'
48     # Imagery
49     if issubclass(model, models.ImageEntry):
50         return 'image_file__file__collection__collection_permissions'
51     if issubclass(model, models.ImageSet):
52         return 'images__image_file__file__collection__collection_permissions'
53     if issubclass(model, models.RasterEntry):
54         return 'image_set__images__image_file__file__collection__collection_permissions'
55     if issubclass(model, models.RasterMetaEntry):
56         return (
57             'parent_raster__image_set__images__image_file__file__collection__collection_permissions'
58         )
59     if issubclass(model, models.BandMetaEntry):
60         return 'parent_image__image_file__file__collection__collection_permissions'
61     if issubclass(model, models.ConvertedImageFile):
62         return 'source_image__image_file__file__collection__collection_permissions'
63     if issubclass(model, models.SubsampledImage):
64         return 'source_image__image_file__file__collection__collection_permissions'
65     if issubclass(model, models.KWCOCOArchive):
66         return 'spec_file__collection__collection_permissions'
67     # Annotation
68     if issubclass(model, models.Annotation):
69         return 'image__image_file__collection__collection_permissions'
70     if issubclass(model, models.Segmentation):
71         return 'annotation__image__image_file__collection__collection_permissions'
72     # Geometry
73     if issubclass(model, models.GeometryEntry):
74         return 'geometry_archive__file__collection__collection_permissions'
75     # FMV
76     if issubclass(model, models.FMVEntry):
77         return 'fmv_file__file__collection__collection_permissions'
78     # SpatialEntry
79     if model == models.SpatialEntry:
80         return '_collection_permissions'
81 
82     raise NotImplementedError
83 
84 
85 def filter_perm(user, queryset, role):
86     """Filter a queryset."""
87     # Called outside of view
88     if user is None:
89         return queryset
90     # Must be logged in
91     if not user.is_active or user.is_anonymous:
92         return queryset.none()
93     # Superusers can see all (not staff users)
94     if user.is_active and user.is_superuser:
95         return queryset
96     # No relationship to collection
97     path = get_collection_membership_path(queryset.model)
98     if path is None:
99         return queryset
100     # Check permissions
101     # `path` can be an empty string (meaning queryset is `CollectionPermission`)
102     user_path = (path + '__' if path != '' else path) + 'user'
103     role_path = (path + '__' if path != '' else path) + 'role'
104     queryset = annotate_queryset(queryset)
105     filtered = queryset.filter(**{user_path: user.pk}).exclude(**{role_path + '__lt': role})
106     # Check setting for unassigned permissions
107     if settings.RGD_GLOBAL_READ_ACCESS:
108         unassigned = queryset.filter(**{user_path + '__isnull': True})
109         return unassigned | filtered
110     return filtered
111 
112 
113 def filter_read_perm(user, queryset):
114     """Filter a queryset to what the user may read."""
115     return filter_perm(user, queryset, models.CollectionPermission.READER)
116 
117 
118 def filter_write_perm(user, queryset):
119     """Filter a queryset to what the user may edit."""
120     return filter_perm(user, queryset, models.CollectionPermission.OWNER)
121 
122 
123 def check_read_perm(user, obj):
124     """Raise 'PermissionDenied' error if user does not have read permissions."""
125     model = type(obj)
126     if not filter_read_perm(user, model.objects.filter(pk=obj.pk)).exists():
127         raise PermissionDenied
128 
129 
130 def check_write_perm(user, obj):
131     """Raise 'PermissionDenied' error if user does not have write permissions."""
132     # Called outside of view
133     model = type(obj)
134     if not filter_write_perm(user, model.objects.filter(pk=obj.pk)).exists():
135         raise PermissionDenied
136 
137 
138 class CollectionAuthorizationBackend(BaseBackend):
139     def has_perm(self, user, perm, obj=None):
140         """Supplement default Django permission backend.
141 
142         Returns `True` if the user has the specified permission, where perm is in the format
143         `"<app label>.<permission codename>"`. If the user is
144         inactive, this method will always return False. For an active superuser, this method
145         will always return `True`.
146 
147         https://docs.djangoproject.com/en/3.1/ref/contrib/auth/#django.contrib.auth.models.User.has_perm
148         """
149         app_label, codename = perm.split('.')
150         if app_label == 'geodata':
151             if codename.startswith('view'):
152                 check_read_perm(user, obj)
153             if (
154                 codename.startswith('add')
155                 or codename.startswith('delete')
156                 or codename.startswith('change')
157             ):
158                 check_write_perm(user, obj)
159
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/rgd/geodata/permissions.py b/rgd/geodata/permissions.py
--- a/rgd/geodata/permissions.py
+++ b/rgd/geodata/permissions.py
@@ -102,10 +102,12 @@
     user_path = (path + '__' if path != '' else path) + 'user'
     role_path = (path + '__' if path != '' else path) + 'role'
     queryset = annotate_queryset(queryset)
-    filtered = queryset.filter(**{user_path: user.pk}).exclude(**{role_path + '__lt': role})
+    filtered = (
+        queryset.filter(**{user_path: user.pk}).exclude(**{role_path + '__lt': role}).distinct()
+    )
     # Check setting for unassigned permissions
     if settings.RGD_GLOBAL_READ_ACCESS:
-        unassigned = queryset.filter(**{user_path + '__isnull': True})
+        unassigned = queryset.filter(**{user_path + '__isnull': True}).distinct()
         return unassigned | filtered
     return filtered

{"golden_diff": "diff --git a/rgd/geodata/permissions.py b/rgd/geodata/permissions.py\n--- a/rgd/geodata/permissions.py\n+++ b/rgd/geodata/permissions.py\n@@ -102,10 +102,12 @@\n     user_path = (path + '__' if path != '' else path) + 'user'\n     role_path = (path + '__' if path != '' else path) + 'role'\n     queryset = annotate_queryset(queryset)\n-    filtered = queryset.filter(**{user_path: user.pk}).exclude(**{role_path + '__lt': role})\n+    filtered = (\n+        queryset.filter(**{user_path: user.pk}).exclude(**{role_path + '__lt': role}).distinct()\n+    )\n     # Check setting for unassigned permissions\n     if settings.RGD_GLOBAL_READ_ACCESS:\n-        unassigned = queryset.filter(**{user_path + '__isnull': True})\n+        unassigned = queryset.filter(**{user_path + '__isnull': True}).distinct()\n         return unassigned | filtered\n     return filtered\n", "issue": "Unassigned permissions not working\nNon-admin accounts are seeing an incorrect amount of spatial entries in the search results. Here are two results: 1) from my `@kitwar`e account which is an admin and one from my `@gmail` account that has no permissions. Using the changes from #401: \r\n\r\nhttps://github.com/ResonantGeoData/ResonantGeoData/blob/014ce2693a0a3e899d6af0a9d7822a5f1327268c/rgd/geodata/permissions.py#L108\r\n\r\nYou can see 475 results with the admin account (which is the correct amount) and 4949 results with the nonadmin account which hits that new code (this number is wildly incorrect): \r\n\r\n| admin | nonadmin |\r\n| --- | --- |\r\n| ![Screen Shot 2021-05-25 at 8 14 00 AM](https://user-images.githubusercontent.com/22067021/119513980-e9e3ce00-bd31-11eb-8a27-44c49b20d1d4.png) | ![Screen Shot 2021-05-25 at 8 13 51 AM](https://user-images.githubusercontent.com/22067021/119514301-21eb1100-bd32-11eb-941c-96ecd6b18a31.png) |\r\n\r\n\n", "before_files": [{"content": "from typing import Optional\n\nfrom django.conf import settings\nfrom django.contrib.auth.backends import BaseBackend\nfrom django.core.exceptions import PermissionDenied\nfrom django.db.models.functions import Coalesce\n\nfrom rgd.geodata import models\n\n\ndef annotate_queryset(queryset):\n    \"\"\"Annotate the queryset to include a path to a collection.\n\n    Some models don't have a direct path to `collection`\n    and must be annotated to include it.\n    \"\"\"\n    model = queryset.model\n    if model == models.SpatialEntry:\n        return queryset.annotate(\n            _collection_permissions__user=Coalesce(\n                'fmventry__fmv_file__file__collection__collection_permissions__user',\n                'geometryentry__geometry_archive__file__collection__collection_permissions__user',\n                'rastermetaentry__parent_raster__image_set__images__image_file__file__collection__collection_permissions__user',\n            ),\n            _collection_permissions__role=Coalesce(\n                'fmventry__fmv_file__file__collection__collection_permissions__role',\n                'geometryentry__geometry_archive__file__collection__collection_permissions__role',\n                'rastermetaentry__parent_raster__image_set__images__image_file__file__collection__collection_permissions__role',\n            ),\n        )\n    return queryset\n\n\ndef get_collection_membership_path(model) -> Optional[str]:\n    \"\"\"Get the path to the 'CollectionPermission' model.\n\n    Relationships are represented as 'dunder's ('__'). Returning `None`\n    means the model is explicitly unprotected.\n    \"\"\"\n    # Collection\n    if issubclass(model, models.CollectionPermission):\n        return ''\n    if issubclass(model, models.Collection):\n        return 'collection_permissions'\n    # Common\n    if issubclass(model, models.ChecksumFile):\n        return 'collection__collection_permissions'\n    # Imagery\n    if issubclass(model, models.ImageEntry):\n        return 'image_file__file__collection__collection_permissions'\n    if issubclass(model, models.ImageSet):\n        return 'images__image_file__file__collection__collection_permissions'\n    if issubclass(model, models.RasterEntry):\n        return 'image_set__images__image_file__file__collection__collection_permissions'\n    if issubclass(model, models.RasterMetaEntry):\n        return (\n            'parent_raster__image_set__images__image_file__file__collection__collection_permissions'\n        )\n    if issubclass(model, models.BandMetaEntry):\n        return 'parent_image__image_file__file__collection__collection_permissions'\n    if issubclass(model, models.ConvertedImageFile):\n        return 'source_image__image_file__file__collection__collection_permissions'\n    if issubclass(model, models.SubsampledImage):\n        return 'source_image__image_file__file__collection__collection_permissions'\n    if issubclass(model, models.KWCOCOArchive):\n        return 'spec_file__collection__collection_permissions'\n    # Annotation\n    if issubclass(model, models.Annotation):\n        return 'image__image_file__collection__collection_permissions'\n    if issubclass(model, models.Segmentation):\n        return 'annotation__image__image_file__collection__collection_permissions'\n    # Geometry\n    if issubclass(model, models.GeometryEntry):\n        return 'geometry_archive__file__collection__collection_permissions'\n    # FMV\n    if issubclass(model, models.FMVEntry):\n        return 'fmv_file__file__collection__collection_permissions'\n    # SpatialEntry\n    if model == models.SpatialEntry:\n        return '_collection_permissions'\n\n    raise NotImplementedError\n\n\ndef filter_perm(user, queryset, role):\n    \"\"\"Filter a queryset.\"\"\"\n    # Called outside of view\n    if user is None:\n        return queryset\n    # Must be logged in\n    if not user.is_active or user.is_anonymous:\n        return queryset.none()\n    # Superusers can see all (not staff users)\n    if user.is_active and user.is_superuser:\n        return queryset\n    # No relationship to collection\n    path = get_collection_membership_path(queryset.model)\n    if path is None:\n        return queryset\n    # Check permissions\n    # `path` can be an empty string (meaning queryset is `CollectionPermission`)\n    user_path = (path + '__' if path != '' else path) + 'user'\n    role_path = (path + '__' if path != '' else path) + 'role'\n    queryset = annotate_queryset(queryset)\n    filtered = queryset.filter(**{user_path: user.pk}).exclude(**{role_path + '__lt': role})\n    # Check setting for unassigned permissions\n    if settings.RGD_GLOBAL_READ_ACCESS:\n        unassigned = queryset.filter(**{user_path + '__isnull': True})\n        return unassigned | filtered\n    return filtered\n\n\ndef filter_read_perm(user, queryset):\n    \"\"\"Filter a queryset to what the user may read.\"\"\"\n    return filter_perm(user, queryset, models.CollectionPermission.READER)\n\n\ndef filter_write_perm(user, queryset):\n    \"\"\"Filter a queryset to what the user may edit.\"\"\"\n    return filter_perm(user, queryset, models.CollectionPermission.OWNER)\n\n\ndef check_read_perm(user, obj):\n    \"\"\"Raise 'PermissionDenied' error if user does not have read permissions.\"\"\"\n    model = type(obj)\n    if not filter_read_perm(user, model.objects.filter(pk=obj.pk)).exists():\n        raise PermissionDenied\n\n\ndef check_write_perm(user, obj):\n    \"\"\"Raise 'PermissionDenied' error if user does not have write permissions.\"\"\"\n    # Called outside of view\n    model = type(obj)\n    if not filter_write_perm(user, model.objects.filter(pk=obj.pk)).exists():\n        raise PermissionDenied\n\n\nclass CollectionAuthorizationBackend(BaseBackend):\n    def has_perm(self, user, perm, obj=None):\n        \"\"\"Supplement default Django permission backend.\n\n        Returns `True` if the user has the specified permission, where perm is in the format\n        `\"<app label>.<permission codename>\"`. If the user is\n        inactive, this method will always return False. For an active superuser, this method\n        will always return `True`.\n\n        https://docs.djangoproject.com/en/3.1/ref/contrib/auth/#django.contrib.auth.models.User.has_perm\n        \"\"\"\n        app_label, codename = perm.split('.')\n        if app_label == 'geodata':\n            if codename.startswith('view'):\n                check_read_perm(user, obj)\n            if (\n                codename.startswith('add')\n                or codename.startswith('delete')\n                or codename.startswith('change')\n            ):\n                check_write_perm(user, obj)\n", "path": "rgd/geodata/permissions.py"}], "after_files": [{"content": "from typing import Optional\n\nfrom django.conf import settings\nfrom django.contrib.auth.backends import BaseBackend\nfrom django.core.exceptions import PermissionDenied\nfrom django.db.models.functions import Coalesce\n\nfrom rgd.geodata import models\n\n\ndef annotate_queryset(queryset):\n    \"\"\"Annotate the queryset to include a path to a collection.\n\n    Some models don't have a direct path to `collection`\n    and must be annotated to include it.\n    \"\"\"\n    model = queryset.model\n    if model == models.SpatialEntry:\n        return queryset.annotate(\n            _collection_permissions__user=Coalesce(\n                'fmventry__fmv_file__file__collection__collection_permissions__user',\n                'geometryentry__geometry_archive__file__collection__collection_permissions__user',\n                'rastermetaentry__parent_raster__image_set__images__image_file__file__collection__collection_permissions__user',\n            ),\n            _collection_permissions__role=Coalesce(\n                'fmventry__fmv_file__file__collection__collection_permissions__role',\n                'geometryentry__geometry_archive__file__collection__collection_permissions__role',\n                'rastermetaentry__parent_raster__image_set__images__image_file__file__collection__collection_permissions__role',\n            ),\n        )\n    return queryset\n\n\ndef get_collection_membership_path(model) -> Optional[str]:\n    \"\"\"Get the path to the 'CollectionPermission' model.\n\n    Relationships are represented as 'dunder's ('__'). Returning `None`\n    means the model is explicitly unprotected.\n    \"\"\"\n    # Collection\n    if issubclass(model, models.CollectionPermission):\n        return ''\n    if issubclass(model, models.Collection):\n        return 'collection_permissions'\n    # Common\n    if issubclass(model, models.ChecksumFile):\n        return 'collection__collection_permissions'\n    # Imagery\n    if issubclass(model, models.ImageEntry):\n        return 'image_file__file__collection__collection_permissions'\n    if issubclass(model, models.ImageSet):\n        return 'images__image_file__file__collection__collection_permissions'\n    if issubclass(model, models.RasterEntry):\n        return 'image_set__images__image_file__file__collection__collection_permissions'\n    if issubclass(model, models.RasterMetaEntry):\n        return (\n            'parent_raster__image_set__images__image_file__file__collection__collection_permissions'\n        )\n    if issubclass(model, models.BandMetaEntry):\n        return 'parent_image__image_file__file__collection__collection_permissions'\n    if issubclass(model, models.ConvertedImageFile):\n        return 'source_image__image_file__file__collection__collection_permissions'\n    if issubclass(model, models.SubsampledImage):\n        return 'source_image__image_file__file__collection__collection_permissions'\n    if issubclass(model, models.KWCOCOArchive):\n        return 'spec_file__collection__collection_permissions'\n    # Annotation\n    if issubclass(model, models.Annotation):\n        return 'image__image_file__collection__collection_permissions'\n    if issubclass(model, models.Segmentation):\n        return 'annotation__image__image_file__collection__collection_permissions'\n    # Geometry\n    if issubclass(model, models.GeometryEntry):\n        return 'geometry_archive__file__collection__collection_permissions'\n    # FMV\n    if issubclass(model, models.FMVEntry):\n        return 'fmv_file__file__collection__collection_permissions'\n    # SpatialEntry\n    if model == models.SpatialEntry:\n        return '_collection_permissions'\n\n    raise NotImplementedError\n\n\ndef filter_perm(user, queryset, role):\n    \"\"\"Filter a queryset.\"\"\"\n    # Called outside of view\n    if user is None:\n        return queryset\n    # Must be logged in\n    if not user.is_active or user.is_anonymous:\n        return queryset.none()\n    # Superusers can see all (not staff users)\n    if user.is_active and user.is_superuser:\n        return queryset\n    # No relationship to collection\n    path = get_collection_membership_path(queryset.model)\n    if path is None:\n        return queryset\n    # Check permissions\n    # `path` can be an empty string (meaning queryset is `CollectionPermission`)\n    user_path = (path + '__' if path != '' else path) + 'user'\n    role_path = (path + '__' if path != '' else path) + 'role'\n    queryset = annotate_queryset(queryset)\n    filtered = (\n        queryset.filter(**{user_path: user.pk}).exclude(**{role_path + '__lt': role}).distinct()\n    )\n    # Check setting for unassigned permissions\n    if settings.RGD_GLOBAL_READ_ACCESS:\n        unassigned = queryset.filter(**{user_path + '__isnull': True}).distinct()\n        return unassigned | filtered\n    return filtered\n\n\ndef filter_read_perm(user, queryset):\n    \"\"\"Filter a queryset to what the user may read.\"\"\"\n    return filter_perm(user, queryset, models.CollectionPermission.READER)\n\n\ndef filter_write_perm(user, queryset):\n    \"\"\"Filter a queryset to what the user may edit.\"\"\"\n    return filter_perm(user, queryset, models.CollectionPermission.OWNER)\n\n\ndef check_read_perm(user, obj):\n    \"\"\"Raise 'PermissionDenied' error if user does not have read permissions.\"\"\"\n    model = type(obj)\n    if not filter_read_perm(user, model.objects.filter(pk=obj.pk)).exists():\n        raise PermissionDenied\n\n\ndef check_write_perm(user, obj):\n    \"\"\"Raise 'PermissionDenied' error if user does not have write permissions.\"\"\"\n    # Called outside of view\n    model = type(obj)\n    if not filter_write_perm(user, model.objects.filter(pk=obj.pk)).exists():\n        raise PermissionDenied\n\n\nclass CollectionAuthorizationBackend(BaseBackend):\n    def has_perm(self, user, perm, obj=None):\n        \"\"\"Supplement default Django permission backend.\n\n        Returns `True` if the user has the specified permission, where perm is in the format\n        `\"<app label>.<permission codename>\"`. If the user is\n        inactive, this method will always return False. For an active superuser, this method\n        will always return `True`.\n\n        https://docs.djangoproject.com/en/3.1/ref/contrib/auth/#django.contrib.auth.models.User.has_perm\n        \"\"\"\n        app_label, codename = perm.split('.')\n        if app_label == 'geodata':\n            if codename.startswith('view'):\n                check_read_perm(user, obj)\n            if (\n                codename.startswith('add')\n                or codename.startswith('delete')\n                or codename.startswith('change')\n            ):\n                check_write_perm(user, obj)\n", "path": "rgd/geodata/permissions.py"}]}