99import rfc2html
1010import time
1111
12+ from typing import Optional , TYPE_CHECKING
13+
1214from django .db import models
1315from django .core import checks
1416from django .core .cache import caches
3436from ietf .utils .validators import validate_no_control_chars
3537from ietf .utils .mail import formataddr
3638from ietf .utils .models import ForeignKey
39+ if TYPE_CHECKING :
40+ # importing other than for type checking causes errors due to cyclic imports
41+ from ietf .meeting .models import ProceedingsMaterial , Session
3742
3843logger = logging .getLogger ('django' )
3944
@@ -129,10 +134,11 @@ def get_file_path(self):
129134 self ._cached_file_path = settings .INTERNET_DRAFT_PATH
130135 else :
131136 self ._cached_file_path = settings .INTERNET_ALL_DRAFTS_ARCHIVE_DIR
132- elif self .type_id in ("agenda" , "minutes" , "slides" , "bluesheets" ) and self .meeting_related ():
133- doc = self .doc if isinstance (self , DocHistory ) else self
134- if doc .session_set .exists ():
135- meeting = doc .session_set .first ().meeting
137+ elif self .meeting_related () and self .type_id in (
138+ "agenda" , "minutes" , "slides" , "bluesheets" , "procmaterials"
139+ ):
140+ meeting = self .get_related_meeting ()
141+ if meeting is not None :
136142 self ._cached_file_path = os .path .join (meeting .get_materials_path (), self .type_id ) + "/"
137143 else :
138144 self ._cached_file_path = ""
@@ -160,8 +166,9 @@ def get_base_name(self):
160166 self ._cached_base_name = "%s.txt" % self .canonical_name ()
161167 else :
162168 self ._cached_base_name = "%s-%s.txt" % (self .name , self .rev )
163- elif self .type_id in ["slides" , "agenda" , "minutes" , "bluesheets" , ] and self .meeting_related ():
164- self ._cached_base_name = "%s-%s.txt" % (self .canonical_name (), self .rev )
169+ elif self .type_id in ["slides" , "agenda" , "minutes" , "bluesheets" , "procmaterials" , ] and self .meeting_related ():
170+ ext = 'pdf' if self .type_id == 'procmaterials' else 'txt'
171+ self ._cached_base_name = f'{ self .canonical_name ()} -{ self .rev } .{ ext } '
165172 elif self .type_id == 'review' :
166173 # TODO: This will be wrong if a review is updated on the same day it was created (or updated more than once on the same day)
167174 self ._cached_base_name = "%s.txt" % self .name
@@ -218,7 +225,6 @@ def _get_ref(self, meeting=None, meeting_doc_refs=settings.MEETING_DOC_HREFS):
218225 log .unreachable ('2018-12-28' )
219226 pass
220227
221-
222228 if self .type_id in settings .DOC_HREFS and self .type_id in meeting_doc_refs :
223229 if self .meeting_related ():
224230 self .is_meeting_related = True
@@ -239,16 +245,13 @@ def _get_ref(self, meeting=None, meeting_doc_refs=settings.MEETING_DOC_HREFS):
239245
240246 if self .is_meeting_related :
241247 if not meeting :
242- # we need to do this because DocHistory items don't have
243- # any session_set entry:
244- doc = self .doc if isinstance (self , DocHistory ) else self
245- sess = doc .session_set .first ()
246- if not sess :
247- return ""
248- meeting = sess .meeting
248+ meeting = self .get_related_meeting ()
249+ if meeting is None :
250+ return ''
251+
249252 # After IETF 96, meeting materials acquired revision
250253 # handling, and the document naming changed.
251- if meeting .number . isdigit () and int ( meeting . number ) <= 96 :
254+ if meeting .proceedings_format_version == 1 :
252255 format = settings .MEETING_DOC_OLD_HREFS [self .type_id ]
253256 else :
254257 # This branch includes interims
@@ -420,10 +423,44 @@ def has_rfc_editor_note(self):
420423 return e != None and (e .text != "" )
421424
422425 def meeting_related (self ):
423- if self .type_id in ("agenda" ,"minutes" ,"bluesheets" ,"slides" ,"recording" ):
426+ if self .type_id in ("agenda" ,"minutes" ,"bluesheets" ,"slides" ,"recording" , "procmaterials" ):
424427 return self .type_id != "slides" or self .get_state_slug ('reuse_policy' )== 'single'
425428 return False
426429
430+ def get_related_session (self ) -> Optional ['Session' ]:
431+ """Get the meeting session related to this document
432+
433+ Return None if there is no related session.
434+ Must define this in DocumentInfo subclasses.
435+ """
436+ raise NotImplementedError (f'Class { self .__class__ } must define get_related_session()' )
437+
438+ def get_related_proceedings_material (self ) -> Optional ['ProceedingsMaterial' ]:
439+ """Get the proceedings material related to this document
440+
441+ Return None if there is no related proceedings material.
442+ Must define this in DocumentInfo subclasses.
443+ """
444+ raise NotImplementedError (f'Class { self .__class__ } must define get_related_proceedings_material()' )
445+
446+ def get_related_meeting (self ):
447+ """Get the meeting this document relates to"""
448+ if not self .meeting_related ():
449+ return None # no related meeting if not meeting_related!
450+ elif self .type_id in ("agenda" , "minutes" , "slides" , "bluesheets" ,):
451+ # session-related
452+ session = self .get_related_session ()
453+ if session is not None :
454+ return session .meeting
455+ elif self .type_id == "procmaterials" :
456+ # proceedings-related
457+ material = self .get_related_proceedings_material ()
458+ if material is not None :
459+ return material .meeting
460+ else :
461+ log .unreachable ('2021-08-29' ) # if meeting_related, there must be a way to retrieve the meeting!
462+ return None
463+
427464 def relations_that (self , relationship ):
428465 """Return the related-document objects that describe a given relationship targeting self."""
429466 if isinstance (relationship , str ):
@@ -713,6 +750,13 @@ def get_absolute_url(self):
713750 self ._cached_absolute_url = url
714751 return self ._cached_absolute_url
715752
753+ def get_related_session (self ):
754+ sessions = self .session_set .all ()
755+ return sessions .first ()
756+
757+ def get_related_proceedings_material (self ):
758+ return self .proceedingsmaterial_set .first ()
759+
716760 def file_tag (self ):
717761 return "<%s>" % self .filename_with_rev ()
718762
@@ -1003,6 +1047,12 @@ class DocHistory(DocumentInfo):
10031047 def __str__ (self ):
10041048 return force_text (self .doc .name )
10051049
1050+ def get_related_session (self ):
1051+ return self .doc .get_related_session ()
1052+
1053+ def get_related_proceedings_material (self ):
1054+ return self .doc .get_related_proceedings_material ()
1055+
10061056 def canonical_name (self ):
10071057 if hasattr (self , '_canonical_name' ):
10081058 return self ._canonical_name
0 commit comments