97 lines
3 KiB
Python
97 lines
3 KiB
Python
"""Project-level views every service exposes: health, timezone, legal pages."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from functools import lru_cache
|
|
from zoneinfo import available_timezones
|
|
|
|
from django.contrib import messages
|
|
from django.db import connection
|
|
from django.http import JsonResponse
|
|
from django.shortcuts import redirect, render
|
|
from django.urls import reverse
|
|
from django.utils import timezone
|
|
from django.utils.http import url_has_allowed_host_and_scheme
|
|
from django.utils.translation import gettext as _
|
|
|
|
from .context_processors import DEFAULT_COMMON_TIMEZONES
|
|
|
|
|
|
@lru_cache(maxsize=1)
|
|
def _timezone_name_options():
|
|
try:
|
|
names = sorted(available_timezones())
|
|
except Exception:
|
|
names = list(DEFAULT_COMMON_TIMEZONES)
|
|
|
|
preferred = ["UTC", "Europe/Moscow", "Asia/Yakutsk"]
|
|
ordered = [n for n in preferred if n in names]
|
|
ordered += [n for n in names if n not in ordered]
|
|
return ordered
|
|
|
|
|
|
def _safe_next_url(request, candidate):
|
|
if candidate and url_has_allowed_host_and_scheme(
|
|
candidate,
|
|
allowed_hosts={request.get_host()},
|
|
require_https=request.is_secure(),
|
|
):
|
|
return candidate
|
|
return reverse("timezone-preferences")
|
|
|
|
|
|
def privacy_policy(request):
|
|
return render(request, "privacy_policy.html")
|
|
|
|
|
|
def cookie_policy(request):
|
|
return render(request, "cookie_policy.html")
|
|
|
|
|
|
def timezone_preferences(request):
|
|
timezone_names = _timezone_name_options()
|
|
timezone_set = set(timezone_names)
|
|
|
|
selected_timezone = request.session.get("user_timezone", "UTC")
|
|
if selected_timezone not in timezone_set:
|
|
selected_timezone = "UTC"
|
|
|
|
if request.method == "POST":
|
|
selected_timezone = (request.POST.get("timezone") or "UTC").strip()
|
|
if selected_timezone not in timezone_set:
|
|
messages.error(request, _("Selected time zone is not supported."))
|
|
else:
|
|
request.session["user_timezone"] = selected_timezone
|
|
request.session.modified = True
|
|
messages.success(request, _("Time zone preference saved."))
|
|
return redirect(_safe_next_url(request, request.POST.get("next")))
|
|
|
|
return render(request, "timezone_preferences.html", {
|
|
"timezone_names": timezone_names,
|
|
"selected_timezone": selected_timezone,
|
|
"next_url": _safe_next_url(
|
|
request, request.GET.get("next") or request.META.get("HTTP_REFERER"),
|
|
),
|
|
})
|
|
|
|
|
|
def health_check(request):
|
|
"""Swarm healthcheck target: it must answer without a database, not raise."""
|
|
try:
|
|
with connection.cursor() as cursor:
|
|
cursor.execute("SELECT 1")
|
|
return JsonResponse({
|
|
"status": "healthy",
|
|
"timestamp": timezone.now().isoformat(),
|
|
"database": "connected",
|
|
})
|
|
except Exception as exc:
|
|
return JsonResponse(
|
|
{
|
|
"status": "unhealthy",
|
|
"timestamp": timezone.now().isoformat(),
|
|
"database": "disconnected",
|
|
"error": str(exc),
|
|
},
|
|
status=503,
|
|
)
|