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.idrfc',
|
||||
'ietf.wginfo',
|
||||
'ietf.submit',
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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):
|
||||
|
||||
txt = forms.FileField(label=u'.txt format', required=True)
|
||||
|
@ -28,6 +38,35 @@ class UploadForm(forms.Form):
|
|||
class Media:
|
||||
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):
|
||||
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
|
||||
continue
|
||||
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):
|
||||
if request.method == 'POST':
|
||||
form = UploadForm(data=request.POST, files=request.FILES)
|
||||
if form.is_valid():
|
||||
pass
|
||||
else:
|
||||
form = UploadForm()
|
||||
return render_to_response('submit/submit_index.html',
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
}
|
||||
.ietf-navset .selected { font-weight:bold; 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 %}
|
||||
|
||||
{% 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 %}
|
||||
</div>
|
||||
|
||||
{% if form.cutoff_warning %}
|
||||
<div class="cutoff-warning">
|
||||
{{ form.cutoff_warning|safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block submit_content %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -42,9 +42,11 @@
|
|||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if not form.shutdown %}
|
||||
<div class="submitrow">
|
||||
<input type="submit" value="Upload" name="upload" />
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
|
Loading…
Reference in a new issue