refactor: migrate vendor APIs to token-based context and consolidate architecture

## Vendor-in-Token Architecture (Complete Migration)
- Migrate all vendor API endpoints from require_vendor_context() to token_vendor_id
- Update permission dependencies to extract vendor from JWT token
- Add vendor exceptions: VendorAccessDeniedException, VendorOwnerOnlyException,
  InsufficientVendorPermissionsException
- Shop endpoints retain require_vendor_context() for URL-based detection
- Add AUTH-004 architecture rule enforcing vendor context patterns
- Fix marketplace router missing /marketplace prefix

## Exception Pattern Fixes (API-003/API-004)
- Services raise domain exceptions, endpoints let them bubble up
- Add code_quality and content_page exception modules
- Move business logic from endpoints to services (admin, auth, content_page)
- Fix exception handling in admin, shop, and vendor endpoints

## Tailwind CSS Consolidation
- Consolidate CSS to per-area files (admin, vendor, shop, platform)
- Remove shared/cdn-fallback.html and shared/css/tailwind.min.css
- Update all templates to use area-specific Tailwind output files
- Remove Node.js config (package.json, postcss.config.js, tailwind.config.js)

## Documentation & Cleanup
- Update vendor-in-token-architecture.md with completed migration status
- Update architecture-rules.md with new rules
- Move migration docs to docs/development/migration/
- Remove duplicate/obsolete documentation files
- Merge pytest.ini settings into pyproject.toml

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-04 22:24:45 +01:00
parent 76f8a59954
commit 8a367077e1
85 changed files with 21787 additions and 134978 deletions

View File

