From 06ea5d2945f311f9ebb347c85bafe5fb794274c7 Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Wed, 27 May 2026 23:33:10 +0545 Subject: [PATCH] =?UTF-8?q?feat(config):=20streamline=20configuration=20an?= =?UTF-8?q?d=20remove=20dev=E2=80=91only=20settingsAdd=20custom=20user=20m?= =?UTF-8?q?odel=20and=20improve=20static/media=20handling.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New Features - Introduce `AUTH_USER_MODEL` for a custom user. - Add `STATICFILES_DIRS` to explicitly point to the static directory. - Simplify email backend configuration using environment variables. - Enhancements - Remove djinit boilerplate and development‑only settings. - Drop `corsheaders` middleware and `rest_framework_simplejwt.token_blacklist`. - Update `TEMPLATES` to include project templates via `BASE_DIR / "templates"`. - Clean up URL patterns, removing deprecated JWT endpoint comments. - Reorganize security settings and static storage configuration. - Bug Fixes - (none) --- config/settings/base.py | 121 ++++----------------------------- config/settings/development.py | 20 +----- config/settings/production.py | 52 ++++---------- config/urls.py | 29 +------- 4 files changed, 30 insertions(+), 192 deletions(-) diff --git a/config/settings/base.py b/config/settings/base.py index 9740791..a3b040b 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -1,10 +1,3 @@ -""" -generated with djinit -Common settings shared between development and production environment -""" - -import os -from datetime import timedelta from pathlib import Path import environ @@ -12,20 +5,9 @@ import environ env = environ.Env() environ.Env.read_env() -# 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", "django_tailwind_cli", "django_htmx", ] @@ -53,7 +35,6 @@ 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", @@ -70,7 +51,7 @@ ROOT_URLCONF = "config.urls" TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [], + "DIRS": [BASE_DIR / "templates"], "APP_DIRS": True, "OPTIONS": { "context_processors": [ @@ -84,117 +65,41 @@ TEMPLATES = [ WSGI_APPLICATION = "config.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", - }, + {"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" +STATICFILES_DIRS = [BASE_DIR / "static/"] MEDIA_URL = "/media/" MEDIA_ROOT = BASE_DIR / "media" STORAGES = { - "default": { - "BACKEND": "django.core.files.storage.FileSystemStorage", - }, - "staticfiles": { - "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage", - }, + "default": {"BACKEND": "django.core.files.storage.FileSystemStorage"}, + "staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"}, } +AUTH_USER_MODEL = "accounts.CustomUser" 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, -} +LOGIN_URL = "/accounts/login/" +LOGIN_REDIRECT_URL = "/" +LOGOUT_REDIRECT_URL = "/accounts/login/" -# DRF Spectacular settings -SPECTACULAR_SETTINGS = { - "TITLE": "config API", - "DESCRIPTION": "API documentation for config", - "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_ALLOW_METHODS = [ - "DELETE", - "GET", - "OPTIONS", - "PATCH", - "POST", - "PUT", -] - -CORS_ALLOW_HEADERS = [ - "accept", - "accept-encoding", - "authorization", - "content-type", - "dnt", - "origin", - "user-agent", - "x-csrftoken", - "x-requested-with", -] - -CORS_PREFLIGHT_MAX_AGE = 86400 # 24 hours -# Security Settings SECURE_BROWSER_XSS_FILTER = True SECURE_CONTENT_TYPE_NOSNIFF = True X_FRAME_OPTIONS = "DENY" -# for tailwind -STATICFILES_DIRS = [BASE_DIR / "static/"] TAILWIND_CLI_VERSION = "2.7.8" TAILWIND_CLI_USE_DAISY_UI = True TAILWIND_CLI_CONFIG = { @@ -226,4 +131,4 @@ TAILWIND_CLI_CONFIG = { } ] }, -} \ No newline at end of file +} diff --git a/config/settings/development.py b/config/settings/development.py index 70305ce..569e13b 100644 --- a/config/settings/development.py +++ b/config/settings/development.py @@ -1,24 +1,16 @@ -"""generated with djinit""" - from .base import * SECRET_KEY = "o$62pY2y3M3&!YtUG*857JA=*svOdaVFf+%veG@XZkmfD0GOm$" - -# 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", "OPTIONS": { "transaction_mode": "IMMEDIATE", - "timeout": 5, # seconds + "timeout": 5, "init_command": """ PRAGMA journal_mode=WAL; PRAGMA synchronous=NORMAL; @@ -30,13 +22,5 @@ DATABASES = { } } -# Email backend for development EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" - -# CORS settings for development -# Allow all origins in development (convenient but not secure) -CORS_ALLOW_ALL_ORIGINS = True -CORS_ALLOW_CREDENTIALS = True - -# Disable HTTPS redirect in development -SECURE_SSL_REDIRECT = False \ No newline at end of file +SECURE_SSL_REDIRECT = False diff --git a/config/settings/production.py b/config/settings/production.py index a3af9dc..0f055bb 100644 --- a/config/settings/production.py +++ b/config/settings/production.py @@ -1,51 +1,25 @@ -"""generated with djinit""" - from .base import * -import dj_database_url DEBUG = False -SECRET_KEY = env('SECRET_KEY') -ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[]) +SECRET_KEY = env("SECRET_KEY") +ALLOWED_HOSTS = env.list("ALLOWED_HOSTS", default=[]) +DATABASES = {"default": env.db("DATABASE_URL")} -# Database -# Using dj_database_url (recommended for production) -DATABASES = { - 'default': env.db('DATABASE_URL') -} +EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" +EMAIL_HOST = env("EMAIL_HOST", default="smtp.gmail.com") +EMAIL_PORT = env.int("EMAIL_PORT", default=587) +EMAIL_USE_TLS = env.bool("EMAIL_USE_TLS", default=True) +EMAIL_HOST_USER = env("EMAIL_HOST_USER", default="") +EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD", default="") +DEFAULT_FROM_EMAIL = env("EMAIL_HOST_USER", default="") +SERVER_EMAIL = env("EMAIL_HOST_USER", default="") -# CORS settings for production -# Filter out empty strings from FRONTEND_URL -CORS_ALLOWED_ORIGINS = env.list('FRONTEND_URL', default=[]) -CORS_ALLOW_CREDENTIALS = True - -# Additional CORS security for production -CORS_ALLOW_PRIVATE_NETWORK = False - -# Email settings -EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' -EMAIL_HOST = env('EMAIL_HOST', default="smtp.gmail.com") -EMAIL_PORT = env.int('EMAIL_PORT', default=587) -EMAIL_USE_TLS = env.bool('EMAIL_USE_TLS', default=True) -EMAIL_HOST_USER = env('EMAIL_HOST_USER', default="") -EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD', default="") -DEFAULT_FROM_EMAIL = env('EMAIL_HOST_USER', default="") -SERVER_EMAIL = env('EMAIL_HOST_USER', default="") - -# 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 +SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True -# Static files -STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' - -## Tailwind -TAILWIND_CLI_VERSION = "4.1.3" # Pin version -TAILWIND_CLI_AUTOMATIC_DOWNLOAD = False # Use pre-installed CLI -TAILWIND_CLI_DIST_CSS = "static/css/tailwind.min.css" \ No newline at end of file +STORAGES["staticfiles"]["BACKEND"] = "whitenoise.storage.CompressedManifestStaticFilesStorage" diff --git a/config/urls.py b/config/urls.py index 64bd3c3..6a055ba 100644 --- a/config/urls.py +++ b/config/urls.py @@ -1,38 +1,13 @@ -"""generated with djinit""" - from django.contrib import admin -from django.urls import path -from django.urls import include -from django.conf import settings -from drf_spectacular.views import ( - SpectacularAPIView, - SpectacularSwaggerView, -) -from rest_framework_simplejwt.views import ( - TokenObtainPairView, - TokenRefreshView, - TokenBlacklistView, -) +from django.urls import include, path 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.accounts.urls")), path("", include("apps.projects.urls")), - path("", include("apps.finance.urls")), path("", include("apps.kanban.urls")), path("", include("apps.issues.urls")), path("", include("apps.tickets.urls")), + path("", include("apps.finance.urls")), path("", include("apps.activity.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")), - ] \ No newline at end of file