Browse Source

Add subdomain routing middleware and admin URL configuration

- Implemented SubdomainRoutingMiddleware to route requests based on subdomains.
- Created urls_admin.py for handling admin-related URLs and Swagger documentation.
- Updated base settings to include the new middleware for subdomain handling.
master
mortezaei 4 months ago
parent
commit
0ead18e9f1
  1. 2
      config/settings/base.py
  2. 106
      config/subdomain_middleware.py
  3. 62
      config/urls_admin.py

2
config/settings/base.py

@ -119,6 +119,8 @@ MIDDLEWARE = [
"whitenoise.middleware.WhiteNoiseMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
# Subdomain routing - must be before LocaleMiddleware
'config.subdomain_middleware.SubdomainRoutingMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',

106
config/subdomain_middleware.py

@ -0,0 +1,106 @@
"""
Subdomain Routing Middleware
Routes requests to different URL configurations based on the subdomain.
This allows clean separation of admin, API, and docs URLs.
Subdomains:
- admin.imamjavad.nwhco.ir config.urls_admin
- api.imamjavad.nwhco.ir config.urls_api
- docs.imamjavad.nwhco.ir config.urls_docs
- imamjavad.nwhco.ir config.urls (main/frontend)
"""
from django.utils.deprecation import MiddlewareMixin
from django.conf import settings
class SubdomainRoutingMiddleware(MiddlewareMixin):
"""
Middleware that sets the ROOT_URLCONF based on the request's subdomain.
"""
# Mapping of subdomain prefixes to URL configurations
SUBDOMAIN_URLCONFS = {
'admin': 'config.urls_admin', # Admin + Swagger/Redoc
}
# List of main domains (without subdomain routing)
MAIN_DOMAINS = [
'imamjavad.nwhco.ir',
'imamjavad.newhorizonco.uk',
'dovoodi.nwhco.ir',
'dovodi.newhorizonco.uk',
'localhost',
'127.0.0.1',
]
def process_request(self, request):
"""
Determine the subdomain and set the appropriate ROOT_URLCONF.
"""
# Get host from request (handles X-Forwarded-Host for proxied requests)
host = request.get_host().split(':')[0].lower()
# Check if this is a subdomain request
subdomain = self._extract_subdomain(host)
if subdomain and subdomain in self.SUBDOMAIN_URLCONFS:
# Set the URL configuration for this subdomain
request.urlconf = self.SUBDOMAIN_URLCONFS[subdomain]
# Store subdomain info for potential use in views
request.subdomain = subdomain
else:
# Use default URL configuration
request.subdomain = None
return None
def _extract_subdomain(self, host):
"""
Extract the subdomain from the host.
Examples:
- admin.imamjavad.nwhco.ir 'admin'
- api.imamjavad.nwhco.ir 'api'
- imamjavad.nwhco.ir None
"""
# Check against main domains
for main_domain in self.MAIN_DOMAINS:
if host == main_domain:
return None
# Check if host is a subdomain of a main domain
if host.endswith('.' + main_domain):
# Extract subdomain part
subdomain = host[:-len('.' + main_domain)]
# Only return first-level subdomain
if '.' not in subdomain:
return subdomain
# Also check against ALLOWED_HOSTS for flexibility
for allowed_host in getattr(settings, 'ALLOWED_HOSTS', []):
if allowed_host.startswith('.'):
# Wildcard domain like .nwhco.ir
base_domain = allowed_host[1:]
if host.endswith(base_domain) and host != base_domain:
subdomain = host[:-len(base_domain)].rstrip('.')
if '.' not in subdomain:
return subdomain
return None
def get_subdomain(request):
"""
Utility function to get the current subdomain from request.
Can be used in views or templates.
"""
return getattr(request, 'subdomain', None)
def is_admin_subdomain(request):
"""Check if current request is on admin subdomain."""
return get_subdomain(request) == 'admin'

62
config/urls_admin.py

@ -0,0 +1,62 @@
"""
URL configuration for Admin Subdomain (admin.imamjavad.nwhco.ir)
This handles all admin-related URLs and Swagger/Redoc when accessed via the admin subdomain.
"""
from django.urls import path, include, re_path
from django.conf import settings
from django.conf.urls.static import static
from django.conf.urls.i18n import i18n_patterns
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from utils.admin import project_admin_site, dovoodi_admin_site, HomeView
from apps.api.views import CustomAPIDocumentationView, CustomSwaggerView, SwaggerTokenAuthView, clear_swagger_auth
from apps.api.permissions import IsAdminOrSwaggerToken
from apps.api.decorators import swagger_auth_required
# Schema view for documentation
schema_view = get_schema_view(
openapi.Info(
title="Imam Javad API",
default_version='v1',
description="Comprehensive API documentation for the Imam Javad educational platform",
contact=openapi.Contact(email="contact@imamjavad.com"),
license=openapi.License(name="MIT License"),
),
public=False,
permission_classes=(IsAdminOrSwaggerToken,),
)
# Swagger URL patterns
swagger_urlpatterns = [
path('swagger-auth/', SwaggerTokenAuthView.as_view(), name='swagger-token-auth'),
path('swagger-auth/clear/', clear_swagger_auth, name='clear-swagger-auth'),
re_path(r'^swagger(?P<format>\.json|\.yaml)$',
swagger_auth_required(schema_view.without_ui(cache_timeout=0)),
name='schema-json'),
path('swagger/', CustomSwaggerView.as_view(), name='schema-swagger-ui'),
re_path(r'^redoc/$',
swagger_auth_required(schema_view.with_ui('redoc', cache_timeout=0)),
name='schema-redoc'),
]
urlpatterns = [
# Root redirect to admin
path("", HomeView.as_view(), name="home"),
path("i18n/", include("django.conf.urls.i18n")),
path('filer/', include('filer.urls')),
]
# i18n admin + swagger patterns
urlpatterns += i18n_patterns(
path("imam-javad/admin/", project_admin_site.urls),
path("dovoodi/admin/", dovoodi_admin_site.urls),
path('docs/', CustomAPIDocumentationView.as_view(), name='docs-index'),
*swagger_urlpatterns,
path('filer/', include('filer.urls')),
)
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Loading…
Cancel
Save