11import os
2+ import re
23import datetime
34import pytz
5+ import xml2rfc
6+ import tempfile
47
58from django import forms
69from django .conf import settings
2326from ietf .utils .draft import Draft
2427
2528
26- class UploadForm (forms .Form ):
27- txt = forms .FileField (label = u'.txt format' , required = True )
29+ class SubmissionUploadForm (forms .Form ):
30+ txt = forms .FileField (label = u'.txt format' , required = False )
2831 xml = forms .FileField (label = u'.xml format' , required = False )
2932 pdf = forms .FileField (label = u'.pdf format' , required = False )
30- ps = forms .FileField (label = u'.ps format' , required = False )
33+ ps = forms .FileField (label = u'.ps format' , required = False )
3134
3235 def __init__ (self , request , * args , ** kwargs ):
33- super (UploadForm , self ).__init__ (* args , ** kwargs )
36+ super (SubmissionUploadForm , self ).__init__ (* args , ** kwargs )
3437
3538 self .remote_ip = request .META .get ('REMOTE_ADDR' , None )
3639
@@ -41,7 +44,13 @@ def __init__(self, request, *args, **kwargs):
4144 self .set_cutoff_warnings ()
4245
4346 self .group = None
47+ self .filename = None
48+ self .revision = None
49+ self .title = None
50+ self .abstract = None
51+ self .authors = []
4452 self .parsed_draft = None
53+ self .file_types = []
4554
4655 def set_cutoff_warnings (self ):
4756 now = datetime .datetime .now (pytz .utc )
@@ -93,15 +102,14 @@ def clean_file(self, field_name, parser_class):
93102
94103 return f
95104
96-
97105 def clean_txt (self ):
98106 return self .clean_file ("txt" , PlainParser )
99107
100108 def clean_pdf (self ):
101109 return self .clean_file ("pdf" , PDFParser )
102110
103111 def clean_ps (self ):
104- return self .clean_file ("ps" , PSParser )
112+ return self .clean_file ("ps" , PSParser )
105113
106114 def clean_xml (self ):
107115 return self .clean_file ("xml" , XMLParser )
@@ -116,37 +124,100 @@ def clean(self):
116124 if not os .path .exists (getattr (settings , s )):
117125 raise forms .ValidationError ('%s defined in settings.py does not exist' % s )
118126
127+ for ext in ['txt' , 'pdf' , 'xml' , 'ps' ]:
128+ f = self .cleaned_data .get (ext , None )
129+ if not f :
130+ continue
131+ self .file_types .append ('.%s' % ext )
132+ if not ('.txt' in self .file_types or '.xml' in self .file_types ):
133+ raise forms .ValidationError ('You must submit either a .txt or an .xml file; didn\' t find either.' )
134+
135+ #debug.show('self.cleaned_data["xml"]')
136+ if self .cleaned_data .get ('xml' ):
137+ #if not self.cleaned_data.get('txt'):
138+ xml_file = self .cleaned_data .get ('xml' )
139+ tfh , tfn = tempfile .mkstemp (suffix = '.xml' )
140+ try :
141+ # We need to write the xml file to disk in order to hand it
142+ # over to the xml parser. XXX FIXME: investigate updating
143+ # xml2rfc to be able to work with file handles to in-memory
144+ # files.
145+ with open (tfn , 'wb+' ) as tf :
146+ for chunk in xml_file .chunks ():
147+ tf .write (chunk )
148+ os .environ ["XML_LIBRARY" ] = settings .XML_LIBRARY
149+ parser = xml2rfc .XmlRfcParser (tfn , quiet = True )
150+ self .xmltree = parser .parse ()
151+ ok , errors = self .xmltree .validate ()
152+ if not ok :
153+ raise forms .ValidationError (errors )
154+ self .xmlroot = self .xmltree .getroot ()
155+ draftname = self .xmlroot .attrib .get ('docName' )
156+ revmatch = re .search ("-[0-9][0-9]$" , draftname )
157+ if revmatch :
158+ self .revision = draftname [- 2 :]
159+ self .filename = draftname [:- 3 ]
160+ else :
161+ self .revision = None
162+ self .filename = draftname
163+ self .title = self .xmlroot .find ('front/title' ).text
164+ self .abstract = self .xmlroot .find ('front/abstract' ).text
165+ self .author_list = []
166+ author_info = self .xmlroot .findall ('front/author' )
167+ for author in author_info :
168+ author_dict = dict (
169+ company = author .find ('organization' ).text ,
170+ last_name = author .attrib .get ('surname' ),
171+ full_name = author .attrib .get ('fullname' ),
172+ email = author .find ('address/email' ).text ,
173+ )
174+ self .author_list .append (author_dict )
175+ line = "%(full_name)s <%(email)s>" % author_dict
176+ self .authors .append (line )
177+ except Exception as e :
178+ raise forms .ValidationError ("Exception: %s" % e )
179+ finally :
180+ os .close (tfh )
181+ os .unlink (tfn )
182+
119183 if self .cleaned_data .get ('txt' ):
120184 # try to parse it
121185 txt_file = self .cleaned_data ['txt' ]
122186 txt_file .seek (0 )
123187 self .parsed_draft = Draft (txt_file .read (), txt_file .name )
188+ self .filename = self .parsed_draft .filename
189+ self .revision = self .parsed_draft .revision
190+ self .title = self .parsed_draft .get_title ()
124191 txt_file .seek (0 )
125192
126- if not self .parsed_draft .filename :
127- raise forms .ValidationError ("Draft parser could not extract a valid draft name from the .txt file" )
193+ if not self .filename :
194+ raise forms .ValidationError ("Draft parser could not extract a valid draft name from the upload" )
195+
196+ if not self .revision :
197+ raise forms .ValidationError ("Draft parser could not extract a valid draft revision from the upload" )
128198
129- if not self .parsed_draft . get_title () :
130- raise forms .ValidationError ("Draft parser could not extract a valid title from the .txt file " )
199+ if not self .title :
200+ raise forms .ValidationError ("Draft parser could not extract a valid title from the upload " )
131201
202+ if self .cleaned_data .get ('txt' ) or self .cleaned_data .get ('xml' ):
132203 # check group
133204 self .group = self .deduce_group ()
134205
135206 # check existing
136- existing = Submission .objects .filter (name = self .parsed_draft . filename , rev = self . parsed_draft .revision ).exclude (state__in = ("posted" , "cancel" ))
207+ existing = Submission .objects .filter (name = self .filename , rev = self .revision ).exclude (state__in = ("posted" , "cancel" ))
137208 if existing :
138209 raise forms .ValidationError (mark_safe ('Submission with same name and revision is currently being processed. <a href="%s">Check the status here.</a>' % urlreverse ("submit_submission_status" , kwargs = { 'submission_id' : existing [0 ].pk })))
139210
140211 # cut-off
141- if self .parsed_draft . revision == '00' and self .in_first_cut_off :
212+ if self .revision == '00' and self .in_first_cut_off :
142213 raise forms .ValidationError (mark_safe (self .cutoff_warning ))
143214
144215 # check thresholds
145216 today = datetime .date .today ()
146217
147218 self .check_submissions_tresholds (
148- "for the draft %s" % self .parsed_draft . filename ,
149- dict (name = self .parsed_draft . filename , rev = self . parsed_draft .revision , submission_date = today ),
219+ "for the draft %s" % self .filename ,
220+ dict (name = self .filename , rev = self .revision , submission_date = today ),
150221 settings .IDSUBMIT_MAX_DAILY_SAME_DRAFT_NAME , settings .IDSUBMIT_MAX_DAILY_SAME_DRAFT_NAME_SIZE ,
151222 )
152223 self .check_submissions_tresholds (
@@ -166,19 +237,19 @@ def clean(self):
166237 settings .IDSUBMIT_MAX_DAILY_SUBMISSIONS , settings .IDSUBMIT_MAX_DAILY_SUBMISSIONS_SIZE ,
167238 )
168239
169- return super (UploadForm , self ).clean ()
240+ return super (SubmissionUploadForm , self ).clean ()
170241
171242 def check_submissions_tresholds (self , which , filter_kwargs , max_amount , max_size ):
172243 submissions = Submission .objects .filter (** filter_kwargs )
173244
174245 if len (submissions ) > max_amount :
175246 raise forms .ValidationError ("Max submissions %s has been reached for today (maximum is %s submissions)." % (which , max_amount ))
176- if sum (s .file_size for s in submissions ) > max_size * 1024 * 1024 :
247+ if sum (s .file_size for s in submissions if s . file_size ) > max_size * 1024 * 1024 :
177248 raise forms .ValidationError ("Max uploaded amount %s has been reached for today (maximum is %s MB)." % (which , max_size ))
178249
179250 def deduce_group (self ):
180251 """Figure out group from name or previously submitted draft, returns None if individual."""
181- name = self .parsed_draft . filename
252+ name = self .filename
182253 existing_draft = Document .objects .filter (name = name , type = "draft" )
183254 if existing_draft :
184255 group = existing_draft [0 ].group
0 commit comments