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
2124from ietf .utils .draft import Draft
2225
2326
24- class UploadForm (forms .Form ):
25- txt = forms .FileField (label = u'.txt format' , required = True )
27+ class SubmissionUploadForm (forms .Form ):
28+ txt = forms .FileField (label = u'.txt format' , required = False )
2629 xml = forms .FileField (label = u'.xml format' , required = False )
2730 pdf = forms .FileField (label = u'.pdf format' , required = False )
28- ps = forms .FileField (label = u'.ps format' , required = False )
31+ ps = forms .FileField (label = u'.ps format' , required = False )
2932
3033 def __init__ (self , request , * args , ** kwargs ):
31- super (UploadForm , self ).__init__ (* args , ** kwargs )
34+ super (SubmissionUploadForm , self ).__init__ (* args , ** kwargs )
3235
3336 self .remote_ip = request .META .get ('REMOTE_ADDR' , None )
3437
@@ -38,7 +41,13 @@ def __init__(self, request, *args, **kwargs):
3841 self .set_cutoff_warnings ()
3942
4043 self .group = None
44+ self .filename = None
45+ self .revision = None
46+ self .title = None
47+ self .abstract = None
48+ self .authors = []
4149 self .parsed_draft = None
50+ self .file_types = []
4251
4352 def set_cutoff_warnings (self ):
4453 now = datetime .datetime .now (pytz .utc )
@@ -90,15 +99,14 @@ def clean_file(self, field_name, parser_class):
9099
91100 return f
92101
93-
94102 def clean_txt (self ):
95103 return self .clean_file ("txt" , PlainParser )
96104
97105 def clean_pdf (self ):
98106 return self .clean_file ("pdf" , PDFParser )
99107
100108 def clean_ps (self ):
101- return self .clean_file ("ps" , PSParser )
109+ return self .clean_file ("ps" , PSParser )
102110
103111 def clean_xml (self ):
104112 return self .clean_file ("xml" , XMLParser )
@@ -113,37 +121,100 @@ def clean(self):
113121 if not os .path .exists (getattr (settings , s )):
114122 raise forms .ValidationError ('%s defined in settings.py does not exist' % s )
115123
124+ for ext in ['txt' , 'pdf' , 'xml' , 'ps' ]:
125+ f = self .cleaned_data .get (ext , None )
126+ if not f :
127+ continue
128+ self .file_types .append ('.%s' % ext )
129+ if not ('.txt' in self .file_types or '.xml' in self .file_types ):
130+ raise forms .ValidationError ('You must submit either a .txt or an .xml file; didn\' t find either.' )
131+
132+ #debug.show('self.cleaned_data["xml"]')
133+ if self .cleaned_data .get ('xml' ):
134+ #if not self.cleaned_data.get('txt'):
135+ xml_file = self .cleaned_data .get ('xml' )
136+ tfh , tfn = tempfile .mkstemp (suffix = '.xml' )
137+ try :
138+ # We need to write the xml file to disk in order to hand it
139+ # over to the xml parser. XXX FIXME: investigate updating
140+ # xml2rfc to be able to work with file handles to in-memory
141+ # files.
142+ with open (tfn , 'wb+' ) as tf :
143+ for chunk in xml_file .chunks ():
144+ tf .write (chunk )
145+ os .environ ["XML_LIBRARY" ] = settings .XML_LIBRARY
146+ parser = xml2rfc .XmlRfcParser (tfn , quiet = True )
147+ self .xmltree = parser .parse ()
148+ ok , errors = self .xmltree .validate ()
149+ if not ok :
150+ raise forms .ValidationError (errors )
151+ self .xmlroot = self .xmltree .getroot ()
152+ draftname = self .xmlroot .attrib .get ('docName' )
153+ revmatch = re .search ("-[0-9][0-9]$" , draftname )
154+ if revmatch :
155+ self .revision = draftname [- 2 :]
156+ self .filename = draftname [:- 3 ]
157+ else :
158+ self .revision = None
159+ self .filename = draftname
160+ self .title = self .xmlroot .find ('front/title' ).text
161+ self .abstract = self .xmlroot .find ('front/abstract' ).text
162+ self .author_list = []
163+ author_info = self .xmlroot .findall ('front/author' )
164+ for author in author_info :
165+ author_dict = dict (
166+ company = author .find ('organization' ).text ,
167+ last_name = author .attrib .get ('surname' ),
168+ full_name = author .attrib .get ('fullname' ),
169+ email = author .find ('address/email' ).text ,
170+ )
171+ self .author_list .append (author_dict )
172+ line = "%(full_name)s <%(email)s>" % author_dict
173+ self .authors .append (line )
174+ except Exception as e :
175+ raise forms .ValidationError ("Exception: %s" % e )
176+ finally :
177+ os .close (tfh )
178+ os .unlink (tfn )
179+
116180 if self .cleaned_data .get ('txt' ):
117181 # try to parse it
118182 txt_file = self .cleaned_data ['txt' ]
119183 txt_file .seek (0 )
120184 self .parsed_draft = Draft (txt_file .read (), txt_file .name )
185+ self .filename = self .parsed_draft .filename
186+ self .revision = self .parsed_draft .revision
187+ self .title = self .parsed_draft .get_title ()
121188 txt_file .seek (0 )
122189
123- if not self .parsed_draft .filename :
124- raise forms .ValidationError ("Draft parser could not extract a valid draft name from the .txt file" )
190+ if not self .filename :
191+ raise forms .ValidationError ("Draft parser could not extract a valid draft name from the upload" )
192+
193+ if not self .revision :
194+ raise forms .ValidationError ("Draft parser could not extract a valid draft revision from the upload" )
125195
126- if not self .parsed_draft . get_title () :
127- raise forms .ValidationError ("Draft parser could not extract a valid title from the .txt file " )
196+ if not self .title :
197+ raise forms .ValidationError ("Draft parser could not extract a valid title from the upload " )
128198
199+ if self .cleaned_data .get ('txt' ) or self .cleaned_data .get ('xml' ):
129200 # check group
130201 self .group = self .deduce_group ()
131202
132203 # check existing
133- existing = Submission .objects .filter (name = self .parsed_draft . filename , rev = self . parsed_draft .revision ).exclude (state__in = ("posted" , "cancel" ))
204+ existing = Submission .objects .filter (name = self .filename , rev = self .revision ).exclude (state__in = ("posted" , "cancel" ))
134205 if existing :
135206 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 })))
136207
137208 # cut-off
138- if self .parsed_draft . revision == '00' and self .in_first_cut_off :
209+ if self .revision == '00' and self .in_first_cut_off :
139210 raise forms .ValidationError (mark_safe (self .cutoff_warning ))
140211
141212 # check thresholds
142213 today = datetime .date .today ()
143214
144215 self .check_submissions_tresholds (
145- "for the draft %s" % self .parsed_draft . filename ,
146- dict (name = self .parsed_draft . filename , rev = self . parsed_draft .revision , submission_date = today ),
216+ "for the draft %s" % self .filename ,
217+ dict (name = self .filename , rev = self .revision , submission_date = today ),
147218 settings .IDSUBMIT_MAX_DAILY_SAME_DRAFT_NAME , settings .IDSUBMIT_MAX_DAILY_SAME_DRAFT_NAME_SIZE ,
148219 )
149220 self .check_submissions_tresholds (
@@ -163,19 +234,19 @@ def clean(self):
163234 settings .IDSUBMIT_MAX_DAILY_SUBMISSIONS , settings .IDSUBMIT_MAX_DAILY_SUBMISSIONS_SIZE ,
164235 )
165236
166- return super (UploadForm , self ).clean ()
237+ return super (SubmissionUploadForm , self ).clean ()
167238
168239 def check_submissions_tresholds (self , which , filter_kwargs , max_amount , max_size ):
169240 submissions = Submission .objects .filter (** filter_kwargs )
170241
171242 if len (submissions ) > max_amount :
172243 raise forms .ValidationError ("Max submissions %s has been reached for today (maximum is %s submissions)." % (which , max_amount ))
173- if sum (s .file_size for s in submissions ) > max_size * 1024 * 1024 :
244+ if sum (s .file_size for s in submissions if s . file_size ) > max_size * 1024 * 1024 :
174245 raise forms .ValidationError ("Max uploaded amount %s has been reached for today (maximum is %s MB)." % (which , max_size ))
175246
176247 def deduce_group (self ):
177248 """Figure out group from name or previously submitted draft, returns None if individual."""
178- name = self .parsed_draft . filename
249+ name = self .filename
179250 existing_draft = Document .objects .filter (name = name , type = "draft" )
180251 if existing_draft :
181252 group = existing_draft [0 ].group
0 commit comments