Cutoff dates and basic checkings over the plain file. See #580
- Legacy-Id: 2806
This commit is contained in:
parent
8c5ffce3eb
commit
4bc95f6436
|
@ -131,6 +131,7 @@ INSTALLED_APPS = (
|
||||||
'ietf.redirects',
|
'ietf.redirects',
|
||||||
'ietf.idrfc',
|
'ietf.idrfc',
|
||||||
'ietf.wginfo',
|
'ietf.wginfo',
|
||||||
|
'ietf.submit',
|
||||||
)
|
)
|
||||||
|
|
||||||
INTERNAL_IPS = (
|
INTERNAL_IPS = (
|
||||||
|
|
19
ietf/submit/error_manager.py
Normal file
19
ietf/submit/error_manager.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from ietf.submit.models import IdSubmissionStatus
|
||||||
|
|
||||||
|
class ErrorManager(object):
|
||||||
|
ERROR_CODES = {
|
||||||
|
'DEFAULT': 'Unknow error',
|
||||||
|
'INVALID_FILENAME': 111,
|
||||||
|
'EXCEEDED_SIZE': 102,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_error_str(self, key):
|
||||||
|
error_code = self.ERROR_CODES.get(key, self.ERROR_CODES['DEFAULT'])
|
||||||
|
if isinstance(error_code, basestring):
|
||||||
|
return '%s (%s)' % (key, error_code)
|
||||||
|
try:
|
||||||
|
return IdSubmissionStatus.objects.get(status_id=error_code).status_value
|
||||||
|
except IdSubmissionStatus.DoesNotExist:
|
||||||
|
return '%s (%s)' % (self.ERROR_CODES['DEFAULT'], key)
|
||||||
|
|
||||||
|
MainErrorManager=ErrorManager()
|
|
@ -16,6 +16,16 @@ from ietf.liaisons.widgets import (FromWidget, ReadOnlyWidget, ButtonWidget,
|
||||||
ShowAttachmentsWidget, RelatedLiaisonWidget)
|
ShowAttachmentsWidget, RelatedLiaisonWidget)
|
||||||
|
|
||||||
|
|
||||||
|
from ietf.submit.models import IdSubmitDateConfig
|
||||||
|
from ietf.submit.parsers.plain_parser import PlainParser
|
||||||
|
from ietf.submit.parsers.pdf_parser import PDFParser
|
||||||
|
from ietf.submit.parsers.ps_parser import PSParser
|
||||||
|
from ietf.submit.parsers.xml_parser import XMLParser
|
||||||
|
|
||||||
|
|
||||||
|
CUTOFF_HOUR = 17
|
||||||
|
|
||||||
|
|
||||||
class UploadForm(forms.Form):
|
class UploadForm(forms.Form):
|
||||||
|
|
||||||
txt = forms.FileField(label=u'.txt format', required=True)
|
txt = forms.FileField(label=u'.txt format', required=True)
|
||||||
|
@ -28,6 +38,35 @@ class UploadForm(forms.Form):
|
||||||
class Media:
|
class Media:
|
||||||
css = {'all': ("/css/liaisons.css", )}
|
css = {'all': ("/css/liaisons.css", )}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(UploadForm, self).__init__(*args, **kwargs)
|
||||||
|
self.in_first_cut_off = False
|
||||||
|
self.shutdown = False
|
||||||
|
self.read_dates()
|
||||||
|
|
||||||
|
def read_dates(self):
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
first_cut_off = IdSubmitDateConfig.get_first_cut_off()
|
||||||
|
second_cut_off = IdSubmitDateConfig.get_second_cut_off()
|
||||||
|
ietf_monday = IdSubmitDateConfig.get_ietf_monday()
|
||||||
|
processed_ids_date = IdSubmitDateConfig.get_processed_ids_date()
|
||||||
|
monday_after_ietf = IdSubmitDateConfig.get_monday_after_ietf()
|
||||||
|
list_aproved_date = IdSubmitDateConfig.get_list_aproved_date()
|
||||||
|
|
||||||
|
if now.date() >= first_cut_off and now.date() < second_cut_off: # We are in the first_cut_off
|
||||||
|
if now.date() == first_cut_off and now.hour < CUTOFF_HOUR:
|
||||||
|
self.cutoff_warning = 'The pre-meeting cutoff date for new documents (i.e., version -00 Internet-Drafts) is %s at 5 PM (PT). You will not be able to submit a new document after this time until %s, at midnight' % (first_cut_off, ietf_monday)
|
||||||
|
else: # No 00 version allowed
|
||||||
|
self.cutoff_warning = 'The pre-meeting cutoff date for new documents (i.e., version -00 Internet-Drafts) was %s at 5 PM (PT). You will not be able to submit a new document until %s, at midnight.<br>You can still submit a version -01 or higher Internet-Draft until 5 PM (PT), %s' % (first_cut_off, ietf_monday, second_cut_off)
|
||||||
|
self.in_first_cut_off = True
|
||||||
|
elif now.date() >= second_cut_off and now.date() < ietf_monday:
|
||||||
|
if now.date() == second_cut_off and now.hour < CUTOFF_HOUR: # We are in the first_cut_off yet
|
||||||
|
self.cutoff_warning = 'The pre-meeting cutoff date for new documents (i.e., version -00 Internet-Drafts) was %s at 5 PM (PT). You will not be able to submit a new document until %s, at midnight.<br>The I-D submission tool will be shut down at 5 PM (PT) today, and reopened at midnight (PT), %s' % (first_cut_off, ietf_monday, ietf_monday)
|
||||||
|
self.in_first_cut_off = True
|
||||||
|
else: # Completely shut down of the tool
|
||||||
|
self.cutoff_warning = 'The cut off time for the I-D submission was 5 PM (PT), %s.<br>The I-D submission tool will be reopened at midnight, %s' % (second_cut_off, ietf_monday)
|
||||||
|
self.shutdown = True
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.as_div()
|
return self.as_div()
|
||||||
|
|
||||||
|
@ -47,3 +86,28 @@ class UploadForm(forms.Form):
|
||||||
# if there is no fields in this fieldset, we continue to next fieldset
|
# if there is no fields in this fieldset, we continue to next fieldset
|
||||||
continue
|
continue
|
||||||
yield fieldset_dict
|
yield fieldset_dict
|
||||||
|
|
||||||
|
def clean_txt(self):
|
||||||
|
parsed_info = PlainParser(self.cleaned_data['txt']).parse_critical()
|
||||||
|
if parsed_info.errors:
|
||||||
|
raise forms.ValidationError(parsed_info.errors)
|
||||||
|
|
||||||
|
def clean_pdf(self):
|
||||||
|
parsed_info = PDFParser(self.cleaned_data['pdf']).parse_critical()
|
||||||
|
if parsed_info.errors:
|
||||||
|
raise forms.ValidationError(parsed_info.errors)
|
||||||
|
|
||||||
|
def clean_ps(self):
|
||||||
|
parsed_info = PSParser(self.cleaned_data['ps']).parse_critical()
|
||||||
|
if parsed_info.errors:
|
||||||
|
raise forms.ValidationError(parsed_info.errors)
|
||||||
|
|
||||||
|
def clean_xml(self):
|
||||||
|
parsed_info = XMLParser(self.cleaned_data['xml']).parse_critical()
|
||||||
|
if parsed_info.errors:
|
||||||
|
raise forms.ValidationError(parsed_info.errors)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
if self.shutdown:
|
||||||
|
raise forms.ValidationError('The tool is shut down')
|
||||||
|
return super(UploadForm, self).clean()
|
||||||
|
|
42
ietf/submit/models.py
Normal file
42
ietf/submit/models.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class IdSubmissionStatus(models.Model):
|
||||||
|
status_id = models.IntegerField(primary_key=True)
|
||||||
|
status_value = models.CharField(blank=True, max_length=255)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'id_submission_status'
|
||||||
|
|
||||||
|
|
||||||
|
class IdSubmitDateConfig(models.Model):
|
||||||
|
id = models.IntegerField(primary_key=True)
|
||||||
|
id_date = models.DateField(null=True, blank=True)
|
||||||
|
date_name = models.CharField(blank=True, max_length=255)
|
||||||
|
f_name = models.CharField(blank=True, max_length=255)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'id_dates'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_first_cut_off(cls):
|
||||||
|
return cls.objects.get(id=1).id_date
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_second_cut_off(cls):
|
||||||
|
return cls.objects.get(id=2).id_date
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_ietf_monday(cls):
|
||||||
|
return cls.objects.get(id=3).id_date
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_processed_ids_date(cls):
|
||||||
|
return cls.objects.get(id=4).id_date
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_monday_after_ietf(cls):
|
||||||
|
return cls.objects.get(id=5).id_date
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_list_aproved_date(cls):
|
||||||
|
return cls.objects.get(id=6).id_date
|
0
ietf/submit/parsers/__init__.py
Normal file
0
ietf/submit/parsers/__init__.py
Normal file
43
ietf/submit/parsers/base.py
Normal file
43
ietf/submit/parsers/base.py
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import datetime
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
CUTOFF_HOUR = 17
|
||||||
|
|
||||||
|
|
||||||
|
class ParseInfo(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.errors = []
|
||||||
|
self.warnings = {}
|
||||||
|
|
||||||
|
def add_error(self, error_str):
|
||||||
|
self.errors.append(error_str)
|
||||||
|
|
||||||
|
def add_warning(self, warning_type, warning_str):
|
||||||
|
warn_list = self.warnings.get(warning_type, [])
|
||||||
|
self.warnings[warning_type] = warn_list + [warning_str]
|
||||||
|
|
||||||
|
|
||||||
|
class FileParser(object):
|
||||||
|
|
||||||
|
def __init__(self, fd):
|
||||||
|
self.fd = fd
|
||||||
|
self.parsed_info = ParseInfo()
|
||||||
|
|
||||||
|
def parse_critical(self):
|
||||||
|
if not self.fd:
|
||||||
|
return self.parsed_info
|
||||||
|
for attr in dir(self):
|
||||||
|
if attr.startswith('parse_critical_'):
|
||||||
|
method = getattr(self, attr, None)
|
||||||
|
if callable(method):
|
||||||
|
method()
|
||||||
|
return self.parsed_info
|
||||||
|
|
||||||
|
def parse_critical_invalid_chars_in_filename(self):
|
||||||
|
name = self.fd.name
|
||||||
|
regexp = re.compile(r'&|\|\/|;|\*|\s|\$')
|
||||||
|
chars = regexp.findall(name)
|
||||||
|
if chars:
|
||||||
|
self.parsed_info.add_error('Invalid characters were found in the name of the file which was just submitted: %s' % ', '.join(set(chars)))
|
7
ietf/submit/parsers/pdf_parser.py
Normal file
7
ietf/submit/parsers/pdf_parser.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from ietf.submit.parsers.base import FileParser
|
||||||
|
|
||||||
|
class PDFParser(FileParser):
|
||||||
|
|
||||||
|
def parse_critical_filename_extension(self):
|
||||||
|
if not self.fd.name.endswith('.pdf'):
|
||||||
|
self.parsed_info.add_error('Format of this document must be PDF')
|
36
ietf/submit/parsers/plain_parser.py
Normal file
36
ietf/submit/parsers/plain_parser.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
from ietf.submit.error_manager import MainErrorManager
|
||||||
|
from ietf.submit.parsers.base import FileParser
|
||||||
|
|
||||||
|
MAX_PLAIN_FILE_SIZE = 6000000
|
||||||
|
|
||||||
|
class PlainParser(FileParser):
|
||||||
|
|
||||||
|
def parse_critical_max_size(self):
|
||||||
|
if self.fd.size > MAX_PLAIN_FILE_SIZE:
|
||||||
|
self.parsed_info.add_error(MainErrorManager.get_error_str('EXCEEDED_SIZE'))
|
||||||
|
|
||||||
|
def parse_critical_file_charset(self):
|
||||||
|
import magic
|
||||||
|
self.fd.file.seek(0)
|
||||||
|
m = magic.open(magic.MAGIC_MIME)
|
||||||
|
m.load()
|
||||||
|
filetype=m.buffer(self.fd.file.read())
|
||||||
|
if not 'ascii' in filetype:
|
||||||
|
self.parsed_info.add_error('A plain text document must be submitted.');
|
||||||
|
|
||||||
|
def parse_filename(self):
|
||||||
|
self.fd.file.seek(0)
|
||||||
|
draftre = re.compile('(draft-\S+)')
|
||||||
|
limit = 80
|
||||||
|
while limit:
|
||||||
|
line = self.fd.readline()
|
||||||
|
match = draftre.match(line)
|
||||||
|
if not match:
|
||||||
|
continue
|
||||||
|
filename = match.group(0)
|
||||||
|
filename = re.sub('^[^\w]+', '', filename)
|
||||||
|
filename = re.sub('[^\w]+$', '', filename)
|
||||||
|
filename = re.sub('\.txt$', '', filename)
|
||||||
|
line = re.sub('^[^\w]+', '')
|
7
ietf/submit/parsers/ps_parser.py
Normal file
7
ietf/submit/parsers/ps_parser.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from ietf.submit.parsers.base import FileParser
|
||||||
|
|
||||||
|
class PSParser(FileParser):
|
||||||
|
|
||||||
|
def parse_critical_filename_extension(self):
|
||||||
|
if not self.fd.name.endswith('.ps'):
|
||||||
|
self.parsed_info.add_error('Format of this document must be PS')
|
7
ietf/submit/parsers/xml_parser.py
Normal file
7
ietf/submit/parsers/xml_parser.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from ietf.submit.parsers.base import FileParser
|
||||||
|
|
||||||
|
class XMLParser(FileParser):
|
||||||
|
|
||||||
|
def parse_critical_filename_extension(self):
|
||||||
|
if not self.fd.name.endswith('.xml'):
|
||||||
|
self.parsed_info.add_error('Format of this document must be XML')
|
|
@ -18,6 +18,8 @@ from ietf.submit.forms import UploadForm
|
||||||
def submit_index(request):
|
def submit_index(request):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = UploadForm(data=request.POST, files=request.FILES)
|
form = UploadForm(data=request.POST, files=request.FILES)
|
||||||
|
if form.is_valid():
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
form = UploadForm()
|
form = UploadForm()
|
||||||
return render_to_response('submit/submit_index.html',
|
return render_to_response('submit/submit_index.html',
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
}
|
}
|
||||||
.ietf-navset .selected { font-weight:bold; padding: 0 3px; }
|
.ietf-navset .selected { font-weight:bold; padding: 0 3px; }
|
||||||
.ietf-navset a, .ietf-navset a:visited { color: white; padding:0 3px; }
|
.ietf-navset a, .ietf-navset a:visited { color: white; padding:0 3px; }
|
||||||
|
.cutoff-warning { border: 1px dashed red; background-color: #ffeeaa; padding: 1em 2em; margin: 1em 0px; }
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
@ -21,6 +22,12 @@
|
||||||
{% ifequal selected "notewell" %}<span class="selected">NOTE WELL</span>{% else %}<a href="{% url submit_note_well %}">NOTE WELL</a>{% endifequal %}
|
{% ifequal selected "notewell" %}<span class="selected">NOTE WELL</span>{% else %}<a href="{% url submit_note_well %}">NOTE WELL</a>{% endifequal %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if form.cutoff_warning %}
|
||||||
|
<div class="cutoff-warning">
|
||||||
|
{{ form.cutoff_warning|safe }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% block submit_content %}
|
{% block submit_content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -42,9 +42,11 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if not form.shutdown %}
|
||||||
<div class="submitrow">
|
<div class="submitrow">
|
||||||
<input type="submit" value="Upload" name="upload" />
|
<input type="submit" value="Upload" name="upload" />
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
Loading…
Reference in a new issue