diff --git a/data/config.json b/data/config.json index ce4c967..e922d5c 100644 --- a/data/config.json +++ b/data/config.json @@ -17,7 +17,7 @@ "keep_days": 30 }, "other": { - "master_password_hash": "$pbkdf2-sha256$29000$DgFgDIHwfk/p/X.PEULIGQ$baPkp2MQxqv8yolTjZ5Ks0fIl9g/Eer3YBE1jjR6qjc", + "master_password_hash": "$pbkdf2-sha256$29000$tRZCyFnr/d87x/i/19p7Lw$BoD8EF67N97SRs7kIX8SREbotRwvFntS.WCH9ZwTxHY", "anime_directory": "/home/lukas/Volume/serien/" }, "version": "1.0.0" diff --git a/data/config_backups/config_backup_20251213_085947.json b/data/config_backups/config_backup_20251213_085947.json new file mode 100644 index 0000000..dca913d --- /dev/null +++ b/data/config_backups/config_backup_20251213_085947.json @@ -0,0 +1,24 @@ +{ + "name": "Aniworld", + "data_dir": "data", + "scheduler": { + "enabled": true, + "interval_minutes": 60 + }, + "logging": { + "level": "INFO", + "file": null, + "max_bytes": null, + "backup_count": 3 + }, + "backup": { + "enabled": false, + "path": "data/backups", + "keep_days": 30 + }, + "other": { + "master_password_hash": "$pbkdf2-sha256$29000$nbNWSkkJIeTce48xxrh3bg$QXT6A63JqmSLimtTeI04HzC4eKfQS26xFW7UL9Ry5co", + "anime_directory": "/home/lukas/Volume/serien/" + }, + "version": "1.0.0" +} \ No newline at end of file diff --git a/data/config_backups/config_backup_20251213_090130.json b/data/config_backups/config_backup_20251213_090130.json new file mode 100644 index 0000000..2157c7d --- /dev/null +++ b/data/config_backups/config_backup_20251213_090130.json @@ -0,0 +1,24 @@ +{ + "name": "Aniworld", + "data_dir": "data", + "scheduler": { + "enabled": true, + "interval_minutes": 60 + }, + "logging": { + "level": "INFO", + "file": null, + "max_bytes": null, + "backup_count": 3 + }, + "backup": { + "enabled": false, + "path": "data/backups", + "keep_days": 30 + }, + "other": { + "master_password_hash": "$pbkdf2-sha256$29000$j5HSWuu9V.rdm9Pa2zunNA$gjQqL753WLBMZtHVOhziVn.vW3Bkq8mGtCzSkbBjSHo", + "anime_directory": "/home/lukas/Volume/serien/" + }, + "version": "1.0.0" +} \ No newline at end of file diff --git a/docs/identifier_standardization_validation.md b/docs/identifier_standardization_validation.md index 9e0d05e..efb1e3f 100644 --- a/docs/identifier_standardization_validation.md +++ b/docs/identifier_standardization_validation.md @@ -178,10 +178,6 @@ grep -rn "data-key\|data-folder\|data-series" src/server/web/templates/ --includ - [ ] All CRUD operations use `key` for identification - [ ] Logging uses `key` in messages -3. **`src/server/database/migrations/`** - - [ ] Migration files maintain `key` as unique, indexed column - - [ ] No migrations that use `folder` as identifier - **Validation Commands:** ```bash diff --git a/docs/infrastructure.md b/docs/infrastructure.md index 54cebbc..583038a 100644 --- a/docs/infrastructure.md +++ b/docs/infrastructure.md @@ -60,10 +60,9 @@ Throughout the codebase, three identifiers are used for anime series: **Valid examples**: `"attack-on-titan"`, `"one-piece"`, `"86-eighty-six"`, `"re-zero"` **Invalid examples**: `"Attack On Titan"`, `"attack_on_titan"`, `"attack on titan"` -### Migration Notes +### Notes - **Backward Compatibility**: API endpoints accepting `anime_id` will check `key` first, then fall back to `folder` lookup -- **Deprecation**: Folder-based lookups are deprecated and will be removed in a future version - **New Code**: Always use `key` for identification; `folder` is metadata only ## API Endpoints diff --git a/requirements.txt b/requirements.txt index fe6fe32..dab5a18 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,5 +14,4 @@ pytest==7.4.3 pytest-asyncio==0.21.1 httpx==0.25.2 sqlalchemy>=2.0.35 -alembic==1.13.0 aiosqlite>=0.19.0 \ No newline at end of file diff --git a/scripts/start.sh b/scripts/start.sh index 186a105..498a94f 100644 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -7,7 +7,7 @@ # installs dependencies, sets up the database, and starts the application. # # Usage: -# ./start.sh [development|production] [--no-install] [--no-migrate] +# ./start.sh [development|production] [--no-install] # # Environment Variables: # ENVIRONMENT: 'development' or 'production' (default: development) @@ -28,7 +28,6 @@ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" CONDA_ENV="${CONDA_ENV:-AniWorld}" ENVIRONMENT="${1:-development}" INSTALL_DEPS="${INSTALL_DEPS:-true}" -RUN_MIGRATIONS="${RUN_MIGRATIONS:-true}" PORT="${PORT:-8000}" HOST="${HOST:-127.0.0.1}" @@ -104,20 +103,6 @@ install_dependencies() { log_success "Dependencies installed." } -# Run database migrations -run_migrations() { - if [[ "$RUN_MIGRATIONS" != "true" ]]; then - log_warning "Skipping database migrations." - return - fi - - log_info "Running database migrations..." - cd "$PROJECT_ROOT" - conda run -n "$CONDA_ENV" \ - python -m alembic upgrade head 2>/dev/null || log_warning "No migrations to run." - log_success "Database migrations completed." -} - # Initialize database init_database() { log_info "Initializing database..." @@ -220,10 +205,6 @@ main() { INSTALL_DEPS="false" shift ;; - --no-migrate) - RUN_MIGRATIONS="false" - shift - ;; *) ENVIRONMENT="$1" shift @@ -237,7 +218,6 @@ main() { create_env_file install_dependencies init_database - run_migrations start_application } diff --git a/src/server/api/auth.py b/src/server/api/auth.py index 31fbb70..7e3a135 100644 --- a/src/server/api/auth.py +++ b/src/server/api/auth.py @@ -31,7 +31,6 @@ async def setup_auth(req: SetupRequest): This endpoint also initializes the configuration with default values and saves the anime directory and master password hash. - If anime_directory is provided, runs migration for existing data files. """ if auth_service.is_configured(): raise HTTPException( diff --git a/src/server/api/config.py b/src/server/api/config.py index 674d72e..740c193 100644 --- a/src/server/api/config.py +++ b/src/server/api/config.py @@ -214,14 +214,14 @@ def update_advanced_config( async def update_directory( directory_config: Dict[str, str], auth: dict = Depends(require_auth) ) -> Dict[str, Any]: - """Update anime directory configuration and run migration. + """Update anime directory configuration. Args: directory_config: Dictionary with 'directory' key auth: Authentication token (required) Returns: - Success message with optional migration results + Success message """ try: directory = directory_config.get("directory") diff --git a/src/server/database/README.md b/src/server/database/README.md index 63a8d19..02885ab 100644 --- a/src/server/database/README.md +++ b/src/server/database/README.md @@ -13,7 +13,7 @@ This package provides persistent storage for anime series, episodes, download qu Install required dependencies: ```bash -pip install sqlalchemy alembic aiosqlite +pip install sqlalchemy aiosqlite ``` Or use the project requirements: @@ -163,24 +163,6 @@ from src.config.settings import settings settings.database_url = "sqlite:///./data/aniworld.db" ``` -## Migrations (Future) - -Alembic is installed for database migrations: - -```bash -# Initialize Alembic -alembic init alembic - -# Generate migration -alembic revision --autogenerate -m "Description" - -# Apply migrations -alembic upgrade head - -# Rollback -alembic downgrade -1 -``` - ## Testing Run database tests: @@ -196,7 +178,6 @@ The test suite uses an in-memory SQLite database for isolation and speed. - **base.py**: Base declarative class and mixins - **models.py**: SQLAlchemy ORM models (4 models) - **connection.py**: Engine, session factory, dependency injection -- **migrations.py**: Alembic migration placeholder - ****init**.py**: Package exports - **service.py**: Service layer with CRUD operations @@ -432,5 +413,4 @@ Solution: Ensure referenced records exist before creating relationships. ## Further Reading - [SQLAlchemy 2.0 Documentation](https://docs.sqlalchemy.org/en/20/) -- [Alembic Tutorial](https://alembic.sqlalchemy.org/en/latest/tutorial.html) - [FastAPI with Databases](https://fastapi.tiangolo.com/tutorial/sql-databases/) diff --git a/src/server/database/init.py b/src/server/database/init.py index a25e25d..b330de9 100644 --- a/src/server/database/init.py +++ b/src/server/database/init.py @@ -313,7 +313,6 @@ async def get_schema_version(engine: Optional[AsyncEngine] = None) -> str: """Get current database schema version. Returns version string based on existing tables and structure. - For production, consider using Alembic versioning. Args: engine: Optional database engine (uses default if not provided) diff --git a/src/server/fastapi_app.py b/src/server/fastapi_app.py index 5588b97..50d155f 100644 --- a/src/server/fastapi_app.py +++ b/src/server/fastapi_app.py @@ -51,7 +51,7 @@ async def lifespan(app: FastAPI): try: logger.info("Starting FastAPI application...") - # Initialize database first (required for migration and other services) + # Initialize database first (required for other services) try: from src.server.database.connection import init_db await init_db() diff --git a/src/server/services/config_service.py b/src/server/services/config_service.py index 61d2d75..6591750 100644 --- a/src/server/services/config_service.py +++ b/src/server/services/config_service.py @@ -4,7 +4,7 @@ This service handles: - Loading and saving configuration to JSON files - Configuration validation - Backup and restore functionality -- Configuration migration for version updates +- Configuration version management """ import json @@ -35,8 +35,8 @@ class ConfigBackupError(ConfigServiceError): class ConfigService: """Service for managing application configuration persistence. - Handles loading, saving, validation, backup, and migration of - configuration files. Uses JSON format for human-readable and + Handles loading, saving, validation, backup, and version management + of configuration files. Uses JSON format for human-readable and version-control friendly storage. """ @@ -84,11 +84,6 @@ class ConfigService: with open(self.config_path, "r", encoding="utf-8") as f: data = json.load(f) - # Check if migration is needed - file_version = data.get("version", "1.0.0") - if file_version != self.CONFIG_VERSION: - data = self._migrate_config(data, file_version) - # Remove version key before constructing AppConfig data.pop("version", None) @@ -328,26 +323,6 @@ class ConfigService: except (OSError, IOError): # Ignore errors during cleanup continue - - def _migrate_config( - self, data: Dict, from_version: str # noqa: ARG002 - ) -> Dict: - """Migrate configuration from old version to current. - - Args: - data: Configuration data to migrate - from_version: Version to migrate from (reserved for future use) - - Returns: - Dict: Migrated configuration data - """ - # Currently only one version exists - # Future migrations would go here - # Example: - # if from_version == "1.0.0" and self.CONFIG_VERSION == "2.0.0": - # data = self._migrate_1_0_to_2_0(data) - - return data # Singleton instance