@@ -2258,3 +2258,96 @@ def create_new_job(self, execute_now=False):
22582258 schedules .clear_job (self .schedule_work_id )
22592259
22602260 return schedules .schedule_execution (self , execute_now ) if self .is_active else None
2261+
2262+
2263+ ISSUE_TYPE_CHOICES = [
2264+ ("MISSING_AFFECTED_PACKAGE" , "Advisory is missing affected package" ),
2265+ ("MISSING_FIXED_BY_PACKAGE" , "Advisory is missing fixed-by package" ),
2266+ (
2267+ "MISSING_AFFECTED_AND_FIXED_BY_PACKAGES" ,
2268+ "Advisory is missing both affected and fixed-by packages" ,
2269+ ),
2270+ ("MISSING_SUMMARY" , "Advisory is missing summary" ),
2271+ ("CONFLICTING_FIXED_BY_PACKAGES" , "Advisories have conflicting fixed-by packages" ),
2272+ ("CONFLICTING_AFFECTED_PACKAGES" , "Advisories have conflicting affected packages" ),
2273+ (
2274+ "CONFLICTING_AFFECTED_AND_FIXED_BY_PACKAGES" ,
2275+ "Advisories have conflicting affected and fixed-by packages" ,
2276+ ),
2277+ ("CONFLICTING_SEVERITY_SCORES" , "Advisories have conflicting severity scores" ),
2278+ ]
2279+
2280+
2281+ class AdvisoryToDo (models .Model ):
2282+ """Track the TODOs for advisory/ies that need to be addressed."""
2283+
2284+ # Since we can not make advisories field (M2M field) unique
2285+ # (see https://code.djangoproject.com/ticket/702), we use related_advisories_id
2286+ # to avoid creating duplicate issue for same set of advisories,
2287+ related_advisories_id = models .CharField (
2288+ max_length = 40 ,
2289+ help_text = "SHA1 digest of the unique_content_id field of the applicable advisories." ,
2290+ )
2291+
2292+ advisories = models .ManyToManyField (
2293+ Advisory ,
2294+ through = "ToDoRelatedAdvisory" ,
2295+ related_name = "advisory_todos" ,
2296+ help_text = "Advisory/ies where this TODO is applicable." ,
2297+ )
2298+
2299+ issue_type = models .CharField (
2300+ max_length = 50 ,
2301+ choices = ISSUE_TYPE_CHOICES ,
2302+ db_index = True ,
2303+ help_text = "Select the issue that needs to be addressed from the available options." ,
2304+ )
2305+
2306+ issue_detail = models .TextField (
2307+ blank = True ,
2308+ help_text = "Additional details about the issue." ,
2309+ )
2310+
2311+ created_at = models .DateTimeField (
2312+ auto_now_add = True ,
2313+ help_text = "Timestamp indicating when this TODO was created." ,
2314+ )
2315+
2316+ is_resolved = models .BooleanField (
2317+ default = False ,
2318+ db_index = True ,
2319+ help_text = "This TODO is resolved or not." ,
2320+ )
2321+
2322+ resolved_at = models .DateTimeField (
2323+ null = True ,
2324+ blank = True ,
2325+ help_text = "Timestamp indicating when this TODO was resolved." ,
2326+ )
2327+
2328+ resolution_detail = models .TextField (
2329+ blank = True ,
2330+ help_text = "Additional detail on how this TODO was resolved." ,
2331+ )
2332+
2333+ class Meta :
2334+ unique_together = ("related_advisories_id" , "issue_type" )
2335+
2336+ def save (self , * args , ** kwargs ):
2337+ self .full_clean ()
2338+ return super ().save (* args , ** kwargs )
2339+
2340+
2341+ class ToDoRelatedAdvisory (models .Model ):
2342+ todo = models .ForeignKey (
2343+ AdvisoryToDo ,
2344+ on_delete = models .CASCADE ,
2345+ )
2346+
2347+ advisory = models .ForeignKey (
2348+ Advisory ,
2349+ on_delete = models .CASCADE ,
2350+ )
2351+
2352+ class Meta :
2353+ unique_together = ("todo" , "advisory" )
0 commit comments