Add admin commands for database operations
Features: - Add admin command group for database operations - admin list-users: List all users from SQLite/PostgreSQL/MySQL - admin user-notes: List notes for specific user - Add CodiMDDatabase class for direct DB access
This commit is contained in:
@@ -122,6 +122,12 @@ def config():
|
||||
pass
|
||||
|
||||
|
||||
@cli.group()
|
||||
def admin():
|
||||
"""Admin operations (require database access)."""
|
||||
pass
|
||||
|
||||
|
||||
# Note commands
|
||||
@note.command("list")
|
||||
@click.option("--limit", type=int, help="Limit number of results")
|
||||
@@ -599,6 +605,109 @@ def config_set(key, value):
|
||||
click.echo(f"Set {key} = {value}")
|
||||
|
||||
|
||||
# Admin commands
|
||||
@admin.command("list-users")
|
||||
@click.option("--db-type", type=click.Choice(["sqlite", "postgresql", "mysql"]), default="sqlite", help="Database type")
|
||||
@click.option("--db-path", type=Path, help="SQLite database path")
|
||||
@click.option("--db-host", help="Database host (for PostgreSQL/MySQL)")
|
||||
@click.option("--db-name", help="Database name (for PostgreSQL/MySQL)")
|
||||
@click.option("--db-user", help="Database user (for PostgreSQL/MySQL)")
|
||||
@click.option("--db-password", help="Database password (for PostgreSQL/MySQL)")
|
||||
@click.option("--db-port", type=int, default=5432, help="Database port (default: 5432 for PostgreSQL, 3306 for MySQL)")
|
||||
@handle_error
|
||||
def admin_list_users(db_type, db_path, db_host, db_name, db_user, db_password, db_port):
|
||||
"""List all users in the CodiMD database."""
|
||||
from cli_anything.codimd.core import CodiMDDatabase
|
||||
|
||||
if db_type == "sqlite":
|
||||
if not db_path:
|
||||
# Try default CodiMD SQLite path
|
||||
default_paths = [
|
||||
"./codimd/db.sqlite",
|
||||
"./db.sqlite",
|
||||
"/var/lib/codimd/db.sqlite"
|
||||
]
|
||||
for path in default_paths:
|
||||
if Path(path).exists():
|
||||
db_path = path
|
||||
break
|
||||
if not db_path:
|
||||
raise ValueError(
|
||||
"SQLite database path not found. "
|
||||
"Please specify with --db-path or ensure db.sqlite is in current directory."
|
||||
)
|
||||
users = CodiMDDatabase.list_users_sqlite(str(db_path))
|
||||
|
||||
elif db_type == "postgresql":
|
||||
if not all([db_host, db_name, db_user]):
|
||||
raise ValueError("--db-host, --db-name, and --db-user are required for PostgreSQL")
|
||||
if not db_password:
|
||||
db_password = click.prompt("Database password", hide_input=True)
|
||||
users = CodiMDDatabase.list_users_postgresql(db_host, db_name, db_user, db_password, db_port)
|
||||
|
||||
elif db_type == "mysql":
|
||||
if not all([db_host, db_name, db_user]):
|
||||
raise ValueError("--db-host, --db-name, and --db-user are required for MySQL")
|
||||
if not db_password:
|
||||
db_password = click.prompt("Database password", hide_input=True)
|
||||
users = CodiMDDatabase.list_users_mysql(db_host, db_name, db_user, db_password, db_port)
|
||||
|
||||
if ctx["json_mode"]:
|
||||
output_json(format_success({"users": users, "count": len(users)}))
|
||||
else:
|
||||
if not users:
|
||||
click.echo("No users found.")
|
||||
else:
|
||||
click.echo(f"Total users: {len(users)}")
|
||||
for u in users:
|
||||
user_id = u.get("id", "N/A")[:8] + "..." if len(u.get("id", "")) > 8 else u.get("id", "N/A")
|
||||
email = u.get("email") or "N/A"
|
||||
|
||||
# Get name from profile
|
||||
profile = u.get("profile")
|
||||
if profile:
|
||||
if isinstance(profile, str):
|
||||
try:
|
||||
profile = json.loads(profile)
|
||||
except:
|
||||
profile = {}
|
||||
name = profile.get("name") or profile.get("displayName") or "N/A"
|
||||
else:
|
||||
name = "N/A"
|
||||
|
||||
created = u.get("createdAt", "N/A")
|
||||
click.echo(f" {user_id} | {email:30s} | {name}")
|
||||
if created != "N/A":
|
||||
click.echo(f" Created: {created}")
|
||||
|
||||
|
||||
@admin.command("user-notes")
|
||||
@click.argument("user_id")
|
||||
@click.option("--db-path", type=Path, default="./db.sqlite", help="SQLite database path")
|
||||
@handle_error
|
||||
def admin_user_notes(user_id, db_path):
|
||||
"""List all notes for a specific user."""
|
||||
from cli_anything.codimd.core import CodiMDDatabase
|
||||
|
||||
if not Path(db_path).exists():
|
||||
raise FileNotFoundError(f"Database not found: {db_path}")
|
||||
|
||||
notes = CodiMDDatabase.list_user_notes_sqlite(str(db_path), user_id)
|
||||
|
||||
if ctx["json_mode"]:
|
||||
output_json(format_success({"user_id": user_id, "notes": notes, "count": len(notes)}))
|
||||
else:
|
||||
if not notes:
|
||||
click.echo(f"No notes found for user {user_id}")
|
||||
else:
|
||||
click.echo(f"Notes for user {user_id}: {len(notes)} total")
|
||||
for n in notes:
|
||||
note_id = n.get("shortid", n.get("id", "N/A"))
|
||||
title = n.get("title") or "Untitled"
|
||||
permission = n.get("permission", "N/A")
|
||||
click.echo(f" {note_id} | {title[:50]} | [{permission}]")
|
||||
|
||||
|
||||
# REPL mode
|
||||
@cli.command("repl")
|
||||
@handle_error
|
||||
|
||||
Reference in New Issue
Block a user