Port submit to new schema, adding a set of tests and fixing some bugs
- Legacy-Id: 3436
This commit is contained in:
parent
95ef2adfcd
commit
6f10d2f3f7
|
@ -1,3 +1,4 @@
|
|||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.contrib import admin
|
||||
from ietf.submit.models import *
|
||||
|
||||
|
@ -9,7 +10,16 @@ class IdSubmissionDetailAdmin(admin.ModelAdmin):
|
|||
list_display = ['submission_id', 'filename', 'status_link', 'submission_date', 'last_updated_date',]
|
||||
ordering = [ '-submission_date' ]
|
||||
search_fields = ['filename', ]
|
||||
admin.site.register(IdSubmissionDetail, IdSubmissionDetailAdmin)
|
||||
raw_id_fields = ['group_acronym']
|
||||
|
||||
def status_link(self, instance):
|
||||
url = urlreverse('draft_status_by_hash',
|
||||
kwargs=dict(submission_id=instance.submission_id,
|
||||
submission_hash=instance.get_hash()))
|
||||
return '<a href="%s">%s</a>' % (url, instance.status)
|
||||
status_link.allow_tags = True
|
||||
|
||||
admin.site.register(IdSubmissionDetail, IdSubmissionDetailAdmin)
|
||||
|
||||
class IdApprovedDetailAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
@ -17,5 +27,5 @@ admin.site.register(IdApprovedDetail, IdApprovedDetailAdmin)
|
|||
|
||||
class TempIdAuthorsAdmin(admin.ModelAdmin):
|
||||
ordering = ["-id"]
|
||||
pass
|
||||
admin.site.register(TempIdAuthors, TempIdAuthorsAdmin)
|
||||
admin.site.register(TempIdAuthors, TempIdAuthorsAdmin)
|
||||
|
||||
|
|
102
ietf/submit/fixtures/idsubmissionstatus.xml
Normal file
102
ietf/submit/fixtures/idsubmissionstatus.xml
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<django-objects version="1.0">
|
||||
<object pk="-4" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Cancelled</field>
|
||||
</object>
|
||||
<object pk="-3" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Dead</field>
|
||||
</object>
|
||||
<object pk="-2" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Posted by the Secretariat</field>
|
||||
</object>
|
||||
<object pk="-1" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Posted</field>
|
||||
</object>
|
||||
<object pk="0" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Ready To Post</field>
|
||||
</object>
|
||||
<object pk="1" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Uploaded</field>
|
||||
</object>
|
||||
<object pk="2" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">ID NITS Passed</field>
|
||||
</object>
|
||||
<object pk="3" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Initial Version Approval Required</field>
|
||||
</object>
|
||||
<object pk="4" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Submitter Authentication Required</field>
|
||||
</object>
|
||||
<object pk="5" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Manual Post Requested</field>
|
||||
</object>
|
||||
<object pk="6" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">External Meta-Data Required</field>
|
||||
</object>
|
||||
<object pk="7" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Internal Database Has Been Updated</field>
|
||||
</object>
|
||||
<object pk="8" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">ID Announcement Scheduled</field>
|
||||
</object>
|
||||
<object pk="9" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">ID Tracker Notification Scheduled</field>
|
||||
</object>
|
||||
<object pk="10" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Initial Version Approval Requested</field>
|
||||
</object>
|
||||
<object pk="101" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Error - Plain text version does not exist</field>
|
||||
</object>
|
||||
<object pk="102" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">File size is larger than 20 MB</field>
|
||||
</object>
|
||||
<object pk="103" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Duplicate Internet-Draft submission is currently in process.</field>
|
||||
</object>
|
||||
<object pk="104" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Error - Simultaneous submission from the same IP address</field>
|
||||
</object>
|
||||
<object pk="105" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Error - Auth key does not match</field>
|
||||
</object>
|
||||
<object pk="106" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Error - No such Internet-Draft is currently in process</field>
|
||||
</object>
|
||||
<object pk="107" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Error - Draft is not in an appropriate status for the requested page</field>
|
||||
</object>
|
||||
<object pk="108" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Error - Unknown Request</field>
|
||||
</object>
|
||||
<object pk="109" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Error - Invalid Email Address</field>
|
||||
</object>
|
||||
<object pk="110" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Error - Direct Access is prohibited</field>
|
||||
</object>
|
||||
<object pk="201" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Error - Invalid version number</field>
|
||||
</object>
|
||||
<object pk="202" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Error - Invalid filename</field>
|
||||
</object>
|
||||
<object pk="203" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Error - The document failed idnits verification</field>
|
||||
</object>
|
||||
<object pk="204" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Creation Date must be within 3 days of the submission date.</field>
|
||||
</object>
|
||||
<object pk="205" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Error – Not a valid submitter</field>
|
||||
</object>
|
||||
<object pk="206" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Incorrect Meta-Data</field>
|
||||
</object>
|
||||
<object pk="111" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">The document does not contain a legitimate filename that start with draft-*.</field>
|
||||
</object>
|
||||
<object pk="11" model="submit.idsubmissionstatus">
|
||||
<field type="CharField" name="status_value">Initial Version Approved</field>
|
||||
</object>
|
||||
</django-objects>
|
|
@ -1,4 +1,4 @@
|
|||
import sha
|
||||
import hashlib
|
||||
import random
|
||||
import os
|
||||
import subprocess
|
||||
|
@ -10,6 +10,7 @@ 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 django.core.urlresolvers import reverse as urlreverse
|
||||
|
||||
from ietf.idtracker.models import InternetDraft, IETFWG
|
||||
from ietf.proceedings.models import Meeting
|
||||
|
@ -51,11 +52,8 @@ class UploadForm(forms.Form):
|
|||
def read_dates(self):
|
||||
now = datetime.datetime.utcnow()
|
||||
first_cut_off = Meeting.get_first_cut_off()
|
||||
print "first_cut_off:", first_cut_off
|
||||
second_cut_off = Meeting.get_second_cut_off()
|
||||
print "second_cut_off:", second_cut_off
|
||||
ietf_monday = Meeting.get_ietf_monday()
|
||||
print "ietf_monday:", 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 < settings.CUTOFF_HOUR:
|
||||
|
@ -252,7 +250,10 @@ class UploadForm(forms.Form):
|
|||
document_id = 0
|
||||
existing_draft = InternetDraft.objects.filter(filename=draft.filename)
|
||||
if existing_draft:
|
||||
document_id = existing_draft[0].id_document_tag
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
document_id = -1
|
||||
else:
|
||||
document_id = existing_draft[0].id_document_tag
|
||||
detail = IdSubmissionDetail.objects.create(
|
||||
id_document_name=draft.get_title(),
|
||||
filename=draft.filename,
|
||||
|
@ -274,22 +275,34 @@ class UploadForm(forms.Form):
|
|||
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)
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
# save full name
|
||||
TempIdAuthors.objects.create(
|
||||
id_document_tag=document_id,
|
||||
first_name=full_name.strip(),
|
||||
email_address=email,
|
||||
author_order=order,
|
||||
submission=detail)
|
||||
else:
|
||||
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)
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
name = forms.CharField(required=True)
|
||||
else:
|
||||
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):
|
||||
|
@ -298,10 +311,21 @@ class AutoPostForm(forms.Form):
|
|||
super(AutoPostForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_author_buttons(self):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
buttons = []
|
||||
for i in self.validation.authors:
|
||||
buttons.append('<input type="button" data-name="%(name)s" data-email="%(email)s" value="%(name)s" />'
|
||||
% dict(name=i.get_full_name(),
|
||||
email=i.email()[1] or ''))
|
||||
return "".join(buttons)
|
||||
|
||||
|
||||
# this should be moved to a Javascript file and attributes like data-first-name ...
|
||||
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)
|
||||
full_name = u'%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 '',
|
||||
|
@ -317,10 +341,22 @@ class AutoPostForm(forms.Form):
|
|||
subject = 'Confirmation for Auto-Post of I-D %s' % self.draft.filename
|
||||
from_email = settings.IDSUBMIT_FROM_EMAIL
|
||||
to_email = self.cleaned_data['email']
|
||||
|
||||
confirm_url = settings.IDTRACKER_BASE_URL + urlreverse('draft_confirm', kwargs=dict(submission_id=self.draft.submission_id, auth_key=self.draft.auth_key))
|
||||
status_url = settings.IDTRACKER_BASE_URL + urlreverse('draft_status_by_hash', kwargs=dict(submission_id=self.draft.submission_id, submission_hash=self.draft.get_hash()))
|
||||
|
||||
send_mail(request, to_email, from_email, subject, 'submit/confirm_autopost.txt',
|
||||
{'draft': self.draft, 'domain': Site.objects.get_current().domain })
|
||||
{ 'draft': self.draft, 'confirm_url': confirm_url, 'status_url': status_url })
|
||||
|
||||
def save_submitter_info(self):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
return TempIdAuthors.objects.create(
|
||||
id_document_tag=self.draft.temp_id_document_tag,
|
||||
first_name=self.cleaned_data['name'],
|
||||
email_address=self.cleaned_data['email'],
|
||||
author_order=0,
|
||||
submission=self.draft)
|
||||
|
||||
return TempIdAuthors.objects.create(
|
||||
id_document_tag=self.draft.temp_id_document_tag,
|
||||
first_name=self.cleaned_data['first_name'],
|
||||
|
@ -330,8 +366,8 @@ class AutoPostForm(forms.Form):
|
|||
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()
|
||||
salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
|
||||
self.draft.auth_key = hashlib.sha1(salt+self.cleaned_data['email']).hexdigest()
|
||||
self.draft.status_id = WAITING_AUTHENTICATION
|
||||
self.draft.save()
|
||||
|
||||
|
@ -343,11 +379,18 @@ class MetaDataForm(AutoPostForm):
|
|||
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)
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
name = forms.CharField(required=True)
|
||||
else:
|
||||
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']
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
fields = ['title', 'version', 'creation_date', 'pages', 'abstract', 'name', 'email', 'comments']
|
||||
else:
|
||||
fields = ['title', 'version', 'creation_date', 'pages', 'abstract', 'first_name', 'last_name', 'email', 'comments']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MetaDataForm, self).__init__(*args, **kwargs)
|
||||
|
@ -358,26 +401,44 @@ class MetaDataForm(AutoPostForm):
|
|||
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'])))
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
if key.startswith('name_'):
|
||||
author = {'errors': {}}
|
||||
index = key.replace('name_', '')
|
||||
name = value.strip()
|
||||
if not name:
|
||||
author['errors']['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 name or email:
|
||||
author.update({'get_full_name': name,
|
||||
'email': (name, email),
|
||||
'index': index,
|
||||
})
|
||||
authors.append(author)
|
||||
|
||||
else:
|
||||
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(key=lambda x: x['index'])
|
||||
return authors
|
||||
|
||||
def set_initials(self):
|
||||
|
@ -437,7 +498,7 @@ class MetaDataForm(AutoPostForm):
|
|||
|
||||
def save_new_draft_info(self):
|
||||
draft = self.draft
|
||||
draft.id_documen_name = self.cleaned_data['title']
|
||||
draft.id_document_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']
|
||||
|
@ -447,7 +508,21 @@ class MetaDataForm(AutoPostForm):
|
|||
draft.comment_to_sec = self.cleaned_data['comments']
|
||||
draft.status_id = MANUAL_POST_REQUESTED
|
||||
draft.save()
|
||||
self.save_submitter_info()
|
||||
|
||||
# sync authors
|
||||
draft.tempidauthors_set.all().delete()
|
||||
|
||||
self.save_submitter_info() # submitter is author 0
|
||||
|
||||
for i, author in enumerate(self.authors):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
# save full name
|
||||
TempIdAuthors.objects.create(
|
||||
id_document_tag=draft.temp_id_document_tag,
|
||||
first_name=author["get_full_name"],
|
||||
email_address=author["email"][1],
|
||||
author_order=i + 1,
|
||||
submission=draft)
|
||||
|
||||
def save(self, request):
|
||||
self.save_new_draft_info()
|
||||
|
@ -462,5 +537,11 @@ class MetaDataForm(AutoPostForm):
|
|||
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)
|
||||
submitter = self.draft.tempidauthors_set.get(author_order=0)
|
||||
send_mail(request, to_email, from_email, subject, 'submit/manual_post_mail.txt', {
|
||||
'form': self,
|
||||
'draft': self.draft,
|
||||
'url': settings.IDTRACKER_BASE_URL + urlreverse('draft_status', kwargs=dict(submission_id=self.draft.submission_id)),
|
||||
'submitter': submitter
|
||||
},
|
||||
cc=cc)
|
||||
|
|
34
ietf/submit/generate_fixtures.py
Executable file
34
ietf/submit/generate_fixtures.py
Executable file
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# boiler plate
|
||||
import os, sys
|
||||
|
||||
ietf_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../ietf'))
|
||||
|
||||
sys.path.insert(0, ietf_path)
|
||||
|
||||
from django.core.management import setup_environ
|
||||
import settings
|
||||
setup_environ(settings)
|
||||
|
||||
# script
|
||||
from django.core.serializers import serialize
|
||||
from django.db.models import Q
|
||||
|
||||
def output(name, qs):
|
||||
try:
|
||||
f = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures/%s.xml" % name), 'w')
|
||||
f.write(serialize("xml", qs, indent=4))
|
||||
f.close()
|
||||
except:
|
||||
from django.db import connection
|
||||
from pprint import pprint
|
||||
pprint(connection.queries)
|
||||
raise
|
||||
|
||||
# pick all name models directly out of the module
|
||||
names = []
|
||||
|
||||
from ietf.submit.models import IdSubmissionStatus
|
||||
|
||||
output("idsubmissionstatus", IdSubmissionStatus.objects.all())
|
|
@ -60,9 +60,6 @@ class IdSubmissionDetail(models.Model):
|
|||
self.create_hash()
|
||||
self.save()
|
||||
return self.submission_hash
|
||||
def status_link(self):
|
||||
return '<a href="http://datatracker.ietf.org/submit/status/%s/%s/">%s</a>' % (self.submission_id, self.submission_hash, self.status)
|
||||
status_link.allow_tags = True
|
||||
|
||||
|
||||
def create_submission_hash(sender, instance, **kwargs):
|
||||
|
@ -86,7 +83,7 @@ class IdApprovedDetail(models.Model):
|
|||
|
||||
class TempIdAuthors(models.Model):
|
||||
id_document_tag = models.IntegerField()
|
||||
first_name = models.CharField(blank=True, max_length=255)
|
||||
first_name = models.CharField(blank=True, max_length=255) # with new schema, this contains the full name while the other name fields are empty to avoid loss of information
|
||||
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)
|
||||
|
@ -100,13 +97,11 @@ class TempIdAuthors(models.Model):
|
|||
db_table = 'temp_id_authors'
|
||||
|
||||
def email(self):
|
||||
return ('%s %s' % (self.first_name, self.last_name), self.email_address)
|
||||
return (self.get_full_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
|
||||
parts = (self.first_name or '', self.middle_initial or '', self.last_name or '', self.name_suffix or '')
|
||||
return u" ".join(x.strip() for x in parts if x.strip())
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s <%s>" % self.email()
|
||||
return u"%s <%s>" % self.email()
|
||||
|
|
|
@ -65,23 +65,3 @@ class PlainParser(FileParser):
|
|||
self.parsed_info.metadraft.filename = filename
|
||||
return
|
||||
self.parsed_info.add_error('The first page of 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)
|
||||
|
|
|
@ -17,9 +17,6 @@ def show_submission_files(context, submission):
|
|||
'url': '%s%s-%s%s' % (settings.IDSUBMIT_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):
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Informational Test Name
|
||||
Internet-Draft Test Center Inc.
|
||||
Intended status: Informational
|
||||
Expires: %(expire)s %(date)s
|
||||
Intended status: Informational %(date)s
|
||||
Expires: %(expire)s
|
||||
|
||||
|
||||
Testing tests
|
||||
|
@ -15,9 +15,7 @@ Abstract
|
|||
Status of this Memo
|
||||
|
||||
This Internet-Draft is submitted in full conformance with the
|
||||
provisions of BCP 78 and BCP 79. This document may not be modified,
|
||||
and derivative works of it may not be created, and it may not be
|
||||
published except as an Internet-Draft.
|
||||
provisions of BCP 78 and BCP 79.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF). Note that other groups may also distribute
|
||||
|
@ -41,73 +39,73 @@ Copyright Notice
|
|||
(http://trustee.ietf.org/license-info) in effect on the date of
|
||||
publication of this document. Please review these documents
|
||||
carefully, as they describe your rights and restrictions with respect
|
||||
to this document.
|
||||
|
||||
This Informational Internet Draft is submitted as an RFC Editor
|
||||
|
||||
to this document. Code Components extracted from this document must
|
||||
|
||||
|
||||
Name Expires %(expire)s [Page 1]
|
||||
|
||||
|
||||
Internet-Draft Testing tests %(month_year)s
|
||||
|
||||
Contribution and/or non-IETF Document (not as a Contribution, IETF
|
||||
Contribution, nor IETF Document) in accordance with BCP 78 and BCP
|
||||
79.
|
||||
include Simplified BSD License text as described in Section 4.e of
|
||||
the Trust Legal Provisions and are provided without warranty as
|
||||
described in the Simplified BSD License.
|
||||
|
||||
This document may contain material from IETF Documents or IETF
|
||||
Contributions published or made publicly available before November
|
||||
10, 2008. The person(s) controlling the copyright in some of this
|
||||
material may not have granted the IETF Trust the right to allow
|
||||
modifications of such material outside the IETF Standards Process.
|
||||
Without obtaining an adequate license from the person(s) controlling
|
||||
the copyright in such materials, this document may not be modified
|
||||
outside the IETF Standards Process, and derivative works of it may
|
||||
not be created outside the IETF Standards Process, except to format
|
||||
it for publication as an RFC or to translate it into languages other
|
||||
than English.
|
||||
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
|
||||
2. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 4
|
||||
3. Security Considerations . . . . . . . . . . . . . . . . . . . 4
|
||||
|
||||
|
||||
Name Expires %(expire)s [Page 2]
|
||||
|
||||
|
||||
Internet-Draft Testing tests %(month_year)s
|
||||
|
||||
1. Introduction
|
||||
|
||||
This document describes a protocol for testing tests.
|
||||
|
||||
Name Expires %(expire)s [Page 3]
|
||||
|
||||
Internet-Draft Testing tests %(month_year)s
|
||||
|
||||
2. Security Considerations
|
||||
|
||||
There are none.
|
||||
|
||||
|
||||
3. IANA Considerations
|
||||
|
||||
No new registrations for IANA.
|
||||
|
||||
|
||||
Authors' Addresses
|
||||
|
||||
Test Name
|
||||
Test Center Inc.
|
||||
Some way 42
|
||||
Some Where, NY
|
||||
|
||||
Email: testname@example.com
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Name Expires %(expire)s [Page 4]
|
||||
|
|
|
@ -13,56 +13,325 @@ from ietf.utils.test_data import make_test_data
|
|||
|
||||
from redesign.person.models import Person, Email
|
||||
from redesign.group.models import Group, Role
|
||||
from redesign.doc.models import Document
|
||||
|
||||
from redesign.doc.models import Document, BallotPositionDocEvent
|
||||
from ietf.submit.models import IdSubmissionDetail
|
||||
|
||||
class SubmitTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
fixtures = ['names', 'idsubmissionstatus']
|
||||
|
||||
def setUp(self):
|
||||
self.staging_dir = os.path.abspath("tmp-submit-staging-dir")
|
||||
os.mkdir(self.staging_dir)
|
||||
|
||||
settings.IDSUBMIT_STAGING_PATH = self.staging_dir
|
||||
|
||||
self.repository_dir = os.path.abspath("tmp-submit-repository-dir")
|
||||
os.mkdir(self.repository_dir)
|
||||
settings.IDSUBMIT_REPOSITORY_PATH = self.repository_dir
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.staging_dir)
|
||||
shutil.rmtree(self.repository_dir)
|
||||
|
||||
def test_submit(self):
|
||||
def do_submission(self, name, rev):
|
||||
# break early in case of missing configuration
|
||||
self.assertTrue(os.path.exists(settings.IDSUBMIT_IDNITS_BINARY))
|
||||
|
||||
draft = make_test_data()
|
||||
|
||||
url = urlreverse('submit_index')
|
||||
|
||||
# get
|
||||
url = urlreverse('submit_index')
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('input[type=file][name=txt]')), 1)
|
||||
|
||||
# submit text draft
|
||||
filename = "draft-mars-testing-tests-00"
|
||||
|
||||
# construct appropriate text file
|
||||
# construct appropriate text draft
|
||||
f = open(os.path.join(settings.BASE_DIR, "submit", "test_submission.txt"))
|
||||
template = f.read()
|
||||
f.close()
|
||||
|
||||
submission_text = template % dict(
|
||||
date=datetime.date.today().strftime("%Y-%m-%d"),
|
||||
date=datetime.date.today().strftime("%d %B %Y"),
|
||||
expire=(datetime.date.today() + datetime.timedelta(days=100)).strftime("%Y-%m-%d"),
|
||||
year=datetime.date.today().strftime("%Y"),
|
||||
month_year=datetime.date.today().strftime("%B, %Y"),
|
||||
filename=filename,
|
||||
filename="%s-%s" % (name, rev),
|
||||
)
|
||||
|
||||
test_file = StringIO(submission_text)
|
||||
|
||||
test_file = StringIO(str(submission_text))
|
||||
test_file.name = "somename.txt"
|
||||
|
||||
# submit
|
||||
r = self.client.post(url,
|
||||
dict(txt=test_file))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
self.assertTrue(os.path.exists(os.path.join(self.staging_dir, filename + ".txt")))
|
||||
supply_submitter_url = r["Location"]
|
||||
self.assertTrue(os.path.exists(os.path.join(self.staging_dir, u"%s-%s.txt" % (name, rev))))
|
||||
self.assertEquals(IdSubmissionDetail.objects.filter(filename=name).count(), 1)
|
||||
submission = IdSubmissionDetail.objects.get(filename=name)
|
||||
self.assertEquals(submission.group_acronym.acronym, "mars")
|
||||
self.assertEquals(submission.tempidauthors_set.count(), 1)
|
||||
author = submission.tempidauthors_set.all()[0]
|
||||
self.assertEquals(author.first_name, "Test Name")
|
||||
|
||||
return supply_submitter_url
|
||||
|
||||
def supply_submitter(self, name, supply_submitter_url):
|
||||
# check the page
|
||||
r = self.client.get(supply_submitter_url)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('input[type=submit][name=autopost]')), 1)
|
||||
|
||||
# post submitter info
|
||||
r = self.client.post(supply_submitter_url,
|
||||
dict(autopost="1",
|
||||
name="Test Name",
|
||||
email="testname@example.com",
|
||||
))
|
||||
# submitter is saved as author order 0
|
||||
submission = IdSubmissionDetail.objects.get(filename=name)
|
||||
self.assertEquals(submission.tempidauthors_set.count(), 2)
|
||||
self.assertEquals(submission.tempidauthors_set.get(author_order=0).first_name, "Test Name")
|
||||
|
||||
return r
|
||||
|
||||
def test_submit_new(self):
|
||||
# submit new -> supply submitter info -> approve
|
||||
draft = make_test_data()
|
||||
|
||||
name = "draft-ietf-mars-testing-tests"
|
||||
rev = "00"
|
||||
|
||||
supply_submitter_url = self.do_submission(name, rev)
|
||||
|
||||
# supply submitter info, then draft should be in and ready for approval
|
||||
mailbox_before = len(mail_outbox)
|
||||
r = self.supply_submitter(name, supply_submitter_url)
|
||||
|
||||
self.assertEquals(r.status_code, 302)
|
||||
status_url = r["Location"]
|
||||
self.assertEquals(len(mail_outbox), mailbox_before + 1)
|
||||
self.assertTrue("New draft waiting for approval" in mail_outbox[-1]["Subject"])
|
||||
self.assertTrue(name in mail_outbox[-1]["Subject"])
|
||||
|
||||
# as chair of WG, we should see approval button
|
||||
self.client.login(remote_user="marschairman")
|
||||
|
||||
r = self.client.get(status_url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
approve_submit = q('input[type=submit][value*="Approve"]')
|
||||
self.assertEquals(len(approve_submit), 1)
|
||||
|
||||
# approve submission
|
||||
mailbox_before = len(mail_outbox)
|
||||
approve_url = approve_submit.parents("form").attr("action")
|
||||
r = self.client.post(approve_url, dict())
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
draft = Document.objects.get(docalias__name=name)
|
||||
self.assertEquals(draft.rev, rev)
|
||||
new_revision = draft.latest_event()
|
||||
self.assertEquals(new_revision.type, "new_revision")
|
||||
self.assertEquals(new_revision.by.name, "Test Name")
|
||||
self.assertTrue(not os.path.exists(os.path.join(self.staging_dir, u"%s-%s.txt" % (name, rev))))
|
||||
self.assertTrue(os.path.exists(os.path.join(self.repository_dir, u"%s-%s.txt" % (name, rev))))
|
||||
self.assertEquals(draft.authors.count(), 1)
|
||||
self.assertEquals(draft.authors.all()[0].get_name(), "Test Name")
|
||||
self.assertEquals(draft.authors.all()[0].address, "testname@example.com")
|
||||
self.assertEquals(len(mail_outbox), mailbox_before + 2)
|
||||
self.assertTrue((u"I-D Action: %s" % name) in mail_outbox[-2]["Subject"])
|
||||
self.assertTrue("Test Name" in unicode(mail_outbox[-2]))
|
||||
self.assertTrue("New Version Notification" in mail_outbox[-1]["Subject"])
|
||||
self.assertTrue(name in unicode(mail_outbox[-1]))
|
||||
self.assertTrue("mars" in unicode(mail_outbox[-1]))
|
||||
|
||||
def test_submit_existing(self):
|
||||
# submit new revision of existing -> supply submitter info -> confirm
|
||||
draft = make_test_data()
|
||||
|
||||
# make a discuss to see if the AD gets an email
|
||||
ballot_position = BallotPositionDocEvent()
|
||||
ballot_position.pos_id = "discuss"
|
||||
ballot_position.type = "changed_ballot_position"
|
||||
ballot_position.doc = draft
|
||||
ballot_position.ad = ballot_position.by = Person.objects.get(user__username="ad2")
|
||||
ballot_position.save()
|
||||
|
||||
name = draft.name
|
||||
rev = "%02d" % (int(draft.rev) + 1)
|
||||
|
||||
supply_submitter_url = self.do_submission(name, rev)
|
||||
|
||||
# supply submitter info, then we get a confirmation email
|
||||
mailbox_before = len(mail_outbox)
|
||||
r = self.supply_submitter(name, supply_submitter_url)
|
||||
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertTrue("Your submission is pending email authentication" in r.content)
|
||||
|
||||
self.assertEquals(len(mail_outbox), mailbox_before + 1)
|
||||
confirmation = mail_outbox[-1]
|
||||
self.assertTrue("Confirmation for" in confirmation["Subject"])
|
||||
self.assertTrue(name in confirmation["Subject"])
|
||||
|
||||
# dig out confirmation link
|
||||
msg = confirmation.get_payload(i=1).get_payload(i=0).get_payload(decode=True)
|
||||
line_start = "I-D Submission Tool URL:"
|
||||
self.assertTrue(line_start in msg)
|
||||
confirm_url = None
|
||||
for line in msg.split("\n"):
|
||||
if line.startswith(line_start):
|
||||
confirm_url = line[len(line_start):].strip()
|
||||
|
||||
# go to confirm page
|
||||
r = self.client.get(confirm_url)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('input[type=submit][value=Auto-Post]')), 1)
|
||||
|
||||
# confirm
|
||||
mailbox_before = len(mail_outbox)
|
||||
r = self.client.post(confirm_url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertTrue('Authorization key accepted' in r.content)
|
||||
|
||||
draft = Document.objects.get(docalias__name=name)
|
||||
self.assertEquals(draft.rev, rev)
|
||||
new_revision = draft.latest_event()
|
||||
self.assertEquals(new_revision.type, "new_revision")
|
||||
self.assertEquals(new_revision.by.name, "Test Name")
|
||||
self.assertTrue(not os.path.exists(os.path.join(self.staging_dir, u"%s-%s.txt" % (name, rev))))
|
||||
self.assertTrue(os.path.exists(os.path.join(self.repository_dir, u"%s-%s.txt" % (name, rev))))
|
||||
self.assertEquals(draft.authors.count(), 1)
|
||||
self.assertEquals(draft.authors.all()[0].get_name(), "Test Name")
|
||||
self.assertEquals(draft.authors.all()[0].address, "testname@example.com")
|
||||
self.assertEquals(len(mail_outbox), mailbox_before + 3)
|
||||
self.assertTrue((u"I-D Action: %s" % name) in mail_outbox[-3]["Subject"])
|
||||
self.assertTrue("Test Name" in unicode(mail_outbox[-3]))
|
||||
self.assertTrue("New Version Notification" in mail_outbox[-2]["Subject"])
|
||||
self.assertTrue(name in unicode(mail_outbox[-2]))
|
||||
self.assertTrue("mars" in unicode(mail_outbox[-2]))
|
||||
self.assertTrue(draft.ad.email_address().address in unicode(mail_outbox[-2]))
|
||||
self.assertTrue(ballot_position.ad.email_address().address in unicode(mail_outbox[-2]))
|
||||
self.assertTrue("New Version Notification" in mail_outbox[-1]["Subject"])
|
||||
self.assertTrue(name in unicode(mail_outbox[-1]))
|
||||
self.assertTrue("mars" in unicode(mail_outbox[-1]))
|
||||
|
||||
def test_cancel_submission(self):
|
||||
# submit -> cancel
|
||||
draft = make_test_data()
|
||||
|
||||
name = "draft-ietf-mars-testing-tests"
|
||||
rev = "00"
|
||||
|
||||
supply_submitter_url = self.do_submission(name, rev)
|
||||
|
||||
# check we got cancel button
|
||||
r = self.client.get(supply_submitter_url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
cancel_submission = q('input[type=submit][value*="Cancel"]')
|
||||
self.assertEquals(len(cancel_submission), 1)
|
||||
|
||||
cancel_url = cancel_submission.parents("form").attr("action")
|
||||
|
||||
# cancel
|
||||
r = self.client.post(cancel_url)
|
||||
self.assertTrue(not os.path.exists(os.path.join(self.staging_dir, u"%s-%s.txt" % (name, rev))))
|
||||
|
||||
def test_edit_submission(self):
|
||||
# submit -> edit
|
||||
draft = make_test_data()
|
||||
|
||||
name = "draft-ietf-mars-testing-tests"
|
||||
rev = "00"
|
||||
|
||||
supply_submitter_url = self.do_submission(name, rev)
|
||||
|
||||
# check we got edit button
|
||||
r = self.client.get(supply_submitter_url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('input[type=submit][value*="Adjust"]')), 1)
|
||||
|
||||
# go to edit, we do this by posting, slightly weird
|
||||
r = self.client.post(supply_submitter_url)
|
||||
self.assertEquals(r.status_code, 302)
|
||||
edit_url = r['Location']
|
||||
|
||||
# check page
|
||||
r = self.client.get(edit_url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('input[name=title]')), 1)
|
||||
|
||||
# edit
|
||||
mailbox_before = len(mail_outbox)
|
||||
creation_date = datetime.date.today() - datetime.timedelta(days=-3)
|
||||
r = self.client.post(edit_url,
|
||||
dict(title="some title",
|
||||
version="00",
|
||||
creation_date=creation_date.strftime("%Y-%m-%d"),
|
||||
abstract="some abstract",
|
||||
pages="123",
|
||||
name="Some Random Test Person",
|
||||
email="random@example.com",
|
||||
comments="no comments",
|
||||
name_0="Person 1",
|
||||
email_0="person1@example.com",
|
||||
name_1="Person 2",
|
||||
email_1="person2@example.com",
|
||||
))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
submission = IdSubmissionDetail.objects.get(filename=name)
|
||||
self.assertEquals(submission.id_document_name, "some title")
|
||||
self.assertEquals(submission.creation_date, creation_date)
|
||||
self.assertEquals(submission.abstract, "some abstract")
|
||||
self.assertEquals(submission.txt_page_count, 123)
|
||||
self.assertEquals(submission.comment_to_sec, "no comments")
|
||||
|
||||
authors = submission.tempidauthors_set
|
||||
self.assertEquals(authors.count(), 3)
|
||||
# first one is submitter
|
||||
self.assertEquals(authors.get(author_order=0).first_name, "Some Random Test Person")
|
||||
self.assertEquals(authors.get(author_order=0).email_address, "random@example.com")
|
||||
self.assertEquals(authors.get(author_order=1).first_name, "Person 1")
|
||||
self.assertEquals(authors.get(author_order=1).email_address, "person1@example.com")
|
||||
self.assertEquals(authors.get(author_order=2).first_name, "Person 2")
|
||||
self.assertEquals(authors.get(author_order=2).email_address, "person2@example.com")
|
||||
|
||||
self.assertEquals(len(mail_outbox), mailbox_before + 1)
|
||||
self.assertTrue("Manual Post Requested" in mail_outbox[-1]["Subject"])
|
||||
self.assertTrue(name in mail_outbox[-1]["Subject"])
|
||||
|
||||
def test_request_full_url(self):
|
||||
# submit -> request full URL to be sent
|
||||
draft = make_test_data()
|
||||
|
||||
name = "draft-ietf-mars-testing-tests"
|
||||
rev = "00"
|
||||
|
||||
self.do_submission(name, rev)
|
||||
|
||||
submission = IdSubmissionDetail.objects.get(filename=name)
|
||||
url = urlreverse('draft_status', kwargs=dict(submission_id=submission.submission_id))
|
||||
|
||||
# check we got request full URL button
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
request_button = q('input[type=submit][value*="Request full access"]')
|
||||
self.assertEquals(len(request_button), 1)
|
||||
|
||||
request_url = request_button.parents("form").attr("action")
|
||||
|
||||
# request URL to be sent
|
||||
mailbox_before = len(mail_outbox)
|
||||
r = self.client.post(request_url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
|
||||
self.assertEquals(len(mail_outbox), mailbox_before + 1)
|
||||
self.assertTrue("Full URL for managing submission" in mail_outbox[-1]["Subject"])
|
||||
self.assertTrue(name in mail_outbox[-1]["Subject"])
|
||||
|
||||
|
||||
if not settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
|
|
|
@ -4,14 +4,20 @@ import datetime
|
|||
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
|
||||
from ietf.idtracker.models import (InternetDraft, PersonOrOrgInfo, IETFWG,
|
||||
IDAuthor, EmailAddress, IESGLogin, BallotInfo)
|
||||
from ietf.submit.models import TempIdAuthors
|
||||
from ietf.utils.mail import send_mail
|
||||
from ietf.idrfc.utils import add_document_comment
|
||||
from ietf.utils import unaccent
|
||||
|
||||
from redesign.doc.models import *
|
||||
from redesign.person.models import Person, Alias, Email
|
||||
from redesign.doc.utils import active_ballot_positions
|
||||
|
||||
# Some usefull states
|
||||
# Some useful states
|
||||
UPLOADED = 1
|
||||
WAITING_AUTHENTICATION = 4
|
||||
MANUAL_POST_REQUESTED = 5
|
||||
|
@ -26,12 +32,15 @@ NONE_WG = 1027
|
|||
|
||||
|
||||
def request_full_url(request, submission):
|
||||
subject = 'Full url for managing submission of draft %s' % submission.filename
|
||||
subject = 'Full URL for managing submission of draft %s' % submission.filename
|
||||
from_email = settings.IDSUBMIT_FROM_EMAIL
|
||||
to_email = ['%s <%s>' % i.email() for i in submission.tempidauthors_set.all()]
|
||||
to_email = list(set(u'%s <%s>' % i.email() for i in submission.tempidauthors_set.all()))
|
||||
url = settings.IDTRACKER_BASE_URL + urlreverse('draft_status_by_hash',
|
||||
kwargs=dict(submission_id=submission.submission_id,
|
||||
submission_hash=submission.get_hash()))
|
||||
send_mail(request, to_email, from_email, subject, 'submit/request_full_url.txt',
|
||||
{'submission': submission,
|
||||
'domain': Site.objects.get_current().domain})
|
||||
{'submission': submission,
|
||||
'url': url})
|
||||
|
||||
|
||||
def perform_post(submission):
|
||||
|
@ -80,6 +89,72 @@ def perform_post(submission):
|
|||
send_announcements(submission, draft, state_change_msg)
|
||||
submission.save()
|
||||
|
||||
def perform_postREDESIGN(submission):
|
||||
system = Person.objects.get(name="(System)")
|
||||
|
||||
group_id = submission.group_acronym_id or NONE_WG
|
||||
try:
|
||||
draft = Document.objects.get(name=submission.filename)
|
||||
save_document_in_history(draft)
|
||||
draft.tags.remove(DocInfoTagName.objects.get(slug="exp-tomb"))
|
||||
except Document.DoesNotExist:
|
||||
draft = Document(name=submission.filename)
|
||||
draft.intended_std_level = None
|
||||
|
||||
draft.time = datetime.datetime.now()
|
||||
draft.title = submission.id_document_name
|
||||
draft.group_id = group_id
|
||||
draft.rev = submission.revision
|
||||
draft.pages = submission.txt_page_count
|
||||
draft.abstract = submission.abstract
|
||||
was_rfc = draft.state_id == "rfc"
|
||||
draft.state_id = "active"
|
||||
draft.save()
|
||||
|
||||
DocAlias.objects.get_or_create(name=submission.filename, document=draft)
|
||||
|
||||
update_authors(draft, submission)
|
||||
|
||||
# new revision event
|
||||
try:
|
||||
a = submission.tempidauthors_set.get(author_order=0)
|
||||
submitter = ensure_person_email_info_exists(a).person
|
||||
except TempIdAuthors.DoesNotExist:
|
||||
submitter = system
|
||||
|
||||
e = NewRevisionDocEvent(type="new_revision", doc=draft, rev=draft.rev)
|
||||
e.time = draft.time #submission.submission_date
|
||||
e.by = submitter
|
||||
e.desc = "New revision available"
|
||||
e.save()
|
||||
|
||||
|
||||
# automatic state changes
|
||||
state_change_msg = ""
|
||||
|
||||
if not was_rfc and draft.tags.filter(slug="need-rev"):
|
||||
draft.tags.remove("need-rev")
|
||||
draft.tags.add("ad-f-up")
|
||||
|
||||
e = DocEvent(type="changed_document", doc=draft)
|
||||
e.desc = "Sub state has been changed to <b>AD Followup</b> from <b>Revised ID Needed</b>"
|
||||
e.by = system
|
||||
e.save()
|
||||
|
||||
state_change_msg = e.desc
|
||||
|
||||
move_docs(submission)
|
||||
submission.status_id = POSTED
|
||||
|
||||
announce_to_lists(submission)
|
||||
if draft.iesg_state != None and not was_rfc:
|
||||
announce_new_version(submission, draft, state_change_msg)
|
||||
announce_to_authors(submission)
|
||||
|
||||
submission.save()
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
perform_post = perform_postREDESIGN
|
||||
|
||||
def send_announcements(submission, draft, state_change_msg):
|
||||
announce_to_lists(submission)
|
||||
|
@ -126,9 +201,29 @@ def announce_new_version(submission, draft, state_change_msg):
|
|||
'msg': state_change_msg})
|
||||
|
||||
|
||||
def announce_new_versionREDESIGN(submission, draft, state_change_msg):
|
||||
to_email = []
|
||||
if draft.notify:
|
||||
to_email.append(draft.notify)
|
||||
if draft.ad:
|
||||
to_email.append(draft.ad.role_email("ad").address)
|
||||
|
||||
for ad, pos in active_ballot_positions(draft).iteritems():
|
||||
if pos and pos.pos_id == "discuss":
|
||||
to_email.append(ad.role_email("ad").address)
|
||||
|
||||
subject = 'New Version Notification - %s-%s.txt' % (submission.filename, submission.revision)
|
||||
from_email = settings.IDSUBMIT_ANNOUNCE_FROM_EMAIL
|
||||
send_mail(None, to_email, from_email, subject, 'submit/announce_new_version.txt',
|
||||
{'submission': submission,
|
||||
'msg': state_change_msg})
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
announce_new_version = announce_new_versionREDESIGN
|
||||
|
||||
def announce_to_authors(submission):
|
||||
authors = submission.tempidauthors_set.order_by('author_order')
|
||||
cc = list(set([i.email()[1] for i in authors]))
|
||||
cc = list(set(i.email()[1] for i in authors if i.email() != authors[0].email()))
|
||||
to_email = [authors[0].email()[1]] # First TempIdAuthor is submitter
|
||||
from_email = settings.IDSUBMIT_ANNOUNCE_FROM_EMAIL
|
||||
subject = 'New Version Notification for %s-%s.txt' % (submission.filename, submission.revision)
|
||||
|
@ -202,6 +297,85 @@ def update_authors(draft, submission):
|
|||
idauthor.save()
|
||||
draft.authors.exclude(person__pk__in=person_pks).delete()
|
||||
|
||||
def get_person_from_author(author):
|
||||
persons = None
|
||||
|
||||
# try email
|
||||
if author.email_address:
|
||||
persons = Person.objects.filter(email__address=author.email_address).distinct()
|
||||
if len(persons) == 1:
|
||||
return persons[0]
|
||||
|
||||
if not persons:
|
||||
persons = Person.objects.all()
|
||||
|
||||
# try full name
|
||||
p = persons.filter(alias__name=author.get_full_name()).distinct()
|
||||
if p:
|
||||
return p[0]
|
||||
|
||||
return None
|
||||
|
||||
def ensure_person_email_info_exists(author):
|
||||
person = get_person_from_author(author)
|
||||
|
||||
# make sure we got a person
|
||||
if not person:
|
||||
person = Person()
|
||||
person.name = author.get_full_name()
|
||||
person.ascii = unaccent.asciify(person.name)
|
||||
person.save()
|
||||
|
||||
Alias.objects.create(name=person.name, person=person)
|
||||
if person.name != person.ascii:
|
||||
Alias.objects.create(name=ascii, person=person)
|
||||
|
||||
# make sure we got an email address
|
||||
if author.email_address:
|
||||
addr = author.email_address.lower()
|
||||
else:
|
||||
# we're in trouble, use a fake one
|
||||
addr = u"unknown-email-%s" % person.name.replace(" ", "-")
|
||||
|
||||
try:
|
||||
email = person.email_set.get(address=addr)
|
||||
except Email.DoesNotExist:
|
||||
try:
|
||||
# maybe it's pointing to someone else
|
||||
email = Email.objects.get(address=addr)
|
||||
except Email.DoesNotExist:
|
||||
# most likely we just need to create it
|
||||
email = Email(address=addr)
|
||||
email.active = False
|
||||
|
||||
email.person = person
|
||||
email.save()
|
||||
|
||||
return email
|
||||
|
||||
|
||||
def update_authorsREDESIGN(draft, submission):
|
||||
# order 0 is submitter
|
||||
authors = []
|
||||
for author in submission.tempidauthors_set.exclude(author_order=0).order_by('author_order'):
|
||||
email = ensure_person_email_info_exists(author)
|
||||
|
||||
try:
|
||||
a = DocumentAuthor.objects.get(document=draft, author=email)
|
||||
except DocumentAuthor.DoesNotExist:
|
||||
a = DocumentAuthor(document=draft, author=email)
|
||||
|
||||
a.order = author.author_order
|
||||
a.save()
|
||||
|
||||
authors.append(email)
|
||||
|
||||
draft.documentauthor_set.exclude(author__in=authors).delete()
|
||||
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
update_authors = update_authorsREDESIGN
|
||||
|
||||
|
||||
def get_person_for_user(user):
|
||||
try:
|
||||
|
@ -215,6 +389,8 @@ def is_secretariat(user):
|
|||
return False
|
||||
return bool(user.groups.filter(name='Secretariat'))
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.liaisons.accounts import is_secretariat, get_person_for_user
|
||||
|
||||
def move_docs(submission):
|
||||
for ext in submission.file_type.split(','):
|
||||
|
@ -274,7 +450,7 @@ class DraftValidation(object):
|
|||
self.validate_wg()
|
||||
|
||||
def validate_wg(self):
|
||||
if self.wg and not self.wg.status.pk == IETFWG.ACTIVE:
|
||||
if self.wg and not self.wg.status_id == IETFWG.ACTIVE:
|
||||
self.add_warning('group', 'Working Group exists but is not an active WG')
|
||||
|
||||
def validate_abstract(self):
|
||||
|
@ -314,8 +490,7 @@ class DraftValidation(object):
|
|||
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
|
||||
return self.draft.tempidauthors_set.exclude(author_order=0).order_by('author_order')
|
||||
|
||||
def get_submitter(self):
|
||||
submitter = self.draft.tempidauthors_set.filter(author_order=0)
|
||||
|
|
|
@ -127,9 +127,9 @@ def draft_status(request, submission_id, submission_hash=None, message=None):
|
|||
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)
|
||||
authors = detail.tempidauthors_set.exclude(author_order=0).order_by('author_order')
|
||||
send_mail(request, to_email, from_email, subject, 'submit/submission_approval.txt',
|
||||
{'submitter': submitter, 'form': metadata_form,
|
||||
{'submitter': submitter, 'authors': authors,
|
||||
'draft': detail, 'domain': Site.objects.get_current().domain})
|
||||
return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': detail.submission_id}))
|
||||
else:
|
||||
|
@ -144,7 +144,11 @@ def draft_status(request, submission_id, submission_hash=None, message=None):
|
|||
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}))
|
||||
submission_hash = detail.get_hash()
|
||||
if submission_hash:
|
||||
return HttpResponseRedirect(reverse('draft_edit_by_hash', None, kwargs={'submission_id': detail.submission_id, 'submission_hash': submission_hash}))
|
||||
else:
|
||||
return HttpResponseRedirect(reverse(draft_edit, None, kwargs={'submission_id': detail.submission_id }))
|
||||
else:
|
||||
auto_post_form = AutoPostForm(draft=detail, validation=validation)
|
||||
|
||||
|
@ -207,6 +211,7 @@ def draft_edit(request, submission_id, submission_hash=None):
|
|||
'detail': detail,
|
||||
'validation': validation,
|
||||
'form': form,
|
||||
'settings': settings
|
||||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
Follow this link to confirm you Auto-Post of I-D {{ draft.filename }}-{{ draft.revision }}
|
||||
Follow this link to confirm your 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 }}/
|
||||
I-D Submission Tool URL: {{ confirm_url|safe }}
|
||||
|
||||
Remember that you can cancel the submission from:
|
||||
http://{{ domain }}/submit/status/{{ draft.submission_id }}/{{ draft.get_hash }}/
|
||||
{{ status_url|safe }}
|
||||
|
|
|
@ -14,6 +14,7 @@ table.ietf-table span.field-error { display: block; color: red; }
|
|||
{% block pagehead %}
|
||||
{{ block.super }}
|
||||
|
||||
<script type="text/javascript" src="/js/draft-submit.js"></script>
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
|
||||
|
@ -118,8 +119,12 @@ Please fix the following errors.
|
|||
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>
|
||||
{% if settings.USE_DB_REDESIGN_PROXY_CLASSES %}
|
||||
<tr{% if form.errors.name %} class="warning"{% endif %}><th class="author">Name</th><td>{{ form.name }}{{ form.errors.name }}</td></tr>
|
||||
{% else %}
|
||||
<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>
|
||||
{% endif %}
|
||||
<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>
|
||||
|
@ -127,13 +132,25 @@ If you are one of the authors, then please click a button by your name to automa
|
|||
<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>
|
||||
<tr>
|
||||
{% if settings.USE_DB_REDESIGN_PROXY_CLASSES %}
|
||||
<th>Name</th>
|
||||
{% else %}
|
||||
<th>First name</th>
|
||||
<th>Last name</th>
|
||||
{% endif %}
|
||||
<th>Email address</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for author in form.get_authors %}
|
||||
<tr class="editable {% cycle oddrow,evenrow %}{% if author.errors %} error{% endif %}">
|
||||
{% if settings.USE_DB_REDESIGN_PROXY_CLASSES %}
|
||||
<td name="name"><span class="fieldValue">{{ author.get_full_name|default:"" }}</span><span class="field-error">{{ author.errors.name }}</span></td>
|
||||
{% else %}
|
||||
<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>
|
||||
{% endif %}
|
||||
<td name="email"><span class="fieldValue">{{ author.email.1|default:"" }}</span><span class="field-error">{{ author.errors.email }}</span></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -21,6 +21,7 @@ pre.twopages { margin: 0px; }
|
|||
|
||||
{% block pagehead %}
|
||||
<script type="text/javascript" src="/js/lib/jquery-1.4.2.min.js"></script>
|
||||
<script type="text/javascript" src="/js/draft-submit.js"></script>
|
||||
{% if can_cancel %}
|
||||
<script type="text/javascript">
|
||||
function confirmCancelation(){
|
||||
|
@ -222,16 +223,16 @@ returned to the submitter.
|
|||
{% 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.
|
||||
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 to 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).
|
||||
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 the submitter's email is available).
|
||||
</p>
|
||||
<form method="post" action="{% url full_url_request detail.submission_id %}">
|
||||
<input type="submit" value="Request full access url" />
|
||||
<input type="submit" value="Request full access URL" />
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% autoescape off %}Manual posting has been requested for the following Internet-Draft:
|
||||
|
||||
I-D Submission Tool URL: http://{{ domain }}/submit/status/{{ draft.submission_id }}/
|
||||
I-D Submission Tool URL: {{ url }}
|
||||
|
||||
File name: {{ draft.filename }}
|
||||
Version: {{ draft.revision }}
|
||||
|
@ -13,10 +13,10 @@ Abstract: {{ draft.abstract }}
|
|||
Pages: {{ draft.txt_page_count }}
|
||||
File size: {{ draft.filesize|filesizeformat }}
|
||||
|
||||
Submitter: {{ form.cleaned_data.first_name }} {{ form.cleaned_data.last_name }} <{{ form.cleaned_data.email }}>
|
||||
Submitter: {{ submitter.get_full_name }} <{{ submitter.email.1 }}>
|
||||
|
||||
Author(s):
|
||||
{% for author in form.get_authors %}{{ author.first_name }} {{ author.last_name }} <{{ author.email.1 }}>
|
||||
Authors:
|
||||
{% for author in form.get_authors %}{{ author.get_full_name }} <{{ author.email.1 }}>
|
||||
{% endfor %}
|
||||
|
||||
{{ draft.comment_to_sec }}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
Follow this link to get full access to the submission of I-D {{ submission.filename }}-{{ submission.revision }}
|
||||
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 }}/
|
||||
{{ url|safe }}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
WG chair approval is needed for posting of {{ draft.filename }}-{{ draft.revision }} draft
|
||||
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 }}/{{ draft.submission_hash }}/
|
||||
|
||||
|
@ -13,8 +13,8 @@ Abstract: {{ draft.abstract }}
|
|||
Pages: {{ draft.txt_page_count }}
|
||||
File size: {{ draft.filesize|filesizeformat }}
|
||||
|
||||
Submitter: {{ submitter.first_name }} {{ submitter.last_name }} <{{ submitter.email_address }}>
|
||||
Submitter: {{ submitter.get_full_name }} <{{ submitter.email_address }}>
|
||||
|
||||
Author(s):
|
||||
{% for author in form.get_authors %}{{ author.first_name }} {{ author.last_name }} <{{ author.email.1 }}>
|
||||
Authors:
|
||||
{% for author in authors %}{{ author.get_full_name }} <{{ author.email.1 }}>
|
||||
{% endfor %}
|
||||
|
|
|
@ -142,7 +142,7 @@ def make_test_data():
|
|||
|
||||
# draft
|
||||
draft = Document.objects.create(
|
||||
name="draft-ietf-test",
|
||||
name="draft-ietf-mars-test",
|
||||
time=datetime.datetime.now(),
|
||||
type_id="draft",
|
||||
title="Optimizing Martian Network Topologies",
|
||||
|
|
49
redesign/doc/utils.py
Normal file
49
redesign/doc/utils.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
from redesign.doc.models import *
|
||||
|
||||
def get_state_types(doc):
|
||||
res = []
|
||||
|
||||
if not doc:
|
||||
return res
|
||||
|
||||
res.append(doc.type_id)
|
||||
#if doc.type_id in ("agenda", "minutes", "slides", "liai-att"):
|
||||
# res.append(doc.type_id)
|
||||
if doc.type_id == "draft":
|
||||
if doc.stream_id == "ietf":
|
||||
wg_specific = doc.type_id + ":" + "wg" + ":" + doc.group.acronym
|
||||
if State.objects.filter(type=wg_specific):
|
||||
res.append(wg_specific)
|
||||
else:
|
||||
res.append(doc.type_id + ":" + "wg")
|
||||
elif doc.stream_id == "irtf":
|
||||
res.append(doc.type_id + ":" + "rg")
|
||||
elif doc.stream_id == "iab":
|
||||
res.append(doc.type_id + ":" + "iab")
|
||||
elif doc.stream_id == "ise":
|
||||
res.append(doc.type_id + ":" + "ise")
|
||||
|
||||
res.append(doc.type_id + ":" + "iesg")
|
||||
res.append(doc.type_id + ":" + "iana")
|
||||
res.append(doc.type_id + ":" + "rfc-editor")
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def active_ballot_positions(doc):
|
||||
"""Return dict mapping each active AD to a current ballot position (or None if they haven't voted)."""
|
||||
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active"))
|
||||
res = {}
|
||||
|
||||
positions = BallotPositionDocEvent.objects.filter(doc=doc, type="changed_ballot_position", ad__in=active_ads).select_related('ad').order_by("-time", "-id")
|
||||
|
||||
for pos in positions:
|
||||
if pos.ad not in res:
|
||||
res[pos.ad] = pos
|
||||
|
||||
for ad in active_ads:
|
||||
if ad not in res:
|
||||
res[ad] = None
|
||||
|
||||
return res
|
||||
|
|
@ -28,10 +28,15 @@ class PersonInfo(models.Model):
|
|||
else:
|
||||
prefix, first, middle, last, suffix = self.ascii_parts()
|
||||
return (first and first[0]+"." or "")+(middle or "")+" "+last+(suffix and " "+suffix or "")
|
||||
def role_email(self, role_name, group):
|
||||
e = Email.objects.filter(person=self, role__group=group, role__name=role_name)
|
||||
if e:
|
||||
return e[0]
|
||||
def role_email(self, role_name, group=None):
|
||||
if group:
|
||||
e = Email.objects.filter(person=self, role__group=group, role__name=role_name)
|
||||
if e:
|
||||
return e[0]
|
||||
else:
|
||||
e = Email.objects.filter(person=self, role__group__state="active", role__name=role_name)
|
||||
if e:
|
||||
return e[0]
|
||||
e = self.email_set.order_by("-active")
|
||||
if e:
|
||||
return e[0]
|
||||
|
|
12
static/js/draft-submit.js
Normal file
12
static/js/draft-submit.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
$(function (){
|
||||
// fill in submitter info when an author button is clicked
|
||||
$("input[type=button]").click(function () {
|
||||
var name = $(this).data("name");
|
||||
if (name == null) // backwards compatibility
|
||||
return;
|
||||
var email = $(this).data("email");
|
||||
|
||||
$(this).parents("form").find("input[name=name]").val(name || "");
|
||||
$(this).parents("form").find("input[name=email]").val(email || "");
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue