3 Commits

Author SHA1 Message Date
Oliver Falk
87f4e45afa Merge branch 'devel' into 'master'
🚀 Major Release: ivatar 2.0 - Performance, Security, and Instrumentation Overhaul

Closes #106, #104, and #102

See merge request oliver/ivatar!281
2025-10-31 16:40:58 +01:00
Oliver Falk
64967c07ad Fix ImproperlyConfigured error when accessing settings before Django config
Handle case where Django settings are not yet configured when
OpenTelemetry setup is called. This occurs when importing ivatar.utils
from standalone scripts like performance_tests.py before Django
settings are initialized.

The fix wraps settings access in try-except to catch ImproperlyConfigured
exceptions and falls back to default value when settings aren't available.
2025-10-31 16:38:34 +01:00
Oliver Falk
c2cbe14b0d Fix CI import error: use proper Django settings pattern for version access
- Fix OpenTelemetry config to use getattr(settings, 'IVATAR_VERSION') without hardcoded fallback
- Fix context processors to use Django settings pattern instead of direct imports
- Remove hardcoded version defaults to ensure version always comes from config
- Resolves ImportError in CI where direct imports from ivatar.settings failed

The issue was that CI environment had different import order/timing than local,
causing 'cannot import name VERSION from ivatar.settings' errors. Using
Django's settings pattern ensures proper configuration loading.
2025-10-31 14:42:30 +01:00
2 changed files with 24 additions and 11 deletions

View File

@@ -2,10 +2,8 @@
Default: useful variables for the base page templates.
"""
from django.conf import settings
from ipware import get_client_ip # type: ignore
from ivatar.settings import IVATAR_VERSION, SITE_NAME, MAX_PHOTO_SIZE
from ivatar.settings import BASE_URL, SECURE_BASE_URL
from ivatar.settings import MAX_NUM_UNCONFIRMED_EMAILS
def basepage(request):
@@ -20,18 +18,21 @@ def basepage(request):
] # pragma: no cover
client_ip = get_client_ip(request)[0]
context["client_ip"] = client_ip
context["ivatar_version"] = IVATAR_VERSION
context["site_name"] = SITE_NAME
context["ivatar_version"] = getattr(settings, "IVATAR_VERSION", "2.0")
context["site_name"] = getattr(settings, "SITE_NAME", "libravatar")
context["site_url"] = request.build_absolute_uri("/")[:-1]
context["max_file_size"] = MAX_PHOTO_SIZE
context["BASE_URL"] = BASE_URL
context["SECURE_BASE_URL"] = SECURE_BASE_URL
context["max_file_size"] = getattr(settings, "MAX_PHOTO_SIZE", 10485760)
context["BASE_URL"] = getattr(settings, "BASE_URL", "http://localhost:8000/avatar/")
context["SECURE_BASE_URL"] = getattr(
settings, "SECURE_BASE_URL", "https://localhost:8000/avatar/"
)
context["max_emails"] = False
if request.user:
if not request.user.is_anonymous:
unconfirmed = request.user.unconfirmedemail_set.count()
if unconfirmed >= MAX_NUM_UNCONFIRMED_EMAILS:
max_unconfirmed = getattr(settings, "MAX_NUM_UNCONFIRMED_EMAILS", 5)
if unconfirmed >= max_unconfirmed:
context["max_emails"] = True
return context

View File

@@ -22,7 +22,8 @@ from opentelemetry.instrumentation.pymysql import PyMySQLInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry.instrumentation.urllib3 import URLLib3Instrumentor
from .settings import VERSION as IVATAR_VERSION
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
# Note: Memcached instrumentation not available in OpenTelemetry Python
@@ -61,10 +62,21 @@ class OpenTelemetryConfig:
def _create_resource(self) -> Resource:
"""Create OpenTelemetry resource with service information."""
# Get IVATAR_VERSION from environment or settings, handling case where
# Django settings might not be configured yet
ivatar_version = os.environ.get("IVATAR_VERSION")
if not ivatar_version:
# Try to access settings, but handle case where Django isn't configured
try:
ivatar_version = getattr(settings, "IVATAR_VERSION", "2.0")
except ImproperlyConfigured:
# Django settings not configured yet, use default
ivatar_version = "2.0"
return Resource.create(
{
"service.name": self.service_name,
"service.version": os.environ.get("IVATAR_VERSION", IVATAR_VERSION),
"service.version": ivatar_version,
"service.namespace": "libravatar",
"deployment.environment": self.environment,
"service.instance.id": os.environ.get("HOSTNAME", "unknown"),