Remove drafts secretariat tool because this functionality is now provided by the core Datatracker. Moved ID reports to proceedings tool. Fixes #1655. Commit ready for merge.
- Legacy-Id: 17488
This commit is contained in:
parent
931c5ce6cd
commit
5649bfdfd1
|
@ -16,7 +16,7 @@ import django
|
||||||
django.setup()
|
django.setup()
|
||||||
# -------------------------------------------------------------------------------------
|
# -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
from ietf.secr.drafts.reports import report_id_activity
|
from ietf.secr.proceedings.reports import report_id_activity
|
||||||
|
|
||||||
print(report_id_activity(sys.argv[1], sys.argv[2]), end='')
|
print(report_id_activity(sys.argv[1], sys.argv[2]), end='')
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import django
|
||||||
django.setup()
|
django.setup()
|
||||||
# -------------------------------------------------------------------------------------
|
# -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
from ietf.secr.drafts.reports import report_progress_report
|
from ietf.secr.proceedings.reports import report_progress_report
|
||||||
|
|
||||||
# handle unicode characters before attempting to print
|
# handle unicode characters before attempting to print
|
||||||
output = report_progress_report(sys.argv[1], sys.argv[2])
|
output = report_progress_report(sys.argv[1], sys.argv[2])
|
||||||
|
|
|
@ -1,178 +0,0 @@
|
||||||
# Copyright The IETF Trust 2013-2020, All Rights Reserved
|
|
||||||
import datetime
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
|
|
||||||
import debug # pyflakes:ignore
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.template.loader import render_to_string
|
|
||||||
|
|
||||||
from ietf.message.models import Message, SendQueue
|
|
||||||
from ietf.message.utils import send_scheduled_message_from_send_queue
|
|
||||||
from ietf.doc.models import DocumentAuthor
|
|
||||||
from ietf.person.models import Person
|
|
||||||
|
|
||||||
def announcement_from_form(data, **kwargs):
|
|
||||||
'''
|
|
||||||
This function creates a new message record. Taking as input EmailForm.data
|
|
||||||
and key word arguments used to override some of the message fields
|
|
||||||
'''
|
|
||||||
# possible overrides
|
|
||||||
by = kwargs.get('by',Person.objects.get(name='(System)'))
|
|
||||||
from_val = kwargs.get('from_val','Datatracker <internet-drafts-reply@ietf.org>')
|
|
||||||
content_type = kwargs.get('content_type','text/plain')
|
|
||||||
|
|
||||||
# from the form
|
|
||||||
subject = data['subject']
|
|
||||||
to_val = data['to']
|
|
||||||
cc_val = data['cc']
|
|
||||||
body = data['body']
|
|
||||||
|
|
||||||
message = Message.objects.create(by=by,
|
|
||||||
subject=subject,
|
|
||||||
frm=from_val,
|
|
||||||
to=to_val,
|
|
||||||
cc=cc_val,
|
|
||||||
body=body,
|
|
||||||
content_type=content_type)
|
|
||||||
|
|
||||||
# create SendQueue
|
|
||||||
send_queue = SendQueue.objects.create(by=by,message=message)
|
|
||||||
|
|
||||||
# uncomment for testing
|
|
||||||
send_scheduled_message_from_send_queue(send_queue)
|
|
||||||
|
|
||||||
return message
|
|
||||||
|
|
||||||
def get_authors(draft):
|
|
||||||
"""
|
|
||||||
Takes a draft object and returns a list of authors suitable for a tombstone document
|
|
||||||
"""
|
|
||||||
authors = []
|
|
||||||
for a in draft.documentauthor_set.all():
|
|
||||||
initial = ''
|
|
||||||
prefix, first, middle, last, suffix = a.person.name_parts()
|
|
||||||
if first:
|
|
||||||
initial = first + '. '
|
|
||||||
entry = '%s%s <%s>' % (initial,last,a.email.address)
|
|
||||||
authors.append(entry)
|
|
||||||
return authors
|
|
||||||
|
|
||||||
def get_abbr_authors(draft):
|
|
||||||
"""
|
|
||||||
Takes a draft object and returns a string of first author followed by "et al"
|
|
||||||
for use in New Revision email body.
|
|
||||||
"""
|
|
||||||
initial = ''
|
|
||||||
result = ''
|
|
||||||
authors = DocumentAuthor.objects.filter(document=draft).order_by("order")
|
|
||||||
|
|
||||||
if authors:
|
|
||||||
prefix, first, middle, last, suffix = authors[0].person.name_parts()
|
|
||||||
if first:
|
|
||||||
initial = first[0] + '. '
|
|
||||||
result = '%s%s' % (initial,last)
|
|
||||||
if len(authors) > 1:
|
|
||||||
result += ', et al'
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def get_last_revision(filename):
|
|
||||||
"""
|
|
||||||
This function takes a filename, in the same form it appears in the InternetDraft record,
|
|
||||||
no revision or extension (ie. draft-ietf-alto-reqs) and returns a string which is the
|
|
||||||
reivision number of the last active version of the document, the highest revision
|
|
||||||
txt document in the archive directory. If no matching file is found raise exception.
|
|
||||||
"""
|
|
||||||
files = glob.glob(os.path.join(settings.INTERNET_DRAFT_ARCHIVE_DIR,filename) + '-??.txt')
|
|
||||||
if files:
|
|
||||||
sorted_files = sorted(files)
|
|
||||||
return get_revision(sorted_files[-1])
|
|
||||||
else:
|
|
||||||
raise Exception('last revision not found in archive')
|
|
||||||
|
|
||||||
def get_revision(name):
|
|
||||||
"""
|
|
||||||
Takes a draft filename and returns the revision, as a string.
|
|
||||||
"""
|
|
||||||
#return name[-6:-4]
|
|
||||||
base,ext = os.path.splitext(name)
|
|
||||||
return base[-2:]
|
|
||||||
|
|
||||||
def get_fullcc_list(draft):
|
|
||||||
"""
|
|
||||||
This function takes a draft object and returns a string of emails to use in cc field
|
|
||||||
of a standard notification. Uses an intermediate "emails" dictionary, emails are the
|
|
||||||
key, name is the value, to prevent adding duplicate emails to the list.
|
|
||||||
"""
|
|
||||||
emails = {}
|
|
||||||
# get authors
|
|
||||||
for author in draft.documentauthor_set.all():
|
|
||||||
if author.email and author.email.address not in emails:
|
|
||||||
emails[author.email.address] = '"%s"' % (author.person.name)
|
|
||||||
|
|
||||||
if draft.group.acronym != 'none':
|
|
||||||
# add chairs
|
|
||||||
for role in draft.group.role_set.filter(name='chair'):
|
|
||||||
if role.email.address not in emails:
|
|
||||||
emails[role.email.address] = '"%s"' % (role.person.name)
|
|
||||||
# add AD
|
|
||||||
if draft.group.type.slug == 'wg':
|
|
||||||
emails['%s-ads@ietf.org' % draft.group.acronym] = '"%s-ads"' % (draft.group.acronym)
|
|
||||||
elif draft.group.type.slug == 'rg':
|
|
||||||
email = draft.group.parent.role_set.filter(name='chair')[0].email
|
|
||||||
emails[email.address] = '"%s"' % (email.person.name)
|
|
||||||
|
|
||||||
# add sheperd
|
|
||||||
if draft.shepherd:
|
|
||||||
emails[draft.shepherd.address] = '"%s"' % (draft.shepherd.person.name)
|
|
||||||
|
|
||||||
# use sort so we get consistently ordered lists
|
|
||||||
result_list = []
|
|
||||||
for key in sorted(emails):
|
|
||||||
if emails[key]:
|
|
||||||
result_list.append('%s <%s>' % (emails[key],key))
|
|
||||||
else:
|
|
||||||
result_list.append('<%s>' % key)
|
|
||||||
|
|
||||||
return ','.join(result_list)
|
|
||||||
|
|
||||||
def get_email_initial(draft, action=None, input=None):
|
|
||||||
"""
|
|
||||||
Takes a draft object, a string representing the email type:
|
|
||||||
(extend,resurrect,revision,update,withdraw) and
|
|
||||||
a dictonary of the action form input data (for use with update, extend).
|
|
||||||
Returns a dictionary containing initial field values for a email notification.
|
|
||||||
The dictionary consists of to, cc, subject, body.
|
|
||||||
|
|
||||||
"""
|
|
||||||
expiration_date = (datetime.date.today() + datetime.timedelta(185)).strftime('%B %d, %Y')
|
|
||||||
curr_filename = draft.name + '-' + draft.rev + '.txt'
|
|
||||||
data = {}
|
|
||||||
data['cc'] = get_fullcc_list(draft)
|
|
||||||
data['to'] = ''
|
|
||||||
data['action'] = action
|
|
||||||
|
|
||||||
if action == 'extend':
|
|
||||||
context = {'doc':curr_filename,'expire_date':input['expiration_date']}
|
|
||||||
data['subject'] = 'Extension of Expiration Date for %s' % (curr_filename)
|
|
||||||
data['body'] = render_to_string('drafts/message_extend.txt', context)
|
|
||||||
data['expiration_date'] = input['expiration_date']
|
|
||||||
|
|
||||||
elif action == 'resurrect':
|
|
||||||
last_revision = get_last_revision(draft.name)
|
|
||||||
last_filename = draft.name + '-' + last_revision + '.txt'
|
|
||||||
context = {'doc':last_filename,'expire_date':expiration_date}
|
|
||||||
data['subject'] = 'Resurrection of %s' % (last_filename)
|
|
||||||
data['body'] = render_to_string('drafts/message_resurrect.txt', context)
|
|
||||||
data['action'] = action
|
|
||||||
|
|
||||||
elif action == 'withdraw':
|
|
||||||
context = {'doc':curr_filename,'by':input['withdraw_type']}
|
|
||||||
data['subject'] = 'Withdraw of %s' % (curr_filename)
|
|
||||||
data['body'] = render_to_string('drafts/message_withdraw.txt', context)
|
|
||||||
data['action'] = action
|
|
||||||
data['withdraw_type'] = input['withdraw_type']
|
|
||||||
|
|
||||||
return data
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,56 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"pk": "rcross@amsl.com",
|
|
||||||
"model": "person.email",
|
|
||||||
"fields": {
|
|
||||||
"active": true,
|
|
||||||
"person": 111252,
|
|
||||||
"time": "1970-01-01 23:59:59"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": "fluffy@cisco.com",
|
|
||||||
"model": "person.email",
|
|
||||||
"fields": {
|
|
||||||
"active": true,
|
|
||||||
"person": 105791,
|
|
||||||
"time": "1970-01-01 23:59:59"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": "cabo@tzi.org",
|
|
||||||
"model": "person.email",
|
|
||||||
"fields": {
|
|
||||||
"active": true,
|
|
||||||
"person": 11843,
|
|
||||||
"time": "1970-01-01 23:59:59"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": "br@brianrosen.net",
|
|
||||||
"model": "person.email",
|
|
||||||
"fields": {
|
|
||||||
"active": true,
|
|
||||||
"person": 106987,
|
|
||||||
"time": "1970-01-01 23:59:59"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": "gaborbajko@yahoo.com",
|
|
||||||
"model": "person.email",
|
|
||||||
"fields": {
|
|
||||||
"active": true,
|
|
||||||
"person": 108123,
|
|
||||||
"time": "1970-01-01 23:59:59"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": "wdec@cisco.com",
|
|
||||||
"model": "person.email",
|
|
||||||
"fields": {
|
|
||||||
"active": true,
|
|
||||||
"person": 106526,
|
|
||||||
"time": "1970-01-01 23:59:59"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,224 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"pk": 4,
|
|
||||||
"model": "group.group",
|
|
||||||
"fields": {
|
|
||||||
"charter": null,
|
|
||||||
"unused_states": [],
|
|
||||||
"ad": null,
|
|
||||||
"parent": null,
|
|
||||||
"list_email": "",
|
|
||||||
"acronym": "secretariat",
|
|
||||||
"comments": "",
|
|
||||||
"list_subscribe": "",
|
|
||||||
"state": "active",
|
|
||||||
"time": "2012-01-24 13:17:42",
|
|
||||||
"unused_tags": [],
|
|
||||||
"list_archive": "",
|
|
||||||
"type": "ietf",
|
|
||||||
"name": "IETF Secretariat"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 29,
|
|
||||||
"model": "group.group",
|
|
||||||
"fields": {
|
|
||||||
"charter": null,
|
|
||||||
"unused_states": [],
|
|
||||||
"ad": null,
|
|
||||||
"parent": null,
|
|
||||||
"list_email": "",
|
|
||||||
"acronym": "nomcom2011",
|
|
||||||
"comments": "",
|
|
||||||
"list_subscribe": "",
|
|
||||||
"state": "active",
|
|
||||||
"time": "2012-01-24 13:17:42",
|
|
||||||
"unused_tags": [],
|
|
||||||
"list_archive": "",
|
|
||||||
"type": "ietf",
|
|
||||||
"name": "IAB/IESG Nominating Committee 2011/2012"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1008,
|
|
||||||
"model": "group.group",
|
|
||||||
"fields": {
|
|
||||||
"charter": null,
|
|
||||||
"unused_states": [],
|
|
||||||
"ad": null,
|
|
||||||
"parent": 2,
|
|
||||||
"list_email": "",
|
|
||||||
"acronym": "gen",
|
|
||||||
"comments": "",
|
|
||||||
"list_subscribe": "",
|
|
||||||
"state": "active",
|
|
||||||
"time": "2012-01-24 13:17:42",
|
|
||||||
"unused_tags": [],
|
|
||||||
"list_archive": "",
|
|
||||||
"type": "area",
|
|
||||||
"name": "General Area"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1052,
|
|
||||||
"model": "group.group",
|
|
||||||
"fields": {
|
|
||||||
"charter": null,
|
|
||||||
"unused_states": [],
|
|
||||||
"ad": null,
|
|
||||||
"parent": 2,
|
|
||||||
"list_email": "",
|
|
||||||
"acronym": "int",
|
|
||||||
"comments": "",
|
|
||||||
"list_subscribe": "",
|
|
||||||
"state": "active",
|
|
||||||
"time": "2012-01-24 13:17:42",
|
|
||||||
"unused_tags": [],
|
|
||||||
"list_archive": "",
|
|
||||||
"type": "area",
|
|
||||||
"name": "Internet Area"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 934,
|
|
||||||
"model": "group.group",
|
|
||||||
"fields": {
|
|
||||||
"charter": null,
|
|
||||||
"unused_states": [],
|
|
||||||
"ad": null,
|
|
||||||
"parent": 2,
|
|
||||||
"list_email": "",
|
|
||||||
"acronym": "app",
|
|
||||||
"comments": "",
|
|
||||||
"list_subscribe": "",
|
|
||||||
"state": "active",
|
|
||||||
"time": "2012-01-24 13:17:42",
|
|
||||||
"unused_tags": [],
|
|
||||||
"list_archive": "",
|
|
||||||
"type": "area",
|
|
||||||
"name": "Applications Area"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1789,
|
|
||||||
"model": "group.group",
|
|
||||||
"fields": {
|
|
||||||
"charter": "charter-ietf-core",
|
|
||||||
"unused_states": [],
|
|
||||||
"ad": 105907,
|
|
||||||
"parent": 934,
|
|
||||||
"list_email": "core@ietf.org",
|
|
||||||
"acronym": "core",
|
|
||||||
"comments": "",
|
|
||||||
"list_subscribe": "https://www.ietf.org/mailman/listinfo/core",
|
|
||||||
"state": "active",
|
|
||||||
"time": "2011-12-09 12:00:00",
|
|
||||||
"unused_tags": [],
|
|
||||||
"list_archive": "http://www.ietf.org/mail-archive/web/core/",
|
|
||||||
"type": "wg",
|
|
||||||
"name": "Constrained RESTful Environments"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1819,
|
|
||||||
"model": "group.group",
|
|
||||||
"fields": {
|
|
||||||
"charter": "charter-ietf-paws",
|
|
||||||
"unused_states": [],
|
|
||||||
"ad": 105907,
|
|
||||||
"parent": 934,
|
|
||||||
"list_email": "paws@ietf.org",
|
|
||||||
"acronym": "paws",
|
|
||||||
"comments": "",
|
|
||||||
"list_subscribe": "https://www.ietf.org/mailman/listinfo/paws",
|
|
||||||
"state": "active",
|
|
||||||
"time": "2011-12-09 12:00:00",
|
|
||||||
"unused_tags": [],
|
|
||||||
"list_archive": "http://www.ietf.org/mail-archive/web/paws/",
|
|
||||||
"type": "wg",
|
|
||||||
"name": "Protocol to Access WS database"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1693,
|
|
||||||
"model": "group.group",
|
|
||||||
"fields": {
|
|
||||||
"charter": "charter-ietf-ancp",
|
|
||||||
"unused_states": [],
|
|
||||||
"ad": 2348,
|
|
||||||
"parent": 1052,
|
|
||||||
"list_email": "ancp@ietf.org",
|
|
||||||
"acronym": "ancp",
|
|
||||||
"comments": "",
|
|
||||||
"list_subscribe": "ancp-request@ietf.org",
|
|
||||||
"state": "active",
|
|
||||||
"time": "2011-12-09 12:00:00",
|
|
||||||
"unused_tags": [],
|
|
||||||
"list_archive": "http://www.ietf.org/mail-archive/web/ancp/",
|
|
||||||
"type": "wg",
|
|
||||||
"name": "Access Node Control Protocol"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1723,
|
|
||||||
"model": "group.group",
|
|
||||||
"fields": {
|
|
||||||
"charter": "charter-ietf-6man",
|
|
||||||
"unused_states": [],
|
|
||||||
"ad": 21072,
|
|
||||||
"parent": 1052,
|
|
||||||
"list_email": "ipv6@ietf.org",
|
|
||||||
"acronym": "6man",
|
|
||||||
"comments": "",
|
|
||||||
"list_subscribe": "https://www.ietf.org/mailman/listinfo/ipv6",
|
|
||||||
"state": "active",
|
|
||||||
"time": "2011-12-09 12:00:00",
|
|
||||||
"unused_tags": [],
|
|
||||||
"list_archive": "http://www.ietf.org/mail-archive/web/ipv6",
|
|
||||||
"type": "wg",
|
|
||||||
"name": "IPv6 Maintenance"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1377,
|
|
||||||
"model": "group.group",
|
|
||||||
"fields": {
|
|
||||||
"charter": "charter-ietf-adsl",
|
|
||||||
"unused_states": [],
|
|
||||||
"ad": null,
|
|
||||||
"parent": 1052,
|
|
||||||
"list_email": "adsl@xlist.agcs.com",
|
|
||||||
"acronym": "adsl",
|
|
||||||
"comments": "",
|
|
||||||
"list_subscribe": "mgr@xlist.agcs.com",
|
|
||||||
"state": "conclude",
|
|
||||||
"time": "2011-12-09 12:00:00",
|
|
||||||
"unused_tags": [],
|
|
||||||
"list_archive": "",
|
|
||||||
"type": "wg",
|
|
||||||
"name": "Asymmetric Digital Subscriber Line"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 30,
|
|
||||||
"model": "group.group",
|
|
||||||
"fields": {
|
|
||||||
"charter": null,
|
|
||||||
"unused_states": [],
|
|
||||||
"ad": null,
|
|
||||||
"parent": 3,
|
|
||||||
"list_email": "",
|
|
||||||
"acronym": "asrg",
|
|
||||||
"comments": "",
|
|
||||||
"list_subscribe": "",
|
|
||||||
"state": "active",
|
|
||||||
"time": "2012-01-24 13:17:42",
|
|
||||||
"unused_tags": [],
|
|
||||||
"list_archive": "",
|
|
||||||
"type": "rg",
|
|
||||||
"name": "Anti-Spam Research Group"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"pk": 79,
|
|
||||||
"model": "meeting.meeting",
|
|
||||||
"fields": {
|
|
||||||
"city": "Beijing",
|
|
||||||
"venue_name": "",
|
|
||||||
"country": "CN",
|
|
||||||
"time_zone": "Asia/Shanghai",
|
|
||||||
"reg_area": "Valley Ballroom Foyer",
|
|
||||||
"number": "79",
|
|
||||||
"break_area": "Valley Ballroom Foyer",
|
|
||||||
"date": "2010-11-07",
|
|
||||||
"type": "ietf",
|
|
||||||
"venue_addr": ""
|
|
||||||
"idsubmit_cutoff_day_offset_00": 20,
|
|
||||||
"idsubmit_cutoff_day_offset_01": 13,
|
|
||||||
"idsubmit_cutoff_time_utc": "23:59:59",
|
|
||||||
"idsubmit_cutoff_warning_days": "21 days, 0:00:00",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 80,
|
|
||||||
"model": "meeting.meeting",
|
|
||||||
"fields": {
|
|
||||||
"city": "Prague",
|
|
||||||
"venue_name": "",
|
|
||||||
"country": "CZ",
|
|
||||||
"time_zone": "Europe/Prague",
|
|
||||||
"reg_area": "Congress Hall Foyer",
|
|
||||||
"number": "80",
|
|
||||||
"break_area": "Congress Hall Foyer",
|
|
||||||
"date": "2011-03-27",
|
|
||||||
"type": "ietf",
|
|
||||||
"venue_addr": ""
|
|
||||||
"idsubmit_cutoff_day_offset_00": 20,
|
|
||||||
"idsubmit_cutoff_day_offset_01": 13,
|
|
||||||
"idsubmit_cutoff_time_utc": "23:59:59",
|
|
||||||
"idsubmit_cutoff_warning_days": "21 days, 0:00:00",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 81,
|
|
||||||
"model": "meeting.meeting",
|
|
||||||
"fields": {
|
|
||||||
"city": "Quebec",
|
|
||||||
"venue_name": "",
|
|
||||||
"country": "CA",
|
|
||||||
"time_zone": "",
|
|
||||||
"reg_area": "2000 A",
|
|
||||||
"number": "81",
|
|
||||||
"break_area": "2000 BC",
|
|
||||||
"date": "2011-07-24",
|
|
||||||
"type": "ietf",
|
|
||||||
"venue_addr": ""
|
|
||||||
"idsubmit_cutoff_day_offset_00": 20,
|
|
||||||
"idsubmit_cutoff_day_offset_01": 13,
|
|
||||||
"idsubmit_cutoff_time_utc": "23:59:59",
|
|
||||||
"idsubmit_cutoff_warning_days": "21 days, 0:00:00",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 82,
|
|
||||||
"model": "meeting.meeting",
|
|
||||||
"fields": {
|
|
||||||
"city": "Taipei",
|
|
||||||
"venue_name": "",
|
|
||||||
"country": "TW",
|
|
||||||
"time_zone": "",
|
|
||||||
"reg_area": "1F North Extended",
|
|
||||||
"number": "82",
|
|
||||||
"break_area": "Common Area",
|
|
||||||
"date": "2011-11-13",
|
|
||||||
"type": "ietf",
|
|
||||||
"venue_addr": ""
|
|
||||||
"idsubmit_cutoff_day_offset_00": 20,
|
|
||||||
"idsubmit_cutoff_day_offset_01": 13,
|
|
||||||
"idsubmit_cutoff_time_utc": "23:59:59",
|
|
||||||
"idsubmit_cutoff_warning_days": "21 days, 0:00:00",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 83,
|
|
||||||
"model": "meeting.meeting",
|
|
||||||
"fields": {
|
|
||||||
"city": "Paris",
|
|
||||||
"venue_name": "",
|
|
||||||
"country": "FR",
|
|
||||||
"time_zone": "Europe/Paris",
|
|
||||||
"reg_area": "",
|
|
||||||
"number": "83",
|
|
||||||
"break_area": "",
|
|
||||||
"date": "2012-03-25",
|
|
||||||
"type": "ietf",
|
|
||||||
"venue_addr": ""
|
|
||||||
"idsubmit_cutoff_day_offset_00": 20,
|
|
||||||
"idsubmit_cutoff_day_offset_01": 13,
|
|
||||||
"idsubmit_cutoff_time_utc": "23:59:59",
|
|
||||||
"idsubmit_cutoff_warning_days": "21 days, 0:00:00",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,132 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"pk": 111252,
|
|
||||||
"model": "person.person",
|
|
||||||
"fields": {
|
|
||||||
"name": "Ryan Cross",
|
|
||||||
"ascii_short": null,
|
|
||||||
"time": "2012-01-24 13:00:24",
|
|
||||||
"affiliation": "",
|
|
||||||
"user": 486,
|
|
||||||
"address": "",
|
|
||||||
"ascii": "Ryan Cross"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 105791,
|
|
||||||
"model": "person.person",
|
|
||||||
"fields": {
|
|
||||||
"name": "Cullen Jennings",
|
|
||||||
"ascii_short": null,
|
|
||||||
"time": "2012-01-24 13:00:23",
|
|
||||||
"affiliation": "Cisco Systems",
|
|
||||||
"user": 454,
|
|
||||||
"address": "",
|
|
||||||
"ascii": "Cullen Jennings"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 11843,
|
|
||||||
"model": "person.person",
|
|
||||||
"fields": {
|
|
||||||
"name": "Dr. Carsten Bormann",
|
|
||||||
"ascii_short": null,
|
|
||||||
"time": "2012-01-24 13:00:13",
|
|
||||||
"affiliation": "University Bremen TZI",
|
|
||||||
"user": 1128,
|
|
||||||
"address": "",
|
|
||||||
"ascii": "Dr. Carsten Bormann"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 106987,
|
|
||||||
"model": "person.person",
|
|
||||||
"fields": {
|
|
||||||
"name": "Brian Rosen",
|
|
||||||
"ascii_short": null,
|
|
||||||
"time": "2012-01-24 13:00:13",
|
|
||||||
"affiliation": "",
|
|
||||||
"user": 1016,
|
|
||||||
"address": "",
|
|
||||||
"ascii": "Brian Rosen"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 108123,
|
|
||||||
"model": "person.person",
|
|
||||||
"fields": {
|
|
||||||
"name": "Gabor Bajko",
|
|
||||||
"ascii_short": null,
|
|
||||||
"time": "2012-01-24 13:00:15",
|
|
||||||
"affiliation": "",
|
|
||||||
"user": 700,
|
|
||||||
"address": "",
|
|
||||||
"ascii": "Gabor Bajko"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 106526,
|
|
||||||
"model": "person.person",
|
|
||||||
"fields": {
|
|
||||||
"name": "Wojciech Dec",
|
|
||||||
"ascii_short": null,
|
|
||||||
"time": "2012-01-24 13:00:19",
|
|
||||||
"affiliation": "",
|
|
||||||
"user": 1395,
|
|
||||||
"address": "",
|
|
||||||
"ascii": "Wojciech Dec"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 105786,
|
|
||||||
"model": "person.person",
|
|
||||||
"fields": {
|
|
||||||
"name": "Matthew Bocci",
|
|
||||||
"ascii_short": null,
|
|
||||||
"time": "2012-01-24 13:00:16",
|
|
||||||
"affiliation": "",
|
|
||||||
"user": 483,
|
|
||||||
"address": "",
|
|
||||||
"ascii": "Matthew Bocci"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 2793,
|
|
||||||
"model": "person.person",
|
|
||||||
"fields": {
|
|
||||||
"name": "Robert M. Hinden",
|
|
||||||
"ascii_short": null,
|
|
||||||
"time": "2012-01-24 13:00:13",
|
|
||||||
"affiliation": "Nokia",
|
|
||||||
"user": 844,
|
|
||||||
"address": "",
|
|
||||||
"ascii": "Robert M. Hinden"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 106653,
|
|
||||||
"model": "person.person",
|
|
||||||
"fields": {
|
|
||||||
"name": "Brian Haberman",
|
|
||||||
"ascii_short": null,
|
|
||||||
"time": "2012-01-24 13:12:51",
|
|
||||||
"affiliation": "",
|
|
||||||
"user": null,
|
|
||||||
"address": "",
|
|
||||||
"ascii": "Brian Haberman"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 112453,
|
|
||||||
"model": "person.person",
|
|
||||||
"fields": {
|
|
||||||
"name": "Russel Housley",
|
|
||||||
"ascii_short": null,
|
|
||||||
"time": "2012-01-24 13:16:11",
|
|
||||||
"affiliation": "",
|
|
||||||
"user": null,
|
|
||||||
"address": "",
|
|
||||||
"ascii": "Russel Housley"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,62 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"pk": 1610,
|
|
||||||
"model": "group.role",
|
|
||||||
"fields": {
|
|
||||||
"person": 111252,
|
|
||||||
"group": 4,
|
|
||||||
"name": "secr",
|
|
||||||
"email": "rcross@amsl.com"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1229,
|
|
||||||
"model": "group.role",
|
|
||||||
"fields": {
|
|
||||||
"person": 105791,
|
|
||||||
"group": 1358,
|
|
||||||
"name": "chair",
|
|
||||||
"email": "fluffy@cisco.com"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1416,
|
|
||||||
"model": "group.role",
|
|
||||||
"fields": {
|
|
||||||
"person": 11843,
|
|
||||||
"group": 1774,
|
|
||||||
"name": "chair",
|
|
||||||
"email": "cabo@tzi.org"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1515,
|
|
||||||
"model": "group.role",
|
|
||||||
"fields": {
|
|
||||||
"person": 106987,
|
|
||||||
"group": 1819,
|
|
||||||
"name": "chair",
|
|
||||||
"email": "br@brianrosen.net"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1516,
|
|
||||||
"model": "group.role",
|
|
||||||
"fields": {
|
|
||||||
"person": 108123,
|
|
||||||
"group": 1819,
|
|
||||||
"name": "chair",
|
|
||||||
"email": "Gabor.Bajko@nokia.com"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 461,
|
|
||||||
"model": "group.role",
|
|
||||||
"fields": {
|
|
||||||
"person": 106526,
|
|
||||||
"group": 1693,
|
|
||||||
"name": "chair",
|
|
||||||
"email": "wdec@cisco.com"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,164 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"pk": 486,
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "rcross",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": true,
|
|
||||||
"is_superuser": true,
|
|
||||||
"is_staff": true,
|
|
||||||
"last_login": "2012-01-25 08:56:54",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "nopass",
|
|
||||||
"email": "",
|
|
||||||
"date_joined": "2010-07-27 01:32:02"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 454,
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "fluffy@cisco.com",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": true,
|
|
||||||
"is_superuser": false,
|
|
||||||
"is_staff": false,
|
|
||||||
"last_login": "2012-01-23 17:27:39",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "",
|
|
||||||
"email": "",
|
|
||||||
"date_joined": "2010-03-10 16:04:51"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1128,
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "cabo@tzi.org",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": true,
|
|
||||||
"is_superuser": false,
|
|
||||||
"is_staff": false,
|
|
||||||
"last_login": "2012-01-10 05:07:13",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "",
|
|
||||||
"email": "",
|
|
||||||
"date_joined": "2011-12-20 03:37:01"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1016,
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "br@brianrosen.net",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": true,
|
|
||||||
"is_superuser": false,
|
|
||||||
"is_staff": false,
|
|
||||||
"last_login": "2011-11-16 17:55:41",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "",
|
|
||||||
"email": "",
|
|
||||||
"date_joined": "2011-11-16 17:55:41"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 700,
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "gabor.bajko@nokia.com",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": true,
|
|
||||||
"is_superuser": false,
|
|
||||||
"is_staff": false,
|
|
||||||
"last_login": "2011-09-09 10:07:39",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "",
|
|
||||||
"email": "",
|
|
||||||
"date_joined": "2011-09-09 10:07:39"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1395,
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "wdec@cisco.com",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": true,
|
|
||||||
"is_superuser": false,
|
|
||||||
"is_staff": false,
|
|
||||||
"last_login": "2012-01-24 13:00:19",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "",
|
|
||||||
"email": "",
|
|
||||||
"date_joined": "2012-01-24 13:00:19"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 483,
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "matthew.bocci@alcatel.co.uk",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": true,
|
|
||||||
"is_superuser": false,
|
|
||||||
"is_staff": false,
|
|
||||||
"last_login": "2012-01-13 09:12:04",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "",
|
|
||||||
"email": "",
|
|
||||||
"date_joined": "2010-07-19 07:16:42"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 986,
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "bob.hinden@nokia.com",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": true,
|
|
||||||
"is_superuser": false,
|
|
||||||
"is_staff": false,
|
|
||||||
"last_login": "2011-11-14 03:19:35",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "",
|
|
||||||
"email": "",
|
|
||||||
"date_joined": "2011-11-14 03:08:01"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1066,
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "brian@innovationslab.net",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": true,
|
|
||||||
"is_superuser": false,
|
|
||||||
"is_staff": false,
|
|
||||||
"last_login": "2011-11-28 11:00:16",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "",
|
|
||||||
"email": "",
|
|
||||||
"date_joined": "2011-11-28 11:00:16"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,244 +0,0 @@
|
||||||
# Copyright The IETF Trust 2013-2019, All Rights Reserved
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
from __future__ import absolute_import, print_function, unicode_literals
|
|
||||||
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
|
|
||||||
from ietf.doc.models import Document, State
|
|
||||||
from ietf.name.models import IntendedStdLevelName
|
|
||||||
from ietf.group.models import Group
|
|
||||||
from ietf.person.models import Person, Email
|
|
||||||
from ietf.person.fields import SearchableEmailField
|
|
||||||
from ietf.secr.groups.forms import get_person
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------
|
|
||||||
# Select Choices
|
|
||||||
# ---------------------------------------------
|
|
||||||
WITHDRAW_CHOICES = (('ietf','Withdraw by IETF'),('author','Withdraw by Author'))
|
|
||||||
|
|
||||||
# ---------------------------------------------
|
|
||||||
# Custom Fields
|
|
||||||
# ---------------------------------------------
|
|
||||||
class DocumentField(forms.FileField):
|
|
||||||
'''A validating document upload field'''
|
|
||||||
|
|
||||||
def __init__(self, unique=False, *args, **kwargs):
|
|
||||||
self.extension = kwargs.pop('extension')
|
|
||||||
self.filename = kwargs.pop('filename')
|
|
||||||
self.rev = kwargs.pop('rev')
|
|
||||||
super(DocumentField, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def clean(self, data, initial=None):
|
|
||||||
file = super(DocumentField, self).clean(data,initial)
|
|
||||||
if file:
|
|
||||||
# validate general file format
|
|
||||||
m = re.search(r'.*-\d{2}\.(txt|pdf|ps|xml)', file.name)
|
|
||||||
if not m:
|
|
||||||
raise forms.ValidationError('File name must be in the form base-NN.[txt|pdf|ps|xml]')
|
|
||||||
|
|
||||||
# ensure file extension is correct
|
|
||||||
base,ext = os.path.splitext(file.name)
|
|
||||||
if ext != self.extension:
|
|
||||||
raise forms.ValidationError('Incorrect file extension: %s' % ext)
|
|
||||||
|
|
||||||
# if this isn't a brand new submission we need to do some extra validations
|
|
||||||
if self.filename:
|
|
||||||
# validate filename
|
|
||||||
if base[:-3] != self.filename:
|
|
||||||
raise forms.ValidationError("Filename: %s doesn't match Draft filename." % base[:-3])
|
|
||||||
# validate revision
|
|
||||||
next_revision = str(int(self.rev)+1).zfill(2)
|
|
||||||
if base[-2:] != next_revision:
|
|
||||||
raise forms.ValidationError("Expected revision # %s" % (next_revision))
|
|
||||||
|
|
||||||
return file
|
|
||||||
|
|
||||||
class GroupModelChoiceField(forms.ModelChoiceField):
|
|
||||||
'''
|
|
||||||
Custom ModelChoiceField sets queryset to include all active workgroups and the
|
|
||||||
individual submission group, none. Displays group acronyms as choices. Call it without the
|
|
||||||
queryset argument, for example:
|
|
||||||
|
|
||||||
group = GroupModelChoiceField(required=True)
|
|
||||||
'''
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
kwargs['queryset'] = Group.objects.filter(type__in=('wg','individ'),state__in=('bof','proposed','active')).order_by('acronym')
|
|
||||||
super(GroupModelChoiceField, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def label_from_instance(self, obj):
|
|
||||||
return obj.acronym
|
|
||||||
|
|
||||||
class AliasModelChoiceField(forms.ModelChoiceField):
|
|
||||||
'''
|
|
||||||
Custom ModelChoiceField, just uses Alias name in the select choices as opposed to the
|
|
||||||
more confusing alias -> doc format used by DocAlias.__unicode__
|
|
||||||
'''
|
|
||||||
def label_from_instance(self, obj):
|
|
||||||
return obj.name
|
|
||||||
|
|
||||||
# ---------------------------------------------
|
|
||||||
# Forms
|
|
||||||
# ---------------------------------------------
|
|
||||||
|
|
||||||
class AuthorForm(forms.Form):
|
|
||||||
'''
|
|
||||||
The generic javascript for populating the email list based on the name selected expects to
|
|
||||||
see an id_email field
|
|
||||||
'''
|
|
||||||
person = forms.CharField(max_length=50,widget=forms.TextInput(attrs={'class':'name-autocomplete'}),help_text="To see a list of people type the first name, or last name, or both.")
|
|
||||||
email = forms.CharField(widget=forms.Select(),help_text="Select an email.")
|
|
||||||
affiliation = forms.CharField(max_length=100, required=False, help_text="Affiliation")
|
|
||||||
country = forms.CharField(max_length=255, required=False, help_text="Country")
|
|
||||||
|
|
||||||
# check for id within parenthesis to ensure name was selected from the list
|
|
||||||
def clean_person(self):
|
|
||||||
person = self.cleaned_data.get('person', '')
|
|
||||||
m = re.search(r'(\d+)', person)
|
|
||||||
if person and not m:
|
|
||||||
raise forms.ValidationError("You must select an entry from the list!")
|
|
||||||
|
|
||||||
# return person object
|
|
||||||
return get_person(person)
|
|
||||||
|
|
||||||
# check that email exists and return the Email object
|
|
||||||
def clean_email(self):
|
|
||||||
email = self.cleaned_data['email']
|
|
||||||
try:
|
|
||||||
obj = Email.objects.get(address=email)
|
|
||||||
except Email.ObjectDoesNoExist:
|
|
||||||
raise forms.ValidationError("Email address not found!")
|
|
||||||
|
|
||||||
# return email object
|
|
||||||
return obj
|
|
||||||
|
|
||||||
class EditModelForm(forms.ModelForm):
|
|
||||||
#expiration_date = forms.DateField(required=False)
|
|
||||||
state = forms.ModelChoiceField(queryset=State.objects.filter(type='draft'),empty_label=None)
|
|
||||||
iesg_state = forms.ModelChoiceField(queryset=State.objects.filter(type='draft-iesg'),empty_label=None)
|
|
||||||
group = GroupModelChoiceField(required=True)
|
|
||||||
review_by_rfc_editor = forms.BooleanField(required=False)
|
|
||||||
shepherd = SearchableEmailField(required=False, only_users=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Document
|
|
||||||
fields = ('title','group','ad','shepherd','notify','stream','review_by_rfc_editor','name','rev','pages','intended_std_level','std_level','abstract','internal_comments')
|
|
||||||
|
|
||||||
# use this method to set attrs which keeps other meta info from model.
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(EditModelForm, self).__init__(*args, **kwargs)
|
|
||||||
self.fields['ad'].queryset = Person.objects.filter(role__name='ad').distinct()
|
|
||||||
self.fields['title'].label='Document Name'
|
|
||||||
self.fields['title'].widget=forms.Textarea()
|
|
||||||
self.fields['rev'].widget.attrs['size'] = 2
|
|
||||||
self.fields['abstract'].widget.attrs['cols'] = 72
|
|
||||||
self.initial['state'] = self.instance.get_state().pk
|
|
||||||
self.initial['iesg_state'] = self.instance.get_state('draft-iesg').pk
|
|
||||||
|
|
||||||
# setup special fields
|
|
||||||
if self.instance:
|
|
||||||
# setup replaced
|
|
||||||
self.fields['review_by_rfc_editor'].initial = bool(self.instance.tags.filter(slug='rfc-rev'))
|
|
||||||
|
|
||||||
def save(self, commit=False):
|
|
||||||
m = super(EditModelForm, self).save(commit=False)
|
|
||||||
state = self.cleaned_data['state']
|
|
||||||
iesg_state = self.cleaned_data['iesg_state']
|
|
||||||
|
|
||||||
if 'state' in self.changed_data:
|
|
||||||
m.set_state(state)
|
|
||||||
|
|
||||||
# note we're not sending notices here, is this desired
|
|
||||||
if 'iesg_state' in self.changed_data:
|
|
||||||
m.set_state(iesg_state)
|
|
||||||
|
|
||||||
if 'review_by_rfc_editor' in self.changed_data:
|
|
||||||
if self.cleaned_data.get('review_by_rfc_editor',''):
|
|
||||||
m.tags.add('rfc-rev')
|
|
||||||
else:
|
|
||||||
m.tags.remove('rfc-rev')
|
|
||||||
|
|
||||||
if 'shepherd' in self.changed_data:
|
|
||||||
email = self.cleaned_data.get('shepherd')
|
|
||||||
if email and not email.origin:
|
|
||||||
email.origin = 'shepherd: %s' % m.name
|
|
||||||
email.save()
|
|
||||||
|
|
||||||
# handle replaced by
|
|
||||||
|
|
||||||
return m
|
|
||||||
|
|
||||||
# field must contain filename of existing draft
|
|
||||||
def clean_replaced_by(self):
|
|
||||||
name = self.cleaned_data.get('replaced_by', '')
|
|
||||||
if name and not Document.objects.filter(name=name):
|
|
||||||
raise forms.ValidationError("ERROR: Draft does not exist")
|
|
||||||
return name
|
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
super(EditModelForm, self).clean()
|
|
||||||
cleaned_data = self.cleaned_data
|
|
||||||
"""
|
|
||||||
expiration_date = cleaned_data.get('expiration_date','')
|
|
||||||
status = cleaned_data.get('status','')
|
|
||||||
replaced = cleaned_data.get('replaced',False)
|
|
||||||
replaced_by = cleaned_data.get('replaced_by','')
|
|
||||||
replaced_status_object = IDStatus.objects.get(status_id=5)
|
|
||||||
expired_status_object = IDStatus.objects.get(status_id=2)
|
|
||||||
# this condition seems to be valid
|
|
||||||
#if expiration_date and status != expired_status_object:
|
|
||||||
# raise forms.ValidationError('Expiration Date set but status is %s' % (status))
|
|
||||||
if status == expired_status_object and not expiration_date:
|
|
||||||
raise forms.ValidationError('Status is Expired but Expirated Date is not set')
|
|
||||||
if replaced and status != replaced_status_object:
|
|
||||||
raise forms.ValidationError('You have checked Replaced but status is %s' % (status))
|
|
||||||
if replaced and not replaced_by:
|
|
||||||
raise forms.ValidationError('You have checked Replaced but Replaced By field is empty')
|
|
||||||
"""
|
|
||||||
return cleaned_data
|
|
||||||
|
|
||||||
class EmailForm(forms.Form):
|
|
||||||
# max_lengths come from db limits, cc is not limited
|
|
||||||
action = forms.CharField(max_length=255, widget=forms.HiddenInput(), required=False)
|
|
||||||
expiration_date = forms.CharField(max_length=255, widget=forms.HiddenInput(), required=False)
|
|
||||||
withdraw_type = forms.CharField(max_length=255, widget=forms.HiddenInput(), required=False)
|
|
||||||
replaced = forms.CharField(max_length=255, widget=forms.HiddenInput(), required=False)
|
|
||||||
replaced_by = forms.CharField(max_length=255, widget=forms.HiddenInput(), required=False)
|
|
||||||
filename = forms.CharField(max_length=255, widget=forms.HiddenInput(), required=False)
|
|
||||||
to = forms.CharField(max_length=255)
|
|
||||||
cc = forms.CharField(required=False)
|
|
||||||
subject = forms.CharField(max_length=255)
|
|
||||||
body = forms.CharField(widget=forms.Textarea(), strip=False)
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
if 'hidden' in kwargs:
|
|
||||||
self.hidden = kwargs.pop('hidden')
|
|
||||||
else:
|
|
||||||
self.hidden = False
|
|
||||||
super(EmailForm, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if self.hidden:
|
|
||||||
for key in list(self.fields.keys()):
|
|
||||||
self.fields[key].widget = forms.HiddenInput()
|
|
||||||
|
|
||||||
class ExtendForm(forms.Form):
|
|
||||||
action = forms.CharField(max_length=255, widget=forms.HiddenInput(),initial='extend')
|
|
||||||
expiration_date = forms.DateField()
|
|
||||||
|
|
||||||
class SearchForm(forms.Form):
|
|
||||||
intended_std_level = forms.ModelChoiceField(queryset=IntendedStdLevelName.objects,label="Intended Status",required=False)
|
|
||||||
document_title = forms.CharField(max_length=80,label='Document Title',required=False)
|
|
||||||
group = forms.CharField(max_length=12,required=False)
|
|
||||||
filename = forms.CharField(max_length=80,required=False)
|
|
||||||
state = forms.ModelChoiceField(queryset=State.objects.filter(type='draft'),required=False)
|
|
||||||
revision_date_start = forms.DateField(label='Revision Date (start)',required=False)
|
|
||||||
revision_date_end = forms.DateField(label='Revision Date (end)',required=False)
|
|
||||||
|
|
||||||
class WithdrawForm(forms.Form):
|
|
||||||
withdraw_type = forms.CharField(widget=forms.Select(choices=WITHDRAW_CHOICES),help_text='Select which type of withdraw to perform.')
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
# see add_id5.cfm ~400 for email To addresses
|
|
||||||
# see generateNotification.cfm
|
|
||||||
|
|
|
@ -1,265 +0,0 @@
|
||||||
# Copyright The IETF Trust 2013-2019, All Rights Reserved
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
from __future__ import absolute_import, print_function, unicode_literals
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.urls import reverse as urlreverse
|
|
||||||
from django.utils.http import urlencode
|
|
||||||
from pyquery import PyQuery
|
|
||||||
|
|
||||||
import debug # pyflakes:ignore
|
|
||||||
|
|
||||||
from ietf.doc.expire import expire_draft
|
|
||||||
from ietf.doc.factories import WgDraftFactory
|
|
||||||
from ietf.doc.models import Document
|
|
||||||
from ietf.group.factories import RoleFactory
|
|
||||||
from ietf.meeting.factories import MeetingFactory
|
|
||||||
from ietf.person.factories import PersonFactory, EmailFactory
|
|
||||||
from ietf.person.models import Person
|
|
||||||
from ietf.submit.models import Preapproval
|
|
||||||
from ietf.utils.mail import outbox
|
|
||||||
from ietf.utils.test_utils import TestCase, login_testing_unauthorized
|
|
||||||
from ietf.secr.drafts.email import get_email_initial
|
|
||||||
|
|
||||||
|
|
||||||
SECR_USER='secretary'
|
|
||||||
|
|
||||||
class SecrDraftsTestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.saved_internet_draft_path = settings.INTERNET_DRAFT_PATH
|
|
||||||
self.repository_dir = self.tempdir('submit-repository')
|
|
||||||
settings.INTERNET_DRAFT_PATH = self.repository_dir
|
|
||||||
|
|
||||||
self.saved_internet_draft_archive_dir = settings.INTERNET_DRAFT_ARCHIVE_DIR
|
|
||||||
self.archive_dir = self.tempdir('submit-archive')
|
|
||||||
settings.INTERNET_DRAFT_ARCHIVE_DIR = self.archive_dir
|
|
||||||
|
|
||||||
self.saved_idsubmit_manual_staging_dir = settings.IDSUBMIT_MANUAL_STAGING_DIR
|
|
||||||
self.manual_dir = self.tempdir('submit-manual')
|
|
||||||
settings.IDSUBMIT_MANUAL_STAGING_DIR = self.manual_dir
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
shutil.rmtree(self.repository_dir)
|
|
||||||
shutil.rmtree(self.archive_dir)
|
|
||||||
shutil.rmtree(self.manual_dir)
|
|
||||||
settings.INTERNET_DRAFT_PATH = self.saved_internet_draft_path
|
|
||||||
settings.INTERNET_DRAFT_ARCHIVE_DIR = self.saved_internet_draft_archive_dir
|
|
||||||
settings.IDSUBMIT_MANUAL_STAGING_DIR = self.saved_idsubmit_manual_staging_dir
|
|
||||||
|
|
||||||
def test_abstract(self):
|
|
||||||
draft = WgDraftFactory()
|
|
||||||
url = urlreverse('ietf.secr.drafts.views.abstract', kwargs={'id':draft.name})
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
def test_approvals(self):
|
|
||||||
Preapproval.objects.create(name='draft-dummy',
|
|
||||||
by=Person.objects.get(name="(System)"))
|
|
||||||
url = urlreverse('ietf.secr.drafts.views.approvals')
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertContains(response, 'draft-dummy')
|
|
||||||
|
|
||||||
def test_edit(self):
|
|
||||||
draft = WgDraftFactory(states=[('draft','active'),('draft-stream-ietf','wg-doc'),('draft-iesg','ad-eval')], shepherd=EmailFactory())
|
|
||||||
url = urlreverse('ietf.secr.drafts.views.edit', kwargs={'id':draft.name})
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
response = self.client.post(url,{'title':draft.title,'name':draft.name,'rev':draft.rev,'state':4,'group':draft.group.pk,'iesg_state':draft.get_state('draft-iesg').pk})
|
|
||||||
self.assertEqual(response.status_code, 302)
|
|
||||||
draft = Document.objects.get(pk=draft.pk)
|
|
||||||
self.assertEqual(draft.get_state().slug,'repl')
|
|
||||||
|
|
||||||
def test_email(self):
|
|
||||||
# can't test this directly, test via drafts actions
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_get_email_initial(self):
|
|
||||||
# Makes sure that a manual posting by the Secretariat of an I-D that is
|
|
||||||
# in the RFC Editor Queue will result in notification of the RFC Editor
|
|
||||||
draft = WgDraftFactory(authors=PersonFactory.create_batch(1),shepherd=EmailFactory())
|
|
||||||
RoleFactory(group=draft.group, name_id='chair')
|
|
||||||
data = get_email_initial(draft,action='extend',input={'expiration_date': '2050-01-01'})
|
|
||||||
self.assertTrue('Extension of Expiration Date' in data['subject'])
|
|
||||||
|
|
||||||
def test_makerfc(self):
|
|
||||||
draft = WgDraftFactory(intended_std_level_id='ps')
|
|
||||||
url = urlreverse('ietf.secr.drafts.views.edit', kwargs={'id':draft.name})
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
# It's not clear what this is testing. Was there supposed to be a POST here?
|
|
||||||
self.assertTrue(draft.intended_std_level)
|
|
||||||
|
|
||||||
def test_search(self):
|
|
||||||
WgDraftFactory() # Test exercises branch that requires >1 doc found
|
|
||||||
draft = WgDraftFactory()
|
|
||||||
url = urlreverse('ietf.secr.drafts.views.search')
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
post = dict(filename='draft',state=1,submit='submit')
|
|
||||||
response = self.client.post(url, post)
|
|
||||||
self.assertContains(response, draft.name)
|
|
||||||
|
|
||||||
def test_view(self):
|
|
||||||
draft = WgDraftFactory()
|
|
||||||
url = urlreverse('ietf.secr.drafts.views.view', kwargs={'id':draft.name})
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
def test_author_delete(self):
|
|
||||||
draft = WgDraftFactory(authors=PersonFactory.create_batch(2))
|
|
||||||
author = draft.documentauthor_set.first()
|
|
||||||
id = author.id
|
|
||||||
url = urlreverse('ietf.secr.drafts.views.author_delete', kwargs={'id':draft.name, 'oid':id})
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
redirect_url = urlreverse('ietf.secr.drafts.views.authors', kwargs={'id':draft.name})
|
|
||||||
response = self.client.post(url, {'post':'yes'})
|
|
||||||
self.assertRedirects(response, redirect_url)
|
|
||||||
self.assertFalse(draft.documentauthor_set.filter(id=id))
|
|
||||||
|
|
||||||
def test_resurrect(self):
|
|
||||||
draft = WgDraftFactory()
|
|
||||||
path = os.path.join(self.repository_dir, draft.filename_with_rev())
|
|
||||||
with io.open(path, 'w') as file:
|
|
||||||
file.write('test')
|
|
||||||
expire_draft(draft)
|
|
||||||
email_url = urlreverse('ietf.secr.drafts.views.email', kwargs={'id':draft.name}) + "?action=resurrect"
|
|
||||||
confirm_url = urlreverse('ietf.secr.drafts.views.confirm', kwargs={'id':draft.name})
|
|
||||||
do_action_url = urlreverse('ietf.secr.drafts.views.do_action', kwargs={'id':draft.name})
|
|
||||||
view_url = urlreverse('ietf.secr.drafts.views.view', kwargs={'id':draft.name})
|
|
||||||
subject = 'Resurrection of %s' % draft.get_base_name()
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.get(email_url)
|
|
||||||
self.assertContains(response, '<title>Drafts - Email</title>')
|
|
||||||
q = PyQuery(response.content)
|
|
||||||
self.assertEqual(q("#id_subject").val(), subject)
|
|
||||||
post_data = {
|
|
||||||
'action': 'resurrect',
|
|
||||||
'to': 'john@example.com',
|
|
||||||
'cc': 'joe@example.com',
|
|
||||||
'subject': subject,
|
|
||||||
'body': 'draft resurrected',
|
|
||||||
'submit': 'Save'
|
|
||||||
}
|
|
||||||
response = self.client.post(confirm_url, post_data)
|
|
||||||
self.assertContains(response, '<title>Drafts - Confirm</title>')
|
|
||||||
self.assertEqual(response.context['email']['subject'], subject)
|
|
||||||
response = self.client.post(do_action_url, post_data)
|
|
||||||
self.assertRedirects(response, view_url)
|
|
||||||
draft = Document.objects.get(name=draft.name)
|
|
||||||
self.assertTrue(draft.get_state_slug('draft') == 'active')
|
|
||||||
recv = outbox[-1]
|
|
||||||
self.assertEqual(recv['Subject'], subject)
|
|
||||||
|
|
||||||
def test_extend(self):
|
|
||||||
draft = WgDraftFactory()
|
|
||||||
url = urlreverse('ietf.secr.drafts.views.extend', kwargs={'id':draft.name})
|
|
||||||
email_url = urlreverse('ietf.secr.drafts.views.email', kwargs={'id':draft.name})
|
|
||||||
confirm_url = urlreverse('ietf.secr.drafts.views.confirm', kwargs={'id':draft.name})
|
|
||||||
do_action_url = urlreverse('ietf.secr.drafts.views.do_action', kwargs={'id':draft.name})
|
|
||||||
view_url = urlreverse('ietf.secr.drafts.views.view', kwargs={'id':draft.name})
|
|
||||||
expiration = datetime.datetime.today() + datetime.timedelta(days=180)
|
|
||||||
expiration = expiration.replace(hour=0,minute=0,second=0,microsecond=0)
|
|
||||||
subject = 'Extension of Expiration Date for %s' % draft.get_base_name()
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
extend_data = {
|
|
||||||
'action': 'extend',
|
|
||||||
'expiration_date': expiration.strftime('%Y-%m-%d'),
|
|
||||||
}
|
|
||||||
post_data = {
|
|
||||||
'action': 'extend',
|
|
||||||
'expiration_date': expiration.strftime('%Y-%m-%d'),
|
|
||||||
'to': 'john@example.com',
|
|
||||||
'cc': 'joe@example.com',
|
|
||||||
'subject': subject,
|
|
||||||
'body': 'draft extended',
|
|
||||||
'submit': 'Save'
|
|
||||||
}
|
|
||||||
response = self.client.post(url, extend_data)
|
|
||||||
self.assertRedirects(response, email_url + '?' + urlencode(extend_data))
|
|
||||||
response = self.client.post(confirm_url, post_data)
|
|
||||||
self.assertContains(response, '<title>Drafts - Confirm</title>')
|
|
||||||
self.assertEqual(response.context['email']['subject'], subject)
|
|
||||||
response = self.client.post(do_action_url, post_data)
|
|
||||||
self.assertRedirects(response, view_url)
|
|
||||||
draft = Document.objects.get(name=draft.name)
|
|
||||||
self.assertTrue(draft.expires == expiration)
|
|
||||||
recv = outbox[-1]
|
|
||||||
self.assertEqual(recv['Subject'], subject)
|
|
||||||
|
|
||||||
def test_withdraw(self):
|
|
||||||
draft = WgDraftFactory()
|
|
||||||
url = urlreverse('ietf.secr.drafts.views.withdraw', kwargs={'id':draft.name})
|
|
||||||
email_url = urlreverse('ietf.secr.drafts.views.email', kwargs={'id':draft.name})
|
|
||||||
confirm_url = urlreverse('ietf.secr.drafts.views.confirm', kwargs={'id':draft.name})
|
|
||||||
do_action_url = urlreverse('ietf.secr.drafts.views.do_action', kwargs={'id':draft.name})
|
|
||||||
view_url = urlreverse('ietf.secr.drafts.views.view', kwargs={'id':draft.name})
|
|
||||||
subject = 'Withdraw of %s' % draft.get_base_name()
|
|
||||||
self.client.login(username="secretary", password="secretary+password")
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
withdraw_data = OrderedDict([('action', 'withdraw'), ('withdraw_type', 'ietf')])
|
|
||||||
post_data = {
|
|
||||||
'action': 'withdraw',
|
|
||||||
'withdraw_type': 'ietf',
|
|
||||||
'to': 'john@example.com',
|
|
||||||
'cc': 'joe@example.com',
|
|
||||||
'subject': subject,
|
|
||||||
'body': 'draft resurrected',
|
|
||||||
'submit': 'Save'
|
|
||||||
}
|
|
||||||
response = self.client.post(url, withdraw_data)
|
|
||||||
self.assertRedirects(response, email_url + '?' + urlencode(withdraw_data))
|
|
||||||
response = self.client.post(confirm_url, post_data)
|
|
||||||
self.assertContains(response, '<title>Drafts - Confirm</title>')
|
|
||||||
self.assertEqual(response.context['email']['subject'], subject)
|
|
||||||
response = self.client.post(do_action_url, post_data)
|
|
||||||
self.assertRedirects(response, view_url)
|
|
||||||
draft = Document.objects.get(name=draft.name)
|
|
||||||
self.assertTrue(draft.get_state_slug('draft') == 'ietf-rm')
|
|
||||||
recv = outbox[-1]
|
|
||||||
self.assertEqual(recv['Subject'], subject)
|
|
||||||
|
|
||||||
def test_authors(self):
|
|
||||||
draft = WgDraftFactory()
|
|
||||||
person = PersonFactory()
|
|
||||||
url = urlreverse('ietf.secr.drafts.views.authors',kwargs={'id':draft.name})
|
|
||||||
login_testing_unauthorized(self, "secretary", url)
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code,200)
|
|
||||||
response = self.client.post(url, {'submit':'Done'})
|
|
||||||
self.assertEqual(response.status_code,302)
|
|
||||||
response = self.client.post(url, {'person':'%s - (%s)'%(person.plain_name(),person.pk),'email':person.email_set.first().pk})
|
|
||||||
self.assertEqual(response.status_code,302)
|
|
||||||
self.assertTrue(draft.documentauthor_set.filter(person=person).exists)
|
|
||||||
|
|
||||||
def test_dates(self):
|
|
||||||
MeetingFactory(type_id='ietf',date=datetime.datetime.today()+datetime.timedelta(days=14))
|
|
||||||
url = urlreverse('ietf.secr.drafts.views.dates')
|
|
||||||
login_testing_unauthorized(self, "secretary", url)
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code,200)
|
|
||||||
|
|
||||||
def test_nudge_report(self):
|
|
||||||
url = urlreverse('ietf.secr.drafts.views.nudge_report')
|
|
||||||
login_testing_unauthorized(self, "secretary", url)
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code,200)
|
|
|
@ -1,20 +0,0 @@
|
||||||
|
|
||||||
from ietf.secr.drafts import views
|
|
||||||
from ietf.utils.urls import url
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^$', views.search),
|
|
||||||
url(r'^approvals/$', views.approvals),
|
|
||||||
url(r'^dates/$', views.dates),
|
|
||||||
url(r'^nudge-report/$', views.nudge_report),
|
|
||||||
url(r'^(?P<id>[A-Za-z0-9._\-\+]+)/$', views.view),
|
|
||||||
url(r'^(?P<id>[A-Za-z0-9._\-\+]+)/abstract/$', views.abstract),
|
|
||||||
url(r'^(?P<id>[A-Za-z0-9._\-\+]+)/authors/$', views.authors),
|
|
||||||
url(r'^(?P<id>[A-Za-z0-9._\-\+]+)/author_delete/(?P<oid>\d{1,6})$', views.author_delete),
|
|
||||||
url(r'^(?P<id>[A-Za-z0-9._\-\+]+)/confirm/$', views.confirm),
|
|
||||||
url(r'^(?P<id>[A-Za-z0-9._\-\+]+)/do_action/$', views.do_action),
|
|
||||||
url(r'^(?P<id>[A-Za-z0-9._\-\+]+)/edit/$', views.edit),
|
|
||||||
url(r'^(?P<id>[A-Za-z0-9._\-\+]+)/extend/$', views.extend),
|
|
||||||
url(r'^(?P<id>[A-Za-z0-9._\-\+]+)/email/$', views.email),
|
|
||||||
url(r'^(?P<id>[A-Za-z0-9._\-\+]+)/withdraw/$', views.withdraw),
|
|
||||||
]
|
|
|
@ -1,638 +0,0 @@
|
||||||
# Copyright The IETF Trust 2013-2019, All Rights Reserved
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
from __future__ import absolute_import, print_function, unicode_literals
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import glob
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
from dateutil.parser import parse
|
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.db.models import Max
|
|
||||||
from django.shortcuts import render, get_object_or_404, redirect
|
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils.http import urlencode
|
|
||||||
|
|
||||||
from ietf.doc.models import Document, DocumentAuthor, State
|
|
||||||
from ietf.doc.models import DocEvent, NewRevisionDocEvent
|
|
||||||
from ietf.doc.utils import add_state_change_event
|
|
||||||
from ietf.ietfauth.utils import role_required
|
|
||||||
from ietf.meeting.helpers import get_meeting
|
|
||||||
from ietf.secr.drafts.email import announcement_from_form, get_email_initial
|
|
||||||
from ietf.secr.drafts.forms import AuthorForm, EditModelForm, EmailForm, ExtendForm, SearchForm, WithdrawForm
|
|
||||||
from ietf.secr.utils.document import get_rfc_num, get_start_date
|
|
||||||
from ietf.submit.models import Preapproval
|
|
||||||
from ietf.utils.log import log
|
|
||||||
|
|
||||||
# -------------------------------------------------
|
|
||||||
# Helper Functions
|
|
||||||
# -------------------------------------------------
|
|
||||||
|
|
||||||
def get_action_details(draft, request):
|
|
||||||
'''
|
|
||||||
This function takes a draft object and request object and returns a list of dictionaries
|
|
||||||
with keys: label, value to be used in displaying information on the confirmation
|
|
||||||
page.
|
|
||||||
'''
|
|
||||||
result = []
|
|
||||||
data = request.POST
|
|
||||||
|
|
||||||
if data['action'] == 'revision':
|
|
||||||
m = {'label':'New Revision','value':data['revision']}
|
|
||||||
result.append(m)
|
|
||||||
|
|
||||||
if data['action'] == 'replace':
|
|
||||||
m = {'label':'Replaced By:','value':data['replaced_by']}
|
|
||||||
result.append(m)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def handle_uploaded_file(f):
|
|
||||||
'''
|
|
||||||
Save uploaded draft files to temporary directory
|
|
||||||
'''
|
|
||||||
destination = io.open(os.path.join(settings.IDSUBMIT_MANUAL_STAGING_DIR, f.name), 'wb+')
|
|
||||||
for chunk in f.chunks():
|
|
||||||
destination.write(chunk)
|
|
||||||
destination.close()
|
|
||||||
|
|
||||||
def file_types_for_draft(draft):
|
|
||||||
'''Returns list of file extensions that exist for this draft'''
|
|
||||||
basename, ext = os.path.splitext(draft.get_file_name())
|
|
||||||
files = glob.glob(basename + '.*')
|
|
||||||
file_types = []
|
|
||||||
for filename in files:
|
|
||||||
base, ext = os.path.splitext(filename)
|
|
||||||
if ext:
|
|
||||||
file_types.append(ext)
|
|
||||||
return file_types
|
|
||||||
|
|
||||||
# -------------------------------------------------
|
|
||||||
# Action Button Functions
|
|
||||||
# -------------------------------------------------
|
|
||||||
'''
|
|
||||||
These functions handle the real work of the action buttons: database updates,
|
|
||||||
moving files, etc. Generally speaking the action buttons trigger a multi-page
|
|
||||||
sequence where information may be gathered using a custom form, an email
|
|
||||||
may be produced and presented to the user to edit, and only then when confirmation
|
|
||||||
is given will the action work take place. That's when these functions are called.
|
|
||||||
'''
|
|
||||||
|
|
||||||
def do_extend(draft, request):
|
|
||||||
'''
|
|
||||||
Actions:
|
|
||||||
- update revision_date
|
|
||||||
- set extension_date
|
|
||||||
'''
|
|
||||||
|
|
||||||
e = DocEvent.objects.create(
|
|
||||||
type='changed_document',
|
|
||||||
by=request.user.person,
|
|
||||||
doc=draft,
|
|
||||||
rev=draft.rev,
|
|
||||||
time=draft.time,
|
|
||||||
desc='Extended expiry',
|
|
||||||
)
|
|
||||||
draft.expires = parse(request.POST.get('expiration_date'))
|
|
||||||
draft.save_with_history([e])
|
|
||||||
|
|
||||||
# save scheduled announcement
|
|
||||||
form = EmailForm(request.POST)
|
|
||||||
announcement_from_form(form.data,by=request.user.person)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def do_resurrect(draft, request):
|
|
||||||
'''
|
|
||||||
Actions
|
|
||||||
- restore last archived version
|
|
||||||
- change state to Active
|
|
||||||
- reset expires
|
|
||||||
- create DocEvent
|
|
||||||
'''
|
|
||||||
# restore latest revision documents file from archive
|
|
||||||
files = glob.glob(os.path.join(settings.INTERNET_DRAFT_ARCHIVE_DIR,draft.name) + '-??.*')
|
|
||||||
sorted_files = sorted(files)
|
|
||||||
latest,ext = os.path.splitext(sorted_files[-1])
|
|
||||||
files = glob.glob(os.path.join(settings.INTERNET_DRAFT_ARCHIVE_DIR,latest) + '.*')
|
|
||||||
log("Resurrecting %s. Moving files:" % draft.name)
|
|
||||||
for file in files:
|
|
||||||
try:
|
|
||||||
shutil.move(file, settings.INTERNET_DRAFT_PATH)
|
|
||||||
log(" Moved file %s to %s" % (file, settings.INTERNET_DRAFT_PATH))
|
|
||||||
except shutil.Error as ex:
|
|
||||||
log(" Exception %s when attempting to move %s" % (ex, file))
|
|
||||||
|
|
||||||
# Update draft record
|
|
||||||
draft.set_state(State.objects.get(type="draft", slug="active"))
|
|
||||||
|
|
||||||
# set expires
|
|
||||||
draft.expires = datetime.datetime.now() + datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
|
|
||||||
|
|
||||||
# create DocEvent
|
|
||||||
e = NewRevisionDocEvent.objects.create(type='completed_resurrect',
|
|
||||||
by=request.user.person,
|
|
||||||
doc=draft,
|
|
||||||
rev=draft.rev,
|
|
||||||
time=draft.time)
|
|
||||||
|
|
||||||
draft.save_with_history([e])
|
|
||||||
|
|
||||||
# send announcement
|
|
||||||
form = EmailForm(request.POST)
|
|
||||||
announcement_from_form(form.data,by=request.user.person)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def do_withdraw(draft,request):
|
|
||||||
'''
|
|
||||||
Actions
|
|
||||||
- change state to withdrawn
|
|
||||||
- TODO move file to archive
|
|
||||||
'''
|
|
||||||
withdraw_type = request.POST.get('withdraw_type')
|
|
||||||
|
|
||||||
prev_state = draft.get_state("draft")
|
|
||||||
new_state = None
|
|
||||||
if withdraw_type == 'ietf':
|
|
||||||
new_state = State.objects.get(type="draft", slug="ietf-rm")
|
|
||||||
elif withdraw_type == 'author':
|
|
||||||
new_state = State.objects.get(type="draft", slug="auth-rm")
|
|
||||||
|
|
||||||
if not new_state:
|
|
||||||
return
|
|
||||||
|
|
||||||
draft.set_state(new_state)
|
|
||||||
|
|
||||||
e = add_state_change_event(draft, request.user.person, prev_state, new_state)
|
|
||||||
if e:
|
|
||||||
draft.save_with_history([e])
|
|
||||||
|
|
||||||
# send announcement
|
|
||||||
form = EmailForm(request.POST)
|
|
||||||
announcement_from_form(form.data,by=request.user.person)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
# -------------------------------------------------
|
|
||||||
# Standard View Functions
|
|
||||||
# -------------------------------------------------
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def abstract(request, id):
|
|
||||||
'''
|
|
||||||
View Internet Draft Abstract
|
|
||||||
|
|
||||||
**Templates:**
|
|
||||||
|
|
||||||
* ``drafts/abstract.html``
|
|
||||||
|
|
||||||
**Template Variables:**
|
|
||||||
|
|
||||||
* draft
|
|
||||||
'''
|
|
||||||
draft = get_object_or_404(Document, name=id)
|
|
||||||
|
|
||||||
return render(request, 'drafts/abstract.html', {
|
|
||||||
'draft': draft},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def approvals(request):
|
|
||||||
'''
|
|
||||||
This view handles setting Initial Approval for drafts
|
|
||||||
'''
|
|
||||||
|
|
||||||
approved = Preapproval.objects.all().order_by('name')
|
|
||||||
form = None
|
|
||||||
|
|
||||||
return render(request, 'drafts/approvals.html', {
|
|
||||||
'form': form,
|
|
||||||
'approved': approved},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def author_delete(request, id, oid):
|
|
||||||
'''
|
|
||||||
This view deletes the specified author from the draft
|
|
||||||
'''
|
|
||||||
author = DocumentAuthor.objects.get(id=oid)
|
|
||||||
|
|
||||||
if request.method == 'POST' and request.POST['post'] == 'yes':
|
|
||||||
author.delete()
|
|
||||||
messages.success(request, 'The author was deleted successfully')
|
|
||||||
return redirect('ietf.secr.drafts.views.authors', id=id)
|
|
||||||
|
|
||||||
return render(request, 'confirm_delete.html', {'object': author})
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def authors(request, id):
|
|
||||||
'''
|
|
||||||
Edit Internet Draft Authors
|
|
||||||
|
|
||||||
**Templates:**
|
|
||||||
|
|
||||||
* ``drafts/authors.html``
|
|
||||||
|
|
||||||
**Template Variables:**
|
|
||||||
|
|
||||||
* form, draft
|
|
||||||
|
|
||||||
'''
|
|
||||||
draft = get_object_or_404(Document, name=id)
|
|
||||||
action = request.GET.get('action')
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
form = AuthorForm(request.POST)
|
|
||||||
button_text = request.POST.get('submit', '')
|
|
||||||
if button_text == 'Done':
|
|
||||||
if action == 'add':
|
|
||||||
return redirect('ietf.secr.drafts.views.announce', id=id)
|
|
||||||
return redirect('ietf.secr.drafts.views.view', id=id)
|
|
||||||
|
|
||||||
if form.is_valid():
|
|
||||||
person = form.cleaned_data['person']
|
|
||||||
email = form.cleaned_data['email']
|
|
||||||
affiliation = form.cleaned_data.get('affiliation') or ""
|
|
||||||
country = form.cleaned_data.get('country') or ""
|
|
||||||
|
|
||||||
authors = draft.documentauthor_set.all()
|
|
||||||
if authors:
|
|
||||||
order = list(authors.aggregate(Max('order')).values())[0] + 1
|
|
||||||
else:
|
|
||||||
order = 1
|
|
||||||
DocumentAuthor.objects.create(document=draft, person=person, email=email, affiliation=affiliation, country=country, order=order)
|
|
||||||
|
|
||||||
messages.success(request, 'Author added successfully!')
|
|
||||||
return redirect('ietf.secr.drafts.views.authors', id=id)
|
|
||||||
|
|
||||||
else:
|
|
||||||
form = AuthorForm()
|
|
||||||
|
|
||||||
return render(request, 'drafts/authors.html', {
|
|
||||||
'draft': draft,
|
|
||||||
'form': form},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def confirm(request, id):
|
|
||||||
draft = get_object_or_404(Document, name=id)
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
button_text = request.POST.get('submit', '')
|
|
||||||
if button_text == 'Cancel':
|
|
||||||
return redirect('ietf.secr.drafts.views.view', id=id)
|
|
||||||
|
|
||||||
action = request.POST.get('action','')
|
|
||||||
form = EmailForm(request.POST)
|
|
||||||
if form.is_valid():
|
|
||||||
email = form.data
|
|
||||||
details = get_action_details(draft, request)
|
|
||||||
hidden_form = EmailForm(request.POST, hidden=True)
|
|
||||||
|
|
||||||
return render(request, 'drafts/confirm.html', {
|
|
||||||
'details': details,
|
|
||||||
'email': email,
|
|
||||||
'action': action,
|
|
||||||
'draft': draft,
|
|
||||||
'form': hidden_form},
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return render(request, 'drafts/email.html', {
|
|
||||||
'form': form,
|
|
||||||
'draft': draft,
|
|
||||||
'action': action},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def do_action(request, id):
|
|
||||||
'''
|
|
||||||
This view displays changes that will be made and calls appropriate
|
|
||||||
function if the user elects to proceed. If the user cancels then
|
|
||||||
the view page is returned.
|
|
||||||
'''
|
|
||||||
draft = get_object_or_404(Document, name=id)
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
button_text = request.POST.get('submit', '')
|
|
||||||
if button_text == 'Cancel':
|
|
||||||
return redirect('ietf.secr.drafts.views.view', id=id)
|
|
||||||
|
|
||||||
action = request.POST.get('action')
|
|
||||||
|
|
||||||
if action == 'resurrect':
|
|
||||||
func = do_resurrect
|
|
||||||
elif action == 'extend':
|
|
||||||
func = do_extend
|
|
||||||
elif action == 'withdraw':
|
|
||||||
func = do_withdraw
|
|
||||||
|
|
||||||
func(draft,request)
|
|
||||||
|
|
||||||
messages.success(request, '%s action performed successfully!' % action)
|
|
||||||
return redirect('ietf.secr.drafts.views.view', id=id)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def dates(request):
|
|
||||||
'''
|
|
||||||
Manage ID Submission Dates
|
|
||||||
|
|
||||||
**Templates:**
|
|
||||||
|
|
||||||
* none
|
|
||||||
|
|
||||||
**Template Variables:**
|
|
||||||
|
|
||||||
* none
|
|
||||||
'''
|
|
||||||
meeting = get_meeting()
|
|
||||||
|
|
||||||
return render(request, 'drafts/dates.html', {
|
|
||||||
'meeting':meeting},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def edit(request, id):
|
|
||||||
'''
|
|
||||||
Since there's a lot going on in this function we are summarizing in the docstring.
|
|
||||||
Also serves as a record of requirements.
|
|
||||||
|
|
||||||
if revision number increases add document_comments and send notify-revision
|
|
||||||
if revision date changed and not the number return error
|
|
||||||
check if using restricted words (?)
|
|
||||||
send notification based on check box
|
|
||||||
revision date = now if a new status box checked add_id5.cfm
|
|
||||||
(notify_[resurrection,revision,updated,extended])
|
|
||||||
if rfcnum="" rfcnum=0
|
|
||||||
if status != 2, expired_tombstone="0"
|
|
||||||
if new revision move current txt and ps files to archive directory (add_id5.cfm)
|
|
||||||
if status > 3 create tombstone, else send revision notification (EmailIDRevision.cfm)
|
|
||||||
'''
|
|
||||||
draft = get_object_or_404(Document, name=id)
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
button_text = request.POST.get('submit', '')
|
|
||||||
if button_text == 'Cancel':
|
|
||||||
return redirect('ietf.secr.drafts.views.view', id=id)
|
|
||||||
|
|
||||||
form = EditModelForm(request.POST, instance=draft)
|
|
||||||
if form.is_valid():
|
|
||||||
if form.changed_data:
|
|
||||||
e = DocEvent.objects.create(type='changed_document',
|
|
||||||
by=request.user.person,
|
|
||||||
doc=draft,
|
|
||||||
rev=draft.rev,
|
|
||||||
desc='Changed field(s): %s' % ','.join(form.changed_data))
|
|
||||||
# see EditModelForm.save() for detailed logic
|
|
||||||
form.save(commit=False)
|
|
||||||
draft.save_with_history([e])
|
|
||||||
|
|
||||||
messages.success(request, 'Draft modified successfully!')
|
|
||||||
|
|
||||||
return redirect('ietf.secr.drafts.views.view', id=id)
|
|
||||||
else:
|
|
||||||
#assert False, form.errors
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
form = EditModelForm(instance=draft)
|
|
||||||
|
|
||||||
return render(request, 'drafts/edit.html', {
|
|
||||||
'form': form,
|
|
||||||
'draft': draft},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def email(request, id):
|
|
||||||
'''
|
|
||||||
This function displays the notification message and allows the
|
|
||||||
user to make changes before continuing to confirmation page.
|
|
||||||
'''
|
|
||||||
draft = get_object_or_404(Document, name=id)
|
|
||||||
action = request.GET.get('action')
|
|
||||||
data = request.GET
|
|
||||||
|
|
||||||
# the resurrect email body references the last revision number, handle
|
|
||||||
# exception if no last revision found
|
|
||||||
# if this exception was handled closer to the source it would be easier to debug
|
|
||||||
# other problems with get_email_initial
|
|
||||||
try:
|
|
||||||
form = EmailForm(initial=get_email_initial(draft,action=action,input=data))
|
|
||||||
except Exception as e:
|
|
||||||
return render(request, 'drafts/error.html', { 'error': e},)
|
|
||||||
|
|
||||||
return render(request, 'drafts/email.html', {
|
|
||||||
'form': form,
|
|
||||||
'draft': draft,
|
|
||||||
'action': action,
|
|
||||||
})
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def extend(request, id):
|
|
||||||
'''
|
|
||||||
This view handles extending the expiration date for an Internet-Draft
|
|
||||||
Prerequisites: draft must be active
|
|
||||||
Input: new date
|
|
||||||
Actions
|
|
||||||
- revision_date = today
|
|
||||||
# - call handle_comment
|
|
||||||
'''
|
|
||||||
draft = get_object_or_404(Document, name=id)
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
button_text = request.POST.get('submit', '')
|
|
||||||
if button_text == 'Cancel':
|
|
||||||
return redirect('ietf.secr.drafts.views.view', id=id)
|
|
||||||
|
|
||||||
form = ExtendForm(request.POST)
|
|
||||||
if form.is_valid():
|
|
||||||
params = form.cleaned_data
|
|
||||||
params['action'] = 'extend'
|
|
||||||
url = reverse('ietf.secr.drafts.views.email', kwargs={'id':id})
|
|
||||||
url = url + '?' + urlencode(params)
|
|
||||||
return redirect(url)
|
|
||||||
|
|
||||||
else:
|
|
||||||
form = ExtendForm(initial={'revision_date':datetime.date.today().isoformat()})
|
|
||||||
|
|
||||||
return render(request, 'drafts/extend.html', {
|
|
||||||
'form': form,
|
|
||||||
'draft': draft},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def nudge_report(request):
|
|
||||||
'''
|
|
||||||
This view produces the Nudge Report, basically a list of documents that are in the IESG
|
|
||||||
process but have not had activity in some time
|
|
||||||
'''
|
|
||||||
docs = Document.objects.filter(type='draft',states__slug='active')
|
|
||||||
docs = docs.filter(states=12,tags='need-rev')
|
|
||||||
|
|
||||||
return render(request, 'drafts/report_nudge.html', {
|
|
||||||
'docs': docs},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def search(request):
|
|
||||||
'''
|
|
||||||
Search Internet Drafts
|
|
||||||
|
|
||||||
**Templates:**
|
|
||||||
|
|
||||||
* ``drafts/search.html``
|
|
||||||
|
|
||||||
**Template Variables:**
|
|
||||||
|
|
||||||
* form, results
|
|
||||||
|
|
||||||
'''
|
|
||||||
results = []
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
form = SearchForm(request.POST)
|
|
||||||
if request.POST['submit'] == 'Add':
|
|
||||||
return redirect('sec.drafts.views.add')
|
|
||||||
|
|
||||||
if form.is_valid():
|
|
||||||
kwargs = {}
|
|
||||||
intended_std_level = form.cleaned_data['intended_std_level']
|
|
||||||
title = form.cleaned_data['document_title']
|
|
||||||
group = form.cleaned_data['group']
|
|
||||||
name = form.cleaned_data['filename']
|
|
||||||
state = form.cleaned_data['state']
|
|
||||||
revision_date_start = form.cleaned_data['revision_date_start']
|
|
||||||
revision_date_end = form.cleaned_data['revision_date_end']
|
|
||||||
# construct seach query
|
|
||||||
if intended_std_level:
|
|
||||||
kwargs['intended_std_level'] = intended_std_level
|
|
||||||
if title:
|
|
||||||
kwargs['title__istartswith'] = title
|
|
||||||
if state:
|
|
||||||
kwargs['states__type'] = 'draft'
|
|
||||||
kwargs['states'] = state
|
|
||||||
if name:
|
|
||||||
kwargs['name__istartswith'] = name
|
|
||||||
if group:
|
|
||||||
kwargs['group__acronym__istartswith'] = group
|
|
||||||
if revision_date_start:
|
|
||||||
kwargs['docevent__type'] = 'new_revision'
|
|
||||||
kwargs['docevent__time__gte'] = revision_date_start
|
|
||||||
if revision_date_end:
|
|
||||||
kwargs['docevent__type'] = 'new_revision'
|
|
||||||
kwargs['docevent__time__lte'] = revision_date_end
|
|
||||||
|
|
||||||
# perform query
|
|
||||||
if kwargs:
|
|
||||||
qs = Document.objects.filter(**kwargs)
|
|
||||||
else:
|
|
||||||
qs = Document.objects.all()
|
|
||||||
#results = qs.order_by('group__name')
|
|
||||||
results = qs.order_by('name')
|
|
||||||
|
|
||||||
# if there's just one result go straight to view
|
|
||||||
if len(results) == 1:
|
|
||||||
return redirect('ietf.secr.drafts.views.view', id=results[0].name)
|
|
||||||
else:
|
|
||||||
active_state = State.objects.get(type='draft',slug='active')
|
|
||||||
form = SearchForm(initial={'state':active_state.pk})
|
|
||||||
|
|
||||||
return render(request, 'drafts/search.html', {
|
|
||||||
'results': results,
|
|
||||||
'form': form},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def view(request, id):
|
|
||||||
'''
|
|
||||||
View Internet Draft
|
|
||||||
|
|
||||||
**Templates:**
|
|
||||||
|
|
||||||
* ``drafts/view.html``
|
|
||||||
|
|
||||||
**Template Variables:**
|
|
||||||
|
|
||||||
* draft, area, id_tracker_state
|
|
||||||
'''
|
|
||||||
draft = get_object_or_404(Document, name=id)
|
|
||||||
|
|
||||||
# TODO fix in Django 1.2
|
|
||||||
# some boolean state variables for use in the view.html template to manage display
|
|
||||||
# of action buttons. NOTE: Django 1.2 support new smart if tag in templates which
|
|
||||||
# will remove the need for these variables
|
|
||||||
state = draft.get_state_slug()
|
|
||||||
is_active = True if state == 'active' else False
|
|
||||||
is_expired = True if state == 'expired' else False
|
|
||||||
is_withdrawn = True if (state in ('auth-rm','ietf-rm')) else False
|
|
||||||
|
|
||||||
# TODO should I rewrite all these or just use proxy.InternetDraft?
|
|
||||||
# add legacy fields
|
|
||||||
draft.iesg_state = draft.get_state('draft-iesg')
|
|
||||||
draft.review_by_rfc_editor = bool(draft.tags.filter(slug='rfc-rev'))
|
|
||||||
|
|
||||||
# can't assume there will be a new_revision record
|
|
||||||
r_event = draft.latest_event(type__in=('new_revision','completed_resurrect'))
|
|
||||||
draft.revision_date = r_event.time.date() if r_event else None
|
|
||||||
|
|
||||||
draft.start_date = get_start_date(draft)
|
|
||||||
|
|
||||||
e = draft.latest_event(type__in=('expired_document', 'new_revision', "completed_resurrect"))
|
|
||||||
draft.expiration_date = e.time.date() if e and e.type == "expired_document" else None
|
|
||||||
draft.rfc_number = get_rfc_num(draft)
|
|
||||||
|
|
||||||
# check for replaced bys
|
|
||||||
qs = Document.objects.filter(relateddocument__target__docs=draft, relateddocument__relationship='replaces')
|
|
||||||
if qs:
|
|
||||||
draft.replaced_by = qs[0]
|
|
||||||
|
|
||||||
# check for DEVELOPMENT setting and pass to template
|
|
||||||
is_development = False
|
|
||||||
try:
|
|
||||||
is_development = settings.DEVELOPMENT
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return render(request, 'drafts/view.html', {
|
|
||||||
'is_active': is_active,
|
|
||||||
'is_expired': is_expired,
|
|
||||||
'is_withdrawn': is_withdrawn,
|
|
||||||
'is_development': is_development,
|
|
||||||
'draft': draft},
|
|
||||||
)
|
|
||||||
|
|
||||||
@role_required('Secretariat')
|
|
||||||
def withdraw(request, id):
|
|
||||||
'''
|
|
||||||
This view handles withdrawing an Internet-Draft
|
|
||||||
Prerequisites: draft must be active
|
|
||||||
Input: by IETF or Author
|
|
||||||
'''
|
|
||||||
|
|
||||||
draft = get_object_or_404(Document, name=id)
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
button_text = request.POST.get('submit', '')
|
|
||||||
if button_text == 'Cancel':
|
|
||||||
return redirect('ietf.secr.drafts.views.view', id=id)
|
|
||||||
|
|
||||||
form = WithdrawForm(request.POST)
|
|
||||||
if form.is_valid():
|
|
||||||
params = OrderedDict([('action', 'withdraw')])
|
|
||||||
params['withdraw_type'] = form.cleaned_data['withdraw_type']
|
|
||||||
url = reverse('ietf.secr.drafts.views.email', kwargs={'id':id})
|
|
||||||
url = url + '?' + urlencode(params)
|
|
||||||
return redirect(url)
|
|
||||||
|
|
||||||
else:
|
|
||||||
form = WithdrawForm()
|
|
||||||
|
|
||||||
return render(request, 'drafts/withdraw.html', {
|
|
||||||
'draft': draft,
|
|
||||||
'form': form},
|
|
||||||
)
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ def report_id_activity(start,end):
|
||||||
'ff_update_count':ff_update_count,
|
'ff_update_count':ff_update_count,
|
||||||
'ff_update_percent':ff_update_percent}
|
'ff_update_percent':ff_update_percent}
|
||||||
|
|
||||||
report = render_to_string('drafts/report_id_activity.txt', context)
|
report = render_to_string('proceedings/report_id_activity.txt', context)
|
||||||
|
|
||||||
return report
|
return report
|
||||||
|
|
||||||
|
@ -98,6 +98,6 @@ def report_progress_report(start_date,end_date):
|
||||||
|
|
||||||
context = get_progress_stats(sdate,edate)
|
context = get_progress_stats(sdate,edate)
|
||||||
|
|
||||||
report = render_to_string('drafts/report_progress_report.txt', context)
|
report = render_to_string('proceedings/report_progress_report.txt', context)
|
||||||
|
|
||||||
return report
|
return report
|
|
@ -2,7 +2,7 @@ import datetime
|
||||||
import debug # pyflakes:ignore
|
import debug # pyflakes:ignore
|
||||||
|
|
||||||
from ietf.doc.factories import DocumentFactory,NewRevisionDocEventFactory
|
from ietf.doc.factories import DocumentFactory,NewRevisionDocEventFactory
|
||||||
from ietf.secr.drafts.reports import report_id_activity, report_progress_report
|
from ietf.secr.proceedings.reports import report_id_activity, report_progress_report
|
||||||
from ietf.utils.test_utils import TestCase
|
from ietf.utils.test_utils import TestCase
|
||||||
from ietf.meeting.factories import MeetingFactory
|
from ietf.meeting.factories import MeetingFactory
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Drafts - Abstract{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../../">Drafts</a>
|
|
||||||
» <a href="../">{{ draft.canonical_name }}</a>
|
|
||||||
» Abstract
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module draft-container">
|
|
||||||
<h2>View Abstract - {{ draft.canonical_name }}</h2>
|
|
||||||
<p>
|
|
||||||
{{ draft.abstract }}
|
|
||||||
</p>
|
|
||||||
<div class="button-group">
|
|
||||||
<ul>
|
|
||||||
<li><button onclick="window.location='../'">Back to View</button></li>
|
|
||||||
</ul>
|
|
||||||
</div> <!-- button-group -->
|
|
||||||
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,47 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Drafts - Approvals{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» Drafts Approvals
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module draft-container">
|
|
||||||
<h2>Draft - Approvals</h2>
|
|
||||||
<form id="drafts-approvals-form" enctype="multipart/form-data" action="" method="post">{% csrf_token %}
|
|
||||||
<table class="full-width">
|
|
||||||
{{ form.as_table }}
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="inline-group">
|
|
||||||
<h2>Approved Drafts</h2>
|
|
||||||
<table id="drafts-approved" class="center" cellspacing="0">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Filename</th>
|
|
||||||
<th>Approved Date</th>
|
|
||||||
<th>Approved by</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for doc in approved %}
|
|
||||||
<tr class="{% cycle 'row1' 'row2' %}">
|
|
||||||
<td>{{ doc.name }}</a></td>
|
|
||||||
<td>{{ doc.time|date:"Y-m-d" }}</td>
|
|
||||||
<td>{{ doc.by }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div> <!-- inline-group -->
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,74 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Drafts - Authors{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'secr/css/jquery-ui-1.11.4.custom.css' %}" />
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/jquery-ui-1.11.4.custom.min.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../../">Drafts</a>
|
|
||||||
» <a href="../">{{ draft.name }}</a>
|
|
||||||
» Authors
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module">
|
|
||||||
<h2>Authors</h2>
|
|
||||||
<table class="full-width">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Email</th>
|
|
||||||
<th>Affiliation</th>
|
|
||||||
<th>Country</th>
|
|
||||||
<th>Order</th>
|
|
||||||
<th>Action</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for author in draft.documentauthor_set.all %}
|
|
||||||
<tr class="{% cycle 'row1' 'row2' %}">
|
|
||||||
<td>{{ author.person }}</td>
|
|
||||||
<td>{{ author.email }}</td>
|
|
||||||
<td>{{ author.affiliation }}</td>
|
|
||||||
<td>{{ author.country.name }}</td>
|
|
||||||
<td>{{ author.order }}</td>
|
|
||||||
<td><a href="{% url 'ietf.secr.drafts.views.author_delete' id=draft.pk oid=author.id %}">Delete</a></td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="inline-related">
|
|
||||||
<!-- <hr><br> -->
|
|
||||||
<h3>Add Author</h3>
|
|
||||||
<form id="groups-people" action="" method="post">{% csrf_token %}
|
|
||||||
{{ form.non_field_errors }}
|
|
||||||
<table class="full-width">
|
|
||||||
<tr>
|
|
||||||
<td>{{ form.person.errors }}{{ form.person }}{% if form.person.help_text %}<br>{{ form.person.help_text }}{% endif %}</td>
|
|
||||||
<td>{{ form.email.errors }}{{ form.email }}{% if form.email.help_text %}<br>{{ form.email.help_text }}{% endif %}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{ form.affiliation.errors }}{{ form.affiliation }}{% if form.affiliation.help_text %}<br>{{ form.affiliation.help_text }}{% endif %}</td>
|
|
||||||
<td>{{ form.country.errors }}{{ form.country }}{% if form.country.help_text %}<br>{{ form.country.help_text }}{% endif %}</td>
|
|
||||||
<td><input type="submit" name="submit" value="Add" /></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div> <!-- inline-related -->
|
|
||||||
|
|
||||||
<div class="button-group">
|
|
||||||
<ul>
|
|
||||||
<li><button type="submit" name="submit" value="Done">Done</button></li>
|
|
||||||
</ul>
|
|
||||||
</div> <!-- button-group -->
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,49 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Drafts - Confirm{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../../">Drafts</a>
|
|
||||||
» <a href="../">{{ draft.name }}</a>
|
|
||||||
» Confirm
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module draft-container">
|
|
||||||
<h2>Draft - Confirm</h2>
|
|
||||||
<form enctype="multipart/form-data" action="{% url "ietf.secr.drafts.views.do_action" id=draft.name %}" method="post">{% csrf_token %}
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr><th>Action Selected:</th><td>{{ action }}</td></tr>
|
|
||||||
<tr><th>Draft:</th><td>{{ draft.name }}</td></tr>
|
|
||||||
{% for detail in details %}
|
|
||||||
<tr><th>{{ detail.label }}</th><td>{{ detail.value }}</td></tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% if email %}
|
|
||||||
<div class="inline-group">
|
|
||||||
<h2>Scheduled Email</h2>
|
|
||||||
<table id="draft-confirm-email">
|
|
||||||
<tr><th>To:</th><td>{{ email.to }}</td></tr>
|
|
||||||
<tr><th>CC:</th><td>{{ email.cc }}</td></tr>
|
|
||||||
<tr><th>Subject:</th><td>{{ email.subject }}</td></tr>
|
|
||||||
<tr><th>Body:</th><td>{{ email.body }}</td></tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{{ form }}
|
|
||||||
|
|
||||||
{% include "includes/buttons_save_cancel.html" %}
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,36 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Drafts - Submission Dates{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../../">Drafts</a>
|
|
||||||
» Submission Dates
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module draft-container">
|
|
||||||
<h2>Draft - Submission Dates</h2>
|
|
||||||
<table class="full-width">
|
|
||||||
<tr><td>First Cut Off (Initial Version)</td><td>{{ meeting.get_first_cut_off }}</td></tr>
|
|
||||||
<tr><td>Second Cut Off (Update Version)</td><td>{{ meeting.get_second_cut_off }}</td></tr>
|
|
||||||
<tr><td>IETF Monday</td><td>{{ meeting.get_ietf_monday }}</td></tr>
|
|
||||||
<tr><td>All I-Ds will be processed by</td><td></td></tr>
|
|
||||||
<tr><td>Monday after IETF</td><td></td></tr>
|
|
||||||
<tr><td>Date for list of approved V-00 submissions from WG Chairs</td><td></td></tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="button-group">
|
|
||||||
<ul>
|
|
||||||
<li><button onclick="history.go(-1);return true">Back</button></li>
|
|
||||||
</ul>
|
|
||||||
</div> <!-- button-group -->
|
|
||||||
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,61 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Drafts - Edit{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'secr/css/jquery-ui-1.11.4.custom.css' %}" />
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/jquery-ui-1.11.4.custom.min.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="{% static 'select2/select2.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'select2-bootstrap-css/select2-bootstrap.min.css' %}">
|
|
||||||
<script src="{% static 'select2/select2.min.js' %}"></script>
|
|
||||||
<script src="{% static 'ietf/js/select2-field.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../../">Drafts</a>
|
|
||||||
» <a href="../">{{ draft.name }}</a>
|
|
||||||
» Edit
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module draft-container">
|
|
||||||
<h2>Draft - Edit</h2>
|
|
||||||
{{ form.non_field_errors }}
|
|
||||||
<form enctype="multipart/form-data" action="" method="post">{% csrf_token %}
|
|
||||||
<table id="draft-edit-table" class="full-width amstable">
|
|
||||||
<tr><th>Document Name:</th><td>{{ form.title.errors }}{{ form.title }}</td></tr>
|
|
||||||
<tr><th>Group:</th><td>{{ form.group.errors }}{{ form.group }}</td></tr>
|
|
||||||
<tr><th>Area Director:</th><td>{{ form.ad.errors }}{{ form.ad }}</td></tr>
|
|
||||||
<tr><th>Shepherd:</th><td>{{ form.shepherd.errors }}{{ form.shepherd }}</td></tr>
|
|
||||||
<tr><th>Notify:</th><td>{{ form.notify.errors }}{{ form.notify }}</td></tr>
|
|
||||||
<tr><th>State:</th><td>{{ form.state.errors }}{{ form.state }}</td></tr>
|
|
||||||
<tr><th>IESG State:</th><td>{{ form.iesg_state.errors }}{{ form.iesg_state }}</td></tr>
|
|
||||||
<tr><th>Stream:</th><td>{{ form.stream.errors }}{{ form.stream }}</td></tr>
|
|
||||||
<tr><th>Under Review by RFC Editor:</th><td>{{ form.review_by_rfc_editor.errors }}{{ form.review_by_rfc_editor }}</td></tr>
|
|
||||||
<tr><th>File Name:</th><td>{{ form.name.errors }}{{ form.name }} - {{ form.rev.errors }}{{ form.rev }}</td></tr>
|
|
||||||
<tr><th>Number of Pages:</th><td>{{ form.pages.errors }}{{ form.pages }}</td></tr>
|
|
||||||
<tr><th>Abstract:</th><td>{{ form.abstract.errors }}{{ form.abstract }}</td></tr>
|
|
||||||
<tr><th>Expiration Date:</th><td>{{ draft.expires|date:"M. d, Y" }}</td></tr>
|
|
||||||
<tr><th>Intended Std Level:</th><td>{{ form.intended_std_level.errors }}{{ form.intended_std_level }}</td></tr>
|
|
||||||
<tr><th>Standardization Level:</th><td>{{ form.std_level.errors }}{{ form.std_level }}</td></tr>
|
|
||||||
<tr><th>RFC Number:</th><td>{{ draft.rfc_number }}</td></tr>
|
|
||||||
<tr><th>Comments:</th><td>{{ form.internal_comments.errors }}{{ form.internal_comments }}</td></tr>
|
|
||||||
<tr><th>Replaced by:</th><td>{{ form.replaced_by.errors }}{{ form.replaced_by }}</td></tr>
|
|
||||||
<tr><th>Last Modified Date:</th><td>{{ draft.time }}</td></tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="button-group">
|
|
||||||
<ul>
|
|
||||||
<li><button type="submit" name="submit" value="Save">Save</button></li>
|
|
||||||
<li><button type="submit" name="submit" value="Cancel">Cancel</button></li>
|
|
||||||
</ul>
|
|
||||||
</div> <!-- button-group -->
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,30 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Drafts - Email{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../../">Drafts</a>
|
|
||||||
» <a href="../">{{ draft.name }}</a>
|
|
||||||
» Email
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module draft-container">
|
|
||||||
<h2>Draft - Email</h2>
|
|
||||||
<form enctype="multipart/form-data" action="{% url "ietf.secr.drafts.views.confirm" id=draft.name %}" method="post">{% csrf_token %}
|
|
||||||
<table id="draft-email-table" class="full-width">
|
|
||||||
{{ form.as_table }}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% include "includes/buttons_save_cancel.html" %}
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,23 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
|
|
||||||
{% block title %}Drafts{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../../">Drafts</a>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module group-container">
|
|
||||||
<h2>Drafts - Error Message</h2>
|
|
||||||
An ERROR has occured:
|
|
||||||
<h3>{{ error }}</h3>
|
|
||||||
<div class="button-group">
|
|
||||||
<ul>
|
|
||||||
<li><button onClick="window.location='../../'">Continue</button></li>
|
|
||||||
</ul>
|
|
||||||
</div> <!-- button-group -->
|
|
||||||
</form>
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,32 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Drafts - Extend{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../../">Drafts</a>
|
|
||||||
» <a href="../">{{ draft.name }}</a>
|
|
||||||
» Extend
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module draft-container">
|
|
||||||
<h2>Draft - Extend Expiry</h2>
|
|
||||||
|
|
||||||
<form enctype="multipart/form-data" action="" method="post">{% csrf_token %}
|
|
||||||
<table class="full-width">
|
|
||||||
<tr><th><label>Current Expiration Date:</label></th><td>{{ draft.expires|date:"Y-m-d" }}</td></tr>
|
|
||||||
{{ form.as_table }}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% include "includes/buttons_save_cancel.html" %}
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,81 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Drafts - Make RFC{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../../">Drafts</a>
|
|
||||||
» <a href="../">{{ draft.name }}</a>
|
|
||||||
» Make RFC
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module draft-container">
|
|
||||||
<div id="draft-view-col1">
|
|
||||||
<h2>Draft - Make RFC</h2>
|
|
||||||
<form enctype="multipart/form-data" action="" method="post">{% csrf_token %}
|
|
||||||
<table id="draft-makerfc-table" class="full-width">
|
|
||||||
{% if form.non_field_errors %}{{ form.non_field_errors }}{% endif %}
|
|
||||||
<tr><th><label for="id_title">RFC Name</label></th><td colspan="3">{{ form.title.errors }}{{ form.title }}</td></tr>
|
|
||||||
<tr>
|
|
||||||
<th><label for="id_rfc_number">RFC Number</label></th><td>{{ form.rfc_number.errors }}{{ form.rfc_number }}</td>
|
|
||||||
<th><label for="id_txt_page_count">No. of Pages</label></th><td>{{ form.pages.errors }}{{ form.pages }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr><th><label for="id_rfc_published_date">RFC Published Date</label></th><td>{{ form.rfc_published_date.errors }}{{ form.rfc_published_date }}</td></tr>
|
|
||||||
<tr>
|
|
||||||
<th><label for="id_status">RFC Std Level</label></th><td>{{ form.std_level.errors }}{{ form.std_level }}</td>
|
|
||||||
<th><label for="id_group_acronym">Group</label></th><td>{{ form.group.errors }}{{ form.group }}</td>
|
|
||||||
</tr>
|
|
||||||
{% comment %}
|
|
||||||
<tr>
|
|
||||||
<th><label for="id_proposed_date">Proposed Date</label></th><td>{{ form.proposed_date.errors }}{{ form.proposed_date }}</td>
|
|
||||||
<th><label for="id_draft_date">Draft Date</label></th><td>{{ form.draft_date.errors }}{{ form.draft_date }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th><label for="id_standard_date">Standard Date</label></th><td>{{ form.standard_date.errors }}{{ form.standard_date }}</td>
|
|
||||||
<th><label for="id_historic_date">Historic Date</label></th><td>{{ form.historic_date.errors }}{{ form.historic_date }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th><label for="id_fyi_number">FYI Number</label></th><td>{{ form.fyi_number.errors }}{{ form.fyi_number }}</td>
|
|
||||||
<th><label for="id_std_number">STD Number</label></th><td>{{ form.std_number.errors }}{{ form.std_number }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endcomment %}
|
|
||||||
<tr><th><label for="id_comments">Comments</label></th><td colspan="3">{{ form.internal_comments.errors }}{{ form.internal_comments }}</td></tr>
|
|
||||||
</table>
|
|
||||||
</div> <!-- draft-view-col1 -->
|
|
||||||
<div id="draft-view-col2">
|
|
||||||
<div class="inline-related">
|
|
||||||
<h2>Author(s)</h2>
|
|
||||||
<table>
|
|
||||||
{% for author in draft.documentauthor_set.all %}
|
|
||||||
<tr><td><a href="{% url "ietf.secr.rolodex.views.view" id=author.person.pk %}">{{ author.person.name }}</a></td></tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
</div> <!-- inline-related -->
|
|
||||||
<div class="inline-related add-form action-group">
|
|
||||||
<h2>Obsolete and Update Relationships</h2>
|
|
||||||
{{ obs_formset.management_form }}
|
|
||||||
{{ obs_formset.non_form_errors }}
|
|
||||||
<table id="draft-obsoletes-table" class="full-width">
|
|
||||||
{% for form in obs_formset.forms %}
|
|
||||||
|
|
||||||
{% comment %}<tr><td colspan="2">{{ form.relation.errors }}{{ form.rfc.errors }}</td></tr>{% endcomment %}
|
|
||||||
<tr>
|
|
||||||
<td>{% if form.non_field_errors %}{{ form.non_field_errors }}{% endif %}
|
|
||||||
{{ form.relation.errors }}{{ form.relation }}</td><td>{{ form.rfc.errors }}{{ form.rfc }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
</div> <!-- inline-related -->
|
|
||||||
</div> <!-- draft-view-col2 -->
|
|
||||||
|
|
||||||
{% include "includes/buttons_save_cancel.html" %}
|
|
||||||
</form>
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,8 +0,0 @@
|
||||||
As you requested, the expiration date for
|
|
||||||
{{ doc }} has been extended. The draft
|
|
||||||
will expire on {{ expire_date }} unless it is replaced by an updated version, or the
|
|
||||||
Secretariat has been notified that the document is under official review by the
|
|
||||||
IESG or has been passed to the IRSG or RFC Editor for review and/or publication
|
|
||||||
as an RFC.
|
|
||||||
|
|
||||||
IETF Secretariat.
|
|
|
@ -1,6 +0,0 @@
|
||||||
As you requested, {{ doc }} has been resurrected. The draft will expire on
|
|
||||||
{{ expire_date }} unless it is replaced by an updated version, or the Secretariat has been notified that the
|
|
||||||
document is under official review by the IESG or has been passed to the IRSG or RFC Editor for review and/or
|
|
||||||
publication as an RFC.
|
|
||||||
|
|
||||||
IETF Secretariat.
|
|
|
@ -1,4 +0,0 @@
|
||||||
As you requested, {{ doc }}
|
|
||||||
has been marked as withdrawn by the {{ by }} in the IETF Internet-Drafts database.
|
|
||||||
|
|
||||||
IETF Secretariat.
|
|
|
@ -1,26 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load ams_filters %}
|
|
||||||
|
|
||||||
{% block title %}Drafts{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../../">Drafts</a>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module">
|
|
||||||
<h2>Nudge Report</h2>
|
|
||||||
<table>
|
|
||||||
{% for doc in docs %}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{{ doc.get_absolute_url }}">{{ doc.name }}</a></td>
|
|
||||||
<td>{{ doc|get_published_date|date:"Y-m-d" }}</td>
|
|
||||||
<td></td>
|
|
||||||
<td>{% if doc.ad_name %}{{ doc.ad_name }}{% else %} {% endif %}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,34 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Drafts - Search{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» Drafts
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module draft-container">
|
|
||||||
<h2>Draft - Search</h2>
|
|
||||||
<form id="draft-search-form" enctype="multipart/form-data" action="" method="post">{% csrf_token %}
|
|
||||||
<table id="draft-search-table" class="full-width amstable">
|
|
||||||
{{ form.as_table }}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% include "includes/buttons_search.html" %}
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="inline-group">
|
|
||||||
<h2>Search Results</h2>
|
|
||||||
{% include "includes/draft_search_results.html" %}
|
|
||||||
{% if not_found %}{{ not_found }}{% endif %}
|
|
||||||
</div> <!-- inline-group -->
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,102 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Drafts - View{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../">Drafts</a>
|
|
||||||
» {{ draft.name }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
{% comment %}{{ request.user }}{% endcomment %}
|
|
||||||
|
|
||||||
<div class="module draft-container">
|
|
||||||
<div id="draft-view-col1">
|
|
||||||
<h2>Draft - View</h2>
|
|
||||||
<table class="full-width">
|
|
||||||
<tr><td>Document Name:</td><td>{{ draft.title }}</td></tr>
|
|
||||||
<tr><td>Area:</td><td>{% if draft.group.parent %}<a href="{% url "ietf.secr.areas.views.view" name=draft.group.parent.acronym %}">{{ draft.group.parent }}{% endif %}</td></tr>
|
|
||||||
<tr><td>Group:</td><td>{% if draft.group %}<a href="{% url 'ietf.secr.groups.views.view' acronym=draft.group.acronym %}">{{ draft.group.acronym }}{% endif %}</td></tr>
|
|
||||||
<tr><td>Area Director:</td><td>{{ draft.ad }}</td></tr>
|
|
||||||
<tr><td>Shepherd:</td><td>{% if draft.shepherd %}{{ draft.shepherd.person }} <{{ draft.shepherd.address }}>{% else %}None{% endif %}</td></tr>
|
|
||||||
<tr><td>Notify:</td><td>{{ draft.notify }}</td></tr>
|
|
||||||
<tr><td>Document State:</td><td>{{ draft.get_state }}</td></tr>
|
|
||||||
<tr><td>IESG State:</td><td>{{ draft.iesg_state }}</td></tr>
|
|
||||||
<tr><td>Stream:</td><td>{{ draft.stream }}</td></tr>
|
|
||||||
<tr><td>Under Review by RFC Editor:</td><td>{% if draft.review_by_rfc_editor %}YES{% else %}NO{% endif %}</td></tr>
|
|
||||||
<tr><td>File Name:</td>
|
|
||||||
<td>{% if draft.expired_tombstone %}
|
|
||||||
{{ draft.filename }}
|
|
||||||
<div class=alert>This is a last active version - the tombstone was expired.</div>
|
|
||||||
{% else %}<a href="{% if is_development %}http://devr.amsl.com/ftp/{% else %}https://www.ietf.org/internet-drafts/{% endif %}{{ draft.name }}-{{ draft.rev }}.txt">{{ draft.name }}</a>
|
|
||||||
{% endif %}
|
|
||||||
</td></tr>
|
|
||||||
<tr><td>Document Aliases:</td>
|
|
||||||
<td>{% for alias in draft.docalias_set.all %}
|
|
||||||
{% if not forloop.first %}, {% endif %}
|
|
||||||
{{ alias.name }}
|
|
||||||
{% endfor %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>Revision:</td><td>{{ draft.rev }}</td></tr>
|
|
||||||
<tr><td>Revision Date:</td><td>{{ draft.revision_date }}</td></tr>
|
|
||||||
<tr><td>Start Date:</td><td>{{ draft.start_date }}</td></tr>
|
|
||||||
<tr><td>Number of Pages:</td><td>{{ draft.pages }}</td></tr>
|
|
||||||
{% comment %}<tr><td>Local Path:</td><td>/ftp/internet-drafts/{{ draft.local_path|default_if_none:"" }}</td></tr>{% endcomment %}
|
|
||||||
<tr><td>Abstract:</td><td><a href="{% url 'ietf.secr.drafts.views.abstract' id=draft.name %}">Click here to view the abstract</td></tr>
|
|
||||||
<tr><td>Expiration Date:</td><td>{{ draft.expires|date:"M. d, Y" }}</td></tr>
|
|
||||||
<tr><td>Intended Status:</td><td>{{ draft.intended_std_level|default_if_none:"" }}</td></tr>
|
|
||||||
<tr><td>Standardization Level:</td><td>{{ draft.std_level|default_if_none:"" }}</td></tr>
|
|
||||||
<tr><td>RFC Number:</td><td>{{ draft.rfc_number|default_if_none:"" }}</td></tr>
|
|
||||||
<tr><td>Comments:</td><td>{{ draft.internal_comments|default_if_none:"" }}</td></tr>
|
|
||||||
<tr><td>Last Modified Date:</td><td>{{ draft.time }}</td></tr>
|
|
||||||
<tr><td>Replaced by:</td><td>{% if draft.replaced_by %}<a href="{% url "ietf.secr.drafts.views.view" id=draft.replaced_by.name %}">{{ draft.replaced_by.name }}{% endif %}</td></tr>
|
|
||||||
<tr><td>Related Documents:</td><td>{% for item in draft.relateddocument_set.all %}{% if not forloop.first %}, {% endif %}{{ item.relationship }} <a href="{% url "ietf.secr.drafts.views.view" id=item.target.document.pk %}">{{ item.target.name }}</a>{% endfor %}</td></tr>
|
|
||||||
<tr><td>Tags:</td>
|
|
||||||
<td>{% for tag in draft.tags.all %}
|
|
||||||
{% if not forloop.first %}, {% endif %}
|
|
||||||
{{ tag }}
|
|
||||||
{% endfor %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</div> <!-- draft-view-col1 -->
|
|
||||||
<div id="draft-view-col2">
|
|
||||||
<div class="inline-related">
|
|
||||||
<h2>Author(s)</h2>
|
|
||||||
<table class="full-width">
|
|
||||||
{% for author in draft.documentauthor_set.all %}
|
|
||||||
<tr><td><a href="{% url 'ietf.secr.rolodex.views.view' id=author.person.id %}">{{ author.person.name }}</a></td></tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
</div> <!-- inline-related -->
|
|
||||||
<div class="inline-related action-group">
|
|
||||||
<h2>Actions</h2>
|
|
||||||
<ul>
|
|
||||||
<li><button {% if is_expired or is_withdrawn %}{% else %}disabled="disabled"{% endif %}onclick="window.location='{% url "ietf.secr.drafts.views.email" id=draft.name %}?action=resurrect'">Resurrect</button></li>
|
|
||||||
<li><button {% if is_active %}{% else %}disabled="disabled"{% endif %}onclick="window.location='extend/'">Extend Expiry</button></li>
|
|
||||||
<li><button {% if is_active %}{% else %}disabled="disabled"{% endif %}onclick="window.location='withdraw/'">Withdraw</button></li>
|
|
||||||
</ul>
|
|
||||||
</div> <!-- inline-related -->
|
|
||||||
</div> <!-- draft-view-col2 -->
|
|
||||||
|
|
||||||
<div class="button-group">
|
|
||||||
<ul>
|
|
||||||
<li><button onclick="window.location='edit/'">Edit</button></li>
|
|
||||||
<li><button onclick="window.location='authors/'">Authors</button></li>
|
|
||||||
{% comment %}
|
|
||||||
<li><button onclick="window.location='{% url "sec.ids.views.search" id=group.group_acronym.acronym_id %}'">Drafts</button></li>
|
|
||||||
<li><button onclick="window.location='{% url "sec.rfcs.views.search" id=group.group_acronym.acronym_id %}'">RFCs</button></li>
|
|
||||||
{% endcomment %}
|
|
||||||
</ul>
|
|
||||||
</div> <!-- button-group -->
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,30 +0,0 @@
|
||||||
{% extends "base_site.html" %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
|
|
||||||
{% block title %}Drafts - Withdraw{% endblock %}
|
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
|
||||||
<script type="text/javascript" src="{% static 'secr/js/utils.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}{{ block.super }}
|
|
||||||
» <a href="../">Drafts</a>
|
|
||||||
» <a href="../">{{ draft.name }}</a>
|
|
||||||
» Withdraw
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="module draft-container">
|
|
||||||
<h2>Draft - Withdraw</h2>
|
|
||||||
<form enctype="multipart/form-data" action="" method="post">{% csrf_token %}
|
|
||||||
<table class="full-width">
|
|
||||||
{{ form.as_table }}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% include "includes/buttons_save_cancel.html" %}
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div> <!-- module -->
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,20 +0,0 @@
|
||||||
<table id="draft-search-results" class="center" cellspacing="0">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Group</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Intended Status</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for item in results %}
|
|
||||||
<tr class="{% cycle 'row1' 'row2' %}">
|
|
||||||
<td><a href="{% url "ietf.secr.drafts.views.view" id=item.name %}">{{ item.name }}</a></td>
|
|
||||||
<td>{{item.group.acronym}}</td>
|
|
||||||
<td>{{item.get_state}}</td>
|
|
||||||
<td>{{item.intended_std_level}}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
|
@ -16,7 +16,6 @@
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<h3>IDs and WGs Process</h3>
|
<h3>IDs and WGs Process</h3>
|
||||||
<li> <a href="{% url "ietf.secr.drafts.views.search" %}"><b>Drafts</b></a></li><br>
|
|
||||||
<li> <a href="{% url "ietf.secr.areas.views.list_areas" %}"><b>Areas</b></a></li><br>
|
<li> <a href="{% url "ietf.secr.areas.views.list_areas" %}"><b>Areas</b></a></li><br>
|
||||||
<li> <a href="{% url 'ietf.secr.groups.views.search' %}"><b>Groups</b></a></li><br>
|
<li> <a href="{% url 'ietf.secr.groups.views.search' %}"><b>Groups</b></a></li><br>
|
||||||
<li> <a href="{% url 'ietf.secr.rolodex.views.search' %}"><b>Rolodex</b></a></li><br>
|
<li> <a href="{% url 'ietf.secr.rolodex.views.search' %}"><b>Rolodex</b></a></li><br>
|
||||||
|
@ -26,7 +25,6 @@
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
<td>
|
<td>
|
||||||
<h3>Meetings and Proceedings</h3>
|
<h3>Meetings and Proceedings</h3>
|
||||||
<li> <a href="{% url 'ietf.secr.drafts.views.dates' %}"><b>Draft Submission Dates</b></a></li><br>
|
|
||||||
<li> <a href="{% url "ietf.secr.sreq.views.main" %}"><b>Session Requests</b></a></li><br>
|
<li> <a href="{% url "ietf.secr.sreq.views.main" %}"><b>Session Requests</b></a></li><br>
|
||||||
<li> <a href="{% url 'ietf.secr.proceedings.views.main' %}"><b>Meeting Materials Manager (Proceedings)</b></a></li><br>
|
<li> <a href="{% url 'ietf.secr.proceedings.views.main' %}"><b>Meeting Materials Manager (Proceedings)</b></a></li><br>
|
||||||
<li> <a href="{% url "ietf.secr.meetings.views.main" %}"><b>Meeting Manager</b></a></li><br>
|
<li> <a href="{% url "ietf.secr.meetings.views.main" %}"><b>Meeting Manager</b></a></li><br>
|
||||||
|
|
|
@ -6,7 +6,6 @@ urlpatterns = [
|
||||||
url(r'^announcement/', include('ietf.secr.announcement.urls')),
|
url(r'^announcement/', include('ietf.secr.announcement.urls')),
|
||||||
url(r'^areas/', include('ietf.secr.areas.urls')),
|
url(r'^areas/', include('ietf.secr.areas.urls')),
|
||||||
url(r'^console/', include('ietf.secr.console.urls')),
|
url(r'^console/', include('ietf.secr.console.urls')),
|
||||||
url(r'^drafts/', include('ietf.secr.drafts.urls')),
|
|
||||||
url(r'^groups/', include('ietf.secr.groups.urls')),
|
url(r'^groups/', include('ietf.secr.groups.urls')),
|
||||||
url(r'^meetings/', include('ietf.secr.meetings.urls')),
|
url(r'^meetings/', include('ietf.secr.meetings.urls')),
|
||||||
url(r'^proceedings/', include('ietf.secr.proceedings.urls')),
|
url(r'^proceedings/', include('ietf.secr.proceedings.urls')),
|
||||||
|
|
|
@ -440,7 +440,6 @@ INSTALLED_APPS = [
|
||||||
# IETF Secretariat apps
|
# IETF Secretariat apps
|
||||||
'ietf.secr.announcement',
|
'ietf.secr.announcement',
|
||||||
'ietf.secr.areas',
|
'ietf.secr.areas',
|
||||||
'ietf.secr.drafts',
|
|
||||||
'ietf.secr.groups',
|
'ietf.secr.groups',
|
||||||
'ietf.secr.meetings',
|
'ietf.secr.meetings',
|
||||||
'ietf.secr.proceedings',
|
'ietf.secr.proceedings',
|
||||||
|
|
Loading…
Reference in a new issue