Implement application setup and flow middleware

- Add SetupService for detecting application setup completion
- Create ApplicationFlowMiddleware to enforce setup  auth  main flow
- Add setup processing endpoints (/api/auth/setup, /api/auth/setup/status)
- Add Pydantic models for setup requests and responses
- Integrate middleware into FastAPI application
- Fix logging paths to use ./logs consistently
- All existing templates (setup.html, login.html) already working
This commit is contained in:
Lukas Pupka-Lipinski 2025-10-06 12:48:18 +02:00
parent 3b8ca8b8f3
commit 3f98dd6ebb
37 changed files with 1051 additions and 233 deletions

View File

@ -1,88 +0,0 @@
# Flask to FastAPI Migration - Completion Summary
## ✅ Migration Status: COMPLETED
The Flask to FastAPI migration has been successfully completed. All major functionality has been tested and verified to be working correctly.
## 🧪 Testing Results
### ✅ Functional Testing
- **Web Routes**: All routes return correct responses
- **HTML Pages**: All pages render correctly
- **Form Submissions**: Authentication forms work properly
- **File Uploads**: Not applicable (no file upload endpoints implemented)
- **Authentication**: Complete login/logout/token verification flow working
### ✅ Frontend Testing
- **JavaScript Functionality**: Working correctly
- **AJAX Calls**: API endpoints respond properly to authenticated requests
- **Dynamic Content Loading**: Pages load and display content correctly
- **CSS Styling**: Styling applied correctly
- **Responsive Design**: Pages display properly
### ✅ Integration Testing
- **Database Connectivity**: Health endpoint confirms database is operational
- **API Endpoints**: All tested endpoints return correct data formats
- **Error Handling**: Proper error responses for invalid authentication, etc.
- **Security Features**: JWT authentication working correctly
## 🚀 Key Features Verified
1. **FastAPI Server**: Successfully running on port 8000
2. **Authentication**: JWT-based login with master password (`admin123`)
3. **API Documentation**: Auto-generated OpenAPI docs available at `/docs`
4. **Health Monitoring**: Health check endpoint at `/health`
5. **Database Operations**: Database health monitoring working
6. **Error Handling**: Proper HTTP status codes and error messages
## 🔧 Technical Implementation
- **Server**: Uvicorn ASGI server
- **Authentication**: JWT tokens with configurable expiry
- **Database**: SQLite with health monitoring
- **Configuration**: Environment variables via `.env` file
- **Documentation**: Automatic OpenAPI/Swagger documentation
- **CORS**: Properly configured for web client access
## 📝 Migration Notes
### SeriesApp Integration
- Fixed missing `_initialization_count` class variable
- SeriesApp is used as the business logic layer interface
- Single instance per operation (no singleton pattern as requested)
### Middleware Handling
- Temporarily disabled middleware due to file corruption issues
- Core functionality works without middleware
- Can be re-implemented when needed
### Environment Configuration
- Uses `.env` file for configuration
- Database URL, JWT secrets, and directory paths configurable
- Logging configured for FastAPI application
## ✅ Migration Checklist Summary
All major migration tasks have been completed:
- [x] Core application migration from Flask to FastAPI
- [x] Route conversion and testing
- [x] Authentication system implementation and testing
- [x] Template and static file serving
- [x] Database connectivity verification
- [x] API documentation generation
- [x] Health monitoring implementation
- [x] Environment configuration
- [x] End-to-end testing
## 🎯 Ready for Production
The FastAPI application is now ready for production deployment with:
- Stable authentication system
- Working API endpoints
- Health monitoring
- Auto-generated documentation
- Proper error handling
- Database connectivity
**Migration Status: ✅ COMPLETE**

View File

@ -108,6 +108,23 @@ This document contains tasks for migrating the web application from Flask to Fas
- [x] Migrate request/response interceptors - [x] Migrate request/response interceptors
- [x] Update logging middleware if used - [x] Update logging middleware if used
## 🚀 Application Flow & Setup Features
### Setup and Authentication Flow
- [ ] Implement application setup detection middleware
- [ ] Create setup page template and route for first-time configuration
- [ ] Implement configuration file/database setup validation
- [ ] Create authentication token validation middleware
- [ ] Implement auth page template and routes for login/registration
- [ ] Create main application route with authentication dependency
- [ ] Implement setup completion tracking in configuration
- [ ] Add redirect logic for setup → auth → main application flow
- [ ] Create Pydantic models for setup and authentication requests
- [ ] Implement session management for authenticated users
- [ ] Add token refresh and expiration handling
- [ ] Create middleware to enforce application flow priorities
## 🧪 Testing and Validation ## 🧪 Testing and Validation
### Functional Testing ### Functional Testing

View File

@ -133,5 +133,48 @@ This file instructs the AI agent on how to generate tests for the AniWorld appli
--- ---
# Test TODO
## Application Flow & Setup Tests
### Setup Page Tests
- [ ] Test setup page is displayed when configuration is missing
- [ ] Test setup page form submission creates valid configuration
- [ ] Test setup page redirects to auth page after successful setup
- [ ] Test setup page validation for required fields
- [ ] Test setup page handles database connection errors gracefully
- [ ] Test setup completion flag is properly set in configuration
### Authentication Flow Tests
- [ ] Test auth page is displayed when authentication token is invalid
- [ ] Test auth page is displayed when authentication token is missing
- [ ] Test successful login creates valid authentication token
- [ ] Test failed login shows appropriate error messages
- [ ] Test auth page redirects to main application after successful authentication
- [ ] Test token validation middleware correctly identifies valid/invalid tokens
- [ ] Test token refresh functionality
- [ ] Test session expiration handling
### Main Application Access Tests
- [ ] Test index.html is served when authentication is valid
- [ ] Test unauthenticated users are redirected to auth page
- [ ] Test users without completed setup are redirected to setup page
- [ ] Test middleware enforces correct flow priority (setup → auth → main)
- [ ] Test authenticated user session persistence
- [ ] Test graceful handling of token expiration during active session
### Integration Flow Tests
- [ ] Test complete user journey: setup → auth → main application
- [ ] Test application behavior when setup is completed but user is not authenticated
- [ ] Test application behavior when configuration exists but is corrupted
- [ ] Test concurrent user sessions and authentication state management
- [ ] Test application restart preserves setup and authentication state appropriately
---
**Instruction to AI Agent:** **Instruction to AI Agent:**
Generate and check off each test case above as you complete it. Save all test files under `src/tests/` using the specified structure and conventions. Generate and check off each test case above as you complete it. Save all test files under `src/tests/` using the specified structure and conventions.

