#!/usr/bin/env python3 """ServerKit CLI - Administrative commands for ServerKit.""" import click import secrets import sys from werkzeug.security import generate_password_hash from app import create_app, db from app.models import User @click.group() def cli(): """ServerKit administrative CLI.""" pass @cli.command() @click.option('--email', prompt=True, help='Admin email address') @click.option('--username', prompt=True, help='Admin username') @click.option('--password', prompt=True, hide_input=True, confirmation_prompt=True, help='Admin password') def create_admin(email, username, password): """Create a new admin user.""" app = create_app() with app.app_context(): # Check if user already exists if User.query.filter((User.email == email) | (User.username == username)).first(): click.echo(click.style('Error: User with this email or username already exists.', fg='red')) sys.exit(1) user = User( email=email, username=username, role='admin', is_active=True ) user.set_password(password) db.session.add(user) db.session.commit() click.echo(click.style(f'Admin user "{username}" created successfully!', fg='green')) @cli.command() @click.option('--email', prompt=True, help='User email address') @click.option('--password', prompt=True, hide_input=True, confirmation_prompt=True, help='New password') def reset_password(email, password): """Reset a user's password.""" app = create_app() with app.app_context(): user = User.query.filter_by(email=email).first() if not user: click.echo(click.style(f'Error: User with email "{email}" not found.', fg='red')) sys.exit(1) user.set_password(password) user.failed_login_count = 0 user.locked_until = None db.session.commit() click.echo(click.style(f'Password reset successfully for "{user.username}"!', fg='green')) @cli.command() @click.option('--email', prompt=True, help='User email address') def unlock_user(email): """Unlock a locked user account.""" app = create_app() with app.app_context(): user = User.query.filter_by(email=email).first() if not user: click.echo(click.style(f'Error: User with email "{email}" not found.', fg='red')) sys.exit(1) user.failed_login_count = 0 user.locked_until = None db.session.commit() click.echo(click.style(f'User "{user.username}" unlocked successfully!', fg='green')) @cli.command() @click.option('--email', prompt=True, help='User email address') def make_admin(email): """Promote a user to admin role.""" app = create_app() with app.app_context(): user = User.query.filter_by(email=email).first() if not user: click.echo(click.style(f'Error: User with email "{email}" not found.', fg='red')) sys.exit(1) user.role = 'admin' db.session.commit() click.echo(click.style(f'User "{user.username}" is now an admin!', fg='green')) @cli.command() @click.option('--email', prompt=True, help='User email address') def deactivate_user(email): """Deactivate a user account.""" app = create_app() with app.app_context(): user = User.query.filter_by(email=email).first() if not user: click.echo(click.style(f'Error: User with email "{email}" not found.', fg='red')) sys.exit(1) user.is_active = False db.session.commit() click.echo(click.style(f'User "{user.username}" has been deactivated.', fg='yellow')) @cli.command() @click.option('--email', prompt=True, help='User email address') def activate_user(email): """Activate a user account.""" app = create_app() with app.app_context(): user = User.query.filter_by(email=email).first() if not user: click.echo(click.style(f'Error: User with email "{email}" not found.', fg='red')) sys.exit(1) user.is_active = True db.session.commit() click.echo(click.style(f'User "{user.username}" has been activated.', fg='green')) @cli.command() def list_users(): """List all users.""" app = create_app() with app.app_context(): users = User.query.all() if not users: click.echo('No users found.') return click.echo(f"\n{'ID':<5} {'Username':<20} {'Email':<30} {'Role':<10} {'Active':<8} {'Locked':<8}") click.echo('-' * 85) for user in users: locked = 'Yes' if user.is_locked else 'No' active = 'Yes' if user.is_active else 'No' click.echo(f"{user.id:<5} {user.username:<20} {user.email:<30} {user.role:<10} {active:<8} {locked:<8}") click.echo(f"\nTotal: {len(users)} user(s)") @cli.command() def generate_keys(): """Generate secure SECRET_KEY and JWT_SECRET_KEY.""" secret_key = secrets.token_hex(32) jwt_secret_key = secrets.token_hex(32) click.echo("\nAdd these to your .env file:\n") click.echo(f"SECRET_KEY={secret_key}") click.echo(f"JWT_SECRET_KEY={jwt_secret_key}") click.echo() @cli.command() def init_db(): """Initialize the database.""" app = create_app() with app.app_context(): db.create_all() click.echo(click.style('Database initialized successfully!', fg='green')) @cli.command() @click.confirmation_option(prompt='Are you sure you want to drop all tables?') def drop_db(): """Drop all database tables.""" app = create_app() with app.app_context(): db.drop_all() click.echo(click.style('All tables dropped!', fg='yellow')) if __name__ == '__main__': cli()