Merged branch/yaco/idsubmit@2903 from esanches@yaco.es to trunk: The Rewritten I-D Submission Tool.
- Legacy-Id: 3036
This commit is contained in:
commit
842b8f428f
|
@ -173,9 +173,9 @@ class InternetDraft(models.Model):
|
|||
idinternal = FKAsOneToOne('idinternal', reverse=True, query=models.Q(rfc_flag = 0))
|
||||
def __str__(self):
|
||||
return self.filename
|
||||
def save(self):
|
||||
def save(self, *args, **kwargs):
|
||||
self.id_document_key = self.title.upper()
|
||||
super(InternetDraft, self).save()
|
||||
super(InternetDraft, self).save(*args, **kwargs)
|
||||
def displayname(self):
|
||||
return self.filename
|
||||
def file_tag(self):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from ietf.idtracker.models import Acronym, PersonOrOrgInfo, IRTF, AreaGroup, Area, IETFWG
|
||||
import datetime
|
||||
#from ietf.utils import log
|
||||
|
@ -149,6 +150,23 @@ class Meeting(models.Model):
|
|||
class Meta:
|
||||
db_table = 'meetings'
|
||||
|
||||
@classmethod
|
||||
def get_first_cut_off(cls):
|
||||
start_date = cls.objects.all().order_by('-start_date')[0].start_date
|
||||
offset = datetime.timedelta(days=settings.FIRST_CUTOFF_DAYS)
|
||||
return start_date - offset
|
||||
|
||||
@classmethod
|
||||
def get_second_cut_off(cls):
|
||||
start_date = cls.objects.all().order_by('-start_date')[0].start_date
|
||||
offset = datetime.timedelta(days=settings.SECOND_CUTOFF_DAYS)
|
||||
return start_date - offset
|
||||
|
||||
@classmethod
|
||||
def get_ietf_monday(cls):
|
||||
start_date = cls.objects.all().order_by('-start_date')[0].start_date
|
||||
return start_date + datetime.timedelta(days=-start_date.weekday(), weeks=1)
|
||||
|
||||
class MeetingVenue(models.Model):
|
||||
meeting_num = models.ForeignKey(Meeting, db_column='meeting_num', unique=True)
|
||||
break_area_name = models.CharField(max_length=255)
|
||||
|
|
|
@ -132,6 +132,7 @@ INSTALLED_APPS = (
|
|||
'ietf.redirects',
|
||||
'ietf.idrfc',
|
||||
'ietf.wginfo',
|
||||
'ietf.submit',
|
||||
)
|
||||
|
||||
INTERNAL_IPS = (
|
||||
|
@ -192,6 +193,30 @@ LIAISON_UNIVERSAL_FROM = 'Liaison Statement Management Tool <lsmt@' + IETF_DOMAI
|
|||
LIAISON_ATTACH_PATH = '/a/www/ietf-datatracker/documents/LIAISON/'
|
||||
LIAISON_ATTACH_URL = '/documents/LIAISON/'
|
||||
|
||||
# ID Submission Tool settings
|
||||
IDST_FROM_EMAIL = 'IETF I-D Submission Tool <idsubmission@ietf.org>'
|
||||
IDST_TO_EMAIL = 'internet-drafts@ietf.org'
|
||||
|
||||
# Days from meeting to cut off dates on submit
|
||||
FIRST_CUTOFF_DAYS = 5
|
||||
SECOND_CUTOFF_DAYS = 3
|
||||
|
||||
STAGING_PATH = '/a/www/www6s/staging/'
|
||||
STAGING_URL = 'http://www.ietf.org/staging/'
|
||||
IDNITS_PATH = '/a/www/ietf-datatracker/release/idnits'
|
||||
MAX_PLAIN_DRAFT_SIZE = 6291456 # Max size of the txt draft in bytes
|
||||
|
||||
# DOS THRESHOLDS PER DAY (Sizes are in MB)
|
||||
MAX_SAME_DRAFT_NAME = 20
|
||||
MAX_SAME_DRAFT_NAME_SIZE = 50
|
||||
MAX_SAME_SUBMITTER = 50
|
||||
MAX_SAME_SUBMITTER_SIZE = 150
|
||||
MAX_SAME_WG_DRAFT = 150
|
||||
MAX_SAME_WG_DRAFT_SIZE = 450
|
||||
MAX_DAILY_SUBMISSION = 1000
|
||||
MAX_DAILY_SUBMISSION_SIZE = 2000
|
||||
# End of ID Submission Tool settings
|
||||
|
||||
# Put SECRET_KEY in here, or any other sensitive or site-specific
|
||||
# changes. DO NOT commit settings_local.py to svn.
|
||||
from settings_local import *
|
||||
|
|
0
ietf/submit/__init__.py
Normal file
0
ietf/submit/__init__.py
Normal file
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()
|
467
ietf/submit/forms.py
Normal file
467
ietf/submit/forms.py
Normal file
|
@ -0,0 +1,467 @@
|
|||
import sha
|
||||
import random
|
||||
import os
|
||||
import subprocess
|
||||
import datetime
|
||||
|
||||
from django import forms
|
||||
from django.forms.fields import email_re
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.html import mark_safe
|
||||
|
||||
from ietf.idtracker.models import InternetDraft, IETFWG
|
||||
from ietf.proceedings.models import Meeting
|
||||
from ietf.submit.models import IdSubmissionDetail, TempIdAuthors
|
||||
from ietf.submit.utils import MANUAL_POST_REQUESTED, NONE_WG, UPLOADED, WAITING_AUTHENTICATION
|
||||
from ietf.submit.parsers.pdf_parser import PDFParser
|
||||
from ietf.submit.parsers.plain_parser import PlainParser
|
||||
from ietf.submit.parsers.ps_parser import PSParser
|
||||
from ietf.submit.parsers.xml_parser import XMLParser
|
||||
from ietf.utils.mail import send_mail
|
||||
from ietf.utils.draft import Draft
|
||||
|
||||
|
||||
CUTOFF_HOUR = 17
|
||||
|
||||
|
||||
class UploadForm(forms.Form):
|
||||
|
||||
txt = forms.FileField(label=u'.txt format', required=True)
|
||||
xml = forms.FileField(label=u'.xml format', required=False)
|
||||
pdf = forms.FileField(label=u'.pdf format', required=False)
|
||||
ps = forms.FileField(label=u'.ps format', required=False)
|
||||
|
||||
fieldsets = [('Upload a draft', ('txt', 'xml', 'pdf', 'ps'))]
|
||||
|
||||
class Media:
|
||||
css = {'all': ("/css/liaisons.css", )}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.request=kwargs.pop('request', None)
|
||||
self.remote_ip=self.request.META.get('REMOTE_ADDR', None)
|
||||
super(UploadForm, self).__init__(*args, **kwargs)
|
||||
self.in_first_cut_off = False
|
||||
self.idnits_message = None
|
||||
self.shutdown = False
|
||||
self.draft = None
|
||||
self.filesize = None
|
||||
self.group = None
|
||||
self.file_type = []
|
||||
self.read_dates()
|
||||
|
||||
def read_dates(self):
|
||||
now = datetime.datetime.utcnow()
|
||||
first_cut_off = Meeting.get_first_cut_off()
|
||||
second_cut_off = Meeting.get_second_cut_off()
|
||||
ietf_monday = Meeting.get_ietf_monday()
|
||||
|
||||
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()
|
||||
|
||||
def as_div(self):
|
||||
return render_to_string('submit/submitform.html', {'form': self})
|
||||
|
||||
def get_fieldsets(self):
|
||||
if not self.fieldsets:
|
||||
yield dict(name=None, fields=self)
|
||||
else:
|
||||
for fieldset, fields in self.fieldsets:
|
||||
fieldset_dict = dict(name=fieldset, fields=[])
|
||||
for field_name in fields:
|
||||
if field_name in self.fields.keyOrder:
|
||||
fieldset_dict['fields'].append(self[field_name])
|
||||
if not fieldset_dict['fields']:
|
||||
# if there is no fields in this fieldset, we continue to next fieldset
|
||||
continue
|
||||
yield fieldset_dict
|
||||
|
||||
def clean_txt(self):
|
||||
txt_file = self.cleaned_data['txt']
|
||||
if not txt_file:
|
||||
return txt_file
|
||||
parsed_info = PlainParser(txt_file).critical_parse()
|
||||
if parsed_info.errors:
|
||||
raise forms.ValidationError(parsed_info.errors)
|
||||
self.filesize=txt_file.size
|
||||
return txt_file
|
||||
|
||||
def clean_pdf(self):
|
||||
pdf_file = self.cleaned_data['pdf']
|
||||
if not pdf_file:
|
||||
return pdf_file
|
||||
parsed_info = PDFParser(pdf_file).critical_parse()
|
||||
if parsed_info.errors:
|
||||
raise forms.ValidationError(parsed_info.errors)
|
||||
return pdf_file
|
||||
|
||||
def clean_ps(self):
|
||||
ps_file = self.cleaned_data['ps']
|
||||
if not ps_file:
|
||||
return ps_file
|
||||
parsed_info = PSParser(ps_file).critical_parse()
|
||||
if parsed_info.errors:
|
||||
raise forms.ValidationError(parsed_info.errors)
|
||||
return ps_file
|
||||
|
||||
def clean_xml(self):
|
||||
xml_file = self.cleaned_data['xml']
|
||||
if not xml_file:
|
||||
return xml_file
|
||||
parsed_info = XMLParser(xml_file).critical_parse()
|
||||
if parsed_info.errors:
|
||||
raise forms.ValidationError(parsed_info.errors)
|
||||
return xml_file
|
||||
|
||||
def clean(self):
|
||||
if self.shutdown:
|
||||
raise forms.ValidationError('The tool is shut down')
|
||||
self.check_paths()
|
||||
if self.cleaned_data.get('txt', None):
|
||||
self.get_draft()
|
||||
self.group=self.get_working_group()
|
||||
self.check_previous_submission()
|
||||
if self.draft.revision == '00' and self.in_first_cut_off:
|
||||
raise forms.ValidationError(mark_safe(self.cutoff_warning))
|
||||
self.check_tresholds()
|
||||
return super(UploadForm, self).clean()
|
||||
|
||||
def check_tresholds(self):
|
||||
filename = self.draft.filename
|
||||
revision = self.draft.revision
|
||||
remote_ip = self.remote_ip
|
||||
today = datetime.date.today()
|
||||
|
||||
# Same draft by name
|
||||
same_name = IdSubmissionDetail.objects.filter(filename=filename, revision=revision, submission_date=today)
|
||||
if same_name.count() > settings.MAX_SAME_DRAFT_NAME:
|
||||
raise forms.ValidationError('A same I-D cannot be submitted more than %s times a day' % settings.MAX_SAME_DRAFT_NAME)
|
||||
if sum([i.filesize for i in same_name]) > (settings.MAX_SAME_DRAFT_NAME_SIZE * 1048576):
|
||||
raise forms.ValidationError('A same I-D submission cannot exceed more than %s MByte a day' % settings.MAX_SAME_DRAFT_NAME_SIZE)
|
||||
|
||||
# Total from same ip
|
||||
same_ip = IdSubmissionDetail.objects.filter(remote_ip=remote_ip, submission_date=today)
|
||||
if same_ip.count() > settings.MAX_SAME_SUBMITTER:
|
||||
raise forms.ValidationError('The same submitter cannot submit more than %s I-Ds a day' % settings.MAX_SAME_SUBMITTER)
|
||||
if sum([i.filesize for i in same_ip]) > (settings.MAX_SAME_SUBMITTER_SIZE * 1048576):
|
||||
raise forms.ValidationError('The same submitter cannot exceed more than %s MByte a day' % settings.MAX_SAME_SUBMITTER_SIZE)
|
||||
|
||||
# Total in same group
|
||||
if self.group:
|
||||
same_group = IdSubmissionDetail.objects.filter(group_acronym=self.group, submission_date=today)
|
||||
if same_group.count() > settings.MAX_SAME_WG_DRAFT:
|
||||
raise forms.ValidationError('A same working group I-Ds cannot be submitted more than %s times a day' % settings.MAX_SAME_WG_DRAFT)
|
||||
if sum([i.filesize for i in same_group]) > (settings.MAX_SAME_WG_DRAFT_SIZE * 1048576):
|
||||
raise forms.ValidationError('Total size of same working group I-Ds cannot exceed %s MByte a day' % settings.MAX_SAME_WG_DRAFT_SIZE)
|
||||
|
||||
|
||||
# Total drafts for today
|
||||
total_today = IdSubmissionDetail.objects.filter(submission_date=today)
|
||||
if total_today.count() > settings.MAX_DAILY_SUBMISSION:
|
||||
raise forms.ValidationError('The total number of today\'s submission has reached the maximum number of submission per day')
|
||||
if sum([i.filesize for i in total_today]) > (settings.MAX_DAILY_SUBMISSION_SIZE * 1048576):
|
||||
raise forms.ValidationError('The total size of today\'s submission has reached the maximum size of submission per day')
|
||||
|
||||
def check_paths(self):
|
||||
self.staging_path = getattr(settings, 'STAGING_PATH', None)
|
||||
self.idnits = getattr(settings, 'IDNITS_PATH', None)
|
||||
if not self.staging_path:
|
||||
raise forms.ValidationError('STAGING_PATH not defined on settings.py')
|
||||
if not os.path.exists(self.staging_path):
|
||||
raise forms.ValidationError('STAGING_PATH defined on settings.py does not exist')
|
||||
if not self.idnits:
|
||||
raise forms.ValidationError('IDNITS_PATH not defined on settings.py')
|
||||
if not os.path.exists(self.idnits):
|
||||
raise forms.ValidationError('IDNITS_PATH defined on settings.py does not exist')
|
||||
|
||||
def check_previous_submission(self):
|
||||
filename = self.draft.filename
|
||||
revision = self.draft.revision
|
||||
existing = IdSubmissionDetail.objects.filter(filename=filename, revision=revision,
|
||||
status__pk__gte=0, status__pk__lt=100)
|
||||
if existing:
|
||||
raise forms.ValidationError(mark_safe('Duplicate Internet-Draft submission is currently in process. <a href="/submit/status/%s/">Check it here</a>' % existing[0].pk))
|
||||
|
||||
def get_draft(self):
|
||||
if self.draft:
|
||||
return self.draft
|
||||
txt_file = self.cleaned_data['txt']
|
||||
txt_file.seek(0)
|
||||
self.draft = Draft(txt_file.read())
|
||||
txt_file.seek(0)
|
||||
return self.draft
|
||||
|
||||
def save(self):
|
||||
for ext in ['txt', 'pdf', 'xml', 'ps']:
|
||||
fd = self.cleaned_data[ext]
|
||||
if not fd:
|
||||
continue
|
||||
self.file_type.append('.%s' % ext)
|
||||
filename = os.path.join(self.staging_path, '%s-%s.%s' % (self.draft.filename, self.draft.revision, ext))
|
||||
destination = open(filename, 'wb+')
|
||||
for chunk in fd.chunks():
|
||||
destination.write(chunk)
|
||||
destination.close()
|
||||
self.check_idnits()
|
||||
return self.save_draft_info(self.draft)
|
||||
|
||||
def check_idnits(self):
|
||||
filepath = os.path.join(self.staging_path, '%s-%s.txt' % (self.draft.filename, self.draft.revision))
|
||||
p = subprocess.Popen([self.idnits, '--submitcheck', '--nitcount', filepath], stdout=subprocess.PIPE)
|
||||
self.idnits_message = p.stdout.read()
|
||||
|
||||
def get_working_group(self):
|
||||
filename = self.draft.filename
|
||||
existing_draft = InternetDraft.objects.filter(filename=filename)
|
||||
if existing_draft:
|
||||
group = existing_draft[0].group and existing_draft[0].group.ietfwg or None
|
||||
if group and group.pk != NONE_WG:
|
||||
return group
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
if filename.startswith('draft-ietf-'):
|
||||
# Extra check for WG that contains dashes
|
||||
for group in IETFWG.objects.filter(group_acronym__acronym__contains='-'):
|
||||
if filename.startswith('draft-ietf-%s-' % group.group_acronym.acronym):
|
||||
return group
|
||||
group_acronym = filename.split('-')[2]
|
||||
try:
|
||||
return IETFWG.objects.get(group_acronym__acronym=group_acronym)
|
||||
except IETFWG.DoesNotExist:
|
||||
raise forms.ValidationError('There is no active group with acronym \'%s\', please rename your draft' % group_acronym)
|
||||
else:
|
||||
return None
|
||||
|
||||
def save_draft_info(self, draft):
|
||||
document_id = 0
|
||||
existing_draft = InternetDraft.objects.filter(filename=draft.filename)
|
||||
if existing_draft:
|
||||
document_id = existing_draft[0].id_document_tag
|
||||
detail = IdSubmissionDetail.objects.create(
|
||||
id_document_name=draft.get_title(),
|
||||
filename=draft.filename,
|
||||
revision=draft.revision,
|
||||
txt_page_count=draft.get_pagecount(),
|
||||
filesize=self.filesize,
|
||||
creation_date=draft.get_creation_date(),
|
||||
submission_date=datetime.date.today(),
|
||||
idnits_message=self.idnits_message,
|
||||
temp_id_document_tag=document_id,
|
||||
group_acronym=self.group,
|
||||
remote_ip=self.remote_ip,
|
||||
first_two_pages=''.join(draft.pages[:2]),
|
||||
status_id=UPLOADED,
|
||||
abstract=draft.get_abstract(),
|
||||
file_type=','.join(self.file_type),
|
||||
)
|
||||
order = 0
|
||||
for author in draft.get_author_info():
|
||||
full_name, first_name, middle_initial, last_name, name_suffix, email = author
|
||||
order += 1
|
||||
TempIdAuthors.objects.create(
|
||||
id_document_tag=document_id,
|
||||
first_name=first_name,
|
||||
middle_initial=middle_initial,
|
||||
last_name=last_name,
|
||||
name_suffix=name_suffix,
|
||||
email_address=email,
|
||||
author_order=order,
|
||||
submission=detail)
|
||||
return detail
|
||||
|
||||
|
||||
class AutoPostForm(forms.Form):
|
||||
|
||||
first_name = forms.CharField(label=u'Given name', required=True)
|
||||
last_name = forms.CharField(label=u'Last name', required=True)
|
||||
email = forms.EmailField(label=u'Email address', required=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.draft = kwargs.pop('draft', None)
|
||||
self.validation = kwargs.pop('validation', None)
|
||||
super(AutoPostForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_author_buttons(self):
|
||||
button_template = '<input type="button" onclick="jQuery(\'#id_first_name\').val(\'%(first_name)s\');jQuery(\'#id_last_name\').val(\'%(last_name)s\');jQuery(\'#id_email\').val(\'%(email)s\');" value="%(full_name)s" />'
|
||||
buttons = []
|
||||
for i in self.validation.authors:
|
||||
full_name = '%s. %s' % (i.first_name[0], i.last_name)
|
||||
buttons.append(button_template % {'first_name': i.first_name,
|
||||
'last_name': i.last_name,
|
||||
'email': i.email()[1] or '',
|
||||
'full_name': full_name})
|
||||
return ''.join(buttons)
|
||||
|
||||
def save(self, request):
|
||||
self.save_submitter_info()
|
||||
self.save_new_draft_info()
|
||||
self.send_confirmation_mail(request)
|
||||
|
||||
def send_confirmation_mail(self, request):
|
||||
subject = 'Confirmation for Auto-Post of I-D %s' % self.draft.filename
|
||||
from_email = settings.IDST_FROM_EMAIL
|
||||
to_email = self.cleaned_data['email']
|
||||
send_mail(request, to_email, from_email, subject, 'submit/confirm_autopost.txt',
|
||||
{'draft': self.draft, 'domain': Site.objects.get_current().domain })
|
||||
|
||||
def save_submitter_info(self):
|
||||
return TempIdAuthors.objects.create(
|
||||
id_document_tag=self.draft.temp_id_document_tag,
|
||||
first_name=self.cleaned_data['first_name'],
|
||||
last_name=self.cleaned_data['last_name'],
|
||||
email_address=self.cleaned_data['email'],
|
||||
author_order=0,
|
||||
submission=self.draft)
|
||||
|
||||
def save_new_draft_info(self):
|
||||
salt = sha.new(str(random.random())).hexdigest()[:5]
|
||||
self.draft.auth_key = sha.new(salt+self.cleaned_data['email']).hexdigest()
|
||||
self.draft.status_id = WAITING_AUTHENTICATION
|
||||
self.draft.save()
|
||||
|
||||
|
||||
class MetaDataForm(AutoPostForm):
|
||||
|
||||
title = forms.CharField(label=u'Title', required=True)
|
||||
version = forms.CharField(label=u'Version', required=True)
|
||||
creation_date = forms.DateField(label=u'Creation date', required=True)
|
||||
pages = forms.IntegerField(label=u'Pages', required=True)
|
||||
abstract = forms.CharField(label=u'Abstract', widget=forms.Textarea, required=True)
|
||||
first_name = forms.CharField(label=u'Given name', required=True)
|
||||
last_name = forms.CharField(label=u'Last name', required=True)
|
||||
email = forms.EmailField(label=u'Email address', required=True)
|
||||
comments = forms.CharField(label=u'Comments to the secretariat', widget=forms.Textarea, required=False)
|
||||
fields = ['title', 'version', 'creation_date', 'pages', 'abstract', 'first_name', 'last_name', 'email', 'comments']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MetaDataForm, self).__init__(*args, **kwargs)
|
||||
self.set_initials()
|
||||
self.authors = self.get_initial_authors()
|
||||
|
||||
def get_initial_authors(self):
|
||||
authors=[]
|
||||
if self.is_bound:
|
||||
for key, value in self.data.items():
|
||||
if key.startswith('first_name_'):
|
||||
author = {'errors': {}}
|
||||
index = key.replace('first_name_', '')
|
||||
first_name = value.strip()
|
||||
if not first_name:
|
||||
author['errors']['first_name'] = 'This field is required'
|
||||
last_name = self.data.get('last_name_%s' % index, '').strip()
|
||||
if not last_name:
|
||||
author['errors']['last_name'] = 'This field is required'
|
||||
email = self.data.get('email_%s' % index, '').strip()
|
||||
if email and not email_re.search(email):
|
||||
author['errors']['email'] = 'Enter a valid e-mail address'
|
||||
if first_name or last_name or email:
|
||||
author.update({'first_name': first_name,
|
||||
'last_name': last_name,
|
||||
'email': ('%s %s' % (first_name, last_name), email),
|
||||
'index': index,
|
||||
})
|
||||
authors.append(author)
|
||||
authors.sort(lambda x,y: cmp(int(x['index']), int(y['index'])))
|
||||
return authors
|
||||
|
||||
def set_initials(self):
|
||||
self.fields['pages'].initial=self.draft.txt_page_count
|
||||
self.fields['creation_date'].initial=self.draft.creation_date
|
||||
self.fields['version'].initial=self.draft.revision
|
||||
self.fields['abstract'].initial=self.draft.abstract
|
||||
self.fields['title'].initial=self.draft.id_document_name
|
||||
|
||||
def clean_creation_date(self):
|
||||
creation_date = self.cleaned_data.get('creation_date', None)
|
||||
if not creation_date:
|
||||
return None
|
||||
submit_date = self.draft.submission_date
|
||||
if creation_date > submit_date:
|
||||
raise forms.ValidationError('Creation Date must not be set after submission date')
|
||||
if creation_date + datetime.timedelta(days=3) < submit_date:
|
||||
raise forms.ValidationError('Creation Date must be within 3 days of submission date')
|
||||
return creation_date
|
||||
|
||||
def clean_version(self):
|
||||
version = self.cleaned_data.get('version', None)
|
||||
if not version:
|
||||
return None
|
||||
if len(version) > 2:
|
||||
raise forms.ValidationError('Version field is not in NN format')
|
||||
try:
|
||||
version_int = int(version)
|
||||
except ValueError:
|
||||
raise forms.ValidationError('Version field is not in NN format')
|
||||
if version_int > 99 or version_int < 0:
|
||||
raise forms.ValidationError('Version must be set between 00 and 99')
|
||||
existing_revisions = [int(i.revision) for i in InternetDraft.objects.filter(filename=self.draft.filename)]
|
||||
expected = 0
|
||||
if existing_revisions:
|
||||
expected = max(existing_revisions) + 1
|
||||
if version_int != expected:
|
||||
raise forms.ValidationError('Invalid Version Number (Version %02d is expected)' % expected)
|
||||
return version
|
||||
|
||||
def clean(self):
|
||||
if bool([i for i in self.authors if i['errors']]):
|
||||
raise forms.ValidationError('Please fix errors in author list')
|
||||
return super(MetaDataForm, self).clean()
|
||||
|
||||
def get_authors(self):
|
||||
if not self.is_bound:
|
||||
return self.validation.get_authors()
|
||||
else:
|
||||
return self.authors
|
||||
|
||||
def move_docs(self, draft, revision):
|
||||
old_revision = draft.revision
|
||||
for ext in draft.file_type.split(','):
|
||||
source = os.path.join(settings.STAGING_PATH, '%s-%s%s' % (draft.filename, old_revision, ext))
|
||||
dest = os.path.join(settings.STAGING_PATH, '%s-%s%s' % (draft.filename, revision, ext))
|
||||
os.rename(source, dest)
|
||||
|
||||
def save_new_draft_info(self):
|
||||
draft = self.draft
|
||||
draft.id_documen_name = self.cleaned_data['title']
|
||||
if draft.revision != self.cleaned_data['version']:
|
||||
self.move_docs(draft, self.cleaned_data['version'])
|
||||
draft.revision = self.cleaned_data['version']
|
||||
draft.creation_date = self.cleaned_data['creation_date']
|
||||
draft.txt_page_count = self.cleaned_data['pages']
|
||||
draft.abstract = self.cleaned_data['abstract']
|
||||
draft.comment_to_sec = self.cleaned_data['comments']
|
||||
draft.status_id = MANUAL_POST_REQUESTED
|
||||
draft.save()
|
||||
self.save_submitter_info()
|
||||
|
||||
def save(self, request):
|
||||
self.save_new_draft_info()
|
||||
self.send_mail_to_secretariat(request)
|
||||
|
||||
def send_mail_to_secretariat(self, request):
|
||||
subject = 'Manual Post Requested for %s' % self.draft.filename
|
||||
from_email = settings.IDST_FROM_EMAIL
|
||||
to_email = settings.IDST_TO_EMAIL
|
||||
cc = [self.cleaned_data['email']]
|
||||
cc += [i['email'][1] for i in self.authors]
|
||||
if self.draft.group_acronym:
|
||||
cc += [i.person.email()[1] for i in self.draft.group_acronym.wgchair_set.all()]
|
||||
cc = list(set(cc))
|
||||
send_mail(request, to_email, from_email, subject, 'submit/manual_post_mail.txt',
|
||||
{'form': self, 'draft': self.draft, 'domain': Site.objects.get_current().domain }, cc=cc)
|
233
ietf/submit/migrations/0001_initial.py
Normal file
233
ietf/submit/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,233 @@
|
|||
|
||||
from south.db import db
|
||||
from django.db import models, connection
|
||||
from ietf.submit.models import *
|
||||
|
||||
class Migration:
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
if 'id_submission_detail' in connection.introspection.get_table_list(connection.cursor()):
|
||||
return # already migrated
|
||||
|
||||
# Adding model 'TempIdAuthors'
|
||||
db.create_table('temp_id_authors', (
|
||||
('id', orm['submit.TempIdAuthors:id']),
|
||||
('id_document_tag', orm['submit.TempIdAuthors:id_document_tag']),
|
||||
('first_name', orm['submit.TempIdAuthors:first_name']),
|
||||
('last_name', orm['submit.TempIdAuthors:last_name']),
|
||||
('email_address', orm['submit.TempIdAuthors:email_address']),
|
||||
('last_modified_date', orm['submit.TempIdAuthors:last_modified_date']),
|
||||
('last_modified_time', orm['submit.TempIdAuthors:last_modified_time']),
|
||||
('author_order', orm['submit.TempIdAuthors:author_order']),
|
||||
('submission', orm['submit.TempIdAuthors:submission']),
|
||||
))
|
||||
db.send_create_signal('submit', ['TempIdAuthors'])
|
||||
|
||||
# Adding model 'IdApprovedDetail'
|
||||
db.create_table('id_approved_detail', (
|
||||
('id', orm['submit.IdApprovedDetail:id']),
|
||||
('filename', orm['submit.IdApprovedDetail:filename']),
|
||||
('approved_status', orm['submit.IdApprovedDetail:approved_status']),
|
||||
('approved_person_tag', orm['submit.IdApprovedDetail:approved_person_tag']),
|
||||
('approved_date', orm['submit.IdApprovedDetail:approved_date']),
|
||||
('recorded_by', orm['submit.IdApprovedDetail:recorded_by']),
|
||||
))
|
||||
db.send_create_signal('submit', ['IdApprovedDetail'])
|
||||
|
||||
# Adding model 'IdSubmissionStatus'
|
||||
db.create_table('id_submission_status', (
|
||||
('status_id', orm['submit.IdSubmissionStatus:status_id']),
|
||||
('status_value', orm['submit.IdSubmissionStatus:status_value']),
|
||||
))
|
||||
db.send_create_signal('submit', ['IdSubmissionStatus'])
|
||||
|
||||
# Adding model 'IdSubmissionDetail'
|
||||
db.create_table('id_submission_detail', (
|
||||
('submission_id', orm['submit.IdSubmissionDetail:submission_id']),
|
||||
('temp_id_document_tag', orm['submit.IdSubmissionDetail:temp_id_document_tag']),
|
||||
('status', orm['submit.IdSubmissionDetail:status']),
|
||||
('last_updated_date', orm['submit.IdSubmissionDetail:last_updated_date']),
|
||||
('last_updated_time', orm['submit.IdSubmissionDetail:last_updated_time']),
|
||||
('id_document_name', orm['submit.IdSubmissionDetail:id_document_name']),
|
||||
('group_acronym', orm['submit.IdSubmissionDetail:group_acronym']),
|
||||
('filename', orm['submit.IdSubmissionDetail:filename']),
|
||||
('creation_date', orm['submit.IdSubmissionDetail:creation_date']),
|
||||
('submission_date', orm['submit.IdSubmissionDetail:submission_date']),
|
||||
('remote_ip', orm['submit.IdSubmissionDetail:remote_ip']),
|
||||
('revision', orm['submit.IdSubmissionDetail:revision']),
|
||||
('submitter_tag', orm['submit.IdSubmissionDetail:submitter_tag']),
|
||||
('auth_key', orm['submit.IdSubmissionDetail:auth_key']),
|
||||
('idnits_message', orm['submit.IdSubmissionDetail:idnits_message']),
|
||||
('file_type', orm['submit.IdSubmissionDetail:file_type']),
|
||||
('comment_to_sec', orm['submit.IdSubmissionDetail:comment_to_sec']),
|
||||
('abstract', orm['submit.IdSubmissionDetail:abstract']),
|
||||
('txt_page_count', orm['submit.IdSubmissionDetail:txt_page_count']),
|
||||
('error_message', orm['submit.IdSubmissionDetail:error_message']),
|
||||
('warning_message', orm['submit.IdSubmissionDetail:warning_message']),
|
||||
('wg_submission', orm['submit.IdSubmissionDetail:wg_submission']),
|
||||
('filesize', orm['submit.IdSubmissionDetail:filesize']),
|
||||
('man_posted_date', orm['submit.IdSubmissionDetail:man_posted_date']),
|
||||
('man_posted_by', orm['submit.IdSubmissionDetail:man_posted_by']),
|
||||
('first_two_pages', orm['submit.IdSubmissionDetail:first_two_pages']),
|
||||
('sub_email_priority', orm['submit.IdSubmissionDetail:sub_email_priority']),
|
||||
('invalid_version', orm['submit.IdSubmissionDetail:invalid_version']),
|
||||
('idnits_failed', orm['submit.IdSubmissionDetail:idnits_failed']),
|
||||
))
|
||||
db.send_create_signal('submit', ['IdSubmissionDetail'])
|
||||
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'TempIdAuthors'
|
||||
db.delete_table('temp_id_authors')
|
||||
|
||||
# Deleting model 'IdApprovedDetail'
|
||||
db.delete_table('id_approved_detail')
|
||||
|
||||
# Deleting model 'IdSubmissionStatus'
|
||||
db.delete_table('id_submission_status')
|
||||
|
||||
# Deleting model 'IdSubmissionDetail'
|
||||
db.delete_table('id_submission_detail')
|
||||
|
||||
|
||||
|
||||
models = {
|
||||
'idtracker.acronym': {
|
||||
'Meta': {'db_table': "'acronym'"},
|
||||
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
|
||||
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'idtracker.area': {
|
||||
'Meta': {'db_table': "'areas'"},
|
||||
'area_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'extra_email_addresses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_modified_date': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'start_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaStatus']"})
|
||||
},
|
||||
'idtracker.areadirector': {
|
||||
'Meta': {'db_table': "'area_directors'"},
|
||||
'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']", 'null': 'True', 'db_column': "'area_acronym_id'"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
|
||||
},
|
||||
'idtracker.areastatus': {
|
||||
'Meta': {'db_table': "'area_status'"},
|
||||
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
|
||||
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'idtracker.ietfwg': {
|
||||
'Meta': {'db_table': "'groups_ietf'"},
|
||||
'area_director': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaDirector']", 'null': 'True'}),
|
||||
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'dormant_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '60', 'blank': 'True'}),
|
||||
'email_archive': ('django.db.models.fields.CharField', [], {'max_length': '95', 'blank': 'True'}),
|
||||
'email_keyword': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'email_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
|
||||
'group_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'group_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGType']"}),
|
||||
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
|
||||
'meeting_scheduled': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
|
||||
'meeting_scheduled_old': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
|
||||
'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGStatus']"})
|
||||
},
|
||||
'idtracker.personororginfo': {
|
||||
'Meta': {'db_table': "'person_or_org_info'"},
|
||||
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
|
||||
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
|
||||
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
|
||||
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
|
||||
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
|
||||
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
|
||||
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
|
||||
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'idtracker.wgstatus': {
|
||||
'Meta': {'db_table': "'g_status'"},
|
||||
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
|
||||
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'idtracker.wgtype': {
|
||||
'Meta': {'db_table': "'g_type'"},
|
||||
'group_type_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'group_type'"})
|
||||
},
|
||||
'submit.idapproveddetail': {
|
||||
'Meta': {'db_table': "'id_approved_detail'"},
|
||||
'approved_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'approved_person_tag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'approved_status': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'recorded_by': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'submit.idsubmissiondetail': {
|
||||
'Meta': {'db_table': "'id_submission_detail'"},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'auth_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'comment_to_sec': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'error_message': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
|
||||
'filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'filesize': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'first_two_pages': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']", 'null': 'True', 'blank': 'True'}),
|
||||
'id_document_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'idnits_failed': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'idnits_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'invalid_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_updated_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_updated_time': ('django.db.models.fields.CharField', [], {'max_length': '25', 'null': 'True', 'blank': 'True'}),
|
||||
'man_posted_by': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'man_posted_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'remote_ip': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
||||
'revision': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True', 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['submit.IdSubmissionStatus']", 'null': 'True', 'db_column': "'status_id'", 'blank': 'True'}),
|
||||
'sub_email_priority': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'submission_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'submission_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'submitter_tag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'temp_id_document_tag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'txt_page_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'warning_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'wg_submission': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'submit.idsubmissionstatus': {
|
||||
'Meta': {'db_table': "'id_submission_status'"},
|
||||
'status_id': ('django.db.models.fields.IntegerField', [], {'primary_key': 'True'}),
|
||||
'status_value': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
|
||||
},
|
||||
'submit.tempidauthors': {
|
||||
'Meta': {'db_table': "'temp_id_authors'"},
|
||||
'author_order': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'id_document_tag': ('django.db.models.fields.IntegerField', [], {}),
|
||||
'last_modified_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_modified_time': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'submission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['submit.IdSubmissionDetail']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['submit']
|
159
ietf/submit/migrations/0002_add_submission_hash.py
Normal file
159
ietf/submit/migrations/0002_add_submission_hash.py
Normal file
|
@ -0,0 +1,159 @@
|
|||
|
||||
from south.db import db
|
||||
from django.db import models
|
||||
from ietf.submit.models import *
|
||||
|
||||
class Migration:
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Adding field 'IdSubmissionDetail.submission_hash'
|
||||
db.add_column('id_submission_detail', 'submission_hash', orm['submit.idsubmissiondetail:submission_hash'])
|
||||
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting field 'IdSubmissionDetail.submission_hash'
|
||||
db.delete_column('id_submission_detail', 'submission_hash')
|
||||
|
||||
|
||||
|
||||
models = {
|
||||
'idtracker.acronym': {
|
||||
'Meta': {'db_table': "'acronym'"},
|
||||
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
|
||||
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'idtracker.area': {
|
||||
'Meta': {'db_table': "'areas'"},
|
||||
'area_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'extra_email_addresses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_modified_date': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'start_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaStatus']"})
|
||||
},
|
||||
'idtracker.areadirector': {
|
||||
'Meta': {'db_table': "'area_directors'"},
|
||||
'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']", 'null': 'True', 'db_column': "'area_acronym_id'"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
|
||||
},
|
||||
'idtracker.areastatus': {
|
||||
'Meta': {'db_table': "'area_status'"},
|
||||
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
|
||||
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'idtracker.ietfwg': {
|
||||
'Meta': {'db_table': "'groups_ietf'"},
|
||||
'area_director': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaDirector']", 'null': 'True'}),
|
||||
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'dormant_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '60', 'blank': 'True'}),
|
||||
'email_archive': ('django.db.models.fields.CharField', [], {'max_length': '95', 'blank': 'True'}),
|
||||
'email_keyword': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'email_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
|
||||
'group_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'group_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGType']"}),
|
||||
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
|
||||
'meeting_scheduled': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
|
||||
'meeting_scheduled_old': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
|
||||
'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGStatus']"})
|
||||
},
|
||||
'idtracker.personororginfo': {
|
||||
'Meta': {'db_table': "'person_or_org_info'"},
|
||||
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
|
||||
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
|
||||
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
|
||||
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
|
||||
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
|
||||
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
|
||||
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
|
||||
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'idtracker.wgstatus': {
|
||||
'Meta': {'db_table': "'g_status'"},
|
||||
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
|
||||
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'idtracker.wgtype': {
|
||||
'Meta': {'db_table': "'g_type'"},
|
||||
'group_type_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'group_type'"})
|
||||
},
|
||||
'submit.idapproveddetail': {
|
||||
'Meta': {'db_table': "'id_approved_detail'"},
|
||||
'approved_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'approved_person_tag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'approved_status': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'recorded_by': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'submit.idsubmissiondetail': {
|
||||
'Meta': {'db_table': "'id_submission_detail'"},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'auth_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'comment_to_sec': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'error_message': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
|
||||
'filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'filesize': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'first_two_pages': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']", 'null': 'True', 'blank': 'True'}),
|
||||
'id_document_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'idnits_failed': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'idnits_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'invalid_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_updated_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_updated_time': ('django.db.models.fields.CharField', [], {'max_length': '25', 'null': 'True', 'blank': 'True'}),
|
||||
'man_posted_by': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'man_posted_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'remote_ip': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
||||
'revision': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True', 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['submit.IdSubmissionStatus']", 'null': 'True', 'db_column': "'status_id'", 'blank': 'True'}),
|
||||
'sub_email_priority': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'submission_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'submission_hash': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'submission_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'submitter_tag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'temp_id_document_tag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'txt_page_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'warning_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'wg_submission': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'submit.idsubmissionstatus': {
|
||||
'Meta': {'db_table': "'id_submission_status'"},
|
||||
'status_id': ('django.db.models.fields.IntegerField', [], {'primary_key': 'True'}),
|
||||
'status_value': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
|
||||
},
|
||||
'submit.tempidauthors': {
|
||||
'Meta': {'db_table': "'temp_id_authors'"},
|
||||
'author_order': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'id_document_tag': ('django.db.models.fields.IntegerField', [], {}),
|
||||
'last_modified_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_modified_time': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'submission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['submit.IdSubmissionDetail']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['submit']
|
167
ietf/submit/migrations/0003_add_extra_name_fields.py
Normal file
167
ietf/submit/migrations/0003_add_extra_name_fields.py
Normal file
|
@ -0,0 +1,167 @@
|
|||
|
||||
from south.db import db
|
||||
from django.db import models
|
||||
from ietf.submit.models import *
|
||||
|
||||
class Migration:
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Adding field 'TempIdAuthors.middle_initial'
|
||||
db.add_column('temp_id_authors', 'middle_initial', orm['submit.tempidauthors:middle_initial'])
|
||||
|
||||
# Adding field 'TempIdAuthors.name_suffix'
|
||||
db.add_column('temp_id_authors', 'name_suffix', orm['submit.tempidauthors:name_suffix'])
|
||||
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting field 'TempIdAuthors.middle_initial'
|
||||
db.delete_column('temp_id_authors', 'middle_initial')
|
||||
|
||||
# Deleting field 'TempIdAuthors.name_suffix'
|
||||
db.delete_column('temp_id_authors', 'name_suffix')
|
||||
|
||||
|
||||
|
||||
models = {
|
||||
'idtracker.acronym': {
|
||||
'Meta': {'db_table': "'acronym'"},
|
||||
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
|
||||
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'idtracker.area': {
|
||||
'Meta': {'db_table': "'areas'"},
|
||||
'area_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'extra_email_addresses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_modified_date': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'start_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaStatus']"})
|
||||
},
|
||||
'idtracker.areadirector': {
|
||||
'Meta': {'db_table': "'area_directors'"},
|
||||
'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']", 'null': 'True', 'db_column': "'area_acronym_id'"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
|
||||
},
|
||||
'idtracker.areastatus': {
|
||||
'Meta': {'db_table': "'area_status'"},
|
||||
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
|
||||
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'idtracker.ietfwg': {
|
||||
'Meta': {'db_table': "'groups_ietf'"},
|
||||
'area_director': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaDirector']", 'null': 'True'}),
|
||||
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'dormant_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '60', 'blank': 'True'}),
|
||||
'email_archive': ('django.db.models.fields.CharField', [], {'max_length': '95', 'blank': 'True'}),
|
||||
'email_keyword': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'email_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
|
||||
'group_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'group_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGType']"}),
|
||||
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
|
||||
'meeting_scheduled': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
|
||||
'meeting_scheduled_old': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
|
||||
'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGStatus']"})
|
||||
},
|
||||
'idtracker.personororginfo': {
|
||||
'Meta': {'db_table': "'person_or_org_info'"},
|
||||
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
|
||||
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
|
||||
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
|
||||
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
|
||||
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
|
||||
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
|
||||
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
|
||||
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'idtracker.wgstatus': {
|
||||
'Meta': {'db_table': "'g_status'"},
|
||||
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
|
||||
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'idtracker.wgtype': {
|
||||
'Meta': {'db_table': "'g_type'"},
|
||||
'group_type_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'group_type'"})
|
||||
},
|
||||
'submit.idapproveddetail': {
|
||||
'Meta': {'db_table': "'id_approved_detail'"},
|
||||
'approved_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'approved_person_tag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'approved_status': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'recorded_by': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'submit.idsubmissiondetail': {
|
||||
'Meta': {'db_table': "'id_submission_detail'"},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'auth_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'comment_to_sec': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'error_message': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
|
||||
'filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'filesize': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'first_two_pages': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'group_acronym': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']", 'null': 'True', 'blank': 'True'}),
|
||||
'id_document_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'idnits_failed': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'idnits_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'invalid_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_updated_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_updated_time': ('django.db.models.fields.CharField', [], {'max_length': '25', 'null': 'True', 'blank': 'True'}),
|
||||
'man_posted_by': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'man_posted_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'remote_ip': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
||||
'revision': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True', 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['submit.IdSubmissionStatus']", 'null': 'True', 'db_column': "'status_id'", 'blank': 'True'}),
|
||||
'sub_email_priority': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'submission_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'submission_hash': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'submission_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'submitter_tag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'temp_id_document_tag': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'txt_page_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'warning_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'wg_submission': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'submit.idsubmissionstatus': {
|
||||
'Meta': {'db_table': "'id_submission_status'"},
|
||||
'status_id': ('django.db.models.fields.IntegerField', [], {'primary_key': 'True'}),
|
||||
'status_value': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
|
||||
},
|
||||
'submit.tempidauthors': {
|
||||
'Meta': {'db_table': "'temp_id_authors'"},
|
||||
'author_order': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'id_document_tag': ('django.db.models.fields.IntegerField', [], {}),
|
||||
'last_modified_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_modified_time': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'submission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['submit.IdSubmissionDetail']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['submit']
|
0
ietf/submit/migrations/__init__.py
Normal file
0
ietf/submit/migrations/__init__.py
Normal file
102
ietf/submit/models.py
Normal file
102
ietf/submit/models.py
Normal file
|
@ -0,0 +1,102 @@
|
|||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils.hashcompat import md5_constructor
|
||||
|
||||
from ietf.idtracker.models import IETFWG
|
||||
|
||||
|
||||
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 IdSubmissionDetail(models.Model):
|
||||
submission_id = models.AutoField(primary_key=True)
|
||||
temp_id_document_tag = models.IntegerField(null=True, blank=True)
|
||||
status = models.ForeignKey(IdSubmissionStatus, db_column='status_id', null=True, blank=True)
|
||||
last_updated_date = models.DateField(null=True, blank=True)
|
||||
last_updated_time = models.CharField(null=True, blank=True, max_length=25)
|
||||
id_document_name = models.CharField(null=True, blank=True, max_length=255)
|
||||
group_acronym = models.ForeignKey(IETFWG, null=True, blank=True)
|
||||
filename = models.CharField(null=True, blank=True, max_length=255)
|
||||
creation_date = models.DateField(null=True, blank=True)
|
||||
submission_date = models.DateField(null=True, blank=True)
|
||||
remote_ip = models.CharField(null=True, blank=True, max_length=100)
|
||||
revision = models.CharField(null=True, blank=True, max_length=3)
|
||||
submitter_tag = models.IntegerField(null=True, blank=True)
|
||||
auth_key = models.CharField(null=True, blank=True, max_length=255)
|
||||
idnits_message = models.TextField(null=True, blank=True)
|
||||
file_type = models.CharField(null=True, blank=True, max_length=50)
|
||||
comment_to_sec = models.TextField(null=True, blank=True)
|
||||
abstract = models.TextField(null=True, blank=True)
|
||||
txt_page_count = models.IntegerField(null=True, blank=True)
|
||||
error_message = models.CharField(null=True, blank=True, max_length=255)
|
||||
warning_message = models.TextField(null=True, blank=True)
|
||||
wg_submission = models.IntegerField(null=True, blank=True)
|
||||
filesize = models.IntegerField(null=True, blank=True)
|
||||
man_posted_date = models.DateField(null=True, blank=True)
|
||||
man_posted_by = models.CharField(null=True, blank=True, max_length=255)
|
||||
first_two_pages = models.TextField(null=True, blank=True)
|
||||
sub_email_priority = models.IntegerField(null=True, blank=True)
|
||||
invalid_version = models.IntegerField(null=True, blank=True)
|
||||
idnits_failed = models.IntegerField(null=True, blank=True)
|
||||
submission_hash = models.CharField(null=True, blank=True, max_length=255)
|
||||
|
||||
class Meta:
|
||||
db_table = 'id_submission_detail'
|
||||
|
||||
def create_hash(self):
|
||||
self.submission_hash = md5_constructor(settings.SECRET_KEY + self.filename).hexdigest()
|
||||
|
||||
def get_hash(self):
|
||||
if not self.submission_hash:
|
||||
self.create_hash()
|
||||
self.save()
|
||||
return self.submission_hash
|
||||
|
||||
def create_submission_hash(sender, instance, **kwargs):
|
||||
instance.create_hash()
|
||||
|
||||
models.signals.pre_save.connect(create_submission_hash, sender=IdSubmissionDetail)
|
||||
|
||||
class IdApprovedDetail(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
filename = models.CharField(null=True, blank=True, max_length=255)
|
||||
approved_status = models.IntegerField(null=True, blank=True)
|
||||
approved_person_tag = models.IntegerField(null=True, blank=True)
|
||||
approved_date = models.DateField(null=True, blank=True)
|
||||
recorded_by = models.IntegerField(null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'id_approved_detail'
|
||||
|
||||
|
||||
class TempIdAuthors(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
id_document_tag = models.IntegerField()
|
||||
first_name = models.CharField(blank=True, max_length=255)
|
||||
last_name = models.CharField(blank=True, max_length=255)
|
||||
email_address = models.CharField(blank=True, max_length=255)
|
||||
last_modified_date = models.DateField(null=True, blank=True)
|
||||
last_modified_time = models.CharField(blank=True, max_length=100)
|
||||
author_order = models.IntegerField(null=True, blank=True)
|
||||
submission = models.ForeignKey(IdSubmissionDetail)
|
||||
middle_initial = models.CharField(blank=True, max_length=255, null=True)
|
||||
name_suffix = models.CharField(blank=True, max_length=255, null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'temp_id_authors'
|
||||
|
||||
def email(self):
|
||||
return ('%s %s' % (self.first_name, self.last_name), self.email_address)
|
||||
|
||||
def get_full_name(self):
|
||||
full_name = ('%s %s %s %s') % (self.first_name, self.middle_initial or '',
|
||||
self.last_name, self.name_suffix or '')
|
||||
full_name = re.sub(' +', ' ', full_name).strip()
|
||||
return full_name
|
0
ietf/submit/parsers/__init__.py
Normal file
0
ietf/submit/parsers/__init__.py
Normal file
50
ietf/submit/parsers/base.py
Normal file
50
ietf/submit/parsers/base.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
import re
|
||||
|
||||
|
||||
CUTOFF_HOUR = 17
|
||||
|
||||
|
||||
class MetaDataDraft(object):
|
||||
revision = None
|
||||
filename = None
|
||||
group = None
|
||||
filesize = None
|
||||
first_two_pages = None
|
||||
page_count = None
|
||||
submission_date = None
|
||||
creation_date = None
|
||||
authors = None
|
||||
|
||||
class ParseInfo(object):
|
||||
|
||||
def __init__(self):
|
||||
self.errors = []
|
||||
self.warnings = {}
|
||||
self.metadraft = MetaDataDraft()
|
||||
|
||||
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()
|
||||
|
||||
# If some error is found after this method invocation
|
||||
# no other file parsing is recommended
|
||||
def critical_parse(self):
|
||||
self.parse_invalid_chars_in_filename()
|
||||
return self.parsed_info
|
||||
|
||||
def parse_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)))
|
15
ietf/submit/parsers/pdf_parser.py
Normal file
15
ietf/submit/parsers/pdf_parser.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
from ietf.submit.parsers.base import FileParser
|
||||
|
||||
|
||||
class PDFParser(FileParser):
|
||||
|
||||
# If some error is found after this method invocation
|
||||
# no other file parsing is recommended
|
||||
def critical_parse(self):
|
||||
super(PDFParser, self).critical_parse()
|
||||
self.parse_filename_extension()
|
||||
return self.parsed_info
|
||||
|
||||
def parse_filename_extension(self):
|
||||
if not self.fd.name.endswith('.pdf'):
|
||||
self.parsed_info.add_error('Format of this document must be PDF')
|
85
ietf/submit/parsers/plain_parser.py
Normal file
85
ietf/submit/parsers/plain_parser.py
Normal file
|
@ -0,0 +1,85 @@
|
|||
import datetime
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from ietf.idtracker.models import InternetDraft, IETFWG
|
||||
from django.template.defaultfilters import filesizeformat
|
||||
from ietf.submit.parsers.base import FileParser
|
||||
|
||||
NONE_WG_PK = 1027
|
||||
|
||||
|
||||
class PlainParser(FileParser):
|
||||
|
||||
def __init__(self, fd):
|
||||
super(PlainParser, self).__init__(fd)
|
||||
|
||||
# If some error is found after this method invocation
|
||||
# no other file parsing is recommended
|
||||
def critical_parse(self):
|
||||
super(PlainParser, self).critical_parse()
|
||||
self.parse_max_size()
|
||||
self.parse_file_charset()
|
||||
self.parse_filename()
|
||||
return self.parsed_info
|
||||
|
||||
def parse_max_size(self):
|
||||
if self.fd.size > settings.MAX_PLAIN_DRAFT_SIZE:
|
||||
self.parsed_info.add_error('File size is larger than %s' % filesizeformat(settings.MAX_PLAIN_DRAFT_SIZE))
|
||||
self.parsed_info.metadraft.filesize = self.fd.size
|
||||
self.parsed_info.metadraft.submission_date = datetime.date.today()
|
||||
|
||||
def parse_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+)')
|
||||
revisionre = re.compile('.*-(\d+)$')
|
||||
limit = 80
|
||||
while limit:
|
||||
limit -= 1
|
||||
line = self.fd.readline()
|
||||
match = draftre.search(line)
|
||||
if not match:
|
||||
continue
|
||||
filename = match.group(1)
|
||||
filename = re.sub('^[^\w]+', '', filename)
|
||||
filename = re.sub('[^\w]+$', '', filename)
|
||||
filename = re.sub('\.txt$', '', filename)
|
||||
extra_chars = re.sub('[0-9a-z\-]', '', filename)
|
||||
if extra_chars:
|
||||
self.parsed_info.add_error(u'Filename contains non alpha-numeric character: %s' % (', '.join(set(extra_chars))).decode('ascii','replace'))
|
||||
match_revision = revisionre.match(filename)
|
||||
if match_revision:
|
||||
self.parsed_info.metadraft.revision = match_revision.group(1)
|
||||
filename = re.sub('-\d+$', '', filename)
|
||||
self.parsed_info.metadraft.filename = filename
|
||||
return
|
||||
self.parsed_info.add_error('The document does not contain a legitimate filename that start with draft-*')
|
||||
|
||||
def parse_wg(self):
|
||||
filename = self.parsed_info.metadraft.filename
|
||||
try:
|
||||
existing_draft = InternetDraft.objects.get(filename=filename)
|
||||
self.parsed_info.metadraft.wg = existing_draft.group
|
||||
except InternetDraft.DoesNotExist:
|
||||
if filename.startswith('draft-ietf-'):
|
||||
# Extra check for WG that contains dashes
|
||||
for group in IETFWG.objects.filter(group_acronym__acronym__contains='-'):
|
||||
if filename.startswith('draft-ietf-%s-' % group.group_acronym.acronym):
|
||||
self.parsed_info.metadraft.wg = group
|
||||
return
|
||||
group_acronym = filename.split('-')[2]
|
||||
try:
|
||||
self.parsed_info.metadraft.wg = IETFWG.objects.get(group_acronym__acronym=group_acronym)
|
||||
except IETFWG.DoesNotExist:
|
||||
self.parsed_info.add_error('Invalid WG ID: %s' % group_acronym)
|
||||
else:
|
||||
self.parsed_info.metadraft.wg = IETFWG.objects.get(pk=NONE_WG_PK)
|
15
ietf/submit/parsers/ps_parser.py
Normal file
15
ietf/submit/parsers/ps_parser.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
from ietf.submit.parsers.base import FileParser
|
||||
|
||||
|
||||
class PSParser(FileParser):
|
||||
|
||||
# If some error is found after this method invocation
|
||||
# no other file parsing is recommended
|
||||
def critical_parse(self):
|
||||
super(PSParser, self).critical_parse()
|
||||
self.parse_filename_extension()
|
||||
return self.parsed_info
|
||||
|
||||
def parse_filename_extension(self):
|
||||
if not self.fd.name.endswith('.ps'):
|
||||
self.parsed_info.add_error('Format of this document must be PS')
|
15
ietf/submit/parsers/xml_parser.py
Normal file
15
ietf/submit/parsers/xml_parser.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
from ietf.submit.parsers.base import FileParser
|
||||
|
||||
|
||||
class XMLParser(FileParser):
|
||||
|
||||
# If some error is found after this method invocation
|
||||
# no other file parsing is recommended
|
||||
def critical_parse(self):
|
||||
super(XMLParser, self).critical_parse()
|
||||
self.parse_filename_extension()
|
||||
return self.parsed_info
|
||||
|
||||
def parse_filename_extension(self):
|
||||
if not self.fd.name.endswith('.xml'):
|
||||
self.parsed_info.add_error('Format of this document must be XML')
|
0
ietf/submit/templatetags/__init__.py
Normal file
0
ietf/submit/templatetags/__init__.py
Normal file
39
ietf/submit/templatetags/submit_tags.py
Normal file
39
ietf/submit/templatetags/submit_tags.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
import os
|
||||
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.utils.html import mark_safe
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.inclusion_tag('submit/submission_files.html', takes_context=True)
|
||||
def show_submission_files(context, submission):
|
||||
result = []
|
||||
for ext in submission.file_type.split(','):
|
||||
source = os.path.join(settings.STAGING_PATH, '%s-%s%s' % (submission.filename, submission.revision, ext))
|
||||
if os.path.exists(source):
|
||||
result.append({'name': '[%s version ]' % ext[1:].capitalize(),
|
||||
'url': '%s%s-%s%s' % (settings.STAGING_URL, submission.filename, submission.revision, ext)})
|
||||
return {'files': result}
|
||||
|
||||
def show_two_pages(context, two_pages, validation):
|
||||
result
|
||||
|
||||
|
||||
@register.filter
|
||||
def two_pages_decorated_with_validation(value, validation):
|
||||
pages = value.first_two_pages
|
||||
if not 'revision' in validation.warnings.keys():
|
||||
return mark_safe('<pre class="twopages" style="display: none;">%s</pre>' % pages)
|
||||
result = '<pre class="twopages" style="display: none;">\n'
|
||||
for line in pages.split('\n'):
|
||||
if line.find('%s-%s' % (value.filename, value.revision)) > -1:
|
||||
result += '</pre><pre class="twopages" style="display: none; background: red;">'
|
||||
result += line
|
||||
result += '\n'
|
||||
result += '</pre><pre class="twopages" style="display: none;">\n'
|
||||
else:
|
||||
result += line
|
||||
result += '\n'
|
||||
return mark_safe(result)
|
30
ietf/submit/urls.py
Normal file
30
ietf/submit/urls.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
from django.conf.urls.defaults import patterns, url
|
||||
|
||||
|
||||
urlpatterns = patterns('ietf.submit.views',
|
||||
url(r'^$', 'submit_index', name='submit_index'),
|
||||
url(r'^status/$', 'submit_status', name='submit_status'),
|
||||
url(r'^status/(?P<submission_id>\d+)/$', 'draft_status', name='draft_status'),
|
||||
url(r'^status/(?P<submission_id>\d+)/edit/$', 'draft_edit', name='draft_edit'),
|
||||
url(r'^status/(?P<submission_id>\d+)/confirm/(?P<auth_key>[a-f\d]+)/$', 'draft_confirm', name='draft_confirm'),
|
||||
url(r'^status/(?P<submission_id>\d+)/cancel/$', 'draft_cancel', name='draft_cancel'),
|
||||
url(r'^status/(?P<submission_id>\d+)/approve/$', 'draft_approve', name='draft_approve'),
|
||||
url(r'^status/(?P<submission_id>\d+)/force/$', 'draft_force', name='draft_force'),
|
||||
url(r'^status/(?P<submission_id>\d+)/request/$', 'full_url_request', name='full_url_request'),
|
||||
url(r'^status/(?P<submission_id>\d+)/(?P<submission_hash>[a-f\d]+)/$', 'draft_status', name='draft_status_by_hash'),
|
||||
url(r'^status/(?P<submission_id>\d+)/(?P<submission_hash>[a-f\d]+)/cancel/$', 'draft_cancel', name='draft_cancel_by_hash'),
|
||||
url(r'^status/(?P<submission_id>\d+)/(?P<submission_hash>[a-f\d]+)/edit/$', 'draft_edit', name='draft_edit_by_hash'),
|
||||
)
|
||||
|
||||
urlpatterns += patterns('django.views.generic.simple',
|
||||
url(r'^note-well/$', 'direct_to_template',
|
||||
{'template': 'submit/note_well.html',
|
||||
'extra_context': {'selected': 'notewell'}
|
||||
},
|
||||
name='submit_note_well'),
|
||||
url(r'^tool-instructions/$', 'direct_to_template',
|
||||
{'template': 'submit/tool_instructions.html',
|
||||
'extra_context': {'selected': 'instructions'}
|
||||
},
|
||||
name='submit_tool_instructions'),
|
||||
)
|
254
ietf/submit/utils.py
Normal file
254
ietf/submit/utils.py
Normal file
|
@ -0,0 +1,254 @@
|
|||
import os
|
||||
import re
|
||||
import datetime
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
from ietf.idtracker.models import (InternetDraft, PersonOrOrgInfo, IETFWG,
|
||||
IDAuthor, EmailAddress)
|
||||
from ietf.utils.mail import send_mail
|
||||
|
||||
|
||||
# Some usefull states
|
||||
UPLOADED = 1
|
||||
WAITING_AUTHENTICATION = 4
|
||||
MANUAL_POST_REQUESTED = 5
|
||||
POSTED = -1
|
||||
POSTED_BY_SECRETARIAT = -2
|
||||
CANCELED = -4
|
||||
INITIAL_VERSION_APPROVAL_REQUESTED = 10
|
||||
|
||||
|
||||
# Not a real WG
|
||||
NONE_WG = 1027
|
||||
|
||||
|
||||
def request_full_url(request, submission):
|
||||
subject = 'Full url for managing submission of draft %s' % submission.filename
|
||||
from_email = settings.IDST_FROM_EMAIL
|
||||
to_email = ['%s <%s>' % i.email() for i in submission.tempidauthors_set.all()]
|
||||
send_mail(request, to_email, from_email, subject, 'submit/request_full_url.txt',
|
||||
{'submission': submission,
|
||||
'domain': Site.objects.get_current().domain})
|
||||
|
||||
|
||||
def perform_post(submission):
|
||||
group_id = submission.group_acronym and submission.group_acronym.pk or NONE_WG
|
||||
try:
|
||||
draft = InternetDraft.objects.get(filename=submission.filename)
|
||||
draft.title = submission.id_document_name
|
||||
draft.group_id = group_id
|
||||
draft.filename = submission.filename
|
||||
draft.revision = submission.revision
|
||||
draft.revision_date = submission.creation_date
|
||||
draft.file_type = submission.file_type
|
||||
draft.txt_page_count = submission.txt_page_count
|
||||
draft.last_modified_date = datetime.date.today()
|
||||
draft.abstract = submission.abstract
|
||||
draft.save()
|
||||
except InternetDraft.DoesNotExist:
|
||||
draft = InternetDraft.objects.create(
|
||||
title=submission.id_document_name,
|
||||
group_id=group_id,
|
||||
filename=submission.filename,
|
||||
revision=submission.revision,
|
||||
revision_date=submission.creation_date,
|
||||
file_type=submission.file_type,
|
||||
txt_page_count=submission.txt_page_count,
|
||||
start_date=datetime.date.today(),
|
||||
last_modified_date=datetime.date.today(),
|
||||
abstract=submission.abstract,
|
||||
status_id=1, # Active
|
||||
intended_status_id=8, # None
|
||||
)
|
||||
update_authors(draft, submission)
|
||||
move_docs(submission)
|
||||
submission.status_id = POSTED
|
||||
submission.save()
|
||||
|
||||
|
||||
def find_person(first_name, last_name, middle_initial, name_suffix, email):
|
||||
person_list = None
|
||||
if email:
|
||||
person_list = PersonOrOrgInfo.objects.filter(emailaddress__address=email).distinct()
|
||||
if person_list and len(person_list) == 1:
|
||||
return person_list[0]
|
||||
if not person_list:
|
||||
person_list = PersonOrOrgInfo.objects.all()
|
||||
person_list = person_list.filter(first_name=first_name,
|
||||
last_name=last_name)
|
||||
if middle_initial:
|
||||
person_list = person_list.filter(middle_initial=middle_initial)
|
||||
if name_suffix:
|
||||
person_list = person_list.filter(name_suffix=name_suffix)
|
||||
if person_list:
|
||||
return person_list[0]
|
||||
return None
|
||||
|
||||
|
||||
def update_authors(draft, submission):
|
||||
# TempAuthor of order 0 is submitter
|
||||
new_authors = list(submission.tempidauthors_set.filter(author_order__gt=0))
|
||||
person_pks = []
|
||||
for author in new_authors:
|
||||
person = find_person(author.first_name, author.last_name,
|
||||
author.middle_initial, author.name_suffix,
|
||||
author.email_address)
|
||||
if not person:
|
||||
person = PersonOrOrgInfo(
|
||||
first_name=author.first_name,
|
||||
last_name=author.last_name,
|
||||
middle_initial=author.middle_initial or '',
|
||||
name_suffix=author.name_suffix or '',
|
||||
)
|
||||
person.save()
|
||||
if author.email:
|
||||
EmailAddress.objects.create(
|
||||
address=author.email,
|
||||
priority=1,
|
||||
type='INET',
|
||||
person_or_org=person,
|
||||
)
|
||||
person_pks.append(person.pk)
|
||||
try:
|
||||
idauthor = IDAuthor.objects.get(
|
||||
document=draft,
|
||||
person=person,
|
||||
)
|
||||
idauthor.author_order = author.author_order
|
||||
except IDAuthor.DoesNotExist:
|
||||
idauthor = IDAuthor(
|
||||
document=draft,
|
||||
person=person,
|
||||
author_order=author.author_order,
|
||||
)
|
||||
idauthor.save()
|
||||
draft.authors.exclude(person__pk__in=person_pks).delete()
|
||||
|
||||
|
||||
def get_person_for_user(user):
|
||||
try:
|
||||
return user.get_profile().person()
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def is_secretariat(user):
|
||||
if not user or not user.is_authenticated():
|
||||
return False
|
||||
return bool(user.groups.filter(name='Secretariat'))
|
||||
|
||||
|
||||
def move_docs(submission):
|
||||
for ext in submission.file_type.split(','):
|
||||
source = os.path.join(settings.STAGING_PATH, '%s-%s%s' % (submission.filename, submission.revision, ext))
|
||||
dest = os.path.join(settings.INTERNET_DRAFT_PATH, '%s-%s%s' % (submission.filename, submission.revision, ext))
|
||||
os.rename(source, dest)
|
||||
|
||||
|
||||
def remove_docs(submission):
|
||||
for ext in submission.file_type.split(','):
|
||||
source = os.path.join(settings.STAGING_PATH, '%s-%s%s' % (submission.filename, submission.revision, ext))
|
||||
if os.path.exists(source):
|
||||
os.unlink(source)
|
||||
|
||||
|
||||
class DraftValidation(object):
|
||||
|
||||
def __init__(self, draft):
|
||||
self.draft = draft
|
||||
self.warnings = {}
|
||||
self.passes_idnits = self.passes_idnits()
|
||||
self.wg = self.get_working_group()
|
||||
self.authors = self.get_authors()
|
||||
self.submitter = self.get_submitter()
|
||||
|
||||
def passes_idnits(self):
|
||||
passes_idnits = self.check_idnits_success(self.draft.idnits_message)
|
||||
return passes_idnits
|
||||
|
||||
def get_working_group(self):
|
||||
if self.draft.group_acronym and self.draft.group_acronym.pk == NONE_WG:
|
||||
return None
|
||||
return self.draft.group_acronym
|
||||
|
||||
def check_idnits_success(self, idnits_message):
|
||||
if not idnits_message:
|
||||
return False
|
||||
success_re = re.compile('\s+Summary:\s+0\s+|No nits found')
|
||||
if success_re.search(idnits_message):
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_valid_attr(self, key):
|
||||
if key in self.warnings.keys():
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_valid(self):
|
||||
self.validate_metadata()
|
||||
return not bool(self.warnings.keys()) and self.passes_idnits
|
||||
|
||||
def validate_metadata(self):
|
||||
self.validate_revision()
|
||||
self.validate_authors()
|
||||
self.validate_abstract()
|
||||
self.validate_creation_date()
|
||||
self.validate_wg()
|
||||
|
||||
def validate_wg(self):
|
||||
if self.wg and not self.wg.status.pk == IETFWG.ACTIVE:
|
||||
self.add_warning('group', 'Working Group exists but is not an active WG')
|
||||
|
||||
def validate_abstract(self):
|
||||
if not self.draft.abstract:
|
||||
self.add_warning('abstract', 'Abstract is empty or was not found')
|
||||
|
||||
def add_warning(self, key, value):
|
||||
self.warnings.update({key: value})
|
||||
|
||||
def validate_revision(self):
|
||||
if self.draft.status_id in [POSTED, POSTED_BY_SECRETARIAT]:
|
||||
return
|
||||
revision = self.draft.revision
|
||||
existing_revisions = [int(i.revision) for i in InternetDraft.objects.filter(filename=self.draft.filename)]
|
||||
expected = 0
|
||||
if existing_revisions:
|
||||
expected = max(existing_revisions) + 1
|
||||
try:
|
||||
if int(revision) != expected:
|
||||
self.add_warning('revision', 'Invalid Version Number (Version %02d is expected)' % expected)
|
||||
except ValueError:
|
||||
self.add_warning('revision', 'Revision not found')
|
||||
|
||||
def validate_authors(self):
|
||||
if not self.authors:
|
||||
self.add_warning('authors', 'No authors found')
|
||||
return
|
||||
|
||||
def validate_creation_date(self):
|
||||
date = self.draft.creation_date
|
||||
if not date:
|
||||
self.add_warning('creation_date', 'Creation Date field is empty or the creation date is not in a proper format')
|
||||
return
|
||||
submit_date = self.draft.submission_date
|
||||
if date > submit_date:
|
||||
self.add_warning('creation_date', 'Creation Date must not be set after submission date')
|
||||
if date + datetime.timedelta(days=3) < submit_date:
|
||||
self.add_warning('creation_date', 'Creation Date must be within 3 days of submission date')
|
||||
|
||||
def get_authors(self):
|
||||
tmpauthors = self.draft.tempidauthors_set.exclude(author_order=0).order_by('author_order')
|
||||
return tmpauthors
|
||||
|
||||
def get_submitter(self):
|
||||
submitter = self.draft.tempidauthors_set.filter(author_order=0)
|
||||
if submitter:
|
||||
return submitter[0]
|
||||
elif self.draft.submitter_tag:
|
||||
try:
|
||||
return PersonOrOrgInfo.objects.get(pk=self.draft.submitter_tag)
|
||||
except PersonOrOrgInfo.DoesNotExist:
|
||||
return False
|
||||
return None
|
239
ietf/submit/views.py
Normal file
239
ietf/submit/views.py
Normal file
|
@ -0,0 +1,239 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.contrib.sites.models import Site
|
||||
from django.http import HttpResponseRedirect, Http404, HttpResponseForbidden
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
from ietf.submit.models import IdSubmissionDetail, IdApprovedDetail
|
||||
from ietf.submit.forms import UploadForm, AutoPostForm, MetaDataForm
|
||||
from ietf.submit.utils import (DraftValidation, perform_post, remove_docs,
|
||||
get_person_for_user, is_secretariat,
|
||||
request_full_url, UPLOADED,
|
||||
WAITING_AUTHENTICATION, CANCELED,
|
||||
INITIAL_VERSION_APPROVAL_REQUESTED,
|
||||
MANUAL_POST_REQUESTED, POSTED)
|
||||
from ietf.utils.mail import send_mail
|
||||
|
||||
|
||||
def submit_index(request):
|
||||
if request.method == 'POST':
|
||||
form = UploadForm(request=request, data=request.POST, files=request.FILES)
|
||||
if form.is_valid():
|
||||
submit = form.save()
|
||||
return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submit.submission_id, 'submission_hash': submit.get_hash()}))
|
||||
else:
|
||||
form = UploadForm(request=request)
|
||||
return render_to_response('submit/submit_index.html',
|
||||
{'selected': 'index',
|
||||
'form': form},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def submit_status(request):
|
||||
error = None
|
||||
filename = None
|
||||
if request.method == 'POST':
|
||||
filename = request.POST.get('filename', '')
|
||||
detail = IdSubmissionDetail.objects.filter(filename=filename).order_by('-pk')
|
||||
if detail:
|
||||
return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': detail[0].submission_id}))
|
||||
error = 'No valid history found for %s' % filename
|
||||
return render_to_response('submit/submit_status.html',
|
||||
{'selected': 'status',
|
||||
'error': error,
|
||||
'filename': filename},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def _can_approve(user, detail):
|
||||
person = get_person_for_user(user)
|
||||
if detail.status_id != INITIAL_VERSION_APPROVAL_REQUESTED or not detail.group_acronym:
|
||||
return None
|
||||
if person in [i.person for i in detail.group_acronym.wgchair_set.all()] or is_secretariat(user):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _can_force_post(user, detail):
|
||||
if detail.status_id not in [MANUAL_POST_REQUESTED,
|
||||
WAITING_AUTHENTICATION, INITIAL_VERSION_APPROVAL_REQUESTED]:
|
||||
return None
|
||||
if is_secretariat(user):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _can_cancel(user, detail, submission_hash):
|
||||
if detail.status_id in [CANCELED, POSTED]:
|
||||
return None
|
||||
if is_secretariat(user):
|
||||
return True
|
||||
if submission_hash and detail.get_hash() == submission_hash:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _can_edit(user, detail, submission_hash):
|
||||
if detail.status_id != UPLOADED:
|
||||
return None
|
||||
if is_secretariat(user):
|
||||
return True
|
||||
if submission_hash and detail.get_hash() == submission_hash:
|
||||
return True
|
||||
return False
|
||||
|
||||
def draft_status(request, submission_id, submission_hash=None, message=None):
|
||||
detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
|
||||
if submission_hash and not detail.get_hash() == submission_hash:
|
||||
raise Http404
|
||||
validation = DraftValidation(detail)
|
||||
is_valid = validation.is_valid()
|
||||
status = None
|
||||
allow_edit = _can_edit(request.user, detail, submission_hash)
|
||||
can_force_post = _can_force_post(request.user, detail)
|
||||
can_approve = _can_approve(request.user, detail)
|
||||
can_cancel = _can_cancel(request.user, detail, submission_hash)
|
||||
if detail.status_id != UPLOADED:
|
||||
if detail.status_id == CANCELED:
|
||||
message = ('error', 'This submission has been canceled, modification is no longer possible')
|
||||
status = detail.status
|
||||
allow_edit = None
|
||||
|
||||
if request.method == 'POST' and allow_edit:
|
||||
if request.POST.get('autopost', False):
|
||||
auto_post_form = AutoPostForm(draft=detail, validation=validation, data=request.POST)
|
||||
if auto_post_form.is_valid():
|
||||
try:
|
||||
approved_detail = IdApprovedDetail.objects.get(filename=detail.filename)
|
||||
except ObjectDoesNotExist:
|
||||
approved_detail = None
|
||||
if detail.group_acronym and not approved_detail:
|
||||
detail.status_id = INITIAL_VERSION_APPROVAL_REQUESTED
|
||||
detail.save()
|
||||
else:
|
||||
approved_detail = True
|
||||
|
||||
if detail.revision == '00' and not approved_detail:
|
||||
submitter = auto_post_form.save_submitter_info()
|
||||
subject = 'New draft waiting for approval: %s' % detail.filename
|
||||
from_email = settings.IDST_FROM_EMAIL
|
||||
to_email = []
|
||||
if detail.group_acronym:
|
||||
to_email += [i.person.email()[1] for i in detail.group_acronym.wgchair_set.all()]
|
||||
to_email = list(set(to_email))
|
||||
if to_email:
|
||||
metadata_form = MetaDataForm(draft=detail, validation=validation)
|
||||
send_mail(request, to_email, from_email, subject, 'submit/submission_approval.txt',
|
||||
{'submitter': submitter, 'form': metadata_form,
|
||||
'draft': detail, 'domain': Site.objects.get_current().domain})
|
||||
return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': detail.submission_id}))
|
||||
else:
|
||||
auto_post_form.save(request)
|
||||
detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
|
||||
validation = DraftValidation(detail)
|
||||
is_valid = validation.is_valid()
|
||||
status = detail.status
|
||||
can_force_post = _can_force_post(request.user, detail)
|
||||
can_approve = _can_approve(request.user, detail)
|
||||
can_cancel = _can_cancel(request.user, detail, submission_hash)
|
||||
allow_edit = None
|
||||
message = ('success', 'Your submission is pending email authentication. An email has been sent you with instructions.')
|
||||
else:
|
||||
return HttpResponseRedirect(reverse(draft_edit, None, kwargs={'submission_id': detail.submission_id, 'submission_hash': submission_hash}))
|
||||
else:
|
||||
auto_post_form = AutoPostForm(draft=detail, validation=validation)
|
||||
|
||||
show_notify_button = False
|
||||
if allow_edit == False or can_cancel == False:
|
||||
show_notify_button = True
|
||||
return render_to_response('submit/draft_status.html',
|
||||
{'selected': 'status',
|
||||
'detail': detail,
|
||||
'validation': validation,
|
||||
'auto_post_form': auto_post_form,
|
||||
'is_valid': is_valid,
|
||||
'status': status,
|
||||
'message': message,
|
||||
'allow_edit': allow_edit,
|
||||
'can_force_post': can_force_post,
|
||||
'can_approve': can_approve,
|
||||
'can_cancel': can_cancel,
|
||||
'submission_hash': submission_hash,
|
||||
'show_notify_button': show_notify_button,
|
||||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def draft_cancel(request, submission_id, submission_hash=None):
|
||||
detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
|
||||
can_cancel = _can_cancel(request.user, detail, submission_hash)
|
||||
if not can_cancel:
|
||||
if can_cancel == None:
|
||||
raise Http404
|
||||
return HttpResponseForbidden('You have no permission to perform this action')
|
||||
detail.status_id = CANCELED
|
||||
detail.save()
|
||||
remove_docs(detail)
|
||||
return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submission_id}))
|
||||
|
||||
|
||||
def draft_edit(request, submission_id, submission_hash=None):
|
||||
detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
|
||||
can_edit = _can_edit(request.user, detail, submission_hash)
|
||||
if not can_edit:
|
||||
if can_edit == None:
|
||||
raise Http404
|
||||
return HttpResponseForbidden('You have no permission to perform this action')
|
||||
validation = DraftValidation(detail)
|
||||
validation.validate_wg()
|
||||
if request.method == 'POST':
|
||||
form = MetaDataForm(draft=detail, validation=validation, data=request.POST)
|
||||
if form.is_valid():
|
||||
form.save(request)
|
||||
return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': detail.submission_id}))
|
||||
else:
|
||||
form = MetaDataForm(draft=detail, validation=validation)
|
||||
return render_to_response('submit/draft_edit.html',
|
||||
{'selected': 'status',
|
||||
'detail': detail,
|
||||
'validation': validation,
|
||||
'form': form,
|
||||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def draft_confirm(request, submission_id, auth_key):
|
||||
detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
|
||||
message = None
|
||||
if auth_key != detail.auth_key:
|
||||
message = ('error', 'Incorrect authorization key')
|
||||
elif detail.status_id != WAITING_AUTHENTICATION:
|
||||
message = ('error', 'The submission can not be autoposted because it is in state: %s' % detail.status.status_value)
|
||||
else:
|
||||
message = ('success', 'Authorization key accepted. Auto-Post complete')
|
||||
perform_post(detail)
|
||||
return draft_status(request, submission_id, message=message)
|
||||
|
||||
|
||||
def draft_approve(request, submission_id, check_function=_can_approve):
|
||||
detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
|
||||
can_perform = check_function(request.user, detail)
|
||||
if not can_perform:
|
||||
if can_perform == None:
|
||||
raise Http404
|
||||
return HttpResponseForbidden('You have no permission to perform this action')
|
||||
perform_post(detail)
|
||||
return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submission_id}))
|
||||
|
||||
|
||||
def draft_force(request, submission_id):
|
||||
return draft_approve(request, submission_id, check_function=_can_force_post)
|
||||
|
||||
|
||||
def full_url_request(request, submission_id):
|
||||
detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
|
||||
request_full_url(request, detail)
|
||||
message = ('success', 'An email has been sent to draft authors to inform them of the full access url')
|
||||
return draft_status(request, submission_id, message=message)
|
|
@ -64,7 +64,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<li class="sect">Drafts & RFCs</li>
|
||||
<li><a href="/doc/">Search</a></li>
|
||||
<li><form action="/doc/search/" method="get" style="padding-bottom:0;margin-bottom:0;"><input type="text" style="margin-left:10px; width:100px; border:1px solid #89d;" name="name" /><input type="hidden" name="activeDrafts" value="on"/><input type="hidden" name="rfcs" value="on"/></form></li>
|
||||
<li><a href="https://datatracker.ietf.org/idst/upload.cgi">Submit a draft</a></li>
|
||||
<li><a href="{% url submit_index %}">Submit a draft</a></li>
|
||||
|
||||
|
||||
<li class="sect">Meetings</li>
|
||||
|
|
6
ietf/templates/submit/confirm_autopost.txt
Normal file
6
ietf/templates/submit/confirm_autopost.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
Follow this link to confirm you Auto-Post of I-D {{ draft.filename }}-{{ draft.revision }}
|
||||
|
||||
I-D Submission Tool URL: http://{{ domain }}/submit/status/{{ draft.submission_id }}/confirm/{{ draft.auth_key }}/
|
||||
|
||||
Remember that you can cancel the submission from:
|
||||
http://{{ domain }}/submit/status/{{ draft.submission_id }}/{{ draft.get_hash }}/
|
152
ietf/templates/submit/draft_edit.html
Normal file
152
ietf/templates/submit/draft_edit.html
Normal file
|
@ -0,0 +1,152 @@
|
|||
{% extends "submit/draft_status.html" %}
|
||||
{% load submit_tags %}
|
||||
{% block title %}Adjust Meta-Data{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
{{ block.super }}
|
||||
table.metadata-table #id_title, table.metadata-table #id_abstract, table.metadata-table #id_comments { width: 500px; }
|
||||
table.metadata-table tr.warning th, table.metadata-table tr.warning td { background-color: #ffeebb; }
|
||||
table.ietf-table tr { vertical-align: top; }
|
||||
table.ietf-table tr.error { background-color: #ffeebb; border-top: 1px dashed red; border-bottom: 1px dashed red;}
|
||||
table.ietf-table span.field-error { display: block; color: red; }
|
||||
{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
{{ block.super }}
|
||||
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
|
||||
$.fn.AuthorList = function() {
|
||||
return this.each(function () {
|
||||
var table = $(this);
|
||||
var makeEditable = function() {
|
||||
table.find('tbody tr').each(function(index, value) {
|
||||
var tr = $(this);
|
||||
tr.find('td').each(function() {
|
||||
var td = $(this);
|
||||
var text = td.find('.fieldValue');
|
||||
var name = td.attr('name');
|
||||
if (tr.hasClass('non_editable')) {
|
||||
td.prepend('<input style="display: none;" type="text" name="' + name + '_' + index + '" value="' + text.text() + '" />');
|
||||
} else {
|
||||
td.prepend('<input type="text" name="' + name + '_' + index + '" value="' + text.text() + '" />');
|
||||
text.html('');
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var addNewEntry = function() {
|
||||
table.append(table.find('tbody tr').last().clone());
|
||||
var new_tr = table.find('tbody tr').last();
|
||||
new_tr.toggleClass('evenrow').toggleClass('oddrow');
|
||||
new_tr.removeClass('error').find('.field-error').remove();
|
||||
new_tr.find('input').each(function() {
|
||||
var name = $(this).attr('name');
|
||||
var splitted = name.split('_');
|
||||
splitted.reverse();
|
||||
name = name.replace(splitted[0], (parseInt(splitted[0]) + 1).toString(10));
|
||||
$(this).attr('name', name);
|
||||
$(this).val('');
|
||||
});
|
||||
};
|
||||
|
||||
var bindTriggers = function() {
|
||||
$('.new_author').click(addNewEntry);
|
||||
};
|
||||
|
||||
var initialize = function() {
|
||||
makeEditable();
|
||||
bindTriggers();
|
||||
};
|
||||
|
||||
initialize();
|
||||
});
|
||||
};
|
||||
|
||||
$(document).ready(function () {
|
||||
$('table.author_list').AuthorList();
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block submit_content %}
|
||||
<h2>Adjust External Meta-Data</h2>
|
||||
|
||||
<div id="idnits_results" style="visibility:hidden;">
|
||||
<div class="hd">
|
||||
<span style="display: none;" id="twopages_title">First two pages</span>
|
||||
</div>
|
||||
<div class="bd">
|
||||
<div id="stream_dialog_body" style="padding: 0em 5em; height: 400px; overflow: auto;">
|
||||
<pre class="twopages" style="display: none;">{{ detail.first_two_pages }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="metadata-table">
|
||||
<tr><th>Document</th><td>{{ detail.filename }} <a class="twopages_trigger" href="#">[View first two pages]</a>
|
||||
{% show_submission_files detail %}
|
||||
</td></tr>
|
||||
<tr><th>Submission date</th><td>{{ detail.submission_date }}</td></tr>
|
||||
<tr{% if validation.warnings.group %} class="warning"{% endif %}><th>WG</th><td>{{ validation.wg|default:"Individual Submission" }}
|
||||
{% if validation.warnings.group %}
|
||||
<div class="warn_message">The secretariat will be notified that the working group is not active</div>
|
||||
{% endif %}
|
||||
</td></tr>
|
||||
<tr><th>File size</th><td>{{ detail.filesize|filesizeformat }}</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>Adjust data</h3>
|
||||
{% if form.errors %}
|
||||
<div class="metadata-errors">
|
||||
Please fix the following errors.
|
||||
</div>
|
||||
{% endif %}
|
||||
<form method="post" action="">
|
||||
<table class="metadata-table">
|
||||
<tr{% if form.errors.title %} class="warning"{% endif %}><th>Title</th><td>{{ form.title }}{{ form.errors.title }}</td></tr>
|
||||
<tr{% if form.errors.version %} class="warning"{% endif %}><th>Version</th><td>{{ form.version }}{{ form.errors.version }}</td></tr>
|
||||
<tr{% if form.errors.creation_date %} class="warning"{% endif %}><th>Creation date</th><td>{{ form.creation_date }}{{ form.errors.creation_date }}</td></tr>
|
||||
<tr{% if form.errors.pages %} class="warning"{% endif %}><th>Pages</th><td>{{ form.pages }}{{ form.errors.pages }}</td></tr>
|
||||
<tr{% if form.errors.abstract %} class="warning"{% endif %}><th>Abstract</th><td>{{ form.abstract }}{{ form.errors.abstract }}</td></tr>
|
||||
<tr><th>Submitter</th>
|
||||
<td>
|
||||
If you are one of the authors, then please click a button by your name to automatically fill in the submitter's information as requested below. Otherwise, Please manually enter your information.<br />
|
||||
{{ form.get_author_buttons|safe }}
|
||||
</td></tr>
|
||||
<tr{% if form.errors.first_name %} class="warning"{% endif %}><th class="author">First name</th><td>{{ form.first_name }}{{ form.errors.first_name }}</td></tr>
|
||||
<tr{% if form.errors.last_name %} class="warning"{% endif %}><th class="author">Last name</th><td>{{ form.last_name }}{{ form.errors.last_name }}</td></tr>
|
||||
<tr{% if form.errors.email %} class="warning"{% endif %}><th class="author">Email address</th><td>{{ form.email }}{{ form.errors.email }}</td></tr>
|
||||
<tr{% if form.errors.comments %} class="warning"{% endif %}><th>Comments to the secretariat</th><td>{{ form.comments }}{{ form.errors.comments }}</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>Authors</h3>
|
||||
<table class="author_list ietf-table" style="width: 100%;">
|
||||
<thead>
|
||||
<tr><th>First name</th><th>Last name</th><th>Email address</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for author in form.get_authors %}
|
||||
<tr class="editable {% cycle oddrow,evenrow %}{% if author.errors %} error{% endif %}">
|
||||
<td name="first_name"><span class="fieldValue">{{ author.first_name|default:"" }}</span><span class="field-error">{{ author.errors.first_name }}</span></td>
|
||||
<td name="last_name"><span class="fieldValue">{{ author.last_name|default:"" }}</span><span class="field-error">{{ author.errors.last_name }}</span></td>
|
||||
<td name="email"><span class="fieldValue">{{ author.email.1|default:"" }}</span><span class="field-error">{{ author.errors.email }}</span></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="text-align: right; margin-bottom: 1em;">
|
||||
<input type="button" value="Add another author" class="new_author" />
|
||||
</div>
|
||||
<input type="submit" value="Submit for manual posting" />
|
||||
</form>
|
||||
|
||||
<p>
|
||||
The IETF is an organized activity of the <a href="http://www.isoc.org">Internet Society</a>
|
||||
<br>Please send problem reports to <a href="mailto:ietf-action@ietf.org">ietf-action@ietf.org</a>.
|
||||
</p>
|
||||
{% endblock %}
|
242
ietf/templates/submit/draft_status.html
Normal file
242
ietf/templates/submit/draft_status.html
Normal file
|
@ -0,0 +1,242 @@
|
|||
{% extends "submit/submit_base.html" %}
|
||||
{% load submit_tags %}
|
||||
{% block title %}Submission status{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
{{ block.super }}
|
||||
div.metadata-errors { border: 1px solid red; background-color: #ffeebb; padding: 5px 10px; margin: 1em 0px; }
|
||||
div.info-message-error { border: 1px solid red; background-color: #ffeebb; padding: 5px 10px; margin: 1em 0px; color: red; }
|
||||
div.info-message-success { border: 1px solid green; background-color: #eeffbb; padding: 5px 10px; margin: 1em 0px; color: green; }
|
||||
table.metadata-table th { white-space: nowrap; font-weight: bold; }
|
||||
table.metadata-table #id_first_name, table.metadata-table #id_last_name { width: 200px; }
|
||||
table.metadata-table #id_email { width: 400px; }
|
||||
table.metadata-table th, table.metadata-table td { text-align: left; background: #ddddff; padding: 5px 10px; }
|
||||
table.metadata-table th.author { text-align: right; }
|
||||
table.metadata-table tr { vertical-align: top; }
|
||||
table.metadata-table tr.warning td, table.metadata-table tr.warning th { background-color: #ffaaaa; }
|
||||
table.metadata-table div.warn_message { color: red; }
|
||||
table.metadata-table ul.errorlist { color: red; padding: 0px; margin: 0px; list-style-type: none; }
|
||||
pre.twopages { margin: 0px; }
|
||||
{% endblock morecss %}
|
||||
|
||||
{% block pagehead %}
|
||||
<script type="text/javascript" src="/js/lib/jquery-1.4.2.min.js"></script>
|
||||
{% if can_cancel %}
|
||||
<script type="text/javascript">
|
||||
function confirmCancelation(){
|
||||
{% if is_valid %}if (confirm("Cancel this submission?")){% endif %}
|
||||
{% if submission_hash %}
|
||||
document.location = "{% url draft_cancel_by_hash detail.submission_id submission_hash %}";
|
||||
{% else %}
|
||||
document.location = "{% url draft_cancel detail.submission_id %}";
|
||||
{% endif %}
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
|
||||
$(document).ready(function () {
|
||||
var handleClose = function() {
|
||||
idnitsDialog.hide();
|
||||
};
|
||||
|
||||
var buttons = [{text:"Close", handler:handleClose, isDefault:true}];
|
||||
var kl = [new YAHOO.util.KeyListener(document, {keys:27}, handleClose)]
|
||||
var idnitsDialog = new YAHOO.widget.Dialog("idnits_results", {
|
||||
visible:false, draggable:false, close:true, modal:true,
|
||||
width:"860px", fixedcenter:true, constraintoviewport:true,
|
||||
buttons: buttons, keylisteners:kl});
|
||||
idnitsDialog.render();
|
||||
|
||||
var showIdnits = function() {
|
||||
$('#idnits_results').show();
|
||||
$('#idnits_title').show();
|
||||
$('#twopages_title').hide();
|
||||
$('pre.idnits_message').show();
|
||||
$('pre.twopages').hide();
|
||||
idnitsDialog.show();
|
||||
return false;
|
||||
}
|
||||
|
||||
var showTwoPages = function() {
|
||||
$('#idnits_results').show();
|
||||
$('#idnits_title').hide();
|
||||
$('#twopages_title').show();
|
||||
$('pre.idnits_message').hide();
|
||||
$('pre.twopages').show();
|
||||
idnitsDialog.show();
|
||||
return false;
|
||||
}
|
||||
|
||||
$('a.idnits_trigger').click(showIdnits);
|
||||
$('a.twopages_trigger').click(showTwoPages);
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block submit_content %}
|
||||
|
||||
{% if status %}
|
||||
<h2>Status of the submission: {{ status.status_value }}</h2>
|
||||
{% endif %}
|
||||
|
||||
{% if message %}
|
||||
<div class="info-message-{{ message.0 }}">{{ message.1 }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if auto_post_form.errors %}
|
||||
<div class="info-message-error">Please fix errors in the form below</div>
|
||||
{% endif %}
|
||||
|
||||
<h2>Check Page</h2>
|
||||
<p>
|
||||
{% if validation.passes_idnits %}
|
||||
Your draft has been verified to meet IDNITS requirements.
|
||||
{% else %}
|
||||
Your draft has NOT been verified to meet IDNITS requirements.
|
||||
{% endif %}
|
||||
<a class="idnits_trigger" href="#">(View IDNITS Results)</a>
|
||||
</p>
|
||||
<div id="idnits_results" style="visibility:hidden; display: none;">
|
||||
<div class="hd">
|
||||
<span style="display: none;" id="idnits_title">Idnits results</span>
|
||||
<span style="display: none;" id="twopages_title">First two pages</span>
|
||||
</div>
|
||||
<div class="bd">
|
||||
<div id="stream_dialog_body" style="padding: 0em 5em; height: 400px; overflow: auto;">
|
||||
<pre class="idnits_message" style="display: none;">{{ detail.idnits_message }}</pre>
|
||||
{{ detail|two_pages_decorated_with_validation:validation }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h2>Meta-Data from the Draft</h2>
|
||||
{% if validation.warnings %}
|
||||
<div class="metadata-errors">
|
||||
<h3>Meta-Data errors found</h3>
|
||||
<p>
|
||||
Please make sure that your Internet-Draft includes all of the required meta-data in the proper format.
|
||||
</p>
|
||||
<p>
|
||||
If your Internet-Draft *does* include all of the required meta-data in the proper format, and if
|
||||
the error(s) identified above are due to the failure of the tool to extract the meta-data correctly,
|
||||
then please use the 'Adjust Meta-Data' button below, which will take you to the 'Adjust Screen' where
|
||||
you can correct the improperly extracted meta-data. You will then be able to submit your Internet-Draft
|
||||
to the Secretariat for manual posting.
|
||||
</p>
|
||||
<p>
|
||||
If your Internet-Draft *does not* include all of the required meta-data in the proper format, then
|
||||
please cancel this submission, update your Internet-Draft, and resubmit it.
|
||||
</p>
|
||||
<p>
|
||||
<strong>NOTE:</strong> The Secretariat will NOT add any meta-data to your Internet-Draft or edit the meta-data. An
|
||||
Internet-Draft that does not include all of the required meta-data in the proper format WILL be
|
||||
returned to the submitter.
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<table class="metadata-table">
|
||||
<tr><th>Document</th><td>{{ detail.filename }} <a class="twopages_trigger" href="#">[View first two pages]</a>
|
||||
{% show_submission_files detail %}
|
||||
</td></tr>
|
||||
<tr{% if validation.warnings.revision %} class="warning"{% endif %}><th>Revision</th><td>{{ detail.revision }}<div class="warn_message">{{ validation.warnings.revision }}{% if validation.warnings.revision %}<br /><a class="twopages_trigger" href="#">[View error]</a>{% endif %}</div></td></tr>
|
||||
<tr><th>Submission date</th><td>{{ detail.submission_date }}</td></tr>
|
||||
<tr><th>Title</th><td>{{ detail.id_document_name }}</td></tr>
|
||||
<tr{% if validation.warnings.group %} class="warning"{% endif %}><th>WG</th><td>{{ validation.wg|default:"Individual Submission" }}<div class="warn_message">{{ validation.warnings.group }}</div></td></tr>
|
||||
<tr><th>File size</th><td>{{ detail.filesize|filesizeformat }}</td></tr>
|
||||
<tr{% if validation.warnings.creation_date %} class="warning"{% endif %}><th>Creation date</th><td>{{ detail.creation_date }}<div class="warn_message">{{ validation.warnings.creation_date }}</div></td></tr>
|
||||
<tr{% if validation.warnings.authors %} class="warning"{% endif %}><th colspan="2">Author(s) information</th></tr>
|
||||
{% if validation.warnings.authors %}
|
||||
<tr class="warning"><td colspan="2"><div class="warn_message">{{ validation.warnings.authors|safe }}</div></td></tr>
|
||||
{% endif %}
|
||||
{% if validation.authors %}
|
||||
{% for author in validation.authors %}
|
||||
<tr{% if validation.warnings.authors %} class="warning"{% endif %}><th class="author">Author {{ forloop.counter }}</th><td>{{ author.get_full_name }} {% if author.email.1 %}<{{ author.email.1 }}>{% endif %}</td></tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<tr{% if validation.warnings.pages %} class="warning"{% endif %}><th>Pages</th><td>{{ detail.txt_page_count }}<div class="warn_message">{{ validation.warnings.pages }}</div></td></tr>
|
||||
<tr{% if validation.warnings.abstract %} class="warning"{% endif %}><th>Abstract</th><td>{{ detail.abstract|linebreaksbr }}<div class="warn_message">{{ validation.warnings.abstract }}</div></td></tr>
|
||||
</table>
|
||||
|
||||
{% if allow_edit %}
|
||||
<form method="post" action="">
|
||||
<input type="submit" value="Adjust Meta-Data" value="adjust" /> (Leads to manual post by the Secretariat)
|
||||
</form>
|
||||
|
||||
{% if is_valid %}
|
||||
<h2>Please edit the following meta-data before proceeding to Auto-Post</h2>
|
||||
<p>
|
||||
If you are one of the authors of this document, then please click the button with your name on it to automatically fill in the submitter information as requested below. Otherwise, please manually enter your information.
|
||||
</p>
|
||||
<form method="post" action="">
|
||||
{{ auto_post_form.get_author_buttons|safe }}
|
||||
<table class="metadata-table">
|
||||
{{ auto_post_form }}
|
||||
</table>
|
||||
<input type="submit" value="Post" name="autopost" />
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% else %}
|
||||
{% if validation.submitter %}
|
||||
<h3>Submitter information</h3>
|
||||
<table class="metadata-table">
|
||||
<tr><th>First name</th><td>{{ validation.submitter.first_name }}</td></tr>
|
||||
<tr><th>Last name</th><td>{{ validation.submitter.last_name }}</td></tr>
|
||||
<tr><th>Email address</th><td>{{ validation.submitter.email_address|default:validation.submitter.email.1 }}</td></tr>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if can_cancel %}
|
||||
<h2>Cancel submission</h2>
|
||||
<p>
|
||||
<input type="button" onclick="confirmCancelation();" value="Cancel Submission" /><br>
|
||||
This submission will be canceled, and its uploaded document(s) permanently deleted.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if can_approve %}
|
||||
<p>
|
||||
<form method="post" action="/submit/status/{{ detail.submission_id }}/approve/">
|
||||
<input type="submit" value="Approve this submission" />
|
||||
</form>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if can_force_post %}
|
||||
<p>
|
||||
<form method="post" action="/submit/status/{{ detail.submission_id }}/force/">
|
||||
<input type="submit" value="Force post" />
|
||||
</form>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if show_notify_button %}
|
||||
<div class="metadata-errors">
|
||||
<p>
|
||||
You are not allowed to modify or cancel this submission. You only can modify or cancel this submission from the same url you were redirected after the submission.
|
||||
</p>
|
||||
<p>
|
||||
If you are the submitter check your browser history to find this url. You can share it with any person you need.
|
||||
</p>
|
||||
<p>
|
||||
If you are one of the authors you can request the url from wich you can modify or cancel this submission by clicking the next button. An email will be sent to the draft authors and to the submitter (if its email is available).
|
||||
</p>
|
||||
<form method="post" action="{% url full_url_request detail.submission_id %}">
|
||||
<input type="submit" value="Request full access url" />
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
<p>
|
||||
The IETF is an organized activity of the <a href="http://www.isoc.org">Internet Society</a>
|
||||
<br>Please send problem reports to <a href="mailto:ietf-action@ietf.org">ietf-action@ietf.org</a>.
|
||||
</p>
|
||||
{% endblock %}
|
21
ietf/templates/submit/manual_post_mail.txt
Normal file
21
ietf/templates/submit/manual_post_mail.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
Manual Posting Requested for the following Internet-Draft:
|
||||
|
||||
I-D Submission Tool URL: http://{{ domain }}/submit/status/{{ draft.submission_id }}/
|
||||
|
||||
File name: {{ draft.filename }}
|
||||
Submission date: {{ draft.submission_date }}
|
||||
WG: {{ draft.group_acronym|default:"Individual Submission" }} {% if form.validation.warnings.group %}*Please note that this WG is not an active one*{% endif %}
|
||||
File size: {{ draft.filesize|filesizeformat }}
|
||||
|
||||
Title: {{ draft.id_document_name }}
|
||||
Version: {{ draft.revision }}
|
||||
Creation date: {{ draft.creation_date }}
|
||||
Pages: {{ draft.txt_page_count }}
|
||||
Abstract: {{ draft.abstract }}
|
||||
Submitter: {{ form.cleaned_data.first_name }} {{ form.cleaned_data.last_name }} <{{ form.cleaned_data.email }}>
|
||||
|
||||
Author(s):
|
||||
{% for author in form.get_authors %}{{ author.first_name }} {{ author.last_name }} <{{ author.email.1 }}>
|
||||
{% endfor %}
|
||||
|
||||
{{ draft.comment_to_sec }}
|
27
ietf/templates/submit/note_well.html
Normal file
27
ietf/templates/submit/note_well.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
{% extends "submit/submit_base.html" %}
|
||||
{% block title %}Note Well{% endblock %}
|
||||
|
||||
{% block submit_content %}
|
||||
<h2>Note Well</h2>
|
||||
<p>Any submission to the IETF intended by the Contributor for publication as all or part of an IETF Internet-Draft or RFC and any statement made within the context of an IETF activity is considered an "IETF Contribution". Such statements include oral statements in IETF sessions, as well as written and electronic communications made at any time or place, which are addressed to:</p>
|
||||
|
||||
<ul>
|
||||
<li>The IETF plenary session</li>
|
||||
<li> The IESG, or any member thereof on behalf of the IESG</li>
|
||||
<li> Any IETF mailing list, including the IETF list itself, any working group
|
||||
or design team list, or any other list functioning under IETF auspices </li>
|
||||
<li> Any IETF working group or portion thereof</li>
|
||||
<li>The IAB or any member thereof on behalf of the IAB</li>
|
||||
<li> The RFC Editor or the Internet-Drafts function</li>
|
||||
</ul>
|
||||
|
||||
<p>All IETF Contributions are subject to the rules of <a href="http://www.ietf.org/rfc/rfc5378.txt">RFC 5378</a> and <a href="http://www.ietf.org/rfc/rfc3979.txt">RFC 3979</a> (updated by <a href="http://www.ietf.org/rfc/rfc4879.txt">RFC 4879</a>). </p>
|
||||
|
||||
<p>Statements made outside of an IETF session, mailing list or other function, that are clearly not intended to be input to an IETF activity, group or function, are not IETF Contributions in the context of this notice.</p>
|
||||
|
||||
<p>Please consult <a href="http://www.ietf.org/rfc/rfc5378.txt">RFC 5378</a> and <a href="http://www.ietf.org/rfc/rfc3979.txt">RFC 3979</a> for details.</p>
|
||||
|
||||
<p>A participant in any IETF activity is deemed to accept all IETF rules of process, as documented in Best Current Practices RFCs and IESG Statements.</p>
|
||||
|
||||
<p>A participant in any IETF activity acknowledges that written, audio and video records of meetings may be made and may be available to the public. </p>
|
||||
{% endblock %}
|
3
ietf/templates/submit/request_full_url.txt
Normal file
3
ietf/templates/submit/request_full_url.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
Follow this link to get full access to the submission of I-D {{ submission.filename }}-{{ submission.revision }}
|
||||
|
||||
http://{{ domain }}/submit/status/{{ submission.submission_id }}/{{ submission.get_hash }}/
|
19
ietf/templates/submit/submission_approval.txt
Normal file
19
ietf/templates/submit/submission_approval.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
WG chair approval is needed for posting of {{ draft.filename }}-{{ draft.revision }} draft
|
||||
|
||||
I-D Submission Tool URL: http://{{ domain }}/submit/status/{{ draft.submission_id }}/
|
||||
|
||||
File name: {{ draft.filename }}
|
||||
Submission date: {{ draft.submission_date }}
|
||||
WG: {{ draft.group_acronym|default:"Individual Submission" }}
|
||||
File size: {{ draft.filesize|filesizeformat }}
|
||||
|
||||
Title: {{ draft.id_document_name }}
|
||||
Version: {{ draft.revision }}
|
||||
Creation date: {{ draft.creation_date }}
|
||||
Pages: {{ draft.txt_page_count }}
|
||||
Abstract: {{ draft.abstract }}
|
||||
Submitter: {{ submitter.first_name }} {{ submitter.last_name }} <{{ submitter.email_address }}>
|
||||
|
||||
Author(s):
|
||||
{% for author in form.get_authors %}{{ author.first_name }} {{ author.last_name }} <{{ author.email.1 }}>
|
||||
{% endfor %}
|
7
ietf/templates/submit/submission_files.html
Normal file
7
ietf/templates/submit/submission_files.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
{% if files %}
|
||||
<ul>
|
||||
{% for file in files %}
|
||||
<li><a href="{{ file.url }}" target="_blank">{{ file.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
33
ietf/templates/submit/submit_base.html
Normal file
33
ietf/templates/submit/submit_base.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block morecss %}
|
||||
.ietf-navset {
|
||||
background:#214197 url(/images/yui/sprite.png) repeat-x left -1400px;
|
||||
color:white;
|
||||
border:1px solid black;
|
||||
padding:4px;
|
||||
}
|
||||
.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 %}
|
||||
<h1>IETF Internet-Draft Submission </h1>
|
||||
|
||||
<div class="ietf-navset">
|
||||
{% ifequal selected "index" %}<span class="selected">Upload</span>{% else %}<a href="{% url submit_index %}">Upload</a>{% endifequal %} |
|
||||
{% ifequal selected "status" %}<span class="selected">Status</span>{% else %}<a href="{% url submit_status %}">Status</a>{% endifequal %} |
|
||||
{% ifequal selected "instructions" %}<span class="selected">Tool Instructions</span>{% else %}<a href="{% url submit_tool_instructions %}">Tool Instructions</a>{% endifequal %} |
|
||||
{% 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 %}
|
20
ietf/templates/submit/submit_index.html
Normal file
20
ietf/templates/submit/submit_index.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
{% extends "submit/submit_base.html" %}
|
||||
{% block title %}Upload{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
{{ form.media }}
|
||||
{% endblock %}
|
||||
|
||||
{% block submit_content %}
|
||||
<p>This page is used to submit IETF Internet-Drafts to the Internet-Draft repository. The list of current Internet-Drafts can be accessed at <a href="http://www.ietf.org/ietf/1id-abstracts.txt">http://www.ietf.org/ietf/1id-abstracts.txt</a></p>
|
||||
<p>Internet-Drafts are working documents of the Internet Engineering Task Force (IETF), its areas, and its working groups. Note that other groups may also distribute working documents as Internet-Drafts.</p>
|
||||
<p>Internet-Drafts are draft documents, and are valid for a maximum of six months. They may be updated, replaced, or obsoleted by other documents at any time.</p>
|
||||
<p>If you run into problems when submitting an Internet-Draft using this and the following pages, you may alternatively submit your draft by email to <a href="mailto:internet-drafts@ietf.org">internet-drafts@ietf.org</a>. However, be advised that manual processing always takes additional time.</p>
|
||||
|
||||
{{ form }}
|
||||
|
||||
<p>
|
||||
The IETF is an organized activity of the <a href="http://www.isoc.org">Internet Society</a>
|
||||
<br>Please send problem reports to <a href="mailto:ietf-action@ietf.org">ietf-action@ietf.org</a>.
|
||||
</p>
|
||||
{% endblock %}
|
27
ietf/templates/submit/submit_status.html
Normal file
27
ietf/templates/submit/submit_status.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
{% extends "submit/submit_base.html" %}
|
||||
{% block title %}Submission status{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
{{ form.media }}
|
||||
{% endblock %}
|
||||
|
||||
{% block submit_content %}
|
||||
<p>
|
||||
Please enter the filename of the Internet-Draft who's status you wish to view:
|
||||
</p>
|
||||
|
||||
<form method="post" action="">
|
||||
{% if error %}<div style="color: red;">{{ error }}</div>{% endif %}
|
||||
<input type="text" name="filename" value="{{ filename|default:"draft-" }}" />
|
||||
<input type="submit" value="Find status" />
|
||||
</form>
|
||||
|
||||
<p>
|
||||
<strong>
|
||||
Please note that the Status page only displays the status of an Internet-Draft whose posting is still in progress or an Internet-Draft that has been successfully posted. </strong>
|
||||
</p>
|
||||
<p>
|
||||
The IETF is an organized activity of the <a href="http://www.isoc.org">Internet Society</a>
|
||||
<br>Please send problem reports to <a href="mailto:ietf-action@ietf.org">ietf-action@ietf.org</a>.
|
||||
</p>
|
||||
{% endblock %}
|
53
ietf/templates/submit/submitform.html
Normal file
53
ietf/templates/submit/submitform.html
Normal file
|
@ -0,0 +1,53 @@
|
|||
{% load i18n %}
|
||||
|
||||
<form class="submitform liaisonform" method="post" action="" enctype="multipart/form-data">
|
||||
|
||||
<div class="formconfig" style="display: none;">
|
||||
{% block formconfig %}
|
||||
<span class="info_update_url">{% url get_info %}</span>
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
<div class="baseform{% if form.edit %} baseformedit{% endif %}">
|
||||
{% if form.errors %}
|
||||
<div class="formErrors">
|
||||
Please correct the errors below.
|
||||
</div>
|
||||
{{ form.non_field_errors }}
|
||||
{% endif %}
|
||||
{% for fieldset in form.get_fieldsets %}
|
||||
{% if fieldset.name %}
|
||||
<div class="fieldset">
|
||||
<h2>{{ fieldset.name }}</h2>
|
||||
{% endif %}
|
||||
|
||||
{% for field in fieldset.fields %}
|
||||
<div id="baseform-fieldname-{{ field.html_name }}"
|
||||
class="{% if field.errors %}fieldError {% endif %}field BaseFormStringWidget{% if field.field.column_style %} {{ field.field.column_style }}{% endif %}">
|
||||
<label for="id_{{ field.html_name }}">{{ field.label }}
|
||||
{% if field.field.required %}
|
||||
<span class="fieldRequired" title="Required">*</span>
|
||||
{% endif %}
|
||||
</label>
|
||||
<div class="fieldWidget">
|
||||
<div id="{{ field.html_name }}_help" class="formHelp"> {{ field.help_text }}</div>
|
||||
{{ field }}
|
||||
{{ field.errors }}
|
||||
</div>
|
||||
<div class="endfield"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% if fieldset.name %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if not form.shutdown %}
|
||||
<div class="submitrow">
|
||||
<input type="submit" value="Upload" name="upload" />
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</form>
|
118
ietf/templates/submit/tool_instructions.html
Normal file
118
ietf/templates/submit/tool_instructions.html
Normal file
|
@ -0,0 +1,118 @@
|
|||
{% extends "submit/submit_base.html" %}
|
||||
{% block title %}Note Well{% endblock %}
|
||||
|
||||
{% block submit_content %}
|
||||
<h2>I-D Submission Tool Instructions</h2>
|
||||
<h3>Tool URL: <a href="{% url submit_index %}">http://datatracker.ietf.org/{% url submit_index %}</a></h3>
|
||||
This page will explain the purpose and content of each screen in the I-D Submission Tool, and the actions that result by clicking the form buttons on each screen.<br>
|
||||
|
||||
The specification for this tool can be found in <a href="http://www.ietf.org/rfc/rfc4228.txt?number=4228">RFC 4228</a>.
|
||||
<OL>
|
||||
<li>
|
||||
<b>Upload Screen</b>
|
||||
<p>
|
||||
The Upload screen is the first screen that a user will see when he or she starts the I-D submission process. A user can submit four different formats of an I-D, plain text, XML, PDF, and postscript, at the same time. Failure to submit a plain-text version will cause an error, and an error screen will be displayed.
|
||||
</p>
|
||||
<p>
|
||||
<u>Form buttons and resulting actions</u>:
|
||||
<table border="0">
|
||||
<tr valign="top">
|
||||
<td width="80"><i>.txt format: </i></td><td>Button to select a plain-text file of an I-D from a user's local file system. A plain-text version is mandatory and leaving the field blank will cause an error.</td>
|
||||
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td><i>.xml format: </i></td><td>Button to select an XML file of an I-D from a user's local file system. </td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td><i>.pdf format: </i></td><td>Button to select a PDF file of an I-D from a user's local file system. </td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td><i>.ps format: </i></td><td>Button to select a postscript file of an I-D from a user's local file system. </td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
|
||||
<td><i>Upload:</i></td><td>Button to upload the document(s). The tool will begin parsing the plain-text document and validate the document. The parsed meta-data will be displayed for user confirmation along with the validation results.</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li>
|
||||
<b>Validation Screen</b>
|
||||
<p>
|
||||
After a user uploads a plain-text version, or multiple versions of an I-D, the tool will parse the plain-text version, validate the I-D, and display the validation results with option(s) for next steps. The validation includes: checking for all IPR-related notices and I-D boilerplate described in <a href="http://www.ietf.org/ietf/1id-guidelines.html">Guidelines to Authors of Internet-Drafts</a>; the required sections described in <a href="http://www.ietf.org/ID-Checklist.html">the I-D Check List</a>; the version number; and the creation date.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
If the submission does not have any validation errors, then the user will be allowed to proceed with the automated posting process. This process will begin with submitter authentication, which will be done by e-mail.
|
||||
</p>
|
||||
<p>
|
||||
A user must carefully examine the meta-data that are displayed on this screen, and make sure that these data were extracted correctly. If the data were not extracted correctly, then the user can correct the errors via the Adjust page. In such a case, the user will pass the draft to the Secretariat for manual posting.
|
||||
</p>
|
||||
<u>Form buttons and resulting actions:</u><br>
|
||||
<table border="0">
|
||||
<tr valign="top">
|
||||
<td width="120"><i>Adjust Meta-Data: </i></td><td>Button to proceed to a screen with editable form fields for correcting the meta-data. A user can use this button to request manual posting by the Secretariat.</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td><i>Cancel: </i></td><td>Button to cancel the current submission. A user will be prompted for a confirmation before the submission is canceled. Once confirmed, the current submission will be canceled, the uploaded document(s) will be deleted permanently from the server, and a notification message will be sent to all authors with the IP address of the user who just canceled the submission.</td>
|
||||
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td colspan="2"><br></td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td colspan="2">When no meta-data error is detected:<br><br></td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td><i>Button(s) with Author's name(s): </i></td><td>Button(s) to automatically fill out the given name, family name, and email address of the authors. If the submitter is one of the authors, then the submitter's information will be automatically inserted in the appropriate fields. If the submitter is not one of the authors, then the submitter will need to manually fill out these fields.</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td><i>Post Now: </i></td><td>Button to start the automated posting process with submitter authentication. Once clicked, an email message will be sent to the submitter whose email address was provided within the form. The submitter will need to open the email message via his or her email application, and click the link provided in the message body.
|
||||
<br><br>
|
||||
|
||||
Once a link in the email body is clicked, the document gets pushed to the IETF Web and FTP sites, a notification is sent to the authors of the document, and an I-D Action announcement will be sent out within the next 15 minutes.
|
||||
<br><br>
|
||||
If the document requires an additional approval from a chair of a working group, i.e., for submission of a 00 version of a working group document, then a message will be sent to the chairs of the working group for the approval. Once approved, the document will be immediately announced and available via the IETF Web and FTP sites.</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li>
|
||||
<b>Adjust Screen</b>
|
||||
<p>
|
||||
This is the screen where a user can adjust any meta-data that could have been incorrectly parsed from the submitted document. The document with adjusted meta-data will be submitted to the Secretariat for manual posting.
|
||||
</p>
|
||||
<u>Form buttons and resulting actions:</u><br>
|
||||
<table border="0">
|
||||
<tr valign="top">
|
||||
|
||||
<td><i>Button(s) with Author's name(s): </i></td><td>Button(s) to automatically fill out the given name, family name, and email address of the authors. If the submitter is one of the authors, then the submitter's information will be automatically inserted in the appropriate fields. If the submitter is not one of the authors, then the submitter will need to manually fill out these fields.</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td width="200"><i>Submit for manual posting: </i></td><td>Button to send a manual posting request to the Secretariat including any corrected meta-data and comments for the Secretariat. Once clicked, a notification message will be sent to the Secretariat, and a receipt page will be displayed.
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td><i>Cancel: </i></td><td>Button to cancel the current submission. A user will be prompted for a confirmation before the submission is canceled. Once confirmed, the current submission will be canceled, the uploaded document(s) will be deleted permanently from the server, and a notification message will be sent to all authors with the IP address of the user who just canceled the submission.</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
<b>Status Screen</b>
|
||||
<p>
|
||||
The Status screen is the screen where a user can view the current status of a document that has just been submitted by the user, or a document that was submitted previously via the tool. If a link 'Status' is clicked from the tool's first page, then a form field will be provided for a user to look up a document by filename.
|
||||
</p>
|
||||
<u>Form buttons and resulting actions:</u><br>
|
||||
<table border="0">
|
||||
<tr valign="top">
|
||||
<td><i>Cancel: </i></td><td>Button to cancel the current submission. This button will be displayed only when the document is in the process of being submitted. A user will be prompted for a confirmation before the submission is canceled. Once confirmed, the current submission will be canceled, the uploaded document(s) will be deleted permanently from the server, and a notification message will be sent to all authors with the IP address of the user who just canceled the submission.</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li>
|
||||
<b>Problem Report</b>
|
||||
|
||||
<p>
|
||||
Please send problem reports to <a href="mailto:ietf-action@ietf.org">ietf-action@ietf.org</a>.
|
||||
</p>
|
||||
</li>
|
||||
</OL>
|
||||
{% endblock %}
|
|
@ -57,6 +57,7 @@ urlpatterns = patterns('',
|
|||
(r'^doc/', include('ietf.idrfc.urls')),
|
||||
(r'^wg/', include('ietf.wginfo.urls')),
|
||||
(r'^cookies/', include('ietf.cookies.urls')),
|
||||
(r'^submit/', include('ietf.submit.urls')),
|
||||
|
||||
(r'^$', 'ietf.idrfc.views.main'),
|
||||
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
|
|
Loading…
Reference in a new issue