feat: replace dashboard and vacancy intelligence

This commit is contained in:
Jens
2026-07-22 19:56:15 +02:00
parent 09af98193f
commit 3371455255
9 changed files with 388 additions and 216 deletions
+26 -49
View File
@@ -3,16 +3,7 @@ from __future__ import annotations
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import (
CharField,
DateTimeField,
DecimalField,
F,
JSONField,
OuterRef,
Q,
Subquery,
)
from django.db.models import Count, F, Q
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
@@ -30,6 +21,7 @@ from .services.applications import (
delete_application_dossier,
track_application_changes,
)
from .services.cockpit import annotate_latest_profile_score, build_job_intelligence
from .services.feedback import record_feedback
from .services.relevance import it_relevance_query
from .services.skill_demand import build_skill_demand_report
@@ -70,40 +62,15 @@ class JobListView(LoginRequiredMixin, ListView):
VALID_SORTS = {"match", "newest", "closing"}
def get_queryset(self):
queryset = JobPosting.objects.select_related("employer").all()
queryset = JobPosting.objects.select_related("employer").annotate(
duplicate_count=Count("duplicates", distinct=True)
)
profile = SearchProfile.objects.filter(user=self.request.user, is_active=True).first()
if profile:
latest_score = ScoreRun.objects.filter(job=OuterRef("pk"), profile=profile).order_by(
"-created_at"
)
queryset = queryset.annotate(
match_score=Subquery(
latest_score.values("score")[:1],
output_field=DecimalField(max_digits=5, decimal_places=2),
),
match_confidence=Subquery(
latest_score.values("confidence")[:1],
output_field=DecimalField(max_digits=4, decimal_places=3),
),
match_recommendation=Subquery(
latest_score.values("recommendation")[:1], output_field=CharField()
),
match_positives=Subquery(
latest_score.values("positives")[:1], output_field=JSONField()
),
match_concerns=Subquery(
latest_score.values("concerns")[:1], output_field=JSONField()
),
match_hard_exclusions=Subquery(
latest_score.values("hard_exclusions")[:1], output_field=JSONField()
),
match_scored_at=Subquery(
latest_score.values("created_at")[:1], output_field=DateTimeField()
),
)
queryset = annotate_latest_profile_score(queryset, profile)
query = self.request.GET.get("q", "").strip()
status = self.request.GET.get("status", "active").strip()
workplace = self.request.GET.get("workplace", "").strip()
channel = self.request.GET.get("channel", "").strip()
focus = self.request.GET.get("focus", "it").strip()
recommendation = self.request.GET.get("match", "radar").strip()
sort = self.request.GET.get("sort", "match").strip()
@@ -120,6 +87,10 @@ class JobListView(LoginRequiredMixin, ListView):
queryset = queryset.filter(status=status)
if workplace:
queryset = queryset.filter(workplace_type=workplace)
if channel == "direct":
queryset = queryset.filter(direct_employer=True, recruiter=False)
elif channel == "recruiter":
queryset = queryset.filter(recruiter=True)
if focus != "all":
queryset = queryset.filter(it_relevance_query())
if profile and recommendation == "radar":
@@ -162,8 +133,21 @@ class JobListView(LoginRequiredMixin, ListView):
else "radar"
),
"current_sort": self.request.GET.get("sort", "match"),
"current_channel": self.request.GET.get("channel", ""),
}
)
jobs = list(context["jobs"])
selected_id = self.request.GET.get("selected", "")
selected_job = next((job for job in jobs if str(job.pk) == selected_id), None)
if selected_job is None and jobs:
selected_job = jobs[0]
context["selected_job"] = selected_job
if selected_job is not None:
context["selected_intelligence"] = build_job_intelligence(
job=selected_job,
profile=context["active_profile"],
user=self.request.user,
)
return context
@@ -180,16 +164,9 @@ class JobDetailView(LoginRequiredMixin, DetailView):
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["score"] = (
ScoreRun.objects.filter(job=self.object, profile=profile)
.order_by("-created_at")
.first()
if profile
else None
context.update(
build_job_intelligence(job=self.object, profile=profile, user=self.request.user)
)
context["application"] = Application.objects.filter(
user=self.request.user, job=self.object
).first()
context["latest_feedback"] = Feedback.objects.filter(
user=self.request.user, job=self.object
).first()