| |
| """Clear LandPPT image generation configuration from the local SQLite database. |
| |
| Usage: |
| python clear_image_config.py |
| python clear_image_config.py --user-id 1 |
| python clear_image_config.py --include-system |
| python clear_image_config.py --dry-run |
| """ |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import sqlite3 |
| from pathlib import Path |
| from typing import Iterable |
|
|
| IMAGE_CONFIG_KEYS = ( |
| "gemini_image_api_base", |
| "gemini_image_model", |
| "openai_image_api_base", |
| "openai_image_model", |
| "openai_image_quality", |
| "openai_image_size", |
| "openai_api_key_image", |
| "openai_image_api_key", |
| "siliconflow_api_key", |
| "pollinations_api_key", |
| "gemini_image_api_key", |
| ) |
|
|
| SECRET_KEYS = { |
| "openai_api_key_image", |
| "openai_image_api_key", |
| "siliconflow_api_key", |
| "pollinations_api_key", |
| "gemini_image_api_key", |
| } |
|
|
|
|
| def mask_value(key: str, value: object) -> str: |
| if value is None or str(value) == "": |
| return "<EMPTY>" |
|
|
| text = str(value) |
| if key in SECRET_KEYS: |
| if len(text) <= 10: |
| return "***" |
| return f"{text[:6]}...{text[-4:]}" |
|
|
| return text |
|
|
|
|
| def format_user_id(user_id: object) -> str: |
| return "SYSTEM" if user_id is None else str(user_id) |
|
|
|
|
| def placeholders(values: Iterable[object]) -> str: |
| return ",".join("?" for _ in values) |
|
|
|
|
| def fetch_rows(conn: sqlite3.Connection, include_system: bool, user_id: int) -> list[tuple]: |
| keys_sql = placeholders(IMAGE_CONFIG_KEYS) |
| params: list[object] = list(IMAGE_CONFIG_KEYS) |
|
|
| if include_system: |
| scope_sql = "(user_id = ? OR user_id IS NULL)" |
| params.append(user_id) |
| else: |
| scope_sql = "user_id = ?" |
| params.append(user_id) |
|
|
| sql = f""" |
| SELECT user_id, config_key, config_value, config_type, category |
| FROM user_configs |
| WHERE category = 'image_service' |
| AND config_key IN ({keys_sql}) |
| AND {scope_sql} |
| ORDER BY user_id, config_key |
| """ |
| return conn.execute(sql, params).fetchall() |
|
|
|
|
| def print_rows(title: str, rows: list[tuple]) -> None: |
| print(f"\n{title}") |
| print("-" * len(title)) |
|
|
| if not rows: |
| print("No matching rows.") |
| return |
|
|
| for user_id, key, value, config_type, category in rows: |
| print( |
| f"user={format_user_id(user_id):>6} | " |
| f"key={key:<24} | " |
| f"value={mask_value(key, value)} | " |
| f"type={config_type} | category={category}" |
| ) |
|
|
|
|
| def clear_config(conn: sqlite3.Connection, include_system: bool, user_id: int) -> int: |
| keys_sql = placeholders(IMAGE_CONFIG_KEYS) |
| params: list[object] = list(IMAGE_CONFIG_KEYS) |
|
|
| if include_system: |
| scope_sql = "(user_id = ? OR user_id IS NULL)" |
| params.append(user_id) |
| else: |
| scope_sql = "user_id = ?" |
| params.append(user_id) |
|
|
| sql = f""" |
| DELETE FROM user_configs |
| WHERE category = 'image_service' |
| AND config_key IN ({keys_sql}) |
| AND {scope_sql} |
| """ |
| cursor = conn.execute(sql, params) |
| return cursor.rowcount |
|
|
|
|
| def main() -> int: |
| parser = argparse.ArgumentParser( |
| description="Clear LandPPT image generation configuration from landppt.db." |
| ) |
| parser.add_argument( |
| "--db", |
| default="landppt.db", |
| help="Path to SQLite database. Default: landppt.db", |
| ) |
| parser.add_argument( |
| "--user-id", |
| type=int, |
| default=1, |
| help="User ID whose image config should be cleared. Default: 1", |
| ) |
| parser.add_argument( |
| "--include-system", |
| action="store_true", |
| help="Also delete system default image config where user_id is NULL.", |
| ) |
| parser.add_argument( |
| "--dry-run", |
| action="store_true", |
| help="Only show what would be deleted, without changing the database.", |
| ) |
| args = parser.parse_args() |
|
|
| db_path = Path(args.db) |
| if not db_path.exists(): |
| print(f"Database not found: {db_path}") |
| return 1 |
|
|
| conn = sqlite3.connect(str(db_path)) |
| try: |
| before_rows = fetch_rows(conn, include_system=args.include_system, user_id=args.user_id) |
| print_rows("Matching image config before cleanup", before_rows) |
|
|
| if args.dry_run: |
| print("\nDry run enabled. No rows were deleted.") |
| return 0 |
|
|
| deleted_count = clear_config(conn, include_system=args.include_system, user_id=args.user_id) |
| conn.commit() |
| print(f"\nDeleted rows: {deleted_count}") |
|
|
| after_rows = fetch_rows(conn, include_system=args.include_system, user_id=args.user_id) |
| print_rows("Matching image config after cleanup", after_rows) |
|
|
| print("\nDone. Restart LandPPT or refresh the settings page to see the result.") |
| return 0 |
| finally: |
| conn.close() |
|
|
|
|
| if __name__ == "__main__": |
| raise SystemExit(main()) |
|
|