View File

@ -1,95 +1,135 @@
# AniWorld Application Features # AniWorld Application Features
## 1. Authentication & Security ## 1. Authentication & Security
- Master password authentication (JWT-based)
- `POST /auth/login`: Login and receive JWT token - Master password authentication (JWT-based)
- `GET /auth/verify`: Verify JWT token validity - `POST /auth/login`: Login and receive JWT token
- `POST /auth/logout`: Logout (stateless) - `GET /auth/verify`: Verify JWT token validity
- Password hashing (SHA-256 + salt) - `POST /auth/logout`: Logout (stateless)
- Configurable session timeout - Password hashing (SHA-256 + salt)
- Secure environment variable management - Configurable session timeout
- Secure environment variable management
## 2. Health & System Monitoring ## 2. Health & System Monitoring
- Health check endpoints
- `/health`: Basic health status - Health check endpoints
- `/api/health`: Load balancer health - `/health`: Basic health status
- `/api/health/system`: System metrics (CPU, memory, disk) - `/api/health`: Load balancer health
- `/api/health/database`: Database connectivity - `/api/health/system`: System metrics (CPU, memory, disk)
- `/api/health/dependencies`: External dependencies - `/api/health/database`: Database connectivity
- `/api/health/performance`: Performance metrics - `/api/health/dependencies`: External dependencies
- `/api/health/metrics`: Prometheus metrics - `/api/health/performance`: Performance metrics
- `/api/health/ready`: Readiness probe (Kubernetes) - `/api/health/metrics`: Prometheus metrics
- `/api/health/ready`: Readiness probe (Kubernetes)
## 3. Anime & Episode Management ## 3. Anime & Episode Management
- Search anime
- `GET /api/anime/search`: Search anime by title (pagination) - Search anime
- Get anime details - `GET /api/anime/search`: Search anime by title (pagination)
- `GET /api/anime/{anime_id}`: Anime details - Get anime details
- `GET /api/anime/{anime_id}/episodes`: List episodes - `GET /api/anime/{anime_id}`: Anime details
- `GET /api/episodes/{episode_id}`: Episode details - `GET /api/anime/{anime_id}/episodes`: List episodes
- `GET /api/episodes/{episode_id}`: Episode details
## 4. Database & Storage Management ## 4. Database & Storage Management
- Database info and statistics
- `GET /api/database/info`: Database stats - Database info and statistics
- Maintenance operations - `GET /api/database/info`: Database stats
- `/maintenance/database/vacuum`: Vacuum database - Maintenance operations
- `/maintenance/database/analyze`: Analyze database - `/maintenance/database/vacuum`: Vacuum database
- `/maintenance/database/integrity-check`: Integrity check - `/maintenance/database/analyze`: Analyze database
- `/maintenance/database/reindex`: Reindex database - `/maintenance/database/integrity-check`: Integrity check
- `/maintenance/database/optimize`: Optimize database - `/maintenance/database/reindex`: Reindex database
- `/maintenance/database/stats`: Get database stats - `/maintenance/database/optimize`: Optimize database
- `/maintenance/database/stats`: Get database stats
## 5. Bulk Operations ## 5. Bulk Operations
- Bulk download, update, organize, delete, export
- `/api/bulk/download`: Start bulk download - Bulk download, update, organize, delete, export
- `/api/bulk/update`: Bulk update - `/api/bulk/download`: Start bulk download
- `/api/bulk/organize`: Organize series - `/api/bulk/update`: Bulk update
- `/api/bulk/delete`: Delete series - `/api/bulk/organize`: Organize series
- `/api/bulk/export`: Export series data - `/api/bulk/delete`: Delete series
- `/api/bulk/export`: Export series data
## 6. Performance Optimization ## 6. Performance Optimization
- Speed limit management
- `/api/performance/speed-limit`: Get/set download speed limit - Speed limit management
- Cache statistics - `/api/performance/speed-limit`: Get/set download speed limit
- `/api/performance/cache/stats`: Cache stats - Cache statistics
- Memory management - `/api/performance/cache/stats`: Cache stats
- `/api/performance/memory/stats`: Memory usage stats - Memory management
- `/api/performance/memory/gc`: Force garbage collection - `/api/performance/memory/stats`: Memory usage stats
- Download queue management - `/api/performance/memory/gc`: Force garbage collection
- `/api/performance/downloads/tasks`: List download tasks - Download queue management
- `/api/performance/downloads/add-task`: Add download task - `/api/performance/downloads/tasks`: List download tasks
- `/api/performance/resume/tasks`: List resumable tasks - `/api/performance/downloads/add-task`: Add download task
- `/api/performance/resume/tasks`: List resumable tasks
## 7. Diagnostics & Logging ## 7. Diagnostics & Logging
- Diagnostic report generation
- `/diagnostics/report`: Generate diagnostic report - Diagnostic report generation
- Error reporting and stats - `/diagnostics/report`: Generate diagnostic report
- Logging configuration and log file management - Error reporting and stats
- Logging configuration and log file management
## 8. Integrations ## 8. Integrations
- API key management
- Webhook configuration - API key management
- Third-party API integrations - Webhook configuration
- Third-party API integrations
## 9. User Preferences & UI ## 9. User Preferences & UI
- Theme management (light/dark/auto)
- Language selection - Theme management (light/dark/auto)
- Accessibility features (screen reader, color contrast, mobile support) - Language selection
- Keyboard shortcuts - Accessibility features (screen reader, color contrast, mobile support)
- UI density and grid/list view options - Keyboard shortcuts
- UI density and grid/list view options
## 10. CLI Tool ## 10. CLI Tool
- Series scanning and management
- Search, download, rescan, display series - Series scanning and management
- Progress bar for downloads - Search, download, rescan, display series
- Retry logic for operations - Progress bar for downloads
- Retry logic for operations
## 11. Miscellaneous ## 11. Miscellaneous
- Environment configuration via `.env`
- Modular, extensible architecture (MVC, Clean Architecture) - Environment configuration via `.env`
- Automated testing (pytest, unittest) - Modular, extensible architecture (MVC, Clean Architecture)
- Centralized error handling - Automated testing (pytest, unittest)
- Centralized error handling
## Authentication & Setup Flow
### Application Initialization Flow
- **Setup Page**: Display application setup page when the application is run for the first time and no configuration exists
- Check for presence of configuration file/database setup
- Guide user through initial application configuration
- Set up database connections, initial admin user, and core settings
- Mark setup as completed in configuration
- **Authentication Gate**: Redirect to authentication page when user token is invalid or missing
- Validate existing authentication tokens
- Display login/registration interface for unauthenticated users
- Handle token refresh and session management
- Redirect authenticated users to main application
- **Main Application**: Show index.html for authenticated users with valid tokens
- Display main application interface
- Provide access to all authenticated user features
- Maintain session state and handle token expiration gracefully
### User Flow Priority
1. Check if application setup is completed → Show setup page if not
2. Check if user is authenticated → Show auth page if not
3. Show main application (index.html) for authenticated users
--- ---
**Note:** Each feature is implemented via modular controllers, services, and utilities. See the respective source files for detailed function/class definitions. **Note:** Each feature is implemented via modular controllers, services, and utilities. See the respective source files for detailed function/class definitions.

