Skip to content

Commit 3af2554

Browse files
committed
Added an API for draft submission, at /api/submit. Added an urls.py file under api/ to hold api urls, and moved those from ietf/urls.py. Refactored out many parts of the regular submission forms and functions in submit/forms.py and submit/views.py in order to re-use the appropriate parts for the submission API. Moved support functions to submit/utils.py. Added a new validation errors for missing docName in xml-based submissions. Updated the submission test document templates to use insert additional values. Added failure and success test cases for automated API submissions, and refactored some test utility functions.
- Legacy-Id: 14125
1 parent da23da1 commit 3af2554

9 files changed

Lines changed: 520 additions & 280 deletions

File tree

ietf/api/urls.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright The IETF Trust 2017, All Rights Reserved
2+
3+
from django.conf.urls import include
4+
5+
from ietf import api
6+
from ietf.meeting import views as meeting_views
7+
from ietf.submit import views as submit_views
8+
from ietf.utils.urls import url
9+
10+
api.autodiscover()
11+
12+
urlpatterns = [
13+
# Top endpoint for Tastypie's REST API (this isn't standard Tastypie):
14+
url(r'^v1/?$', api.top_level),
15+
# Custom API endpoints
16+
url(r'^notify/meeting/import_recordings/(?P<number>[a-z0-9-]+)/?$', meeting_views.api_import_recordings),
17+
url(r'^submit/?$', submit_views.api_submit),
18+
]
19+
# Additional (standard) Tastypie endpoints
20+
for n,a in api._api_list:
21+
urlpatterns += [
22+
url(r'^v1/', include(a.urls)),
23+
]
24+

ietf/submit/forms.py

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,11 @@
3131
from ietf.submit.parsers.xml_parser import XMLParser
3232
from ietf.utils.draft import Draft
3333

34-
class SubmissionUploadForm(forms.Form):
35-
txt = forms.FileField(label=u'.txt format', required=False)
36-
xml = forms.FileField(label=u'.xml format', required=False)
37-
pdf = forms.FileField(label=u'.pdf format', required=False)
38-
ps = forms.FileField(label=u'.ps format', required=False)
34+
class SubmissionBaseUploadForm(forms.Form):
35+
xml = forms.FileField(label=u'.xml format', required=True)
3936

4037
def __init__(self, request, *args, **kwargs):
41-
super(SubmissionUploadForm, self).__init__(*args, **kwargs)
38+
super(SubmissionBaseUploadForm, self).__init__(*args, **kwargs)
4239

4340
self.remote_ip = request.META.get('REMOTE_ADDR', None)
4441

@@ -56,6 +53,14 @@ def __init__(self, request, *args, **kwargs):
5653
self.authors = []
5754
self.parsed_draft = None
5855
self.file_types = []
56+
# No code currently (14 Sep 2017) uses this class directly; it is
57+
# only used through its subclasses. The two assignments below are
58+
# set to trigger an exception if it is used directly only to make
59+
# sure that adequate consideration is made if it is decided to use it
60+
# directly in the future. Feel free to set these appropriately to
61+
# avoid the exceptions in that case:
62+
self.formats = None # None will raise an exception in clean() if this isn't changed in a subclass
63+
self.base_formats = None # None will raise an exception in clean() if this isn't changed in a subclass
5964

6065
def set_cutoff_warnings(self):
6166
now = datetime.datetime.now(pytz.utc)
@@ -96,6 +101,7 @@ def set_cutoff_warnings(self):
96101
'The last submission time for the I-D submission was %s.<br/><br>'
97102
'The I-D submission tool will be reopened after %s (IETF-meeting local time).' % (cutoff_01_str, reopen_str))
98103
self.shutdown = True
104+
99105
def clean_file(self, field_name, parser_class):
100106
f = self.cleaned_data[field_name]
101107
if not f:
@@ -107,29 +113,20 @@ def clean_file(self, field_name, parser_class):
107113

108114
return f
109115

110-
def clean_txt(self):
111-
return self.clean_file("txt", PlainParser)
112-
113-
def clean_pdf(self):
114-
return self.clean_file("pdf", PDFParser)
115-
116-
def clean_ps(self):
117-
return self.clean_file("ps", PSParser)
118-
119116
def clean_xml(self):
120117
return self.clean_file("xml", XMLParser)
121118

122119
def clean(self):
123120
if self.shutdown and not has_role(self.request.user, "Secretariat"):
124121
raise forms.ValidationError('The submission tool is currently shut down')
125122

