diff --git a/apps/accounts/api_views.py b/apps/accounts/api_views.py
index aa3f836d..82e914e0 100644
--- a/apps/accounts/api_views.py
+++ b/apps/accounts/api_views.py
@@ -113,24 +113,6 @@ class TokenRefreshView(TokenRefreshView):
)
return Response({"error": "Unauthorized"}, status=status.HTTP_403_FORBIDDEN)
- # Check if user account is still active before issuing new access token
- raw_token = request.data.get("refresh")
- if raw_token:
- try:
- from rest_framework_simplejwt.tokens import RefreshToken as RefreshTokenClass
- token = RefreshTokenClass(raw_token)
- user_id = token.payload.get("user_id")
- if user_id:
- user = User.objects.filter(id=user_id).first()
- if user and not user.is_active:
- logger.info(f"Token refresh blocked for disabled user: user_id={user_id}")
- return Response(
- {"error": "Account is disabled"},
- status=status.HTTP_403_FORBIDDEN
- )
- except Exception:
- pass # Let parent handle invalid tokens
-
return super().post(request, *args, **kwargs)
diff --git a/apps/accounts/tests.py b/apps/accounts/tests.py
index f3afdbc4..629207ba 100644
--- a/apps/accounts/tests.py
+++ b/apps/accounts/tests.py
@@ -1,7 +1,6 @@
-from django.test import TestCase, RequestFactory
+from django.test import TestCase
from django.contrib.auth import get_user_model
from rest_framework.test import APIClient
-from rest_framework import status
User = get_user_model()
@@ -70,214 +69,4 @@ class InitializeSuperuserTests(TestCase):
self.assertEqual(response.status_code, 200)
self.assertTrue(response.json()["superuser_exists"])
# Should NOT have created a new user
- self.assertFalse(User.objects.filter(username="newadmin").exists())
-
-
-class TokenRefreshDisabledUserTests(TestCase):
- """Tests for blocking token refresh on disabled users"""
-
- def setUp(self):
- self.client = APIClient()
- self.token_url = "/api/accounts/token/"
- self.refresh_url = "/api/accounts/token/refresh/"
-
- def test_refresh_works_for_active_user(self):
- """Active user should be able to refresh their token"""
- user = User.objects.create_user(username="active", password="testpass123")
- user.user_level = 1
- user.is_active = True
- user.save()
-
- # Get tokens
- login_response = self.client.post(
- self.token_url,
- {"username": "active", "password": "testpass123"},
- format="json",
- )
- self.assertEqual(login_response.status_code, 200)
- refresh_token = login_response.data["refresh"]
-
- # Refresh should succeed
- refresh_response = self.client.post(
- self.refresh_url,
- {"refresh": refresh_token},
- format="json",
- )
- self.assertEqual(refresh_response.status_code, 200)
- self.assertIn("access", refresh_response.data)
-
- def test_refresh_blocked_for_disabled_user(self):
- """Disabled user should not be able to refresh their token"""
- user = User.objects.create_user(username="disabled", password="testpass123")
- user.user_level = 1
- user.is_active = True
- user.save()
-
- # Get tokens while user is active
- login_response = self.client.post(
- self.token_url,
- {"username": "disabled", "password": "testpass123"},
- format="json",
- )
- self.assertEqual(login_response.status_code, 200)
- refresh_token = login_response.data["refresh"]
-
- # Disable the user
- user.is_active = False
- user.save()
-
- # Refresh should be blocked
- refresh_response = self.client.post(
- self.refresh_url,
- {"refresh": refresh_token},
- format="json",
- )
- self.assertEqual(refresh_response.status_code, 403)
-
-
-class LastAdminProtectionTests(TestCase):
- """Tests for preventing disabling the last active admin"""
-
- def setUp(self):
- self.admin = User.objects.create_user(username="admin1", password="testpass123")
- self.admin.user_level = 10
- self.admin.save()
-
- self.client = APIClient()
- self.client.force_authenticate(user=self.admin)
-
- def test_cannot_disable_last_admin(self):
- """Should reject disabling the only active admin"""
- response = self.client.patch(
- f"/api/accounts/users/{self.admin.id}/",
- {"is_active": False},
- format="json",
- )
- self.assertEqual(response.status_code, 400)
- self.assertIn("is_active", response.data)
-
- # Verify admin is still active
- self.admin.refresh_from_db()
- self.assertTrue(self.admin.is_active)
-
- def test_can_disable_admin_when_another_exists(self):
- """Should allow disabling an admin when another active admin exists"""
- admin2 = User.objects.create_user(username="admin2", password="testpass123")
- admin2.user_level = 10
- admin2.save()
-
- response = self.client.patch(
- f"/api/accounts/users/{admin2.id}/",
- {"is_active": False},
- format="json",
- )
- self.assertEqual(response.status_code, 200)
-
- admin2.refresh_from_db()
- self.assertFalse(admin2.is_active)
-
- def test_can_disable_non_admin_user(self):
- """Should always allow disabling non-admin users"""
- regular = User.objects.create_user(username="regular", password="testpass123")
- regular.user_level = 1
- regular.save()
-
- response = self.client.patch(
- f"/api/accounts/users/{regular.id}/",
- {"is_active": False},
- format="json",
- )
- self.assertEqual(response.status_code, 200)
-
- regular.refresh_from_db()
- self.assertFalse(regular.is_active)
-
- def test_can_reenable_disabled_user(self):
- """Should allow re-enabling a disabled user"""
- regular = User.objects.create_user(username="disabled", password="testpass123")
- regular.user_level = 1
- regular.is_active = False
- regular.save()
-
- response = self.client.patch(
- f"/api/accounts/users/{regular.id}/",
- {"is_active": True},
- format="json",
- )
- self.assertEqual(response.status_code, 200)
-
- regular.refresh_from_db()
- self.assertTrue(regular.is_active)
-
-
-class DisabledUserLoginTests(TestCase):
- """Tests that disabled users cannot log in"""
-
- def setUp(self):
- self.client = APIClient()
- self.token_url = "/api/accounts/token/"
-
- def test_disabled_user_cannot_login(self):
- """Disabled user should get rejected at login"""
- user = User.objects.create_user(username="disabled", password="testpass123")
- user.is_active = False
- user.save()
-
- response = self.client.post(
- self.token_url,
- {"username": "disabled", "password": "testpass123"},
- format="json",
- )
- self.assertEqual(response.status_code, 401)
-
- def test_active_user_can_login(self):
- """Active user should be able to log in"""
- user = User.objects.create_user(username="active", password="testpass123")
- user.is_active = True
- user.save()
-
- response = self.client.post(
- self.token_url,
- {"username": "active", "password": "testpass123"},
- format="json",
- )
- self.assertEqual(response.status_code, 200)
- self.assertIn("access", response.data)
-
-
-class DisabledUserAccessTokenTests(TestCase):
- """Tests that a disabled user's existing access token is rejected on authenticated endpoints"""
-
- def setUp(self):
- self.client = APIClient()
- self.token_url = "/api/accounts/token/"
- self.users_url = "/api/accounts/users/"
-
- def test_existing_token_rejected_after_disable(self):
- """Access token obtained while active should be rejected after user is disabled"""
- user = User.objects.create_user(username="willdisable", password="testpass123")
- user.user_level = 10 # Admin so they can access the users endpoint
- user.is_active = True
- user.save()
-
- # Get tokens while user is active
- login_response = self.client.post(
- self.token_url,
- {"username": "willdisable", "password": "testpass123"},
- format="json",
- )
- self.assertEqual(login_response.status_code, 200)
- access_token = login_response.data["access"]
-
- # Verify token works while active
- self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {access_token}")
- response = self.client.get(self.users_url)
- self.assertEqual(response.status_code, 200)
-
- # Disable the user
- user.is_active = False
- user.save()
-
- # Same token should now be rejected
- response = self.client.get(self.users_url)
- self.assertIn(response.status_code, [401, 403])
\ No newline at end of file
+ self.assertFalse(User.objects.filter(username="newadmin").exists())
\ No newline at end of file
diff --git a/frontend/src/components/forms/User.jsx b/frontend/src/components/forms/User.jsx
index d76dd2ec..44ec17ac 100644
--- a/frontend/src/components/forms/User.jsx
+++ b/frontend/src/components/forms/User.jsx
@@ -42,7 +42,6 @@ const User = ({ user = null, isOpen, onClose }) => {
xc_password: '',
channel_profiles: [],
hide_adult_content: false,
- is_active: true,
},
validate: (values) => ({
@@ -135,7 +134,6 @@ const User = ({ user = null, isOpen, onClose }) => {
: ['0'],
xc_password: customProps.xc_password || '',
hide_adult_content: customProps.hide_adult_content || false,
- is_active: user.is_active !== false,
});
if (customProps.xc_password) {
@@ -203,30 +201,6 @@ const User = ({ user = null, isOpen, onClose }) => {
/>
)}
- {isAdmin && (
-
-
-
-
-
-
-
- )}
diff --git a/frontend/src/components/tables/UsersTable.jsx b/frontend/src/components/tables/UsersTable.jsx
index e9cf0a4c..af4e3087 100644
--- a/frontend/src/components/tables/UsersTable.jsx
+++ b/frontend/src/components/tables/UsersTable.jsx
@@ -8,7 +8,6 @@ import useWarningsStore from '../../store/warnings';
import { SquarePlus, SquareMinus, SquarePen, Eye, EyeOff } from 'lucide-react';
import {
ActionIcon,
- Badge,
Box,
Text,
Paper,
@@ -148,20 +147,6 @@ const UsersTable = () => {
{USER_LEVEL_LABELS[getValue()]}
),
},
- {
- header: 'Status',
- accessorKey: 'is_active',
- size: 90,
- cell: ({ getValue }) => (
-
- {getValue() !== false ? 'Active' : 'Disabled'}
-
- ),
- },
{
header: 'Username',
accessorKey: 'username',
@@ -331,7 +316,6 @@ const UsersTable = () => {
name: renderHeaderCell,
email: renderHeaderCell,
user_level: renderHeaderCell,
- is_active: renderHeaderCell,
last_login: renderHeaderCell,
date_joined: renderHeaderCell,
custom_properties: renderHeaderCell,