We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[PUI] Global login
Global Login (CUI logs in PUI and vice versa) is not working (anymore)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `InvenTree/users/api.py`
Content:
```
1 """DRF API definition for the 'users' app."""
2 
3 import datetime
4 import logging
5 
6 from django.contrib.auth.models import Group, User
7 from django.urls import include, path, re_path
8 
9 from rest_framework import exceptions, permissions
10 from rest_framework.response import Response
11 from rest_framework.views import APIView
12 
13 import InvenTree.helpers
14 from InvenTree.filters import SEARCH_ORDER_FILTER
15 from InvenTree.mixins import (
16     ListAPI,
17     ListCreateAPI,
18     RetrieveAPI,
19     RetrieveUpdateAPI,
20     RetrieveUpdateDestroyAPI,
21 )
22 from InvenTree.serializers import ExendedUserSerializer, UserCreateSerializer
23 from users.models import ApiToken, Owner, RuleSet, check_user_role
24 from users.serializers import GroupSerializer, OwnerSerializer
25 
26 logger = logging.getLogger('inventree')
27 
28 
29 class OwnerList(ListAPI):
30     """List API endpoint for Owner model.
31 
32     Cannot create.
33     """
34 
35     queryset = Owner.objects.all()
36     serializer_class = OwnerSerializer
37 
38     def filter_queryset(self, queryset):
39         """Implement text search for the "owner" model.
40 
41         Note that an "owner" can be either a group, or a user,
42         so we cannot do a direct text search.
43 
44         A "hack" here is to post-process the queryset and simply
45         remove any values which do not match.
46 
47         It is not necessarily "efficient" to do it this way,
48         but until we determine a better way, this is what we have...
49         """
50         search_term = str(self.request.query_params.get('search', '')).lower()
51         is_active = self.request.query_params.get('is_active', None)
52 
53         queryset = super().filter_queryset(queryset)
54 
55         results = []
56 
57         # Get a list of all matching users, depending on the *is_active* flag
58         if is_active is not None:
59             is_active = InvenTree.helpers.str2bool(is_active)
60             matching_user_ids = User.objects.filter(is_active=is_active).values_list(
61                 'pk', flat=True
62             )
63 
64         for result in queryset.all():
65             name = str(result.name()).lower().strip()
66             search_match = True
67 
68             # Extract search term f
69             if search_term:
70                 for entry in search_term.strip().split(' '):
71                     if entry not in name:
72                         search_match = False
73                         break
74 
75             if not search_match:
76                 continue
77 
78             if is_active is not None:
79                 # Skip any users which do not match the required *is_active* value
80                 if (
81                     result.owner_type.name == 'user'
82                     and result.owner_id not in matching_user_ids
83                 ):
84                     continue
85 
86             # If we get here, there is no reason *not* to include this result
87             results.append(result)
88 
89         return results
90 
91 
92 class OwnerDetail(RetrieveAPI):
93     """Detail API endpoint for Owner model.
94 
95     Cannot edit or delete
96     """
97 
98     queryset = Owner.objects.all()
99     serializer_class = OwnerSerializer
100 
101 
102 class RoleDetails(APIView):
103     """API endpoint which lists the available role permissions for the current user.
104 
105     (Requires authentication)
106     """
107 
108     permission_classes = [permissions.IsAuthenticated]
109 
110     def get(self, request, *args, **kwargs):
111         """Return the list of roles / permissions available to the current user."""
112         user = request.user
113 
114         roles = {}
115 
116         for ruleset in RuleSet.RULESET_CHOICES:
117             role, _text = ruleset
118 
119             permissions = []
120 
121             for permission in RuleSet.RULESET_PERMISSIONS:
122                 if check_user_role(user, role, permission):
123                     permissions.append(permission)
124 
125             if len(permissions) > 0:
126                 roles[role] = permissions
127             else:
128                 roles[role] = None  # pragma: no cover
129 
130         data = {
131             'user': user.pk,
132             'username': user.username,
133             'roles': roles,
134             'is_staff': user.is_staff,
135             'is_superuser': user.is_superuser,
136         }
137 
138         return Response(data)
139 
140 
141 class UserDetail(RetrieveUpdateDestroyAPI):
142     """Detail endpoint for a single user."""
143 
144     queryset = User.objects.all()
145     serializer_class = ExendedUserSerializer
146     permission_classes = [permissions.IsAuthenticated]
147 
148 
149 class MeUserDetail(RetrieveUpdateAPI, UserDetail):
150     """Detail endpoint for current user."""
151 
152     def get_object(self):
153         """Always return the current user object."""
154         return self.request.user
155 
156 
157 class UserList(ListCreateAPI):
158     """List endpoint for detail on all users."""
159 
160     queryset = User.objects.all()
161     serializer_class = UserCreateSerializer
162     permission_classes = [permissions.IsAuthenticated]
163     filter_backends = SEARCH_ORDER_FILTER
164 
165     search_fields = ['first_name', 'last_name', 'username']
166 
167     ordering_fields = [
168         'email',
169         'username',
170         'first_name',
171         'last_name',
172         'is_staff',
173         'is_superuser',
174         'is_active',
175     ]
176 
177     filterset_fields = ['is_staff', 'is_active', 'is_superuser']
178 
179 
180 class GroupDetail(RetrieveUpdateDestroyAPI):
181     """Detail endpoint for a particular auth group."""
182 
183     queryset = Group.objects.all()
184     serializer_class = GroupSerializer
185     permission_classes = [permissions.IsAuthenticated]
186 
187 
188 class GroupList(ListCreateAPI):
189     """List endpoint for all auth groups."""
190 
191     queryset = Group.objects.all()
192     serializer_class = GroupSerializer
193     permission_classes = [permissions.IsAuthenticated]
194 
195     filter_backends = SEARCH_ORDER_FILTER
196 
197     search_fields = ['name']
198 
199     ordering_fields = ['name']
200 
201 
202 class GetAuthToken(APIView):
203     """Return authentication token for an authenticated user."""
204 
205     permission_classes = [permissions.IsAuthenticated]
206 
207     def get(self, request, *args, **kwargs):
208         """Return an API token if the user is authenticated.
209 
210         - If the user already has a matching token, delete it and create a new one
211         - Existing tokens are *never* exposed again via the API
212         - Once the token is provided, it can be used for auth until it expires
213         """
214         if request.user.is_authenticated:
215             user = request.user
216             name = request.query_params.get('name', '')
217 
218             name = ApiToken.sanitize_name(name)
219 
220             today = datetime.date.today()
221 
222             # Find existing token, which has not expired
223             token = ApiToken.objects.filter(
224                 user=user, name=name, revoked=False, expiry__gte=today
225             ).first()
226 
227             if not token:
228                 # User is authenticated, and requesting a token against the provided name.
229                 token = ApiToken.objects.create(user=request.user, name=name)
230 
231             # Add some metadata about the request
232             token.set_metadata('user_agent', request.META.get('HTTP_USER_AGENT', ''))
233             token.set_metadata('remote_addr', request.META.get('REMOTE_ADDR', ''))
234             token.set_metadata('remote_host', request.META.get('REMOTE_HOST', ''))
235             token.set_metadata('remote_user', request.META.get('REMOTE_USER', ''))
236             token.set_metadata('server_name', request.META.get('SERVER_NAME', ''))
237             token.set_metadata('server_port', request.META.get('SERVER_PORT', ''))
238 
239             data = {'token': token.key, 'name': token.name, 'expiry': token.expiry}
240 
241             logger.info(
242                 "Created new API token for user '%s' (name='%s')", user.username, name
243             )
244 
245             return Response(data)
246 
247         else:
248             raise exceptions.NotAuthenticated()
249 
250 
251 user_urls = [
252     path('roles/', RoleDetails.as_view(), name='api-user-roles'),
253     path('token/', GetAuthToken.as_view(), name='api-token'),
254     path('me/', MeUserDetail.as_view(), name='api-user-me'),
255     path(
256         'owner/',
257         include([
258             path('<int:pk>/', OwnerDetail.as_view(), name='api-owner-detail'),
259             path('', OwnerList.as_view(), name='api-owner-list'),
260         ]),
261     ),
262     path(
263         'group/',
264         include([
265             re_path(
266                 r'^(?P<pk>[0-9]+)/?$', GroupDetail.as_view(), name='api-group-detail'
267             ),
268             path('', GroupList.as_view(), name='api-group-list'),
269         ]),
270     ),
271     re_path(r'^(?P<pk>[0-9]+)/?$', UserDetail.as_view(), name='api-user-detail'),
272     path('', UserList.as_view(), name='api-user-list'),
273 ]
274
```
--- 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/InvenTree/users/api.py b/InvenTree/users/api.py
--- a/InvenTree/users/api.py
+++ b/InvenTree/users/api.py
@@ -3,6 +3,7 @@
 import datetime
 import logging
 
