From 0df1bf1224034b124d50f1c0c15da733b988672e Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Wed, 29 Oct 2025 11:14:09 +0545 Subject: [PATCH] feat(app_generator): support nested Django app structures and custom app module paths --- src/scripts/app_generator.py | 117 ++++++++++++++++-- src/scripts/command_handler.py | 2 +- yoo/.env.sample | 18 --- yoo/.gitignore | 89 -------------- yoo/Procfile | 20 ---- yoo/README.md | 60 ---------- yoo/apps/__init__.py | 0 yoo/apps/store/__init__.py | 0 yoo/apps/store/admin.py | 3 - yoo/apps/store/apps.py | 6 - yoo/apps/store/migrations/__init__.py | 0 yoo/apps/store/models.py | 3 - yoo/apps/store/routes.py | 16 --- yoo/apps/store/serializers.py | 13 -- yoo/apps/store/tests.py | 3 - yoo/apps/store/urls.py | 9 -- yoo/apps/store/views.py | 3 - yoo/core/__init__.py | 0 yoo/core/asgi.py | 9 -- yoo/core/settings/__init__.py | 0 yoo/core/settings/base.py | 163 -------------------------- yoo/core/settings/development.py | 27 ----- yoo/core/settings/production.py | 43 ------- yoo/core/urls.py | 29 ----- yoo/core/wsgi.py | 9 -- yoo/justfile | 154 ------------------------ yoo/manage.py | 26 ---- yoo/pyproject.toml | 41 ------- yoo/requirements.txt | 10 -- yoo/runtime.txt | 1 - 30 files changed, 109 insertions(+), 765 deletions(-) delete mode 100644 yoo/.env.sample delete mode 100644 yoo/.gitignore delete mode 100644 yoo/Procfile delete mode 100644 yoo/README.md delete mode 100644 yoo/apps/__init__.py delete mode 100644 yoo/apps/store/__init__.py delete mode 100644 yoo/apps/store/admin.py delete mode 100644 yoo/apps/store/apps.py delete mode 100644 yoo/apps/store/migrations/__init__.py delete mode 100644 yoo/apps/store/models.py delete mode 100644 yoo/apps/store/routes.py delete mode 100644 yoo/apps/store/serializers.py delete mode 100644 yoo/apps/store/tests.py delete mode 100644 yoo/apps/store/urls.py delete mode 100644 yoo/apps/store/views.py delete mode 100644 yoo/core/__init__.py delete mode 100644 yoo/core/asgi.py delete mode 100644 yoo/core/settings/__init__.py delete mode 100644 yoo/core/settings/base.py delete mode 100644 yoo/core/settings/development.py delete mode 100644 yoo/core/settings/production.py delete mode 100644 yoo/core/urls.py delete mode 100644 yoo/core/wsgi.py delete mode 100644 yoo/justfile delete mode 100755 yoo/manage.py delete mode 100644 yoo/pyproject.toml delete mode 100644 yoo/requirements.txt delete mode 100644 yoo/runtime.txt diff --git a/src/scripts/app_generator.py b/src/scripts/app_generator.py index 01bb692..8d745ea 100644 --- a/src/scripts/app_generator.py +++ b/src/scripts/app_generator.py @@ -5,11 +5,12 @@ Handles creation of Django apps and updating settings. import os import subprocess +import sys from typing import Optional from src.scripts.console_ui import UIFormatter from src.scripts.template_engine import template_engine -from src.utils import create_file_with_content +from src.utils import change_cwd, create_file_with_content class AppManager: @@ -45,13 +46,42 @@ class AppManager: return os.path.exists(self.manage_py_path) def _app_exists(self) -> bool: - app_path = os.path.join(self.current_dir, self.app_name) + # Detect project structure to check in correct location + is_nested, nested_dir, apps_base_dir = self._detect_project_structure() + app_path = os.path.join(apps_base_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) + # Detect project structure + is_nested, nested_dir, apps_base_dir = self._detect_project_structure() + + # manage.py is always in the project root (current_dir), not in the project directory + manage_py_path = os.path.join(self.current_dir, "manage.py") + if not os.path.exists(manage_py_path): + UIFormatter.print_error("Could not find manage.py file in project root") + return False + + # Create app in the correct location + with change_cwd(apps_base_dir): + UIFormatter.print_info(f"Creating app '{self.app_name}' in directory: {os.getcwd()}") + + try: + # Use django-admin instead of manage.py to avoid dependency issues + result = subprocess.run( + ["django-admin", "startapp", self.app_name], + capture_output=True, + text=True, + check=True + ) + except subprocess.CalledProcessError as e: + UIFormatter.print_error(f"Failed to create app '{self.app_name}': {e}") + if e.stderr: + UIFormatter.print_error(f"Error details: {e.stderr}") + if e.stdout: + UIFormatter.print_info(f"Output: {e.stdout}") + return False - UIFormatter.print_success(f"Created Django app '{self.app_name}'") + UIFormatter.print_success(f"Created Django app '{self.app_name}' in {apps_base_dir}") return True def _add_to_installed_apps(self) -> bool: @@ -65,11 +95,38 @@ class AppManager: UIFormatter.print_error("Could not find base.py settings file") return False + UIFormatter.print_info(f"Found base.py at: {base_settings_path}") + 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") + # Detect project structure to determine the correct app module path + is_nested, nested_dir, apps_base_dir = self._detect_project_structure() + + # Determine the correct module path for the app + if is_nested and nested_dir: + app_module_path = f"{nested_dir}.{self.app_name}" + else: + app_module_path = self.app_name + + UIFormatter.print_info(f"App module path: {app_module_path}") + + # Check if app is already in USER_DEFINED_APPS section specifically + lines = content.split("\n") + in_user_apps = False + app_already_exists = False + + for line in lines: + if "USER_DEFINED_APPS" in line and "=" in line: + in_user_apps = True + elif in_user_apps and line.strip() == "]": + in_user_apps = False + elif in_user_apps and (f'"{app_module_path}"' in line or f"'{app_module_path}'" in line): + app_already_exists = True + break + + if app_already_exists: + UIFormatter.print_info(f"App '{app_module_path}' is already in USER_DEFINED_APPS") return True if "USER_DEFINED_APPS" not in content: @@ -86,7 +143,7 @@ class AppManager: 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(f' "{app_module_path}",') new_lines.append(line) in_user_apps = False apps_added = True @@ -100,7 +157,7 @@ class AppManager: 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") + UIFormatter.print_success(f"Added '{app_module_path}' to USER_DEFINED_APPS in base.py") return True def _find_settings_path(self) -> Optional[str]: @@ -122,9 +179,51 @@ class AppManager: return None + def _detect_project_structure(self) -> tuple[bool, Optional[str], str]: + """ + Detect if the project uses nested apps and return the structure info. + + Returns: + tuple: (is_nested, nested_dir, apps_base_dir) + """ + # 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")): + # Found the project directory, now check for nested apps + project_name = item + + # Look for common nested app directories + for nested_dir in ["apps", "modules", "packages"]: + nested_path = os.path.join(self.current_dir, nested_dir) + if os.path.exists(nested_path) and os.path.isdir(nested_path): + # Check if there are any Django apps in this directory + for app_item in os.listdir(nested_path): + app_path = os.path.join(nested_path, app_item) + if os.path.isdir(app_path) and os.path.exists(os.path.join(app_path, "apps.py")): + # Found nested apps structure + return True, nested_dir, nested_path + + # No nested structure found + return False, None, self.current_dir + + # Fallback: check 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 False, None, self.current_dir + + return False, None, self.current_dir + def _create_additional_files(self) -> bool: """Create additional files for the app (serializers.py, routes.py).""" - app_path = os.path.join(self.current_dir, self.app_name) + # Detect project structure to get correct app path + is_nested, nested_dir, apps_base_dir = self._detect_project_structure() + app_path = os.path.join(apps_base_dir, self.app_name) # Create serializers.py context = {"app_name": self.app_name} diff --git a/src/scripts/command_handler.py b/src/scripts/command_handler.py index 9c5d7d6..8a82540 100644 --- a/src/scripts/command_handler.py +++ b/src/scripts/command_handler.py @@ -98,7 +98,7 @@ def handle_app_command(args: argparse.Namespace) -> None: 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") + instructions.append("5. Create views, serializers and routes(URLs) for your app\n") console.print(Panel(instructions, title="💡 What's Next", border_style="green")) else: diff --git a/yoo/.env.sample b/yoo/.env.sample deleted file mode 100644 index 281b616..0000000 --- a/yoo/.env.sample +++ /dev/null @@ -1,18 +0,0 @@ -# Django settings -DJANGO_SETTINGS_MODULE=core.settings.development -SECRET_KEY= your-secret-key -ALLOWED_HOSTS=api.your-domain.com,www.your-domain.com - -# Database (individual parameters) -DB_NAME= -DB_USER= -DB_PASSWORD= -DB_HOST= -DB_PORT= - -# Email settings -EMAIL_HOST= -EMAIL_PORT= -EMAIL_USE_TLS= -EMAIL_HOST_USER= -EMAIL_HOST_PASSWORD= \ No newline at end of file diff --git a/yoo/.gitignore b/yoo/.gitignore deleted file mode 100644 index 51c5a35..0000000 --- a/yoo/.gitignore +++ /dev/null @@ -1,89 +0,0 @@ -# Python -*.py[cod] -*$py.class -*.so -__pycache__/ -*.egg-info/ -dist/ -build/ -.eggs/ -*.egg - -# Django -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal -*.sqlite3 - -# Environment -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# IDEs -.vscode/ -.idea/ -*.swp -*.swo -*~ -.project -.pydevproject -.settings/ -.ropeproject/ - -# OS -.DS_Store -*.DS_Store -Thumbs.db -desktop.ini - -# Django specific -media/ -staticfiles/ -staticfiles/ -static_root/ -/static/ - -# Testing -.coverage -htmlcov/ -.pytest_cache/ -.tox/ -coverage.xml -*.cover -.hypothesis/ -.cache - -# Logs -logs/ -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Node modules (if using frontend tools) -node_modules/ - -# Secret keys -secret.txt -secrets.json - -# Jupyter Notebook -.ipynb_checkpoints - -# Backup files -*.bak -*.tmp -*~ - -# Database -*.db -*.sql - -# Cloud -.cloud diff --git a/yoo/Procfile b/yoo/Procfile deleted file mode 100644 index 51f48af..0000000 --- a/yoo/Procfile +++ /dev/null @@ -1,20 +0,0 @@ -# Procfile for core -# Used for deploying to PaaS platforms like Heroku, Railway, Render, etc. - -# Web server process (using Gunicorn) -# Adjust workers based on your needs: (2 x CPU cores) + 1 -web: gunicorn core.wsgi:application --bind 0.0.0.0:$PORT --workers 2 --timeout 120 --access-logfile - --error-logfile - --log-level info - -# Alternative web server configurations (uncomment to use): -# web: gunicorn core.wsgi:application --bind 0.0.0.0:$PORT --workers 4 --threads 2 --timeout 120 -# web: gunicorn core.wsgi:application --bind 0.0.0.0:$PORT --workers 2 --worker-class gevent --worker-connections 1000 --timeout 120 - -# Release task (runs migrations before deployment) -release: python manage.py migrate --noinput && python manage.py collectstatic --noinput - -# Uncomment below to run scheduled tasks (if using Celery) -# worker: celery -A core worker --loglevel=info -# beat: celery -A core beat --loglevel=info - -# Development server (for local testing with Foreman/Overmind) -# web: python manage.py runserver 0.0.0.0:$PORT diff --git a/yoo/README.md b/yoo/README.md deleted file mode 100644 index 1699752..0000000 --- a/yoo/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# core - -A Django project created with django-setup. - -## Features - -- Modern project structure with environment-specific settings -- Pre-configured REST API with JWT authentication -- Essential dependencies and utilities -- Production-ready configuration - -## Setup - -1. Install dependencies: - ```bash - pip install -r requirements.txt - ``` - -2. Set environment variables in `.env` file - -3. Run migrations: - ```bash - python manage.py migrate - ``` - -4. Create superuser: - ```bash - python manage.py createsuperuser - ``` - -5. Start development server: - ```bash - python manage.py runserver - ``` - -## Project Structure - -``` -core/ -├── core/ -│ ├── settings/ -│ │ ├── base.py -│ │ ├── development.py -│ │ └── production.py -│ ├── urls.py -│ ├── wsgi.py -│ └── asgi.py -├── store/ -├── manage.py -├── requirements.txt -├── pyproject.toml -├── .env.sample -└── README.md -``` - -## API Documentation - -When running in development mode, API documentation is available at: -- Swagger UI: http://localhost:8000/docs/ -- Schema: http://localhost:8000/schema/ diff --git a/yoo/apps/__init__.py b/yoo/apps/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/yoo/apps/store/__init__.py b/yoo/apps/store/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/yoo/apps/store/admin.py b/yoo/apps/store/admin.py deleted file mode 100644 index 8c38f3f..0000000 --- a/yoo/apps/store/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/yoo/apps/store/apps.py b/yoo/apps/store/apps.py deleted file mode 100644 index 1a5be03..0000000 --- a/yoo/apps/store/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class StoreConfig(AppConfig): - default_auto_field = "django.db.models.BigAutoField" - name = "store" diff --git a/yoo/apps/store/migrations/__init__.py b/yoo/apps/store/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/yoo/apps/store/models.py b/yoo/apps/store/models.py deleted file mode 100644 index 71a8362..0000000 --- a/yoo/apps/store/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/yoo/apps/store/routes.py b/yoo/apps/store/routes.py deleted file mode 100644 index 276d801..0000000 --- a/yoo/apps/store/routes.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -API routes for store app. -""" - -from rest_framework.routers import DefaultRouter -from . import views - -# Create router instance -router = DefaultRouter() - -# Register viewsets with router -# Example: -# router.register(r'store', views.StoreViewSet) - -# Get URL patterns -urlpatterns = router.urls diff --git a/yoo/apps/store/serializers.py b/yoo/apps/store/serializers.py deleted file mode 100644 index 85ffff9..0000000 --- a/yoo/apps/store/serializers.py +++ /dev/null @@ -1,13 +0,0 @@ -""" -Serializers for store app. -""" - -from rest_framework import serializers - - -# Add your serializers here -# Example: -# class StoreSerializer(serializers.ModelSerializer): -# class Meta: -# model = YourModel -# fields = '__all__' diff --git a/yoo/apps/store/tests.py b/yoo/apps/store/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/yoo/apps/store/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/yoo/apps/store/urls.py b/yoo/apps/store/urls.py deleted file mode 100644 index 2b978dc..0000000 --- a/yoo/apps/store/urls.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.urls import path -from . import views - -app_name = "store" - -urlpatterns = [ - # Add your URL patterns here - # path('', views.index, name='index'), -] diff --git a/yoo/apps/store/views.py b/yoo/apps/store/views.py deleted file mode 100644 index 91ea44a..0000000 --- a/yoo/apps/store/views.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.shortcuts import render - -# Create your views here. diff --git a/yoo/core/__init__.py b/yoo/core/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/yoo/core/asgi.py b/yoo/core/asgi.py deleted file mode 100644 index 6380cd7..0000000 --- a/yoo/core/asgi.py +++ /dev/null @@ -1,9 +0,0 @@ -import os -from dotenv import load_dotenv -from django.core.asgi import get_asgi_application - -load_dotenv() - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", os.getenv("DJANGO_SETTINGS_MODULE")) - -application = get_asgi_application() diff --git a/yoo/core/settings/__init__.py b/yoo/core/settings/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/yoo/core/settings/base.py b/yoo/core/settings/base.py deleted file mode 100644 index 014c4a2..0000000 --- a/yoo/core/settings/base.py +++ /dev/null @@ -1,163 +0,0 @@ -""" -Common settings shared between development and production environment -""" - -import os -from datetime import timedelta -from pathlib import Path - -from dotenv import load_dotenv - -load_dotenv() - -# Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent.parent - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/ - - -# Application definition -THIRD_PARTY_APPS = [ - "rest_framework", - "rest_framework_simplejwt", - "rest_framework_simplejwt.token_blacklist", - "corsheaders", - "drf_spectacular", -] - -USER_DEFINED_APPS = [ - "apps.store", - "account", -] - -BUILT_IN_APPS = [ - "django.contrib.admin", - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.staticfiles", -] - -INSTALLED_APPS = BUILT_IN_APPS + THIRD_PARTY_APPS + USER_DEFINED_APPS -INSTALLED_APPS.insert(0, "jazzmin") - -MIDDLEWARE = [ - "corsheaders.middleware.CorsMiddleware", - "django.middleware.security.SecurityMiddleware", - "whitenoise.middleware.WhiteNoiseMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", - "django.contrib.messages.middleware.MessageMiddleware", - "django.middleware.clickjacking.XFrameOptionsMiddleware", - "account", -] - -ROOT_URLCONF = "core.urls" - -TEMPLATES = [ - { - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [], - "APP_DIRS": True, - "OPTIONS": { - "context_processors": [ - "django.template.context_processors.request", - "django.contrib.auth.context_processors.auth", - "django.contrib.messages.context_processors.messages", - ], - }, - }, -] - -WSGI_APPLICATION = "core.wsgi.application" - - -# Password validation -# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/5.2/topics/i18n/ - -LANGUAGE_CODE = "en-us" -TIME_ZONE = "UTC" -USE_I18N = True -USE_TZ = True - -# Static files and media files -STATIC_URL = "static/" -STATIC_ROOT = BASE_DIR / "staticfiles" - -MEDIA_URL = "media/" -MEDIA_ROOT = BASE_DIR / "media" - -STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" - -DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" - -# REST Framework Settings -REST_FRAMEWORK = { - "DEFAULT_RENDERER_CLASSES": [ - "rest_framework.renderers.JSONRenderer", - ], - "DEFAULT_PARSER_CLASSES": [ - "rest_framework.parsers.JSONParser", - ], - "DEFAULT_AUTHENTICATION_CLASSES": ( - "rest_framework_simplejwt.authentication.JWTAuthentication", - "rest_framework.authentication.SessionAuthentication", - ), - "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", - "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination", - "PAGE_SIZE": 20, -} - -# DRF Spectacular settings -SPECTACULAR_SETTINGS = { - "TITLE": "core API", - "DESCRIPTION": "API documentation for core", - "VERSION": "1.0.0", - "SERVE_INCLUDE_SCHEMA": False, - "COMPONENT_SPLIT_REQUEST": True, - "SCHEMA_PATH_PREFIX": "/api/", -} - -# JWT Settings -SIMPLE_JWT = { - "ACCESS_TOKEN_LIFETIME": timedelta(days=1), - "REFRESH_TOKEN_LIFETIME": timedelta(days=3), - "ROTATE_REFRESH_TOKENS": True, - "BLACKLIST_AFTER_ROTATION": True, -} - -# CORS Settings -CORS_ALLOWED_ORIGINS = [ - "http://localhost:3000", - "http://127.0.0.1:3000", -] - -CORS_ALLOW_CREDENTIALS = True - -# Security Settings -SECURE_BROWSER_XSS_FILTER = True -SECURE_CONTENT_TYPE_NOSNIFF = True -X_FRAME_OPTIONS = "DENY" diff --git a/yoo/core/settings/development.py b/yoo/core/settings/development.py deleted file mode 100644 index 02cde63..0000000 --- a/yoo/core/settings/development.py +++ /dev/null @@ -1,27 +0,0 @@ -from .base import * - -SECRET_KEY = "+#JJBTL^S&N7FOYi8_WM$*(BvxD6VqB7JnLCvgO_4f9yN$FJP8" - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = ["*"] - -# Database -# https://docs.djangoproject.com/en/5.2/ref/settings/#databases - -DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", - } -} - -# Email backend for development -EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" - -# CORS settings for development -CORS_ALLOW_ALL_ORIGINS = True - -# Disable HTTPS redirect in development -SECURE_SSL_REDIRECT = False diff --git a/yoo/core/settings/production.py b/yoo/core/settings/production.py deleted file mode 100644 index 05fcfbd..0000000 --- a/yoo/core/settings/production.py +++ /dev/null @@ -1,43 +0,0 @@ -from .base import * -import os -import dj_database_url - -DEBUG = False -SECRET_KEY = os.getenv("SECRET_KEY") -ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "").split(",") - -# Database -# Using individual database parameters -DATABASES = { - "default": { - "ENGINE": "django.db.backends.postgresql", - "NAME": os.getenv("DB_NAME"), - "USER": os.getenv("DB_USER"), - "PASSWORD": os.getenv("DB_PASSWORD"), - "HOST": os.getenv("DB_HOST"), - "PORT": os.getenv("DB_PORT"), - } -} - - -# Email settings -EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" -EMAIL_HOST = os.getenv("EMAIL_HOST") -EMAIL_PORT = int(os.getenv("EMAIL_PORT", 587)) -EMAIL_USE_TLS = os.getenv("EMAIL_USE_TLS", "True").lower() == "true" -EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER") -EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD") - -# Security settings for production -SECURE_SSL_REDIRECT = True -SECURE_HSTS_SECONDS = 31536000 -SECURE_HSTS_INCLUDE_SUBDOMAINS = True -SECURE_HSTS_PRELOAD = True -SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") - -# Session settings -SESSION_COOKIE_SECURE = True -CSRF_COOKIE_SECURE = True - -# Static files -STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" diff --git a/yoo/core/urls.py b/yoo/core/urls.py deleted file mode 100644 index a9ad054..0000000 --- a/yoo/core/urls.py +++ /dev/null @@ -1,29 +0,0 @@ -from django.contrib import admin -from django.urls import path, include -from django.conf import settings -from drf_spectacular.views import ( - SpectacularAPIView, - SpectacularSwaggerView, -) -from rest_framework_simplejwt.views import ( - TokenObtainPairView, - TokenRefreshView, - TokenBlacklistView, -) - -urlpatterns = [ - path("admin/", admin.site.urls), - # JWT tokens - path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), - path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), - path("token/blacklist/", TokenBlacklistView.as_view(), name="token_blacklist"), - # App URLs - path("", include("apps.store.urls")), -] - -# Don't show schema in production -if settings.DEBUG: - urlpatterns += [ - path("schema/", SpectacularAPIView.as_view(), name="schema"), - path("docs/", SpectacularSwaggerView.as_view(url_name="schema")), - ] diff --git a/yoo/core/wsgi.py b/yoo/core/wsgi.py deleted file mode 100644 index d414bb0..0000000 --- a/yoo/core/wsgi.py +++ /dev/null @@ -1,9 +0,0 @@ -import os -from dotenv import load_dotenv -from django.core.wsgi import get_wsgi_application - -load_dotenv() - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", os.getenv("DJANGO_SETTINGS_MODULE")) - -application = get_wsgi_application() diff --git a/yoo/justfile b/yoo/justfile deleted file mode 100644 index a3e7127..0000000 --- a/yoo/justfile +++ /dev/null @@ -1,154 +0,0 @@ -# Justfile for core -# Task runner for Django development -# Install just: https://github.com/casey/just - -# Default task: show available commands -default: - @just --list - -# Run development server -dev: - uv run python manage.py runserver - -# Run development server with custom host and port -dev-server HOST="0.0.0.0" PORT="8000": - uv run python manage.py runserver : - -# Create migrations for all apps -makemigrations: - uv run python manage.py makemigrations - -# Create migrations for specific app -makemigrations-app APP: - uv run python manage.py makemigrations - -# Run all migrations -migrate: - uv run python manage.py migrate - -# Reset database (delete all migrations) -reset-db: - uv run python manage.py flush --noinput - uv run python manage.py migrate - -# Create superuser -createsuperuser: - uv run python manage.py createsuperuser - -# Collect static files -collectstatic: - uv run python manage.py collectstatic --noinput - -# Run Django shell -shell: - uv run python manage.py shell - -# Run Django shell plus (IPython) -shell-plus: - uv run python manage.py shell_plus - -# Run tests -test: - uv run python manage.py test - -# Run tests with coverage -test-coverage: - uv run pytest --cov=. --cov-report=html --cov-report=term - -# Lint code with ruff -lint: - uv run ruff check . - -# Format code with ruff -format: - uv run ruff format . - -# Lint and format code -style: - uv run ruff check . - uv run ruff format . - -# Check security issues -check: - uv run python manage.py check - -# Check security issues (production settings) -check-deploy: - uv run python manage.py check --deploy - -# Show all database migrations status -showmigrations: - uv run python manage.py showmigrations - -# Sync dependencies (uv equivalent of pip freeze) -requirements: - uv pip compile - -# Run all linting and checks -ci: - uv run ruff check . - uv run ruff format --check . - uv run python manage.py check - -# Start interactive shell -shell-ipython: - uv run python manage.py shell_plus - -# Clear all cache -clear-cache: - uv run python manage.py clear_cache - -# Show Django version -version: - uv run python manage.py version - -# Run database shell -dbshell: - uv run python manage.py dbshell - -# Start production server with gunicorn -server: - uv run gunicorn core.wsgi:application --bind 0.0.0.0:8000 - -# Start production server with gunicorn workers -server-prod WORKERS="4": - uv run gunicorn core.wsgi:application --bind 0.0.0.0:8000 --workers - -# Start production server with gunicorn and reload on file changes -server-watch: - uv run gunicorn core.wsgi:application --bind 0.0.0.0:8000 --reload - -# Clean Python cache files -clean: - find . -type d -name "__pycache__" -exec rm -rf {} + - find . -type f -name "*.pyc" -delete - find . -type f -name "*.pyo" -delete - find . -type f -name ".coverage" -delete - find . -type d -name "*.egg-info" -exec rm -rf {} + - rm -rf htmlcov/ - rm -rf .pytest_cache/ - -# Setup project for development (using uv) -setup: - uv sync - uv run python manage.py migrate - uv run python manage.py createsuperuser - -# Complete setup including static files -setup-complete: - uv sync - uv run python manage.py migrate - uv run python manage.py collectstatic --noinput - uv run python manage.py createsuperuser - -# Install a new package -install PACKAGE: - uv add - -# Install a dev package -install-dev PACKAGE: - uv add --dev - -# Remove a package -remove PACKAGE: - uv remove diff --git a/yoo/manage.py b/yoo/manage.py deleted file mode 100755 index ff307fd..0000000 --- a/yoo/manage.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -"""Django's command-line utility for administrative tasks.""" - -import os -import sys -from dotenv import load_dotenv - - -def main(): - """Run administrative tasks.""" - os.environ.setdefault("DJANGO_SETTINGS_MODULE", os.getenv("DJANGO_SETTINGS_MODULE")) - - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) - - -if __name__ == "__main__": - load_dotenv() - main() diff --git a/yoo/pyproject.toml b/yoo/pyproject.toml deleted file mode 100644 index d4031ea..0000000 --- a/yoo/pyproject.toml +++ /dev/null @@ -1,41 +0,0 @@ -[project] -name = "yoo" -version = "0.1.0" -description = "" -readme = "README.md" -requires-python = ">=3.13" -license = { text = "MIT" } -dependencies = [ - "django>=5.2.7", - "python-dotenv>=1.1.1", - "django-jazzmin>=3.0.1", - "djangorestframework>=3.16.1", - "djangorestframework-simplejwt>=5.5.1", - "drf-spectacular>=0.28.0", - "django-cors-headers>=4.9.0", - "whitenoise>=6.8.2", - "psycopg2-binary>=2.9.9", - "gunicorn>=21.2.0", -] - -[tool.ruff] -line-length = 88 -target-version = "py38" - -[tool.ruff.lint] -select = [ - "E", # pycodestyle errors - "W", # pycodestyle warnings - "F", # pyflakes - "I", # isort - "B", # flake8-bugbear - "C4", # flake8-comprehensions - "UP", # pyupgrade -] -ignore = [ - "E501", # line too long, handled by formatter - "B008", # do not perform function calls in argument defaults -] - -[tool.ruff.lint.isort] -known-first-party = ["core"] diff --git a/yoo/requirements.txt b/yoo/requirements.txt deleted file mode 100644 index 6bdaa52..0000000 --- a/yoo/requirements.txt +++ /dev/null @@ -1,10 +0,0 @@ -Django -python-dotenv -django-jazzmin> -djangorestframework -djangorestframework_simplejwt -drf-spectacular -django-cors-headers -whitenoise -psycopg2-binary -gunicorn diff --git a/yoo/runtime.txt b/yoo/runtime.txt deleted file mode 100644 index e912aa6..0000000 --- a/yoo/runtime.txt +++ /dev/null @@ -1 +0,0 @@ -python-3.13