@@ -1,519 +1,253 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Auth Flow Testing - Admin Panel</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
{# app/templates/admin/test-auth-flow.html #}
{% extends 'admin/base.html' %}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
padding: 20px;
background: #f5f5f5;
line-height: 1.6;
}
{% block title %}Auth Flow Testing{% endblock %}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
h1 {
color: #333;
margin-bottom: 10px;
font-size: 28px;
}
.subtitle {
color: #666;
margin-bottom: 30px;
font-size: 14px;
}
.test-section {
margin-bottom: 30px;
padding: 20px;
background: #f9f9f9;
border-radius: 6px;
border-left: 4px solid #3b82f6;
}
.test-section h2 {
color: #333;
margin-bottom: 15px;
font-size: 20px;
}
.test-description {
color: #666;
margin-bottom: 15px;
font-size: 14px;
}
.test-steps {
background: white;
padding: 15px;
border-radius: 4px;
margin-bottom: 15px;
}
.test-steps ol {
margin-left: 20px;
}
.test-steps li {
margin-bottom: 8px;
color: #444;
}
.expected-result {
background: #e8f5e9;
padding: 12px;
border-radius: 4px;
border-left: 3px solid #4caf50;
margin-bottom: 15px;
}
.expected-result strong {
color: #2e7d32;
display: block;
margin-bottom: 5px;
}
.expected-result ul {
margin-left: 20px;
color: #555;
}
.button-group {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
button {
padding: 12px 24px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
}
button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
button:active {
transform: translateY(0);
}
.btn-primary {
background: #3b82f6;
color: white;
}
.btn-primary:hover {
background: #2563eb;
}
.btn-danger {
background: #ef4444;
color: white;
}
.btn-danger:hover {
background: #dc2626;
}
.btn-warning {
background: #f59e0b;
color: white;
}
.btn-warning:hover {
background: #d97706;
}
.btn-success {
background: #10b981;
color: white;
}
.btn-success:hover {
background: #059669;
}
.btn-secondary {
background: #6b7280;
color: white;
}
.btn-secondary:hover {
background: #4b5563;
}
.status-panel {
background: #1e293b;
color: #e2e8f0;
padding: 20px;
border-radius: 6px;
margin-top: 30px;
font-family: 'Courier New', monospace;
font-size: 13px;
}
.status-panel h3 {
color: #38bdf8;
margin-bottom: 15px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.status-item {
margin-bottom: 8px;
display: flex;
justify-content: space-between;
}
.status-label {
color: #94a3b8;
}
.status-value {
color: #34d399;
font-weight: 500;
}
.status-value.false {
color: #f87171;
}
.log-level-control {
background: #fef3c7;
padding: 15px;
border-radius: 6px;
margin-bottom: 30px;
border-left: 4px solid #f59e0b;
}
.log-level-control h3 {
color: #92400e;
margin-bottom: 10px;
font-size: 16px;
}
.log-level-buttons {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.log-level-buttons button {
padding: 8px 16px;
font-size: 12px;
}
.warning-box {
background: #fef2f2;
border: 1px solid #fecaca;
border-radius: 6px;
padding: 15px;
margin-top: 30px;
}
.warning-box h3 {
color: #991b1b;
margin-bottom: 10px;
font-size: 16px;
}
.warning-box ul {
margin-left: 20px;
color: #7f1d1d;
}
.warning-box li {
margin-bottom: 5px;
}
</style>
</head>
<body>
<div class="container">
<h1>🧪 Auth Flow Testing</h1>
<p class="subtitle">Comprehensive testing for the Jinja2 migration auth loop fix</p>
<!-- Log Level Control -->
<div class="log-level-control">
<h3>📊 Log Level Control</h3>
<p style="color: #78350f; font-size: 13px; margin-bottom: 10px;">
Change logging verbosity for login.js and api-client.js
{% block content %}
<div x-data="authFlowTest()" x-init="init()">
{# Page Header #}
<div class="flex flex-col md:flex-row md:items-center md:justify-between mb-8">
<div>
<h2 class="text-2xl font-semibold text-gray-700 dark:text-gray-200">
Auth Flow Testing
</h2>
<p class="text-gray-600 dark:text-gray-400 mt-1">
Comprehensive testing for Jinja2 migration auth loop fix
</p>
<div class="log-level-buttons">
<button onclick="setLogLevel(0)" class="btn-secondary">0 - None</button>
<button onclick="setLogLevel(1)" class="btn-danger">1 - Errors Only</button>
<button onclick="setLogLevel(2)" class="btn-warning">2 - Warnings</button>
<button onclick="setLogLevel(3)" class="btn-success">3 - Info (Production)</button>
<button onclick="setLogLevel(4)" class="btn-primary">4 - Debug (Full)</button>
</div>
<p style="color: #78350f; font-size: 12px; margin-top: 10px; font-style: italic;">
Current levels: LOGIN = <span id="currentLoginLevel">4</span>, API = <span id="currentApiLevel">3</span>
</p>
</div>
<!-- Test 1: Clean Slate -->
<div class="test-section">
<h2>Test 1: Clean Slate - Fresh Login Flow</h2>
<p class="test-description">
Tests the complete login flow from scratch with no existing tokens.
</p>
<div class="test-steps">
<strong>Steps:</strong>
<ol>
<li>Click "Clear All Data" below</li>
<li>Click "Navigate to /admin"</li>
<li>Observe browser behavior and console logs</li>
<li>You should land on login page</li>
</ol>
</div>
<div class="expected-result">
<strong>✅ Expected Result:</strong>
<ul>
<li>Single redirect: /admin → /admin/login</li>
<li>Login page loads with NO API calls to /admin/auth/me</li>
<li>No loops, no errors in console</li>
<li>Form is ready for input</li>
</ul>
</div>
<div class="button-group">
<button onclick="clearAllData()" class="btn-danger">Clear All Data</button>
<button onclick="navigateToAdmin()" class="btn-primary">Navigate to /admin</button>
<button onclick="navigateToLogin()" class="btn-secondary">Go to Login</button>
</div>
</div>
<!-- Test 2: Login Success -->
<div class="test-section">
<h2>Test 2: Successful Login</h2>
<p class="test-description">
Tests that login works correctly and redirects to dashboard.
</p>
<div class="test-steps">
<strong>Steps:</strong>
<ol>
<li>Ensure you're on /admin/login</li>
<li>Enter valid admin credentials</li>
<li>Click "Login"</li>
<li>Observe redirect and dashboard load</li>
</ol>
</div>
<div class="expected-result">
<strong>✅ Expected Result:</strong>
<ul>
<li>Login API call succeeds (check Network tab)</li>
<li>Token stored in localStorage</li>
<li>Success message shows briefly</li>
<li>Redirect to /admin/dashboard after 500ms</li>
<li>Dashboard loads with stats and recent vendors</li>
</ul>
</div>
<div class="button-group">
<button onclick="navigateToLogin()" class="btn-primary">Go to Login Page</button>
<button onclick="checkAuthStatus()" class="btn-secondary">Check Auth Status</button>
</div>
</div>
<!-- Test 3: Dashboard Refresh -->
<div class="test-section">
<h2>Test 3: Dashboard Refresh (Authenticated)</h2>
<p class="test-description">
Tests that refreshing the dashboard works without redirect loops.
</p>
<div class="test-steps">
<strong>Steps:</strong>
<ol>
<li>Complete Test 2 (login successfully)</li>
<li>On dashboard, press F5 or click "Refresh Page"</li>
<li>Observe page reload behavior</li>
</ol>
</div>
<div class="expected-result">
<strong>✅ Expected Result:</strong>
<ul>
<li>Dashboard reloads normally</li>
<li>No redirects to login</li>
<li>Stats and vendors load correctly</li>
<li>No console errors</li>
</ul>
</div>
<div class="button-group">
<button onclick="navigateToDashboard()" class="btn-primary">Go to Dashboard</button>
<button onclick="window.location.reload()" class="btn-secondary">Refresh Page</button>
</div>
</div>
<!-- Test 4: Expired Token -->
<div class="test-section">
<h2>Test 4: Expired Token Handling</h2>
<p class="test-description">
Tests that expired tokens are handled gracefully with redirect to login.
</p>
<div class="test-steps">
<strong>Steps:</strong>
<ol>
<li>Click "Set Expired Token"</li>
<li>Click "Navigate to Dashboard"</li>
<li>Observe authentication failure and redirect</li>
</ol>
</div>
<div class="expected-result">
<strong>✅ Expected Result:</strong>
<ul>
<li>Server detects expired token</li>
<li>Returns 401 Unauthorized</li>
<li>Browser redirects to /admin/login</li>
<li>Token is cleared from localStorage</li>
<li>No infinite loops</li>
</ul>
</div>
<div class="button-group">
<button onclick="setExpiredToken()" class="btn-warning">Set Expired Token</button>
<button onclick="navigateToDashboard()" class="btn-primary">Navigate to Dashboard</button>
</div>
</div>
<!-- Test 5: Direct Dashboard Access (No Token) -->
<div class="test-section">
<h2>Test 5: Direct Dashboard Access (Unauthenticated)</h2>
<p class="test-description">
Tests that accessing dashboard without token redirects to login.
</p>
<div class="test-steps">
<strong>Steps:</strong>
<ol>
<li>Click "Clear All Data"</li>
<li>Click "Navigate to Dashboard"</li>
<li>Observe immediate redirect to login</li>
</ol>
</div>
<div class="expected-result">
<strong>✅ Expected Result:</strong>
<ul>
<li>Redirect from /admin/dashboard to /admin/login</li>
<li>No API calls attempted</li>
<li>Login page loads correctly</li>
</ul>
</div>
<div class="button-group">
<button onclick="clearAllData()" class="btn-danger">Clear All Data</button>
<button onclick="navigateToDashboard()" class="btn-primary">Navigate to Dashboard</button>
</div>
</div>
<!-- Test 6: Login Page with Valid Token -->
<div class="test-section">
<h2>Test 6: Login Page with Valid Token</h2>
<p class="test-description">
Tests what happens when user visits login page while already authenticated.
</p>
<div class="test-steps">
<strong>Steps:</strong>
<ol>
<li>Login successfully (Test 2)</li>
<li>Click "Go to Login Page" below</li>
<li>Observe behavior</li>
</ol>
</div>
<div class="expected-result">
<strong>✅ Expected Result:</strong>
<ul>
<li>Login page loads</li>
<li>Existing token is cleared (init() clears it)</li>
<li>Form is displayed normally</li>
<li>NO redirect loops</li>
<li>NO API calls to validate token</li>
</ul>
</div>
<div class="button-group">
<button onclick="setValidToken()" class="btn-success">Set Valid Token (Mock)</button>
<button onclick="navigateToLogin()" class="btn-primary">Go to Login Page</button>
</div>
</div>
<!-- Status Panel -->
<div class="status-panel">
<h3>🔍 Current Auth Status</h3>
<div id="statusDisplay">
<div class="status-item">
<span class="status-label">Current URL:</span>
<span class="status-value" id="currentUrl">-</span>
</div>
<div class="status-item">
<span class="status-label">Has admin_token:</span>
<span class="status-value" id="hasToken">-</span>
</div>
<div class="status-item">
<span class="status-label">Has admin_user:</span>
<span class="status-value" id="hasUser">-</span>
</div>
<div class="status-item">
<span class="status-label">Token Preview:</span>
<span class="status-value" id="tokenPreview">-</span>
</div>
<div class="status-item">
<span class="status-label">Username:</span>
<span class="status-value" id="username">-</span>
</div>
</div>
<button onclick="updateStatus()" style="margin-top: 15px; background: #38bdf8; color: #0f172a; padding: 8px 16px; border-radius: 4px; font-size: 12px; cursor: pointer; border: none;">
🔄 Refresh Status
</button>
</div>
<!-- Warning Box -->
<div class="warning-box">
<h3>⚠️ Important Notes</h3>
<ul>
<li>Always check browser console for detailed logs</li>
<li>Use Network tab to see actual HTTP requests and redirects</li>
<li>Clear browser cache if you see unexpected behavior</li>
<li>Make sure FastAPI server is running on localhost:8000</li>
<li>Valid admin credentials required for login tests</li>
</ul>
</div>
</div>
<script>
// Update status display
function updateStatus() {
{# Log Level Control #}
<div class="px-4 py-3 mb-6 bg-yellow-50 dark:bg-yellow-900/20 rounded-lg shadow-md border-l-4 border-yellow-500">
<h4 class="mb-2 text-lg font-semibold text-yellow-800 dark:text-yellow-200">Log Level Control</h4>
<p class="text-sm text-yellow-700 dark:text-yellow-300 mb-3">
Change logging verbosity for login.js and api-client.js
</p>
<div class="flex flex-wrap gap-2">
<button @click="setLogLevel(0)" class="px-3 py-1 text-xs font-medium text-white bg-gray-600 rounded hover:bg-gray-700">0 - None</button>
<button @click="setLogLevel(1)" class="px-3 py-1 text-xs font-medium text-white bg-red-600 rounded hover:bg-red-700">1 - Errors</button>
<button @click="setLogLevel(2)" class="px-3 py-1 text-xs font-medium text-white bg-yellow-600 rounded hover:bg-yellow-700">2 - Warnings</button>
<button @click="setLogLevel(3)" class="px-3 py-1 text-xs font-medium text-white bg-green-600 rounded hover:bg-green-700">3 - Info</button>
<button @click="setLogLevel(4)" class="px-3 py-1 text-xs font-medium text-white bg-blue-600 rounded hover:bg-blue-700">4 - Debug</button>
</div>
<p class="text-xs text-yellow-600 dark:text-yellow-400 mt-2 italic">
Current: LOGIN = <span x-text="currentLoginLevel">4</span>, API = <span x-text="currentApiLevel">3</span>
</p>
</div>
{# Test Sections Grid #}
<div class="grid gap-6 mb-8 md:grid-cols-2">
{# Test 1: Clean Slate #}
<div class="px-4 py-3 bg-white rounded-lg shadow-md dark:bg-gray-800 border-l-4 border-blue-500">
<h4 class="mb-2 text-lg font-semibold text-gray-600 dark:text-gray-300">
Test 1: Clean Slate - Fresh Login
</h4>
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">
Tests complete login flow from scratch with no existing tokens.
</p>
<div class="p-3 mb-3 bg-gray-50 dark:bg-gray-700 rounded text-sm">
<ol class="list-decimal list-inside text-gray-700 dark:text-gray-300 space-y-1">
<li>Clear All Data</li>
<li>Navigate to /admin</li>
<li>Should land on login page</li>
</ol>
</div>
<div class="p-2 mb-3 bg-green-50 dark:bg-green-900/20 rounded border-l-3 border-green-500">
<p class="text-xs text-green-700 dark:text-green-400">Expected: Single redirect /admin -> /admin/login, no loops</p>
</div>
<div class="flex flex-wrap gap-2">
<button @click="clearAllData()" class="px-3 py-1 text-xs font-medium text-white bg-red-600 rounded hover:bg-red-700">Clear All Data</button>
<button @click="navigateTo('/admin')" class="px-3 py-1 text-xs font-medium text-white bg-blue-600 rounded hover:bg-blue-700">Go to /admin</button>
</div>
</div>
{# Test 2: Successful Login #}
<div class="px-4 py-3 bg-white rounded-lg shadow-md dark:bg-gray-800 border-l-4 border-green-500">
<h4 class="mb-2 text-lg font-semibold text-gray-600 dark:text-gray-300">
Test 2: Successful Login
</h4>
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">
Tests that login works correctly and redirects to dashboard.
</p>
<div class="p-3 mb-3 bg-gray-50 dark:bg-gray-700 rounded text-sm">
<ol class="list-decimal list-inside text-gray-700 dark:text-gray-300 space-y-1">
<li>Go to /admin/login</li>
<li>Enter valid admin credentials</li>
<li>Click Login</li>
</ol>
</div>
<div class="p-2 mb-3 bg-green-50 dark:bg-green-900/20 rounded border-l-3 border-green-500">
<p class="text-xs text-green-700 dark:text-green-400">Expected: Token stored, redirect to /admin/dashboard</p>
</div>
<div class="flex flex-wrap gap-2">
<button @click="navigateTo('/admin/login')" class="px-3 py-1 text-xs font-medium text-white bg-blue-600 rounded hover:bg-blue-700">Go to Login</button>
<button @click="checkAuthStatus()" class="px-3 py-1 text-xs font-medium text-white bg-gray-600 rounded hover:bg-gray-700">Check Status</button>
</div>
</div>
{# Test 3: Dashboard Refresh #}
<div class="px-4 py-3 bg-white rounded-lg shadow-md dark:bg-gray-800 border-l-4 border-purple-500">
<h4 class="mb-2 text-lg font-semibold text-gray-600 dark:text-gray-300">
Test 3: Dashboard Refresh
</h4>
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">
Tests that refreshing dashboard works without redirect loops.
</p>
<div class="p-3 mb-3 bg-gray-50 dark:bg-gray-700 rounded text-sm">
<ol class="list-decimal list-inside text-gray-700 dark:text-gray-300 space-y-1">
<li>Complete Test 2 (login)</li>
<li>Press F5 or click Refresh</li>
<li>Dashboard should reload normally</li>
</ol>
</div>
<div class="p-2 mb-3 bg-green-50 dark:bg-green-900/20 rounded border-l-3 border-green-500">
<p class="text-xs text-green-700 dark:text-green-400">Expected: No redirect to login, stats load correctly</p>
</div>
<div class="flex flex-wrap gap-2">
<button @click="navigateTo('/admin/dashboard')" class="px-3 py-1 text-xs font-medium text-white bg-blue-600 rounded hover:bg-blue-700">Go to Dashboard</button>
<button @click="window.location.reload()" class="px-3 py-1 text-xs font-medium text-white bg-gray-600 rounded hover:bg-gray-700">Refresh Page</button>
</div>
</div>
{# Test 4: Expired Token #}
<div class="px-4 py-3 bg-white rounded-lg shadow-md dark:bg-gray-800 border-l-4 border-orange-500">
<h4 class="mb-2 text-lg font-semibold text-gray-600 dark:text-gray-300">
Test 4: Expired Token Handling
</h4>
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">
Tests that expired tokens are handled gracefully.
</p>
<div class="p-3 mb-3 bg-gray-50 dark:bg-gray-700 rounded text-sm">
<ol class="list-decimal list-inside text-gray-700 dark:text-gray-300 space-y-1">
<li>Set Expired Token</li>
<li>Navigate to Dashboard</li>
<li>Should redirect to login</li>
</ol>
</div>
<div class="p-2 mb-3 bg-green-50 dark:bg-green-900/20 rounded border-l-3 border-green-500">
<p class="text-xs text-green-700 dark:text-green-400">Expected: 401 response, redirect to login, no loops</p>
</div>
<div class="flex flex-wrap gap-2">
<button @click="setExpiredToken()" class="px-3 py-1 text-xs font-medium text-white bg-orange-600 rounded hover:bg-orange-700">Set Expired Token</button>
<button @click="navigateTo('/admin/dashboard')" class="px-3 py-1 text-xs font-medium text-white bg-blue-600 rounded hover:bg-blue-700">Go to Dashboard</button>
</div>
</div>
{# Test 5: Direct Access (No Token) #}
<div class="px-4 py-3 bg-white rounded-lg shadow-md dark:bg-gray-800 border-l-4 border-red-500">
<h4 class="mb-2 text-lg font-semibold text-gray-600 dark:text-gray-300">
Test 5: Direct Access (Unauthenticated)
</h4>
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">
Tests accessing dashboard without token redirects to login.
</p>
<div class="p-3 mb-3 bg-gray-50 dark:bg-gray-700 rounded text-sm">
<ol class="list-decimal list-inside text-gray-700 dark:text-gray-300 space-y-1">
<li>Clear All Data</li>
<li>Navigate to Dashboard</li>
<li>Should redirect to login</li>
</ol>
</div>
<div class="p-2 mb-3 bg-green-50 dark:bg-green-900/20 rounded border-l-3 border-green-500">
<p class="text-xs text-green-700 dark:text-green-400">Expected: Redirect to /admin/login, no API calls</p>
</div>
<div class="flex flex-wrap gap-2">
<button @click="clearAllData()" class="px-3 py-1 text-xs font-medium text-white bg-red-600 rounded hover:bg-red-700">Clear All Data</button>
<button @click="navigateTo('/admin/dashboard')" class="px-3 py-1 text-xs font-medium text-white bg-blue-600 rounded hover:bg-blue-700">Go to Dashboard</button>
</div>
</div>
{# Test 6: Login with Valid Token #}
<div class="px-4 py-3 bg-white rounded-lg shadow-md dark:bg-gray-800 border-l-4 border-teal-500">
<h4 class="mb-2 text-lg font-semibold text-gray-600 dark:text-gray-300">
Test 6: Login Page with Valid Token
</h4>
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">
Tests visiting login page while already authenticated.
</p>
<div class="p-3 mb-3 bg-gray-50 dark:bg-gray-700 rounded text-sm">
<ol class="list-decimal list-inside text-gray-700 dark:text-gray-300 space-y-1">
<li>Login successfully (Test 2)</li>
<li>Click Go to Login Page</li>
<li>Token should be cleared</li>
</ol>
</div>
<div class="p-2 mb-3 bg-green-50 dark:bg-green-900/20 rounded border-l-3 border-green-500">
<p class="text-xs text-green-700 dark:text-green-400">Expected: Token cleared, form displayed, no loops</p>
</div>
<div class="flex flex-wrap gap-2">
<button @click="setMockToken()" class="px-3 py-1 text-xs font-medium text-white bg-green-600 rounded hover:bg-green-700">Set Mock Token</button>
<button @click="navigateTo('/admin/login')" class="px-3 py-1 text-xs font-medium text-white bg-blue-600 rounded hover:bg-blue-700">Go to Login</button>
</div>
</div>
</div>
{# Status Panel #}
<div class="px-4 py-3 bg-gray-800 rounded-lg shadow-md">
<div class="flex items-center justify-between mb-3">
<h4 class="text-lg font-semibold text-gray-200">Current Auth Status</h4>
<button @click="updateStatus()" class="px-3 py-1 text-xs text-gray-400 border border-gray-600 rounded hover:bg-gray-700">Refresh</button>
</div>
<div class="font-mono text-sm space-y-2">
<div class="flex justify-between">
<span class="text-gray-500">Current URL:</span>
<span class="text-blue-400" x-text="currentUrl">-</span>
</div>
<div class="flex justify-between">
<span class="text-gray-500">Has admin_token:</span>
<span :class="hasToken ? 'text-green-400' : 'text-red-400'" x-text="hasToken ? 'Yes' : 'No'">-</span>
</div>
<div class="flex justify-between">
<span class="text-gray-500">Has admin_user:</span>
<span :class="hasUser ? 'text-green-400' : 'text-red-400'" x-text="hasUser ? 'Yes' : 'No'">-</span>
</div>
<div class="flex justify-between">
<span class="text-gray-500">Token Preview:</span>
<span class="text-green-400 truncate max-w-xs" x-text="tokenPreview">-</span>
</div>
<div class="flex justify-between">
<span class="text-gray-500">Username:</span>
<span class="text-green-400" x-text="username">-</span>
</div>
</div>
</div>
{# Warning Box #}
<div class="mt-6 px-4 py-3 bg-red-50 dark:bg-red-900/20 rounded-lg border border-red-200 dark:border-red-800">
<h4 class="text-lg font-semibold text-red-700 dark:text-red-300 mb-2">Important Notes</h4>
<ul class="list-disc list-inside text-sm text-red-600 dark:text-red-400 space-y-1">
<li>Always check browser console for detailed logs</li>
<li>Use Network tab to see actual HTTP requests and redirects</li>
<li>Clear browser cache if you see unexpected behavior</li>
<li>Make sure FastAPI server is running on localhost:8000</li>
<li>Valid admin credentials required for login tests</li>
</ul>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
function authFlowTest() {
return {
...data(),
currentPage: 'auth-testing',
currentUrl: '-',
hasToken: false,
hasUser: false,
tokenPreview: '-',
username: '-',
currentLoginLevel: 4,
currentApiLevel: 3,
init() {
this.updateStatus();
setInterval(() => this.updateStatus(), 2000);
console.log('Auth Flow Testing Script Loaded');
},
updateStatus() {
const token = localStorage.getItem('admin_token');
const userStr = localStorage.getItem('admin_user');
let user = null;
@@ -524,121 +258,67 @@
console.error('Failed to parse user data:', e);
}
document.getElementById('currentUrl').textContent = window.location.href;
this.currentUrl = window.location.href;
this.hasToken = !!token;
this.hasUser = !!user;
this.tokenPreview = token ? token.substring(0, 30) + '...' : 'No token';
this.username = user?.username || 'Not logged in';
},
const hasTokenEl = document.getElementById('hasToken');
hasTokenEl.textContent = token ? 'Yes' : 'No';
hasTokenEl.className = token ? 'status-value' : 'status-value false';
const hasUserEl = document.getElementById('hasUser');
hasUserEl.textContent = user ? 'Yes' : 'No';
hasUserEl.className = user ? 'status-value' : 'status-value false';
document.getElementById('tokenPreview').textContent = token
? token.substring(0, 30) + '...'
: 'No token';
document.getElementById('username').textContent = user?.username || 'Not logged in';
console.log('📊 Status Updated:', {
hasToken: !!token,
hasUser: !!user,
user: user
});
}
// Test functions
function clearAllData() {
console.log('🗑️ Clearing all localStorage data...');
clearAllData() {
console.log('Clearing all localStorage data...');
localStorage.clear();
console.log('All data cleared');
alert('All localStorage data cleared!\n\nCheck console for details.');
updateStatus();
}
console.log('All data cleared');
alert('All localStorage data cleared!');
this.updateStatus();
},
function navigateToAdmin() {
console.log('🚀 Navigating to /admin...');
window.location.href = '/admin';
}
navigateTo(path) {
console.log(`Navigating to ${path}...`);
window.location.href = path;
},
function navigateToLogin() {
console.log('🚀 Navigating to /admin/login...');
window.location.href = '/admin/login';
}
function navigateToDashboard() {
console.log('🚀 Navigating to /admin/dashboard...');
window.location.href = '/admin/dashboard';
}
function checkAuthStatus() {
updateStatus();
checkAuthStatus() {
this.updateStatus();
alert('Check console and status panel for auth details.');
}
},
function setExpiredToken() {
const expiredToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyMzkwMjJ9.invalidexpiredtoken';
console.log('⚠️ Setting expired/invalid token...');
setExpiredToken() {
const expiredToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiZXhwIjoxNTE2MjM5MDIyfQ.invalid';
localStorage.setItem('admin_token', expiredToken);
localStorage.setItem('admin_user', JSON.stringify({
id: 1,
username: 'test_expired',
role: 'admin'
}));
console.log('Expired token set');
alert('⚠️ Expired token set!\n\nNow try navigating to dashboard.');
updateStatus();
}
alert('Expired token set! Now try navigating to dashboard.');
this.updateStatus();
},
function setValidToken() {
// This is a mock token - won't actually work with backend
setMockToken() {
const mockToken = 'mock_valid_token_' + Date.now();
console.log('✅ Setting mock valid token...');
localStorage.setItem('admin_token', mockToken);
localStorage.setItem('admin_user', JSON.stringify({
id: 1,
username: 'test_user',
role: 'admin'
}));
console.log('Mock token set (will not work with real backend)');
alert('✅ Mock token set!\n\nNote: This is a fake token and won\'t work with the real backend.');
updateStatus();
}
alert('Mock token set! Note: This won\'t work with real backend.');
this.updateStatus();
},
// Log level control
function setLogLevel(level) {
console.log(`📊 Setting log level to ${level}...`);
// Note: This only works if login.js and api-client.js are loaded
// In production, you'd need to reload the page or use a more sophisticated approach
if (typeof LOG_LEVEL !== 'undefined') {
setLogLevel(level) {
if (typeof window.LOG_LEVEL !== 'undefined') {
window.LOG_LEVEL = level;
document.getElementById('currentLoginLevel').textContent = level;
console.log('✅ LOGIN log level set to', level);
} else {
console.warn('⚠️ LOG_LEVEL not found (login.js not loaded)');
this.currentLoginLevel = level;
}
if (typeof API_LOG_LEVEL !== 'undefined') {
if (typeof window.API_LOG_LEVEL !== 'undefined') {
window.API_LOG_LEVEL = level;
document.getElementById('currentApiLevel').textContent = level;
console.log('✅ API log level set to', level);
} else {
console.warn('⚠️ API_LOG_LEVEL not found (api-client.js not loaded)');
this.currentApiLevel = level;
}
alert(`Log level set to ${level}\n\n0 = None\n1 = Errors\n2 = Warnings\n3 = Info\n4 = Debug\n\nNote: Changes apply to current page. Reload to apply to all scripts.`);
alert(`Log level set to ${level}. Reload to apply to all scripts.`);
}
// Initialize status on load
updateStatus();
// Auto-refresh status every 2 seconds
setInterval(updateStatus, 2000);
console.log('🧪 Auth Flow Testing Script Loaded');
console.log('📊 Use the buttons above to run tests');
console.log('🔍 Watch browser console and Network tab for details');
</script>
</body>
</html>
};
}
</script>
{% endblock %}