+from django.contrib.auth import get_user, login
 from django.contrib.auth.models import Group, User
 from django.urls import include, path, re_path
 
@@ -242,6 +243,10 @@
                 "Created new API token for user '%s' (name='%s')", user.username, name
             )
 
+            # Ensure that the users session is logged in (PUI -> CUI login)
+            if not get_user(request).is_authenticated:
+                login(request, user)
+
             return Response(data)
 
         else:

{"golden_diff": "diff --git a/InvenTree/users/api.py b/InvenTree/users/api.py\n--- a/InvenTree/users/api.py\n+++ b/InvenTree/users/api.py\n@@ -3,6 +3,7 @@\n import datetime\n import logging\n \n+from django.contrib.auth import get_user, login\n from django.contrib.auth.models import Group, User\n from django.urls import include, path, re_path\n \n@@ -242,6 +243,10 @@\n                 \"Created new API token for user '%s' (name='%s')\", user.username, name\n             )\n \n+            # Ensure that the users session is logged in (PUI -> CUI login)\n+            if not get_user(request).is_authenticated:\n+                login(request, user)\n+\n             return Response(data)\n \n         else:\n", "issue": "[PUI] Global login\nGlobal Login (CUI logs in PUI and vice versa) is not working (anymore)\n", "before_files": [{"content": "\"\"\"DRF API definition for the 'users' app.\"\"\"\n\nimport datetime\nimport logging\n\nfrom django.contrib.auth.models import Group, User\nfrom django.urls import include, path, re_path\n\nfrom rest_framework import exceptions, permissions\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\nimport InvenTree.helpers\nfrom InvenTree.filters import SEARCH_ORDER_FILTER\nfrom InvenTree.mixins import (\n    ListAPI,\n    ListCreateAPI,\n    RetrieveAPI,\n    RetrieveUpdateAPI,\n    RetrieveUpdateDestroyAPI,\n)\nfrom InvenTree.serializers import ExendedUserSerializer, UserCreateSerializer\nfrom users.models import ApiToken, Owner, RuleSet, check_user_role\nfrom users.serializers import GroupSerializer, OwnerSerializer\n\nlogger = logging.getLogger('inventree')\n\n\nclass OwnerList(ListAPI):\n    \"\"\"List API endpoint for Owner model.\n\n    Cannot create.\n    \"\"\"\n\n    queryset = Owner.objects.all()\n    serializer_class = OwnerSerializer\n\n    def filter_queryset(self, queryset):\n        \"\"\"Implement text search for the \"owner\" model.\n\n        Note that an \"owner\" can be either a group, or a user,\n        so we cannot do a direct text search.\n\n        A \"hack\" here is to post-process the queryset and simply\n        remove any values which do not match.\n\n        It is not necessarily \"efficient\" to do it this way,\n        but until we determine a better way, this is what we have...\n        \"\"\"\n        search_term = str(self.request.query_params.get('search', '')).lower()\n        is_active = self.request.query_params.get('is_active', None)\n\n        queryset = super().filter_queryset(queryset)\n\n        results = []\n\n        # Get a list of all matching users, depending on the *is_active* flag\n        if is_active is not None:\n            is_active = InvenTree.helpers.str2bool(is_active)\n            matching_user_ids = User.objects.filter(is_active=is_active).values_list(\n                'pk', flat=True\n            )\n\n        for result in queryset.all():\n            name = str(result.name()).lower().strip()\n            search_match = True\n\n            # Extract search term f\n            if search_term:\n                for entry in search_term.strip().split(' '):\n                    if entry not in name:\n                        search_match = False\n                        break\n\n            if not search_match:\n                continue\n\n            if is_active is not None:\n                # Skip any users which do not match the required *is_active* value\n                if (\n                    result.owner_type.name == 'user'\n                    and result.owner_id not in matching_user_ids\n                ):\n                    continue\n\n            # If we get here, there is no reason *not* to include this result\n            results.append(result)\n\n        return results\n\n\nclass OwnerDetail(RetrieveAPI):\n    \"\"\"Detail API endpoint for Owner model.\n\n    Cannot edit or delete\n    \"\"\"\n\n    queryset = Owner.objects.all()\n    serializer_class = OwnerSerializer\n\n\nclass RoleDetails(APIView):\n    \"\"\"API endpoint which lists the available role permissions for the current user.\n\n    (Requires authentication)\n    \"\"\"\n\n    permission_classes = [permissions.IsAuthenticated]\n\n    def get(self, request, *args, **kwargs):\n        \"\"\"Return the list of roles / permissions available to the current user.\"\"\"\n        user = request.user\n\n        roles = {}\n\n        for ruleset in RuleSet.RULESET_CHOICES:\n            role, _text = ruleset\n\n            permissions = []\n\n            for permission in RuleSet.RULESET_PERMISSIONS:\n                if check_user_role(user, role, permission):\n                    permissions.append(permission)\n\n            if len(permissions) > 0:\n                roles[role] = permissions\n            else:\n                roles[role] = None  # pragma: no cover\n\n        data = {\n            'user': user.pk,\n            'username': user.username,\n            'roles': roles,\n            'is_staff': user.is_staff,\n            'is_superuser': user.is_superuser,\n        }\n\n        return Response(data)\n\n\nclass UserDetail(RetrieveUpdateDestroyAPI):\n    \"\"\"Detail endpoint for a single user.\"\"\"\n\n    queryset = User.objects.all()\n    serializer_class = ExendedUserSerializer\n    permission_classes = [permissions.IsAuthenticated]\n\n\nclass MeUserDetail(RetrieveUpdateAPI, UserDetail):\n    \"\"\"Detail endpoint for current user.\"\"\"\n\n    def get_object(self):\n        \"\"\"Always return the current user object.\"\"\"\n        return self.request.user\n\n\nclass UserList(ListCreateAPI):\n    \"\"\"List endpoint for detail on all users.\"\"\"\n\n    queryset = User.objects.all()\n    serializer_class = UserCreateSerializer\n    permission_classes = [permissions.IsAuthenticated]\n    filter_backends = SEARCH_ORDER_FILTER\n\n    search_fields = ['first_name', 'last_name', 'username']\n\n    ordering_fields = [\n        'email',\n        'username',\n        'first_name',\n        'last_name',\n        'is_staff',\n        'is_superuser',\n        'is_active',\n    ]\n\n    filterset_fields = ['is_staff', 'is_active', 'is_superuser']\n\n\nclass GroupDetail(RetrieveUpdateDestroyAPI):\n    \"\"\"Detail endpoint for a particular auth group.\"\"\"\n\n    queryset = Group.objects.all()\n    serializer_class = GroupSerializer\n    permission_classes = [permissions.IsAuthenticated]\n\n\nclass GroupList(ListCreateAPI):\n    \"\"\"List endpoint for all auth groups.\"\"\"\n\n    queryset = Group.objects.all()\n    serializer_class = GroupSerializer\n    permission_classes = [permissions.IsAuthenticated]\n\n    filter_backends = SEARCH_ORDER_FILTER\n\n    search_fields = ['name']\n\n    ordering_fields = ['name']\n\n\nclass GetAuthToken(APIView):\n    \"\"\"Return authentication token for an authenticated user.\"\"\"\n\n    permission_classes = [permissions.IsAuthenticated]\n\n    def get(self, request, *args, **kwargs):\n        \"\"\"Return an API token if the user is authenticated.\n\n        - If the user already has a matching token, delete it and create a new one\n        - Existing tokens are *never* exposed again via the API\n        - Once the token is provided, it can be used for auth until it expires\n        \"\"\"\n        if request.user.is_authenticated:\n            user = request.user\n            name = request.query_params.get('name', '')\n\n            name = ApiToken.sanitize_name(name)\n\n            today = datetime.date.today()\n\n            # Find existing token, which has not expired\n            token = ApiToken.objects.filter(\n                user=user, name=name, revoked=False, expiry__gte=today\n            ).first()\n\n            if not token:\n                # User is authenticated, and requesting a token against the provided name.\n                token = ApiToken.objects.create(user=request.user, name=name)\n\n            # Add some metadata about the request\n            token.set_metadata('user_agent', request.META.get('HTTP_USER_AGENT', ''))\n            token.set_metadata('remote_addr', request.META.get('REMOTE_ADDR', ''))\n            token.set_metadata('remote_host', request.META.get('REMOTE_HOST', ''))\n            token.set_metadata('remote_user', request.META.get('REMOTE_USER', ''))\n            token.set_metadata('server_name', request.META.get('SERVER_NAME', ''))\n            token.set_metadata('server_port', request.META.get('SERVER_PORT', ''))\n\n            data = {'token': token.key, 'name': token.name, 'expiry': token.expiry}\n\n            logger.info(\n                \"Created new API token for user '%s' (name='%s')\", user.username, name\n            )\n\n            return Response(data)\n\n        else:\n            raise exceptions.NotAuthenticated()\n\n\nuser_urls = [\n    path('roles/', RoleDetails.as_view(), name='api-user-roles'),\n    path('token/', GetAuthToken.as_view(), name='api-token'),\n    path('me/', MeUserDetail.as_view(), name='api-user-me'),\n    path(\n        'owner/',\n        include([\n            path('<int:pk>/', OwnerDetail.as_view(), name='api-owner-detail'),\n            path('', OwnerList.as_view(), name='api-owner-list'),\n        ]),\n    ),\n    path(\n        'group/',\n        include([\n            re_path(\n                r'^(?P<pk>[0-9]+)/?$', GroupDetail.as_view(), name='api-group-detail'\n            ),\n            path('', GroupList.as_view(), name='api-group-list'),\n        ]),\n    ),\n    re_path(r'^(?P<pk>[0-9]+)/?$', UserDetail.as_view(), name='api-user-detail'),\n    path('', UserList.as_view(), name='api-user-list'),\n]\n", "path": "InvenTree/users/api.py"}], "after_files": [{"content": "\"\"\"DRF API definition for the 'users' app.\"\"\"\n\nimport datetime\nimport logging\n\nfrom django.contrib.auth import get_user, login\nfrom django.contrib.auth.models import Group, User\nfrom django.urls import include, path, re_path\n\nfrom rest_framework import exceptions, permissions\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\nimport InvenTree.helpers\nfrom InvenTree.filters import SEARCH_ORDER_FILTER\nfrom InvenTree.mixins import (\n    ListAPI,\n    ListCreateAPI,\n    RetrieveAPI,\n    RetrieveUpdateAPI,\n    RetrieveUpdateDestroyAPI,\n)\nfrom InvenTree.serializers import ExendedUserSerializer, UserCreateSerializer\nfrom users.models import ApiToken, Owner, RuleSet, check_user_role\nfrom users.serializers import GroupSerializer, OwnerSerializer\n\nlogger = logging.getLogger('inventree')\n\n\nclass OwnerList(ListAPI):\n    \"\"\"List API endpoint for Owner model.\n\n    Cannot create.\n    \"\"\"\n\n    queryset = Owner.objects.all()\n    serializer_class = OwnerSerializer\n\n    def filter_queryset(self, queryset):\n        \"\"\"Implement text search for the \"owner\" model.\n\n        Note that an \"owner\" can be either a group, or a user,\n        so we cannot do a direct text search.\n\n        A \"hack\" here is to post-process the queryset and simply\n        remove any values which do not match.\n\n        It is not necessarily \"efficient\" to do it this way,\n        but until we determine a better way, this is what we have...\n        \"\"\"\n        search_term = str(self.request.query_params.get('search', '')).lower()\n        is_active = self.request.query_params.get('is_active', None)\n\n        queryset = super().filter_queryset(queryset)\n\n        results = []\n\n        # Get a list of all matching users, depending on the *is_active* flag\n        if is_active is not None:\n            is_active = InvenTree.helpers.str2bool(is_active)\n            matching_user_ids = User.objects.filter(is_active=is_active).values_list(\n                'pk', flat=True\n            )\n\n        for result in queryset.all():\n            name = str(result.name()).lower().strip()\n            search_match = True\n\n            # Extract search term f\n            if search_term:\n                for entry in search_term.strip().split(' '):\n                    if entry not in name:\n                        search_match = False\n                        break\n\n            if not search_match:\n                continue\n\n            if is_active is not None:\n                # Skip any users which do not match the required *is_active* value\n                if (\n                    result.owner_type.name == 'user'\n                    and result.owner_id not in matching_user_ids\n                ):\n                    continue\n\n            # If we get here, there is no reason *not* to include this result\n            results.append(result)\n\n        return results\n\n\nclass OwnerDetail(RetrieveAPI):\n    \"\"\"Detail API endpoint for Owner model.\n\n    Cannot edit or delete\n    \"\"\"\n\n    queryset = Owner.objects.all()\n    serializer_class = OwnerSerializer\n\n\nclass RoleDetails(APIView):\n    \"\"\"API endpoint which lists the available role permissions for the current user.\n\n    (Requires authentication)\n    \"\"\"\n\n    permission_classes = [permissions.IsAuthenticated]\n\n    def get(self, request, *args, **kwargs):\n        \"\"\"Return the list of roles / permissions available to the current user.\"\"\"\n        user = request.user\n\n        roles = {}\n\n        for ruleset in RuleSet.RULESET_CHOICES:\n            role, _text = ruleset\n\n            permissions = []\n\n            for permission in RuleSet.RULESET_PERMISSIONS:\n                if check_user_role(user, role, permission):\n                    permissions.append(permission)\n\n            if len(permissions) > 0:\n                roles[role] = permissions\n            else:\n                roles[role] = None  # pragma: no cover\n\n        data = {\n            'user': user.pk,\n            'username': user.username,\n            'roles': roles,\n            'is_staff': user.is_staff,\n            'is_superuser': user.is_superuser,\n        }\n\n        return Response(data)\n\n\nclass UserDetail(RetrieveUpdateDestroyAPI):\n    \"\"\"Detail endpoint for a single user.\"\"\"\n\n    queryset = User.objects.all()\n    serializer_class = ExendedUserSerializer\n    permission_classes = [permissions.IsAuthenticated]\n\n\nclass MeUserDetail(RetrieveUpdateAPI, UserDetail):\n    \"\"\"Detail endpoint for current user.\"\"\"\n\n    def get_object(self):\n        \"\"\"Always return the current user object.\"\"\"\n        return self.request.user\n\n\nclass UserList(ListCreateAPI):\n    \"\"\"List endpoint for detail on all users.\"\"\"\n\n    queryset = User.objects.all()\n    serializer_class = UserCreateSerializer\n    permission_classes = [permissions.IsAuthenticated]\n    filter_backends = SEARCH_ORDER_FILTER\n\n    search_fields = ['first_name', 'last_name', 'username']\n\n    ordering_fields = [\n        'email',\n        'username',\n        'first_name',\n        'last_name',\n        'is_staff',\n        'is_superuser',\n        'is_active',\n    ]\n\n    filterset_fields = ['is_staff', 'is_active', 'is_superuser']\n\n\nclass GroupDetail(RetrieveUpdateDestroyAPI):\n    \"\"\"Detail endpoint for a particular auth group.\"\"\"\n\n    queryset = Group.objects.all()\n    serializer_class = GroupSerializer\n    permission_classes = [permissions.IsAuthenticated]\n\n\nclass GroupList(ListCreateAPI):\n    \"\"\"List endpoint for all auth groups.\"\"\"\n\n    queryset = Group.objects.all()\n    serializer_class = GroupSerializer\n    permission_classes = [permissions.IsAuthenticated]\n\n    filter_backends = SEARCH_ORDER_FILTER\n\n    search_fields = ['name']\n\n    ordering_fields = ['name']\n\n\nclass GetAuthToken(APIView):\n    \"\"\"Return authentication token for an authenticated user.\"\"\"\n\n    permission_classes = [permissions.IsAuthenticated]\n\n    def get(self, request, *args, **kwargs):\n        \"\"\"Return an API token if the user is authenticated.\n\n        - If the user already has a matching token, delete it and create a new one\n        - Existing tokens are *never* exposed again via the API\n        - Once the token is provided, it can be used for auth until it expires\n        \"\"\"\n        if request.user.is_authenticated:\n            user = request.user\n            name = request.query_params.get('name', '')\n\n            name = ApiToken.sanitize_name(name)\n\n            today = datetime.date.today()\n\n            # Find existing token, which has not expired\n            token = ApiToken.objects.filter(\n                user=user, name=name, revoked=False, expiry__gte=today\n            ).first()\n\n            if not token:\n                # User is authenticated, and requesting a token against the provided name.\n                token = ApiToken.objects.create(user=request.user, name=name)\n\n            # Add some metadata about the request\n            token.set_metadata('user_agent', request.META.get('HTTP_USER_AGENT', ''))\n            token.set_metadata('remote_addr', request.META.get('REMOTE_ADDR', ''))\n            token.set_metadata('remote_host', request.META.get('REMOTE_HOST', ''))\n            token.set_metadata('remote_user', request.META.get('REMOTE_USER', ''))\n            token.set_metadata('server_name', request.META.get('SERVER_NAME', ''))\n            token.set_metadata('server_port', request.META.get('SERVER_PORT', ''))\n\n            data = {'token': token.key, 'name': token.name, 'expiry': token.expiry}\n\n            logger.info(\n                \"Created new API token for user '%s' (name='%s')\", user.username, name\n            )\n\n            # Ensure that the users session is logged in (PUI -> CUI login)\n            if not get_user(request).is_authenticated:\n                login(request, user)\n\n            return Response(data)\n\n        else:\n            raise exceptions.NotAuthenticated()\n\n\nuser_urls = [\n    path('roles/', RoleDetails.as_view(), name='api-user-roles'),\n    path('token/', GetAuthToken.as_view(), name='api-token'),\n    path('me/', MeUserDetail.as_view(), name='api-user-me'),\n    path(\n        'owner/',\n        include([\n            path('<int:pk>/', OwnerDetail.as_view(), name='api-owner-detail'),\n            path('', OwnerList.as_view(), name='api-owner-list'),\n        ]),\n    ),\n    path(\n        'group/',\n        include([\n            re_path(\n                r'^(?P<pk>[0-9]+)/?$', GroupDetail.as_view(), name='api-group-detail'\n            ),\n            path('', GroupList.as_view(), name='api-group-list'),\n        ]),\n    ),\n    re_path(r'^(?P<pk>[0-9]+)/?$', UserDetail.as_view(), name='api-user-detail'),\n    path('', UserList.as_view(), name='api-user-list'),\n]\n", "path": "InvenTree/users/api.py"}]}