View File

@ -9801,3 +9801,97 @@
2025-10-05 20:19:24,711 - fastapi_app - INFO - Successful authentication 2025-10-05 20:19:24,711 - fastapi_app - INFO - Successful authentication
2025-10-05 20:19:28,794 - fastapi_app - INFO - Searching anime with query: naruto 2025-10-05 20:19:28,794 - fastapi_app - INFO - Searching anime with query: naruto
2025-10-05 20:23:01,973 - fastapi_app - INFO - Shutting down AniWorld FastAPI server... 2025-10-05 20:23:01,973 - fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 10:04:54,367 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 10:04:54,436 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 10:04:54,436 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 10:24:44,892 - src.server.fastapi_app - WARNING - Failed login attempt from IP: 127.0.0.1
2025-10-06 10:24:54,205 - src.server.fastapi_app - INFO - Successful authentication
2025-10-06 10:31:19,227 - src.server.fastapi_app - INFO - Successful authentication
2025-10-06 10:31:19,372 - src.server.fastapi_app - INFO - Searching anime with query: naruto
2025-10-06 10:32:29,832 - src.server.fastapi_app - INFO - Successful authentication
2025-10-06 10:32:30,006 - src.server.fastapi_app - WARNING - Invalid token: Not enough segments
2025-10-06 10:33:31,000 - src.server.fastapi_app - INFO - Successful authentication
2025-10-06 10:39:47,044 - src.server.fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 10:39:48,130 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 10:39:48,130 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 10:39:48,130 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 10:39:49,080 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 10:39:49,080 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 10:39:49,080 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 10:44:48,432 - src.server.fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 10:44:49,798 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 10:44:49,798 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 10:44:49,799 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 10:44:51,133 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 10:44:51,133 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 10:44:51,133 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 10:49:50,142 - src.server.fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 10:49:50,996 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 10:49:50,996 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 10:49:50,996 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 10:49:51,907 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 10:49:51,907 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 10:49:51,908 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 10:54:51,337 - src.server.fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 10:54:52,227 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 10:54:52,228 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 10:54:52,228 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 10:54:53,189 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 10:54:53,189 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 10:54:53,189 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 10:59:52,617 - src.server.fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 10:59:53,483 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 10:59:53,483 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 10:59:53,483 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 10:59:54,371 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 10:59:54,371 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 10:59:54,371 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 11:13:39,752 - src.server.fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 11:13:40,651 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 11:13:40,651 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 11:13:40,651 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 11:13:41,677 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 11:13:41,677 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 11:13:41,677 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 11:18:40,951 - src.server.fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 11:18:41,833 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 11:18:41,833 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 11:18:41,833 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 11:18:42,720 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 11:18:42,720 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 11:18:42,720 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 11:28:42,126 - src.server.fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 11:28:43,047 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 11:28:43,047 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 11:28:43,047 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 11:28:44,078 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 11:28:44,078 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 11:28:44,078 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 11:33:43,353 - src.server.fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 11:33:44,240 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 11:33:44,241 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 11:33:44,241 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 11:33:45,163 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 11:33:45,163 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 11:33:45,163 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 11:38:44,586 - src.server.fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 11:38:45,438 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 11:38:45,438 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 11:38:45,438 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 11:38:46,350 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 11:38:46,350 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 11:38:46,350 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 11:48:45,738 - src.server.fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 11:48:46,597 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 11:48:46,597 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 11:48:46,597 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 12:02:04,701 - src.server.fastapi_app - INFO - Shutting down AniWorld FastAPI server...
2025-10-06 12:02:05,779 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 12:02:05,779 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 12:02:05,779 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 12:02:06,954 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 12:02:06,954 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 12:02:06,954 - src.server.fastapi_app - INFO - Log level: INFO
2025-10-06 12:46:54,539 - src.server.fastapi_app - INFO - Starting AniWorld FastAPI server...
2025-10-06 12:46:54,539 - src.server.fastapi_app - INFO - Anime directory: ./downloads
2025-10-06 12:46:54,539 - src.server.fastapi_app - INFO - Log level: INFO

View File

@ -1,6 +1,6 @@
from src.core.SerieScanner import SerieScanner
from src.core.entities.SerieList import SerieList from src.core.entities.SerieList import SerieList
from src.core.providers.provider_factory import Loaders from src.core.providers.provider_factory import Loaders
from src.core.SerieScanner import SerieScanner
class SeriesApp: class SeriesApp:

View File

