feat: add admin dashboard, audit logs, token expiry check and test suite

Frontend Features:
- Add ProtectedRoute component with token expiry validation
- Create AdminDashboardPage with system statistics and user management
- Create AuditLogsPage with filtering and pagination
- Add admin-only navigation (Shield icon) for ymirliu@panjit.com.tw
- Add admin API methods to apiV2 service
- Add admin type definitions (SystemStats, AuditLog, etc.)

Token Management:
- Auto-redirect to login on token expiry
- Check authentication on route change
- Show loading state during auth check
- Admin privilege verification

Backend Testing:
- Add pytest configuration (pytest.ini)
- Create test fixtures (conftest.py)
- Add unit tests for auth, tasks, and admin endpoints
- Add integration tests for complete workflows
- Test user isolation and admin access control

Documentation:
- Add TESTING.md with comprehensive testing guide
- Include test running instructions
- Document fixtures and best practices

Routes:
- /admin - Admin dashboard (admin only)
- /admin/audit-logs - Audit logs viewer (admin only)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
egg
2025-11-16 18:01:50 +08:00
parent fd98018ddd
commit 8f94191914
13 changed files with 1554 additions and 45 deletions

105
backend/tests/test_tasks.py Normal file
View File

@@ -0,0 +1,105 @@
"""
Unit tests for task management endpoints
"""
import pytest
from app.models.task import Task
class TestTasks:
"""Test task management endpoints"""
def test_create_task(self, client, auth_token):
"""Test task creation"""
response = client.post(
'/api/v2/tasks/',
headers={'Authorization': f'Bearer {auth_token}'},
json={
'filename': 'test.pdf',
'file_type': 'application/pdf'
}
)
assert response.status_code == 201
data = response.json()
assert 'task_id' in data
assert data['filename'] == 'test.pdf'
assert data['status'] == 'pending'
def test_list_tasks(self, client, auth_token, test_task):
"""Test listing user tasks"""
response = client.get(
'/api/v2/tasks/',
headers={'Authorization': f'Bearer {auth_token}'}
)
assert response.status_code == 200
data = response.json()
assert 'tasks' in data
assert 'total' in data
assert len(data['tasks']) > 0
def test_get_task(self, client, auth_token, test_task):
"""Test get single task"""
response = client.get(
f'/api/v2/tasks/{test_task.task_id}',
headers={'Authorization': f'Bearer {auth_token}'}
)
assert response.status_code == 200
data = response.json()
assert data['task_id'] == test_task.task_id
def test_get_task_stats(self, client, auth_token, test_task):
"""Test get task statistics"""
response = client.get(
'/api/v2/tasks/stats',
headers={'Authorization': f'Bearer {auth_token}'}
)
assert response.status_code == 200
data = response.json()
assert 'total' in data
assert 'pending' in data
assert 'processing' in data
assert 'completed' in data
assert 'failed' in data
def test_delete_task(self, client, auth_token, test_task):
"""Test task deletion"""
response = client.delete(
f'/api/v2/tasks/{test_task.task_id}',
headers={'Authorization': f'Bearer {auth_token}'}
)
assert response.status_code == 200
def test_user_isolation(self, client, db, test_user):
"""Test that users can only access their own tasks"""
# Create another user
from app.models.user import User
other_user = User(email="other@example.com", display_name="Other User")
db.add(other_user)
db.commit()
# Create task for other user
other_task = Task(
user_id=other_user.id,
task_id="other-task-123",
filename="other.pdf",
status="pending"
)
db.add(other_task)
db.commit()
# Create token for test_user
from app.core.security import create_access_token
token = create_access_token({"sub": str(test_user.id)})
# Try to access other user's task
response = client.get(
f'/api/v2/tasks/{other_task.task_id}',
headers={'Authorization': f'Bearer {token}'}
)
assert response.status_code == 404 # Task not found (user isolation)