Files
VacatureRadar/apps/core/views.py
T

99 lines
3.6 KiB
Python

from __future__ import annotations
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView
from django.http import JsonResponse
from django.views.generic import TemplateView
from apps.core.rate_limit import clear_rate_limit, is_rate_limited, register_rate_limit_failure
from apps.jobs.services.cockpit import build_dashboard_cockpit
from apps.profiles.models import SearchProfile
from apps.sources.services.health import collect_source_health
from .health import readiness
from .services.automation import build_automation_cockpit
class SecurityAwareLoginView(LoginView):
template_name = "registration/login.html"
@staticmethod
def _remaining_minutes(seconds: int) -> str:
minutes = max(1, (seconds + 59) // 60)
return f"{minutes} minuut" if minutes == 1 else f"{minutes} minuten"
def dispatch(self, request, *args, **kwargs):
if request.method == "POST":
state = is_rate_limited(
request,
namespace="login",
max_attempts=settings.AUTH_LOGIN_RATE_LIMIT_MAX_ATTEMPTS,
window_seconds=settings.AUTH_LOGIN_RATE_LIMIT_WINDOW_SECONDS,
block_seconds=settings.AUTH_LOGIN_RATE_LIMIT_BLOCK_SECONDS,
)
if state.is_blocked:
messages.error(
request,
(
"Te veel inlogpogingen op dit account. Wacht "
f"{self._remaining_minutes(state.remaining_seconds)} en probeer daarna "
"opnieuw."
),
)
return self.form_invalid(self.get_form())
return super().dispatch(request, *args, **kwargs)
def form_invalid(self, form):
state = register_rate_limit_failure(
self.request,
namespace="login",
max_attempts=settings.AUTH_LOGIN_RATE_LIMIT_MAX_ATTEMPTS,
window_seconds=settings.AUTH_LOGIN_RATE_LIMIT_WINDOW_SECONDS,
block_seconds=settings.AUTH_LOGIN_RATE_LIMIT_BLOCK_SECONDS,
)
if state.is_blocked:
messages.error(
self.request,
(
"Te veel inlogpogingen. Wacht "
f"{self._remaining_minutes(state.remaining_seconds)} en probeer daarna opnieuw."
),
)
return super().form_invalid(form)
def form_valid(self, form):
clear_rate_limit(self.request, namespace="login")
return super().form_valid(form)
def health_live(request):
return JsonResponse({"ok": True, "service": "vacatureradar"})
def health_ready(request):
result = readiness()
return JsonResponse(result.to_dict(), status=200 if result.ok else 503)
class TodayView(LoginRequiredMixin, TemplateView):
template_name = "dashboard/today.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
profile = SearchProfile.objects.filter(user=self.request.user, is_active=True).first()
context.update(build_dashboard_cockpit(self.request.user, profile))
context["active_profile"] = profile
return context
class SystemStatusView(LoginRequiredMixin, TemplateView):
template_name = "system/status.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update(build_automation_cockpit())
context["source_health"] = collect_source_health()
return context