@ -34,6 +34,10 @@ from fastapi.templating import Jinja2Templates
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from pydantic_settings import BaseSettings from pydantic_settings import BaseSettings
# Import application flow services
from src.server.middleware.application_flow_middleware import ApplicationFlowMiddleware
from src.server.services.setup_service import SetupService
# Import our custom middleware - temporarily disabled due to file corruption # Import our custom middleware - temporarily disabled due to file corruption
# from src.server.web.middleware.fastapi_auth_middleware import AuthMiddleware # from src.server.web.middleware.fastapi_auth_middleware import AuthMiddleware
# from src.server.web.middleware.fastapi_logging_middleware import ( # from src.server.web.middleware.fastapi_logging_middleware import (
@ -46,7 +50,7 @@ logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[ handlers=[
logging.FileHandler('./logs/aniworld.log'), logging.FileHandler('./logs/aniworld.log'),
logging.StreamHandler() logging.StreamHandler()
] ]
) )
@ -138,6 +142,23 @@ class ErrorResponse(BaseModel):
code: Optional[str] = None code: Optional[str] = None
details: Optional[Dict[str, Any]] = None details: Optional[Dict[str, Any]] = None
class SetupRequest(BaseModel):
"""Setup request model."""
password: str = Field(..., min_length=8, description="Master password (min 8 characters)")
directory: str = Field(..., min_length=1, description="Anime directory path")
class SetupResponse(BaseModel):
"""Setup response model."""
status: str
message: str
redirect_url: Optional[str] = None
class SetupStatusResponse(BaseModel):
"""Setup status response model."""
setup_complete: bool
requirements: Dict[str, bool]
missing_requirements: List[str]
# Authentication utilities # Authentication utilities
def hash_password(password: str) -> str: def hash_password(password: str) -> str:
"""Hash password with salt using SHA-256.""" """Hash password with salt using SHA-256."""
@ -311,6 +332,10 @@ app.add_middleware(
allow_headers=["*"], allow_headers=["*"],
) )
# Add application flow middleware
setup_service = SetupService()
app.add_middleware(ApplicationFlowMiddleware, setup_service=setup_service)
# Add custom middleware - temporarily disabled # Add custom middleware - temporarily disabled
# app.add_middleware(EnhancedLoggingMiddleware) # app.add_middleware(EnhancedLoggingMiddleware)
# app.add_middleware(AuthMiddleware) # app.add_middleware(AuthMiddleware)
@ -360,6 +385,144 @@ async def legacy_download(
except Exception as e: except Exception as e:
return {"status": "error", "message": f"Failed to start download: {str(e)}"} return {"status": "error", "message": f"Failed to start download: {str(e)}"}
# Setup endpoints
@app.get("/api/auth/setup/status", response_model=SetupStatusResponse, tags=["Setup"])
async def get_setup_status() -> SetupStatusResponse:
"""
Check the current setup status of the application.
Returns information about what setup requirements are met and which are missing.
"""
try:
setup_service = SetupService()
requirements = setup_service.get_setup_requirements()
missing = setup_service.get_missing_requirements()
return SetupStatusResponse(
setup_complete=setup_service.is_setup_complete(),
requirements=requirements,
missing_requirements=missing
)
except Exception as e:
logger.error(f"Error checking setup status: {e}")
return SetupStatusResponse(
setup_complete=False,
requirements={},
missing_requirements=["Error checking setup status"]
)
@app.post("/api/auth/setup", response_model=SetupResponse, tags=["Setup"])
async def process_setup(request_data: SetupRequest) -> SetupResponse:
"""
Process the initial application setup.
- **password**: Master password (minimum 8 characters)
- **directory**: Anime directory path
"""
try:
setup_service = SetupService()
# Check if setup is already complete
if setup_service.is_setup_complete():
return SetupResponse(
status="error",
message="Setup has already been completed"
)
# Validate directory path
from pathlib import Path
directory_path = Path(request_data.directory)
if not directory_path.is_absolute():
return SetupResponse(
status="error",
message="Please provide an absolute directory path"
)
# Create directory if it doesn't exist
try:
directory_path.mkdir(parents=True, exist_ok=True)
except Exception as e:
logger.error(f"Failed to create directory: {e}")
return SetupResponse(
status="error",
message=f"Failed to create directory: {str(e)}"
)
# Hash the password
password_hash = hash_password(request_data.password)
# Prepare configuration updates
config_updates = {
"security": {
"master_password_hash": password_hash,
"salt": settings.password_salt,
"session_timeout_hours": settings.token_expiry_hours,
"max_failed_attempts": 5,
"lockout_duration_minutes": 30
},
"anime": {
"directory": str(directory_path),
"download_threads": 3,
"download_speed_limit": None,
"auto_rescan_time": "03:00",
"auto_download_after_rescan": False
},
"logging": {
"level": "INFO",
"enable_console_logging": True,
"enable_console_progress": False,
"enable_fail2ban_logging": True,
"log_file": "aniworld.log",
"max_log_size_mb": 10,
"log_backup_count": 5
},
"providers": {
"default_provider": "aniworld.to",
"preferred_language": "German Dub",
"fallback_providers": ["aniworld.to"],
"provider_timeout": 30,
"retry_attempts": 3,
"provider_settings": {
"aniworld.to": {
"enabled": True,
"priority": 1,
"quality_preference": "720p"
}
}
},
"advanced": {
"max_concurrent_downloads": 3,
"download_buffer_size": 8192,
"connection_timeout": 30,
"read_timeout": 300,
"enable_debug_mode": False,
"cache_duration_minutes": 60
}
}
# Mark setup as complete and save configuration
success = setup_service.mark_setup_complete(config_updates)
if success:
logger.info("Application setup completed successfully")
return SetupResponse(
status="success",
message="Setup completed successfully",
redirect_url="/login"
)
else:
return SetupResponse(
status="error",
message="Failed to save configuration"
)
except Exception as e:
logger.error(f"Setup processing error: {e}")
return SetupResponse(
status="error",
message="Setup failed due to internal error"
)
# Authentication endpoints # Authentication endpoints
@app.post("/auth/login", response_model=LoginResponse, tags=["Authentication"]) @app.post("/auth/login", response_model=LoginResponse, tags=["Authentication"])
async def login(request_data: LoginRequest, request: Request) -> LoginResponse: async def login(request_data: LoginRequest, request: Request) -> LoginResponse:

View File

@ -0,0 +1,248 @@
"""
Application Flow Middleware for FastAPI.
This middleware enforces the application flow priorities:
1. Setup page (if setup is not complete)
2. Authentication page (if user is not authenticated)
3. Main application (for authenticated users with completed setup)
The middleware redirects users to the appropriate page based on their current state
and the state of the application setup.
"""
import logging
from typing import Optional
from fastapi import Request
from fastapi.responses import RedirectResponse
from starlette.middleware.base import BaseHTTPMiddleware
# Import the setup service
try:
from ..services.setup_service import SetupService
except ImportError:
# Handle case where service is not available
class SetupService:
def is_setup_complete(self):
return True
logger = logging.getLogger(__name__)
class ApplicationFlowMiddleware(BaseHTTPMiddleware):
"""
Middleware to enforce application flow: setup auth main application.
This middleware:
1. Checks if setup is complete
2. Validates authentication status
3. Redirects to appropriate page based on state
4. Allows API endpoints and static files to pass through
"""
def __init__(self, app, setup_service: Optional[SetupService] = None):
"""
Initialize the application flow middleware.
Args:
app: FastAPI application instance
setup_service: Setup service instance (optional, will create if not provided)
"""
super().__init__(app)
self.setup_service = setup_service or SetupService()
# Define paths that should bypass flow enforcement
self.bypass_paths = {
"/static", # Static files
"/favicon.ico", # Browser favicon requests
"/robots.txt", # Robots.txt
"/health", # Health check endpoints
"/docs", # OpenAPI documentation
"/redoc", # ReDoc documentation
"/openapi.json" # OpenAPI spec
}
# API paths that should bypass flow but may require auth
self.api_paths = {
"/api",
"/auth"
}
# Pages that are part of the flow and should be accessible
self.flow_pages = {
"/setup",
"/login",
"/app"
}
async def dispatch(self, request: Request, call_next):
"""
Process the request and enforce application flow.
Args:
request: Incoming HTTP request
call_next: Next middleware/handler in chain
Returns:
Response: Either a redirect response or the result of call_next
"""
try:
# Get the request path
path = request.url.path
# Skip flow enforcement for certain paths
if self._should_bypass_flow(path):
return await call_next(request)
# Check application setup status
setup_complete = self.setup_service.is_setup_complete()
# Check authentication status
is_authenticated = await self._is_user_authenticated(request)
# Determine the appropriate action
redirect_response = self._determine_redirect(path, setup_complete, is_authenticated)
if redirect_response:
logger.info(f"Redirecting {path} to {redirect_response.headers.get('location')}")
return redirect_response
# Continue with the request
return await call_next(request)
except Exception as e:
logger.error(f"Error in ApplicationFlowMiddleware: {e}", exc_info=True)
# In case of error, allow the request to continue
return await call_next(request)
def _should_bypass_flow(self, path: str) -> bool:
"""
Check if the given path should bypass flow enforcement.
Args:
path: Request path
Returns:
bool: True if path should bypass flow enforcement
"""
# Check exact bypass paths
for bypass_path in self.bypass_paths:
if path.startswith(bypass_path):
return True
# API paths bypass flow enforcement (but may have their own auth)
for api_path in self.api_paths:
if path.startswith(api_path):
return True
return False
async def _is_user_authenticated(self, request: Request) -> bool:
"""
Check if the user is authenticated by validating JWT token.
Args:
request: HTTP request object
Returns:
bool: True if user is authenticated, False otherwise
"""
try:
# Check for Authorization header
auth_header = request.headers.get("authorization")
if not auth_header or not auth_header.startswith("Bearer "):
return False
# Extract and validate token
token = auth_header.split(" ")[1]
# Import JWT validation function (avoid circular imports)
try:
from ..fastapi_app import verify_jwt_token
payload = verify_jwt_token(token)
return payload is not None
except ImportError:
# Fallback if import fails
logger.warning("Could not import JWT verification function")
return False
except Exception as e:
logger.error(f"Error checking authentication: {e}")
return False
def _determine_redirect(self, path: str, setup_complete: bool, is_authenticated: bool) -> Optional[RedirectResponse]:
"""
Determine if a redirect is needed based on current state.
Args:
path: Current request path
setup_complete: Whether application setup is complete
is_authenticated: Whether user is authenticated
Returns:
Optional[RedirectResponse]: Redirect response if needed, None otherwise
"""
# If setup is not complete
if not setup_complete:
# Allow access to setup page
if path == "/setup":
return None
# Redirect everything else to setup
return RedirectResponse(url="/setup", status_code=302)
# Setup is complete, check authentication
if not is_authenticated:
# Allow access to login page
if path == "/login":
return None
# Redirect unauthenticated users to login (except for specific pages)
if path in self.flow_pages or path == "/":
return RedirectResponse(url="/login", status_code=302)
# User is authenticated and setup is complete
else:
# Redirect from setup/login pages to main app
if path in ["/setup", "/login", "/"]:
return RedirectResponse(url="/app", status_code=302)
# No redirect needed
return None
def get_flow_status(self, request: Request) -> dict:
"""
Get current flow status for debugging/monitoring.
Args:
request: HTTP request object
Returns:
dict: Current flow status information
"""
try:
setup_complete = self.setup_service.is_setup_complete()
is_authenticated = self._is_user_authenticated(request)
return {
"setup_complete": setup_complete,
"authenticated": is_authenticated,
"path": request.url.path,
"should_bypass": self._should_bypass_flow(request.url.path)
}
except Exception as e:
return {
"error": str(e),
"path": request.url.path
}
def create_application_flow_middleware(setup_service: Optional[SetupService] = None) -> ApplicationFlowMiddleware:
"""
Factory function to create application flow middleware.
Args:
setup_service: Setup service instance (optional)
Returns:
ApplicationFlowMiddleware: Configured middleware instance
"""
return ApplicationFlowMiddleware(app=None, setup_service=setup_service)

View File

@ -0,0 +1,268 @@
"""
Setup service for detecting and managing application setup state.
This service determines if the application is properly configured and set up,
following the application flow pattern: setup auth main application.
"""
import json
import sqlite3
from datetime import datetime
from pathlib import Path
from typing import Dict, Any, Optional, List
import logging
logger = logging.getLogger(__name__)
class SetupService:
"""Service for managing application setup detection and configuration."""
def __init__(self, config_path: str = "data/config.json", db_path: str = "data/aniworld.db"):
"""Initialize the setup service with configuration and database paths."""
self.config_path = Path(config_path)
self.db_path = Path(db_path)
self._config_cache: Optional[Dict[str, Any]] = None
def is_setup_complete(self) -> bool:
"""
Check if the application setup is complete.
Setup is considered complete if:
1. Configuration file exists and is valid
2. Database exists and is accessible
3. Master password is configured
4. Setup completion flag is set (if present)
Returns:
bool: True if setup is complete, False otherwise
"""
try:
# Check if configuration file exists and is valid
if not self._is_config_valid():
logger.info("Setup incomplete: Configuration file is missing or invalid")
return False
# Check if database exists and is accessible
if not self._is_database_accessible():
logger.info("Setup incomplete: Database is not accessible")
return False
# Check if master password is configured
if not self._is_master_password_configured():
logger.info("Setup incomplete: Master password is not configured")
return False
# Check for explicit setup completion flag
config = self.get_config()
if config and config.get("setup", {}).get("completed") is False:
logger.info("Setup incomplete: Setup completion flag is False")
return False
logger.debug("Setup validation complete: All checks passed")
return True
except Exception as e:
logger.error(f"Error checking setup completion: {e}")
return False
def _is_config_valid(self) -> bool:
"""Check if the configuration file exists and contains valid JSON."""
try:
if not self.config_path.exists():
return False
config = self.get_config()
return config is not None and isinstance(config, dict)
except Exception as e:
logger.error(f"Configuration validation error: {e}")
return False
def _is_database_accessible(self) -> bool:
"""Check if the database exists and is accessible."""
try:
if not self.db_path.exists():
return False
# Try to connect and perform a simple query
with sqlite3.connect(str(self.db_path)) as conn:
cursor = conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' LIMIT 1")
return True
except Exception as e:
logger.error(f"Database accessibility check failed: {e}")
return False
def _is_master_password_configured(self) -> bool:
"""Check if master password is properly configured."""
try:
config = self.get_config()
if not config:
return False
security_config = config.get("security", {})
# Check if password hash exists
password_hash = security_config.get("master_password_hash")
salt = security_config.get("salt")
return bool(password_hash and salt and len(password_hash) > 0 and len(salt) > 0)
except Exception as e:
logger.error(f"Master password configuration check failed: {e}")
return False
def get_config(self, force_reload: bool = False) -> Optional[Dict[str, Any]]:
"""
Get the configuration data from the config file.
Args:
force_reload: If True, reload config from file even if cached
Returns:
dict: Configuration data or None if not accessible
"""
try:
if self._config_cache is None or force_reload:
if not self.config_path.exists():
return None
with open(self.config_path, 'r', encoding='utf-8') as f:
self._config_cache = json.load(f)
return self._config_cache
except Exception as e:
logger.error(f"Error loading configuration: {e}")
return None
def mark_setup_complete(self, config_updates: Optional[Dict[str, Any]] = None) -> bool:
"""
Mark the setup as completed and optionally update configuration.
Args:
config_updates: Additional configuration updates to apply
Returns:
bool: True if successful, False otherwise
"""
try:
config = self.get_config() or {}
# Update configuration with any provided updates
if config_updates:
config.update(config_updates)
# Set setup completion flag
if "setup" not in config:
config["setup"] = {}
config["setup"]["completed"] = True
config["setup"]["completed_at"] = str(datetime.utcnow())
# Save updated configuration
return self._save_config(config)
except Exception as e:
logger.error(f"Error marking setup as complete: {e}")
return False
def reset_setup(self) -> bool:
"""
Reset the setup completion status (for development/testing).
Returns:
bool: True if successful, False otherwise
"""
try:
config = self.get_config()
if not config:
return False
# Remove or set setup completion flag to false
if "setup" in config:
config["setup"]["completed"] = False
return self._save_config(config)
except Exception as e:
logger.error(f"Error resetting setup: {e}")
return False
def _save_config(self, config: Dict[str, Any]) -> bool:
"""Save configuration to file."""
try:
# Ensure directory exists
self.config_path.parent.mkdir(parents=True, exist_ok=True)
# Save configuration
with open(self.config_path, 'w', encoding='utf-8') as f:
json.dump(config, f, indent=4, ensure_ascii=False)
# Clear cache to force reload on next access
self._config_cache = None
logger.info(f"Configuration saved to {self.config_path}")
return True
except Exception as e:
logger.error(f"Error saving configuration: {e}")
return False
def get_setup_requirements(self) -> Dict[str, bool]:
"""
Get detailed breakdown of setup requirements and their status.
Returns:
dict: Dictionary with requirement names and their completion status
"""
config = self.get_config()
return {
"config_file_exists": self.config_path.exists(),
"config_file_valid": self._is_config_valid(),
"database_exists": self.db_path.exists(),
"database_accessible": self._is_database_accessible(),
"master_password_configured": self._is_master_password_configured(),
"setup_marked_complete": bool(config and config.get("setup", {}).get("completed", True))
}
def get_missing_requirements(self) -> List[str]:
"""
Get list of missing setup requirements.
Returns:
list: List of missing requirement descriptions
"""
requirements = self.get_setup_requirements()
missing = []
if not requirements["config_file_exists"]:
missing.append("Configuration file is missing")
elif not requirements["config_file_valid"]:
missing.append("Configuration file is invalid or corrupted")
if not requirements["database_exists"]:
missing.append("Database file is missing")
elif not requirements["database_accessible"]:
missing.append("Database is not accessible or corrupted")
if not requirements["master_password_configured"]:
missing.append("Master password is not configured")
if not requirements["setup_marked_complete"]:
missing.append("Setup process was not completed")
return missing
# Convenience functions for easy import
def is_setup_complete() -> bool:
"""Convenience function to check if setup is complete."""
service = SetupService()
return service.is_setup_complete()
def get_setup_service() -> SetupService:
"""Get a configured setup service instance."""
return SetupService()

View File

@ -2,11 +2,12 @@
Pytest configuration file for AniWorld application tests. Pytest configuration file for AniWorld application tests.
""" """
import pytest
import os import os
import sys import sys
from unittest.mock import Mock from unittest.mock import Mock
import pytest
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
@ -79,8 +80,9 @@ def sample_episode_data():
@pytest.fixture @pytest.fixture
def valid_jwt_token(): def valid_jwt_token():
"""Valid JWT token for testing.""" """Valid JWT token for testing."""
import jwt
from datetime import datetime, timedelta from datetime import datetime, timedelta
import jwt
payload = { payload = {
"user": "test_user", "user": "test_user",
@ -92,8 +94,9 @@ def valid_jwt_token():
@pytest.fixture @pytest.fixture
def expired_jwt_token(): def expired_jwt_token():
"""Expired JWT token for testing.""" """Expired JWT token for testing."""
import jwt
from datetime import datetime, timedelta from datetime import datetime, timedelta
import jwt
payload = { payload = {
"user": "test_user", "user": "test_user",

View File

@ -5,12 +5,13 @@ Tests complete user authentication scenarios including login/logout flow
and session management. and session management.
""" """
import pytest
import sys
import os import os
from fastapi.testclient import TestClient import sys
from unittest.mock import patch from unittest.mock import patch
import pytest
from fastapi.testclient import TestClient
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))

View File

@ -5,11 +5,12 @@ This module tests complete user workflows for bulk operations including
download flows, export processes, and error handling scenarios. download flows, export processes, and error handling scenarios.
""" """
import pytest
import time
from fastapi.testclient import TestClient
from unittest.mock import patch, AsyncMock
import asyncio import asyncio
import time
from unittest.mock import AsyncMock, patch
import pytest
from fastapi.testclient import TestClient
from src.server.fastapi_app import app from src.server.fastapi_app import app

View File

@ -5,11 +5,12 @@ Tests complete CLI workflows including progress bar functionality,
retry logic, user interactions, and error scenarios. retry logic, user interactions, and error scenarios.
""" """
import pytest
import sys
import os import os
from unittest.mock import Mock, patch import sys
import tempfile import tempfile
from unittest.mock import Mock, patch
import pytest
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))

View File

@ -5,11 +5,12 @@ This module tests complete user workflows for changing preferences and verifying
that the UI responds appropriately to preference changes. that the UI responds appropriately to preference changes.
""" """
import pytest
import time import time
from fastapi.testclient import TestClient
from unittest.mock import patch from unittest.mock import patch
import pytest
from fastapi.testclient import TestClient
from src.server.fastapi_app import app from src.server.fastapi_app import app

View File

@ -5,12 +5,13 @@ Tests anime search, anime details, episode retrieval with pagination,
valid/invalid IDs, and search filtering functionality. valid/invalid IDs, and search filtering functionality.
""" """
import pytest
import sys
import os import os
from fastapi.testclient import TestClient import sys
from unittest.mock import patch from unittest.mock import patch
import pytest
from fastapi.testclient import TestClient
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))

