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:
Henrik Levkowetz 2011-04-07 20:29:45 +00:00
commit 842b8f428f
37 changed files with 2664 additions and 3 deletions

View file

@ -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):

View file

@ -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)

View file

@ -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
View file

View 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
View 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)

View 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']

View 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']

View 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']

View file

102
ietf/submit/models.py Normal file
View 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

View file

View 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)))

View 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')

View 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)

View 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')

View 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')

View file

View 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
View 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
View 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
View 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)

View file

@ -64,7 +64,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<li class="sect">Drafts&nbsp;&amp;&nbsp;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>

View 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 }}/

View 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 %}

View 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 %}&lt;{{ author.email.1 }}&gt;{% 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 %}

View 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 }}

View 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 &quot;IETF Contribution&quot;. 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 %}

View 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 }}/

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View 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>

View 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 %}

View file

@ -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')),