77# See https://aboutcode.org for more information about nexB OSS projects.
88#
99
10+ import datetime
1011import json
1112import logging
1213import time
4041from django .urls import reverse_lazy
4142from django .views import View
4243from django .views import generic
43- from django .views .decorators .http import require_safe
4444from django .views .generic .detail import DetailView
4545from django .views .generic .edit import FormMixin
4646from django .views .generic .edit import FormView
@@ -589,6 +589,61 @@ def get_context_data(self, **kwargs):
589589 return context
590590
591591
592+ def get_epss_history (advisory , epss_page_param ):
593+ """
594+ Fetch and return EPSS history data for an advisory.
595+ """
596+
597+ epss_history_data = []
598+ epss_pagination_obj = None
599+
600+ epss_scores_queryset = (
601+ models .AdvisorySeverity .objects .filter (
602+ advisories__advisory_id = advisory .advisory_id ,
603+ advisories__datasource_id = EPSS .identifier ,
604+ scoring_system = EPSS .identifier ,
605+ published_at__isnull = False ,
606+ )
607+ .annotate (pub_date = TruncDate ("published_at" ))
608+ .values ("pub_date" )
609+ .annotate (
610+ max_score = Max (Cast ("value" , FloatField ())),
611+ max_percentile = Max (Cast ("scoring_elements" , FloatField ())),
612+ )
613+ .order_by ("-pub_date" )
614+ )
615+
616+ paginator = Paginator (epss_scores_queryset , 30 )
617+ epss_page = epss_page_param or 1
618+ epss_pagination_obj = paginator .get_page (epss_page )
619+
620+ if epss_pagination_obj .object_list :
621+ records = list (epss_pagination_obj .object_list )
622+ newest_date = records [0 ]["pub_date" ]
623+ oldest_date = records [- 1 ]["pub_date" ]
624+
625+ records_by_date = {
626+ record ["pub_date" ]: {
627+ "score" : record ["max_score" ],
628+ "percentile" : record ["max_percentile" ],
629+ "published_at" : record ["pub_date" ],
630+ }
631+ for record in records
632+ }
633+
634+ total_days = (newest_date - oldest_date ).days
635+ all_dates = [oldest_date + datetime .timedelta (days = i ) for i in range (total_days + 1 )]
636+
637+ # Handle missing dates
638+ for date in all_dates :
639+ if date in records_by_date :
640+ epss_history_data .append (records_by_date [date ])
641+ else :
642+ epss_history_data .append ({"published_at" : date , "score" : None , "percentile" : None })
643+
644+ return epss_history_data , epss_pagination_obj
645+
646+
592647class AdvisoryDetails (VulnerableCodeDetailView ):
593648 model = models .AdvisoryV2
594649 template_name = "advisory_detail.html"
@@ -749,47 +804,9 @@ def add_ssvc(ssvc):
749804
750805 context ["ssvcs" ] = ssvc_entries
751806
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
807+ epss_history_data , epss_pagination_obj = get_epss_history (
808+ advisory , self .request .GET .get ("epss_page" )
809+ )
793810
794811 context .update (
795812 {
@@ -803,8 +820,7 @@ def add_ssvc(ssvc):
803820 "status" : advisory .get_status_label ,
804821 "epss_data" : epss_data ,
805822 "epss_history_data" : epss_history_data ,
806- "epss_page_obj" : epss_page_obj ,
807- "is_epss_tab_active" : "epss_page" in self .request .GET ,
823+ "epss_pagination_obj" : epss_pagination_obj ,
808824 }
809825 )
810826 return context
0 commit comments