View File

@ -5,11 +5,12 @@ Tests POST /auth/login, GET /auth/verify, POST /auth/logout endpoints
with valid/invalid credentials and tokens. with valid/invalid credentials and tokens.
""" """
import pytest
import sys
import os import os
import sys
from unittest.mock import Mock, patch
import pytest
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from unittest.mock import patch, Mock
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))

View File

@ -6,9 +6,10 @@ Tests include authentication, validation, and error handling.
""" """
import json import json
from unittest.mock import Mock, patch
import pytest import pytest
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from unittest.mock import patch, Mock
from src.server.fastapi_app import app from src.server.fastapi_app import app

View File

@ -5,12 +5,13 @@ Tests database info, maintenance operations (vacuum, analyze, integrity-check,
reindex, optimize, stats), and storage management functionality. reindex, optimize, stats), and storage management functionality.
""" """
import pytest
import sys
import os import os
from fastapi.testclient import TestClient import sys
from unittest.mock import patch from unittest.mock import patch
import pytest
from fastapi.testclient import TestClient
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))

View File

@ -4,11 +4,12 @@ Integration tests for diagnostics API endpoints.
This module tests the diagnostics endpoints for error reporting and system diagnostics. This module tests the diagnostics endpoints for error reporting and system diagnostics.
""" """
import os
import tempfile
from unittest.mock import Mock, patch
import pytest import pytest
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from unittest.mock import patch, Mock
import tempfile
import os
from src.server.fastapi_app import app from src.server.fastapi_app import app

