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:
Ryan Cross 2020-03-21 19:52:12 +00:00
parent 931c5ce6cd
commit 5649bfdfd1
45 changed files with 5 additions and 292514 deletions

View file

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

View file

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

View file

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

View file

@ -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"
}
}
]

View file

@ -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"
}
}
]

View file

@ -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",
}
}
]

View file

@ -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"
}
}
]

View file

@ -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"
}
}
]

View file

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

View file

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

View file

@ -1,3 +0,0 @@
# see add_id5.cfm ~400 for email To addresses
# see generateNotification.cfm

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 }}
&raquo; <a href="../../">Drafts</a>
&raquo; <a href="../">{{ draft.canonical_name }}</a>
&raquo; 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 %}

View file

@ -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 }}
&raquo; 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 %}

View file

@ -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 }}
&raquo; <a href="../../">Drafts</a>
&raquo; <a href="../">{{ draft.name }}</a>
&raquo; 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 %}

View file

@ -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 }}
&raquo; <a href="../../">Drafts</a>
&raquo; <a href="../">{{ draft.name }}</a>
&raquo; 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 %}

View file

@ -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 }}
&raquo; <a href="../../">Drafts</a>
&raquo; 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 %}

View file

@ -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 }}
&raquo; <a href="../../">Drafts</a>
&raquo; <a href="../">{{ draft.name }}</a>
&raquo; 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 %}

View file

@ -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 }}
&raquo; <a href="../../">Drafts</a>
&raquo; <a href="../">{{ draft.name }}</a>
&raquo; 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 %}

View file

@ -1,23 +0,0 @@
{% extends "base_site.html" %}
{% block title %}Drafts{% endblock %}
{% block breadcrumbs %}{{ block.super }}
&raquo; <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 %}

View file

@ -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 }}
&raquo; <a href="../../">Drafts</a>
&raquo; <a href="../">{{ draft.name }}</a>
&raquo; 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 %}

View file

@ -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 }}
&raquo; <a href="../../">Drafts</a>
&raquo; <a href="../">{{ draft.name }}</a>
&raquo; 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 %}

View file

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

View file

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

View file

@ -1,4 +0,0 @@
As you requested, {{ doc }}
has been marked as withdrawn by the {{ by }} in the IETF Internet-Drafts database.
IETF Secretariat.

View file

@ -1,26 +0,0 @@
{% extends "base_site.html" %}
{% load ams_filters %}
{% block title %}Drafts{% endblock %}
{% block breadcrumbs %}{{ block.super }}
&raquo; <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 %}&nbsp;{% endif %}</td>
</tr>
{% endfor %}
</table>
</div> <!-- module -->
{% endblock %}

View file

@ -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 }}
&raquo; 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 %}

View file

@ -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 }}
&raquo; <a href="../">Drafts</a>
&raquo; {{ 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 }} &lt;{{ draft.shepherd.address }}&gt;{% 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 %}

View file

@ -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 }}
&raquo; <a href="../">Drafts</a>
&raquo; <a href="../">{{ draft.name }}</a>
&raquo; 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 %}

View file

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

View file

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

View file

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

View file

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