126-
for ext in ['txt', 'pdf', 'xml', 'ps']:
123+
for ext in self.formats:
127124
f = self.cleaned_data.get(ext, None)
128125
if not f:
129126
continue
130127
self.file_types.append('.%s' % ext)
131128
if not ('.txt' in self.file_types or '.xml' in self.file_types):
132-
raise forms.ValidationError('You must submit at least a valid .txt or a valid .xml file; didn\'t find either.')
129+
raise forms.ValidationError('Unexpected submission file types; found %s, but %s is required' % (', '.join(self.file_types), ' or '.join(self.base_formats)))
133130

134131
#debug.show('self.cleaned_data["xml"]')
135132
if self.cleaned_data.get('xml'):
@@ -168,6 +165,8 @@ def clean(self):
168165
)
169166
self.xmlroot = self.xmltree.getroot()
170167
draftname = self.xmlroot.attrib.get('docName')
168+
if draftname is None:
169+
raise forms.ValidationError("No docName attribute found in the xml root element")
171170
revmatch = re.search("-[0-9][0-9]$", draftname)
172171
if revmatch:
173172
self.revision = draftname[-2:]
@@ -273,7 +272,7 @@ def clean(self):
273272
settings.IDSUBMIT_MAX_DAILY_SUBMISSIONS, settings.IDSUBMIT_MAX_DAILY_SUBMISSIONS_SIZE,
274273
)
275274

276-
return super(SubmissionUploadForm, self).clean()
275+
return super(SubmissionBaseUploadForm, self).clean()
277276

278277
def check_submissions_tresholds(self, which, filter_kwargs, max_amount, max_size):
279278
submissions = Submission.objects.filter(**filter_kwargs)
@@ -332,6 +331,34 @@ def deduce_group(self):
332331
else:
333332
return None
334333

334+
class SubmissionManualUploadForm(SubmissionBaseUploadForm):
335+
xml = forms.FileField(label=u'.xml format', required=False) # xml field with required=False instead of True
336+
txt = forms.FileField(label=u'.txt format', required=False)
337+
pdf = forms.FileField(label=u'.pdf format', required=False)
338+
ps = forms.FileField(label=u'.ps format', required=False)
339+
340+
def __init__(self, request, *args, **kwargs):
341+
super(SubmissionManualUploadForm, self).__init__(request, *args, **kwargs)
342+
self.formats = ['txt', 'pdf', 'xml', 'ps', ]
343+
self.base_formats = ['txt', 'xml', ]
344+
345+
def clean_txt(self):
346+
return self.clean_file("txt", PlainParser)
347+
348+
def clean_pdf(self):
349+
return self.clean_file("pdf", PDFParser)
350+
351+
def clean_ps(self):
352+
return self.clean_file("ps", PSParser)
353+
354+
class SubmissionAutoUploadForm(SubmissionBaseUploadForm):
355+
user = forms.EmailField(required=True)
356+
357+
def __init__(self, request, *args, **kwargs):
358+
super(SubmissionAutoUploadForm, self).__init__(request, *args, **kwargs)
359+
self.formats = ['xml', ]
360+
self.base_formats = ['xml', ]
361+
335362
class NameEmailForm(forms.Form):
336363
name = forms.CharField(required=True)
337364
email = forms.EmailField(label=u'Email address', required=True)

ietf/submit/test_submission.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33

44

5-
Network Working Group A. Name
5+
Network Working Group %(initials)s %(surname)s
66
Internet-Draft Test Centre Inc.
77
Intended status: Informational %(month)s %(year)s
88
Expires: %(expiration)s
@@ -180,13 +180,13 @@ Table of Contents
180180

181181
Author's Address
182182

183-
Author Name
183+
%(author)s
184184
Test Centre Inc.
185185
42 Some Road
186186
Some Where 12345
187187
UK
188188

189-
Email: author@example.com
189+
Email: %(email)s
190190

191191

192192

ietf/submit/test_submission.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
<?rfc toc="yes"?>
44
<rfc category="info" docName="%(name)s" ipr="trust200902">
55
<front>
6-
<title>Testing&nbsp;Tests</title>
7-
<author fullname="Author Name" initials="A." surname="Name">
6+
<title>%(title)s</title>
7+
<author fullname="%(author)s" initials="%(initials)s" surname="%(surname)s">
88
<organization>Test Centre Inc.</organization>
99

1010
<address>
@@ -13,7 +13,7 @@
1313
<city>Some Where 12345</city>
1414
<country>UK</country>
1515
</postal>
16-
<email>author@example.com</email>
16+
<email>%(email)s</email>
1717
</address>
1818
</author>
1919
<date month="%(month)s" year="%(year)s" />

ietf/submit/test_submission_invalid_yang.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,13 @@ Table of Contents
180180

181181
Author's Address
182182

183-
Author Name
183+
%(author)s
184184
Test Centre Inc.
185185
42 Some Road
186186
Some Where 12345
187187
UK
188188

189-
Email: author@example.com
189+
Email: %(email)s
190190

191191

192192

0 commit comments

Comments
 (0)