1111import email
1212import pytz
1313import six
14+ import sys
1415import tempfile
1516import xml2rfc
1617
1718from email .utils import formataddr
1819from unidecode import unidecode
1920
21+ if six .PY2 :
22+ from StringIO import StringIO
23+ else :
24+ from io import StringIO
25+
26+
2027from django import forms
2128from django .conf import settings
22- from django .utils .html import mark_safe
29+ from django .utils .html import mark_safe # type:ignore
2330from django .urls import reverse as urlreverse
2431from django .utils .encoding import force_str
2532
3946from ietf .submit .parsers .plain_parser import PlainParser
4047from ietf .submit .parsers .ps_parser import PSParser
4148from ietf .submit .parsers .xml_parser import XMLParser
49+ from ietf .utils import log
4250from ietf .utils .draft import Draft
4351
4452class SubmissionBaseUploadForm (forms .Form ):
@@ -128,6 +136,20 @@ def clean_xml(self):
128136 return self .clean_file ("xml" , XMLParser )
129137
130138 def clean (self ):
139+ def format_messages (where , e , log ):
140+ out = log .write_out .getvalue ().splitlines ()
141+ err = log .write_err .getvalue ().splitlines ()
142+ m = str (e )
143+ if m :
144+ m = [ m ]
145+ else :
146+ import traceback
147+ typ , val , tb = sys .exc_info ()
148+ m = traceback .format_exception (typ , val , tb )
149+ m = [ l .replace ('\n ' , ':\n ' ) for l in m ]
150+ msgs = [s for s in (["Error from xml2rfc (%s):" % (where ,)] + m + out + err ) if s ]
151+ return msgs
152+
131153 if self .shutdown and not has_role (self .request .user , "Secretariat" ):
132154 raise forms .ValidationError ('The submission tool is currently shut down' )
133155
@@ -145,6 +167,9 @@ def clean(self):
145167 xml_file = self .cleaned_data .get ('xml' )
146168 name , ext = os .path .splitext (os .path .basename (xml_file .name ))
147169 tfh , tfn = tempfile .mkstemp (prefix = name + '-' , suffix = '.xml' )
170+ file_name = {}
171+ xml2rfc .log .write_out = StringIO () # open(os.devnull, "w")
172+ xml2rfc .log .write_err = StringIO () # open(os.devnull, "w")
148173 try :
149174 # We need to write the xml file to disk in order to hand it
150175 # over to the xml parser. XXX FIXME: investigate updating
@@ -154,33 +179,15 @@ def clean(self):
154179 for chunk in xml_file .chunks ():
155180 tf .write (chunk )
156181 os .environ ["XML_LIBRARY" ] = settings .XML_LIBRARY
182+ # --- Parse the xml ---
157183 try :
158184 parser = xml2rfc .XmlRfcParser (str (tfn ), quiet = True )
159185 self .xmltree = parser .parse (normalize = True )
160- root = self .xmltree .getroot ()
161- ver = root .get ('version' , '2' )
162- if ver == '2' :
163- ok , errors = self .xmltree .validate ()
164- else :
165- # XXX TODO: Add v3 validation
166- ok , errors = True , ''
167- except Exception as exc :
168- raise forms .ValidationError ("An exception occurred when trying to process the XML file: %s" % exc )
169- if not ok :
170- # Each error has properties:
171- #
172- # message: the message text
173- # domain: the domain ID (see lxml.etree.ErrorDomains)
174- # type: the message type ID (see lxml.etree.ErrorTypes)
175- # level: the log level ID (see lxml.etree.ErrorLevels)
176- # line: the line at which the message originated (if applicable)
177- # column: the character column at which the message originated (if applicable)
178- # filename: the name of the file in which the message originated (if applicable)
179- raise forms .ValidationError (
180- [ forms .ValidationError ("One or more XML validation errors occurred when processing the XML file:" ) ] +
181- [ forms .ValidationError ("%s: Line %s: %s" % (xml_file .name , e .line , e .message ), code = "%s" % e .type ) for e in errors ]
182- )
183- self .xmlroot = self .xmltree .getroot ()
186+ self .xmlroot = self .xmltree .getroot ()
187+ xml_version = self .xmlroot .get ('version' , '2' )
188+ except Exception as e :
189+ raise forms .ValidationError ("An exception occurred when trying to [arse the XML file: %s" % e )
190+
184191 draftname = self .xmlroot .attrib .get ('docName' )
185192 if draftname is None :
186193 raise forms .ValidationError ("No docName attribute found in the xml root element" )
@@ -212,8 +219,76 @@ def clean(self):
212219 if info [item ]:
213220 info [item ] = info [item ].strip ()
214221 self .authors .append (info )
215- except forms .ValidationError :
216- raise
222+
223+ # --- Prep the xml ---
224+ file_name ['xml' ] = os .path .join (settings .IDSUBMIT_STAGING_PATH , '%s-%s.%s' % (self .filename , self .revision , ext ))
225+ try :
226+ if xml_version == '3' :
227+ prep = xml2rfc .PrepToolWriter (self .xmltree , quiet = True )
228+ self .xmltree .tree = prep .prep ()
229+ if self .xmltree .tree == None :
230+ raise forms .ValidationError ("Error from xml2rfc (prep): %s" % prep .errors )
231+ except Exception as e :
232+ msgs = format_messages ('prep' , e , xml2rfc .log )
233+ raise forms .ValidationError (msgs )
234+
235+ # --- Convert to txt ---
236+ if not ('txt' in self .cleaned_data and self .cleaned_data ['txt' ]):
237+ file_name ['txt' ] = os .path .join (settings .IDSUBMIT_STAGING_PATH , '%s-%s.txt' % (self .filename , self .revision ))
238+ try :
239+ if xml_version != '3' :
240+ pagedwriter = xml2rfc .PaginatedTextRfcWriter (self .xmltree , quiet = True )
241+ pagedwriter .write (file_name ['txt' ])
242+ else :
243+ writer = xml2rfc .TextWriter (self .xmltree , quiet = True )
244+ writer .write (file_name ['txt' ])
245+ log .log ("In %s: xml2rfc %s generated %s from %s (version %s)" %
246+ ( os .path .dirname (file_name ['xml' ]),
247+ xml2rfc .__version__ ,
248+ os .path .basename (file_name ['txt' ]),
249+ os .path .basename (file_name ['xml' ]),
250+ xml_version ))
251+ except Exception as e :
252+ msgs = format_messages ('txt' , e , xml2rfc .log )
253+ raise forms .ValidationError (msgs )
254+
255+ # --- Convert to xml ---
256+ if xml_version == '3' :
257+ try :
258+ file_name ['html' ] = os .path .join (settings .IDSUBMIT_STAGING_PATH , '%s-%s.html' % (self .filename , self .revision ))
259+ writer = xml2rfc .HtmlWriter (self .xmltree , quiet = True )
260+ writer .write (file_name ['html' ])
261+ self .file_types .append ('.html' )
262+ log .log ("In %s: xml2rfc %s generated %s from %s (version %s)" %
263+ ( os .path .dirname (file_name ['xml' ]),
264+ xml2rfc .__version__ ,
265+ os .path .basename (file_name ['html' ]),
266+ os .path .basename (file_name ['xml' ]),
267+ xml_version ))
268+ except Exception as e :
269+ msgs = format_messages ('html' , e , xml2rfc .log )
270+ raise forms .ValidationError (msgs )
271+
272+ if xml_version == '2' :
273+ ok , errors = self .xmltree .validate ()
274+ else :
275+ ok , errors = True , ''
276+
277+ if not ok :
278+ # Each error has properties:
279+ #
280+ # message: the message text
281+ # domain: the domain ID (see lxml.etree.ErrorDomains)
282+ # type: the message type ID (see lxml.etree.ErrorTypes)
283+ # level: the log level ID (see lxml.etree.ErrorLevels)
284+ # line: the line at which the message originated (if applicable)
285+ # column: the character column at which the message originated (if applicable)
286+ # filename: the name of the file in which the message originated (if applicable)
287+ raise forms .ValidationError (
288+ [ forms .ValidationError ("One or more XML validation errors occurred when processing the XML file:" ) ] +
289+ [ forms .ValidationError ("%s: Line %s: %s" % (xml_file .name , r .line , r .message ), code = "%s" % r .type ) for r in errors ]
290+ )
291+
217292 finally :
218293 os .close (tfh )
219294 os .unlink (tfn )
0 commit comments