77# See https://aboutcode.org for more information about nexB OSS projects.
88#
99
10+ import datetime
1011import json
1112import logging
1213import time
3132from django .db .models import Q
3233from django .db .models .functions import Cast
3334from django .db .models .functions import TruncDate
34- from django .http import HttpRequest
3535from django .http import HttpResponse
36- from django .http import JsonResponse
3736from django .http .response import Http404
3837from django .shortcuts import get_object_or_404
3938from django .shortcuts import render
4039from django .urls import reverse_lazy
4140from django .views import View
4241from django .views import generic
43- from django .views .decorators .http import require_safe
4442from django .views .generic .detail import DetailView
4543from django .views .generic .edit import FormMixin
4644from django .views .generic .edit import FormView
@@ -589,6 +587,61 @@ def get_context_data(self, **kwargs):
589587 return context
590588
591589
590+ def get_epss_history (advisory , epss_page_param ):
591+ """
592+ Fetch and return EPSS history data for an advisory.
593+ """
594+
595+ epss_history_data = []
596+ epss_pagination_obj = None
597+
598+ epss_scores_queryset = (
599+ models .AdvisorySeverity .objects .filter (
600+ advisories__advisory_id = advisory .advisory_id ,
601+ advisories__datasource_id = EPSS .identifier ,
602+ scoring_system = EPSS .identifier ,
603+ published_at__isnull = False ,
604+ )
605+ .annotate (pub_date = TruncDate ("published_at" ))
606+ .values ("pub_date" )
607+ .annotate (
608+ max_score = Max (Cast ("value" , FloatField ())),
609+ max_percentile = Max (Cast ("scoring_elements" , FloatField ())),
610+ )
611+ .order_by ("-pub_date" )
612+ )
613+
614+ paginator = Paginator (epss_scores_queryset , 30 )
615+ epss_page = epss_page_param or 1
616+ epss_pagination_obj = paginator .get_page (epss_page )
617+
618+ if epss_pagination_obj .object_list :
619+ records = list (epss_pagination_obj .object_list )
620+ newest_date = records [0 ]["pub_date" ]
621+ oldest_date = records [- 1 ]["pub_date" ]
622+
623+ records_by_date = {
624+ record ["pub_date" ]: {
625+ "score" : record ["max_score" ],
626+ "percentile" : record ["max_percentile" ],
627+ "published_at" : record ["pub_date" ],
628+ }
629+ for record in records
630+ }
631+
632+ total_days = (newest_date - oldest_date ).days
633+ all_dates = [oldest_date + datetime .timedelta (days = i ) for i in range (total_days + 1 )]
634+
635+ # Handle missing dates
636+ for date in all_dates :
637+ if date in records_by_date :
638+ epss_history_data .append (records_by_date [date ])
639+ else :
640+ epss_history_data .append ({"published_at" : date , "score" : None , "percentile" : None })
641+
642+ return epss_history_data , epss_pagination_obj
643+
644+
592645class AdvisoryDetails (VulnerableCodeDetailView ):
593646 model = models .AdvisoryV2
594647 template_name = "advisory_detail.html"
@@ -749,47 +802,9 @@ def add_ssvc(ssvc):
749802
750803 context ["ssvcs" ] = ssvc_entries
751804
752- # EPSS history
753- cves = {
754- alias_obj .alias
755- for alias_obj in advisory .aliases .all ()
756- if alias_obj .alias .startswith ("CVE-" )
757- }
758- if advisory .advisory_id and advisory .advisory_id .startswith ("CVE-" ):
759- cves .add (advisory .advisory_id )
760-
761- if cves :
762- epss_scores_queryset = (
763- models .AdvisorySeverity .objects .filter (
764- advisories__advisory_id__in = cves ,
765- scoring_system = EPSS .identifier ,
766- published_at__isnull = False ,
767- )
768- .annotate (pub_date = TruncDate ("published_at" ))
769- .values ("pub_date" )
770- .annotate (
771- max_score = Max (Cast ("value" , FloatField ())),
772- max_percentile = Max (Cast ("scoring_elements" , FloatField ())),
773- )
774- .order_by ("-pub_date" )
775- )
776-
777- paginator = Paginator (epss_scores_queryset , 30 )
778- epss_page = self .request .GET .get ("epss_page" , 1 )
779- epss_page_obj = paginator .get_page (epss_page )
780-
781- epss_history_data = [
782- {
783- "score" : record ["max_score" ],
784- "percentile" : record ["max_percentile" ],
785- "published_at" : record ["pub_date" ],
786- }
787- for record in epss_page_obj .object_list
788- ]
789- epss_history_data .reverse ()
790- else :
791- epss_history_data = []
792- epss_page_obj = None
805+ epss_history_data , epss_pagination_obj = get_epss_history (
806+ advisory , self .request .GET .get ("epss_page" )
807+ )
793808
794809 context .update (
795810 {
@@ -803,8 +818,7 @@ def add_ssvc(ssvc):
803818 "status" : advisory .get_status_label ,
804819 "epss_data" : epss_data ,
805820 "epss_history_data" : epss_history_data ,
806- "epss_page_obj" : epss_page_obj ,
807- "is_epss_tab_active" : "epss_page" in self .request .GET ,
821+ "epss_pagination_obj" : epss_pagination_obj ,
808822 }
809823 )
810824 return context
0 commit comments