Merge in ^/branch/iola/event-saving-refactor-r10076, fixing a few problems
- Legacy-Id: 10298
This commit is contained in:
commit
86c3a430d1
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os, sys, re, datetime, argparse, traceback, tempfile, json, subprocess
|
||||
import os, sys, re, datetime, argparse, traceback, json, subprocess
|
||||
import html5lib
|
||||
import random
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os, sys, re, json, datetime
|
||||
import os, sys, datetime
|
||||
import syslog
|
||||
import traceback
|
||||
|
||||
|
@ -29,22 +29,28 @@ if options.skip_date:
|
|||
skip_date = datetime.datetime.strptime(options.skip_date, "%Y-%m-%d").date()
|
||||
|
||||
from ietf.utils.pipe import pipe
|
||||
from ietf.sync.rfceditor import *
|
||||
from ietf.doc.utils import rebuild_reference_relations
|
||||
import ietf.sync.rfceditor
|
||||
|
||||
syslog.syslog("Updating document metadata from RFC index from %s" % settings.RFC_EDITOR_QUEUE_URL)
|
||||
|
||||
response = fetch_index_xml(settings.RFC_EDITOR_INDEX_URL)
|
||||
data = parse_index(response)
|
||||
response = ietf.sync.rfceditor.fetch_index_xml(settings.RFC_EDITOR_INDEX_URL)
|
||||
data = ietf.sync.rfceditor.parse_index(response)
|
||||
|
||||
if len(data) < MIN_INDEX_RESULTS:
|
||||
if len(data) < ietf.sync.rfceditor.MIN_INDEX_RESULTS:
|
||||
syslog.syslog("Not enough results, only %s" % len(data))
|
||||
sys.exit(1)
|
||||
|
||||
changed, new_rfcs = update_docs_from_rfc_index(data, skip_older_than_date=skip_date)
|
||||
new_rfcs = []
|
||||
for changes, doc, rfc_published in ietf.sync.rfceditor.update_docs_from_rfc_index(data, skip_older_than_date=skip_date):
|
||||
if rfc_published:
|
||||
new_rfcs.append(doc)
|
||||
|
||||
for c in changed:
|
||||
syslog.syslog(c)
|
||||
for c in changes:
|
||||
syslog.syslog("%s: %s" % (doc.name, c))
|
||||
print "%s: %s" % (doc.name, c)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
# This can be called while processing a notifying POST from the RFC Editor
|
||||
# Spawn a child to sync the rfcs and calculate new reference relationships
|
||||
|
|
|
@ -6,7 +6,7 @@ import datetime, os, shutil, glob, re
|
|||
from pathlib import Path
|
||||
|
||||
from ietf.utils.mail import send_mail
|
||||
from ietf.doc.models import Document, DocEvent, State, save_document_in_history, IESG_SUBSTATE_TAGS
|
||||
from ietf.doc.models import Document, DocEvent, State, IESG_SUBSTATE_TAGS
|
||||
from ietf.person.models import Person
|
||||
from ietf.meeting.models import Meeting
|
||||
from ietf.doc.utils import add_state_change_event
|
||||
|
@ -129,8 +129,9 @@ def expire_draft(doc):
|
|||
|
||||
system = Person.objects.get(name="(System)")
|
||||
|
||||
events = []
|
||||
|
||||
# change the state
|
||||
save_document_in_history(doc)
|
||||
if doc.latest_event(type='started_iesg_process'):
|
||||
new_state = State.objects.get(used=True, type="draft-iesg", slug="dead")
|
||||
prev_state = doc.get_state(new_state.type_id)
|
||||
|
@ -139,15 +140,13 @@ def expire_draft(doc):
|
|||
doc.set_state(new_state)
|
||||
doc.tags.remove(*prev_tags)
|
||||
e = add_state_change_event(doc, system, prev_state, new_state, prev_tags=prev_tags, new_tags=[])
|
||||
if e:
|
||||
events.append(e)
|
||||
|
||||
e = DocEvent(doc=doc, by=system)
|
||||
e.type = "expired_document"
|
||||
e.desc = "Document has expired"
|
||||
e.save()
|
||||
events.append(DocEvent.objects.create(doc=doc, by=system, type="expired_document", desc="Document has expired"))
|
||||
|
||||
doc.set_state(State.objects.get(used=True, type="draft", slug="expired"))
|
||||
doc.time = datetime.datetime.now()
|
||||
doc.save()
|
||||
doc.save_with_history(events)
|
||||
|
||||
def clean_up_draft_files():
|
||||
"""Move unidentified and old files out of the Internet Draft directory."""
|
||||
|
|
|
@ -5,7 +5,6 @@ import datetime
|
|||
from django.db.models import Q
|
||||
|
||||
from ietf.doc.models import Document, State, DocEvent, LastCallDocEvent, WriteupDocEvent
|
||||
from ietf.doc.models import save_document_in_history
|
||||
from ietf.doc.models import IESG_SUBSTATE_TAGS
|
||||
from ietf.person.models import Person
|
||||
from ietf.doc.utils import add_state_change_event
|
||||
|
@ -14,12 +13,15 @@ from ietf.doc.mails import send_last_call_request, email_last_call_expired
|
|||
|
||||
def request_last_call(request, doc):
|
||||
if not doc.latest_event(type="changed_ballot_writeup_text"):
|
||||
generate_ballot_writeup(request, doc)
|
||||
e = generate_ballot_writeup(request, doc)
|
||||
e.save()
|
||||
if not doc.latest_event(type="changed_ballot_approval_text"):
|
||||
generate_approval_mail(request, doc)
|
||||
e = generate_approval_mail(request, doc)
|
||||
e.save()
|
||||
if not doc.latest_event(type="changed_last_call_text"):
|
||||
generate_last_call_announcement(request, doc)
|
||||
|
||||
e = generate_last_call_announcement(request, doc)
|
||||
e.save()
|
||||
|
||||
send_last_call_request(request, doc)
|
||||
|
||||
e = DocEvent()
|
||||
|
@ -50,8 +52,6 @@ def expire_last_call(doc):
|
|||
else:
|
||||
raise ValueError("Unexpected document type to expire_last_call(): %s" % doc.type)
|
||||
|
||||
save_document_in_history(doc)
|
||||
|
||||
prev_state = doc.get_state(new_state.type_id)
|
||||
doc.set_state(new_state)
|
||||
|
||||
|
@ -60,8 +60,7 @@ def expire_last_call(doc):
|
|||
|
||||
system = Person.objects.get(name="(System)")
|
||||
e = add_state_change_event(doc, system, prev_state, new_state, prev_tags=prev_tags, new_tags=[])
|
||||
|
||||
doc.time = (e and e.time) or datetime.datetime.now()
|
||||
doc.save()
|
||||
if e:
|
||||
doc.save_with_history([e])
|
||||
|
||||
email_last_call_expired(doc)
|
||||
|
|
|
@ -78,6 +78,21 @@ def email_iesg_processing_document(request, doc, changes):
|
|||
def html_to_text(html):
|
||||
return strip_tags(html.replace("<", "<").replace(">", ">").replace("&", "&").replace("<br>", "\n"))
|
||||
|
||||
def email_update_telechat(request, doc, text):
|
||||
(to, cc) = gather_address_lists('doc_telechat_details_changed',doc=doc)
|
||||
|
||||
if not to:
|
||||
return
|
||||
|
||||
text = strip_tags(text)
|
||||
send_mail(request, to, None,
|
||||
"Telechat update notice: %s" % doc.file_tag(),
|
||||
"doc/mail/update_telechat.txt",
|
||||
dict(text=text,
|
||||
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
|
||||
cc=cc)
|
||||
|
||||
|
||||
def generate_ballot_writeup(request, doc):
|
||||
e = doc.latest_event(type="iana_review")
|
||||
iana = e.desc if e else ""
|
||||
|
@ -88,8 +103,8 @@ def generate_ballot_writeup(request, doc):
|
|||
e.doc = doc
|
||||
e.desc = u"Ballot writeup was generated"
|
||||
e.text = unicode(render_to_string("doc/mail/ballot_writeup.txt", {'iana': iana}))
|
||||
e.save()
|
||||
|
||||
|
||||
# caller is responsible for saving, if necessary
|
||||
return e
|
||||
|
||||
def generate_last_call_announcement(request, doc):
|
||||
|
@ -130,8 +145,8 @@ def generate_last_call_announcement(request, doc):
|
|||
e.doc = doc
|
||||
e.desc = u"Last call announcement was generated"
|
||||
e.text = unicode(mail)
|
||||
e.save()
|
||||
|
||||
# caller is responsible for saving, if necessary
|
||||
return e
|
||||
|
||||
|
||||
|
@ -149,8 +164,8 @@ def generate_approval_mail(request, doc):
|
|||
e.doc = doc
|
||||
e.desc = u"Ballot approval text was generated"
|
||||
e.text = unicode(mail)
|
||||
e.save()
|
||||
|
||||
# caller is responsible for saving, if necessary
|
||||
return e
|
||||
|
||||
def generate_approval_mail_approved(request, doc):
|
||||
|
|
91
ietf/doc/migrations/0011_auto_20151027_1127.py
Normal file
91
ietf/doc/migrations/0011_auto_20151027_1127.py
Normal file
|
@ -0,0 +1,91 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
def fix_buggy_author_foreignkey(apps, schema_editor):
|
||||
DocumentAuthor = apps.get_model("doc", "DocumentAuthor")
|
||||
# apparently, we have a buggy key in the DB, fix it
|
||||
DocumentAuthor.objects.filter(author="[<Email: d3e3e3@gmail.com>]").update(author="d3e3e3@gmail.com")
|
||||
|
||||
def save_all_documents_in_history(apps, schema_editor):
|
||||
State = apps.get_model("doc", "State")
|
||||
Document = apps.get_model("doc", "Document")
|
||||
DocHistory = apps.get_model("doc", "DocHistory")
|
||||
RelatedDocument = apps.get_model("doc", "RelatedDocument")
|
||||
RelatedDocHistory = apps.get_model("doc", "RelatedDocHistory")
|
||||
DocumentAuthor = apps.get_model("doc", "DocumentAuthor")
|
||||
DocHistoryAuthor = apps.get_model("doc", "DocHistoryAuthor")
|
||||
|
||||
def canonical_name(self):
|
||||
name = self.name
|
||||
state = State.objects.filter(document=self, type_id=self.type_id).first()
|
||||
if self.type_id == "draft" and state.slug == "rfc":
|
||||
a = self.docalias_set.filter(name__startswith="rfc")
|
||||
if a:
|
||||
name = a[0].name
|
||||
elif self.type_id == "charter":
|
||||
return charter_name_for_group(self.chartered_group)
|
||||
return name
|
||||
|
||||
def charter_name_for_group(group):
|
||||
if group.type_id == "rg":
|
||||
top_org = "irtf"
|
||||
else:
|
||||
top_org = "ietf"
|
||||
|
||||
return "charter-%s-%s" % (top_org, group.acronym)
|
||||
|
||||
def save_document_in_history(doc):
|
||||
"""Save a snapshot of document and related objects in the database."""
|
||||
def get_model_fields_as_dict(obj):
|
||||
return dict((field.name, getattr(obj, field.name))
|
||||
for field in obj._meta.fields
|
||||
if field is not obj._meta.pk)
|
||||
|
||||
# copy fields
|
||||
fields = get_model_fields_as_dict(doc)
|
||||
fields["doc"] = doc
|
||||
fields["name"] = canonical_name(doc)
|
||||
|
||||
dochist = DocHistory(**fields)
|
||||
dochist.save()
|
||||
|
||||
# copy many to many
|
||||
for field in doc._meta.many_to_many:
|
||||
if field.rel.through and field.rel.through._meta.auto_created:
|
||||
setattr(dochist, field.name, getattr(doc, field.name).all())
|
||||
|
||||
# copy remaining tricky many to many
|
||||
def transfer_fields(obj, HistModel):
|
||||
mfields = get_model_fields_as_dict(item)
|
||||
# map doc -> dochist
|
||||
for k, v in mfields.iteritems():
|
||||
if v == doc:
|
||||
mfields[k] = dochist
|
||||
HistModel.objects.create(**mfields)
|
||||
|
||||
for item in RelatedDocument.objects.filter(source=doc):
|
||||
transfer_fields(item, RelatedDocHistory)
|
||||
|
||||
for item in DocumentAuthor.objects.filter(document=doc):
|
||||
transfer_fields(item, DocHistoryAuthor)
|
||||
|
||||
return dochist
|
||||
|
||||
from django.conf import settings
|
||||
settings.DEBUG = False # prevent out-of-memory problems
|
||||
|
||||
for d in Document.objects.iterator():
|
||||
save_document_in_history(d)
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('doc', '0010_auto_20150930_0251'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(fix_buggy_author_foreignkey),
|
||||
migrations.RunPython(save_all_documents_in_history)
|
||||
]
|
|
@ -18,7 +18,6 @@ from ietf.name.models import ( DocTypeName, DocTagName, StreamName, IntendedStdL
|
|||
from ietf.person.models import Email, Person
|
||||
from ietf.utils.admin import admin_link
|
||||
|
||||
|
||||
class StateType(models.Model):
|
||||
slug = models.CharField(primary_key=True, max_length=30) # draft, draft-iesg, charter, ...
|
||||
label = models.CharField(max_length=255, help_text="Label that should be used (e.g. in admin) for state drop-down for this type of state") # State, IESG state, WG state, ...
|
||||
|
@ -432,6 +431,27 @@ class Document(DocumentInfo):
|
|||
name = name.upper()
|
||||
return name
|
||||
|
||||
def save_with_history(self, events):
|
||||
"""Save document and put a snapshot in the history models where they
|
||||
can be retrieved later. You must pass in at least one event
|
||||
with a description of what happened."""
|
||||
|
||||
assert events, "You must always add at least one event to describe the changes in the history log"
|
||||
self.time = max(self.time, events[0].time)
|
||||
|
||||
self._has_an_event_so_saving_is_allowed = True
|
||||
self.save()
|
||||
del self._has_an_event_so_saving_is_allowed
|
||||
|
||||
from ietf.doc.utils import save_document_in_history
|
||||
save_document_in_history(self)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# if there's no primary key yet, we can allow the save to go
|
||||
# through to break the cycle between the document and any
|
||||
# events
|
||||
assert kwargs.get("force_insert", False) or getattr(self, "_has_an_event_so_saving_is_allowed", None), "Use .save_with_history to save documents"
|
||||
super(Document, self).save(*args, **kwargs)
|
||||
|
||||
def telechat_date(self, e=None):
|
||||
if not e:
|
||||
|
@ -568,50 +588,6 @@ class DocHistory(DocumentInfo):
|
|||
verbose_name = "document history"
|
||||
verbose_name_plural = "document histories"
|
||||
|
||||
def save_document_in_history(doc):
|
||||
"""This should be called before saving changes to a Document instance,
|
||||
so that the DocHistory entries contain all previous states, while
|
||||
the Group entry contain the current state. XXX TODO: Call this
|
||||
directly from Document.save(), and add event listeners for save()
|
||||
on related objects so we can save as needed when they change, too.
|
||||
"""
|
||||
def get_model_fields_as_dict(obj):
|
||||
return dict((field.name, getattr(obj, field.name))
|
||||
for field in obj._meta.fields
|
||||
if field is not obj._meta.pk)
|
||||
|
||||
# copy fields
|
||||
fields = get_model_fields_as_dict(doc)
|
||||
fields["doc"] = doc
|
||||
fields["name"] = doc.canonical_name()
|
||||
|
||||
dochist = DocHistory(**fields)
|
||||
dochist.save()
|
||||
|
||||
# copy many to many
|
||||
for field in doc._meta.many_to_many:
|
||||
if field.rel.through and field.rel.through._meta.auto_created:
|
||||
setattr(dochist, field.name, getattr(doc, field.name).all())
|
||||
|
||||
# copy remaining tricky many to many
|
||||
def transfer_fields(obj, HistModel):
|
||||
mfields = get_model_fields_as_dict(item)
|
||||
# map doc -> dochist
|
||||
for k, v in mfields.iteritems():
|
||||
if v == doc:
|
||||
mfields[k] = dochist
|
||||
HistModel.objects.create(**mfields)
|
||||
|
||||
for item in RelatedDocument.objects.filter(source=doc):
|
||||
transfer_fields(item, RelatedDocHistory)
|
||||
|
||||
for item in DocumentAuthor.objects.filter(document=doc):
|
||||
transfer_fields(item, DocHistoryAuthor)
|
||||
|
||||
return dochist
|
||||
|
||||
|
||||
|
||||
class DocAlias(models.Model):
|
||||
"""This is used for documents that may appear under multiple names,
|
||||
and in particular for RFCs, which for continuity still keep the
|
||||
|
@ -693,7 +669,8 @@ EVENT_TYPES = [
|
|||
|
||||
# RFC Editor
|
||||
("rfc_editor_received_announcement", "Announcement was received by RFC Editor"),
|
||||
("requested_publication", "Publication at RFC Editor requested")
|
||||
("requested_publication", "Publication at RFC Editor requested"),
|
||||
("sync_from_rfc_editor", "Received updated information from RFC Editor"),
|
||||
]
|
||||
|
||||
class DocEvent(models.Model):
|
||||
|
@ -705,10 +682,11 @@ class DocEvent(models.Model):
|
|||
desc = models.TextField()
|
||||
|
||||
def for_current_revision(self):
|
||||
return self.time >= self.doc.latest_event(NewRevisionDocEvent,type='new_revision').time
|
||||
e = self.doc.latest_event(NewRevisionDocEvent,type='new_revision')
|
||||
return not e or (self.time, self.pk) >= (e.time, e.pk)
|
||||
|
||||
def get_dochistory(self):
|
||||
return DocHistory.objects.filter(time__lte=self.time,doc__name=self.doc.name).order_by('-time').first()
|
||||
return DocHistory.objects.filter(time__lte=self.time,doc__name=self.doc.name).order_by('-time', '-pk').first()
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s %s by %s at %s" % (self.doc.name, self.get_type_display().lower(), self.by.plain_name(), self.time)
|
||||
|
|
|
@ -18,8 +18,7 @@ from django.conf import settings
|
|||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.models import ( Document, DocAlias, DocRelationshipName, RelatedDocument, State,
|
||||
DocEvent, BallotPositionDocEvent, LastCallDocEvent, WriteupDocEvent, NewRevisionDocEvent,
|
||||
save_document_in_history )
|
||||
DocEvent, BallotPositionDocEvent, LastCallDocEvent, WriteupDocEvent, NewRevisionDocEvent )
|
||||
from ietf.group.models import Group
|
||||
from ietf.meeting.models import Meeting, Session, SessionPresentation
|
||||
from ietf.name.models import SessionStatusName
|
||||
|
@ -111,10 +110,11 @@ class SearchTests(TestCase):
|
|||
|
||||
def test_search_for_name(self):
|
||||
draft = make_test_data()
|
||||
save_document_in_history(draft)
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
prev_rev = draft.rev
|
||||
draft.rev = "%02d" % (int(prev_rev) + 1)
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
# exact match
|
||||
r = self.client.get(urlreverse("doc_search_for_name", kwargs=dict(name=draft.name)))
|
||||
|
@ -513,9 +513,8 @@ Man Expires September 22, 2015 [Page 3]
|
|||
# draft published as RFC
|
||||
draft.set_state(State.objects.get(type="draft", slug="rfc"))
|
||||
draft.std_level_id = "bcp"
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="published_rfc", by=Person.objects.get(name="(System)"))])
|
||||
|
||||
DocEvent.objects.create(doc=draft, type="published_rfc", by=Person.objects.get(name="(System)"))
|
||||
|
||||
rfc_alias = DocAlias.objects.create(name="rfc123456", document=draft)
|
||||
bcp_alias = DocAlias.objects.create(name="bcp123456", document=draft)
|
||||
|
@ -561,9 +560,10 @@ Man Expires September 22, 2015 [Page 3]
|
|||
]:
|
||||
doc = Document.objects.get(name=docname)
|
||||
# give it some history
|
||||
save_document_in_history(doc)
|
||||
doc.rev="01"
|
||||
doc.save()
|
||||
doc.save_with_history([DocEvent.objects.create(doc=doc, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
doc.rev = "01"
|
||||
doc.save_with_history([DocEvent.objects.create(doc=doc, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
r = self.client.get(urlreverse("doc_view", kwargs=dict(name=doc.name)))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
@ -620,7 +620,8 @@ class DocTestCase(TestCase):
|
|||
doc = make_test_data()
|
||||
ballot = doc.active_ballot()
|
||||
|
||||
save_document_in_history(doc)
|
||||
# make sure we have some history
|
||||
doc.save_with_history([DocEvent.objects.create(doc=doc, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
pos = BallotPositionDocEvent.objects.create(
|
||||
doc=doc,
|
||||
|
@ -648,9 +649,8 @@ class DocTestCase(TestCase):
|
|||
# Now simulate a new revision and make sure positions on older revisions are marked as such
|
||||
oldrev = doc.rev
|
||||
e = NewRevisionDocEvent.objects.create(doc=doc,rev='%02d'%(int(doc.rev)+1),type='new_revision',by=Person.objects.get(name="(System)"))
|
||||
save_document_in_history(doc)
|
||||
doc.rev = e.rev
|
||||
doc.save()
|
||||
doc.save_with_history([e])
|
||||
r = self.client.get(urlreverse("ietf.doc.views_doc.document_ballot", kwargs=dict(name=doc.name)))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue( '(%s for -%s)' % (pos.comment_time.strftime('%Y-%m-%d'), oldrev) in r.content)
|
||||
|
|
|
@ -125,7 +125,7 @@ class EditPositionTests(TestCase):
|
|||
def test_send_ballot_comment(self):
|
||||
draft = make_test_data()
|
||||
draft.notify = "somebody@example.com"
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
ad = Person.objects.get(name="Aread Irector")
|
||||
|
||||
|
@ -217,8 +217,8 @@ class BallotWriteupsTests(TestCase):
|
|||
regenerate_last_call_text="1"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertTrue("Subject: Last Call" in draft.latest_event(WriteupDocEvent, type="changed_last_call_text").text)
|
||||
text = q("[name=last_call_text]").text()
|
||||
self.assertTrue("Subject: Last Call" in text)
|
||||
|
||||
|
||||
def test_request_last_call(self):
|
||||
|
@ -229,12 +229,14 @@ class BallotWriteupsTests(TestCase):
|
|||
# give us an announcement to send
|
||||
r = self.client.post(url, dict(regenerate_last_call_text="1"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
q = PyQuery(r.content)
|
||||
text = q("[name=last_call_text]").text()
|
||||
|
||||
mailbox_before = len(outbox)
|
||||
|
||||
# send
|
||||
r = self.client.post(url, dict(
|
||||
last_call_text=draft.latest_event(WriteupDocEvent, type="changed_last_call_text").text,
|
||||
last_call_text=text,
|
||||
send_last_call_request="1"))
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEqual(draft.get_state_slug("draft-iesg"), "lc-req")
|
||||
|
@ -318,7 +320,6 @@ class BallotWriteupsTests(TestCase):
|
|||
# test regenerate
|
||||
r = self.client.post(url, dict(regenerate_approval_text="1"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertTrue("Subject: Protocol Action" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
|
||||
|
||||
# test regenerate when it's a disapprove
|
||||
|
@ -326,18 +327,16 @@ class BallotWriteupsTests(TestCase):
|
|||
|
||||
r = self.client.post(url, dict(regenerate_approval_text="1"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertTrue("NOT be published" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
|
||||
|
||||
# test regenerate when it's a conflict review
|
||||
draft.group = Group.objects.get(type="individ")
|
||||
draft.stream_id = "irtf"
|
||||
draft.save()
|
||||
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="iesg-eva"))
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
r = self.client.post(url, dict(regenerate_approval_text="1"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertTrue("Subject: Results of IETF-conflict review" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
|
||||
|
||||
|
||||
|
@ -519,7 +518,6 @@ class DeferUndeferTestCase(TestCase):
|
|||
defer_states = dict(draft=['draft-iesg','defer'],conflrev=['conflrev','defer'],statchg=['statchg','defer'])
|
||||
if doc.type_id in defer_states:
|
||||
doc.set_state(State.objects.get(used=True, type=defer_states[doc.type_id][0],slug=defer_states[doc.type_id][1]))
|
||||
doc.save()
|
||||
|
||||
# get
|
||||
r = self.client.get(url)
|
||||
|
|
|
@ -9,7 +9,8 @@ from django.core.urlresolvers import reverse as urlreverse
|
|||
|
||||
from ietf.doc.models import ( Document, State, BallotDocEvent, BallotType, NewRevisionDocEvent,
|
||||
TelechatDocEvent, WriteupDocEvent )
|
||||
from ietf.doc.utils_charter import next_revision, default_review_text, default_action_text
|
||||
from ietf.doc.utils_charter import ( next_revision, default_review_text, default_action_text,
|
||||
charter_name_for_group )
|
||||
from ietf.group.models import Group, GroupMilestone
|
||||
from ietf.iesg.models import TelechatDate
|
||||
from ietf.person.models import Person
|
||||
|
@ -27,6 +28,10 @@ class EditCharterTests(TestCase):
|
|||
def tearDown(self):
|
||||
shutil.rmtree(self.charter_dir)
|
||||
|
||||
def write_charter_file(self, charter):
|
||||
with open(os.path.join(self.charter_dir, "%s-%s.txt" % (charter.canonical_name(), charter.rev)), "w") as f:
|
||||
f.write("This is a charter.")
|
||||
|
||||
def test_startstop_process(self):
|
||||
make_test_data()
|
||||
|
||||
|
@ -43,6 +48,8 @@ class EditCharterTests(TestCase):
|
|||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
# post
|
||||
self.write_charter_file(charter)
|
||||
|
||||
r = self.client.post(url, dict(message="test message"))
|
||||
self.assertEqual(r.status_code, 302)
|
||||
if option == "abandon":
|
||||
|
@ -273,6 +280,40 @@ class EditCharterTests(TestCase):
|
|||
self.assertEqual(f.read(),
|
||||
"Windows line\nMac line\nUnix line\n" + utf_8_snippet)
|
||||
|
||||
def test_submit_initial_charter(self):
|
||||
make_test_data()
|
||||
|
||||
group = Group.objects.get(acronym="mars")
|
||||
# get rid of existing charter
|
||||
charter = group.charter
|
||||
group.charter = None
|
||||
group.save()
|
||||
charter.delete()
|
||||
charter = None
|
||||
|
||||
url = urlreverse('charter_submit', kwargs=dict(name=charter_name_for_group(group)))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('form input[name=txt]')), 1)
|
||||
|
||||
# create charter
|
||||
test_file = StringIO("Simple test")
|
||||
test_file.name = "unnamed"
|
||||
|
||||
r = self.client.post(url, dict(txt=test_file))
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
charter = Document.objects.get(name="charter-ietf-%s" % group.acronym)
|
||||
self.assertEqual(charter.rev, "00-00")
|
||||
self.assertTrue("new_revision" in charter.latest_event().type)
|
||||
|
||||
group = Group.objects.get(pk=group.pk)
|
||||
self.assertEqual(group.charter, charter)
|
||||
|
||||
def test_edit_review_announcement_text(self):
|
||||
draft = make_test_data()
|
||||
charter = draft.group.charter
|
||||
|
@ -385,7 +426,8 @@ class EditCharterTests(TestCase):
|
|||
url = urlreverse('ietf.doc.views_charter.ballot_writeupnotes', kwargs=dict(name=charter.name))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
default_action_text(draft.group, charter, by)
|
||||
e = default_action_text(draft.group, charter, by)
|
||||
e.save()
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
|
@ -417,8 +459,7 @@ class EditCharterTests(TestCase):
|
|||
url = urlreverse('charter_approve', kwargs=dict(name=charter.name))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
with open(os.path.join(self.charter_dir, "%s-%s.txt" % (charter.canonical_name(), charter.rev)), "w") as f:
|
||||
f.write("This is a charter.")
|
||||
self.write_charter_file(charter)
|
||||
|
||||
p = Person.objects.get(name="Aread Irector")
|
||||
|
||||
|
|
|
@ -32,8 +32,8 @@ class ConflictReviewTests(TestCase):
|
|||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 404)
|
||||
|
||||
doc.stream=StreamName.objects.get(slug='ise')
|
||||
doc.save()
|
||||
doc.stream = StreamName.objects.get(slug='ise')
|
||||
doc.save_with_history([DocEvent.objects.create(doc=doc, type="changed_stream", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
# normal get should succeed and get a reasonable form
|
||||
r = self.client.get(url)
|
||||
|
@ -89,14 +89,14 @@ class ConflictReviewTests(TestCase):
|
|||
|
||||
|
||||
# can't start conflict reviews on documents in some other stream
|
||||
doc.stream=StreamName.objects.get(slug='irtf')
|
||||
doc.save()
|
||||
doc.stream = StreamName.objects.get(slug='irtf')
|
||||
doc.save_with_history([DocEvent.objects.create(doc=doc, type="changed_stream", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 404)
|
||||
|
||||
# successful get
|
||||
doc.stream=StreamName.objects.get(slug='ise')
|
||||
doc.save()
|
||||
doc.stream = StreamName.objects.get(slug='ise')
|
||||
doc.save_with_history([DocEvent.objects.create(doc=doc, type="changed_stream", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
|
@ -269,7 +269,6 @@ class ConflictReviewTests(TestCase):
|
|||
# Some additional setup
|
||||
create_ballot_if_not_open(doc,Person.objects.get(name="Sec Retary"),"conflrev")
|
||||
doc.set_state(State.objects.get(used=True, slug=approve_type+'-pend',type='conflrev'))
|
||||
doc.save()
|
||||
|
||||
# get
|
||||
r = self.client.get(url)
|
||||
|
|
|
@ -370,9 +370,9 @@ class EditInfoTests(TestCase):
|
|||
self.assertEqual(draft.ad, ad)
|
||||
self.assertEqual(draft.note, "This is a note")
|
||||
self.assertTrue(not draft.latest_event(TelechatDocEvent, type="scheduled_for_telechat"))
|
||||
self.assertEqual(draft.docevent_set.count(), events_before + 3)
|
||||
self.assertEqual(draft.docevent_set.count(), events_before + 4)
|
||||
events = list(draft.docevent_set.order_by('time', 'id'))
|
||||
self.assertEqual(events[-3].type, "started_iesg_process")
|
||||
self.assertEqual(events[-4].type, "started_iesg_process")
|
||||
self.assertEqual(len(outbox), mailbox_before+1)
|
||||
self.assertTrue('IESG processing' in outbox[-1]['Subject'])
|
||||
self.assertTrue('draft-ietf-mars-test2@' in outbox[-1]['To'])
|
||||
|
@ -381,7 +381,7 @@ class EditInfoTests(TestCase):
|
|||
draft.unset_state('draft-iesg')
|
||||
draft.set_state(State.objects.get(type='draft-stream-ietf',slug='writeupw'))
|
||||
draft.stream = StreamName.objects.get(slug='ietf')
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_stream", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
r = self.client.post(url,
|
||||
dict(intended_std_level=str(draft.intended_std_level_id),
|
||||
ad=ad.pk,
|
||||
|
@ -537,7 +537,7 @@ class ExpireIDsTests(TestCase):
|
|||
# hack into expirable state
|
||||
draft.unset_state("draft-iesg")
|
||||
draft.expires = datetime.datetime.now() + datetime.timedelta(days=10)
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
self.assertEqual(len(list(get_soon_to_expire_drafts(14))), 1)
|
||||
|
||||
|
@ -561,7 +561,7 @@ class ExpireIDsTests(TestCase):
|
|||
# hack into expirable state
|
||||
draft.unset_state("draft-iesg")
|
||||
draft.expires = datetime.datetime.now()
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
self.assertEqual(len(list(get_expired_drafts())), 1)
|
||||
|
||||
|
@ -624,7 +624,6 @@ class ExpireIDsTests(TestCase):
|
|||
|
||||
# RFC draft
|
||||
draft.set_state(State.objects.get(used=True, type="draft", slug="rfc"))
|
||||
draft.save()
|
||||
|
||||
txt = "%s-%s.txt" % (draft.name, draft.rev)
|
||||
self.write_draft_file(txt, 5000)
|
||||
|
@ -642,7 +641,7 @@ class ExpireIDsTests(TestCase):
|
|||
# expire draft
|
||||
draft.set_state(State.objects.get(used=True, type="draft", slug="expired"))
|
||||
draft.expires = datetime.datetime.now() - datetime.timedelta(days=1)
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
e = DocEvent()
|
||||
e.doc = draft
|
||||
|
@ -862,7 +861,7 @@ class IndividualInfoFormsTests(TestCase):
|
|||
|
||||
def test_doc_change_shepherd(self):
|
||||
self.doc.shepherd = None
|
||||
self.doc.save()
|
||||
self.doc.save_with_history([DocEvent.objects.create(doc=self.doc, type="changed_shepherd", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
url = urlreverse('doc_edit_shepherd',kwargs=dict(name=self.docname))
|
||||
|
||||
|
@ -914,19 +913,19 @@ class IndividualInfoFormsTests(TestCase):
|
|||
|
||||
def test_doc_change_shepherd_email(self):
|
||||
self.doc.shepherd = None
|
||||
self.doc.save()
|
||||
self.doc.save_with_history([DocEvent.objects.create(doc=self.doc, type="changed_shepherd", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
url = urlreverse('doc_change_shepherd_email',kwargs=dict(name=self.docname))
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 404)
|
||||
|
||||
self.doc.shepherd = Email.objects.get(person__user__username="ad1")
|
||||
self.doc.save()
|
||||
self.doc.save_with_history([DocEvent.objects.create(doc=self.doc, type="changed_shepherd", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
login_testing_unauthorized(self, "plain", url)
|
||||
|
||||
self.doc.shepherd = Email.objects.get(person__user__username="plain")
|
||||
self.doc.save()
|
||||
self.doc.save_with_history([DocEvent.objects.create(doc=self.doc, type="changed_shepherd", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
new_email = Email.objects.create(address="anotheremail@example.com", person=self.doc.shepherd.person)
|
||||
|
||||
|
@ -961,7 +960,7 @@ class IndividualInfoFormsTests(TestCase):
|
|||
# Try again when no longer a shepherd.
|
||||
|
||||
self.doc.shepherd = None
|
||||
self.doc.save()
|
||||
self.doc.save_with_history([DocEvent.objects.create(doc=self.doc, type="changed_shepherd", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code,200)
|
||||
q = PyQuery(r.content)
|
||||
|
@ -1070,7 +1069,7 @@ class RequestPublicationTests(TestCase):
|
|||
draft.stream = StreamName.objects.get(slug="iab")
|
||||
draft.group = Group.objects.get(acronym="iab")
|
||||
draft.intended_std_level = IntendedStdLevelName.objects.get(slug="inf")
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
draft.set_state(State.objects.get(used=True, type="draft-stream-iab", slug="approved"))
|
||||
|
||||
url = urlreverse('doc_request_publication', kwargs=dict(name=draft.name))
|
||||
|
@ -1110,8 +1109,8 @@ class AdoptDraftTests(TestCase):
|
|||
draft = make_test_data()
|
||||
draft.stream = None
|
||||
draft.group = Group.objects.get(type="individ")
|
||||
draft.save()
|
||||
draft.unset_state("draft-stream-ietf")
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
url = urlreverse('doc_adopt_draft', kwargs=dict(name=draft.name))
|
||||
login_testing_unauthorized(self, "marschairman", url)
|
||||
|
|
|
@ -23,7 +23,7 @@ from ietf.utils.test_utils import login_testing_unauthorized
|
|||
class StatusChangeTests(TestCase):
|
||||
def test_start_review(self):
|
||||
|
||||
url = urlreverse('start_rfc_status_change',kwargs=dict(name=""))
|
||||
url = urlreverse('start_rfc_status_change')
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
# normal get should succeed and get a reasonable form
|
||||
|
@ -104,7 +104,7 @@ class StatusChangeTests(TestCase):
|
|||
# successful change to Last Call Requested
|
||||
messages_before = len(outbox)
|
||||
doc.ad = Person.objects.get(user__username='ad')
|
||||
doc.save()
|
||||
doc.save_with_history([DocEvent.objects.create(doc=doc, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
lc_req_pk = str(State.objects.get(slug='lc-req',type__slug='statchg').pk)
|
||||
r = self.client.post(url,dict(new_state=lc_req_pk))
|
||||
self.assertEquals(r.status_code, 200)
|
||||
|
@ -251,8 +251,8 @@ class StatusChangeTests(TestCase):
|
|||
# additional setup
|
||||
doc.relateddocument_set.create(target=DocAlias.objects.get(name='rfc9999'),relationship_id='tois')
|
||||
doc.relateddocument_set.create(target=DocAlias.objects.get(name='rfc9998'),relationship_id='tohist')
|
||||
doc.ad = Person.objects.get(name='Ad No2')
|
||||
doc.save()
|
||||
doc.ad = Person.objects.get(name='Ad No2')
|
||||
doc.save_with_history([DocEvent.objects.create(doc=doc, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
# get
|
||||
r = self.client.get(url)
|
||||
|
@ -295,9 +295,8 @@ class StatusChangeTests(TestCase):
|
|||
# Some additional setup
|
||||
doc.relateddocument_set.create(target=DocAlias.objects.get(name='rfc9999'),relationship_id='tois')
|
||||
doc.relateddocument_set.create(target=DocAlias.objects.get(name='rfc9998'),relationship_id='tohist')
|
||||
create_ballot_if_not_open(doc,Person.objects.get(name="Sec Retary"),"statchg")
|
||||
create_ballot_if_not_open(doc,Person.objects.get(user__username="secretary"),"statchg")
|
||||
doc.set_state(State.objects.get(slug='appr-pend',type='statchg'))
|
||||
doc.save()
|
||||
|
||||
# get
|
||||
r = self.client.get(url)
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
from django.conf.urls import patterns, url, include
|
||||
from django.views.generic import RedirectView
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.doc import views_search, views_draft, views_ballot
|
||||
from ietf.doc import views_status_change
|
||||
|
@ -45,7 +46,7 @@ urlpatterns = patterns('',
|
|||
url(r'^ad/(?P<name>[A-Za-z0-9.-]+)/$', views_search.docs_for_ad, name="docs_for_ad"),
|
||||
(r'^ad2/(?P<name>[A-Za-z0-9.-]+)/$', RedirectView.as_view(url='/doc/ad/%(name)s/', permanent=True)),
|
||||
url(r'^rfc-status-changes/$', views_status_change.rfc_status_changes, name='rfc_status_changes'),
|
||||
url(r'^start-rfc-status-change/(?P<name>[A-Za-z0-9._+-]*)$', views_status_change.start_rfc_status_change, name='start_rfc_status_change'),
|
||||
url(r'^start-rfc-status-change/(?:%(name)s/)?$' % settings.URL_REGEXPS, views_status_change.start_rfc_status_change, name='start_rfc_status_change'),
|
||||
url(r'^iesg/(?P<last_call_only>[A-Za-z0-9.-]+/)?$', views_search.drafts_in_iesg_process, name="drafts_in_iesg_process"),
|
||||
url(r'^email-aliases/$', views_doc.email_aliases),
|
||||
|
||||
|
@ -53,62 +54,62 @@ urlpatterns = patterns('',
|
|||
url(r'^active/$', views_search.index_active_drafts, name="index_active_drafts"),
|
||||
url(r'^select2search/(?P<model_name>(document|docalias))/(?P<doc_type>draft)/$', views_search.ajax_select2_search_docs, name="ajax_select2_search_docs"),
|
||||
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/(?:(?P<rev>[0-9-]+)/)?$', views_doc.document_main, name="doc_view"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/history/$', views_doc.document_history, name="doc_history"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/writeup/$', views_doc.document_writeup, name="doc_writeup"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/email/$', views_doc.document_email, name="doc_email"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/shepherdwriteup/$', views_doc.document_shepherd_writeup, name="doc_shepherd_writeup"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/references/$', views_doc.document_references, name="doc_references"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/referencedby/$', views_doc.document_referenced_by, name="doc_referenced_by"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/(?P<ballot_id>[0-9]+)/position/$', views_ballot.edit_position),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/(?P<ballot_id>[0-9]+)/emailposition/$', views_ballot.send_ballot_comment, name='doc_send_ballot_comment'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/(?P<ballot_id>[0-9]+)/$', views_doc.document_ballot, name="doc_ballot"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/$', views_doc.document_ballot, name="doc_ballot"),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/doc.json$', views_doc.document_json),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/ballotpopup/(?P<ballot_id>[0-9]+)/$', views_doc.ballot_popup),
|
||||
url(r'^%(name)s/(?:%(rev)s/)?$' % settings.URL_REGEXPS, views_doc.document_main, name="doc_view"),
|
||||
url(r'^%(name)s/history/$' % settings.URL_REGEXPS, views_doc.document_history, name="doc_history"),
|
||||
url(r'^%(name)s/writeup/$' % settings.URL_REGEXPS, views_doc.document_writeup, name="doc_writeup"),
|
||||
url(r'^%(name)s/email/$' % settings.URL_REGEXPS, views_doc.document_email, name="doc_email"),
|
||||
url(r'^%(name)s/shepherdwriteup/$' % settings.URL_REGEXPS, views_doc.document_shepherd_writeup, name="doc_shepherd_writeup"),
|
||||
url(r'^%(name)s/references/$' % settings.URL_REGEXPS, views_doc.document_references, name="doc_references"),
|
||||
url(r'^%(name)s/referencedby/$' % settings.URL_REGEXPS, views_doc.document_referenced_by, name="doc_referenced_by"),
|
||||
url(r'^%(name)s/ballot/(?P<ballot_id>[0-9]+)/position/$' % settings.URL_REGEXPS, views_ballot.edit_position),
|
||||
url(r'^%(name)s/ballot/(?P<ballot_id>[0-9]+)/emailposition/$' % settings.URL_REGEXPS, views_ballot.send_ballot_comment, name='doc_send_ballot_comment'),
|
||||
url(r'^%(name)s/ballot/(?P<ballot_id>[0-9]+)/$' % settings.URL_REGEXPS, views_doc.document_ballot, name="doc_ballot"),
|
||||
url(r'^%(name)s/ballot/$' % settings.URL_REGEXPS, views_doc.document_ballot, name="doc_ballot"),
|
||||
(r'^%(name)s/doc.json$' % settings.URL_REGEXPS, views_doc.document_json),
|
||||
(r'^%(name)s/ballotpopup/(?P<ballot_id>[0-9]+)/$' % settings.URL_REGEXPS, views_doc.ballot_popup),
|
||||
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/email-aliases/$', RedirectView.as_view(pattern_name='doc_email', permanent=False),name='doc_specific_email_aliases'),
|
||||
url(r'^%(name)s/email-aliases/$' % settings.URL_REGEXPS, RedirectView.as_view(pattern_name='doc_email', permanent=False),name='doc_specific_email_aliases'),
|
||||
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/$', views_draft.change_state, name='doc_change_state'), # IESG state
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/(?P<state_type>iana-action|iana-review)/$', views_draft.change_iana_state, name='doc_change_iana_state'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/info/$', views_draft.edit_info, name='doc_edit_info'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/requestresurrect/$', views_draft.request_resurrect, name='doc_request_resurrect'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/submit-to-iesg/$', views_draft.to_iesg, name='doc_to_iesg'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/resurrect/$', views_draft.resurrect, name='doc_resurrect'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/addcomment/$', views_doc.add_comment, name='doc_add_comment'),
|
||||
url(r'^%(name)s/edit/state/$' % settings.URL_REGEXPS, views_draft.change_state, name='doc_change_state'), # IESG state
|
||||
url(r'^%(name)s/edit/state/(?P<state_type>iana-action|iana-review)/$' % settings.URL_REGEXPS, views_draft.change_iana_state, name='doc_change_iana_state'),
|
||||
url(r'^%(name)s/edit/info/$' % settings.URL_REGEXPS, views_draft.edit_info, name='doc_edit_info'),
|
||||
url(r'^%(name)s/edit/requestresurrect/$' % settings.URL_REGEXPS, views_draft.request_resurrect, name='doc_request_resurrect'),
|
||||
url(r'^%(name)s/edit/submit-to-iesg/$' % settings.URL_REGEXPS, views_draft.to_iesg, name='doc_to_iesg'),
|
||||
url(r'^%(name)s/edit/resurrect/$' % settings.URL_REGEXPS, views_draft.resurrect, name='doc_resurrect'),
|
||||
url(r'^%(name)s/edit/addcomment/$' % settings.URL_REGEXPS, views_doc.add_comment, name='doc_add_comment'),
|
||||
url(r'^ajax/internet_draft/?$', views_draft.doc_ajax_internet_draft, name="doc_ajax_internet_draft"),
|
||||
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/stream/$', views_draft.change_stream, name='doc_change_stream'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/replaces/$', views_draft.replaces, name='doc_change_replaces'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/notify/$', views_doc.edit_notify, name='doc_change_notify'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/suggested-replaces/$', views_draft.review_possibly_replaces, name='doc_review_possibly_replaces'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/status/$', views_draft.change_intention, name='doc_change_intended_status'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/telechat/$', views_doc.telechat_date, name='doc_change_telechat_date'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/iesgnote/$', views_draft.edit_iesg_note, name='doc_change_iesg_note'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/ad/$', views_draft.edit_ad, name='doc_change_ad'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/consensus/$', views_draft.edit_consensus, name='doc_edit_consensus'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/shepherd/$', views_draft.edit_shepherd, name='doc_edit_shepherd'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/shepherdemail/$', views_draft.change_shepherd_email, name='doc_change_shepherd_email'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/shepherdwriteup/$', views_draft.edit_shepherd_writeup, name='doc_edit_shepherd_writeup'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/requestpublication/$', views_draft.request_publication, name='doc_request_publication'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/adopt/$', views_draft.adopt_draft, name='doc_adopt_draft'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/(?P<state_type>draft-stream-[a-z]+)/$', views_draft.change_stream_state, name='doc_change_stream_state'),
|
||||
url(r'^%(name)s/edit/stream/$' % settings.URL_REGEXPS, views_draft.change_stream, name='doc_change_stream'),
|
||||
url(r'^%(name)s/edit/replaces/$' % settings.URL_REGEXPS, views_draft.replaces, name='doc_change_replaces'),
|
||||
url(r'^%(name)s/edit/notify/$' % settings.URL_REGEXPS, views_doc.edit_notify, name='doc_change_notify'),
|
||||
url(r'^%(name)s/edit/suggested-replaces/$' % settings.URL_REGEXPS, views_draft.review_possibly_replaces, name='doc_review_possibly_replaces'),
|
||||
url(r'^%(name)s/edit/status/$' % settings.URL_REGEXPS, views_draft.change_intention, name='doc_change_intended_status'),
|
||||
url(r'^%(name)s/edit/telechat/$' % settings.URL_REGEXPS, views_doc.telechat_date, name='doc_change_telechat_date'),
|
||||
url(r'^%(name)s/edit/iesgnote/$' % settings.URL_REGEXPS, views_draft.edit_iesg_note, name='doc_change_iesg_note'),
|
||||
url(r'^%(name)s/edit/ad/$' % settings.URL_REGEXPS, views_draft.edit_ad, name='doc_change_ad'),
|
||||
url(r'^%(name)s/edit/consensus/$' % settings.URL_REGEXPS, views_draft.edit_consensus, name='doc_edit_consensus'),
|
||||
url(r'^%(name)s/edit/shepherd/$' % settings.URL_REGEXPS, views_draft.edit_shepherd, name='doc_edit_shepherd'),
|
||||
url(r'^%(name)s/edit/shepherdemail/$' % settings.URL_REGEXPS, views_draft.change_shepherd_email, name='doc_change_shepherd_email'),
|
||||
url(r'^%(name)s/edit/shepherdwriteup/$' % settings.URL_REGEXPS, views_draft.edit_shepherd_writeup, name='doc_edit_shepherd_writeup'),
|
||||
url(r'^%(name)s/edit/requestpublication/$' % settings.URL_REGEXPS, views_draft.request_publication, name='doc_request_publication'),
|
||||
url(r'^%(name)s/edit/adopt/$' % settings.URL_REGEXPS, views_draft.adopt_draft, name='doc_adopt_draft'),
|
||||
url(r'^%(name)s/edit/state/(?P<state_type>draft-stream-[a-z]+)/$' % settings.URL_REGEXPS, views_draft.change_stream_state, name='doc_change_stream_state'),
|
||||
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/clearballot/$', views_ballot.clear_ballot, name='doc_clear_ballot'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/deferballot/$', views_ballot.defer_ballot, name='doc_defer_ballot'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/undeferballot/$', views_ballot.undefer_ballot, name='doc_undefer_ballot'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/lastcalltext/$', views_ballot.lastcalltext, name='doc_ballot_lastcall'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/ballotwriteupnotes/$', views_ballot.ballot_writeupnotes, name='doc_ballot_writeupnotes'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/approvaltext/$', views_ballot.ballot_approvaltext, name='doc_ballot_approvaltext'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/approveballot/$', views_ballot.approve_ballot, name='doc_approve_ballot'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/makelastcall/$', views_ballot.make_last_call, name='doc_make_last_call'),
|
||||
url(r'^%(name)s/edit/clearballot/$' % settings.URL_REGEXPS, views_ballot.clear_ballot, name='doc_clear_ballot'),
|
||||
url(r'^%(name)s/edit/deferballot/$' % settings.URL_REGEXPS, views_ballot.defer_ballot, name='doc_defer_ballot'),
|
||||
url(r'^%(name)s/edit/undeferballot/$' % settings.URL_REGEXPS, views_ballot.undefer_ballot, name='doc_undefer_ballot'),
|
||||
url(r'^%(name)s/edit/lastcalltext/$' % settings.URL_REGEXPS, views_ballot.lastcalltext, name='doc_ballot_lastcall'),
|
||||
url(r'^%(name)s/edit/ballotwriteupnotes/$' % settings.URL_REGEXPS, views_ballot.ballot_writeupnotes, name='doc_ballot_writeupnotes'),
|
||||
url(r'^%(name)s/edit/approvaltext/$' % settings.URL_REGEXPS, views_ballot.ballot_approvaltext, name='doc_ballot_approvaltext'),
|
||||
url(r'^%(name)s/edit/approveballot/$' % settings.URL_REGEXPS, views_ballot.approve_ballot, name='doc_approve_ballot'),
|
||||
url(r'^%(name)s/edit/makelastcall/$' % settings.URL_REGEXPS, views_ballot.make_last_call, name='doc_make_last_call'),
|
||||
|
||||
url(r'^help/state/(?P<type>[\w-]+)/$', 'ietf.doc.views_help.state_help', name="state_help"),
|
||||
url(r'^help/relationships/$', 'ietf.doc.views_help.relationship_help', name="relationship_help"),
|
||||
url(r'^help/relationships/(?P<subset>\w+)/$', 'ietf.doc.views_help.relationship_help', name="relationship_subset_help"),
|
||||
|
||||
(r'^(?P<name>charter-[A-Za-z0-9._+-]+)/', include('ietf.doc.urls_charter')),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/conflict-review/', include('ietf.doc.urls_conflict_review')),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/status-change/', include('ietf.doc.urls_status_change')),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/material/', include('ietf.doc.urls_material')),
|
||||
(r'^%(name)s/conflict-review/' % settings.URL_REGEXPS, include('ietf.doc.urls_conflict_review')),
|
||||
(r'^%(name)s/status-change/' % settings.URL_REGEXPS, include('ietf.doc.urls_status_change')),
|
||||
(r'^%(name)s/material/' % settings.URL_REGEXPS, include('ietf.doc.urls_material')),
|
||||
)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Copyright The IETF Trust 2011, All Rights Reserved
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
from django.conf import settings
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^state/$', "ietf.doc.views_charter.change_state", name='charter_change_state'),
|
||||
|
@ -14,5 +15,5 @@ urlpatterns = patterns('',
|
|||
url(r'^ballotwriteupnotes/$', "ietf.doc.views_charter.ballot_writeupnotes"),
|
||||
url(r'^approve/$', "ietf.doc.views_charter.approve", name='charter_approve'),
|
||||
url(r'^submit/(?:(?P<option>initcharter|recharter)/)?$', "ietf.doc.views_charter.submit", name='charter_submit'),
|
||||
url(r'^withmilestones-(?P<rev>[0-9-]+).txt$', "ietf.doc.views_charter.charter_with_milestones_txt", name='charter_with_milestones_txt'),
|
||||
url(r'^withmilestones-%(rev)s.txt$' % settings.URL_REGEXPS, "ietf.doc.views_charter.charter_with_milestones_txt", name='charter_with_milestones_txt'),
|
||||
)
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
from django.conf.urls import patterns, url
|
||||
from django.conf import settings
|
||||
|
||||
urlpatterns = patterns('ietf.doc.views_material',
|
||||
url(r'^(?P<action>state|title|abstract|revise)/$', "edit_material", name="material_edit"),
|
||||
url(r'^sessions/$', "material_presentations", name="material_presentations"),
|
||||
(r'^sessions/(?P<seq>\d+)/edit/$', "edit_material_presentations"),
|
||||
(r'^sessions/(?P<acronym>[A-Za-z0-9_\-\+]+)/edit/$', "edit_material_presentations"),
|
||||
(r'^sessions/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<seq>\d+)/edit/$', "edit_material_presentations"),
|
||||
(r'^sessions/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<week_day>[a-zA-Z]+)/edit/$', "edit_material_presentations"),
|
||||
(r'^sessions/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<week_day>[a-zA-Z]+)/(?P<seq>\d+)/edit/$', "edit_material_presentations"),
|
||||
(r'^sessions/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/edit/$', "edit_material_presentations"),
|
||||
(r'^sessions/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/(?P<seq>\d+)/edit/$', "edit_material_presentations"),
|
||||
(r'^sessions/%(acronym)s/edit/$' % settings.URL_REGEXPS, "edit_material_presentations"),
|
||||
(r'^sessions/%(acronym)s/(?P<seq>\d+)/edit/$' % settings.URL_REGEXPS, "edit_material_presentations"),
|
||||
(r'^sessions/%(acronym)s/(?P<week_day>[a-zA-Z]+)/edit/$' % settings.URL_REGEXPS, "edit_material_presentations"),
|
||||
(r'^sessions/%(acronym)s/(?P<week_day>[a-zA-Z]+)/(?P<seq>\d+)/edit/$' % settings.URL_REGEXPS, "edit_material_presentations"),
|
||||
(r'^sessions/%(acronym)s/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/edit/$' % settings.URL_REGEXPS, "edit_material_presentations"),
|
||||
(r'^sessions/%(acronym)s/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/(?P<seq>\d+)/edit/$' % settings.URL_REGEXPS, "edit_material_presentations"),
|
||||
(r'^sessions/(?P<seq>\d+)/$', "material_presentations"),
|
||||
(r'^sessions/(?P<acronym>[A-Za-z0-9_\-\+]+)/$', "material_presentations"),
|
||||
(r'^sessions/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<seq>\d+)/$', "material_presentations"),
|
||||
(r'^sessions/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<week_day>[a-zA-Z]+)/$', "material_presentations"),
|
||||
(r'^sessions/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<week_day>[a-zA-Z]+)/(?P<seq>\d+)/$', "material_presentations"),
|
||||
(r'^sessions/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/$', "material_presentations"),
|
||||
(r'^sessions/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/(?P<seq>\d+)/$', "material_presentations"),
|
||||
(r'^sessions/%(acronym)s/$' % settings.URL_REGEXPS, "material_presentations"),
|
||||
(r'^sessions/%(acronym)s/(?P<seq>\d+)/$' % settings.URL_REGEXPS, "material_presentations"),
|
||||
(r'^sessions/%(acronym)s/(?P<week_day>[a-zA-Z]+)/$' % settings.URL_REGEXPS, "material_presentations"),
|
||||
(r'^sessions/%(acronym)s/(?P<week_day>[a-zA-Z]+)/(?P<seq>\d+)/$' % settings.URL_REGEXPS, "material_presentations"),
|
||||
(r'^sessions/%(acronym)s/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/$' % settings.URL_REGEXPS, "material_presentations"),
|
||||
(r'^sessions/%(acronym)s/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/(?P<seq>\d+)/$' % settings.URL_REGEXPS, "material_presentations"),
|
||||
)
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@ import datetime
|
|||
from django.conf import settings
|
||||
from django.db.models.query import EmptyQuerySet
|
||||
from django.forms import ValidationError
|
||||
from django.utils.html import strip_tags, escape
|
||||
from django.utils.html import escape
|
||||
|
||||
from ietf.doc.models import Document, DocHistory, State
|
||||
from ietf.doc.models import DocAlias, RelatedDocument, BallotType, DocReminder
|
||||
from ietf.doc.models import Document, DocHistory, State, DocumentAuthor, DocHistoryAuthor
|
||||
from ietf.doc.models import DocAlias, RelatedDocument, RelatedDocHistory, BallotType, DocReminder
|
||||
from ietf.doc.models import DocEvent, BallotDocEvent, NewRevisionDocEvent, StateDocEvent
|
||||
from ietf.doc.models import save_document_in_history
|
||||
from ietf.doc.models import TelechatDocEvent
|
||||
from ietf.name.models import DocReminderTypeName, DocRelationshipName
|
||||
from ietf.group.models import Role
|
||||
from ietf.ietfauth.utils import has_role
|
||||
|
@ -20,21 +20,43 @@ from ietf.utils import draft, markup_txt
|
|||
from ietf.utils.mail import send_mail
|
||||
from ietf.mailtrigger.utils import gather_address_lists
|
||||
|
||||
#TODO FIXME - it would be better if this lived in ietf/doc/mails.py, but there's
|
||||
# an import order issue to work out.
|
||||
def email_update_telechat(request, doc, text):
|
||||
(to, cc) = gather_address_lists('doc_telechat_details_changed',doc=doc)
|
||||
def save_document_in_history(doc):
|
||||
"""Save a snapshot of document and related objects in the database."""
|
||||
def get_model_fields_as_dict(obj):
|
||||
return dict((field.name, getattr(obj, field.name))
|
||||
for field in obj._meta.fields
|
||||
if field is not obj._meta.pk)
|
||||
|
||||
if not to:
|
||||
return
|
||||
# copy fields
|
||||
fields = get_model_fields_as_dict(doc)
|
||||
fields["doc"] = doc
|
||||
fields["name"] = doc.canonical_name()
|
||||
|
||||
text = strip_tags(text)
|
||||
send_mail(request, to, None,
|
||||
"Telechat update notice: %s" % doc.file_tag(),
|
||||
"doc/mail/update_telechat.txt",
|
||||
dict(text=text,
|
||||
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
|
||||
cc=cc)
|
||||
dochist = DocHistory(**fields)
|
||||
dochist.save()
|
||||
|
||||
# copy many to many
|
||||
for field in doc._meta.many_to_many:
|
||||
if field.rel.through and field.rel.through._meta.auto_created:
|
||||
setattr(dochist, field.name, getattr(doc, field.name).all())
|
||||
|
||||
# copy remaining tricky many to many
|
||||
def transfer_fields(obj, HistModel):
|
||||
mfields = get_model_fields_as_dict(item)
|
||||
# map doc -> dochist
|
||||
for k, v in mfields.iteritems():
|
||||
if v == doc:
|
||||
mfields[k] = dochist
|
||||
HistModel.objects.create(**mfields)
|
||||
|
||||
for item in RelatedDocument.objects.filter(source=doc):
|
||||
transfer_fields(item, RelatedDocHistory)
|
||||
|
||||
for item in DocumentAuthor.objects.filter(document=doc):
|
||||
transfer_fields(item, DocHistoryAuthor)
|
||||
|
||||
return dochist
|
||||
|
||||
|
||||
def get_state_types(doc):
|
||||
res = []
|
||||
|
@ -343,7 +365,6 @@ def make_notify_changed_event(request, doc, by, new_notify, time=None):
|
|||
# events to match
|
||||
if doc.type.slug=='charter':
|
||||
event_type = 'changed_document'
|
||||
save_document_in_history(doc)
|
||||
else:
|
||||
event_type = 'added_comment'
|
||||
|
||||
|
@ -358,8 +379,6 @@ def make_notify_changed_event(request, doc, by, new_notify, time=None):
|
|||
return e
|
||||
|
||||
def update_telechat(request, doc, by, new_telechat_date, new_returning_item=None):
|
||||
from ietf.doc.models import TelechatDocEvent
|
||||
|
||||
on_agenda = bool(new_telechat_date)
|
||||
|
||||
prev = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||
|
@ -410,8 +429,12 @@ def update_telechat(request, doc, by, new_telechat_date, new_returning_item=None
|
|||
e.desc = "Removed telechat returning item indication"
|
||||
|
||||
e.save()
|
||||
|
||||
from ietf.doc.mails import email_update_telechat
|
||||
email_update_telechat(request, doc, e.desc)
|
||||
|
||||
return e
|
||||
|
||||
def rebuild_reference_relations(doc,filename=None):
|
||||
if doc.type.slug != 'draft':
|
||||
return None
|
||||
|
@ -457,7 +480,7 @@ def rebuild_reference_relations(doc,filename=None):
|
|||
|
||||
return ret
|
||||
|
||||
def set_replaces_for_document(request, doc, new_replaces, by, email_subject, email_comment=""):
|
||||
def set_replaces_for_document(request, doc, new_replaces, by, email_subject, comment=""):
|
||||
addrs = gather_address_lists('doc_replacement_changed',doc=doc)
|
||||
to = set(addrs.to)
|
||||
cc = set(addrs.cc)
|
||||
|
@ -465,6 +488,19 @@ def set_replaces_for_document(request, doc, new_replaces, by, email_subject, ema
|
|||
relationship = DocRelationshipName.objects.get(slug='replaces')
|
||||
old_replaces = doc.related_that_doc("replaces")
|
||||
|
||||
events = []
|
||||
|
||||
e = DocEvent(doc=doc, by=by, type='changed_document')
|
||||
new_replaces_names = u", ".join(d.name for d in new_replaces) or u"None"
|
||||
old_replaces_names = u", ".join(d.name for d in old_replaces) or u"None"
|
||||
e.desc = u"This document now replaces <b>%s</b> instead of %s" % (new_replaces_names, old_replaces_names)
|
||||
e.save()
|
||||
|
||||
events.append(e)
|
||||
|
||||
if comment:
|
||||
events.append(DocEvent.objects.create(doc=doc, by=by, type="added_comment", desc=comment))
|
||||
|
||||
for d in old_replaces:
|
||||
if d not in new_replaces:
|
||||
other_addrs = gather_address_lists('doc_replacement_changed',doc=d.document)
|
||||
|
@ -483,19 +519,13 @@ def set_replaces_for_document(request, doc, new_replaces, by, email_subject, ema
|
|||
RelatedDocument.objects.create(source=doc, target=d, relationship=relationship)
|
||||
d.document.set_state(State.objects.get(type='draft', slug='repl'))
|
||||
|
||||
e = DocEvent(doc=doc, by=by, type='changed_document')
|
||||
new_replaces_names = u", ".join(d.name for d in new_replaces) or u"None"
|
||||
old_replaces_names = u", ".join(d.name for d in old_replaces) or u"None"
|
||||
e.desc = u"This document now replaces <b>%s</b> instead of %s" % (new_replaces_names, old_replaces_names)
|
||||
e.save()
|
||||
|
||||
# make sure there are no lingering suggestions duplicating new replacements
|
||||
RelatedDocument.objects.filter(source=doc, target__in=new_replaces, relationship="possibly-replaces").delete()
|
||||
|
||||
email_desc = e.desc.replace(", ", "\n ")
|
||||
|
||||
if email_comment:
|
||||
email_desc += "\n" + email_comment
|
||||
if comment:
|
||||
email_desc += "\n" + comment
|
||||
|
||||
from ietf.doc.mails import html_to_text
|
||||
|
||||
|
@ -508,6 +538,8 @@ def set_replaces_for_document(request, doc, new_replaces, by, email_subject, ema
|
|||
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
|
||||
cc=list(cc))
|
||||
|
||||
return events
|
||||
|
||||
def check_common_doc_name_rules(name):
|
||||
"""Check common rules for document names for use in forms, throws
|
||||
ValidationError in case there's a problem."""
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
import re, datetime, os
|
||||
import re, datetime, os, shutil
|
||||
|
||||
from django.template.loader import render_to_string
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.doc.models import NewRevisionDocEvent, WriteupDocEvent
|
||||
from ietf.group.models import ChangeStateGroupEvent
|
||||
from ietf.name.models import GroupStateName
|
||||
from ietf.utils.history import find_history_active_at
|
||||
from ietf.utils.mail import parse_preformatted
|
||||
from ietf.mailtrigger.utils import gather_address_lists
|
||||
from ietf.utils.log import log
|
||||
from ietf.group.utils import save_group_in_history
|
||||
|
||||
def charter_name_for_group(group):
|
||||
if group.type_id == "rg":
|
||||
|
@ -16,6 +20,10 @@ def charter_name_for_group(group):
|
|||
|
||||
return "charter-%s-%s" % (top_org, group.acronym)
|
||||
|
||||
def split_charter_name(charter_name):
|
||||
top_org, group_acronym = charter_name.split("-", 2)[1:]
|
||||
return top_org, group_acronym
|
||||
|
||||
def next_revision(rev):
|
||||
if rev == "":
|
||||
return "00-00"
|
||||
|
@ -45,6 +53,45 @@ def read_charter_text(doc):
|
|||
except IOError:
|
||||
return "Error: couldn't read charter text"
|
||||
|
||||
def change_group_state_after_charter_approval(group, by):
|
||||
new_state = GroupStateName.objects.get(slug="active")
|
||||
if group.state == new_state:
|
||||
return None
|
||||
|
||||
save_group_in_history(group)
|
||||
group.state = new_state
|
||||
group.time = datetime.datetime.now()
|
||||
group.save()
|
||||
|
||||
# create an event for the group state change, too
|
||||
e = ChangeStateGroupEvent(group=group, type="changed_state")
|
||||
e.time = group.time
|
||||
e.by = by
|
||||
e.state_id = "active"
|
||||
e.desc = "Charter approved, group active"
|
||||
e.save()
|
||||
|
||||
return e
|
||||
|
||||
def fix_charter_revision_after_approval(charter, by):
|
||||
# according to spec, 00-02 becomes 01, so copy file and record new revision
|
||||
try:
|
||||
old = os.path.join(charter.get_file_path(), '%s-%s.txt' % (charter.canonical_name(), charter.rev))
|
||||
new = os.path.join(charter.get_file_path(), '%s-%s.txt' % (charter.canonical_name(), next_approved_revision(charter.rev)))
|
||||
shutil.copy(old, new)
|
||||
except IOError:
|
||||
log("There was an error copying %s to %s" % (old, new))
|
||||
|
||||
events = []
|
||||
e = NewRevisionDocEvent(doc=charter, by=by, type="new_revision")
|
||||
e.rev = next_approved_revision(charter.rev)
|
||||
e.desc = "New version available: <b>%s-%s.txt</b>" % (charter.canonical_name(), e.rev)
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
charter.rev = e.rev
|
||||
charter.save_with_history(events)
|
||||
|
||||
def historic_milestones_for_charter(charter, rev):
|
||||
"""Return GroupMilestone/GroupMilestoneHistory objects for charter
|
||||
document at rev by looking through the history."""
|
||||
|
@ -89,8 +136,8 @@ def generate_ballot_writeup(request, doc):
|
|||
e.doc = doc
|
||||
e.desc = u"Ballot writeup was generated"
|
||||
e.text = unicode(render_to_string("doc/charter/ballot_writeup.txt"))
|
||||
e.save()
|
||||
|
||||
|
||||
# caller is responsible for saving, if necessary
|
||||
return e
|
||||
|
||||
def default_action_text(group, charter, by):
|
||||
|
@ -117,7 +164,7 @@ def default_action_text(group, charter, by):
|
|||
cc=addrs.cc,
|
||||
))
|
||||
|
||||
e.save()
|
||||
# caller is responsible for saving, if necessary
|
||||
return e
|
||||
|
||||
def derive_new_work_text(review_text,group):
|
||||
|
@ -133,7 +180,7 @@ def derive_new_work_text(review_text,group):
|
|||
|
||||
def default_review_text(group, charter, by):
|
||||
now = datetime.datetime.now()
|
||||
addrs=gather_address_lists('charter_external_review',group=group).as_strings(compact=False)
|
||||
addrs = gather_address_lists('charter_external_review',group=group).as_strings(compact=False)
|
||||
|
||||
e1 = WriteupDocEvent(doc=charter, by=by)
|
||||
e1.by = by
|
||||
|
@ -154,17 +201,16 @@ def default_review_text(group, charter, by):
|
|||
)
|
||||
)
|
||||
e1.time = now
|
||||
e1.save()
|
||||
|
||||
|
||||
e2 = WriteupDocEvent(doc=charter, by=by)
|
||||
e2.by = by
|
||||
e2.type = "changed_new_work_text"
|
||||
e2.desc = "%s review text was changed" % group.type.name
|
||||
e2.text = derive_new_work_text(e1.text,group)
|
||||
e2.time = now
|
||||
e2.save()
|
||||
|
||||
return (e1,e2)
|
||||
# caller is responsible for saving, if necessary
|
||||
return (e1, e2)
|
||||
|
||||
def generate_issue_ballot_mail(request, doc, ballot):
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
import datetime, json
|
||||
|
||||
from django.http import HttpResponseForbidden, HttpResponseRedirect, Http404
|
||||
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
||||
from django.shortcuts import render, render_to_response, get_object_or_404, redirect
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.template.loader import render_to_string
|
||||
from django.template import RequestContext
|
||||
|
@ -14,7 +14,7 @@ from django.conf import settings
|
|||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.models import ( Document, State, DocEvent, BallotDocEvent, BallotPositionDocEvent,
|
||||
BallotType, LastCallDocEvent, WriteupDocEvent, save_document_in_history, IESG_SUBSTATE_TAGS )
|
||||
BallotType, LastCallDocEvent, WriteupDocEvent, IESG_SUBSTATE_TAGS )
|
||||
from ietf.doc.utils import ( add_state_change_event, close_ballot, close_open_ballots,
|
||||
create_ballot_if_not_open, update_telechat )
|
||||
from ietf.doc.mails import ( email_ballot_deferred, email_ballot_undeferred,
|
||||
|
@ -46,12 +46,12 @@ def do_undefer_ballot(request, doc):
|
|||
Helper function to perform undefer of ballot. Takes the Request object, for use in
|
||||
logging, and the Document object.
|
||||
'''
|
||||
login = request.user.person
|
||||
by = request.user.person
|
||||
telechat_date = TelechatDate.objects.active().order_by("date")[0].date
|
||||
save_document_in_history(doc)
|
||||
|
||||
new_state = doc.get_state()
|
||||
prev_tags = new_tags = []
|
||||
prev_tags = []
|
||||
new_tags = []
|
||||
|
||||
if doc.type_id == 'draft':
|
||||
new_state = State.objects.get(used=True, type="draft-iesg", slug='iesg-eva')
|
||||
|
@ -64,14 +64,20 @@ def do_undefer_ballot(request, doc):
|
|||
doc.set_state(new_state)
|
||||
doc.tags.remove(*prev_tags)
|
||||
|
||||
e = add_state_change_event(doc, login, prev_state, new_state, prev_tags=prev_tags, new_tags=new_tags)
|
||||
|
||||
doc.time = (e and e.time) or datetime.datetime.now()
|
||||
doc.save()
|
||||
events = []
|
||||
state_change_event = add_state_change_event(doc, by, prev_state, new_state, prev_tags=prev_tags, new_tags=new_tags)
|
||||
if state_change_event:
|
||||
events.append(state_change_event)
|
||||
|
||||
e = update_telechat(request, doc, by, telechat_date)
|
||||
if e:
|
||||
events.append(e)
|
||||
|
||||
if events:
|
||||
doc.save_with_history(events)
|
||||
|
||||
email_ballot_undeferred(request, doc, by.plain_name(), telechat_date)
|
||||
|
||||
update_telechat(request, doc, login, telechat_date)
|
||||
email_ballot_undeferred(request, doc, login.plain_name(), telechat_date)
|
||||
|
||||
def position_to_ballot_choice(position):
|
||||
for v, label in BALLOT_CHOICES:
|
||||
if v and getattr(position, v):
|
||||
|
@ -350,10 +356,9 @@ def defer_ballot(request, name):
|
|||
telechat_date = TelechatDate.objects.active().order_by("date")[1].date
|
||||
|
||||
if request.method == 'POST':
|
||||
save_document_in_history(doc)
|
||||
|
||||
new_state = doc.get_state()
|
||||
prev_tags = new_tags = []
|
||||
prev_tags = []
|
||||
new_tags = []
|
||||
|
||||
if doc.type_id == 'draft':
|
||||
new_state = State.objects.get(used=True, type="draft-iesg", slug='defer')
|
||||
|
@ -366,12 +371,18 @@ def defer_ballot(request, name):
|
|||
doc.set_state(new_state)
|
||||
doc.tags.remove(*prev_tags)
|
||||
|
||||
e = add_state_change_event(doc, login, prev_state, new_state, prev_tags=prev_tags, new_tags=new_tags)
|
||||
|
||||
doc.time = (e and e.time) or datetime.datetime.now()
|
||||
doc.save()
|
||||
events = []
|
||||
|
||||
state_change_event = add_state_change_event(doc, login, prev_state, new_state, prev_tags=prev_tags, new_tags=new_tags)
|
||||
if state_change_event:
|
||||
events.append(state_change_event)
|
||||
|
||||
e = update_telechat(request, doc, login, telechat_date)
|
||||
if e:
|
||||
events.append(e)
|
||||
|
||||
doc.save_with_history(events)
|
||||
|
||||
update_telechat(request, doc, login, telechat_date)
|
||||
email_ballot_deferred(request, doc, login.plain_name(), telechat_date)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
|
@ -446,10 +457,10 @@ def lastcalltext(request, name):
|
|||
e.desc = "Last call announcement was changed"
|
||||
e.text = t
|
||||
e.save()
|
||||
elif existing.pk == None:
|
||||
existing.save()
|
||||
|
||||
if "send_last_call_request" in request.POST:
|
||||
save_document_in_history(doc)
|
||||
|
||||
prev_state = doc.get_state("draft-iesg")
|
||||
new_state = State.objects.get(used=True, type="draft-iesg", slug='lc-req')
|
||||
|
||||
|
@ -460,8 +471,8 @@ def lastcalltext(request, name):
|
|||
|
||||
e = add_state_change_event(doc, login, prev_state, new_state, prev_tags=prev_tags, new_tags=[])
|
||||
|
||||
doc.time = (e and e.time) or datetime.datetime.now()
|
||||
doc.save()
|
||||
if e:
|
||||
doc.save_with_history([e])
|
||||
|
||||
request_last_call(request, doc)
|
||||
|
||||
|
@ -471,7 +482,8 @@ def lastcalltext(request, name):
|
|||
|
||||
if "regenerate_last_call_text" in request.POST:
|
||||
e = generate_last_call_announcement(request, doc)
|
||||
|
||||
e.save()
|
||||
|
||||
# make sure form has the updated text
|
||||
form = LastCallTextForm(initial=dict(last_call_text=e.text))
|
||||
|
||||
|
@ -524,6 +536,8 @@ def ballot_writeupnotes(request, name):
|
|||
e.desc = "Ballot writeup was changed"
|
||||
e.text = t
|
||||
e.save()
|
||||
elif existing.pk == None:
|
||||
existing.save()
|
||||
|
||||
if "issue_ballot" in request.POST:
|
||||
create_ballot_if_not_open(doc, login, "approve")
|
||||
|
@ -544,6 +558,7 @@ def ballot_writeupnotes(request, name):
|
|||
approval = doc.latest_event(WriteupDocEvent, type="changed_ballot_approval_text")
|
||||
if not approval:
|
||||
approval = generate_approval_mail(request, doc)
|
||||
approval.save()
|
||||
|
||||
msg = generate_issue_ballot_mail(request, doc, ballot)
|
||||
|
||||
|
@ -618,9 +633,12 @@ def ballot_approvaltext(request, name):
|
|||
e.desc = "Ballot approval text was changed"
|
||||
e.text = t
|
||||
e.save()
|
||||
elif existing.pk == None:
|
||||
existing.save()
|
||||
|
||||
if "regenerate_approval_text" in request.POST:
|
||||
e = generate_approval_mail(request, doc)
|
||||
e.save()
|
||||
|
||||
# make sure form has the updated text
|
||||
form = ApprovalTextForm(initial=dict(approval_text=e.text))
|
||||
|
@ -648,15 +666,15 @@ def approve_ballot(request, name):
|
|||
|
||||
login = request.user.person
|
||||
|
||||
e = doc.latest_event(WriteupDocEvent, type="changed_ballot_approval_text")
|
||||
if not e:
|
||||
e = generate_approval_mail(request, doc)
|
||||
approval_text = e.text
|
||||
approval_mail_event = doc.latest_event(WriteupDocEvent, type="changed_ballot_approval_text")
|
||||
if not approval_mail_event:
|
||||
approval_mail_event = generate_approval_mail(request, doc)
|
||||
approval_text = approval_mail_event.text
|
||||
|
||||
e = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text")
|
||||
if not e:
|
||||
e = generate_ballot_writeup(request, doc)
|
||||
ballot_writeup = e.text
|
||||
ballot_writeup_event = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text")
|
||||
if not ballot_writeup_event:
|
||||
ballot_writeup_event = generate_ballot_writeup(request, doc)
|
||||
ballot_writeup = ballot_writeup_event.text
|
||||
|
||||
if "NOT be published" in approval_text:
|
||||
action = "do_not_publish"
|
||||
|
@ -679,19 +697,22 @@ def approve_ballot(request, name):
|
|||
|
||||
prev_state = doc.get_state("draft-iesg")
|
||||
prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
events = []
|
||||
|
||||
if approval_mail_event.pk == None:
|
||||
approval_mail_event.save()
|
||||
if ballot_writeup_event.pk == None:
|
||||
ballot_writeup_event.save()
|
||||
|
||||
if new_state.slug == "ann" and new_state.slug != prev_state.slug and not request.REQUEST.get("skiprfceditorpost"):
|
||||
# start by notifying the RFC Editor
|
||||
import ietf.sync.rfceditor
|
||||
response, error = ietf.sync.rfceditor.post_approved_draft(settings.RFC_EDITOR_SYNC_NOTIFICATION_URL, doc.name)
|
||||
if error:
|
||||
return render_to_response('doc/draft/rfceditor_post_approved_draft_failed.html',
|
||||
dict(name=doc.name,
|
||||
response=response,
|
||||
error=error),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
save_document_in_history(doc)
|
||||
return render(request, 'doc/draft/rfceditor_post_approved_draft_failed.html',
|
||||
dict(name=doc.name,
|
||||
response=response,
|
||||
error=error))
|
||||
|
||||
doc.set_state(new_state)
|
||||
doc.tags.remove(*prev_tags)
|
||||
|
@ -706,16 +727,17 @@ def approve_ballot(request, name):
|
|||
else:
|
||||
e.type = "iesg_approved"
|
||||
e.desc = "IESG has approved the document"
|
||||
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
e = add_state_change_event(doc, login, prev_state, new_state, prev_tags=prev_tags, new_tags=[])
|
||||
|
||||
doc.time = (e and e.time) or datetime.datetime.now()
|
||||
doc.save()
|
||||
if e:
|
||||
events.append(e)
|
||||
|
||||
doc.save_with_history(events)
|
||||
|
||||
# send announcement
|
||||
|
||||
send_mail_preformatted(request, announcement)
|
||||
|
||||
if action == "to_announcement_list":
|
||||
|
@ -750,16 +772,19 @@ def make_last_call(request, name):
|
|||
|
||||
login = request.user.person
|
||||
|
||||
e = doc.latest_event(WriteupDocEvent, type="changed_last_call_text")
|
||||
if not e:
|
||||
if doc.type.slug != 'draft':
|
||||
announcement_event = doc.latest_event(WriteupDocEvent, type="changed_last_call_text")
|
||||
if not announcement_event:
|
||||
if doc.type_id != 'draft':
|
||||
raise Http404
|
||||
e = generate_last_call_announcement(request, doc)
|
||||
announcement = e.text
|
||||
announcement_event = generate_last_call_announcement(request, doc)
|
||||
announcement = announcement_event.text
|
||||
|
||||
if request.method == 'POST':
|
||||
form = MakeLastCallForm(request.POST)
|
||||
if form.is_valid():
|
||||
if announcement_event.pk == None:
|
||||
announcement_event.save()
|
||||
|
||||
send_mail_preformatted(request, announcement)
|
||||
if doc.type.slug == 'draft':
|
||||
addrs = gather_address_lists('last_call_issued_iana',doc=doc).as_strings(compact=False)
|
||||
|
@ -771,10 +796,10 @@ def make_last_call(request, name):
|
|||
msg.save()
|
||||
msg.related_docs.add(doc)
|
||||
|
||||
save_document_in_history(doc)
|
||||
|
||||
new_state = doc.get_state()
|
||||
prev_tags = new_tags = []
|
||||
prev_tags = []
|
||||
new_tags = []
|
||||
events = []
|
||||
|
||||
if doc.type.slug == 'draft':
|
||||
new_state = State.objects.get(used=True, type="draft-iesg", slug='lc')
|
||||
|
@ -788,10 +813,8 @@ def make_last_call(request, name):
|
|||
doc.tags.remove(*prev_tags)
|
||||
|
||||
e = add_state_change_event(doc, login, prev_state, new_state, prev_tags=prev_tags, new_tags=new_tags)
|
||||
|
||||
doc.time = (e and e.time) or datetime.datetime.now()
|
||||
doc.save()
|
||||
|
||||
if e:
|
||||
events.append(e)
|
||||
e = LastCallDocEvent(doc=doc, by=login)
|
||||
e.type = "sent_last_call"
|
||||
e.desc = "The following Last Call announcement was sent out:<br><br>"
|
||||
|
@ -801,6 +824,7 @@ def make_last_call(request, name):
|
|||
e.time = datetime.datetime.combine(form.cleaned_data['last_call_sent_date'], e.time.time())
|
||||
e.expires = form.cleaned_data['last_call_expiration_date']
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
# update IANA Review state
|
||||
if doc.type.slug == 'draft':
|
||||
|
@ -808,7 +832,11 @@ def make_last_call(request, name):
|
|||
if not prev_state:
|
||||
next_state = State.objects.get(used=True, type="draft-iana-review", slug="need-rev")
|
||||
doc.set_state(next_state)
|
||||
add_state_change_event(doc, login, prev_state, next_state)
|
||||
e = add_state_change_event(doc, login, prev_state, next_state)
|
||||
if e:
|
||||
events.append(e)
|
||||
|
||||
doc.save_with_history(events)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
else:
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import os, datetime, shutil, textwrap, json
|
||||
import os, datetime, textwrap, json
|
||||
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound, HttpResponseForbidden, Http404
|
||||
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
||||
from django.http import HttpResponseRedirect, HttpResponseNotFound, HttpResponseForbidden, Http404
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.template import RequestContext
|
||||
from django import forms
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.conf import settings
|
||||
|
@ -12,17 +11,19 @@ from django.contrib.auth.decorators import login_required
|
|||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.models import ( Document, DocHistory, State, DocEvent, BallotDocEvent,
|
||||
BallotPositionDocEvent, InitialReviewDocEvent, NewRevisionDocEvent,
|
||||
WriteupDocEvent, save_document_in_history )
|
||||
from ietf.doc.models import ( Document, DocAlias, DocHistory, State, DocEvent,
|
||||
BallotDocEvent, BallotPositionDocEvent, InitialReviewDocEvent, NewRevisionDocEvent,
|
||||
WriteupDocEvent )
|
||||
from ietf.doc.utils import ( add_state_change_event, close_open_ballots,
|
||||
create_ballot_if_not_open, get_chartering_type )
|
||||
from ietf.doc.utils_charter import ( historic_milestones_for_charter,
|
||||
approved_revision, default_review_text, default_action_text,
|
||||
generate_ballot_writeup, generate_issue_ballot_mail, next_approved_revision, next_revision,
|
||||
derive_new_work_text )
|
||||
generate_ballot_writeup, generate_issue_ballot_mail, next_revision,
|
||||
derive_new_work_text,
|
||||
change_group_state_after_charter_approval, fix_charter_revision_after_approval,
|
||||
split_charter_name)
|
||||
from ietf.doc.mails import email_state_changed, email_charter_internal_review
|
||||
from ietf.group.models import ChangeStateGroupEvent, MilestoneGroupEvent
|
||||
from ietf.group.models import Group, ChangeStateGroupEvent, MilestoneGroupEvent
|
||||
from ietf.group.utils import save_group_in_history, save_milestone_in_history, can_manage_group_type
|
||||
from ietf.ietfauth.utils import has_role, role_required
|
||||
from ietf.name.models import GroupStateName
|
||||
|
@ -67,7 +68,7 @@ def change_state(request, name, option=None):
|
|||
if charter.get_state_slug() != "infrev" or (initial_review and initial_review.expires < datetime.datetime.now()) or chartering_type == "rechartering":
|
||||
initial_review = None
|
||||
|
||||
login = request.user.person
|
||||
by = request.user.person
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ChangeStateForm(request.POST, group=group)
|
||||
|
@ -99,7 +100,7 @@ def change_state(request, name, option=None):
|
|||
group.save()
|
||||
e = ChangeStateGroupEvent(group=group, type="changed_state")
|
||||
e.time = group.time
|
||||
e.by = login
|
||||
e.by = by
|
||||
e.state_id = group.state.slug
|
||||
e.desc = "Group state changed to %s from %s" % (group.state, oldstate)
|
||||
e.save()
|
||||
|
@ -114,32 +115,30 @@ def change_state(request, name, option=None):
|
|||
message = clean['message']
|
||||
|
||||
if charter_state != charter.get_state():
|
||||
# Charter state changed
|
||||
save_document_in_history(charter)
|
||||
|
||||
events = []
|
||||
prev_state = charter.get_state()
|
||||
new_state = charter_state
|
||||
charter.set_state(new_state)
|
||||
charter.rev = charter_rev
|
||||
|
||||
if option != "abandon":
|
||||
add_state_change_event(charter, login, prev_state, new_state)
|
||||
e = add_state_change_event(charter, by, prev_state, new_state)
|
||||
if e:
|
||||
events.append(e)
|
||||
else:
|
||||
# kill hanging ballots
|
||||
close_open_ballots(charter, login)
|
||||
close_open_ballots(charter, by)
|
||||
|
||||
# Special log for abandoned efforts
|
||||
e = DocEvent(type="changed_document", doc=charter, by=login)
|
||||
e = DocEvent(type="changed_document", doc=charter, by=by)
|
||||
e.desc = "IESG has abandoned the chartering effort"
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
if comment:
|
||||
c = DocEvent(type="added_comment", doc=charter, by=login)
|
||||
c.desc = comment
|
||||
c.save()
|
||||
events.append(DocEvent.objects.create(type="added_comment", doc=charter, by=by, desc=comment))
|
||||
|
||||
charter.time = datetime.datetime.now()
|
||||
charter.save()
|
||||
charter.save_with_history(events)
|
||||
|
||||
if charter_state.slug == 'intrev':
|
||||
email_charter_internal_review(request,charter)
|
||||
|
@ -152,19 +151,22 @@ def change_state(request, name, option=None):
|
|||
|
||||
if charter_state.slug == "intrev" and group.type_id == "wg":
|
||||
if request.POST.get("ballot_wo_extern"):
|
||||
create_ballot_if_not_open(charter, login, "r-wo-ext")
|
||||
create_ballot_if_not_open(charter, by, "r-wo-ext")
|
||||
else:
|
||||
create_ballot_if_not_open(charter, login, "r-extrev")
|
||||
default_review_text(group, charter, login)
|
||||
default_action_text(group, charter, login)
|
||||
create_ballot_if_not_open(charter, by, "r-extrev")
|
||||
(e1, e2) = default_review_text(group, charter, by)
|
||||
e1.save()
|
||||
e2.save()
|
||||
e = default_action_text(group, charter, by)
|
||||
e.save()
|
||||
elif charter_state.slug == "iesgrev":
|
||||
create_ballot_if_not_open(charter, login, "approve")
|
||||
create_ballot_if_not_open(charter, by, "approve")
|
||||
elif charter_state.slug == "approved":
|
||||
change_group_state_after_charter_approval(group, login)
|
||||
fix_charter_revision_after_approval(charter, login)
|
||||
change_group_state_after_charter_approval(group, by)
|
||||
fix_charter_revision_after_approval(charter, by)
|
||||
|
||||
if charter_state.slug == "infrev" and clean["initial_time"] and clean["initial_time"] != 0:
|
||||
e = InitialReviewDocEvent(type="initial_review", by=login, doc=charter)
|
||||
e = InitialReviewDocEvent(type="initial_review", by=by, doc=charter)
|
||||
e.expires = datetime.datetime.now() + datetime.timedelta(weeks=clean["initial_time"])
|
||||
e.desc = "Initial review time expires %s" % e.expires.strftime("%Y-%m-%d")
|
||||
e.save()
|
||||
|
@ -184,10 +186,10 @@ def change_state(request, name, option=None):
|
|||
init = dict()
|
||||
elif option == "initcharter":
|
||||
hide = ['charter_state']
|
||||
init = dict(initial_time=1, message='%s has initiated chartering of the proposed %s:\n "%s" (%s).' % (login.plain_name(), group.type.name, group.name, group.acronym))
|
||||
init = dict(initial_time=1, message='%s has initiated chartering of the proposed %s:\n "%s" (%s).' % (by.plain_name(), group.type.name, group.name, group.acronym))
|
||||
elif option == "abandon":
|
||||
hide = ['initial_time', 'charter_state']
|
||||
init = dict(message='%s has abandoned the chartering effort on the %s:\n "%s" (%s).' % (login.plain_name(), group.type.name, group.name, group.acronym))
|
||||
init = dict(message='%s has abandoned the chartering effort on the %s:\n "%s" (%s).' % (by.plain_name(), group.type.name, group.name, group.acronym))
|
||||
form = ChangeStateForm(hide=hide, initial=init, group=group)
|
||||
|
||||
prev_charter_state = None
|
||||
|
@ -208,27 +210,25 @@ def change_state(request, name, option=None):
|
|||
|
||||
info_msg = {}
|
||||
if group.type_id == "wg":
|
||||
info_msg[state_pk("infrev")] = 'The proposed charter for %s "%s" (%s) has been set to Informal IESG review by %s.' % (group.type.name, group.name, group.acronym, login.plain_name())
|
||||
info_msg[state_pk("intrev")] = 'The proposed charter for %s "%s" (%s) has been set to Internal review by %s.\nPlease place it on the next IESG telechat if it has not already been placed.' % (group.type.name, group.name, group.acronym, login.plain_name())
|
||||
info_msg[state_pk("extrev")] = 'The proposed charter for %s "%s" (%s) has been set to External review by %s.\nPlease send out the external review announcement to the appropriate lists.\n\nSend the announcement to other SDOs: Yes\nAdditional recipients of the announcement: ' % (group.type.name, group.name, group.acronym, login.plain_name())
|
||||
info_msg[state_pk("infrev")] = 'The proposed charter for %s "%s" (%s) has been set to Informal IESG review by %s.' % (group.type.name, group.name, group.acronym, by.plain_name())
|
||||
info_msg[state_pk("intrev")] = 'The proposed charter for %s "%s" (%s) has been set to Internal review by %s.\nPlease place it on the next IESG telechat if it has not already been placed.' % (group.type.name, group.name, group.acronym, by.plain_name())
|
||||
info_msg[state_pk("extrev")] = 'The proposed charter for %s "%s" (%s) has been set to External review by %s.\nPlease send out the external review announcement to the appropriate lists.\n\nSend the announcement to other SDOs: Yes\nAdditional recipients of the announcement: ' % (group.type.name, group.name, group.acronym, by.plain_name())
|
||||
|
||||
states_for_ballot_wo_extern = State.objects.none()
|
||||
if group.type_id == "wg":
|
||||
states_for_ballot_wo_extern = State.objects.filter(used=True, type="charter", slug="intrev").values_list("pk", flat=True)
|
||||
|
||||
return render_to_response('doc/charter/change_state.html',
|
||||
dict(form=form,
|
||||
doc=group.charter,
|
||||
login=login,
|
||||
option=option,
|
||||
prev_charter_state=prev_charter_state,
|
||||
title=title,
|
||||
initial_review=initial_review,
|
||||
chartering_type=chartering_type,
|
||||
info_msg=json.dumps(info_msg),
|
||||
states_for_ballot_wo_extern=json.dumps(list(states_for_ballot_wo_extern)),
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
return render(request, 'doc/charter/change_state.html',
|
||||
dict(form=form,
|
||||
doc=group.charter,
|
||||
option=option,
|
||||
prev_charter_state=prev_charter_state,
|
||||
title=title,
|
||||
initial_review=initial_review,
|
||||
chartering_type=chartering_type,
|
||||
info_msg=json.dumps(info_msg),
|
||||
states_for_ballot_wo_extern=json.dumps(list(states_for_ballot_wo_extern)),
|
||||
))
|
||||
|
||||
class ChangeTitleForm(forms.Form):
|
||||
charter_title = forms.CharField(widget=forms.TextInput, label="Charter title", help_text="Enter new charter title.", required=True)
|
||||
|
@ -248,7 +248,7 @@ def change_title(request, name, option=None):
|
|||
group = charter.group
|
||||
if not can_manage_group_type(request.user, group.type_id):
|
||||
return HttpResponseForbidden("You don't have permission to access this view")
|
||||
login = request.user.person
|
||||
by = request.user.person
|
||||
if request.method == 'POST':
|
||||
form = ChangeTitleForm(request.POST, charter=charter)
|
||||
if form.is_valid():
|
||||
|
@ -259,17 +259,19 @@ def change_title(request, name, option=None):
|
|||
message = clean['message']
|
||||
prev_title = charter.title
|
||||
if new_title != prev_title:
|
||||
# Charter title changed
|
||||
save_document_in_history(charter)
|
||||
charter.title=new_title
|
||||
events = []
|
||||
charter.title = new_title
|
||||
charter.rev = charter_rev
|
||||
|
||||
if not comment:
|
||||
comment = "Changed charter title from '%s' to '%s'." % (prev_title, new_title)
|
||||
event = DocEvent(type="added_comment", doc=charter, by=login)
|
||||
event.desc = comment
|
||||
event.save()
|
||||
charter.time = datetime.datetime.now()
|
||||
charter.save()
|
||||
e = DocEvent(type="added_comment", doc=charter, by=by)
|
||||
e.desc = comment
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
charter.save_with_history(events)
|
||||
|
||||
if message:
|
||||
email_admin_re_charter(request, group, "Charter title changed to %s" % new_title, message,'charter_state_edit_admin_needed')
|
||||
email_state_changed(request, charter, "Title changed to %s." % new_title,'doc_state_edited')
|
||||
|
@ -277,13 +279,11 @@ def change_title(request, name, option=None):
|
|||
else:
|
||||
form = ChangeTitleForm(charter=charter)
|
||||
title = "Change charter title of %s %s" % (group.acronym, group.type.name)
|
||||
return render_to_response('doc/charter/change_title.html',
|
||||
dict(form=form,
|
||||
doc=group.charter,
|
||||
login=login,
|
||||
title=title,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
return render(request, 'doc/charter/change_title.html',
|
||||
dict(form=form,
|
||||
doc=group.charter,
|
||||
title=title,
|
||||
))
|
||||
|
||||
class AdForm(forms.Form):
|
||||
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active", role__group__type="area").order_by('name'),
|
||||
|
@ -303,34 +303,34 @@ def edit_ad(request, name):
|
|||
"""Change the responsible Area Director for this charter."""
|
||||
|
||||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
login = request.user.person
|
||||
by = request.user.person
|
||||
|
||||
if request.method == 'POST':
|
||||
form = AdForm(request.POST)
|
||||
if form.is_valid():
|
||||
new_ad = form.cleaned_data['ad']
|
||||
if new_ad != charter.ad:
|
||||
save_document_in_history(charter)
|
||||
e = DocEvent(doc=charter, by=login)
|
||||
events = []
|
||||
e = DocEvent(doc=charter, by=by)
|
||||
e.desc = "Responsible AD changed to %s" % new_ad.plain_name()
|
||||
if charter.ad:
|
||||
e.desc += " from %s" % charter.ad.plain_name()
|
||||
e.type = "changed_document"
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
charter.ad = new_ad
|
||||
charter.time = e.time
|
||||
charter.save()
|
||||
charter.save_with_history(events)
|
||||
|
||||
return redirect('doc_view', name=charter.name)
|
||||
else:
|
||||
init = { "ad" : charter.ad_id }
|
||||
form = AdForm(initial=init)
|
||||
|
||||
return render_to_response('doc/charter/change_ad.html',
|
||||
{'form': form,
|
||||
'charter': charter,
|
||||
},
|
||||
context_instance = RequestContext(request))
|
||||
return render(request, 'doc/charter/change_ad.html', {
|
||||
'form': form,
|
||||
'charter': charter,
|
||||
})
|
||||
|
||||
|
||||
class UploadForm(forms.Form):
|
||||
|
@ -352,22 +352,31 @@ class UploadForm(forms.Form):
|
|||
destination.write(self.cleaned_data['content'].encode("utf-8"))
|
||||
|
||||
@login_required
|
||||
def submit(request, name=None, option=None):
|
||||
def submit(request, name, option=None):
|
||||
if not name.startswith('charter-'):
|
||||
raise Http404
|
||||
|
||||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
group = charter.group
|
||||
charter = Document.objects.filter(type="charter", name=name).first()
|
||||
if charter:
|
||||
group = charter.group
|
||||
charter_canonical_name = charter.canonical_name()
|
||||
charter_rev = charter.rev
|
||||
else:
|
||||
top_org, group_acronym = split_charter_name(name)
|
||||
group = get_object_or_404(Group, acronym=group_acronym)
|
||||
charter_canonical_name = name
|
||||
charter_rev = "00-00"
|
||||
|
||||
if not can_manage_group_type(request.user, group.type_id):
|
||||
if not can_manage_group_type(request.user, group.type_id) or not group.features.has_chartering_process:
|
||||
return HttpResponseForbidden("You don't have permission to access this view")
|
||||
|
||||
path = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (charter.canonical_name(), charter.rev))
|
||||
not_uploaded_yet = charter.rev.endswith("-00") and not os.path.exists(path)
|
||||
|
||||
if not_uploaded_yet:
|
||||
path = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (charter_canonical_name, charter_rev))
|
||||
not_uploaded_yet = charter_rev.endswith("-00") and not os.path.exists(path)
|
||||
|
||||
if not_uploaded_yet or not charter:
|
||||
# this case is special - we recently chartered or rechartered and have no file yet
|
||||
next_rev = charter.rev
|
||||
next_rev = charter_rev
|
||||
else:
|
||||
# search history for possible collisions with abandoned efforts
|
||||
prev_revs = list(charter.history_set.order_by('-time').values_list('rev', flat=True))
|
||||
|
@ -378,16 +387,33 @@ def submit(request, name=None, option=None):
|
|||
if request.method == 'POST':
|
||||
form = UploadForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
save_document_in_history(charter)
|
||||
# Also save group history so we can search for it
|
||||
save_group_in_history(group)
|
||||
|
||||
charter.rev = next_rev
|
||||
if not charter:
|
||||
charter = Document.objects.create(
|
||||
name=name,
|
||||
type_id="charter",
|
||||
title=group.name,
|
||||
group=group,
|
||||
abstract=group.name,
|
||||
rev=next_rev,
|
||||
)
|
||||
DocAlias.objects.create(name=charter.name, document=charter)
|
||||
|
||||
charter.set_state(State.objects.get(used=True, type="charter", slug="notrev"))
|
||||
|
||||
group.charter = charter
|
||||
group.save()
|
||||
else:
|
||||
charter.rev = next_rev
|
||||
|
||||
events = []
|
||||
e = NewRevisionDocEvent(doc=charter, by=request.user.person, type="new_revision")
|
||||
e.desc = "New version available: <b>%s-%s.txt</b>" % (charter.canonical_name(), charter.rev)
|
||||
e.rev = charter.rev
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
# Save file on disk
|
||||
form.save(group, charter.rev)
|
||||
|
@ -395,25 +421,24 @@ def submit(request, name=None, option=None):
|
|||
if option in ['initcharter','recharter'] and charter.ad == None:
|
||||
charter.ad = getattr(group.ad_role(),'person',None)
|
||||
|
||||
charter.time = datetime.datetime.now()
|
||||
charter.save()
|
||||
charter.save_with_history(events)
|
||||
|
||||
if option:
|
||||
return redirect('charter_startstop_process', name=charter.name, option=option)
|
||||
else:
|
||||
return redirect("doc_view", name=charter.name)
|
||||
else:
|
||||
init = { "content": ""}
|
||||
c = charter
|
||||
init = { "content": "" }
|
||||
|
||||
if not_uploaded_yet:
|
||||
if not_uploaded_yet and charter:
|
||||
# use text from last approved revision
|
||||
last_approved = charter.rev.split("-")[0]
|
||||
h = charter.history_set.filter(rev=last_approved).order_by("-time", "-id")
|
||||
h = charter.history_set.filter(rev=last_approved).order_by("-time", "-id").first()
|
||||
if h:
|
||||
c = h[0]
|
||||
charter_canonical_name = h.canonical_name()
|
||||
charter_rev = h.rev
|
||||
|
||||
filename = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (c.canonical_name(), c.rev))
|
||||
filename = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (charter_canonical_name, charter_rev))
|
||||
|
||||
try:
|
||||
with open(filename, 'r') as f:
|
||||
|
@ -421,12 +446,12 @@ def submit(request, name=None, option=None):
|
|||
except IOError:
|
||||
pass
|
||||
form = UploadForm(initial=init)
|
||||
return render_to_response('doc/charter/submit.html',
|
||||
{'form': form,
|
||||
'next_rev': next_rev,
|
||||
'group': group,
|
||||
'name': name },
|
||||
context_instance=RequestContext(request))
|
||||
return render(request, 'doc/charter/submit.html', {
|
||||
'form': form,
|
||||
'next_rev': next_rev,
|
||||
'group': group,
|
||||
'name': name,
|
||||
})
|
||||
|
||||
class ActionAnnouncementTextForm(forms.Form):
|
||||
announcement_text = forms.CharField(widget=forms.Textarea, required=True)
|
||||
|
@ -449,60 +474,63 @@ def review_announcement_text(request, name):
|
|||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
group = charter.group
|
||||
|
||||
login = request.user.person
|
||||
by = request.user.person
|
||||
|
||||
existing = charter.latest_event(WriteupDocEvent, type="changed_review_announcement")
|
||||
existing_new_work = charter.latest_event(WriteupDocEvent, type="changed_new_work_text")
|
||||
|
||||
if not existing:
|
||||
(existing, existing_new_work) = default_review_text(group, charter, login)
|
||||
(existing, existing_new_work) = default_review_text(group, charter, by)
|
||||
|
||||
if not existing:
|
||||
raise Http404
|
||||
|
||||
if not existing_new_work:
|
||||
existing_new_work = WriteupDocEvent(doc=charter, by=login)
|
||||
existing_new_work.by = login
|
||||
existing_new_work = WriteupDocEvent(doc=charter)
|
||||
existing_new_work.by = by
|
||||
existing_new_work.type = "changed_new_work_text"
|
||||
existing_new_work.desc = "%s review text was changed" % group.type.name
|
||||
existing_new_work.text = derive_new_work_text(existing.text,group)
|
||||
existing_new_work.time = datetime.datetime.now()
|
||||
existing_new_work.save()
|
||||
|
||||
new_work_text = existing_new_work.text
|
||||
|
||||
form = ReviewAnnouncementTextForm(initial=dict(announcement_text=existing.text,new_work_text=new_work_text))
|
||||
form = ReviewAnnouncementTextForm(initial=dict(announcement_text=existing.text,new_work_text=existing_new_work.text))
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ReviewAnnouncementTextForm(request.POST)
|
||||
if "save_text" in request.POST and form.is_valid():
|
||||
|
||||
now = datetime.datetime.now()
|
||||
(e1, e2) = (None, None)
|
||||
events = []
|
||||
|
||||
t = form.cleaned_data['announcement_text']
|
||||
if t != existing.text:
|
||||
e1 = WriteupDocEvent(doc=charter, by=login)
|
||||
e1.by = login
|
||||
e1.type = "changed_review_announcement"
|
||||
e1.desc = "%s review text was changed" % (group.type.name)
|
||||
e1.text = t
|
||||
e1.time = now
|
||||
e1.save()
|
||||
e = WriteupDocEvent(doc=charter)
|
||||
e.by = by
|
||||
e.type = "changed_review_announcement"
|
||||
e.desc = "%s review text was changed" % (group.type.name)
|
||||
e.text = t
|
||||
e.time = now
|
||||
e.save()
|
||||
events.append(e)
|
||||
elif existing.pk is None:
|
||||
existing.save()
|
||||
events.append(existing)
|
||||
|
||||
t = form.cleaned_data['new_work_text']
|
||||
if t != new_work_text:
|
||||
e2 = WriteupDocEvent(doc=charter, by=login)
|
||||
e2.by = login
|
||||
e2.type = "changed_new_work_text"
|
||||
e2.desc = "%s new work message text was changed" % (group.type.name)
|
||||
e2.text = t
|
||||
e2.time = now
|
||||
e2.save()
|
||||
if t != existing_new_work.text:
|
||||
e = WriteupDocEvent(doc=charter)
|
||||
e.by = by
|
||||
e.type = "changed_new_work_text"
|
||||
e.desc = "%s new work message text was changed" % (group.type.name)
|
||||
e.text = t
|
||||
e.time = now
|
||||
e.save()
|
||||
elif existing_new_work.pk is None:
|
||||
existing_new_work.save()
|
||||
events.append(existing_new_work)
|
||||
|
||||
if e1 or e2:
|
||||
charter.time = now
|
||||
charter.save()
|
||||
if events:
|
||||
charter.save_with_history(events)
|
||||
|
||||
if request.GET.get("next", "") == "approve":
|
||||
return redirect('charter_approve', name=charter.canonical_name())
|
||||
|
@ -510,24 +538,26 @@ def review_announcement_text(request, name):
|
|||
return redirect('doc_writeup', name=charter.canonical_name())
|
||||
|
||||
if "regenerate_text" in request.POST:
|
||||
(e1, e2) = default_review_text(group, charter, login)
|
||||
form = ReviewAnnouncementTextForm(initial=dict(announcement_text=e1.text,new_work_text=e2.text))
|
||||
(existing, existing_new_work) = default_review_text(group, charter, by)
|
||||
existing.save()
|
||||
existing_new_work.save()
|
||||
form = ReviewAnnouncementTextForm(initial=dict(announcement_text=existing.text,
|
||||
new_work_text=existing_new_work.text))
|
||||
|
||||
if any([x in request.POST for x in ['send_annc_only','send_nw_only','send_both']]) and form.is_valid():
|
||||
if any([x in request.POST for x in ['send_annc_only','send_both']]):
|
||||
if any(x in request.POST for x in ['send_annc_only','send_nw_only','send_both']) and form.is_valid():
|
||||
if any(x in request.POST for x in ['send_annc_only','send_both']):
|
||||
parsed_msg = send_mail_preformatted(request, form.cleaned_data['announcement_text'])
|
||||
messages.success(request, "The email To: '%s' with Subject: '%s' has been sent." % (parsed_msg["To"],parsed_msg["Subject"],))
|
||||
if any([x in request.POST for x in ['send_nw_only','send_both']]):
|
||||
if any(x in request.POST for x in ['send_nw_only','send_both']):
|
||||
parsed_msg = send_mail_preformatted(request, form.cleaned_data['new_work_text'])
|
||||
messages.success(request, "The email To: '%s' with Subject: '%s' has been sent." % (parsed_msg["To"],parsed_msg["Subject"],))
|
||||
return redirect('doc_writeup', name=charter.name)
|
||||
|
||||
return render_to_response('doc/charter/review_announcement_text.html',
|
||||
dict(charter=charter,
|
||||
back_url=urlreverse("doc_writeup", kwargs=dict(name=charter.name)),
|
||||
announcement_text_form=form,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
return render(request, 'doc/charter/review_announcement_text.html',
|
||||
dict(charter=charter,
|
||||
back_url=urlreverse("doc_writeup", kwargs=dict(name=charter.name)),
|
||||
announcement_text_form=form,
|
||||
))
|
||||
|
||||
@role_required('Area Director','Secretariat')
|
||||
def action_announcement_text(request, name):
|
||||
|
@ -535,11 +565,11 @@ def action_announcement_text(request, name):
|
|||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
group = charter.group
|
||||
|
||||
login = request.user.person
|
||||
by = request.user.person
|
||||
|
||||
existing = charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
|
||||
if not existing:
|
||||
existing = default_action_text(group, charter, login)
|
||||
existing = default_action_text(group, charter, by)
|
||||
|
||||
if not existing:
|
||||
raise Http404
|
||||
|
@ -551,15 +581,14 @@ def action_announcement_text(request, name):
|
|||
if "save_text" in request.POST and form.is_valid():
|
||||
t = form.cleaned_data['announcement_text']
|
||||
if t != existing.text:
|
||||
e = WriteupDocEvent(doc=charter, by=login)
|
||||
e.by = login
|
||||
e = WriteupDocEvent(doc=charter)
|
||||
e.by = by
|
||||
e.type = "changed_action_announcement"
|
||||
e.desc = "%s action text was changed" % group.type.name
|
||||
e.text = t
|
||||
e.save()
|
||||
|
||||
charter.time = e.time
|
||||
charter.save()
|
||||
elif existing.pk == None:
|
||||
existing.save()
|
||||
|
||||
if request.GET.get("next", "") == "approve":
|
||||
return redirect('charter_approve', name=charter.canonical_name())
|
||||
|
@ -567,7 +596,8 @@ def action_announcement_text(request, name):
|
|||
return redirect('doc_writeup', name=charter.canonical_name())
|
||||
|
||||
if "regenerate_text" in request.POST:
|
||||
e = default_action_text(group, charter, login)
|
||||
e = default_action_text(group, charter, by)
|
||||
e.save()
|
||||
form = ActionAnnouncementTextForm(initial=dict(announcement_text=e.text))
|
||||
|
||||
if "send_text" in request.POST and form.is_valid():
|
||||
|
@ -575,12 +605,11 @@ def action_announcement_text(request, name):
|
|||
messages.success(request, "The email To: '%s' with Subject: '%s' has been sent." % (parsed_msg["To"],parsed_msg["Subject"],))
|
||||
return redirect('doc_writeup', name=charter.name)
|
||||
|
||||
return render_to_response('doc/charter/action_announcement_text.html',
|
||||
dict(charter=charter,
|
||||
back_url=urlreverse("doc_writeup", kwargs=dict(name=charter.name)),
|
||||
announcement_text_form=form,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
return render(request, 'doc/charter/action_announcement_text.html',
|
||||
dict(charter=charter,
|
||||
back_url=urlreverse("doc_writeup", kwargs=dict(name=charter.name)),
|
||||
announcement_text_form=form,
|
||||
))
|
||||
|
||||
class BallotWriteupForm(forms.Form):
|
||||
ballot_writeup = forms.CharField(widget=forms.Textarea, required=True)
|
||||
|
@ -597,7 +626,7 @@ def ballot_writeupnotes(request, name):
|
|||
if not ballot:
|
||||
raise Http404
|
||||
|
||||
login = request.user.person
|
||||
by = request.user.person
|
||||
|
||||
approval = charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
|
||||
|
||||
|
@ -614,21 +643,22 @@ def ballot_writeupnotes(request, name):
|
|||
if form.is_valid():
|
||||
t = form.cleaned_data["ballot_writeup"]
|
||||
if t != existing.text:
|
||||
e = WriteupDocEvent(doc=charter, by=login)
|
||||
e.by = login
|
||||
e = WriteupDocEvent(doc=charter, by=by)
|
||||
e.type = "changed_ballot_writeup_text"
|
||||
e.desc = "Ballot writeup was changed"
|
||||
e.text = t
|
||||
e.save()
|
||||
|
||||
existing = e
|
||||
elif existing.pk == None:
|
||||
existing.save()
|
||||
|
||||
if "send_ballot" in request.POST and approval:
|
||||
if has_role(request.user, "Area Director") and not charter.latest_event(BallotPositionDocEvent, type="changed_ballot_position", ad=login, ballot=ballot):
|
||||
if has_role(request.user, "Area Director") and not charter.latest_event(BallotPositionDocEvent, type="changed_ballot_position", ad=by, ballot=ballot):
|
||||
# sending the ballot counts as a yes
|
||||
pos = BallotPositionDocEvent(doc=charter, by=login)
|
||||
pos = BallotPositionDocEvent(doc=charter, by=by)
|
||||
pos.type = "changed_ballot_position"
|
||||
pos.ad = login
|
||||
pos.ad = by
|
||||
pos.pos_id = "yes"
|
||||
pos.desc = "[Ballot Position Update] New position, %s, has been recorded for %s" % (pos.pos.name, pos.ad.plain_name())
|
||||
pos.save()
|
||||
|
@ -637,65 +667,23 @@ def ballot_writeupnotes(request, name):
|
|||
msg = generate_issue_ballot_mail(request, charter, ballot)
|
||||
send_mail_preformatted(request, msg)
|
||||
|
||||
e = DocEvent(doc=charter, by=login)
|
||||
e.by = login
|
||||
e = DocEvent(doc=charter, by=by)
|
||||
e.by = by
|
||||
e.type = "sent_ballot_announcement"
|
||||
e.desc = "Ballot has been sent"
|
||||
e.save()
|
||||
|
||||
return render_to_response('doc/charter/ballot_issued.html',
|
||||
dict(doc=charter,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
return render(request, 'doc/charter/ballot_issued.html',
|
||||
dict(doc=charter,
|
||||
))
|
||||
|
||||
return render_to_response('doc/charter/ballot_writeupnotes.html',
|
||||
dict(charter=charter,
|
||||
ballot_issued=bool(charter.latest_event(type="sent_ballot_announcement")),
|
||||
ballot_writeup_form=form,
|
||||
reissue=reissue,
|
||||
approval=approval,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def change_group_state_after_charter_approval(group, by):
|
||||
new_state = GroupStateName.objects.get(slug="active")
|
||||
if group.state == new_state:
|
||||
return None
|
||||
|
||||
save_group_in_history(group)
|
||||
group.state = new_state
|
||||
group.time = datetime.datetime.now()
|
||||
group.save()
|
||||
|
||||
# create an event for the group state change, too
|
||||
e = ChangeStateGroupEvent(group=group, type="changed_state")
|
||||
e.time = group.time
|
||||
e.by = by
|
||||
e.state_id = "active"
|
||||
e.desc = "Charter approved, group active"
|
||||
e.save()
|
||||
|
||||
return e
|
||||
|
||||
def fix_charter_revision_after_approval(charter, by):
|
||||
# according to spec, 00-02 becomes 01, so copy file and record new revision
|
||||
try:
|
||||
old = os.path.join(charter.get_file_path(), '%s-%s.txt' % (charter.canonical_name(), charter.rev))
|
||||
new = os.path.join(charter.get_file_path(), '%s-%s.txt' % (charter.canonical_name(), next_approved_revision(charter.rev)))
|
||||
shutil.copy(old, new)
|
||||
except IOError:
|
||||
return HttpResponse("There was an error copying %s to %s" %
|
||||
('%s-%s.txt' % (charter.canonical_name(), charter.rev),
|
||||
'%s-%s.txt' % (charter.canonical_name(), next_approved_revision(charter.rev))))
|
||||
|
||||
e = NewRevisionDocEvent(doc=charter, by=by, type="new_revision")
|
||||
e.rev = next_approved_revision(charter.rev)
|
||||
e.desc = "New version available: <b>%s-%s.txt</b>" % (charter.canonical_name(), e.rev)
|
||||
e.save()
|
||||
|
||||
charter.rev = e.rev
|
||||
charter.time = e.time
|
||||
charter.save()
|
||||
return render(request, 'doc/charter/ballot_writeupnotes.html',
|
||||
dict(charter=charter,
|
||||
ballot_issued=bool(charter.latest_event(type="sent_ballot_announcement")),
|
||||
ballot_writeup_form=form,
|
||||
reissue=reissue,
|
||||
approval=approval,
|
||||
))
|
||||
|
||||
@role_required("Secretariat")
|
||||
def approve(request, name):
|
||||
|
@ -703,11 +691,11 @@ def approve(request, name):
|
|||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
group = charter.group
|
||||
|
||||
login = request.user.person
|
||||
by = request.user.person
|
||||
|
||||
e = charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
|
||||
if not e:
|
||||
announcement = default_action_text(group, charter, login).text
|
||||
announcement = default_action_text(group, charter, by).text
|
||||
else:
|
||||
announcement = e.text
|
||||
|
||||
|
@ -715,26 +703,31 @@ def approve(request, name):
|
|||
new_charter_state = State.objects.get(used=True, type="charter", slug="approved")
|
||||
prev_charter_state = charter.get_state()
|
||||
|
||||
save_document_in_history(charter)
|
||||
charter.set_state(new_charter_state)
|
||||
|
||||
close_open_ballots(charter, login)
|
||||
close_open_ballots(charter, by)
|
||||
|
||||
events = []
|
||||
# approve
|
||||
e = DocEvent(doc=charter, by=login)
|
||||
e = DocEvent(doc=charter, by=by)
|
||||
e.type = "iesg_approved"
|
||||
e.desc = "IESG has approved the charter"
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
change_description = e.desc
|
||||
|
||||
group_state_change_event = change_group_state_after_charter_approval(group, login)
|
||||
group_state_change_event = change_group_state_after_charter_approval(group, by)
|
||||
if group_state_change_event:
|
||||
change_description += " and group state has been changed to %s" % group.state.name
|
||||
|
||||
add_state_change_event(charter, login, prev_charter_state, new_charter_state)
|
||||
e = add_state_change_event(charter, by, prev_charter_state, new_charter_state)
|
||||
if e:
|
||||
events.append(e)
|
||||
|
||||
fix_charter_revision_after_approval(charter, login)
|
||||
fix_charter_revision_after_approval(charter, by)
|
||||
|
||||
charter.save_with_history(events)
|
||||
|
||||
email_admin_re_charter(request, group, "Charter state changed to %s" % new_charter_state.name, change_description,'charter_state_edit_admin_needed')
|
||||
|
||||
|
@ -757,7 +750,7 @@ def approve(request, name):
|
|||
o.state_id = "active"
|
||||
o.save()
|
||||
MilestoneGroupEvent.objects.create(
|
||||
group=group, type="changed_milestone", by=login,
|
||||
group=group, type="changed_milestone", by=by,
|
||||
desc="Changed milestone \"%s\", set state to active from review" % o.desc,
|
||||
milestone=o)
|
||||
|
||||
|
@ -774,7 +767,7 @@ def approve(request, name):
|
|||
m.save()
|
||||
|
||||
MilestoneGroupEvent.objects.create(
|
||||
group=group, type="changed_milestone", by=login,
|
||||
group=group, type="changed_milestone", by=by,
|
||||
desc="Added milestone \"%s\", due %s, from approved charter" % (m.desc, m.due),
|
||||
milestone=m)
|
||||
|
||||
|
@ -784,7 +777,7 @@ def approve(request, name):
|
|||
m.save()
|
||||
|
||||
MilestoneGroupEvent.objects.create(
|
||||
group=group, type="changed_milestone", by=login,
|
||||
group=group, type="changed_milestone", by=by,
|
||||
desc="Deleted milestone \"%s\", not present in approved charter" % m.desc,
|
||||
milestone=m)
|
||||
|
||||
|
@ -793,10 +786,9 @@ def approve(request, name):
|
|||
|
||||
return HttpResponseRedirect(charter.get_absolute_url())
|
||||
|
||||
return render_to_response('doc/charter/approve.html',
|
||||
dict(charter=charter,
|
||||
announcement=announcement),
|
||||
context_instance=RequestContext(request))
|
||||
return render(request, 'doc/charter/approve.html',
|
||||
dict(charter=charter,
|
||||
announcement=announcement))
|
||||
|
||||
def charter_with_milestones_txt(request, name, rev):
|
||||
charter = get_object_or_404(Document, type="charter", docalias__name=name)
|
||||
|
@ -824,8 +816,7 @@ def charter_with_milestones_txt(request, name, rev):
|
|||
for m in milestones:
|
||||
m.desc_filled = wrapper.fill(m.desc)
|
||||
|
||||
return render_to_response('doc/charter/charter_with_milestones.txt',
|
||||
dict(charter_text=charter_text,
|
||||
milestones=milestones),
|
||||
context_instance=RequestContext(request),
|
||||
content_type="text/plain; charset=%s"%settings.DEFAULT_CHARSET)
|
||||
return render(request, 'doc/charter/charter_with_milestones.txt',
|
||||
dict(charter_text=charter_text,
|
||||
milestones=milestones),
|
||||
content_type="text/plain; charset=%s"%settings.DEFAULT_CHARSET)
|
||||
|
|
|
@ -9,7 +9,7 @@ from django.template.loader import render_to_string
|
|||
from django.conf import settings
|
||||
|
||||
from ietf.doc.models import ( BallotDocEvent, BallotPositionDocEvent, DocAlias, DocEvent,
|
||||
Document, NewRevisionDocEvent, State, save_document_in_history )
|
||||
Document, NewRevisionDocEvent, State )
|
||||
from ietf.doc.utils import ( add_state_change_event, close_open_ballots,
|
||||
create_ballot_if_not_open, get_document_content, update_telechat )
|
||||
from ietf.doc.mails import email_iana
|
||||
|
@ -48,13 +48,12 @@ def change_state(request, name, option=None):
|
|||
|
||||
prev_state = review.get_state()
|
||||
if new_state != prev_state:
|
||||
save_document_in_history(review)
|
||||
events = []
|
||||
|
||||
review.set_state(new_state)
|
||||
add_state_change_event(review, login, prev_state, new_state)
|
||||
events.append(add_state_change_event(review, login, prev_state, new_state))
|
||||
|
||||
review.time = datetime.datetime.now()
|
||||
review.save()
|
||||
review.save_with_history(events)
|
||||
|
||||
if new_state.slug == "iesgeval":
|
||||
create_ballot_if_not_open(review, login, "conflrev")
|
||||
|
@ -165,20 +164,19 @@ def submit(request, name):
|
|||
if "submit_response" in request.POST:
|
||||
form = UploadForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
save_document_in_history(review)
|
||||
|
||||
review.rev = next_rev
|
||||
|
||||
events = []
|
||||
e = NewRevisionDocEvent(doc=review, by=login, type="new_revision")
|
||||
e.desc = "New version available: <b>%s-%s.txt</b>" % (review.canonical_name(), review.rev)
|
||||
e.rev = review.rev
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
# Save file on disk
|
||||
form.save(review)
|
||||
|
||||
review.time = datetime.datetime.now()
|
||||
review.save()
|
||||
review.save_with_history(events)
|
||||
|
||||
return redirect('doc_view', name=review.name)
|
||||
|
||||
|
@ -228,15 +226,14 @@ def edit_ad(request, name):
|
|||
if request.method == 'POST':
|
||||
form = AdForm(request.POST)
|
||||
if form.is_valid():
|
||||
|
||||
review.ad = form.cleaned_data['ad']
|
||||
review.save()
|
||||
|
||||
login = request.user.person
|
||||
c = DocEvent(type="added_comment", doc=review, by=login)
|
||||
|
||||
c = DocEvent(type="added_comment", doc=review, by=request.user.person)
|
||||
c.desc = "Shepherding AD changed to "+review.ad.name
|
||||
c.save()
|
||||
|
||||
review.save_with_history([c])
|
||||
|
||||
return redirect('doc_view', name=review.name)
|
||||
|
||||
else:
|
||||
|
@ -300,13 +297,14 @@ def approve(request, name):
|
|||
|
||||
if form.is_valid():
|
||||
prev_state = review.get_state()
|
||||
events = []
|
||||
|
||||
new_state_slug = 'appr-reqnopub-sent' if prev_state.slug == 'appr-reqnopub-pend' else 'appr-noprob-sent'
|
||||
new_state = State.objects.get(used=True, type="conflrev", slug=new_state_slug)
|
||||
save_document_in_history(review)
|
||||
|
||||
review.set_state(new_state)
|
||||
add_state_change_event(review, login, prev_state, new_state)
|
||||
e = add_state_change_event(review, login, prev_state, new_state)
|
||||
events.append(e)
|
||||
|
||||
close_open_ballots(review, login)
|
||||
|
||||
|
@ -314,9 +312,9 @@ def approve(request, name):
|
|||
e.type = "iesg_approved"
|
||||
e.desc = "IESG has approved the conflict review response"
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
review.time = e.time
|
||||
review.save()
|
||||
review.save_with_history(events)
|
||||
|
||||
# send announcement
|
||||
send_mail_preformatted(request, form.cleaned_data['announcement_text'])
|
||||
|
@ -396,16 +394,16 @@ def build_conflict_review_document(login, doc_to_review, ad, notify, create_in_s
|
|||
|
||||
iesg_group = Group.objects.get(acronym='iesg')
|
||||
|
||||
conflict_review=Document( type_id = "conflrev",
|
||||
title = "IETF conflict review for %s" % doc_to_review.name,
|
||||
name = review_name,
|
||||
rev = "00",
|
||||
ad = ad,
|
||||
notify = notify,
|
||||
stream_id = 'ietf',
|
||||
group = iesg_group,
|
||||
)
|
||||
conflict_review.save()
|
||||
conflict_review = Document.objects.create(
|
||||
type_id="conflrev",
|
||||
title="IETF conflict review for %s" % doc_to_review.name,
|
||||
name=review_name,
|
||||
rev="00",
|
||||
ad=ad,
|
||||
notify=notify,
|
||||
stream_id='ietf',
|
||||
group=iesg_group,
|
||||
)
|
||||
conflict_review.set_state(create_in_state)
|
||||
|
||||
DocAlias.objects.create( name=review_name , document=conflict_review )
|
||||
|
|
|
@ -309,24 +309,24 @@ def document_main(request, name, rev=None):
|
|||
# remaining actions
|
||||
actions = []
|
||||
|
||||
if can_adopt_draft(request.user, doc) and not doc.get_state_slug() in ["rfc"]:
|
||||
if can_adopt_draft(request.user, doc) and not doc.get_state_slug() in ["rfc"] and not snapshot:
|
||||
actions.append(("Manage Document Adoption in Group", urlreverse('doc_adopt_draft', kwargs=dict(name=doc.name))))
|
||||
|
||||
if doc.get_state_slug() == "expired" and not resurrected_by and can_edit:
|
||||
if doc.get_state_slug() == "expired" and not resurrected_by and can_edit and not snapshot:
|
||||
actions.append(("Request Resurrect", urlreverse('doc_request_resurrect', kwargs=dict(name=doc.name))))
|
||||
|
||||
if doc.get_state_slug() == "expired" and has_role(request.user, ("Secretariat",)):
|
||||
if doc.get_state_slug() == "expired" and has_role(request.user, ("Secretariat",)) and not snapshot:
|
||||
actions.append(("Resurrect", urlreverse('doc_resurrect', kwargs=dict(name=doc.name))))
|
||||
|
||||
if (doc.get_state_slug() not in ["rfc", "expired"] and doc.stream_id in ("ise", "irtf")
|
||||
and can_edit_stream_info and not conflict_reviews):
|
||||
and can_edit_stream_info and not conflict_reviews and not snapshot):
|
||||
label = "Begin IETF Conflict Review"
|
||||
if not doc.intended_std_level:
|
||||
label += " (note that intended status is not set)"
|
||||
actions.append((label, urlreverse('conflict_review_start', kwargs=dict(name=doc.name))))
|
||||
|
||||
if (doc.get_state_slug() not in ["rfc", "expired"] and doc.stream_id in ("iab", "ise", "irtf")
|
||||
and can_edit_stream_info):
|
||||
and can_edit_stream_info and not snapshot):
|
||||
label = "Request Publication"
|
||||
if not doc.intended_std_level:
|
||||
label += " (note that intended status is not set)"
|
||||
|
@ -334,7 +334,7 @@ def document_main(request, name, rev=None):
|
|||
label += " (Warning: the IESG state indicates ongoing IESG processing)"
|
||||
actions.append((label, urlreverse('doc_request_publication', kwargs=dict(name=doc.name))))
|
||||
|
||||
if doc.get_state_slug() not in ["rfc", "expired"] and doc.stream_id in ("ietf",):
|
||||
if doc.get_state_slug() not in ["rfc", "expired"] and doc.stream_id in ("ietf",) and not snapshot:
|
||||
if not iesg_state and can_edit:
|
||||
actions.append(("Begin IESG Processing", urlreverse('doc_edit_info', kwargs=dict(name=doc.name)) + "?new=1"))
|
||||
elif can_edit_stream_info and (not iesg_state or iesg_state.slug == 'watching'):
|
||||
|
@ -674,9 +674,10 @@ def document_writeup(request, name):
|
|||
"<em>Draft</em> of message to be sent <em>after</em> approval:",
|
||||
writeups))
|
||||
|
||||
writeups.append(("Announcement",
|
||||
text_from_writeup("changed_ballot_approval_text"),
|
||||
urlreverse("doc_ballot_approvaltext", kwargs=dict(name=doc.name))))
|
||||
if doc.get_state("draft-iesg"):
|
||||
writeups.append(("Announcement",
|
||||
text_from_writeup("changed_ballot_approval_text"),
|
||||
urlreverse("doc_ballot_approvaltext", kwargs=dict(name=doc.name))))
|
||||
|
||||
writeups.append(("Ballot Text",
|
||||
text_from_writeup("changed_ballot_writeup_text"),
|
||||
|
@ -981,8 +982,7 @@ def edit_notify(request, name):
|
|||
if set(new_notify.split(',')) != set(doc.notify.split(',')):
|
||||
e = make_notify_changed_event(request, doc, login.person, new_notify)
|
||||
doc.notify = new_notify
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
doc.save_with_history([e])
|
||||
return redirect('doc_view', name=doc.name)
|
||||
|
||||
elif "regenerate_addresses" in request.POST:
|
||||
|
|
|
@ -16,8 +16,7 @@ from django.contrib import messages
|
|||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.models import ( Document, DocAlias, RelatedDocument, State,
|
||||
StateType, DocEvent, ConsensusDocEvent, TelechatDocEvent, WriteupDocEvent, IESG_SUBSTATE_TAGS,
|
||||
save_document_in_history )
|
||||
StateType, DocEvent, ConsensusDocEvent, TelechatDocEvent, WriteupDocEvent, IESG_SUBSTATE_TAGS)
|
||||
from ietf.doc.mails import ( email_pulled_from_rfc_queue, email_resurrect_requested,
|
||||
email_resurrection_completed, email_state_changed, email_stream_changed,
|
||||
email_stream_state_changed, email_stream_tags_changed, extra_automation_headers,
|
||||
|
@ -89,17 +88,17 @@ def change_state(request, name):
|
|||
prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
new_tags = [tag] if tag else []
|
||||
if new_state != prev_state or set(new_tags) != set(prev_tags):
|
||||
save_document_in_history(doc)
|
||||
|
||||
doc.set_state(new_state)
|
||||
|
||||
doc.tags.remove(*prev_tags)
|
||||
doc.tags.add(*new_tags)
|
||||
|
||||
events = []
|
||||
|
||||
e = add_state_change_event(doc, login, prev_state, new_state,
|
||||
prev_tags=prev_tags, new_tags=new_tags)
|
||||
|
||||
msg = e.desc
|
||||
events.append(e)
|
||||
|
||||
if comment:
|
||||
c = DocEvent(type="added_comment")
|
||||
|
@ -108,14 +107,14 @@ def change_state(request, name):
|
|||
c.desc = comment
|
||||
c.save()
|
||||
|
||||
msg += "\n" + comment
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
events.append(c)
|
||||
|
||||
doc.save_with_history(events)
|
||||
|
||||
msg = u"\n".join(e.desc for e in events)
|
||||
|
||||
email_state_changed(request, doc, msg,'doc_state_edited')
|
||||
|
||||
|
||||
if prev_state and prev_state.slug in ("ann", "rfcqueue") and new_state.slug not in ("rfcqueue", "pub"):
|
||||
email_pulled_from_rfc_queue(request, doc, comment, prev_state, new_state)
|
||||
|
||||
|
@ -188,14 +187,11 @@ def change_iana_state(request, name, state_type):
|
|||
new_state = form.cleaned_data['state']
|
||||
|
||||
if new_state != prev_state:
|
||||
save_document_in_history(doc)
|
||||
|
||||
doc.set_state(new_state)
|
||||
|
||||
e = add_state_change_event(doc, request.user.person, prev_state, new_state)
|
||||
events = [add_state_change_event(doc, request.user.person, prev_state, new_state)]
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
doc.save_with_history(events)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
|
||||
|
@ -244,27 +240,28 @@ def change_stream(request, name):
|
|||
elif "irsg@irtf.org" not in doc.notify:
|
||||
doc.notify += ", irsg@irtf.org"
|
||||
|
||||
save_document_in_history(doc)
|
||||
|
||||
doc.stream = new_stream
|
||||
doc.group = Group.objects.get(type="individ")
|
||||
|
||||
events = []
|
||||
|
||||
e = DocEvent(doc=doc,by=login,type='changed_document')
|
||||
e.desc = u"Stream changed to <b>%s</b> from %s"% (new_stream, old_stream or "None")
|
||||
e.save()
|
||||
|
||||
email_desc = e.desc
|
||||
events.append(e)
|
||||
|
||||
if comment:
|
||||
c = DocEvent(doc=doc,by=login,type="added_comment")
|
||||
c.desc = comment
|
||||
c.save()
|
||||
email_desc += "\n"+c.desc
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
events.append(c)
|
||||
|
||||
email_stream_changed(request, doc, old_stream, new_stream, email_desc)
|
||||
doc.save_with_history(events)
|
||||
|
||||
msg = u"\n".join(e.desc for e in events)
|
||||
|
||||
email_stream_changed(request, doc, old_stream, new_stream, msg)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
|
||||
|
@ -327,16 +324,11 @@ def replaces(request, name):
|
|||
by = request.user.person
|
||||
|
||||
if new_replaces != old_replaces:
|
||||
save_document_in_history(doc)
|
||||
doc.time = datetime.datetime.now()
|
||||
doc.save()
|
||||
events = set_replaces_for_document(request, doc, new_replaces, by=by,
|
||||
email_subject="%s replacement status updated by %s" % (doc.name, by),
|
||||
comment=comment)
|
||||
|
||||
set_replaces_for_document(request, doc, new_replaces, by=by,
|
||||
email_subject="%s replacement status updated by %s" % (doc.name, by),
|
||||
email_comment=comment)
|
||||
|
||||
if comment:
|
||||
DocEvent.objects.create(doc=doc, by=by, type="added_comment", desc=comment)
|
||||
doc.save_with_history(events)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
else:
|
||||
|
@ -381,22 +373,22 @@ def review_possibly_replaces(request, name):
|
|||
comment = form.cleaned_data['comment'].strip()
|
||||
by = request.user.person
|
||||
|
||||
save_document_in_history(doc)
|
||||
doc.time = datetime.datetime.now()
|
||||
doc.save()
|
||||
events = []
|
||||
|
||||
# all suggestions reviewed, so get rid of them
|
||||
DocEvent.objects.create(doc=doc, by=by, type="reviewed_suggested_replaces",
|
||||
desc="Reviewed suggested replacement relationships: %s" % ", ".join(d.name for d in suggested))
|
||||
events.append(DocEvent.objects.create(doc=doc, by=by, type="reviewed_suggested_replaces",
|
||||
desc="Reviewed suggested replacement relationships: %s" % ", ".join(d.name for d in suggested)))
|
||||
RelatedDocument.objects.filter(source=doc, target__in=suggested,relationship__slug='possibly-replaces').delete()
|
||||
|
||||
if new_replaces != old_replaces:
|
||||
set_replaces_for_document(request, doc, new_replaces, by=by,
|
||||
email_subject="%s replacement status updated by %s" % (doc.name, by),
|
||||
email_comment=comment)
|
||||
events.extend(set_replaces_for_document(request, doc, new_replaces, by=by,
|
||||
email_subject="%s replacement status updated by %s" % (doc.name, by),
|
||||
comment=comment))
|
||||
|
||||
if comment:
|
||||
DocEvent.objects.create(doc=doc, by=by, type="added_comment", desc=comment)
|
||||
events.append(DocEvent.objects.create(doc=doc, by=by, type="added_comment", desc=comment))
|
||||
|
||||
doc.save_with_history(events)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
else:
|
||||
|
@ -433,26 +425,25 @@ def change_intention(request, name):
|
|||
old_level = doc.intended_std_level
|
||||
|
||||
if new_level != old_level:
|
||||
save_document_in_history(doc)
|
||||
|
||||
doc.intended_std_level = new_level
|
||||
|
||||
events = []
|
||||
e = DocEvent(doc=doc,by=login,type='changed_document')
|
||||
e.desc = u"Intended Status changed to <b>%s</b> from %s"% (new_level,old_level)
|
||||
e.save()
|
||||
|
||||
email_desc = e.desc
|
||||
events.append(e)
|
||||
|
||||
if comment:
|
||||
c = DocEvent(doc=doc,by=login,type="added_comment")
|
||||
c.desc = comment
|
||||
c.save()
|
||||
email_desc += "\n"+c.desc
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
events.append(c)
|
||||
|
||||
email_intended_status_changed(request, doc, email_desc)
|
||||
doc.save_with_history(events)
|
||||
|
||||
msg = u"\n".join(e.desc for e in events)
|
||||
|
||||
email_intended_status_changed(request, doc, msg)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
|
||||
|
@ -539,27 +530,27 @@ def to_iesg(request,name):
|
|||
|
||||
if request.POST.get("confirm", ""):
|
||||
|
||||
save_document_in_history(doc)
|
||||
by = request.user.person
|
||||
|
||||
login = request.user.person
|
||||
events = []
|
||||
|
||||
changes = []
|
||||
|
||||
if not doc.get_state("draft-iesg"):
|
||||
|
||||
e = DocEvent()
|
||||
e.type = "started_iesg_process"
|
||||
e.by = login
|
||||
e.by = by
|
||||
e.doc = doc
|
||||
e.desc = "IESG process started in state <b>%s</b>" % target_state['iesg'].name
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
for state_type in ['draft-iesg','draft-stream-ietf']:
|
||||
prev_state=doc.get_state(state_type)
|
||||
new_state = target_state[target_map[state_type]]
|
||||
if not prev_state==new_state:
|
||||
doc.set_state(new_state)
|
||||
add_state_change_event(doc=doc,by=login,prev_state=prev_state,new_state=new_state)
|
||||
events.append(add_state_change_event(doc=doc,by=by,prev_state=prev_state,new_state=new_state))
|
||||
|
||||
if not doc.ad == ad :
|
||||
doc.ad = ad
|
||||
|
@ -575,24 +566,23 @@ def to_iesg(request,name):
|
|||
changes.append(previous_writeup.text)
|
||||
|
||||
for c in changes:
|
||||
e = DocEvent(doc=doc, by=login)
|
||||
e = DocEvent(doc=doc, by=by)
|
||||
e.desc = c
|
||||
e.type = "changed_document"
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
doc.time = datetime.datetime.now()
|
||||
|
||||
doc.save()
|
||||
doc.save_with_history(events)
|
||||
|
||||
addrs= gather_address_lists('pubreq_iesg',doc=doc)
|
||||
extra = {}
|
||||
extra['Cc'] = addrs.as_strings().cc
|
||||
send_mail(request=request,
|
||||
to = addrs.to,
|
||||
frm = login.formatted_email(),
|
||||
frm = by.formatted_email(),
|
||||
subject = "Publication has been requested for %s-%s" % (doc.name,doc.rev),
|
||||
template = "doc/submit_to_iesg_email.txt",
|
||||
context = dict(doc=doc,login=login,url="%s%s"%(settings.IDTRACKER_BASE_URL,doc.get_absolute_url()),),
|
||||
context = dict(doc=doc,by=by,url="%s%s"%(settings.IDTRACKER_BASE_URL,doc.get_absolute_url()),),
|
||||
extra = extra)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
|
@ -616,8 +606,6 @@ def edit_info(request, name):
|
|||
if doc.get_state_slug() == "expired":
|
||||
raise Http404
|
||||
|
||||
login = request.user.person
|
||||
|
||||
new_document = False
|
||||
if not doc.get_state("draft-iesg"): # FIXME: should probably receive "new document" as argument to view instead of this
|
||||
new_document = True
|
||||
|
@ -632,27 +620,26 @@ def edit_info(request, name):
|
|||
initial=dict(ad=doc.ad_id,
|
||||
telechat_date=initial_telechat_date))
|
||||
if form.is_valid():
|
||||
save_document_in_history(doc)
|
||||
|
||||
by = request.user.person
|
||||
|
||||
r = form.cleaned_data
|
||||
events = []
|
||||
|
||||
if new_document:
|
||||
doc.set_state(r['create_in_state'])
|
||||
|
||||
# Is setting the WG state here too much of a hidden side-effect?
|
||||
if r['create_in_state'].slug=='pub-req':
|
||||
if doc.stream and ( doc.stream.slug=='ietf' ) and doc.group and ( doc.group.type.name=='WG'):
|
||||
if doc.stream and doc.stream.slug=='ietf' and doc.group and doc.group.type_id == 'wg':
|
||||
submitted_state = State.objects.get(type='draft-stream-ietf',slug='sub-pub')
|
||||
doc.set_state(submitted_state)
|
||||
e = DocEvent()
|
||||
e.type = "changed_document"
|
||||
e.by = login
|
||||
e.by = by
|
||||
e.doc = doc
|
||||
e.desc = "Working group state set to %s" % submitted_state.name
|
||||
e.save()
|
||||
|
||||
# fix so Django doesn't barf in the diff below because these
|
||||
# fields can't be NULL
|
||||
doc.ad = r['ad']
|
||||
events.append(e)
|
||||
|
||||
replaces = Document.objects.filter(docalias__relateddocument__source=doc, docalias__relateddocument__relationship="replaces")
|
||||
if replaces:
|
||||
|
@ -664,14 +651,16 @@ def edit_info(request, name):
|
|||
e.doc = doc
|
||||
e.desc = "Earlier history may be found in the Comment Log for <a href=\"%s\">%s</a>" % (replaces[0], replaces[0].get_absolute_url())
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
e = DocEvent()
|
||||
e.type = "started_iesg_process"
|
||||
e.by = login
|
||||
e.by = by
|
||||
e.doc = doc
|
||||
e.desc = "IESG process started in state <b>%s</b>" % doc.get_state("draft-iesg").name
|
||||
e.save()
|
||||
|
||||
events.append(e)
|
||||
|
||||
changes = []
|
||||
|
||||
def desc(attr, new, old):
|
||||
|
@ -716,21 +705,20 @@ def edit_info(request, name):
|
|||
doc.group = r["area"]
|
||||
|
||||
for c in changes:
|
||||
e = DocEvent(doc=doc, by=login)
|
||||
e.desc = c
|
||||
e.type = "changed_document"
|
||||
e.save()
|
||||
events.append(DocEvent.objects.create(doc=doc, by=by, desc=c, type="changed_document"))
|
||||
|
||||
# Todo - chase this
|
||||
update_telechat(request, doc, login,
|
||||
r['telechat_date'], r['returning_item'])
|
||||
e = update_telechat(request, doc, by,
|
||||
r['telechat_date'], r['returning_item'])
|
||||
|
||||
doc.time = datetime.datetime.now()
|
||||
if e:
|
||||
events.append(e)
|
||||
|
||||
doc.save_with_history(events)
|
||||
|
||||
if changes:
|
||||
email_iesg_processing_document(request, doc, changes)
|
||||
|
||||
doc.save()
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
else:
|
||||
init = dict(intended_std_level=doc.intended_std_level_id,
|
||||
|
@ -754,7 +742,6 @@ def edit_info(request, name):
|
|||
dict(doc=doc,
|
||||
form=form,
|
||||
user=request.user,
|
||||
login=login,
|
||||
ballot_issued=doc.latest_event(type="sent_ballot_announcement")),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
@ -765,12 +752,12 @@ def request_resurrect(request, name):
|
|||
if doc.get_state_slug() != "expired":
|
||||
raise Http404
|
||||
|
||||
login = request.user.person
|
||||
|
||||
if request.method == 'POST':
|
||||
email_resurrect_requested(request, doc, login)
|
||||
by = request.user.person
|
||||
|
||||
email_resurrect_requested(request, doc, by)
|
||||
|
||||
e = DocEvent(doc=doc, by=login)
|
||||
e = DocEvent(doc=doc, by=by)
|
||||
e.type = "requested_resurrect"
|
||||
e.desc = "Resurrection was requested"
|
||||
e.save()
|
||||
|
@ -789,24 +776,22 @@ def resurrect(request, name):
|
|||
if doc.get_state_slug() != "expired":
|
||||
raise Http404
|
||||
|
||||
login = request.user.person
|
||||
|
||||
if request.method == 'POST':
|
||||
save_document_in_history(doc)
|
||||
|
||||
e = doc.latest_event(type__in=('requested_resurrect', "completed_resurrect"))
|
||||
if e and e.type == 'requested_resurrect':
|
||||
email_resurrection_completed(request, doc, requester=e.by)
|
||||
|
||||
e = DocEvent(doc=doc, by=login)
|
||||
events = []
|
||||
e = DocEvent(doc=doc, by=request.user.person)
|
||||
e.type = "completed_resurrect"
|
||||
e.desc = "Resurrection was completed"
|
||||
e.save()
|
||||
|
||||
events.append(e)
|
||||
|
||||
doc.set_state(State.objects.get(used=True, type="draft", slug="active"))
|
||||
doc.expires = datetime.datetime.now() + datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
|
||||
doc.time = datetime.datetime.now()
|
||||
doc.save()
|
||||
doc.save_with_history(events)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
|
||||
return render_to_response('doc/draft/resurrect.html',
|
||||
|
@ -818,7 +803,7 @@ class IESGNoteForm(forms.Form):
|
|||
note = forms.CharField(widget=forms.Textarea, label="IESG note", required=False)
|
||||
|
||||
def clean_note(self):
|
||||
# not muning the database content to use html line breaks --
|
||||
# not munging the database content to use html line breaks --
|
||||
# that has caused a lot of pain in the past.
|
||||
return self.cleaned_data['note'].replace('\r', '').strip()
|
||||
|
||||
|
@ -844,13 +829,13 @@ def edit_iesg_note(request, name):
|
|||
else:
|
||||
log_message = "Note added '%s'" % new_note
|
||||
|
||||
doc.note = new_note
|
||||
doc.save()
|
||||
|
||||
c = DocEvent(type="added_comment", doc=doc, by=login)
|
||||
c.desc = log_message
|
||||
c.save()
|
||||
|
||||
doc.note = new_note
|
||||
doc.save_with_history([c])
|
||||
|
||||
return redirect('doc_view', name=doc.name)
|
||||
else:
|
||||
form = IESGNoteForm(initial=initial)
|
||||
|
@ -957,27 +942,24 @@ def edit_shepherd(request, name):
|
|||
if form.is_valid():
|
||||
|
||||
if form.cleaned_data['shepherd'] != doc.shepherd:
|
||||
events = []
|
||||
|
||||
save_document_in_history(doc)
|
||||
|
||||
doc.shepherd = form.cleaned_data['shepherd']
|
||||
doc.save()
|
||||
|
||||
|
||||
c = DocEvent(type="added_comment", doc=doc, by=request.user.person)
|
||||
c.desc = "Document shepherd changed to "+ (doc.shepherd.person.name if doc.shepherd else "(None)")
|
||||
c.save()
|
||||
events.append(c)
|
||||
|
||||
if doc.shepherd and (doc.shepherd.formatted_email() not in doc.notify):
|
||||
login = request.user.person
|
||||
addrs = doc.notify
|
||||
if addrs:
|
||||
addrs += ', '
|
||||
addrs += doc.shepherd.formatted_email()
|
||||
make_notify_changed_event(request, doc, login, addrs, c.time)
|
||||
events.append(make_notify_changed_event(request, doc, request.user.person, addrs, c.time))
|
||||
doc.notify = addrs
|
||||
|
||||
doc.time = c.time
|
||||
doc.save()
|
||||
doc.save_with_history(events)
|
||||
|
||||
else:
|
||||
messages.info(request,"The selected shepherd was already assigned - no changes have been made.")
|
||||
|
@ -1016,14 +998,15 @@ def change_shepherd_email(request, name):
|
|||
form = ChangeShepherdEmailForm(request.POST, initial=initial)
|
||||
if form.is_valid():
|
||||
if form.cleaned_data['shepherd'] != doc.shepherd:
|
||||
save_document_in_history(doc)
|
||||
|
||||
doc.shepherd = form.cleaned_data['shepherd']
|
||||
doc.save()
|
||||
|
||||
|
||||
events = []
|
||||
c = DocEvent(type="added_comment", doc=doc, by=request.user.person)
|
||||
c.desc = "Document shepherd email changed"
|
||||
c.save()
|
||||
events.append(c)
|
||||
|
||||
doc.save_with_history(events)
|
||||
else:
|
||||
messages.info(request,"The selected shepherd address was already assigned - no changes have been made.")
|
||||
|
||||
|
@ -1059,15 +1042,14 @@ def edit_ad(request, name):
|
|||
if request.method == 'POST':
|
||||
form = AdForm(request.POST)
|
||||
if form.is_valid():
|
||||
|
||||
doc.ad = form.cleaned_data['ad']
|
||||
doc.save()
|
||||
|
||||
login = request.user.person
|
||||
c = DocEvent(type="added_comment", doc=doc, by=login)
|
||||
|
||||
c = DocEvent(type="added_comment", doc=doc, by=request.user.person)
|
||||
c.desc = "Shepherding AD changed to "+doc.ad.name
|
||||
c.save()
|
||||
|
||||
doc.save_with_history([c])
|
||||
|
||||
return redirect('doc_view', name=doc.name)
|
||||
|
||||
else:
|
||||
|
@ -1143,6 +1125,8 @@ def request_publication(request, name):
|
|||
if request.method == 'POST' and not request.POST.get("reset"):
|
||||
form = PublicationForm(request.POST)
|
||||
if form.is_valid():
|
||||
events = []
|
||||
|
||||
if not request.REQUEST.get("skiprfceditorpost"):
|
||||
# start by notifying the RFC Editor
|
||||
import ietf.sync.rfceditor
|
||||
|
@ -1171,14 +1155,16 @@ def request_publication(request, name):
|
|||
e = DocEvent(doc=doc, type="requested_publication", by=request.user.person)
|
||||
e.desc = "Sent request for publication to the RFC Editor"
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
# change state
|
||||
prev_state = doc.get_state(next_state.type_id)
|
||||
if next_state != prev_state:
|
||||
doc.set_state(next_state)
|
||||
e = add_state_change_event(doc, request.user.person, prev_state, next_state)
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
if e:
|
||||
events.append(e)
|
||||
doc.save_with_history(events)
|
||||
|
||||
return redirect('doc_view', name=doc.name)
|
||||
|
||||
|
@ -1247,10 +1233,7 @@ def adopt_draft(request, name):
|
|||
if form.is_valid():
|
||||
# adopt
|
||||
by = request.user.person
|
||||
|
||||
save_document_in_history(doc)
|
||||
|
||||
doc.time = datetime.datetime.now()
|
||||
events = []
|
||||
|
||||
group = form.cleaned_data["group"]
|
||||
if group.type.slug == "rg":
|
||||
|
@ -1267,6 +1250,7 @@ def adopt_draft(request, name):
|
|||
if doc.stream:
|
||||
e.desc += u" from %s" % doc.stream.name
|
||||
e.save()
|
||||
events.append(e)
|
||||
old_stream = doc.stream
|
||||
doc.stream = new_stream
|
||||
if old_stream != None:
|
||||
|
@ -1279,14 +1263,13 @@ def adopt_draft(request, name):
|
|||
if doc.group.type_id != "individ":
|
||||
e.desc += " from %s (%s)" % (doc.group.name, doc.group.acronym.upper())
|
||||
e.save()
|
||||
events.append(e)
|
||||
doc.group = group
|
||||
|
||||
new_notify = get_initial_notify(doc,extra=doc.notify)
|
||||
make_notify_changed_event(request, doc, by, new_notify, doc.time)
|
||||
events.append(make_notify_changed_event(request, doc, by, new_notify, doc.time))
|
||||
doc.notify = new_notify
|
||||
|
||||
doc.save()
|
||||
|
||||
comment = form.cleaned_data["comment"].strip()
|
||||
|
||||
# state
|
||||
|
@ -1294,6 +1277,7 @@ def adopt_draft(request, name):
|
|||
if new_state != prev_state:
|
||||
doc.set_state(new_state)
|
||||
e = add_state_change_event(doc, by, prev_state, new_state, timestamp=doc.time)
|
||||
events.append(e)
|
||||
|
||||
due_date = None
|
||||
if form.cleaned_data["weeks"] != None:
|
||||
|
@ -1308,6 +1292,9 @@ def adopt_draft(request, name):
|
|||
e = DocEvent(type="added_comment", time=doc.time, by=by, doc=doc)
|
||||
e.desc = comment
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
doc.save_with_history(events)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
else:
|
||||
|
@ -1383,10 +1370,8 @@ def change_stream_state(request, name, state_type):
|
|||
form = ChangeStreamStateForm(request.POST, doc=doc, state_type=state_type)
|
||||
if form.is_valid():
|
||||
by = request.user.person
|
||||
events = []
|
||||
|
||||
save_document_in_history(doc)
|
||||
|
||||
doc.time = datetime.datetime.now()
|
||||
comment = form.cleaned_data["comment"].strip()
|
||||
|
||||
# state
|
||||
|
@ -1394,6 +1379,7 @@ def change_stream_state(request, name, state_type):
|
|||
if new_state != prev_state:
|
||||
doc.set_state(new_state)
|
||||
e = add_state_change_event(doc, by, prev_state, new_state, timestamp=doc.time)
|
||||
events.append(e)
|
||||
|
||||
due_date = None
|
||||
if form.cleaned_data["weeks"] != None:
|
||||
|
@ -1420,6 +1406,7 @@ def change_stream_state(request, name, state_type):
|
|||
l.append(u"Tag%s %s cleared." % (pluralize(removed_tags), ", ".join(t.name for t in removed_tags)))
|
||||
e.desc = " ".join(l)
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
email_stream_tags_changed(request, doc, added_tags, removed_tags, by, comment)
|
||||
|
||||
|
@ -1428,6 +1415,9 @@ def change_stream_state(request, name, state_type):
|
|||
e = DocEvent(type="added_comment", time=doc.time, by=by, doc=doc)
|
||||
e.desc = comment
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
doc.save_with_history(events)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
else:
|
||||
|
|
|
@ -12,6 +12,9 @@ def state_help(request, type):
|
|||
"draft-rfceditor": ("draft-rfceditor", "RFC Editor States for Internet-Drafts"),
|
||||
"draft-iana-action": ("draft-iana-action", "IANA Action States for Internet-Drafts"),
|
||||
"draft-stream-ietf": ("draft-stream-ietf", "IETF Stream States for Internet-Drafts"),
|
||||
"draft-stream-irtf": ("draft-stream-irtf", "IRTF Stream States for Internet-Drafts"),
|
||||
"draft-stream-ise": ("draft-stream-ise", "ISE Stream States for Internet-Drafts"),
|
||||
"draft-stream-iab": ("draft-stream-iab", "IAB Stream States for Internet-Drafts"),
|
||||
"charter": ("charter", "Charter States"),
|
||||
"conflict-review": ("conflrev", "Conflict Review States"),
|
||||
"status-change": ("statchg", "RFC Status Change States"),
|
||||
|
|
|
@ -13,7 +13,7 @@ from django.core.urlresolvers import reverse as urlreverse
|
|||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.models import Document, DocAlias, DocTypeName, DocEvent, State
|
||||
from ietf.doc.models import NewRevisionDocEvent, save_document_in_history
|
||||
from ietf.doc.models import NewRevisionDocEvent
|
||||
from ietf.doc.utils import add_state_change_event, check_common_doc_name_rules
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.utils import can_manage_materials
|
||||
|
@ -104,15 +104,17 @@ def edit_material(request, name=None, acronym=None, action=None, doc_type=None):
|
|||
form = UploadMaterialForm(document_type, action, group, doc, request.POST, request.FILES)
|
||||
|
||||
if form.is_valid():
|
||||
events = []
|
||||
|
||||
if action == "new":
|
||||
doc = Document()
|
||||
doc.type = document_type
|
||||
doc.group = group
|
||||
doc.rev = "00"
|
||||
doc.name = form.cleaned_data["name"]
|
||||
doc = Document.objects.create(
|
||||
type=document_type,
|
||||
group=group,
|
||||
rev="00",
|
||||
name=form.cleaned_data["name"])
|
||||
|
||||
prev_rev = None
|
||||
else:
|
||||
save_document_in_history(doc)
|
||||
prev_rev = doc.rev
|
||||
|
||||
prev_title = doc.title
|
||||
|
@ -124,8 +126,6 @@ def edit_material(request, name=None, acronym=None, action=None, doc_type=None):
|
|||
if "abstract" in form.cleaned_data:
|
||||
doc.abstract = form.cleaned_data["abstract"]
|
||||
|
||||
doc.time = datetime.datetime.now()
|
||||
|
||||
if "material" in form.fields:
|
||||
if action != "new":
|
||||
doc.rev = "%02d" % (int(doc.rev) + 1)
|
||||
|
@ -137,8 +137,6 @@ def edit_material(request, name=None, acronym=None, action=None, doc_type=None):
|
|||
for chunk in f.chunks():
|
||||
dest.write(chunk)
|
||||
|
||||
doc.save()
|
||||
|
||||
if action == "new":
|
||||
DocAlias.objects.get_or_create(name=doc.name, document=doc)
|
||||
|
||||
|
@ -148,7 +146,8 @@ def edit_material(request, name=None, acronym=None, action=None, doc_type=None):
|
|||
e.by = request.user.person
|
||||
e.desc = "New version available: <b>%s-%s</b>" % (doc.name, doc.rev)
|
||||
e.save()
|
||||
|
||||
events.append(e)
|
||||
|
||||
if prev_title != doc.title:
|
||||
e = DocEvent(doc=doc, by=request.user.person, type='changed_document')
|
||||
e.desc = u"Changed title to <b>%s</b>" % doc.title
|
||||
|
@ -156,10 +155,15 @@ def edit_material(request, name=None, acronym=None, action=None, doc_type=None):
|
|||
e.desc += u" from %s" % prev_title
|
||||
e.time = doc.time
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
if "state" in form.cleaned_data and form.cleaned_data["state"] != prev_state:
|
||||
doc.set_state(form.cleaned_data["state"])
|
||||
add_state_change_event(doc, request.user.person, prev_state, form.cleaned_data["state"])
|
||||
e = add_state_change_event(doc, request.user.person, prev_state, form.cleaned_data["state"])
|
||||
events.append(e)
|
||||
|
||||
if events:
|
||||
doc.save_with_history(events)
|
||||
|
||||
return redirect("doc_view", name=doc.name)
|
||||
else:
|
||||
|
|
|
@ -9,8 +9,7 @@ from django.template.loader import render_to_string
|
|||
from django.conf import settings
|
||||
|
||||
from ietf.doc.models import ( Document, DocAlias, State, DocEvent, BallotDocEvent,
|
||||
BallotPositionDocEvent, NewRevisionDocEvent, WriteupDocEvent,
|
||||
save_document_in_history, STATUSCHANGE_RELATIONS )
|
||||
BallotPositionDocEvent, NewRevisionDocEvent, WriteupDocEvent, STATUSCHANGE_RELATIONS )
|
||||
from ietf.doc.forms import AdForm
|
||||
from ietf.doc.lastcall import request_last_call
|
||||
from ietf.doc.utils import get_document_content, add_state_change_event, update_telechat, close_open_ballots, create_ballot_if_not_open
|
||||
|
@ -51,16 +50,13 @@ def change_state(request, name, option=None):
|
|||
|
||||
prev_state = status_change.get_state()
|
||||
if new_state != prev_state:
|
||||
save_document_in_history(status_change)
|
||||
|
||||
status_change.set_state(new_state)
|
||||
e = add_state_change_event(status_change, login, prev_state, new_state)
|
||||
|
||||
status_change.time = e.time
|
||||
status_change.save()
|
||||
events = []
|
||||
events.append(add_state_change_event(status_change, login, prev_state, new_state))
|
||||
status_change.save_with_history(events)
|
||||
|
||||
if new_state.slug == "iesgeval":
|
||||
create_ballot_if_not_open(status_change, login, "statchg", e.time)
|
||||
create_ballot_if_not_open(status_change, login, "statchg", status_change.time)
|
||||
ballot = status_change.latest_event(BallotDocEvent, type="created_ballot")
|
||||
if has_role(request.user, "Area Director") and not status_change.latest_event(BallotPositionDocEvent, ad=login, ballot=ballot, type="changed_ballot_position"):
|
||||
|
||||
|
@ -151,20 +147,19 @@ def submit(request, name):
|
|||
if "submit_response" in request.POST:
|
||||
form = UploadForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
save_document_in_history(doc)
|
||||
|
||||
doc.rev = next_rev
|
||||
|
||||
events = []
|
||||
e = NewRevisionDocEvent(doc=doc, by=login, type="new_revision")
|
||||
e.desc = "New version available: <b>%s-%s.txt</b>" % (doc.canonical_name(), doc.rev)
|
||||
e.rev = doc.rev
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
# Save file on disk
|
||||
form.save(doc)
|
||||
|
||||
doc.time = datetime.datetime.now()
|
||||
doc.save()
|
||||
doc.save_with_history(events)
|
||||
|
||||
return redirect('doc_view', name=doc.name)
|
||||
|
||||
|
@ -218,13 +213,13 @@ def edit_title(request, name):
|
|||
if form.is_valid():
|
||||
|
||||
status_change.title = form.cleaned_data['title']
|
||||
status_change.save()
|
||||
|
||||
login = request.user.person
|
||||
c = DocEvent(type="added_comment", doc=status_change, by=login)
|
||||
|
||||
c = DocEvent(type="added_comment", doc=status_change, by=request.user.person)
|
||||
c.desc = "Title changed to '%s'"%status_change.title
|
||||
c.save()
|
||||
|
||||
status_change.save_with_history([c])
|
||||
|
||||
return redirect("doc_view", name=status_change.name)
|
||||
|
||||
else:
|
||||
|
@ -248,15 +243,14 @@ def edit_ad(request, name):
|
|||
if request.method == 'POST':
|
||||
form = AdForm(request.POST)
|
||||
if form.is_valid():
|
||||
|
||||
status_change.ad = form.cleaned_data['ad']
|
||||
status_change.save()
|
||||
|
||||
login = request.user.person
|
||||
c = DocEvent(type="added_comment", doc=status_change, by=login)
|
||||
|
||||
c = DocEvent(type="added_comment", doc=status_change, by=request.user.person)
|
||||
c.desc = "Shepherding AD changed to "+status_change.ad.name
|
||||
c.save()
|
||||
|
||||
status_change.save_with_history([c])
|
||||
|
||||
return redirect("doc_view", name=status_change.name)
|
||||
|
||||
else:
|
||||
|
@ -339,13 +333,13 @@ def approve(request, name):
|
|||
|
||||
if formset.is_valid():
|
||||
|
||||
save_document_in_history(status_change)
|
||||
|
||||
prev_state = status_change.get_state()
|
||||
new_state = State.objects.get(type='statchg', slug='appr-sent')
|
||||
|
||||
status_change.set_state(new_state)
|
||||
add_state_change_event(status_change, login, prev_state, new_state)
|
||||
|
||||
events = []
|
||||
events.append(add_state_change_event(status_change, login, prev_state, new_state))
|
||||
|
||||
close_open_ballots(status_change, login)
|
||||
|
||||
|
@ -353,9 +347,9 @@ def approve(request, name):
|
|||
e.type = "iesg_approved"
|
||||
e.desc = "IESG has approved the status change"
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
status_change.time = e.time
|
||||
status_change.save()
|
||||
status_change.save_with_history(events)
|
||||
|
||||
|
||||
for form in formset.forms:
|
||||
|
@ -524,16 +518,16 @@ def start_rfc_status_change(request,name):
|
|||
|
||||
iesg_group = Group.objects.get(acronym='iesg')
|
||||
|
||||
status_change=Document( type_id = "statchg",
|
||||
name = 'status-change-'+form.cleaned_data['document_name'],
|
||||
title = form.cleaned_data['title'],
|
||||
rev = "00",
|
||||
ad = form.cleaned_data['ad'],
|
||||
notify = form.cleaned_data['notify'],
|
||||
stream_id = 'ietf',
|
||||
group = iesg_group,
|
||||
)
|
||||
status_change.save()
|
||||
status_change = Document.objects.create(
|
||||
type_id="statchg",
|
||||
name='status-change-'+form.cleaned_data['document_name'],
|
||||
title=form.cleaned_data['title'],
|
||||
rev="00",
|
||||
ad=form.cleaned_data['ad'],
|
||||
notify=form.cleaned_data['notify'],
|
||||
stream_id='ietf',
|
||||
group=iesg_group,
|
||||
)
|
||||
status_change.set_state(form.cleaned_data['create_in_state'])
|
||||
|
||||
DocAlias.objects.create( name= 'status-change-'+form.cleaned_data['document_name'], document=status_change )
|
||||
|
@ -662,6 +656,8 @@ def last_call(request, name):
|
|||
if "save_last_call_text" in request.POST or "send_last_call_request" in request.POST:
|
||||
form = LastCallTextForm(request.POST)
|
||||
if form.is_valid():
|
||||
events = []
|
||||
|
||||
t = form.cleaned_data['last_call_text']
|
||||
if t != last_call_event.text:
|
||||
e = WriteupDocEvent(doc=status_change, by=login)
|
||||
|
@ -671,17 +667,19 @@ def last_call(request, name):
|
|||
e.text = t
|
||||
e.save()
|
||||
|
||||
if "send_last_call_request" in request.POST:
|
||||
save_document_in_history(status_change)
|
||||
events.append(e)
|
||||
|
||||
if "send_last_call_request" in request.POST:
|
||||
prev_state = status_change.get_state()
|
||||
new_state = State.objects.get(type='statchg', slug='lc-req')
|
||||
|
||||
status_change.set_state(new_state)
|
||||
e = add_state_change_event(status_change, login, prev_state, new_state)
|
||||
if e:
|
||||
events.append(e)
|
||||
|
||||
status_change.time = (e and e.time) or datetime.datetime.now()
|
||||
status_change.save()
|
||||
if events:
|
||||
status_change.save_with_history(events)
|
||||
|
||||
request_last_call(request, status_change)
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from django.conf.urls import patterns
|
||||
from django.views.generic import RedirectView
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.doc.feeds import DocumentChangesFeed, InLastCallFeed
|
||||
from ietf.group.feeds import GroupChangesFeed
|
||||
|
@ -11,9 +12,9 @@ from ietf.meeting.feeds import LatestMeetingMaterialFeed
|
|||
urlpatterns = patterns(
|
||||
'',
|
||||
(r'^comments/(?P<remainder>.*)/$', RedirectView.as_view(url='/feed/document-changes/%(remainder)s/')),
|
||||
(r'^document-changes/(?P<name>[A-Za-z0-9._+-]+)/$', DocumentChangesFeed()),
|
||||
(r'^document-changes/%(name)s/$' % settings.URL_REGEXPS, DocumentChangesFeed()),
|
||||
(r'^last-call/$', InLastCallFeed()),
|
||||
(r'^group-changes/(?P<acronym>[a-zA-Z0-9-]+)/$', GroupChangesFeed()),
|
||||
(r'^group-changes/%(acronym)s/$' % settings.URL_REGEXPS, GroupChangesFeed()),
|
||||
(r'^iesg-agenda/$', IESGAgendaFeed()),
|
||||
(r'^ipr/$', LatestIprDisclosuresFeed()),
|
||||
(r'^liaison/(?P<kind>recent|from|to|subject)/(?:(?P<search>[^/]+)/)?$', LiaisonStatementsFeed()),
|
||||
|
|
|
@ -11,7 +11,7 @@ from django.contrib.auth.decorators import login_required
|
|||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.models import Document, DocAlias, DocTagName, State
|
||||
from ietf.doc.models import DocTagName, State
|
||||
from ietf.doc.utils import get_tags_for_stream_id
|
||||
from ietf.doc.utils_charter import charter_name_for_group
|
||||
from ietf.group.models import ( Group, Role, GroupEvent, GroupHistory, GroupStateName,
|
||||
|
@ -143,58 +143,6 @@ def format_urls(urls, fs="\n"):
|
|||
res.append(u.url)
|
||||
return fs.join(res)
|
||||
|
||||
def get_or_create_initial_charter(group, group_type):
|
||||
charter_name = charter_name_for_group(group)
|
||||
|
||||
try:
|
||||
charter = Document.objects.get(docalias__name=charter_name)
|
||||
except Document.DoesNotExist:
|
||||
charter = Document(
|
||||
name=charter_name,
|
||||
type_id="charter",
|
||||
title=group.name,
|
||||
group=group,
|
||||
abstract=group.name,
|
||||
rev="00-00",
|
||||
)
|
||||
charter.save()
|
||||
charter.set_state(State.objects.get(used=True, type="charter", slug="notrev"))
|
||||
|
||||
# Create an alias as well
|
||||
DocAlias.objects.create(name=charter.name, document=charter)
|
||||
|
||||
return charter
|
||||
|
||||
@login_required
|
||||
def submit_initial_charter(request, group_type=None, acronym=None):
|
||||
|
||||
# This needs refactoring.
|
||||
# The signature assumed you could have groups with the same name, but with different types, which we do not allow.
|
||||
# Consequently, this can be called with an existing group acronym and a type
|
||||
# that doesn't match the existing group type. The code below essentially ignores the group_type argument.
|
||||
#
|
||||
# If possible, the use of get_or_create_initial_charter should be moved
|
||||
# directly into charter_submit, and this function should go away.
|
||||
|
||||
if acronym==None:
|
||||
raise Http404
|
||||
|
||||
group = get_object_or_404(Group, acronym=acronym)
|
||||
if not group.features.has_chartering_process:
|
||||
raise Http404
|
||||
|
||||
# This is where we start ignoring the passed in group_type
|
||||
group_type = group.type_id
|
||||
|
||||
if not can_manage_group_type(request.user, group_type):
|
||||
return HttpResponseForbidden("You don't have permission to access this view")
|
||||
|
||||
if not group.charter:
|
||||
group.charter = get_or_create_initial_charter(group, group_type)
|
||||
group.save()
|
||||
|
||||
return redirect('charter_submit', name=group.charter.name, option="initcharter")
|
||||
|
||||
@login_required
|
||||
def edit(request, group_type=None, acronym=None, action="edit"):
|
||||
"""Edit or create a group, notifying parties as
|
||||
|
@ -241,9 +189,6 @@ def edit(request, group_type=None, acronym=None, action="edit"):
|
|||
save_group_in_history(group)
|
||||
|
||||
|
||||
if action == "charter" and not group.charter: # make sure we have a charter
|
||||
group.charter = get_or_create_initial_charter(group, group_type)
|
||||
|
||||
changes = []
|
||||
|
||||
def desc(attr, new, old):
|
||||
|
@ -324,7 +269,7 @@ def edit(request, group_type=None, acronym=None, action="edit"):
|
|||
group.save()
|
||||
|
||||
if action=="charter":
|
||||
return redirect('charter_submit', name=group.charter.name, option="initcharter")
|
||||
return redirect('charter_submit', name=charter_name_for_group(group), option="initcharter")
|
||||
|
||||
return HttpResponseRedirect(group.about_url())
|
||||
else: # form.is_valid()
|
||||
|
|
|
@ -50,6 +50,7 @@ from django.utils.safestring import mark_safe
|
|||
from ietf.doc.views_search import SearchForm, retrieve_search_results, get_doc_is_tracked
|
||||
from ietf.doc.models import Document, State, DocAlias, RelatedDocument
|
||||
from ietf.doc.utils import get_chartering_type
|
||||
from ietf.doc.utils_charter import charter_name_for_group
|
||||
from ietf.doc.templatetags.ietf_filters import clean_whitespace
|
||||
from ietf.group.models import Group, Role, ChangeStateGroupEvent
|
||||
from ietf.name.models import GroupTypeName
|
||||
|
@ -473,6 +474,9 @@ def group_about(request, acronym, group_type=None):
|
|||
requested_close = group.state_id != "conclude" and e and e.type == "requested_close"
|
||||
|
||||
can_manage = can_manage_group_type(request.user, group.type_id)
|
||||
charter_submit_url = ""
|
||||
if group.features.has_chartering_process:
|
||||
charter_submit_url = urlreverse("charter_submit", kwargs={ "name": charter_name_for_group(group) })
|
||||
|
||||
return render(request, 'group/group_about.html',
|
||||
construct_group_menu_context(request, group, "charter" if group.features.has_chartering_process else "about", group_type, {
|
||||
|
@ -480,6 +484,7 @@ def group_about(request, acronym, group_type=None):
|
|||
"milestone_reviewer": milestone_reviewer_for_group_type(group_type),
|
||||
"requested_close": requested_close,
|
||||
"can_manage": can_manage,
|
||||
"charter_submit_url": charter_submit_url
|
||||
}))
|
||||
|
||||
def get_group_email_aliases(acronym, group_type):
|
||||
|
|
119
ietf/group/migrations/0007_auto_20150930_0758.py
Normal file
119
ietf/group/migrations/0007_auto_20150930_0758.py
Normal file
|
@ -0,0 +1,119 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
import os, datetime
|
||||
|
||||
from django.db import migrations
|
||||
from django.conf import settings
|
||||
|
||||
def rename_x3s3dot3_forwards(apps, schema_editor):
|
||||
Group = apps.get_model("group", "Group")
|
||||
Group.objects.filter(acronym="x3s3.3").update(acronym="x3s3dot3")
|
||||
|
||||
def rename_x3s3dot3_backwards(apps, schema_editor):
|
||||
Group = apps.get_model("group", "Group")
|
||||
Group.objects.filter(acronym="x3s3dot3").update(acronym="x3s3.3")
|
||||
|
||||
def get_rid_of_empty_charters(apps, schema_editor):
|
||||
Group = apps.get_model("group", "Group")
|
||||
|
||||
for acronym in ["fun", "multrans", "cicm", "woes", "dcon", "sdn", "i2aex", "rpsreqs", "antitrust", "iprbis", "dsii"]:
|
||||
group = Group.objects.get(acronym=acronym)
|
||||
if group.charter:
|
||||
charter = group.charter
|
||||
|
||||
# clean up any empty files left behind
|
||||
revisions = set()
|
||||
revisions.add(charter.rev)
|
||||
for h in charter.history_set.all():
|
||||
revisions.add(h.rev)
|
||||
|
||||
for rev in revisions:
|
||||
path = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (charter.name, rev))
|
||||
try:
|
||||
if os.path.exists(path):
|
||||
with open(path, 'r') as f:
|
||||
if f.read() == "":
|
||||
os.remove(path)
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
group.charter = None
|
||||
group.save()
|
||||
|
||||
charter.delete()
|
||||
|
||||
|
||||
def fix_empty_rrg_charter(apps, schema_editor):
|
||||
Document = apps.get_model("doc", "Document")
|
||||
DocEvent = apps.get_model("doc", "DocEvent")
|
||||
NewRevisionDocEvent = apps.get_model("doc", "NewRevisionDocEvent")
|
||||
Person = apps.get_model("person", "Person")
|
||||
State = apps.get_model("doc", "State")
|
||||
|
||||
charter = Document.objects.get(name="charter-irtf-rrg")
|
||||
system = Person.objects.get(name="(System)")
|
||||
|
||||
if charter.rev == "00-00":
|
||||
charter.rev = "01"
|
||||
charter.time = datetime.datetime.now()
|
||||
charter.save()
|
||||
|
||||
NewRevisionDocEvent.objects.get_or_create(
|
||||
rev=charter.rev,
|
||||
doc=charter,
|
||||
type="new_revision",
|
||||
by=system,
|
||||
desc="New version available: <b>%s-%s.txt</b>" % (charter.name, charter.rev),
|
||||
defaults=dict(time=charter.time)
|
||||
)
|
||||
|
||||
DocEvent.objects.get_or_create(
|
||||
doc=charter,
|
||||
type="added_comment",
|
||||
by=system,
|
||||
desc="Added existing charter",
|
||||
defaults=dict(time=charter.time)
|
||||
)
|
||||
|
||||
approved = State.objects.get(type="charter", slug="approved")
|
||||
already_set = list(charter.states.filter(type="charter"))
|
||||
if already_set:
|
||||
charter.states.remove(*already_set)
|
||||
charter.states.add(approved)
|
||||
|
||||
path = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (charter.name, charter.rev))
|
||||
with open(path, "w") as f:
|
||||
f.write("""The Routing Research Group (RRG) is chartered to explore routing and addressing problems that are important to the development of the Internet but are not yet mature enough for engineering work within the IETF. As the Internet continues to evolve, the challenges in providing a scalable and robust global routing system will also change over time. At the moment, the Internet routing and addressing architecture is facing challenges in scalability, mobility, multi-homing, and inter-domain traffic engineering. Thus the RRG proposes to focus its effort on designing an alternate architecture to meet these challenges. Although Internet routing is a broad and active research area, a focused effort at this time is necessary to assure rapid progress towards reaching the goal.
|
||||
|
||||
More specifically, we propose to explore architectural alternatives, including, but not limited to, separating host location and identification information. Research and experimentation in addressing and routing algorithms will be encouraged to understand whether this new direction can provide effective solutions, to work out candidate designs as necessary for a complete solution, and to fully understand both the gains and the tradeoffs that the new solutions may bring. The group will produce a list of prioritized design goals and a recommendation for a routing and addressing architecture.
|
||||
|
||||
The RRG will have an open general discussion mailing list where any topic of interest to the routing research community can be discussed, and topics related to scalable routing architectures are particularly encouraged. For specific topics with widespread discussion, interested parties will be encouraged to form ad-hoc mailing lists, with summaries sent to the general mailing list quarterly. Summaries will contain the recent conclusions reached as well as the near-term agenda for future progress.
|
||||
|
||||
It is commonly recognized that productive design efforts can be carried out by small and focused design teams. The RRG encourages the formation of focused design teams to explore specific design choices. As with ad-hoc mailing lists, individual design teams are required to report back quarterly to the RRG with their progress and remaining open issues. Each design team is expected to produce a set of Internet Drafts that documents their current thinking.
|
||||
|
||||
The RRG, as a whole, will hold open meetings from time to time to solicit input from, and supply information to, the broader community. In particular, at least once per year there will be a review of the group's activities held at an IETF meeting. More frequent meetings will be held if it will speed group progress. Ad-hoc and design team meetings are strongly encouraged.
|
||||
|
||||
The output of the group will consist of Informational and Experimental RFCs as well as Journal Articles on the topics covered by the subgroups.""")
|
||||
|
||||
|
||||
|
||||
def fix_cicm_state(apps, schema_editor):
|
||||
Group = apps.get_model("group", "Group")
|
||||
Group.objects.filter(acronym="cicm").update(state="bof-conc")
|
||||
|
||||
def noop(apps, schema_editor):
|
||||
pass
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('doc', '0010_auto_20150930_0251'),
|
||||
('group', '0006_auto_20150718_0509'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(rename_x3s3dot3_forwards, rename_x3s3dot3_backwards),
|
||||
migrations.RunPython(fix_empty_rrg_charter, noop),
|
||||
migrations.RunPython(get_rid_of_empty_charters, noop),
|
||||
migrations.RunPython(fix_cicm_state, noop),
|
||||
]
|
|
@ -6,7 +6,9 @@ from django.core.urlresolvers import reverse as urlreverse
|
|||
from django.db.models import Q
|
||||
from django.test import Client
|
||||
|
||||
from ietf.doc.models import DocEvent
|
||||
from ietf.group.models import Role, Group
|
||||
from ietf.person.models import Person
|
||||
from ietf.utils.test_data import make_test_data
|
||||
from ietf.utils.test_utils import login_testing_unauthorized, TestCase
|
||||
|
||||
|
@ -33,7 +35,7 @@ class StreamTests(TestCase):
|
|||
def test_stream_documents(self):
|
||||
draft = make_test_data()
|
||||
draft.stream_id = "iab"
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_stream", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
r = self.client.get(urlreverse("ietf.group.views_stream.stream_documents", kwargs=dict(acronym="iab")))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
|
|
@ -13,10 +13,11 @@ from django.core.urlresolvers import reverse as urlreverse
|
|||
from django.core.urlresolvers import NoReverseMatch
|
||||
|
||||
from ietf.doc.models import Document, DocAlias, DocEvent, State
|
||||
from ietf.group.models import Group, GroupEvent, GroupMilestone, GroupStateTransitions
|
||||
from ietf.group.models import Group, GroupEvent, GroupMilestone, GroupStateTransitions
|
||||
from ietf.group.utils import save_group_in_history
|
||||
from ietf.name.models import DocTagName, GroupStateName, GroupTypeName
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.doc.utils_charter import charter_name_for_group
|
||||
from ietf.utils.test_utils import TestCase
|
||||
from ietf.utils.mail import outbox, empty_outbox
|
||||
from ietf.utils.test_data import make_test_data
|
||||
|
@ -374,8 +375,7 @@ class GroupEditTests(TestCase):
|
|||
self.assertEqual(len(Group.objects.filter(type="wg")), num_wgs + 1)
|
||||
group = Group.objects.get(acronym="testwg")
|
||||
self.assertEqual(group.name, "Testing WG")
|
||||
self.assertEqual(group.charter.name, "charter-ietf-testwg")
|
||||
self.assertEqual(group.charter.rev, "00-00")
|
||||
self.assertEqual(charter_name_for_group(group), "charter-ietf-testwg")
|
||||
|
||||
def test_create_rg(self):
|
||||
|
||||
|
@ -401,9 +401,7 @@ class GroupEditTests(TestCase):
|
|||
self.assertEqual(len(Group.objects.filter(type="rg")), num_rgs + 1)
|
||||
group = Group.objects.get(acronym="testrg")
|
||||
self.assertEqual(group.name, "Testing RG")
|
||||
self.assertEqual(group.charter.name, "charter-irtf-testrg")
|
||||
self.assertEqual(group.charter.rev, "00-00")
|
||||
self.assertEqual(group.parent.acronym,'irtf')
|
||||
self.assertEqual(charter_name_for_group(group), "charter-irtf-testrg")
|
||||
|
||||
def test_create_based_on_existing_bof(self):
|
||||
make_test_data()
|
||||
|
@ -515,19 +513,6 @@ class GroupEditTests(TestCase):
|
|||
for prefix in ['ad1','ad2','aread','marschairman','marsdelegate']:
|
||||
self.assertTrue(prefix+'@' in outbox[0]['To'])
|
||||
|
||||
def test_initial_charter(self):
|
||||
make_test_data()
|
||||
group = Group.objects.get(acronym="mars")
|
||||
for url in [ urlreverse('ietf.group.edit.submit_initial_charter', kwargs={'acronym':group.acronym}),
|
||||
urlreverse('ietf.group.edit.submit_initial_charter', kwargs={'acronym':group.acronym,'group_type':group.type_id}),
|
||||
]:
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
r = self.client.get(url,follow=True)
|
||||
self.assertEqual(r.status_code,200)
|
||||
self.assertTrue(r.redirect_chain[0][0].endswith(urlreverse('charter_submit',kwargs={'name':group.charter.name,'option':'initcharter'})))
|
||||
self.client.logout()
|
||||
|
||||
|
||||
def test_conclude(self):
|
||||
make_test_data()
|
||||
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
from django.conf.urls import patterns, include
|
||||
from django.conf import settings
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^$', 'ietf.group.info.active_groups'),
|
||||
(r'^groupmenu.json', 'ietf.group.ajax.group_menu_data', None, "group_menu_data"),
|
||||
(r'^(?P<acronym>[a-z0-9]+).json$', 'ietf.group.ajax.group_json'),
|
||||
(r'^%(acronym)s.json$' % settings.URL_REGEXPS, 'ietf.group.ajax.group_json'),
|
||||
(r'^chartering/$', 'ietf.group.info.chartering_groups'),
|
||||
(r'^chartering/create/(?P<group_type>(wg|rg))/$', 'ietf.group.edit.edit', {'action': "charter"}, "group_create"),
|
||||
(r'^concluded/$', 'ietf.group.info.concluded_groups'),
|
||||
(r'^email-aliases/$', 'ietf.group.info.email_aliases'),
|
||||
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/$', 'ietf.group.info.group_home', None, "group_home"),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/', include('ietf.group.urls_info_details')),
|
||||
(r'^%(acronym)s/$' % settings.URL_REGEXPS, 'ietf.group.info.group_home', None, "group_home"),
|
||||
(r'^%(acronym)s/' % settings.URL_REGEXPS, include('ietf.group.urls_info_details')),
|
||||
)
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.conf.urls import patterns, include
|
||||
from django.views.generic import RedirectView
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.group import info, edit
|
||||
|
||||
|
@ -19,5 +20,5 @@ urlpatterns = patterns('',
|
|||
(r'^bofs/$', info.bofs),
|
||||
(r'^email-aliases/$', 'ietf.group.info.email_aliases'),
|
||||
(r'^bofs/create/$', edit.edit, {'action': "create"}, "bof_create"),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/', include('ietf.group.urls_info_details')),
|
||||
(r'^%(acronym)s/' % settings.URL_REGEXPS, include('ietf.group.urls_info_details')),
|
||||
)
|
||||
|
|
|
@ -11,7 +11,6 @@ urlpatterns = patterns('',
|
|||
(r'^email/$', 'ietf.group.info.email'),
|
||||
(r'^deps/dot/$', 'ietf.group.info.dependencies_dot'),
|
||||
(r'^deps/pdf/$', 'ietf.group.info.dependencies_pdf'),
|
||||
(r'^init-charter/', 'ietf.group.edit.submit_initial_charter'),
|
||||
(r'^edit/$', 'ietf.group.edit.edit', {'action': "edit"}, "group_edit"),
|
||||
(r'^conclude/$', 'ietf.group.edit.conclude'),
|
||||
(r'^milestones/$', 'ietf.group.milestones.edit_milestones', {'milestone_set': "current"}, "group_edit_milestones"),
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# Copyright The IETF Trust 2008, All Rights Reserved
|
||||
|
||||
from django.conf.urls import patterns
|
||||
from django.conf import settings
|
||||
|
||||
import views_stream
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^$', views_stream.streams),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/$', views_stream.stream_documents, None),
|
||||
(r'^(?P<acronym>[a-zA-Z0-9-]+)/edit/$', views_stream.stream_edit),
|
||||
(r'^%(acronym)s/$' % settings.URL_REGEXPS, views_stream.stream_documents, None),
|
||||
(r'^%(acronym)s/edit/$' % settings.URL_REGEXPS, views_stream.stream_edit),
|
||||
)
|
||||
|
|
|
@ -71,7 +71,7 @@ class IESGAgendaTests(TestCase):
|
|||
|
||||
ise_draft = Document.objects.get(name="draft-imaginary-independent-submission")
|
||||
ise_draft.stream = StreamName.objects.get(slug="ise")
|
||||
ise_draft.save()
|
||||
ise_draft.save_with_history([DocEvent(doc=ise_draft, type="changed_stream", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
self.telechat_docs = {
|
||||
"ietf_draft": Document.objects.get(name="draft-ietf-mars-test"),
|
||||
|
@ -120,7 +120,7 @@ class IESGAgendaTests(TestCase):
|
|||
# 2.1 protocol WG submissions
|
||||
draft.intended_std_level_id = "ps"
|
||||
draft.group = Group.objects.get(acronym="mars")
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_group", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="iesg-eva"))
|
||||
self.assertTrue(draft in agenda_data(date_str)["sections"]["2.1.1"]["docs"])
|
||||
|
||||
|
@ -135,7 +135,7 @@ class IESGAgendaTests(TestCase):
|
|||
|
||||
# 2.2 protocol individual submissions
|
||||
draft.group = Group.objects.get(type="individ")
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_group", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="iesg-eva"))
|
||||
self.assertTrue(draft in agenda_data(date_str)["sections"]["2.2.1"]["docs"])
|
||||
|
||||
|
@ -151,7 +151,7 @@ class IESGAgendaTests(TestCase):
|
|||
# 3.1 document WG submissions
|
||||
draft.intended_std_level_id = "inf"
|
||||
draft.group = Group.objects.get(acronym="mars")
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_group", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="iesg-eva"))
|
||||
self.assertTrue(draft in agenda_data(date_str)["sections"]["3.1.1"]["docs"])
|
||||
|
||||
|
@ -166,7 +166,7 @@ class IESGAgendaTests(TestCase):
|
|||
|
||||
# 3.2 document individual submissions
|
||||
draft.group = Group.objects.get(type="individ")
|
||||
draft.save()
|
||||
draft.save_with_history([DocEvent.objects.create(doc=draft, type="changed_group", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="iesg-eva"))
|
||||
self.assertTrue(draft in agenda_data(date_str)["sections"]["3.2.1"]["docs"])
|
||||
|
||||
|
@ -189,7 +189,7 @@ class IESGAgendaTests(TestCase):
|
|||
relationship_id="tohist")
|
||||
|
||||
statchg.group = Group.objects.get(acronym="mars")
|
||||
statchg.save()
|
||||
statchg.save_with_history([DocEvent.objects.create(doc=statchg, type="changed_group", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
statchg.set_state(State.objects.get(type="statchg", slug="iesgeval"))
|
||||
self.assertTrue(statchg in agenda_data(date_str)["sections"]["2.3.1"]["docs"])
|
||||
|
||||
|
@ -207,7 +207,7 @@ class IESGAgendaTests(TestCase):
|
|||
relation.save()
|
||||
|
||||
statchg.group = Group.objects.get(acronym="mars")
|
||||
statchg.save()
|
||||
statchg.save_with_history([DocEvent.objects.create(doc=statchg, type="changed_group", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
statchg.set_state(State.objects.get(type="statchg", slug="iesgeval"))
|
||||
self.assertTrue(statchg in agenda_data(date_str)["sections"]["3.3.1"]["docs"])
|
||||
|
||||
|
@ -225,7 +225,7 @@ class IESGAgendaTests(TestCase):
|
|||
telechat_event.save()
|
||||
|
||||
conflrev.group = Group.objects.get(acronym="mars")
|
||||
conflrev.save()
|
||||
conflrev.save_with_history([DocEvent.objects.create(doc=conflrev, type="changed_group", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
conflrev.set_state(State.objects.get(type="conflrev", slug="iesgeval"))
|
||||
self.assertTrue(conflrev in agenda_data(date_str)["sections"]["3.4.1"]["docs"])
|
||||
|
||||
|
@ -244,7 +244,7 @@ class IESGAgendaTests(TestCase):
|
|||
telechat_event.save()
|
||||
|
||||
charter.group = Group.objects.get(acronym="mars")
|
||||
charter.save()
|
||||
charter.save_with_history([DocEvent.objects.create(doc=charter, type="changed_group", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
||||
charter.group.state_id = "bof"
|
||||
charter.group.save()
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
from django.conf.urls import patterns
|
||||
from django.views.generic import RedirectView
|
||||
from django.conf import settings
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^telechat/.*$', RedirectView.as_view(url='https://www.ietf.org/iesg/minutes.html')),
|
||||
|
@ -41,16 +42,16 @@ urlpatterns = patterns('',
|
|||
(r'^telechatdates/$', RedirectView.as_view(url='/admin/iesg/telechatdate/')),
|
||||
|
||||
(r'^decisions/(?:(?P<year>[0-9]{4})/)?$', "ietf.iesg.views.review_decisions"),
|
||||
(r'^agenda/(?:(?P<date>\d{4}-\d{2}-\d{2})/)?$', "ietf.iesg.views.agenda"),
|
||||
(r'^agenda/(?:(?P<date>\d{4}-\d{2}-\d{2})/)?agenda.txt$', "ietf.iesg.views.agenda_txt"),
|
||||
(r'^agenda/(?:(?P<date>\d{4}-\d{2}-\d{2})/)?agenda.json$', "ietf.iesg.views.agenda_json"),
|
||||
(r'^agenda/(?:(?P<date>\d{4}-\d{2}-\d{2})/)?scribe_template.html$', "ietf.iesg.views.agenda_scribe_template"),
|
||||
(r'^agenda/(?:(?P<date>\d{4}-\d{2}-\d{2})/)?moderator_package.html$', "ietf.iesg.views.agenda_moderator_package"),
|
||||
(r'^agenda/(?:(?P<date>\d{4}-\d{2}-\d{2})/)?agenda_package.txt$', "ietf.iesg.views.agenda_package"),
|
||||
(r'^agenda/(?:%(date)s/)?$' % settings.URL_REGEXPS, "ietf.iesg.views.agenda"),
|
||||
(r'^agenda/(?:%(date)s/)?agenda.txt$' % settings.URL_REGEXPS, "ietf.iesg.views.agenda_txt"),
|
||||
(r'^agenda/(?:%(date)s/)?agenda.json$' % settings.URL_REGEXPS, "ietf.iesg.views.agenda_json"),
|
||||
(r'^agenda/(?:%(date)s/)?scribe_template.html$' % settings.URL_REGEXPS, "ietf.iesg.views.agenda_scribe_template"),
|
||||
(r'^agenda/(?:%(date)s/)?moderator_package.html$' % settings.URL_REGEXPS, "ietf.iesg.views.agenda_moderator_package"),
|
||||
(r'^agenda/(?:%(date)s/)?agenda_package.txt$' % settings.URL_REGEXPS, "ietf.iesg.views.agenda_package"),
|
||||
|
||||
(r'^agenda/documents.txt$', "ietf.iesg.views.agenda_documents_txt"),
|
||||
(r'^agenda/documents/$', "ietf.iesg.views.agenda_documents"),
|
||||
(r'^agenda/telechat-(?:(?P<date>\d{4}-\d{2}-\d{2})-)?docs.tgz', "ietf.iesg.views.telechat_docs_tarfile"),
|
||||
(r'^agenda/telechat-(?:%(date)s-)?docs.tgz' % settings.URL_REGEXPS, "ietf.iesg.views.telechat_docs_tarfile"),
|
||||
(r'^discusses/$', "ietf.iesg.views.discusses"),
|
||||
(r'^milestones/$', "ietf.iesg.views.milestones_needing_review"),
|
||||
)
|
||||
|
|
|
@ -327,11 +327,11 @@ def handle_reschedule_form(request, doc, dates, status):
|
|||
if request.method == 'POST':
|
||||
form = RescheduleForm(request.POST, **formargs)
|
||||
if form.is_valid():
|
||||
update_telechat(request, doc, request.user.person,
|
||||
form.cleaned_data['telechat_date'],
|
||||
False if form.cleaned_data['clear_returning_item'] else None)
|
||||
doc.time = datetime.datetime.now()
|
||||
doc.save()
|
||||
e = update_telechat(request, doc, request.user.person,
|
||||
form.cleaned_data['telechat_date'],
|
||||
False if form.cleaned_data['clear_returning_item'] else None)
|
||||
if e:
|
||||
doc.save_with_history([e])
|
||||
|
||||
status["changed"] = True
|
||||
else:
|
||||
|
|
|
@ -357,7 +357,7 @@ def email(request, id):
|
|||
'to': addrs.to,
|
||||
'cc': addrs.cc,
|
||||
'frm': settings.IPR_EMAIL_FROM,
|
||||
'subject': 'Regarding {}'.format(ipr.title),
|
||||
'subject': u'Regarding {}'.format(ipr.title),
|
||||
'reply_to': reply_to,
|
||||
}
|
||||
form = MessageModelForm(initial=initial)
|
||||
|
|
|
@ -17,7 +17,6 @@ from ietf.liaisons.models import LiaisonStatement
|
|||
class LiaisonStatementsFeed(Feed):
|
||||
feed_type = Atom1Feed
|
||||
link = reverse_lazy("ietf.liaisons.views.liaison_list")
|
||||
description_template = "liaisons/feed_item_description.html"
|
||||
|
||||
def get_object(self, request, kind, search=None):
|
||||
obj = {}
|
||||
|
@ -77,7 +76,10 @@ class LiaisonStatementsFeed(Feed):
|
|||
qs = qs.filter(**obj['filter'])
|
||||
if obj.has_key('limit'):
|
||||
qs = qs[:obj['limit']]
|
||||
return qs
|
||||
|
||||
qs = qs.prefetch_related("attachments")
|
||||
|
||||
return qs
|
||||
|
||||
def title(self, obj):
|
||||
return obj['title']
|
||||
|
@ -88,6 +90,12 @@ class LiaisonStatementsFeed(Feed):
|
|||
def item_title(self, item):
|
||||
return render_to_string("liaisons/liaison_title.html", { 'liaison': item }).strip()
|
||||
|
||||
def item_description(self, item):
|
||||
return render_to_string("liaisons/feed_item_description.html", {
|
||||
'liaison': item,
|
||||
"attachments": item.attachments.all(),
|
||||
})
|
||||
|
||||
def item_link(self, item):
|
||||
return urlreverse("ietf.liaisons.views.liaison_detail", kwargs={ "object_id": item.pk })
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ def approvable_liaison_statements(user):
|
|||
|
||||
def can_edit_liaison(user, liaison):
|
||||
'''Return True if user is Secretariat or Liaison Manager of all SDO groups involved'''
|
||||
if not user.is_authenticated():
|
||||
return False
|
||||
if has_role(user, "Secretariat"):
|
||||
return True
|
||||
if has_role(user, "Liaison Manager"):
|
||||
|
|
|
@ -7,8 +7,7 @@ from django.core.urlresolvers import reverse as urlreverse
|
|||
from django.core.validators import validate_email, ValidationError
|
||||
from django.db.models import Q
|
||||
from django.http import HttpResponse, HttpResponseForbidden
|
||||
from django.shortcuts import render, render_to_response, get_object_or_404, redirect
|
||||
from django.template import RequestContext
|
||||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
|
||||
from ietf.doc.models import Document
|
||||
from ietf.ietfauth.utils import role_required, has_role
|
||||
|
@ -315,12 +314,10 @@ def liaison_add(request, type=None, **kwargs):
|
|||
else:
|
||||
form = liaison_form_factory(request,type=type,**kwargs)
|
||||
|
||||
return render_to_response(
|
||||
'liaisons/edit.html',
|
||||
{'form': form,
|
||||
'liaison': kwargs.get('instance')},
|
||||
context_instance=RequestContext(request),
|
||||
)
|
||||
return render(request, 'liaisons/edit.html', {
|
||||
'form': form,
|
||||
'liaison': kwargs.get('instance')
|
||||
})
|
||||
|
||||
def liaison_history(request, object_id):
|
||||
"""Show the history for a specific liaison statement"""
|
||||
|
@ -382,7 +379,7 @@ def liaison_detail(request, object_id):
|
|||
relations_by = [i.target for i in liaison.source_of_set.filter(target__state__slug='posted')]
|
||||
relations_to = [i.source for i in liaison.target_of_set.filter(source__state__slug='posted')]
|
||||
|
||||
return render_to_response("liaisons/detail.html", {
|
||||
return render(request, "liaisons/detail.html", {
|
||||
"liaison": liaison,
|
||||
'tabs': get_details_tabs(liaison, 'Statement'),
|
||||
"can_edit": can_edit,
|
||||
|
@ -390,7 +387,7 @@ def liaison_detail(request, object_id):
|
|||
"can_reply": can_reply,
|
||||
"relations_to": relations_to,
|
||||
"relations_by": relations_by,
|
||||
}, context_instance=RequestContext(request))
|
||||
})
|
||||
|
||||
def liaison_edit(request, object_id):
|
||||
liaison = get_object_or_404(LiaisonStatement, pk=object_id)
|
||||
|
@ -409,28 +406,28 @@ def liaison_edit_attachment(request, object_id, doc_id):
|
|||
form = EditAttachmentForm(request.POST)
|
||||
if form.is_valid():
|
||||
title = form.cleaned_data.get('title')
|
||||
doc.title = title
|
||||
doc.save()
|
||||
|
||||
# create event
|
||||
LiaisonStatementEvent.objects.create(
|
||||
e = LiaisonStatementEvent.objects.create(
|
||||
type_id='modified',
|
||||
by=get_person_for_user(request.user),
|
||||
statement=liaison,
|
||||
desc='Attachment Title changed to {}'.format(title)
|
||||
)
|
||||
|
||||
doc.title = title
|
||||
doc.save_with_history([e])
|
||||
|
||||
messages.success(request,'Attachment title changed')
|
||||
return redirect('ietf.liaisons.views.liaison_detail', object_id=liaison.pk)
|
||||
|
||||
else:
|
||||
form = EditAttachmentForm(initial={'title':doc.title})
|
||||
|
||||
return render_to_response(
|
||||
'liaisons/edit_attachment.html',
|
||||
{'form': form,
|
||||
'liaison': liaison},
|
||||
context_instance=RequestContext(request),
|
||||
)
|
||||
return render(request, 'liaisons/edit_attachment.html', {
|
||||
'form': form,
|
||||
'liaison': liaison
|
||||
})
|
||||
|
||||
def liaison_list(request, state='posted'):
|
||||
"""A generic list view with tabs for different states: posted, pending, dead"""
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.db.models.query import QuerySet
|
||||
from django.forms.widgets import Widget
|
||||
|
@ -33,11 +32,11 @@ class ShowAttachmentsWidget(Widget):
|
|||
html += u'<div class="attachedFiles form-control widget">'
|
||||
if value and isinstance(value, QuerySet):
|
||||
for attachment in value:
|
||||
html += u'<a class="initialAttach" href="%s%s">%s</a> ' % (settings.LIAISON_ATTACH_URL, conditional_escape(attachment.document.external_url), conditional_escape(attachment.document.title))
|
||||
html += u'<a class="initialAttach" href="%s">%s</a> ' % (conditional_escape(attachment.document.href()), conditional_escape(attachment.document.title))
|
||||
html += u'<a class="btn btn-default btn-xs" href="{}">Edit</a> '.format(urlreverse("ietf.liaisons.views.liaison_edit_attachment", kwargs={'object_id':attachment.statement.pk,'doc_id':attachment.document.pk}))
|
||||
html += u'<a class="btn btn-default btn-xs" href="{}">Delete</a> '.format(urlreverse("ietf.liaisons.views.liaison_delete_attachment", kwargs={'object_id':attachment.statement.pk,'attach_id':attachment.pk}))
|
||||
html += u'<br />'
|
||||
else:
|
||||
html += u'No files attached'
|
||||
html += u'</div></div>'
|
||||
return mark_safe(html)
|
||||
return mark_safe(html)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.conf.urls import patterns
|
||||
from django.views.generic import RedirectView
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.meeting import views
|
||||
from ietf.meeting import ajax
|
||||
|
@ -60,11 +61,11 @@ urlpatterns = patterns('',
|
|||
(r'^(?P<num>\d+)/session/(?P<sessionid>\d+).json', ajax.session_json),
|
||||
(r'^(?P<num>\d+)/session/(?P<sessionid>\d+)/constraints.json', ajax.session_constraints),
|
||||
|
||||
(r'^(?P<num>\d+)/session/(?P<acronym>[A-Za-z0-9_\-\+]+)/$', views.session_details),
|
||||
(r'^(?P<num>\d+)/session/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<seq>\d+)/$', views.session_details),
|
||||
(r'^(?P<num>\d+)/session/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<week_day>[a-zA-Z]+)/$', views.session_details),
|
||||
(r'^(?P<num>\d+)/session/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/$', views.session_details),
|
||||
(r'^(?P<num>\d+)/session/(?P<acronym>[A-Za-z0-9_\-\+]+)/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/(?P<seq>\d+)/$', views.session_details),
|
||||
(r'^(?P<num>\d+)/session/%(acronym)s/$' % settings.URL_REGEXPS, views.session_details),
|
||||
(r'^(?P<num>\d+)/session/%(acronym)s/(?P<seq>\d+)/$' % settings.URL_REGEXPS, views.session_details),
|
||||
(r'^(?P<num>\d+)/session/%(acronym)s/(?P<week_day>[a-zA-Z]+)/$' % settings.URL_REGEXPS, views.session_details),
|
||||
(r'^(?P<num>\d+)/session/%(acronym)s/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/$' % settings.URL_REGEXPS, views.session_details),
|
||||
(r'^(?P<num>\d+)/session/%(acronym)s/(?P<date>\d{4}-\d{2}-\d{2}(-\d{4})?)/(?P<seq>\d+)/$' % settings.URL_REGEXPS, views.session_details),
|
||||
|
||||
(r'^(?P<num>\d+)/constraint/(?P<constraintid>\d+).json', ajax.constraint_json),
|
||||
(r'^(?P<num>\d+).json$', ajax.meeting_json),
|
||||
|
|
|
@ -709,13 +709,13 @@ def room_view(request, num=None):
|
|||
meeting = get_meeting(num)
|
||||
|
||||
rooms = meeting.room_set.order_by('functional_name','name')
|
||||
if rooms.count() == 0:
|
||||
raise Http404
|
||||
if not rooms:
|
||||
return HttpResponse("No rooms defined yet")
|
||||
|
||||
scheduledsessions = meeting.agenda.scheduledsession_set.all()
|
||||
unavailable = meeting.timeslot_set.filter(type__slug='unavail')
|
||||
if (unavailable.count() + scheduledsessions.count()) == 0 :
|
||||
raise Http404
|
||||
if not (unavailable or scheduledsessions):
|
||||
return HttpResponse("No sessions/timeslots available yet")
|
||||
|
||||
earliest = None
|
||||
latest = None
|
||||
|
|
|
@ -106,7 +106,7 @@ class NomcomViewsTest(TestCase):
|
|||
def create_nominees_for_states(self, base_state):
|
||||
cnominee = Nominee.objects.get(email__person__user__username=COMMUNITY_USER)
|
||||
position = Position.objects.get(name='APP')
|
||||
NomineePosition.objects.create(position=position,
|
||||
nom_pos = NomineePosition.objects.create(position=position,
|
||||
nominee=cnominee,
|
||||
state=NomineePositionStateName.objects.get(slug=base_state))
|
||||
position = Position.objects.get(name='INT')
|
||||
|
@ -117,12 +117,13 @@ class NomcomViewsTest(TestCase):
|
|||
NomineePosition.objects.create(position=position,
|
||||
nominee=cnominee,
|
||||
state=NomineePositionStateName.objects.get(slug=base_state))
|
||||
return nom_pos
|
||||
|
||||
def test_private_index_post_accept(self):
|
||||
self.create_nominees_for_states('pending')
|
||||
nom_pos = self.create_nominees_for_states('pending')
|
||||
login_testing_unauthorized(self, CHAIR_USER, self.private_index_url)
|
||||
test_data = {"action": "set_as_accepted",
|
||||
"selected": [1]}
|
||||
"selected": [nom_pos.pk]}
|
||||
r = self.client.post(self.private_index_url, test_data)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
|
@ -131,10 +132,10 @@ class NomcomViewsTest(TestCase):
|
|||
self.client.logout()
|
||||
|
||||
def test_private_index_post_decline(self):
|
||||
self.create_nominees_for_states('pending')
|
||||
nom_pos = self.create_nominees_for_states('pending')
|
||||
login_testing_unauthorized(self, CHAIR_USER, self.private_index_url)
|
||||
test_data = {"action": "set_as_declined",
|
||||
"selected": [1]}
|
||||
"selected": [nom_pos.pk]}
|
||||
r = self.client.post(self.private_index_url, test_data)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
|
@ -143,10 +144,10 @@ class NomcomViewsTest(TestCase):
|
|||
self.client.logout()
|
||||
|
||||
def test_private_index_post_pending(self):
|
||||
self.create_nominees_for_states('declined')
|
||||
nom_pos = self.create_nominees_for_states('declined')
|
||||
login_testing_unauthorized(self, CHAIR_USER, self.private_index_url)
|
||||
test_data = {"action": "set_as_pending",
|
||||
"selected": [1]}
|
||||
"selected": [nom_pos.pk]}
|
||||
r = self.client.post(self.private_index_url, test_data)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
|
|
|
@ -155,7 +155,7 @@ class EditModelForm(forms.ModelForm):
|
|||
# setup replaced
|
||||
self.fields['review_by_rfc_editor'].initial = bool(self.instance.tags.filter(slug='rfc-rev'))
|
||||
|
||||
def save(self, force_insert=False, force_update=False, commit=True):
|
||||
def save(self, commit=False):
|
||||
m = super(EditModelForm, self).save(commit=False)
|
||||
state = self.cleaned_data['state']
|
||||
iesg_state = self.cleaned_data['iesg_state']
|
||||
|
@ -176,11 +176,8 @@ class EditModelForm(forms.ModelForm):
|
|||
else:
|
||||
m.tags.remove('rfc-rev')
|
||||
|
||||
m.time = datetime.datetime.now()
|
||||
# handle replaced by
|
||||
|
||||
if commit:
|
||||
m.save()
|
||||
return m
|
||||
|
||||
# field must contain filename of existing draft
|
||||
|
@ -274,14 +271,12 @@ class RfcModelForm(forms.ModelForm):
|
|||
self.fields['title'].widget = forms.Textarea()
|
||||
self.fields['std_level'].required = True
|
||||
|
||||
def save(self, force_insert=False, force_update=False, commit=True):
|
||||
def save(self, force_insert=False, force_update=False, commit=False):
|
||||
obj = super(RfcModelForm, self).save(commit=False)
|
||||
|
||||
# create DocAlias
|
||||
DocAlias.objects.create(document=self.instance,name="rfc%d" % self.cleaned_data['rfc_number'])
|
||||
|
||||
if commit:
|
||||
obj.save()
|
||||
return obj
|
||||
|
||||
def clean_rfc_number(self):
|
||||
|
|
|
@ -14,7 +14,7 @@ from django.template.loader import render_to_string
|
|||
#from email import *
|
||||
from ietf.doc.models import Document, DocumentAuthor, DocAlias, DocRelationshipName, RelatedDocument, State
|
||||
from ietf.doc.models import DocEvent, NewRevisionDocEvent
|
||||
from ietf.doc.models import save_document_in_history
|
||||
from ietf.doc.utils import add_state_change_event
|
||||
from ietf.ietfauth.utils import role_required
|
||||
from ietf.meeting.models import Meeting
|
||||
from ietf.meeting.helpers import get_meeting
|
||||
|
@ -176,18 +176,17 @@ def do_extend(draft, request):
|
|||
- update revision_date
|
||||
- set extension_date
|
||||
'''
|
||||
save_document_in_history(draft)
|
||||
|
||||
e = DocEvent.objects.create(
|
||||
type='changed_document',
|
||||
by=request.user.person,
|
||||
doc=draft,
|
||||
time=draft.time,
|
||||
desc='Extended expiry',
|
||||
)
|
||||
draft.expires = request.session['data']['expiration_date']
|
||||
draft.time = datetime.datetime.now()
|
||||
draft.save()
|
||||
|
||||
DocEvent.objects.create(type='changed_document',
|
||||
by=request.user.person,
|
||||
doc=draft,
|
||||
time=draft.time,
|
||||
desc='extend_expiry')
|
||||
|
||||
draft.save_with_history([e])
|
||||
|
||||
# save scheduled announcement
|
||||
announcement_from_form(request.session['email'],by=request.user.person)
|
||||
|
||||
|
@ -196,24 +195,28 @@ def do_extend(draft, request):
|
|||
def do_replace(draft, request):
|
||||
'Perform document replace'
|
||||
|
||||
save_document_in_history(draft)
|
||||
|
||||
replaced = request.session['data']['replaced'] # a DocAlias
|
||||
replaced_by = request.session['data']['replaced_by'] # a Document
|
||||
|
||||
# change state and update last modified
|
||||
draft.set_state(State.objects.get(type="draft", slug="repl"))
|
||||
draft.time = datetime.datetime.now()
|
||||
draft.save()
|
||||
|
||||
# create relationship
|
||||
RelatedDocument.objects.create(source=replaced_by,
|
||||
target=replaced,
|
||||
relationship=DocRelationshipName.objects.get(slug='replaces'))
|
||||
|
||||
# create DocEvent
|
||||
# no replace DocEvent at this time, Jan 2012
|
||||
|
||||
|
||||
|
||||
draft.set_state(State.objects.get(type="draft", slug="repl"))
|
||||
|
||||
e = DocEvent.objects.create(
|
||||
type='changed_document',
|
||||
by=request.user.person,
|
||||
doc=replaced_by,
|
||||
time=draft.time,
|
||||
desc='This document now replaces <b>%s</b>' % request.session['data']['replaced'],
|
||||
)
|
||||
|
||||
draft.save_with_history([e])
|
||||
|
||||
# move replaced document to archive
|
||||
archive_draft_files(replaced.document.name + '-' + replaced.document.rev)
|
||||
|
||||
|
@ -243,16 +246,16 @@ def do_resurrect(draft, request):
|
|||
|
||||
# set expires
|
||||
draft.expires = datetime.datetime.now() + datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
|
||||
draft.time = datetime.datetime.now()
|
||||
draft.save()
|
||||
|
||||
# create DocEvent
|
||||
NewRevisionDocEvent.objects.create(type='completed_resurrect',
|
||||
by=request.user.person,
|
||||
doc=draft,
|
||||
rev=draft.rev,
|
||||
time=draft.time)
|
||||
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
|
||||
announcement_from_form(request.session['email'],by=request.user.person)
|
||||
|
||||
|
@ -278,12 +281,10 @@ def do_revision(draft, request):
|
|||
# TODO this behavior may change with archive strategy
|
||||
archive_draft_files(draft.name + '-' + draft.rev)
|
||||
|
||||
save_document_in_history(draft)
|
||||
|
||||
# save form data
|
||||
form = BaseRevisionModelForm(request.session['data'],instance=draft)
|
||||
if form.is_valid():
|
||||
new_draft = form.save()
|
||||
new_draft = form.save(commit=False)
|
||||
else:
|
||||
raise Exception(form.errors)
|
||||
raise Exception('Problem with input data %s' % form.data)
|
||||
|
@ -291,16 +292,16 @@ def do_revision(draft, request):
|
|||
# set revision and expires
|
||||
new_draft.rev = request.session['filename'][-2:]
|
||||
new_draft.expires = datetime.datetime.now() + datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
|
||||
new_draft.time = datetime.datetime.now()
|
||||
new_draft.save()
|
||||
|
||||
|
||||
# create DocEvent
|
||||
NewRevisionDocEvent.objects.create(type='new_revision',
|
||||
by=request.user.person,
|
||||
doc=draft,
|
||||
rev=new_draft.rev,
|
||||
desc='New revision available',
|
||||
time=draft.time)
|
||||
e = NewRevisionDocEvent.objects.create(type='new_revision',
|
||||
by=request.user.person,
|
||||
doc=draft,
|
||||
rev=new_draft.rev,
|
||||
desc='New revision available',
|
||||
time=draft.time)
|
||||
|
||||
new_draft.save_with_history([e])
|
||||
|
||||
handle_substate(new_draft)
|
||||
|
||||
|
@ -325,12 +326,10 @@ def do_update(draft,request):
|
|||
- do substate check
|
||||
- change state to Active
|
||||
'''
|
||||
save_document_in_history(draft)
|
||||
|
||||
# save form data
|
||||
form = BaseRevisionModelForm(request.session['data'],instance=draft)
|
||||
if form.is_valid():
|
||||
new_draft = form.save()
|
||||
new_draft = form.save(commit=False)
|
||||
else:
|
||||
raise Exception('Problem with input data %s' % form.data)
|
||||
|
||||
|
@ -339,19 +338,19 @@ def do_update(draft,request):
|
|||
# update draft record
|
||||
new_draft.rev = os.path.splitext(request.session['data']['filename'])[0][-2:]
|
||||
new_draft.expires = datetime.datetime.now() + datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
|
||||
new_draft.time = datetime.datetime.now()
|
||||
new_draft.save()
|
||||
|
||||
|
||||
new_draft.set_state(State.objects.get(type="draft", slug="active"))
|
||||
|
||||
# create DocEvent
|
||||
NewRevisionDocEvent.objects.create(type='new_revision',
|
||||
by=request.user.person,
|
||||
doc=new_draft,
|
||||
rev=new_draft.rev,
|
||||
desc='New revision available',
|
||||
time=new_draft.time)
|
||||
e = NewRevisionDocEvent.objects.create(type='new_revision',
|
||||
by=request.user.person,
|
||||
doc=new_draft,
|
||||
rev=new_draft.rev,
|
||||
desc='New revision available',
|
||||
time=new_draft.time)
|
||||
|
||||
new_draft.save_with_history([e])
|
||||
|
||||
# move uploaded files to production directory
|
||||
promote_files(new_draft, request.session['file_type'])
|
||||
|
||||
|
@ -370,15 +369,22 @@ def do_withdraw(draft,request):
|
|||
- TODO move file to archive
|
||||
'''
|
||||
withdraw_type = request.session['data']['type']
|
||||
|
||||
prev_state = draft.get_state("draft")
|
||||
new_state = None
|
||||
if withdraw_type == 'ietf':
|
||||
draft.set_state(State.objects.get(type="draft", slug="ietf-rm"))
|
||||
new_state = State.objects.get(type="draft", slug="ietf-rm")
|
||||
elif withdraw_type == 'author':
|
||||
draft.set_state(State.objects.get(type="draft", slug="auth-rm"))
|
||||
|
||||
draft.time = datetime.datetime.now()
|
||||
draft.save()
|
||||
|
||||
# no DocEvent ?
|
||||
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
|
||||
announcement_from_form(request.session['email'],by=request.user.person)
|
||||
|
@ -538,8 +544,7 @@ def add(request):
|
|||
draft.rev = revision
|
||||
draft.name = name
|
||||
draft.type_id = 'draft'
|
||||
draft.time = datetime.datetime.now()
|
||||
|
||||
|
||||
# set stream based on document name
|
||||
if not draft.stream:
|
||||
stream_slug = None
|
||||
|
@ -556,7 +561,7 @@ def add(request):
|
|||
# set expires
|
||||
draft.expires = datetime.datetime.now() + datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
|
||||
|
||||
draft.save()
|
||||
draft.save(force_insert=True)
|
||||
|
||||
# set state
|
||||
draft.set_state(State.objects.get(type="draft", slug="active"))
|
||||
|
@ -792,13 +797,13 @@ def edit(request, id):
|
|||
form = EditModelForm(request.POST, instance=draft)
|
||||
if form.is_valid():
|
||||
if form.changed_data:
|
||||
save_document_in_history(draft)
|
||||
DocEvent.objects.create(type='changed_document',
|
||||
by=request.user.person,
|
||||
doc=draft,
|
||||
desc='Changed field(s): %s' % ','.join(form.changed_data))
|
||||
e = DocEvent.objects.create(type='changed_document',
|
||||
by=request.user.person,
|
||||
doc=draft,
|
||||
desc='Changed field(s): %s' % ','.join(form.changed_data))
|
||||
# see EditModelForm.save() for detailed logic
|
||||
form.save()
|
||||
form.save(commit=False)
|
||||
draft.save_with_history([e])
|
||||
|
||||
messages.success(request, 'Draft modified successfully!')
|
||||
|
||||
|
@ -924,16 +929,16 @@ def makerfc(request, id):
|
|||
if form.is_valid() and obs_formset.is_valid():
|
||||
|
||||
# TODO
|
||||
save_document_in_history(draft)
|
||||
archive_draft_files(draft.name + '-' + draft.rev)
|
||||
|
||||
rfc = form.save()
|
||||
rfc = form.save(commit=False)
|
||||
|
||||
# create DocEvent
|
||||
DocEvent.objects.create(type='published_rfc',
|
||||
by=request.user.person,
|
||||
doc=rfc)
|
||||
|
||||
e = DocEvent.objects.create(type='published_rfc',
|
||||
by=request.user.person,
|
||||
doc=rfc,
|
||||
desc="Published RFC")
|
||||
|
||||
# change state
|
||||
draft.set_state(State.objects.get(type="draft", slug="rfc"))
|
||||
|
||||
|
@ -950,7 +955,9 @@ def makerfc(request, id):
|
|||
RelatedDocument.objects.create(source=draft,
|
||||
target=target,
|
||||
relationship=DocRelationshipName.objects.get(slug=relation))
|
||||
|
||||
|
||||
rfc.save_with_history([e])
|
||||
|
||||
messages.success(request, 'RFC created successfully!')
|
||||
return redirect('drafts_view', id=id)
|
||||
else:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.conf.urls import patterns, url
|
||||
from django.conf import settings
|
||||
|
||||
urlpatterns = patterns('ietf.secr.groups.views',
|
||||
url(r'^$', 'search', name='groups'),
|
||||
|
@ -6,11 +7,11 @@ urlpatterns = patterns('ietf.secr.groups.views',
|
|||
url(r'^blue-dot-report/$', 'blue_dot', name='groups_blue_dot'),
|
||||
url(r'^search/$', 'search', name='groups_search'),
|
||||
#(r'^ajax/get_ads/$', 'get_ads'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+\.]+)/$', 'view', name='groups_view'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+\.]+)/delete/(?P<id>\d{1,6})/$', 'delete_role', name='groups_delete_role'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+\.]+)/charter/$', 'charter', name='groups_charter'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+\.]+)/edit/$', 'edit', name='groups_edit'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+\.]+)/gm/$', 'view_gm', name='groups_view_gm'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+\.]+)/gm/edit/$', 'edit_gm', name='groups_edit_gm'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+\.]+)/people/$', 'people', name='groups_people'),
|
||||
url(r'^%(acronym)s/$' % settings.URL_REGEXPS, 'view', name='groups_view'),
|
||||
url(r'^%(acronym)s/delete/(?P<id>\d{1,6})/$' % settings.URL_REGEXPS, 'delete_role', name='groups_delete_role'),
|
||||
url(r'^%(acronym)s/charter/$' % settings.URL_REGEXPS, 'charter', name='groups_charter'),
|
||||
url(r'^%(acronym)s/edit/$' % settings.URL_REGEXPS, 'edit', name='groups_edit'),
|
||||
url(r'^%(acronym)s/gm/$' % settings.URL_REGEXPS, 'view_gm', name='groups_view_gm'),
|
||||
url(r'^%(acronym)s/gm/edit/$' % settings.URL_REGEXPS, 'edit_gm', name='groups_edit_gm'),
|
||||
url(r'^%(acronym)s/people/$' % settings.URL_REGEXPS, 'people', name='groups_people'),
|
||||
)
|
||||
|
|
|
@ -117,7 +117,7 @@ class MainTestCase(TestCase):
|
|||
meeting = make_meeting_test_data()
|
||||
url = reverse('meetings_blue_sheet_generate',kwargs={'meeting_id':meeting.number})
|
||||
self.client.login(username="secretary", password="secretary+password")
|
||||
response = self.client.get(url)
|
||||
response = self.client.post(url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertTrue(os.path.exists(self.bluesheet_path))
|
||||
|
||||
|
|
|
@ -369,10 +369,11 @@ def blue_sheet_generate(request, meeting_id):
|
|||
'''
|
||||
meeting = get_object_or_404(Meeting, number=meeting_id)
|
||||
|
||||
groups = Group.objects.filter(session__meeting=meeting).order_by('acronym')
|
||||
create_blue_sheets(meeting, groups)
|
||||
if request.method == "POST":
|
||||
groups = Group.objects.filter(session__meeting=meeting).order_by('acronym')
|
||||
create_blue_sheets(meeting, groups)
|
||||
|
||||
messages.success(request, 'Blue Sheets generated')
|
||||
messages.success(request, 'Blue Sheets generated')
|
||||
return redirect('meetings_blue_sheet', meeting_id=meeting.number)
|
||||
|
||||
@role_required('Secretariat')
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
from django.conf.urls import patterns, url
|
||||
from django.conf import settings
|
||||
|
||||
urlpatterns = patterns('ietf.secr.proceedings.views',
|
||||
url(r'^$', 'main', name='proceedings'),
|
||||
url(r'^ajax/generate-proceedings/(?P<meeting_num>\d{1,3})/$', 'ajax_generate_proceedings', name='proceedings_ajax_generate_proceedings'),
|
||||
url(r'^ajax/get-sessions/(?P<meeting_num>\d{1,3})/(?P<acronym>[A-Za-z0-9_\-\+]+)/', 'ajax_get_sessions', name='proceedings_ajax_get_sessions'),
|
||||
url(r'^ajax/get-sessions/(?P<meeting_num>\d{1,3})/%(acronym)s/' % settings.URL_REGEXPS, 'ajax_get_sessions', name='proceedings_ajax_get_sessions'),
|
||||
url(r'^ajax/order-slide/$', 'ajax_order_slide', name='proceedings_ajax_order_slide'),
|
||||
# special offline URL for testing proceedings build
|
||||
url(r'^build/(?P<meeting_num>\d{1,3}|interim-\d{4}-[A-Za-z0-9_\-\+]+)/(?P<acronym>[A-Za-z0-9_\-\+]+)/$',
|
||||
|
@ -21,11 +22,11 @@ urlpatterns = patterns('ietf.secr.proceedings.views',
|
|||
# NOTE: we have two entries here which both map to upload_unified, passing session_id or acronym
|
||||
url(r'^(?P<meeting_num>\d{1,3}|interim-\d{4}-[A-Za-z0-9_\-\+]+)/(?P<session_id>\d{1,6})/$',
|
||||
'upload_unified', name='proceedings_upload_unified'),
|
||||
url(r'^(?P<meeting_num>\d{1,3}|interim-\d{4}-[A-Za-z0-9_\-\+]+)/(?P<acronym>[A-Za-z0-9_\-\+]+)/$',
|
||||
url(r'^(?P<meeting_num>\d{1,3}|interim-\d{4}-[A-Za-z0-9_\-\+]+)/%(acronym)s/$' % settings.URL_REGEXPS,
|
||||
'upload_unified', name='proceedings_upload_unified'),
|
||||
# interim stuff
|
||||
url(r'^interim/$', 'select_interim', name='proceedings_select_interim'),
|
||||
url(r'^interim/(?P<meeting_num>interim-\d{4}-[A-Za-z0-9_\-\+]+)/delete/$', 'delete_interim_meeting',
|
||||
name='proceedings_delete_interim_meeting'),
|
||||
url(r'^interim/(?P<acronym>[A-Za-z0-9_\-\+]+)/$', 'interim', name='proceedings_interim'),
|
||||
url(r'^interim/%(acronym)s/$' % settings.URL_REGEXPS, 'interim', name='proceedings_interim'),
|
||||
)
|
||||
|
|
|
@ -25,6 +25,7 @@ from ietf.secr.utils.group import get_my_groups, groups_by_session
|
|||
from ietf.secr.utils.meeting import get_upload_root, get_materials, get_timeslot, get_proceedings_path, get_proceedings_url
|
||||
from ietf.doc.models import Document, DocAlias, DocEvent, State, NewRevisionDocEvent
|
||||
from ietf.group.models import Group
|
||||
from ietf.person.models import Person
|
||||
from ietf.ietfauth.utils import has_role, role_required
|
||||
from ietf.meeting.models import Meeting, Session, TimeSlot, ScheduledSession
|
||||
from ietf.secr.proceedings.forms import EditSlideForm, InterimMeetingForm, RecordingForm, RecordingEditForm, ReplaceSlideForm, UnifiedUploadForm
|
||||
|
@ -212,7 +213,14 @@ def post_process(doc):
|
|||
# change extension
|
||||
base,ext = os.path.splitext(doc.external_url)
|
||||
doc.external_url = base + '.pdf'
|
||||
doc.save()
|
||||
|
||||
e = DocEvent.objects.create(
|
||||
type='changed_document',
|
||||
by=Person.objects.get(name="(System)"),
|
||||
doc=doc,
|
||||
desc='Converted document to PDF',
|
||||
)
|
||||
doc.save_with_history([e])
|
||||
|
||||
# -------------------------------------------------
|
||||
# AJAX Functions
|
||||
|
@ -360,9 +368,12 @@ def delete_material(request,slide_id):
|
|||
doc.set_state(state)
|
||||
|
||||
# create deleted_document
|
||||
DocEvent.objects.create(doc=doc,
|
||||
by=request.user.person,
|
||||
type='deleted')
|
||||
e = DocEvent.objects.create(doc=doc,
|
||||
by=request.user.person,
|
||||
type='deleted',
|
||||
desc="State set to deleted")
|
||||
|
||||
doc.save_with_history([e])
|
||||
|
||||
create_proceedings(meeting,group)
|
||||
|
||||
|
@ -582,7 +593,13 @@ def process_pdfs(request, meeting_num):
|
|||
path = os.path.join(settings.SECR_PROCEEDINGS_DIR,meeting_num,'slides',pdf_file)
|
||||
if os.path.exists(path):
|
||||
doc.external_url = pdf_file
|
||||
doc.save()
|
||||
e = DocEvent.objects.create(
|
||||
type='changed_document',
|
||||
by=Person.objects.get(name="(System)"),
|
||||
doc=doc,
|
||||
desc='Set URL to PDF version',
|
||||
)
|
||||
doc.save_with_history([e])
|
||||
count += 1
|
||||
else:
|
||||
warn_count += 1
|
||||
|
@ -658,7 +675,15 @@ def recording_edit(request, meeting_num, name):
|
|||
form = RecordingEditForm(request.POST, instance=recording)
|
||||
if form.is_valid():
|
||||
# save record and rebuild proceedings
|
||||
form.save()
|
||||
form.save(commit=False)
|
||||
e = DocEvent.objects.create(
|
||||
type='changed_document',
|
||||
by=request.user.person,
|
||||
doc=recording,
|
||||
desc=u'Changed URL to %s' % recording.external_url,
|
||||
)
|
||||
recording.save_with_history([e])
|
||||
|
||||
create_proceedings(meeting,recording.group)
|
||||
messages.success(request,'Recording saved')
|
||||
return redirect('proceedings_recording', meeting_num=meeting_num)
|
||||
|
@ -704,13 +729,15 @@ def replace_slide(request, slide_id):
|
|||
handle_upload_file(file,disk_filename,meeting,'slides')
|
||||
|
||||
new_slide.external_url = disk_filename
|
||||
new_slide.save()
|
||||
post_process(new_slide)
|
||||
|
||||
|
||||
# create DocEvent uploaded
|
||||
DocEvent.objects.create(doc=slide,
|
||||
by=request.user.person,
|
||||
type='uploaded')
|
||||
e = DocEvent.objects.create(doc=slide,
|
||||
by=request.user.person,
|
||||
type='uploaded',
|
||||
desc="Uploaded")
|
||||
new_slide.save_with_history([e])
|
||||
|
||||
post_process(new_slide)
|
||||
|
||||
# rebuild proceedings.html
|
||||
create_proceedings(meeting,group)
|
||||
|
@ -936,7 +963,6 @@ def upload_unified(request, meeting_num, acronym=None, session_id=None):
|
|||
doc.title = doc.name
|
||||
else:
|
||||
doc.title = '%s for %s at %s' % (material_type.slug.capitalize(), group.acronym.upper(), meeting)
|
||||
doc.save()
|
||||
|
||||
DocAlias.objects.get_or_create(name=doc.name, document=doc)
|
||||
|
||||
|
@ -960,12 +986,13 @@ def upload_unified(request, meeting_num, acronym=None, session_id=None):
|
|||
s.sessionpresentation_set.create(document=doc,rev=doc.rev)
|
||||
|
||||
# create NewRevisionDocEvent instead of uploaded, per Ole
|
||||
NewRevisionDocEvent.objects.create(type='new_revision',
|
||||
by=request.user.person,
|
||||
doc=doc,
|
||||
rev=doc.rev,
|
||||
desc='New revision available',
|
||||
time=now)
|
||||
e = NewRevisionDocEvent.objects.create(type='new_revision',
|
||||
by=request.user.person,
|
||||
doc=doc,
|
||||
rev=doc.rev,
|
||||
desc='New revision available')
|
||||
|
||||
doc.save_with_history([e])
|
||||
|
||||
post_process(doc)
|
||||
create_proceedings(meeting,group)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from django.conf.urls import patterns, url
|
||||
from django.conf import settings
|
||||
|
||||
urlpatterns = patterns('ietf.secr.roles.views',
|
||||
url(r'^$', 'main', name='roles'),
|
||||
url(r'^ajax/get-roles/(?P<acronym>[A-Za-z0-9_\-\+\.]+)/$', 'ajax_get_roles', name='roles_ajax_get_roles'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+\.]+)/delete/(?P<id>\d{1,6})/$', 'delete_role', name='roles_delete_role'),
|
||||
url(r'^ajax/get-roles/%(acronym)s/$' % settings.URL_REGEXPS, 'ajax_get_roles', name='roles_ajax_get_roles'),
|
||||
url(r'^%(acronym)s/delete/(?P<id>\d{1,6})/$' % settings.URL_REGEXPS, 'delete_role', name='roles_delete_role'),
|
||||
)
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
from django.conf.urls import patterns, url
|
||||
from django.conf import settings
|
||||
|
||||
urlpatterns = patterns('ietf.secr.sreq.views',
|
||||
url(r'^$', 'main', name='sessions'),
|
||||
url(r'^status/$', 'tool_status', name='sessions_tool_status'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+]+)/$', 'view', name='sessions_view'),
|
||||
url(r'^(?P<num>[A-Za-z0-9_\-\+]+)/(?P<acronym>[A-Za-z0-9_\-\+]+)/view/$', 'view', name='sessions_view'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+]+)/approve/$', 'approve', name='sessions_approve'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+]+)/cancel/$', 'cancel', name='sessions_cancel'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+]+)/confirm/$', 'confirm', name='sessions_confirm'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+]+)/edit/$', 'edit', name='sessions_edit'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+]+)/new/$', 'new', name='sessions_new'),
|
||||
url(r'^(?P<acronym>[A-Za-z0-9_\-\+]+)/no_session/$', 'no_session', name='sessions_no_session'),
|
||||
url(r'^(?P<num>[A-Za-z0-9_\-\+]+)/(?P<acronym>[A-Za-z0-9_\-\+]+)/edit/$', 'edit_mtg', name='sessions_edit'),
|
||||
url(r'^%(acronym)s/$' % settings.URL_REGEXPS, 'view', name='sessions_view'),
|
||||
url(r'^(?P<num>[A-Za-z0-9_\-\+]+)/%(acronym)s/view/$' % settings.URL_REGEXPS, 'view', name='sessions_view'),
|
||||
url(r'^%(acronym)s/approve/$' % settings.URL_REGEXPS, 'approve', name='sessions_approve'),
|
||||
url(r'^%(acronym)s/cancel/$' % settings.URL_REGEXPS, 'cancel', name='sessions_cancel'),
|
||||
url(r'^%(acronym)s/confirm/$' % settings.URL_REGEXPS, 'confirm', name='sessions_confirm'),
|
||||
url(r'^%(acronym)s/edit/$' % settings.URL_REGEXPS, 'edit', name='sessions_edit'),
|
||||
url(r'^%(acronym)s/new/$' % settings.URL_REGEXPS, 'new', name='sessions_new'),
|
||||
url(r'^%(acronym)s/no_session/$' % settings.URL_REGEXPS, 'no_session', name='sessions_no_session'),
|
||||
url(r'^(?P<num>[A-Za-z0-9_\-\+]+)/%(acronym)s/edit/$' % settings.URL_REGEXPS, 'edit_mtg', name='sessions_edit'),
|
||||
)
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.forms.formsets import formset_factory
|
|||
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
||||
from django.template import RequestContext
|
||||
|
||||
from ietf.doc.models import DocEvent, Document, BallotDocEvent, BallotPositionDocEvent, WriteupDocEvent, save_document_in_history
|
||||
from ietf.doc.models import DocEvent, Document, BallotDocEvent, BallotPositionDocEvent, WriteupDocEvent
|
||||
from ietf.doc.utils import get_document_content, add_state_change_event
|
||||
from ietf.person.models import Person
|
||||
from ietf.doc.lastcall import request_last_call
|
||||
|
@ -247,8 +247,6 @@ def doc_detail(request, date, name):
|
|||
new_tags = [tag] if tag else []
|
||||
|
||||
if state_form.changed_data:
|
||||
save_document_in_history(doc)
|
||||
|
||||
if 'state' in state_form.changed_data:
|
||||
doc.set_state(new_state)
|
||||
|
||||
|
@ -258,8 +256,8 @@ def doc_detail(request, date, name):
|
|||
|
||||
e = add_state_change_event(doc, login, prev_state, new_state,
|
||||
prev_tags=prev_tags, new_tags=new_tags)
|
||||
doc.time = (e and e.time) or datetime.datetime.now()
|
||||
doc.save()
|
||||
if e:
|
||||
doc.save_with_history([e])
|
||||
|
||||
email_state_changed(request, doc, e.desc, 'doc_state_edited')
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
</td>
|
||||
<td align="right">
|
||||
<br>
|
||||
<span class="login">{% if user|has_role:"Secretariat" %}Secretariat {% endif %}Logged in: <a href="/accounts/profile/">{{ user }}</a> | <a href="/accounts/logout/">Log out</a></span>
|
||||
<span class="login">{% if user|has_role:"Secretariat" %}Secretariat {% endif %}Logged in: <a href="/accounts/profile/">{{ user }}</a> | <a rel="nofollow" href="/accounts/logout/">Log out</a></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
<p>Use this to generate blue sheets for meeting sessions.</p>
|
||||
<ul class="none">
|
||||
<li>
|
||||
<button onclick="window.location='{% url "meetings_blue_sheet_generate" meeting_id=meeting.number%}'">Generate Blue Sheets</button>
|
||||
Last run:
|
||||
<form style="display:inline" method="post" action="{% url "meetings_blue_sheet_generate" meeting_id=meeting.number%}">{% csrf_token %}
|
||||
<input type="submit" value="Generate Blue Sheets">
|
||||
</form>
|
||||
Last run:
|
||||
{% if last_run %}
|
||||
{{ last_run }}
|
||||
{% else %}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
});
|
||||
|
||||
$('#generate-button').click(function(){
|
||||
var ajax_load = "<p><h4 align='center'>Generating Proceedings. This may take a few minutes.</h3><img class='loading' src='{% static 'secr/img/ajax-loader.gif' %}' alt='loading...' /></p>";
|
||||
var ajax_load = '<p><h4 align="center">Generating Proceedings. This may take a few minutes.</h3><img class="loading" src="{% static "secr/img/ajax-loader.gif" %}" alt="loading..." /></p>';
|
||||
var url = window.location.pathname;
|
||||
var parts = url.split("/");
|
||||
var loadUrl = "/secr/proceedings/ajax/generate-proceedings/" + parts[3] + "/";
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<h2>Proceedings</h2>
|
||||
<hr />
|
||||
<h2>{{ message }}</h2>
|
||||
<img class='loading' src='{% static 'secr/img/ajax-loader.gif' %}' alt='loading...' />
|
||||
<img class="loading" src="{% static "secr/img/ajax-loader.gif" %}" alt="loading..." />
|
||||
</div> <!-- module -->
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
$('#id_group').change(function(){
|
||||
var loadUrl = "/secr/roles/ajax/get-roles/" + $(this).val() + "/";
|
||||
var ajax_load = "<img class='loading' src='{% static 'secr/img/ajax-loader.gif' %}' alt='loading...' />";
|
||||
var ajax_load = '<img class="loading" src="{% static "secr/img/ajax-loader.gif" %}" alt="loading..." />';
|
||||
var text = $(this).val();
|
||||
$("#id_group_acronym").val(text);
|
||||
$("#roles-list").html(ajax_load).load(loadUrl);
|
||||
|
|
|
@ -365,6 +365,13 @@ MAX_WG_DELEGATES = 3
|
|||
DATE_FORMAT = "Y-m-d"
|
||||
DATETIME_FORMAT = "Y-m-d H:i T"
|
||||
|
||||
URL_REGEXPS = {
|
||||
"acronym": r"(?P<acronym>[a-zA-Z0-9-]+)",
|
||||
"date": r"(?P<date>\d{4}-\d{2}-\d{2})",
|
||||
"name": r"(?P<name>[A-Za-z0-9._\+\-]+)",
|
||||
"rev": r"(?P<rev>[0-9-]+)",
|
||||
}
|
||||
|
||||
# Override this in settings_local.py if needed
|
||||
# *_PATH variables ends with a slash/ .
|
||||
DOCUMENT_PATH_PATTERN = '/a/www/ietf-ftp/{doc.type_id}/'
|
||||
|
|
|
@ -5,7 +5,7 @@ import datetime
|
|||
from django.conf import settings
|
||||
|
||||
from ietf.doc.models import Document, State, DocAlias, DocEvent, DocumentAuthor
|
||||
from ietf.doc.models import NewRevisionDocEvent, save_document_in_history
|
||||
from ietf.doc.models import NewRevisionDocEvent
|
||||
from ietf.doc.models import RelatedDocument, DocRelationshipName
|
||||
from ietf.doc.utils import add_state_change_event, rebuild_reference_relations
|
||||
from ietf.doc.utils import set_replaces_for_document
|
||||
|
@ -126,19 +126,23 @@ def create_submission_event(request, submission, desc):
|
|||
|
||||
|
||||
def post_submission(request, submission):
|
||||
# find out who did it
|
||||
system = Person.objects.get(name="(System)")
|
||||
submitter_parsed = submission.submitter_parsed()
|
||||
if submitter_parsed["name"] and submitter_parsed["email"]:
|
||||
submitter = ensure_person_email_info_exists(submitter_parsed["name"], submitter_parsed["email"]).person
|
||||
else:
|
||||
submitter = system
|
||||
|
||||
# update draft attributes
|
||||
try:
|
||||
draft = Document.objects.get(name=submission.name)
|
||||
save_document_in_history(draft)
|
||||
except Document.DoesNotExist:
|
||||
draft = Document(name=submission.name)
|
||||
draft.intended_std_level = None
|
||||
draft = Document.objects.create(name=submission.name, type_id="draft")
|
||||
|
||||
prev_rev = draft.rev
|
||||
|
||||
draft.type_id = "draft"
|
||||
draft.time = datetime.datetime.now()
|
||||
draft.title = submission.title
|
||||
group = submission.group or Group.objects.get(type="individ")
|
||||
if not (group.type_id == "individ" and draft.group and draft.group.type_id == "area"):
|
||||
|
@ -163,16 +167,23 @@ def post_submission(request, submission):
|
|||
draft.stream = StreamName.objects.get(slug=stream_slug)
|
||||
|
||||
draft.expires = datetime.datetime.now() + datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
|
||||
draft.save()
|
||||
|
||||
submitter_parsed = submission.submitter_parsed()
|
||||
if submitter_parsed["name"] and submitter_parsed["email"]:
|
||||
submitter = ensure_person_email_info_exists(submitter_parsed["name"], submitter_parsed["email"]).person
|
||||
else:
|
||||
submitter = system
|
||||
events = []
|
||||
|
||||
# new revision event
|
||||
e = NewRevisionDocEvent.objects.create(
|
||||
type="new_revision",
|
||||
doc=draft,
|
||||
rev=draft.rev,
|
||||
by=submitter,
|
||||
desc="New version available: <b>%s-%s.txt</b>" % (draft.name, draft.rev),
|
||||
)
|
||||
events.append(e)
|
||||
|
||||
# update related objects
|
||||
DocAlias.objects.get_or_create(name=submission.name, document=draft)
|
||||
|
||||
draft.set_state(State.objects.get(used=True, type="draft", slug="active"))
|
||||
DocAlias.objects.get_or_create(name=submission.name, document=draft)
|
||||
|
||||
update_authors(draft, submission)
|
||||
|
||||
|
@ -180,29 +191,15 @@ def post_submission(request, submission):
|
|||
if trouble:
|
||||
log('Rebuild_reference_relations trouble: %s'%trouble)
|
||||
|
||||
# new revision event
|
||||
e = NewRevisionDocEvent(type="new_revision", doc=draft, rev=draft.rev)
|
||||
e.time = draft.time #submission.submission_date
|
||||
e.by = submitter
|
||||
e.desc = "New version available: <b>%s-%s.txt</b>" % (draft.name, draft.rev)
|
||||
e.save()
|
||||
|
||||
if draft.stream_id == "ietf" and draft.group.type_id == "wg" and draft.rev == "00":
|
||||
# automatically set state "WG Document"
|
||||
draft.set_state(State.objects.get(used=True, type="draft-stream-%s" % draft.stream_id, slug="wg-doc"))
|
||||
|
||||
# automatic state changes
|
||||
if draft.get_state_slug("draft-iana-review") in ("ok-act", "ok-noact", "not-ok"):
|
||||
prev_state = draft.get_state("draft-iana-review")
|
||||
next_state = State.objects.get(used=True, type="draft-iana-review", slug="changed")
|
||||
draft.set_state(next_state)
|
||||
add_state_change_event(draft, submitter, prev_state, next_state)
|
||||
e = add_state_change_event(draft, submitter, prev_state, next_state)
|
||||
if e:
|
||||
events.append(e)
|
||||
|
||||
# clean up old files
|
||||
if prev_rev != draft.rev:
|
||||
from ietf.doc.expire import move_draft_files_to_archive
|
||||
move_draft_files_to_archive(draft, prev_rev)
|
||||
|
||||
# automatic state changes
|
||||
state_change_msg = ""
|
||||
|
||||
if not was_rfc and draft.tags.filter(slug="need-rev"):
|
||||
|
@ -213,9 +210,22 @@ def post_submission(request, submission):
|
|||
e.desc = "Sub state has been changed to <b>AD Followup</b> from <b>Revised ID Needed</b>"
|
||||
e.by = system
|
||||
e.save()
|
||||
events.append(e)
|
||||
|
||||
state_change_msg = e.desc
|
||||
|
||||
if draft.stream_id == "ietf" and draft.group.type_id == "wg" and draft.rev == "00":
|
||||
# automatically set state "WG Document"
|
||||
draft.set_state(State.objects.get(used=True, type="draft-stream-%s" % draft.stream_id, slug="wg-doc"))
|
||||
|
||||
# save history now that we're done with changes to the draft itself
|
||||
draft.save_with_history(events)
|
||||
|
||||
# clean up old files
|
||||
if prev_rev != draft.rev:
|
||||
from ietf.doc.expire import move_draft_files_to_archive
|
||||
move_draft_files_to_archive(draft, prev_rev)
|
||||
|
||||
move_files_to_repository(submission)
|
||||
submission.state = DraftSubmissionStateName.objects.get(slug="posted")
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ from django.utils.http import urlquote
|
|||
from django.conf import settings
|
||||
|
||||
from ietf.doc.mails import email_state_changed
|
||||
from ietf.doc.models import Document, DocEvent, State, StateDocEvent, StateType, save_document_in_history
|
||||
from ietf.doc.models import Document, DocEvent, State, StateDocEvent, StateType
|
||||
from ietf.doc.utils import add_state_change_event
|
||||
from ietf.person.models import Person
|
||||
from ietf.utils.timezone import local_timezone_to_utc, email_time_to_local_timezone, utc_to_local_timezone
|
||||
|
@ -201,15 +201,14 @@ def update_history_with_changes(changes, send_email=True):
|
|||
added_events.append(e)
|
||||
|
||||
if not StateDocEvent.objects.filter(doc=doc, time__gt=timestamp, state_type=state_type):
|
||||
save_document_in_history(doc)
|
||||
doc.set_state(state)
|
||||
|
||||
if e:
|
||||
doc.save_with_history([e])
|
||||
|
||||
if send_email and (state != prev_state):
|
||||
email_state_changed(None, doc, "IANA %s state changed to %s" % (kind, state.name),'doc_iana_state_changed')
|
||||
|
||||
if doc.time < timestamp:
|
||||
doc.time = timestamp
|
||||
doc.save()
|
||||
|
||||
return added_events, warnings
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ from xml.dom import pulldom, Node
|
|||
from django.conf import settings
|
||||
|
||||
from ietf.doc.models import ( Document, DocAlias, State, StateType, DocEvent, DocRelationshipName,
|
||||
DocTagName, DocTypeName, RelatedDocument, save_document_in_history )
|
||||
DocTagName, DocTypeName, RelatedDocument )
|
||||
from ietf.doc.expire import move_draft_files_to_archive
|
||||
from ietf.doc.utils import add_state_change_event
|
||||
from ietf.doc.utils import add_state_change_event, prettify_std_name
|
||||
from ietf.group.models import Group
|
||||
from ietf.name.models import StdLevelName, StreamName
|
||||
from ietf.person.models import Person
|
||||
|
@ -37,6 +37,8 @@ def fetch_queue_xml(url):
|
|||
return urllib2.urlopen(url)
|
||||
|
||||
def parse_queue(response):
|
||||
"""Parse RFC Editor queue XML into a bunch of tuples + warnings."""
|
||||
|
||||
events = pulldom.parse(response)
|
||||
drafts = []
|
||||
warnings = []
|
||||
|
@ -108,6 +110,9 @@ def parse_queue(response):
|
|||
return drafts, warnings
|
||||
|
||||
def update_drafts_from_queue(drafts):
|
||||
"""Given a list of parsed drafts from the RFC Editor queue, update the
|
||||
documents in the database. Return those that were changed."""
|
||||
|
||||
tag_mapping = {
|
||||
'IANA': DocTagName.objects.get(slug='iana'),
|
||||
'REF': DocTagName.objects.get(slug='ref')
|
||||
|
@ -154,6 +159,7 @@ def update_drafts_from_queue(drafts):
|
|||
|
||||
prev_state = d.get_state("draft-rfceditor")
|
||||
next_state = state_mapping[state]
|
||||
events = []
|
||||
|
||||
# check if we've noted it's been received
|
||||
if d.get_state_slug("draft-iesg") == "ann" and not prev_state and not d.latest_event(DocEvent, type="rfc_editor_received_announcement"):
|
||||
|
@ -166,15 +172,15 @@ def update_drafts_from_queue(drafts):
|
|||
# change draft-iesg state to RFC Ed Queue
|
||||
prev_iesg_state = State.objects.get(used=True, type="draft-iesg", slug="ann")
|
||||
next_iesg_state = State.objects.get(used=True, type="draft-iesg", slug="rfcqueue")
|
||||
save_document_in_history(d)
|
||||
|
||||
d.set_state(next_iesg_state)
|
||||
add_state_change_event(d, system, prev_iesg_state, next_iesg_state)
|
||||
e = add_state_change_event(d, system, prev_iesg_state, next_iesg_state)
|
||||
if e:
|
||||
events.append(e)
|
||||
changed.add(name)
|
||||
|
||||
# check draft-rfceditor state
|
||||
if prev_state != next_state:
|
||||
save_document_in_history(d)
|
||||
|
||||
d.set_state(next_state)
|
||||
|
||||
e = add_state_change_event(d, system, prev_state, next_state)
|
||||
|
@ -183,6 +189,9 @@ def update_drafts_from_queue(drafts):
|
|||
e.desc = re.sub(r"(<b>.*</b>)", "<a href=\"%s\">\\1</a>" % auth48, e.desc)
|
||||
e.save()
|
||||
|
||||
if e:
|
||||
events.append(e)
|
||||
|
||||
changed.add(name)
|
||||
|
||||
t = DocTagName.objects.filter(slug__in=tags)
|
||||
|
@ -190,6 +199,9 @@ def update_drafts_from_queue(drafts):
|
|||
d.tags = t
|
||||
changed.add(name)
|
||||
|
||||
if events:
|
||||
d.save_with_history(events)
|
||||
|
||||
|
||||
# remove tags and states for those not in the queue anymore
|
||||
for d in Document.objects.exclude(docalias__name__in=names).filter(states__type="draft-rfceditor").distinct():
|
||||
|
@ -207,6 +219,8 @@ def fetch_index_xml(url):
|
|||
return urllib2.urlopen(url)
|
||||
|
||||
def parse_index(response):
|
||||
"""Parse RFC Editor index XML into a bunch of tuples."""
|
||||
|
||||
def normalize_std_name(std_name):
|
||||
# remove zero padding
|
||||
prefix = std_name[:3]
|
||||
|
@ -297,6 +311,10 @@ def parse_index(response):
|
|||
|
||||
|
||||
def update_docs_from_rfc_index(data, skip_older_than_date=None):
|
||||
"""Given parsed data from the RFC Editor index, update the documents
|
||||
in the database. Yields a list of change descriptions for each
|
||||
document, if any."""
|
||||
|
||||
std_level_mapping = {
|
||||
"Standard": StdLevelName.objects.get(slug="std"),
|
||||
"Internet Standard": StdLevelName.objects.get(slug="std"),
|
||||
|
@ -323,9 +341,6 @@ def update_docs_from_rfc_index(data, skip_older_than_date=None):
|
|||
|
||||
system = Person.objects.get(name="(System)")
|
||||
|
||||
results = []
|
||||
new_rfcs = []
|
||||
|
||||
for rfc_number, title, authors, rfc_published_date, current_status, updates, updated_by, obsoletes, obsoleted_by, also, draft, has_errata, stream, wg, file_formats, pages, abstract in data:
|
||||
|
||||
if skip_older_than_date and rfc_published_date < skip_older_than_date:
|
||||
|
@ -335,6 +350,9 @@ def update_docs_from_rfc_index(data, skip_older_than_date=None):
|
|||
# we assume two things can happen: we get a new RFC, or an
|
||||
# attribute has been updated at the RFC Editor (RFC Editor
|
||||
# attributes take precedence over our local attributes)
|
||||
events = []
|
||||
changes = []
|
||||
rfc_published = False
|
||||
|
||||
# make sure we got the document and alias
|
||||
doc = None
|
||||
|
@ -350,42 +368,45 @@ def update_docs_from_rfc_index(data, skip_older_than_date=None):
|
|||
pass
|
||||
|
||||
if not doc:
|
||||
results.append("created document %s" % name)
|
||||
changes.append("created document %s" % prettify_std_name(name))
|
||||
doc = Document.objects.create(name=name, type=DocTypeName.objects.get(slug="draft"))
|
||||
|
||||
# add alias
|
||||
DocAlias.objects.get_or_create(name=name, document=doc)
|
||||
results.append("created alias %s to %s" % (name, doc.name))
|
||||
changes.append("created alias %s" % prettify_std_name(name))
|
||||
|
||||
# check attributes
|
||||
changed_attributes = {}
|
||||
changed_states = []
|
||||
created_relations = []
|
||||
other_changes = False
|
||||
if title != doc.title:
|
||||
changed_attributes["title"] = title
|
||||
doc.title = title
|
||||
changes.append("changed title to '%s'" % doc.title)
|
||||
|
||||
if abstract and abstract != doc.abstract:
|
||||
changed_attributes["abstract"] = abstract
|
||||
doc.abstract = abstract
|
||||
changes.append("changed abstract to '%s'" % doc.abstract)
|
||||
|
||||
if pages and int(pages) != doc.pages:
|
||||
changed_attributes["pages"] = int(pages)
|
||||
doc.pages = int(pages)
|
||||
changes.append("changed pages to %s" % doc.pages)
|
||||
|
||||
if std_level_mapping[current_status] != doc.std_level:
|
||||
changed_attributes["std_level"] = std_level_mapping[current_status]
|
||||
doc.std_level = std_level_mapping[current_status]
|
||||
changes.append("changed standardization level to %s" % doc.std_level)
|
||||
|
||||
if doc.get_state_slug() != "rfc":
|
||||
changed_states.append(State.objects.get(used=True, type="draft", slug="rfc"))
|
||||
doc.set_state(State.objects.get(used=True, type="draft", slug="rfc"))
|
||||
move_draft_files_to_archive(doc, doc.rev)
|
||||
changes.append("changed state to %s" % doc.get_state())
|
||||
|
||||
if doc.stream != stream_mapping[stream]:
|
||||
changed_attributes["stream"] = stream_mapping[stream]
|
||||
doc.stream = stream_mapping[stream]
|
||||
changes.append("changed stream to %s" % doc.stream)
|
||||
|
||||
if not doc.group: # if we have no group assigned, check if RFC Editor has a suggestion
|
||||
if wg:
|
||||
changed_attributes["group"] = Group.objects.get(acronym=wg)
|
||||
doc.group = Group.objects.get(acronym=wg)
|
||||
changes.append("set group to %s" % doc.group)
|
||||
else:
|
||||
changed_attributes["group"] = Group.objects.get(type="individ")
|
||||
doc.group = Group.objects.get(type="individ") # fallback for newly created doc
|
||||
|
||||
if not doc.latest_event(type="published_rfc"):
|
||||
e = DocEvent(doc=doc, type="published_rfc")
|
||||
|
@ -404,15 +425,17 @@ def update_docs_from_rfc_index(data, skip_older_than_date=None):
|
|||
e.by = system
|
||||
e.desc = "RFC published"
|
||||
e.save()
|
||||
other_changes = True
|
||||
events.append(e)
|
||||
|
||||
results.append("Added RFC published event: %s" % e.time.strftime("%Y-%m-%d"))
|
||||
new_rfcs.append(doc)
|
||||
changes.append("added RFC published event at %s" % e.time.strftime("%Y-%m-%d"))
|
||||
rfc_published = True
|
||||
|
||||
for t in ("draft-iesg", "draft-stream-iab", "draft-stream-irtf", "draft-stream-ise"):
|
||||
slug = doc.get_state_slug(t)
|
||||
if slug and slug != "pub":
|
||||
changed_states.append(State.objects.get(used=True, type=t, slug="pub"))
|
||||
new_state = State.objects.select_related("type").get(used=True, type=t, slug="pub")
|
||||
doc.set_state(new_state)
|
||||
changes.append("changed %s to %s" % (new_state.type.label, new_state))
|
||||
|
||||
def parse_relation_list(l):
|
||||
res = []
|
||||
|
@ -431,46 +454,42 @@ def update_docs_from_rfc_index(data, skip_older_than_date=None):
|
|||
|
||||
for x in parse_relation_list(obsoletes):
|
||||
if not RelatedDocument.objects.filter(source=doc, target=x, relationship=relationship_obsoletes):
|
||||
created_relations.append(RelatedDocument(source=doc, target=x, relationship=relationship_obsoletes))
|
||||
r = RelatedDocument.objects.create(RelatedDocument(source=doc, target=x, relationship=relationship_obsoletes))
|
||||
changes.append("created %s relation between %s and %s" % (r.relationship.name.lower(), prettify_std_name(r.source.name), prettify_std_name(r.target.name)))
|
||||
|
||||
for x in parse_relation_list(updates):
|
||||
if not RelatedDocument.objects.filter(source=doc, target=x, relationship=relationship_updates):
|
||||
created_relations.append(RelatedDocument(source=doc, target=x, relationship=relationship_updates))
|
||||
r = RelatedDocument.objects.create(source=doc, target=x, relationship=relationship_updates)
|
||||
changes.append("created %s relation between %s and %s" % (r.relationship.name.lower(), prettify_std_name(r.source.name), prettify_std_name(r.target.name)))
|
||||
|
||||
if also:
|
||||
for a in also:
|
||||
a = a.lower()
|
||||
if not DocAlias.objects.filter(name=a):
|
||||
DocAlias.objects.create(name=a, document=doc)
|
||||
other_changes = True
|
||||
results.append("Created alias %s to %s" % (a, doc.name))
|
||||
changes.append("created alias %s" % prettify_std_name(a))
|
||||
|
||||
if has_errata:
|
||||
if not doc.tags.filter(pk=tag_has_errata.pk):
|
||||
changed_attributes["tags"] = list(doc.tags.all()) + [tag_has_errata]
|
||||
doc.tags.add(tag_has_errata)
|
||||
changes.append("added Errata tag")
|
||||
else:
|
||||
if doc.tags.filter(pk=tag_has_errata.pk):
|
||||
changed_attributes["tags"] = set(doc.tags.all()) - set([tag_has_errata])
|
||||
doc.tags.remove(tag_has_errata)
|
||||
changes.append("removed Errata tag")
|
||||
|
||||
if changed_attributes or changed_states or created_relations or other_changes:
|
||||
# apply changes
|
||||
save_document_in_history(doc)
|
||||
for k, v in changed_attributes.iteritems():
|
||||
setattr(doc, k, v)
|
||||
results.append("Changed %s to %s on %s" % (k, v, doc.name))
|
||||
if changes:
|
||||
events.append(DocEvent.objects.create(
|
||||
doc=doc,
|
||||
by=system,
|
||||
type="sync_from_rfc_editor",
|
||||
desc=u"Received changes through RFC Editor sync (%s)" % u", ".join(changes),
|
||||
))
|
||||
|
||||
for s in changed_states:
|
||||
doc.set_state(s)
|
||||
results.append("Set state %s on %s" % (s, doc.name))
|
||||
doc.save_with_history(events)
|
||||
|
||||
for o in created_relations:
|
||||
o.save()
|
||||
results.append("Created %s" % o)
|
||||
|
||||
doc.time = datetime.datetime.now()
|
||||
doc.save()
|
||||
|
||||
return results, new_rfcs
|
||||
if changes:
|
||||
yield changes, doc, rfc_published
|
||||
|
||||
|
||||
def post_approved_draft(url, name):
|
||||
|
|
|
@ -327,12 +327,15 @@ class RFCSyncTests(TestCase):
|
|||
draft_filename = "%s-%s.txt" % (doc.name, doc.rev)
|
||||
self.write_draft_file(draft_filename, 5000)
|
||||
|
||||
changed,_ = rfceditor.update_docs_from_rfc_index(data, today - datetime.timedelta(days=30))
|
||||
changes = []
|
||||
for cs, d, rfc_published in rfceditor.update_docs_from_rfc_index(data, today - datetime.timedelta(days=30)):
|
||||
changes.append(cs)
|
||||
|
||||
doc = Document.objects.get(name=doc.name)
|
||||
|
||||
self.assertEqual(doc.docevent_set.all()[0].type, "published_rfc")
|
||||
self.assertEqual(doc.docevent_set.all()[0].time.date(), today)
|
||||
self.assertEqual(doc.docevent_set.all()[0].type, "sync_from_rfc_editor")
|
||||
self.assertEqual(doc.docevent_set.all()[1].type, "published_rfc")
|
||||
self.assertEqual(doc.docevent_set.all()[1].time.date(), today)
|
||||
self.assertTrue("errata" in doc.tags.all().values_list("slug", flat=True))
|
||||
self.assertTrue(DocAlias.objects.filter(name="rfc1234", document=doc))
|
||||
self.assertTrue(DocAlias.objects.filter(name="bcp1", document=doc))
|
||||
|
@ -350,7 +353,7 @@ class RFCSyncTests(TestCase):
|
|||
self.assertTrue(os.path.exists(os.path.join(self.archive_dir, draft_filename)))
|
||||
|
||||
# make sure we can apply it again with no changes
|
||||
changed,_ = rfceditor.update_docs_from_rfc_index(data, today - datetime.timedelta(days=30))
|
||||
changed = list(rfceditor.update_docs_from_rfc_index(data, today - datetime.timedelta(days=30)))
|
||||
self.assertEqual(len(changed), 0)
|
||||
|
||||
|
||||
|
|
|
@ -4,14 +4,13 @@ import os
|
|||
import json
|
||||
|
||||
from django.http import HttpResponse, HttpResponseForbidden, HttpResponseServerError, HttpResponseRedirect, Http404
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
from django.shortcuts import render
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from ietf.doc.models import DeletedEvent, StateDocEvent
|
||||
from ietf.doc.models import DeletedEvent, StateDocEvent, DocEvent
|
||||
from ietf.ietfauth.utils import role_required, has_role
|
||||
from ietf.sync.discrepancies import find_discrepancies
|
||||
from ietf.utils.serialize import object_as_shallow_dict
|
||||
|
@ -22,9 +21,7 @@ SYNC_BIN_PATH = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__f
|
|||
def discrepancies(request):
|
||||
sections = find_discrepancies()
|
||||
|
||||
return render_to_response("sync/discrepancies.html",
|
||||
dict(sections=sections),
|
||||
context_instance=RequestContext(request))
|
||||
return render(request, "sync/discrepancies.html", dict(sections=sections))
|
||||
|
||||
@csrf_exempt # external API so we can't expect the other end to have a token
|
||||
def notify(request, org, notification):
|
||||
|
@ -100,19 +97,27 @@ def notify(request, org, notification):
|
|||
else:
|
||||
return HttpResponse("OK", content_type="text/plain; charset=%s"%settings.DEFAULT_CHARSET)
|
||||
|
||||
return render_to_response('sync/notify.html',
|
||||
dict(org=known_orgs[org],
|
||||
notification=notification,
|
||||
help_text=known_notifications[notification],
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
return render(request, 'sync/notify.html',
|
||||
dict(org=known_orgs[org],
|
||||
notification=notification,
|
||||
help_text=known_notifications[notification],
|
||||
))
|
||||
|
||||
@role_required('Secretariat', 'RFC Editor')
|
||||
def rfceditor_undo(request):
|
||||
"""Undo a DocEvent."""
|
||||
events = StateDocEvent.objects.filter(state_type="draft-rfceditor",
|
||||
time__gte=datetime.datetime.now() - datetime.timedelta(weeks=1)
|
||||
).order_by("-time", "-id")
|
||||
events = []
|
||||
events.extend(StateDocEvent.objects.filter(
|
||||
state_type="draft-rfceditor",
|
||||
time__gte=datetime.datetime.now() - datetime.timedelta(weeks=1)
|
||||
).order_by("-time", "-id"))
|
||||
|
||||
events.extend(DocEvent.objects.filter(
|
||||
type="sync_from_rfc_editor",
|
||||
time__gte=datetime.datetime.now() - datetime.timedelta(weeks=1)
|
||||
).order_by("-time", "-id"))
|
||||
|
||||
events.sort(key=lambda e: (e.time, e.id), reverse=True)
|
||||
|
||||
if request.method == "POST":
|
||||
try:
|
||||
|
@ -120,9 +125,10 @@ def rfceditor_undo(request):
|
|||
except ValueError:
|
||||
return HttpResponse("Could not parse event id")
|
||||
|
||||
try:
|
||||
e = events.get(id=eid)
|
||||
except StateDocEvent.DoesNotExist:
|
||||
for e in events:
|
||||
if e.id == eid:
|
||||
break
|
||||
else:
|
||||
return HttpResponse("Event does not exist")
|
||||
|
||||
doc = e.doc
|
||||
|
@ -145,7 +151,4 @@ def rfceditor_undo(request):
|
|||
|
||||
return HttpResponseRedirect("")
|
||||
|
||||
return render_to_response('sync/rfceditor_undo.html',
|
||||
dict(events=events,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
return render(request, 'sync/rfceditor_undo.html', dict(events=events))
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
{% bootstrap_messages %}
|
||||
|
||||
<p class="alert alert-info">The text will be submitted as <b>charter-ietf-{{ name }}-{{ next_rev }}</b>.</p>
|
||||
<p class="alert alert-info">The text will be submitted as <b>{{ name }}-{{ next_rev }}</b>.</p>
|
||||
|
||||
<form enctype="multipart/form-data" method="post">
|
||||
{% csrf_token %}
|
||||
|
@ -22,7 +22,11 @@
|
|||
|
||||
{% buttons %}
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
<a class="btn btn-default pull-right" href="{% url "doc_view" name=group.charter.name %}">Back</a>
|
||||
{% if group.charter %}
|
||||
<a class="btn btn-default pull-right" href="{% url "doc_view" name=name %}">Back</a>
|
||||
{% else %}
|
||||
<a class="btn btn-default pull-right" href="{% url "group_charter" group_type=group.type_id acronym=group.acronym %}">Back</a>
|
||||
{% endif %}
|
||||
{% endbuttons %}
|
||||
</form>
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
<th></th>
|
||||
<th>Replaces</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_stream_info %}
|
||||
{% if can_edit_stream_info and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_replaces" name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
@ -106,7 +106,7 @@
|
|||
<tr>
|
||||
<th>Possibly Replaces</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_replaces %}
|
||||
{% if can_edit_replaces and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_review_possibly_replaces" name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
@ -120,7 +120,7 @@
|
|||
<tr>
|
||||
<th>Possibly Replaced By</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_replaces %}
|
||||
{% if can_edit_replaces and not snapshot %}
|
||||
{% comment %}<a class="btn btn-default btn-xs" href="{% url "doc_review_possibly_replaces" name=doc.name %}">Edit</a>{% endcomment %}
|
||||
{% endif %}
|
||||
</td>
|
||||
|
@ -135,7 +135,7 @@
|
|||
<th></th>
|
||||
<th>Stream</th>
|
||||
<td class="edit">
|
||||
{% if can_change_stream %}
|
||||
{% if can_change_stream and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_stream" name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
@ -149,8 +149,8 @@
|
|||
<th></th>
|
||||
<th>Intended RFC status</th>
|
||||
<td class="edit">
|
||||
{% if can_edit or can_edit_stream_info %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_intended_status" name=doc.name %}">Edit</a>
|
||||
{% if can_edit_stream_info and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_intended_status" name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
|
@ -201,7 +201,7 @@
|
|||
{% endif %}
|
||||
</th>
|
||||
<td class="edit">
|
||||
{% if doc.stream and can_edit_stream_info %}
|
||||
{% if doc.stream and can_edit_stream_info and doc.stream.slug != "legacy" and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_stream_state" name=doc.name state_type=stream_state_type_slug %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
@ -228,7 +228,7 @@
|
|||
<th></th>
|
||||
<th>Consensus</th>
|
||||
<td class="edit">
|
||||
{% if can_edit or can_edit_stream_info %}
|
||||
{% if can_edit_stream_info and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_edit_consensus" name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
@ -241,13 +241,15 @@
|
|||
<tr>
|
||||
<th></th>
|
||||
<th>Document shepherd</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_stream_info %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_edit_shepherd" name=doc.name %}">Edit</a>
|
||||
{% elif is_shepherd %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_shepherd_email" name=doc.name %}">Change Email</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="edit">
|
||||
{% if not snapshot %}
|
||||
{% if can_edit_stream_info %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_edit_shepherd" name=doc.name %}">Edit</a>
|
||||
{% elif is_shepherd %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_shepherd_email" name=doc.name %}">Change Email</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if doc.shepherd %}{{ doc.shepherd.person }}{% else %}No shepherd assigned{% endif %}
|
||||
</td>
|
||||
|
@ -258,7 +260,7 @@
|
|||
<th></th>
|
||||
<th>Shepherd write-up</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_shepherd_writeup %}
|
||||
{% if can_edit_shepherd_writeup and not snapshot %}
|
||||
{% url "doc_edit_shepherd_writeup" name=doc.name as doc_edit_url %}
|
||||
{% if doc_edit_url %}
|
||||
<a class="btn btn-default btn-xs" href="{{doc_edit_url}}">Edit</a>
|
||||
|
@ -289,7 +291,7 @@
|
|||
<th>IESG</th>
|
||||
<th><a href="{% url "ietf.help.views.state" doc=doc.type.slug type="iesg" %}">IESG state</a></th>
|
||||
<td class="edit">
|
||||
{% if iesg_state and can_edit %}
|
||||
{% if started_iesg_process and doc.get_state_slug != "expired" and can_edit and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_state" name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
@ -302,7 +304,7 @@
|
|||
<th></th>
|
||||
<th>Telechat date</th>
|
||||
<td class="edit">
|
||||
{% if can_edit %}
|
||||
{% if can_edit and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_telechat_date" name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
@ -328,7 +330,7 @@
|
|||
<th></th>
|
||||
<th>Responsible AD</th>
|
||||
<td class="edit">
|
||||
{% if can_edit %}
|
||||
{% if can_edit and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_ad" name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
@ -343,7 +345,7 @@
|
|||
<th></th>
|
||||
<th>IESG note</th>
|
||||
<td class="edit">
|
||||
{% if can_edit %}
|
||||
{% if can_edit and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_iesg_note" name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
@ -358,7 +360,7 @@
|
|||
<th></th>
|
||||
<th>Send notices to</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_notify %}
|
||||
{% if can_edit_notify and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_notify" name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
@ -375,7 +377,7 @@
|
|||
<th>IANA</th>
|
||||
<th><a href="{% url "ietf.help.views.state" doc=doc.type.slug type="iana-review" %}">IANA review state</a></th>
|
||||
<td class="edit">
|
||||
{% if can_edit_iana_state %}
|
||||
{% if can_edit_iana_state and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_iana_state" name=doc.name state_type="iana-review" %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
@ -388,7 +390,7 @@
|
|||
<th></th>
|
||||
<th>IANA action state</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_iana_state %}
|
||||
{% if can_edit_iana_state and not snapshot %}
|
||||
<a class="btn btn-default btn-xs" href="{% url "doc_change_iana_state" name=doc.name state_type="iana-action" %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<h1>RFC status changes</h1>
|
||||
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
<p><a class="btn btn-default" href="{% url "start_rfc_status_change" name='' %}">New RFC status change</a></p>
|
||||
<p><a class="btn btn-default" href="{% url "start_rfc_status_change" %}">New RFC status change</a></p>
|
||||
{% endif %}
|
||||
|
||||
{% regroup docs by get_state as state_groups %}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{login}} has requested publication of {{doc.name}}-{{doc.rev}} as {{doc.intended_std_level}} on behalf of the {{doc.group.acronym|upper}} working group.
|
||||
{{by}} has requested publication of {{doc.name}}-{{doc.rev}} as {{doc.intended_std_level}} on behalf of the {{doc.group.acronym|upper}} working group.
|
||||
|
||||
Please verify the document's state at {{url}}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
{% else %}
|
||||
(None)
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
<a class="btn btn-warning btn-xs" href="{% url "ietf.group.edit.submit_initial_charter" group_type=group.type_id acronym=group.acronym %}">Submit charter</a>
|
||||
<a class="btn btn-warning btn-xs" href="{{ charter_submit_url }}">Submit charter</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
{# Copyright The IETF Trust 2015, All Rights Reserved #}{% load origin %}{% origin %}
|
||||
{{ obj.body|truncatewords:"30"|wordwrap:"71"|linebreaksbr }}
|
||||
{% with obj.attachments.all as attachments %}
|
||||
<h3>Attached Document{{ attachments|pluralize }}</h3>
|
||||
{% if attachments %}
|
||||
<ul>
|
||||
{% for doc in attachments %}
|
||||
<li><a href="{{ doc.href }}">{{ doc.title }}</a><br>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>NONE</p>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<h3>Attached Document{{ attachments|pluralize }}</h3>
|
||||
{% if attachments %}
|
||||
<ul>
|
||||
{% for doc in attachments %}
|
||||
<li><a href="{{ doc.href }}">{{ doc.title }}</a><br>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>NONE</p>
|
||||
{% endif %}
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<a href="/wg/">Active IETF working groups</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/liaison/managers/">IETF liaison managers</a>
|
||||
<a href="https://www.ietf.org/liaison/managers.html">IETF liaison managers</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -32,28 +32,28 @@
|
|||
|
||||
<tr>
|
||||
<td>The IAB</td>
|
||||
<td><a href="/liaison/managers/">The IETF Liaison Manager for the SDO</a> <sup><small>(4)</small></sup><br>
|
||||
<td><a href="https://www.ietf.org/liaison/managers.html">The IETF Liaison Manager for the SDO</a> <sup><small>(4)</small></sup><br>
|
||||
The IAB Chair (if not the submitter) <iab-chair@iab.org><br>
|
||||
The IAB <iab@iab.org></li></td></tr>
|
||||
<tr>
|
||||
<td>The IESG</td>
|
||||
<td><a href="/liaison/managers/">The IETF Liaison Manager for the SDO</a> <sup><small>(4)</small></sup><br>
|
||||
<td><a href="https://www.ietf.org/liaison/managers.html">The IETF Liaison Manager for the SDO</a> <sup><small>(4)</small></sup><br>
|
||||
The IETF Chair (if not the submitter) <chair@ietf.org><br>
|
||||
The IESG <iesg@ietf.org></li></td></tr>
|
||||
<tr>
|
||||
<td>The IETF</td>
|
||||
<td><a href="/liaison/managers/">The IETF Liaison Manager for the SDO</a> <sup><small>(4)</small></sup><br>
|
||||
<td><a href="https://www.ietf.org/liaison/managers.html">The IETF Liaison Manager for the SDO</a> <sup><small>(4)</small></sup><br>
|
||||
The IETF Chair (if not the submitter) <chair@ietf.org><br>
|
||||
The IESG <iesg@ietf.org></li></td></tr>
|
||||
<tr>
|
||||
<td>An IETF Area</td>
|
||||
<td><a href="/liaison/managers/">The IETF Liaison Manager for the SDO</a> <sup><small>(4)</small></sup><br>
|
||||
<td><a href="https://www.ietf.org/liaison/managers.html">The IETF Liaison Manager for the SDO</a> <sup><small>(4)</small></sup><br>
|
||||
<a href="/wg/">The IETF Area Director(s)</a> (if not the submitter)<br>
|
||||
The IETF Chair <chair@ietf.org><br>
|
||||
The IETF Area Directorate Mailing List (where applicable) <sup><small>(5)</small></sup></li></td></tr>
|
||||
<tr>
|
||||
<td>An IETF Working Group</td>
|
||||
<td><a href="/liaison/managers/">The IETF Liaison Manager for the SDO</a> <sup><small>(4)</small></sup><br>
|
||||
<td><a href="https://www.ietf.org/liaison/managers.html">The IETF Liaison Manager for the SDO</a> <sup><small>(4)</small></sup><br>
|
||||
<a href="/wg/">The IETF Working Group Chair(s)</a> (if not the submitter)<br>
|
||||
<a href="/wg/">The IETF Area Director(s)</a><br>
|
||||
<a href="/wg/">The IETF Working Group Discussion List</a></li></td></tr>
|
||||
|
|
|
@ -28,28 +28,28 @@
|
|||
<tr>
|
||||
<td>The IAB </td>
|
||||
<td>The IAB Chair <iab-chair@iab.org></td>
|
||||
<td><a href="/liaison/managers/">The IETF Liaison Manager for the SDO</a><br>
|
||||
<td><a href="https://www.ietf.org/liaison/managers.html">The IETF Liaison Manager for the SDO</a><br>
|
||||
The IAB <iab@iab.org></td></tr>
|
||||
<tr>
|
||||
<td>The IESG </td>
|
||||
<td>The IETF Chair <chair@ietf.org></td>
|
||||
<td><a href="/liaison/managers/">The IETF Liaison Manager for the SDO</a><br>
|
||||
<td><a href="https://www.ietf.org/liaison/managers.html">The IETF Liaison Manager for the SDO</a><br>
|
||||
The IESG <iesg@ietf.org></td></tr>
|
||||
<tr>
|
||||
<td>The IETF </td>
|
||||
<td>The IETF Chair <chair@ietf.org></td>
|
||||
<td><a href="/liaison/managers/">The IETF Liaison Manager for the SDO</a><br>
|
||||
<td><a href="https://www.ietf.org/liaison/managers.html">The IETF Liaison Manager for the SDO</a><br>
|
||||
The IESG <iesg@ietf.org></td></tr>
|
||||
<tr>
|
||||
<td>An IETF Area </td>
|
||||
<td><a href="/wg/">The IETF Area Director(s)</a></td>
|
||||
<td><a href="/liaison/managers/">The IETF Liaison Manager for the SDO</a><br>
|
||||
<td><a href="https://www.ietf.org/liaison/managers.html">The IETF Liaison Manager for the SDO</a><br>
|
||||
The IETF Chair <chair@ietf.org><br>
|
||||
The IETF Area Directorate Mailing List(where applicable) <sup><small>(3)</small></sup></td></tr>
|
||||
<tr>
|
||||
<td>An IETF Working Group </td>
|
||||
<td><a href="/wg/">The Working Group Chair(s)</a></td>
|
||||
<td><a href="/liaison/managers/">The IETF Liaison Manager for the SDO</a><br>
|
||||
<td><a href="https://www.ietf.org/liaison/managers.html">The IETF Liaison Manager for the SDO</a><br>
|
||||
<a href="/wg/">The IETF Area Director(s)</a><br>
|
||||
<a href="/wg/">The IETF Working Group Discussion List</a></td></tr>
|
||||
</table>
|
||||
|
|
|
@ -306,10 +306,8 @@ def make_test_data():
|
|||
DocAlias.objects.create(name=doc.name, document=doc)
|
||||
|
||||
# an irtf submission mid review
|
||||
doc = Document.objects.create(name='draft-imaginary-irtf-submission', type_id='draft',rev='00')
|
||||
doc = Document.objects.create(name='draft-imaginary-irtf-submission', type_id='draft',rev='00', stream=StreamName.objects.get(slug='irtf'))
|
||||
docalias = DocAlias.objects.create(name=doc.name, document=doc)
|
||||
doc.stream = StreamName.objects.get(slug='irtf')
|
||||
doc.save()
|
||||
doc.set_state(State.objects.get(type="draft", slug="active"))
|
||||
crdoc = Document.objects.create(name='conflict-review-imaginary-irtf-submission', type_id='conflrev', rev='00', notify="fsm@ietf.org")
|
||||
DocAlias.objects.create(name=crdoc.name, document=crdoc)
|
||||
|
@ -320,15 +318,12 @@ def make_test_data():
|
|||
iesg = Group.objects.get(acronym='iesg')
|
||||
doc = Document.objects.create(name='status-change-imaginary-mid-review',type_id='statchg', rev='00', notify="fsm@ietf.org",group=iesg)
|
||||
doc.set_state(State.objects.get(slug='needshep',type__slug='statchg'))
|
||||
doc.save()
|
||||
docalias = DocAlias.objects.create(name='status-change-imaginary-mid-review',document=doc)
|
||||
|
||||
# Some things for a status change to affect
|
||||
def rfc_for_status_change_test_factory(name,rfc_num,std_level_id):
|
||||
target_rfc = Document.objects.create(name=name, type_id='draft', std_level_id=std_level_id)
|
||||
target_rfc = Document.objects.create(name=name, type_id='draft', std_level_id=std_level_id, notify="%s@ietf.org"%name)
|
||||
target_rfc.set_state(State.objects.get(slug='rfc',type__slug='draft'))
|
||||
target_rfc.notify = "%s@ietf.org"%name
|
||||
target_rfc.save()
|
||||
docalias = DocAlias.objects.create(name=name,document=target_rfc)
|
||||
docalias = DocAlias.objects.create(name='rfc%d'%rfc_num,document=target_rfc) # pyflakes:ignore
|
||||
return target_rfc
|
||||
|
|
|
@ -328,6 +328,8 @@ class IetfTestRunner(DiscoverRunner):
|
|||
ietf.utils.mail.test_mode = True
|
||||
ietf.utils.mail.SMTP_ADDR['ip4'] = '127.0.0.1'
|
||||
ietf.utils.mail.SMTP_ADDR['port'] = 2025
|
||||
# switch to a much faster hasher
|
||||
settings.PASSWORD_HASHERS = ( 'django.contrib.auth.hashers.MD5PasswordHasher', )
|
||||
#
|
||||
if self.check_coverage:
|
||||
if self.coverage_file.endswith('.gz'):
|
||||
|
|
Loading…
Reference in a new issue