mirror of
https://github.com/inventree/InvenTree.git
synced 2026-11-10 02:47:49 +00:00
Logout user when deleting UserSession (#13145)
This commit is contained in:
1 parent
b5cfd9528e
commit
9bb7d23f80
3 files changed
+61
No files matched your search
@@ -44,6 +44,15 @@ admin.site.register(Schedule, ReadOnlyScheduleAdmin)
|
||||
class InvenTreeUserSessionAdmin(NoEditAdminMixin, UserSessionAdmin):
|
||||
"""Admin interface for UserSession - view and delete only, no add or edit."""
|
||||
|
||||
def delete_model(self, request, obj):
|
||||
"""End the underlying session, not just the tracking record."""
|
||||
obj.end()
|
||||
|
||||
def delete_queryset(self, request, queryset):
|
||||
"""End the underlying sessions, not just the tracking records."""
|
||||
for session in queryset:
|
||||
session.end()
|
||||
|
||||
|
||||
admin.site.unregister(UserSession)
|
||||
admin.site.register(UserSession, InvenTreeUserSessionAdmin)
|
||||
@@ -198,6 +198,8 @@ class UserDetail(RetrieveUpdateDestroyAPI):
|
||||
"""Override destroy method to ensure sessions are deleted first."""
|
||||
# Remove all sessions for this user
|
||||
if sessions := instance.usersession_set.all():
|
||||
for session in sessions:
|
||||
session.end()
|
||||
sessions.delete()
|
||||
# Normally delete the user
|
||||
return super().perform_destroy(instance)
|
||||
|
||||
@@ -534,6 +534,56 @@ class AdminTest(AdminTestCase):
|
||||
)
|
||||
self.assertEqual(qs.count(), 0)
|
||||
|
||||
def test_usersession_admin_delete(self):
|
||||
"""Deleting a UserSession via the admin must log the user out."""
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.sessions.models import Session
|
||||
|
||||
from allauth.usersessions.models import UserSession
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
victim = get_user_model().objects.create_user(
|
||||
username='victim', password='password'
|
||||
)
|
||||
me_url = reverse('api-user-me')
|
||||
|
||||
def login_victim():
|
||||
"""Log in as the victim user and return the client and its UserSession."""
|
||||
client = APIClient()
|
||||
client.login(username='victim', password='password')
|
||||
self.assertEqual(client.get(me_url).status_code, 200)
|
||||
# client.login() bypasses the allauth signal which tracks the session
|
||||
session = UserSession.objects.create(
|
||||
user=victim, session_key=client.session.session_key, ip='127.0.0.1'
|
||||
)
|
||||
return client, session
|
||||
|
||||
def check_logged_out(client, session):
|
||||
"""Check the victim session has been ended."""
|
||||
self.assertFalse(UserSession.objects.filter(pk=session.pk).exists())
|
||||
self.assertFalse(Session.objects.filter(pk=session.session_key).exists())
|
||||
self.assertIn(client.get(me_url).status_code, [401, 403])
|
||||
|
||||
# Single object delete view
|
||||
client, session = login_victim()
|
||||
self.client.post(
|
||||
reverse('admin:usersessions_usersession_delete', args=[session.pk]),
|
||||
{'post': 'yes'},
|
||||
)
|
||||
check_logged_out(client, session)
|
||||
|
||||
# Bulk "delete selected" action
|
||||
client, session = login_victim()
|
||||
self.client.post(
|
||||
reverse('admin:usersessions_usersession_changelist'),
|
||||
{
|
||||
'action': 'delete_selected',
|
||||
'_selected_action': [session.pk],
|
||||
'post': 'yes',
|
||||
},
|
||||
)
|
||||
check_logged_out(client, session)
|
||||
|
||||
def test_owner_admin_autocomplete(self):
|
||||
"""Test admin autocomplete endpoint for SalesOrder responsible field."""
|
||||
url = reverse('admin:autocomplete')
|
||||
|
||||
Reference in new issue
Block a user