diff --git a/src/scripts/app_generator.py b/src/scripts/app_generator.py new file mode 100644 index 0000000..45286f4 --- /dev/null +++ b/src/scripts/app_generator.py @@ -0,0 +1,118 @@ +""" +App management for Django project setup. +Handles creation of Django apps and updating settings. +""" + +import os +import subprocess +from typing import Optional + +from src.scripts.console_ui import UIFormatter + + +class AppManager: + def __init__(self, app_name: str): + self.app_name = app_name + self.current_dir = os.getcwd() + self.manage_py_path = os.path.join(self.current_dir, "manage.py") + + def create_app(self) -> bool: + if not self._is_django_project(): + UIFormatter.print_error( + "Not in a Django project directory. Please run this command from your Django project root." + ) + return False + + if self._app_exists(): + UIFormatter.print_error(f"Django app '{self.app_name}' already exists.") + return False + + if not self._create_django_app(): + return False + + if not self._add_to_installed_apps(): + return False + + UIFormatter.print_success(f"Django app '{self.app_name}' created and configured successfully!") + return True + + def _is_django_project(self) -> bool: + return os.path.exists(self.manage_py_path) + + def _app_exists(self) -> bool: + app_path = os.path.join(self.current_dir, self.app_name) + return os.path.exists(app_path) + + def _create_django_app(self) -> bool: + result = subprocess.run(["django-admin", "startapp", self.app_name], capture_output=True, text=True, check=True) + + UIFormatter.print_success(f"Created Django app '{self.app_name}'") + return True + + def _add_to_installed_apps(self) -> bool: + settings_path = self._find_settings_path() + if not settings_path: + UIFormatter.print_error("Could not find Django settings directory") + return False + + base_settings_path = os.path.join(settings_path, "base.py") + if not os.path.exists(base_settings_path): + UIFormatter.print_error("Could not find base.py settings file") + return False + + with open(base_settings_path) as f: + content = f.read() + + if f'"{self.app_name}"' in content or f"'{self.app_name}'" in content: + UIFormatter.print_info(f"App '{self.app_name}' is already in INSTALLED_APPS") + return True + + if "USER_DEFINED_APPS" not in content: + UIFormatter.print_error("Could not find USER_DEFINED_APPS section in base.py") + return False + + lines = content.split("\n") + new_lines = [] + in_user_apps = False + apps_added = False + + for line in lines: + if "USER_DEFINED_APPS" in line and "=" in line: + in_user_apps = True + new_lines.append(line) + elif in_user_apps and line.strip() == "]": + new_lines.append(f' "{self.app_name}",') + new_lines.append(line) + in_user_apps = False + apps_added = True + else: + new_lines.append(line) + + if not apps_added: + UIFormatter.print_error("Could not find USER_DEFINED_APPS section in base.py") + return False + + with open(base_settings_path, "w") as f: + f.write("\n".join(new_lines)) + + UIFormatter.print_success(f"Added '{self.app_name}' to USER_DEFINED_APPS in base.py") + return True + + def _find_settings_path(self) -> Optional[str]: + # Look for project directories that contain settings + for item in os.listdir(self.current_dir): + if os.path.isdir(item) and not item.startswith(".") and item != "__pycache__": + # Check if this directory contains Django project files + project_path = os.path.join(self.current_dir, item) + settings_path = os.path.join(project_path, "settings") + + # Check if settings directory exists with base.py + if os.path.exists(settings_path) and os.path.exists(os.path.join(settings_path, "base.py")): + return settings_path + + # Fallback: look for settings in current directory + settings_path = os.path.join(self.current_dir, "settings") + if os.path.exists(settings_path) and os.path.exists(os.path.join(settings_path, "base.py")): + return settings_path + + return None diff --git a/src/scripts/command_handler.py b/src/scripts/command_handler.py new file mode 100644 index 0000000..9c5d7d6 --- /dev/null +++ b/src/scripts/command_handler.py @@ -0,0 +1,112 @@ +""" +Command handlers for Django project setup CLI. +Handles different commands like secret key generation and app creation. +""" + +import argparse +import sys + +from src.scripts.console_ui import UIColors, UIFormatter, console +from src.scripts.name_validator import validate_app_name + + +def parse_arguments() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Django project setup tool", prog="django-init") + + subparsers = parser.add_subparsers(dest="command", help="Available commands") + + # Setup command (default) + setup_parser = subparsers.add_parser("setup", help="Create a new Django project") + setup_parser.add_argument("--project", help="Django project name") + setup_parser.add_argument("--app", help="Django app name") + + # Secret command + secret_parser = subparsers.add_parser("secret", help="Generate Django secret keys") + secret_parser.add_argument("--count", type=int, default=3, help="Number of keys to generate") + secret_parser.add_argument("--length", type=int, default=50, help="Length of each secret key") + + # App command + app_parser = subparsers.add_parser("app", help="Create a new Django app") + app_parser.add_argument("app_name", help="Name of the Django app to create") + + return parser.parse_args() + + +def handle_secret_command(args: argparse.Namespace) -> None: + try: + from src.scripts.secretkey_generator import display_secret_keys, generate_multiple_keys + + # Generate keys + keys = generate_multiple_keys(args.count, args.length) + + # Display results + UIFormatter.print_info("") + display_secret_keys(keys) + + # Show usage instructions + from rich.panel import Panel + from rich.text import Text + + instructions = Text() + instructions.append("📋 Usage Instructions:\n", style=UIColors.ACCENT) + instructions.append("1. Copy the appropriate secret key for your environment\n") + instructions.append("2. Add it to your .env file:\n") + instructions.append(" SECRET_KEY=your_secret_key_here\n", style=UIColors.CODE) + instructions.append("3. Or set it as an environment variable:\n") + instructions.append(" export SECRET_KEY=your_secret_key_here\n", style=UIColors.CODE) + instructions.append("4. Never commit secret keys to version control!\n", style=UIColors.WARNING) + + console.print(Panel(instructions, title="💡 How to Use", border_style="blue")) + console.print() + + except Exception as e: + UIFormatter.print_error(f"Failed to generate secret keys: {e}") + sys.exit(1) + + +def handle_app_command(args: argparse.Namespace) -> None: + try: + from src.scripts.app_generator import AppManager + + # Display welcome message + UIFormatter.print_info("") + UIFormatter.print_header("Django App Creation") + UIFormatter.print_info("") + + # Validate app name + is_valid, error_msg = validate_app_name(args.app_name) + if not is_valid: + UIFormatter.print_error(error_msg) + sys.exit(1) + + # Create app manager + app_manager = AppManager(args.app_name) + + # Create the app + success = app_manager.create_app() + + if success: + UIFormatter.print_success(f"Django app '{args.app_name}' created successfully!") + + # Show next steps + from rich.panel import Panel + from rich.text import Text + + instructions = Text() + instructions.append("🚀 Next Steps:\n", style=UIColors.ACCENT) + instructions.append("1. The app has been added to INSTALLED_APPS in base.py\n") + instructions.append("2. Create your models in the app's models.py\n") + instructions.append("3. Run migrations: python manage.py makemigrations\n") + instructions.append("4. Apply migrations: python manage.py migrate\n") + instructions.append("5. Create views and URLs for your app\n") + + console.print(Panel(instructions, title="💡 What's Next", border_style="green")) + else: + UIFormatter.print_error(f"Failed to create Django app '{args.app_name}'") + sys.exit(1) + + UIFormatter.print_info("") + + except Exception as e: + UIFormatter.print_error(f"Failed to create Django app: {e}") + sys.exit(1)