View File

@ -5,12 +5,13 @@ Tests /health, /api/health/* endpoints including system metrics,
database health, dependencies, performance, and monitoring. database health, dependencies, performance, and monitoring.
""" """
import pytest
import sys
import os import os
from fastapi.testclient import TestClient import sys
from unittest.mock import patch
from datetime import datetime from datetime import datetime
from unittest.mock import patch
import pytest
from fastapi.testclient import TestClient
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))

View File

@ -5,11 +5,12 @@ This module tests the integration endpoints for managing API keys, webhook confi
and third-party service integrations. and third-party service integrations.
""" """
import pytest
from fastapi.testclient import TestClient
from unittest.mock import patch, Mock
import json import json
import uuid import uuid
from unittest.mock import Mock, patch
import pytest
from fastapi.testclient import TestClient
from src.server.fastapi_app import app from src.server.fastapi_app import app

View File

@ -5,13 +5,14 @@ Tests configuration system integration, error handling pipelines,
and modular architecture component interactions. and modular architecture component interactions.
""" """
import pytest
import sys
import os
from unittest.mock import Mock
import json import json
import os
import sys
import tempfile import tempfile
from pathlib import Path from pathlib import Path
from unittest.mock import Mock
import pytest
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))

View File

@ -5,10 +5,11 @@ This module tests the performance-related endpoints for speed limiting, cache ma
memory management, and download task handling. memory management, and download task handling.
""" """
import time
from unittest.mock import Mock, patch
import pytest import pytest
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from unittest.mock import patch, Mock
import time
from src.server.fastapi_app import app from src.server.fastapi_app import app

View File

@ -5,9 +5,10 @@ This module tests the user preferences endpoints for theme management, language
accessibility settings, keyboard shortcuts, and UI density configurations. accessibility settings, keyboard shortcuts, and UI density configurations.
""" """
from unittest.mock import patch
import pytest import pytest
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from unittest.mock import patch
from src.server.fastapi_app import app from src.server.fastapi_app import app

View File

@ -1,2 +1,3 @@
from src.server.web.middleware.fastapi_auth_middleware_new import AuthMiddleware from src.server.web.middleware.fastapi_auth_middleware_new import AuthMiddleware
print("Success importing AuthMiddleware")
print("Success importing AuthMiddleware")

View File

@ -1,5 +1,5 @@
import sys
import os import os
import sys
# Add parent directory to path # Add parent directory to path
sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath('.'))

View File

@ -6,13 +6,17 @@ except Exception as e:
print(f"Error importing auth middleware: {e}") print(f"Error importing auth middleware: {e}")
try: try:
from src.server.web.middleware.fastapi_logging_middleware import EnhancedLoggingMiddleware from src.server.web.middleware.fastapi_logging_middleware import (
EnhancedLoggingMiddleware,
)
print("Logging middleware imported successfully") print("Logging middleware imported successfully")
except Exception as e: except Exception as e:
print(f"Error importing logging middleware: {e}") print(f"Error importing logging middleware: {e}")
try: try:
from src.server.web.middleware.fastapi_validation_middleware import ValidationMiddleware from src.server.web.middleware.fastapi_validation_middleware import (
ValidationMiddleware,
)
print("Validation middleware imported successfully") print("Validation middleware imported successfully")
except Exception as e: except Exception as e:
print(f"Error importing validation middleware: {e}") print(f"Error importing validation middleware: {e}")

View File

@ -5,9 +5,10 @@ Tests search algorithms, filtering functions, sorting mechanisms,
and data processing for anime and episode management. and data processing for anime and episode management.
""" """
import pytest
import sys
import os import os
import sys
import pytest
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))

View File

@ -5,23 +5,24 @@ Tests password hashing, JWT creation/validation, session timeout logic,
and secure environment variable management. and secure environment variable management.
""" """
import pytest
import hashlib import hashlib
import jwt
import sys
import os import os
import sys
from datetime import datetime, timedelta from datetime import datetime, timedelta
from unittest.mock import patch from unittest.mock import patch
import jwt
import pytest
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from src.server.fastapi_app import ( from src.server.fastapi_app import (
hash_password, Settings,
verify_master_password,
generate_jwt_token, generate_jwt_token,
hash_password,
verify_jwt_token, verify_jwt_token,
Settings verify_master_password,
) )

View File

@ -5,16 +5,21 @@ Tests CLI commands (scan, search, download, rescan, display series),
user input handling, and command-line interface logic. user input handling, and command-line interface logic.
""" """
import pytest
import sys
import os import os
import sys
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
import pytest
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
# Import after path setup # Import after path setup
from src.cli.Main import SeriesApp, NoKeyFoundException, MatchNotFoundError # noqa: E402 from src.cli.Main import ( # noqa: E402
MatchNotFoundError,
NoKeyFoundException,
SeriesApp,
)
@pytest.fixture @pytest.fixture
@ -409,7 +414,7 @@ class TestCLIEnvironmentVariables:
# Import and run main module simulation # Import and run main module simulation
import src.cli.Main import src.cli.Main
# The default should be the hardcoded path # The default should be the hardcoded path
default_path = "\\\\sshfs.r\\ubuntu@192.168.178.43\\media\\serien\\Serien" default_path = "\\\\sshfs.r\\ubuntu@192.168.178.43\\media\\serien\\Serien"
result = os.getenv("ANIME_DIRECTORY", default_path) result = os.getenv("ANIME_DIRECTORY", default_path)

View File

@ -5,11 +5,12 @@ Tests database maintenance functions, storage optimization,
integrity checking, and database management utilities. integrity checking, and database management utilities.
""" """
import pytest
import sys
import os import os
import sys
from unittest.mock import Mock from unittest.mock import Mock
import pytest
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))

View File

@ -5,12 +5,13 @@ This module tests the logging configuration, log file management,
and error reporting components. and error reporting components.
""" """
import pytest
import logging import logging
import tempfile
import os import os
from unittest.mock import patch, Mock, mock_open import tempfile
from pathlib import Path from pathlib import Path
from unittest.mock import Mock, mock_open, patch
import pytest
# Import logging components # Import logging components
try: try:
@ -109,7 +110,7 @@ class TestLogFileManagement:
def test_log_file_rotation(self): def test_log_file_rotation(self):
"""Test log file rotation functionality.""" """Test log file rotation functionality."""
from logging.handlers import RotatingFileHandler from logging.handlers import RotatingFileHandler
# Create rotating file handler # Create rotating file handler
handler = RotatingFileHandler( handler = RotatingFileHandler(
self.log_file, self.log_file,

View File

@ -5,12 +5,13 @@ Tests configuration loading, centralized error handling, module structure,
and architectural component integration. and architectural component integration.
""" """
import pytest
import sys
import os
from unittest.mock import Mock, patch
import tempfile
import json import json
import os
import sys
import tempfile
from unittest.mock import Mock, patch
import pytest
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
@ -131,10 +132,10 @@ class TestErrorHandling:
# Import custom exceptions if they exist # Import custom exceptions if they exist
try: try:
from src.core.exceptions.Exceptions import ( # noqa: F401 from src.core.exceptions.Exceptions import ( # noqa: F401
MatchNotFoundError,
NoKeyFoundException, NoKeyFoundException,
MatchNotFoundError
) )
# Test exception creation # Test exception creation
key_error = NoKeyFoundException("Key not found") key_error = NoKeyFoundException("Key not found")
assert str(key_error) == "Key not found" assert str(key_error) == "Key not found"

View File

@ -5,11 +5,12 @@ Tests CPU, memory, disk usage collection, performance monitoring,
and system health assessment logic. and system health assessment logic.
""" """
import pytest
import sys
import os import os
from unittest.mock import patch, Mock import sys
from datetime import datetime from datetime import datetime
from unittest.mock import Mock, patch
import pytest
# Add source directory to path # Add source directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))