def edit_ad(request, name): """Change the shepherding Area Director for this review.""" review = get_object_or_404(Document, type="conflrev", name=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.desc = "Shepherding AD changed to "+review.ad.name c.save() return redirect('doc_view', name=review.name) else: init = { "ad" : review.ad_id } form = AdForm(initial=init) conflictdoc = review.relateddocument_set.get(relationship__slug='conflrev').target.document titletext = 'the conflict review of %s-%s' % (conflictdoc.canonical_name(),conflictdoc.rev) return render_to_response('doc/change_ad.html', {'form': form, 'doc': review, 'titletext': titletext }, context_instance = RequestContext(request))
def change_state(request, name, option=None): """Change state of an IESG review for IETF conflicts in other stream's documents, notifying parties as necessary and logging the change as a comment.""" review = get_object_or_404(Document, type="conflrev", name=name) login = request.user.get_profile() if request.method == 'POST': form = ChangeStateForm(request.POST) if form.is_valid(): clean = form.cleaned_data review_state = clean['review_state'] comment = clean['comment'].rstrip() if comment: c = DocEvent(type="added_comment", doc=review, by=login) c.desc = comment c.save() if review_state != review.get_state(): save_document_in_history(review) old_description = review.friendly_state() review.set_state(review_state) new_description = review.friendly_state() log_state_changed(request, review, login, new_description, old_description) review.time = datetime.datetime.now() review.save() if review_state.slug == "iesgeval": create_ballot_if_not_open(review, login, "conflrev") ballot = review.latest_event(BallotDocEvent, type="created_ballot") if has_role(request.user, "Area Director") and not review.latest_event(BallotPositionDocEvent, ad=login, ballot=ballot, type="changed_ballot_position"): # The AD putting a conflict review into iesgeval who doesn't already have a position is saying "yes" pos = BallotPositionDocEvent(doc=review, by=login) pos.ballot = ballot pos.type = "changed_ballot_position" pos.ad = login 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() send_conflict_eval_email(request,review) return redirect('doc_view', name=review.name) else: s = review.get_state() init = dict(review_state=s.pk if s else None) form = ChangeStateForm(initial=init) return render_to_response('doc/change_state.html', dict(form=form, doc=review, login=login, help_url=reverse('help_conflict_review_states'), ), context_instance=RequestContext(request))
def expire_draft(doc): # clean up files move_draft_files_to_archive(doc, doc.rev) # change the state system = Person.objects.get(name="(System)") save_document_in_history(doc) if doc.latest_event(type='started_iesg_process'): dead_state = State.objects.get(used=True, type="draft-iesg", slug="dead") prev = doc.get_state("draft-iesg") prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS) prev_tag = prev_tag[0] if prev_tag else None if prev != dead_state: doc.set_state(dead_state) if prev_tag: doc.tags.remove(prev_tag) log_state_changed(None, doc, system, prev, prev_tag) e = DocEvent(doc=doc, by=system) e.type = "expired_document" e.desc = "Document has expired" e.save() doc.set_state(State.objects.get(used=True, type="draft", slug="expired")) doc.time = datetime.datetime.now() doc.save()
def edit_title(request, name): """Change the title for this status_change document.""" status_change = get_object_or_404(Document, type="statchg", name=name) if request.method == 'POST': form = ChangeTitleForm(request.POST) 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.desc = "Title changed to '%s'"%status_change.title c.save() return redirect("doc_view", name=status_change.name) else: init = { "title" : status_change.title } form = ChangeTitleForm(initial=init) titletext = '%s-%s.txt' % (status_change.canonical_name(),status_change.rev) return render_to_response('doc/change_title.html', {'form': form, 'doc': status_change, 'titletext' : titletext, }, context_instance = RequestContext(request))
def build_conflict_review_document(login, doc_to_review, ad, notify, create_in_state): if doc_to_review.name.startswith('draft-'): review_name = 'conflict-review-'+doc_to_review.name[6:] else: # This is a failsafe - and might be treated better as an error review_name = 'conflict-review-'+doc_to_review.name 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.set_state(create_in_state) DocAlias.objects.create( name=review_name , document=conflict_review ) conflict_review.relateddocument_set.create(target=DocAlias.objects.get(name=doc_to_review.name),relationship_id='conflrev') c = DocEvent(type="added_comment", doc=conflict_review, by=login) c.desc = "IETF conflict review requested" c.save() c = DocEvent(type="added_comment", doc=doc_to_review, by=login) # Is it really OK to put html tags into comment text? c.desc = 'IETF conflict review initiated - see <a href="%s">%s</a>' % (reverse('doc_view', kwargs={'name':conflict_review.name}),conflict_review.name) c.save() return conflict_review
def edit_notices(request, name): """Change the set of email addresses document change notificaitions go to.""" review = get_object_or_404(Document, type="conflrev", name=name) if request.method == 'POST': form = NotifyForm(request.POST) if form.is_valid(): review.notify = form.cleaned_data['notify'] review.save() login = request.user.person c = DocEvent(type="added_comment", doc=review, by=login) c.desc = "Notification list changed to : "+review.notify c.save() return redirect('doc_view', name=review.name) else: init = { "notify" : review.notify } form = NotifyForm(initial=init) conflictdoc = review.relateddocument_set.get(relationship__slug='conflrev').target.document titletext = 'the conflict review of %s-%s' % (conflictdoc.canonical_name(),conflictdoc.rev) return render_to_response('doc/notify.html', {'form': form, 'doc': review, 'titletext' : titletext }, context_instance = RequestContext(request))
def edit_notices(request, name): """Change the set of email addresses document change notificaitions go to.""" status_change = get_object_or_404(Document, type="statchg", name=name) if request.method == 'POST': form = NotifyForm(request.POST) if form.is_valid(): status_change.notify = form.cleaned_data['notify'] status_change.save() login = request.user.get_profile() c = DocEvent(type="added_comment", doc=status_change, by=login) c.desc = "Notification list changed to : "+status_change.notify c.save() return HttpResponseRedirect(reverse('doc_view', kwargs={'name': status_change.name})) else: init = { "notify" : status_change.notify } form = NotifyForm(initial=init) return render_to_response('doc/notify.html', {'form': form, 'doc': status_change, 'titletext' : '%s-%s.txt' % (status_change.canonical_name(),status_change.rev) }, context_instance = RequestContext(request))
def assign_shepherd(user, internetdraft, shepherd): if internetdraft.shepherd == shepherd: return from ietf.doc.models import save_document_in_history, DocEvent, Document # saving the proxy object is a bit of a mess, so convert it to a # proper document doc = Document.objects.get(name=internetdraft.name) save_document_in_history(doc) doc.time = datetime.datetime.now() doc.shepherd = shepherd doc.save() e = DocEvent(type="changed_document") e.time = doc.time e.doc = doc e.by = user.get_profile() if not shepherd: e.desc = u"Unassigned shepherd" else: e.desc = u"Changed shepherd to %s" % shepherd.plain_name() e.save() # update proxy too internetdraft.shepherd = shepherd
def edit_notices(request, name): """Change the set of email addresses document change notificaitions go to.""" status_change = get_object_or_404(Document, type="statchg", name=name) if request.method == 'POST': form = NotifyForm(request.POST) if form.is_valid(): status_change.notify = form.cleaned_data['notify'] status_change.save() login = request.user.get_profile() c = DocEvent(type="added_comment", doc=status_change, by=login) c.desc = "Notification list changed to : " + status_change.notify c.save() return HttpResponseRedirect( reverse('doc_view', kwargs={'name': status_change.name})) else: init = {"notify": status_change.notify} form = NotifyForm(initial=init) return render_to_response('doc/notify.html', { 'form': form, 'doc': status_change, 'titletext': '%s-%s.txt' % (status_change.canonical_name(), status_change.rev) }, context_instance=RequestContext(request))
def assign_shepherd(user, internetdraft, shepherd): if internetdraft.shepherd == shepherd: return from ietf.doc.models import save_document_in_history, DocEvent, Document # saving the proxy object is a bit of a mess, so convert it to a # proper document doc = Document.objects.get(name=internetdraft.name) save_document_in_history(doc) doc.time = datetime.datetime.now() doc.shepherd = shepherd doc.save() e = DocEvent(type="changed_document") e.time = doc.time e.doc = doc e.by = user.get_profile() if not shepherd: e.desc = u"Unassigned shepherd" else: e.desc = u"Changed shepherd to %s" % shepherd.plain_name() e.save() # update proxy too internetdraft.shepherd = shepherd
def expire_draft(doc): # clean up files move_draft_files_to_archive(doc, doc.rev) system = Person.objects.get(name="(System)") # 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) prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS) if new_state != prev_state: 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=[]) e = DocEvent(doc=doc, by=system) e.type = "expired_document" e.desc = "Document has expired" e.save() doc.set_state(State.objects.get(used=True, type="draft", slug="expired")) doc.time = datetime.datetime.now() doc.save()
def edit_ad(request, name): """Change the shepherding Area Director for this review.""" review = get_object_or_404(Document, type="conflrev", name=name) if request.method == 'POST': form = AdForm(request.POST) if form.is_valid(): review.ad = form.cleaned_data['ad'] review.save() login = request.user.get_profile() c = DocEvent(type="added_comment", doc=review, by=login) c.desc = "Shepherding AD changed to " + review.ad.name c.save() return HttpResponseRedirect( reverse('doc_view', kwargs={'name': review.name})) else: init = {"ad": review.ad_id} form = AdForm(initial=init) conflictdoc = review.relateddocument_set.get( relationship__slug='conflrev').target.document titletext = 'the conflict review of %s-%s' % (conflictdoc.canonical_name(), conflictdoc.rev) return render_to_response('doc/change_ad.html', { 'form': form, 'doc': review, 'titletext': titletext }, context_instance=RequestContext(request))
def build_conflict_review_document(login, doc_to_review, ad, notify, create_in_state): if doc_to_review.name.startswith('draft-'): review_name = 'conflict-review-'+doc_to_review.name[6:] else: # This is a failsafe - and might be treated better as an error review_name = 'conflict-review-'+doc_to_review.name iesg_group = Group.objects.get(acronym='iesg') 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 ) conflict_review.relateddocument_set.create(target=DocAlias.objects.get(name=doc_to_review.name),relationship_id='conflrev') c = DocEvent(type="added_comment", doc=conflict_review, rev=conflict_review.rev, by=login) c.desc = "IETF conflict review requested" c.save() c = DocEvent(type="added_comment", doc=doc_to_review, rev=doc_to_review.rev, by=login) # Is it really OK to put html tags into comment text? c.desc = 'IETF conflict review initiated - see <a href="%s">%s</a>' % (reverse('ietf.doc.views_doc.document_main', kwargs={'name':conflict_review.name}),conflict_review.name) c.save() return conflict_review
def edit_notices(request, name): """Change the set of email addresses document change notificaitions go to.""" review = get_object_or_404(Document, type="conflrev", name=name) if request.method == 'POST': form = NotifyForm(request.POST) if form.is_valid(): review.notify = form.cleaned_data['notify'] review.save() login = request.user.get_profile() c = DocEvent(type="added_comment", doc=review, by=login) c.desc = "Notification list changed to : " + review.notify c.save() return HttpResponseRedirect( reverse('doc_view', kwargs={'name': review.name})) else: init = {"notify": review.notify} form = NotifyForm(initial=init) conflictdoc = review.relateddocument_set.get( relationship__slug='conflrev').target.document titletext = 'the conflict review of %s-%s' % (conflictdoc.canonical_name(), conflictdoc.rev) return render_to_response('doc/notify.html', { 'form': form, 'doc': review, 'titletext': titletext }, context_instance=RequestContext(request))
def edit_ad(request, name): """Change the responsible Area Director for this charter.""" charter = get_object_or_404(Document, type="charter", name=name) 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: events = [] e = DocEvent(doc=charter, rev=charter.rev, 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.save_with_history(events) return redirect('ietf.doc.views_doc.document_main', name=charter.name) else: init = {"ad": charter.ad_id} form = AdForm(initial=init) return render(request, 'doc/charter/change_ad.html', { 'form': form, 'charter': charter, })
def edit_ad(request, name): """Change the shepherding Area Director for this status_change.""" status_change = get_object_or_404(Document, type="statchg", name=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.get_profile() c = DocEvent(type="added_comment", doc=status_change, by=login) c.desc = "Shepherding AD changed to " + status_change.ad.name c.save() return redirect("doc_view", name=status_change.name) else: init = {"ad": status_change.ad_id} form = AdForm(initial=init) titletext = '%s-%s.txt' % (status_change.canonical_name(), status_change.rev) return render_to_response('doc/change_ad.html', { 'form': form, 'doc': status_change, 'titletext': titletext, }, context_instance=RequestContext(request))
def edit_ad(request, name): """Change the shepherding Area Director for this status_change.""" status_change = get_object_or_404(Document, type="statchg", name=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.get_profile() c = DocEvent(type="added_comment", doc=status_change, by=login) c.desc = "Shepherding AD changed to "+status_change.ad.name c.save() return redirect("doc_view", name=status_change.name) else: init = { "ad" : status_change.ad_id } form = AdForm(initial=init) titletext = '%s-%s.txt' % (status_change.canonical_name(),status_change.rev) return render_to_response('doc/change_ad.html', {'form': form, 'doc': status_change, 'titletext' : titletext, }, context_instance = RequestContext(request))
def log_state_changed(request, doc, by, prev_state): e = DocEvent(doc=doc, by=by) e.type = "changed_document" e.desc = u"State changed to <b>%s</b> from %s" % ( doc.get_state().name, prev_state.name if prev_state else "None") e.save() return e
def edit_notify(request, name): doc = get_object_or_404(Document, type="charter", name=name) login = request.user.person init = {'notify': doc.notify} if request.method == "POST": form = NotifyForm(request.POST, initial=init) if form.is_valid(): n = form.cleaned_data["notify"] if n != doc.notify: save_document_in_history(doc) e = DocEvent(doc=doc, by=login) e.desc = "Notification list changed to %s" % (escape(n) or "none") if doc.notify: e.desc += " from %s" % escape(doc.notify) e.type = "changed_document" e.save() doc.notify = n doc.time = e.time doc.save() return redirect("doc_view", name=doc.name) else: form = NotifyForm(initial=init) return render_to_response('doc/charter/edit_notify.html', dict(doc=doc, form=form, user=request.user, login=login), context_instance=RequestContext(request))
def add_comment(request, name): """Add comment to history of document.""" doc = get_object_or_404(Document, docalias__name=name) login = request.user.person if request.method == 'POST': form = AddCommentForm(request.POST) if form.is_valid(): c = form.cleaned_data['comment'] e = DocEvent(doc=doc, by=login) e.type = "added_comment" e.desc = c e.save() if doc.type_id == "draft": email_ad(request, doc, doc.ad, login, "A new comment added by %s" % login.name) return redirect("doc_history", name=doc.name) else: form = AddCommentForm() return render_to_response('doc/add_comment.html', dict(doc=doc, form=form), context_instance=RequestContext(request))
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 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) 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() charter.ad = new_ad charter.time = e.time charter.save() 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))
def edit_ad(request, name): """Change the shepherding Area Director for this review.""" review = get_object_or_404(Document, type="conflrev", name=name) if request.method == 'POST': form = AdForm(request.POST) if form.is_valid(): review.ad = form.cleaned_data['ad'] c = DocEvent(type="added_comment", doc=review, rev=review.rev, by=request.user.person) c.desc = "Shepherding AD changed to "+review.ad.name c.save() review.save_with_history([c]) return redirect('ietf.doc.views_doc.document_main', name=review.name) else: init = { "ad" : review.ad_id } form = AdForm(initial=init) conflictdoc = review.relateddocument_set.get(relationship__slug='conflrev').target.document titletext = 'the conflict review of %s-%s' % (conflictdoc.canonical_name(),conflictdoc.rev) return render(request, 'doc/change_ad.html', {'form': form, 'doc': review, 'titletext': titletext }, )
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) relationship = DocRelationshipName.objects.get(slug='replaces') old_replaces = doc.related_that_doc("replaces") events = [] e = DocEvent(doc=doc, rev=doc.rev, 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, rev=doc.rev, 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) to.update(other_addrs.to) cc.update(other_addrs.cc) RelatedDocument.objects.filter(source=doc, target=d, relationship=relationship).delete() if not RelatedDocument.objects.filter(target=d, relationship=relationship): s = 'active' if d.document.expires > datetime.datetime.now() else 'expired' d.document.set_state(State.objects.get(type='draft', slug=s)) for d in new_replaces: if d not in old_replaces: other_addrs = gather_address_lists('doc_replacement_changed',doc=d.document) to.update(other_addrs.to) cc.update(other_addrs.cc) RelatedDocument.objects.create(source=doc, target=d, relationship=relationship) d.document.set_state(State.objects.get(type='draft', slug='repl')) # 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 comment: email_desc += "\n" + comment from ietf.doc.mails import html_to_text send_mail(request, list(to), "DraftTracker Mail System <*****@*****.**>", email_subject, "doc/mail/change_notice.txt", dict(text=html_to_text(email_desc), doc=doc, url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()), cc=list(cc)) return events
def log_state_changed(request, doc, by, prev_state): e = DocEvent(doc=doc, by=by) e.type = "changed_document" e.desc = u"State changed to <b>%s</b> from %s" % ( doc.get_state().name, prev_state.name if prev_state else "None") e.save() return e
def update_tags(request, obj, comment, person, set_tags=[], reset_tags=[], extra_notify=[]): if settings.USE_DB_REDESIGN_PROXY_CLASSES: doc = Document.objects.get(pk=obj.pk) save_document_in_history(doc) obj.tags.remove(*reset_tags) obj.tags.add(*set_tags) doc.time = datetime.datetime.now() e = DocEvent(type="changed_document", time=doc.time, by=person, doc=doc) l = [] if set_tags: l.append(u"Annotation tag%s %s set." % (pluralize(set_tags), ", ".join(x.name for x in set_tags))) if reset_tags: l.append(u"Annotation tag%s %s cleared." % (pluralize(reset_tags), ", ".join(x.name for x in reset_tags))) e.desc = " ".join(l) e.save() receivers = get_notification_receivers(doc, extra_notify) send_mail(request, receivers, settings.DEFAULT_FROM_EMAIL, u"Annotations tags changed for draft %s" % doc.name, 'ietfworkflows/annotation_tags_updated_mail.txt', dict(doc=doc, entry=dict(setted=", ".join(x.name for x in set_tags), unsetted=", ".join(x.name for x in reset_tags), change_date=doc.time, person=person, comment=comment))) return ctype = ContentType.objects.get_for_model(obj) setted = [] resetted = [] for tag in set_tags: if isinstance(tag, basestring): if set_tag_by_name(obj, tag): setted.append(tag) else: if set_tag(obj, tag): setted.append(tag.name) for tag in reset_tags: if isinstance(tag, basestring): if reset_tag_by_name(obj, tag): resetted.append(tag) else: if reset_tag(obj, tag): resetted.append(tag.name) entry = ObjectAnnotationTagHistoryEntry.objects.create( content_type=ctype, content_id=obj.pk, setted=','.join(setted), unsetted=','.join(resetted), date=datetime.datetime.now(), comment=comment, person=person) notify_tag_entry(entry, extra_notify)
def change_state(request, name, option=None): """Change state of an IESG review for IETF conflicts in other stream's documents, notifying parties as necessary and logging the change as a comment.""" review = get_object_or_404(Document, type="conflrev", name=name) login = request.user.person if request.method == 'POST': form = ChangeStateForm(request.POST) if form.is_valid(): clean = form.cleaned_data new_state = clean['review_state'] comment = clean['comment'].rstrip() if comment: c = DocEvent(type="added_comment", doc=review, rev=review.rev, by=login) c.desc = comment c.save() prev_state = review.get_state() if new_state != prev_state: events = [] review.set_state(new_state) events.append(add_state_change_event(review, login, prev_state, new_state)) review.save_with_history(events) if new_state.slug == "iesgeval": create_ballot_if_not_open(review, login, "conflrev") ballot = review.latest_event(BallotDocEvent, type="created_ballot") if has_role(request.user, "Area Director") and not review.latest_event(BallotPositionDocEvent, ad=login, ballot=ballot, type="changed_ballot_position"): # The AD putting a conflict review into iesgeval who doesn't already have a position is saying "yes" pos = BallotPositionDocEvent(doc=review, rev=review.rev, by=login) pos.ballot = ballot pos.type = "changed_ballot_position" pos.ad = login 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() # Consider mailing that position to 'ballot_saved' send_conflict_eval_email(request,review) return redirect('ietf.doc.views_doc.document_main', name=review.name) else: s = review.get_state() init = dict(review_state=s.pk if s else None) form = ChangeStateForm(initial=init) return render(request, 'doc/change_state.html', dict(form=form, doc=review, login=login, help_url=reverse('ietf.doc.views_help.state_help', kwargs=dict(type="conflict-review")), ))
def approve(request, name): """Approve this conflict review, setting the appropriate state and send the announcement to the right parties.""" review = get_object_or_404(Document, type="conflrev", name=name) if review.get_state('conflrev').slug not in ('appr-reqnopub-pend','appr-noprob-pend'): raise Http404 login = request.user.get_profile() if request.method == 'POST': form = AnnouncementForm(request.POST) if form.is_valid(): new_state_slug = 'appr-reqnopub-sent' if review.get_state('conflrev').slug=='appr-reqnopub-pend' else 'appr-noprob-sent' new_review_state = State.objects.get(used=True, type="conflrev", slug=new_state_slug) save_document_in_history(review) old_description = review.friendly_state() review.set_state(new_review_state) new_description = review.friendly_state() log_state_changed(request, review, login, new_description, old_description) close_open_ballots(review, login) e = DocEvent(doc=review, by=login) e.type = "iesg_approved" e.desc = "IESG has approved the conflict review response" e.save() review.time = e.time review.save() # send announcement send_mail_preformatted(request, form.cleaned_data['announcement_text']) c = DocEvent(type="added_comment", doc=review, by=login) c.desc = "The following approval message was sent\n"+form.cleaned_data['announcement_text'] c.save() return HttpResponseRedirect(review.get_absolute_url()) else: init = { "announcement_text" : default_approval_text(review) } form = AnnouncementForm(initial=init) return render_to_response('doc/conflict_review/approve.html', dict( review = review, conflictdoc = review.relateddocument_set.get(relationship__slug='conflrev').target.document, form = form, ), context_instance=RequestContext(request))
def change_title(request, name, option=None): """Change title of charter, notifying parties as necessary and logging the title as a comment.""" charter = get_object_or_404(Document, type="charter", name=name) group = charter.group if not can_manage_group_type(request.user, group): return HttpResponseForbidden( "You don't have permission to access this view") by = request.user.person if request.method == 'POST': form = ChangeTitleForm(request.POST, charter=charter) if form.is_valid(): clean = form.cleaned_data charter_rev = charter.rev new_title = clean['charter_title'] comment = clean['comment'].rstrip() message = clean['message'] prev_title = charter.title if new_title != prev_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) e = DocEvent(type="added_comment", doc=charter, rev=charter.rev, 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') return redirect('ietf.doc.views_doc.document_main', name=charter.name) else: form = ChangeTitleForm(charter=charter) title = "Change charter title of %s %s" % (group.acronym, group.type.name) return render(request, 'doc/charter/change_title.html', dict( form=form, doc=group.charter, title=title, ))
def approve(request, name): """Approve this conflict review, setting the appropriate state and send the announcement to the right parties.""" review = get_object_or_404(Document, type="conflrev", name=name) if review.get_state('conflrev').slug not in ('appr-reqnopub-pend','appr-noprob-pend'): raise Http404 login = request.user.person if request.method == 'POST': form = AnnouncementForm(request.POST) 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) review.set_state(new_state) e = add_state_change_event(review, login, prev_state, new_state) events.append(e) close_open_ballots(review, login) e = DocEvent(doc=review, rev=review.rev, by=login) e.type = "iesg_approved" e.desc = "IESG has approved the conflict review response" e.save() events.append(e) review.save_with_history(events) # send announcement send_mail_preformatted(request, form.cleaned_data['announcement_text']) c = DocEvent(type="added_comment", doc=review, rev=review.rev, by=login) c.desc = "The following approval message was sent\n"+form.cleaned_data['announcement_text'] c.save() return HttpResponseRedirect(review.get_absolute_url()) else: init = { "announcement_text" : default_approval_text(review) } form = AnnouncementForm(initial=init) return render(request, 'doc/conflict_review/approve.html', dict( review = review, conflictdoc = review.relateddocument_set.get(relationship__slug='conflrev').target.document, form = form, ))
def add_review_comment(doc_name, review_time, by, comment): try: e = DocEvent.objects.get(doc__name=doc_name, time=review_time, type="iana_review") except DocEvent.DoesNotExist: doc = Document.objects.get(name=doc_name) e = DocEvent(doc=doc, time=review_time, type="iana_review") e.desc = comment e.by = by e.save()
def add_review_comment(doc_name, review_time, by, comment): if comment: try: e = DocEvent.objects.get(doc__name=doc_name, time=review_time, type="iana_review") except DocEvent.DoesNotExist: doc = Document.objects.get(name=doc_name) e = DocEvent(doc=doc, rev=doc.rev, time=review_time, type="iana_review") e.desc = comment e.by = by e.save()
def test_review_decisions(self): draft = make_test_data() e = DocEvent(type="iesg_approved") e.doc = draft e.by = Person.objects.get(name="Aread Irector") e.save() url = urlreverse('ietf.iesg.views.review_decisions') r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(draft.name in r.content)
def edit_relations(request, name): """Change the affected set of RFCs""" status_change = get_object_or_404(Document, type="statchg", name=name) login = request.user.get_profile() relation_slugs = DocRelationshipName.objects.filter(slug__in=RELATION_SLUGS) if request.method == 'POST': form = EditStatusChangeForm(request.POST) if 'Submit' in request.POST and form.is_valid(): old_relations={} for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS): old_relations[rel.target.document.canonical_name()]=rel.relationship.slug new_relations=form.cleaned_data['relations'] status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS).delete() for key in new_relations: status_change.relateddocument_set.create(target=DocAlias.objects.get(name=key), relationship_id=new_relations[key]) c = DocEvent(type="added_comment", doc=status_change, by=login) c.desc = "Affected RFC list changed.\nOLD:" for relname,relslug in (set(old_relations.items())-set(new_relations.items())): c.desc += "\n "+relname+": "+DocRelationshipName.objects.get(slug=relslug).name c.desc += "\nNEW:" for relname,relslug in (set(new_relations.items())-set(old_relations.items())): c.desc += "\n "+relname+": "+DocRelationshipName.objects.get(slug=relslug).name c.desc += "\n" c.save() return HttpResponseRedirect(status_change.get_absolute_url()) elif 'Cancel' in request.POST: return HttpResponseRedirect(status_change.get_absolute_url()) else: relations={} for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS): relations[rel.target.document.canonical_name()]=rel.relationship.slug init = { "relations":relations, } form = EditStatusChangeForm(initial=init) return render_to_response('doc/status_change/edit_relations.html', { 'doc': status_change, 'form': form, 'relation_slugs': relation_slugs, }, context_instance = RequestContext(request))
def save(self): self.save_tags() if 'only_tags' not in self.data.keys(): self.save_state() if settings.USE_DB_REDESIGN_PROXY_CLASSES: comment = self.cleaned_data.get('comment').strip() if comment: e = DocEvent(type="added_comment") e.time = datetime.datetime.now() e.by = self.person e.doc_id = self.draft.pk e.desc = comment e.save()
def save(self): self.save_tags() if 'only_tags' not in self.data.keys(): self.save_state() if settings.USE_DB_REDESIGN_PROXY_CLASSES: comment = self.cleaned_data.get('comment').strip() if comment: e = DocEvent(type="added_comment") e.time = datetime.datetime.now() e.by = self.person e.doc_id = self.draft.pk e.desc = comment e.save()
def set_replaces_for_document(request, doc, new_replaces, by, email_subject, email_comment=""): addrs = gather_address_lists('doc_replacement_changed',doc=doc) to = set(addrs.to) cc = set(addrs.cc) relationship = DocRelationshipName.objects.get(slug='replaces') old_replaces = doc.related_that_doc("replaces") for d in old_replaces: if d not in new_replaces: other_addrs = gather_address_lists('doc_replacement_changed',doc=d.document) to.update(other_addrs.to) cc.update(other_addrs.cc) RelatedDocument.objects.filter(source=doc, target=d, relationship=relationship).delete() if not RelatedDocument.objects.filter(target=d, relationship=relationship): s = 'active' if d.document.expires > datetime.datetime.now() else 'expired' d.document.set_state(State.objects.get(type='draft', slug=s)) for d in new_replaces: if d not in old_replaces: other_addrs = gather_address_lists('doc_replacement_changed',doc=d.document) to.update(other_addrs.to) cc.update(other_addrs.cc) 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 from ietf.doc.mails import html_to_text send_mail(request, list(to), "DraftTracker Mail System <*****@*****.**>", email_subject, "doc/mail/change_notice.txt", dict(text=html_to_text(email_desc), doc=doc, url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()), cc=list(cc))
def test_review_decisions(self): draft = make_test_data() e = DocEvent(type="iesg_approved") e.doc = draft e.rev = draft.rev e.by = Person.objects.get(name="Areað Irector") e.save() url = urlreverse('ietf.iesg.views.review_decisions') r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(draft.name in unicontent(r))
def request_last_call(request, doc): if not doc.latest_event(type="changed_ballot_writeup_text"): generate_ballot_writeup(request, doc) if not doc.latest_event(type="changed_ballot_approval_text"): generate_approval_mail(request, doc) if not doc.latest_event(type="changed_last_call_text"): generate_last_call_announcement(request, doc) send_last_call_request(request, doc) e = DocEvent() e.type = "requested_last_call" e.by = request.user.person e.doc = doc e.desc = "Last call was requested" e.save()
def change_title(request, name, option=None): """Change title of charter, notifying parties as necessary and logging the title as a comment.""" charter = get_object_or_404(Document, type="charter", name=name) 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 if request.method == 'POST': form = ChangeTitleForm(request.POST, charter=charter) if form.is_valid(): clean = form.cleaned_data charter_rev = charter.rev new_title = clean['charter_title'] comment = clean['comment'].rstrip() message = clean['message'] prev_title = charter.title if new_title != prev_title: # Charter title changed save_document_in_history(charter) 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() 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') return redirect('doc_view', name=charter.name) 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))
def request_last_call(request, doc): if not doc.latest_event(type="changed_ballot_writeup_text"): e = generate_ballot_writeup(request, doc) e.save() if not doc.latest_event(type="changed_ballot_approval_text"): e = generate_approval_mail(request, doc) e.save() if not doc.latest_event(type="changed_last_call_text"): e = generate_last_call_announcement(request, doc) e.save() send_last_call_request(request, doc) e = DocEvent() e.type = "requested_last_call" e.by = request.user.person e.doc = doc e.rev = doc.rev e.desc = "Last call was requested" e.save()
def make_notify_changed_event(request, doc, by, new_notify, time=None): # FOR REVIEW: This preserves the behavior from when # drafts and charters had separate edit_notify # functions. If it should be unified, there should # also be a migration function cause historic # events to match if doc.type.slug=='charter': event_type = 'changed_document' else: event_type = 'added_comment' e = DocEvent(type=event_type, doc=doc, rev=doc.rev, by=by) e.desc = "Notification list changed to %s" % (escape(new_notify) or "none") if doc.notify: e.desc += " from %s" % escape(doc.notify) if time: e.time = time e.save() return e
def log_state_changedREDESIGN(request, doc, by, prev_iesg_state, prev_iesg_tag): from ietf.doc.models import DocEvent, IESG_SUBSTATE_TAGS state = doc.get_state("draft-iesg") state_name = state.name tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS) if tags: state_name += "::" + tags[0].name prev_state_name = prev_iesg_state.name if prev_iesg_state else "I-D Exists" if prev_iesg_tag: prev_state_name += "::" + prev_iesg_tag.name e = DocEvent(doc=doc, by=by) e.type = "changed_document" e.desc = u"State changed to <b>%s</b> from %s" % (state_name, prev_state_name) e.save() return e
def update_stream(request, doc, comment, person, to_stream, extra_notify=[]): if settings.USE_DB_REDESIGN_PROXY_CLASSES: doc = Document.objects.get(pk=doc.pk) save_document_in_history(doc) doc.time = datetime.datetime.now() from_stream = doc.stream doc.stream = to_stream doc.save() e = DocEvent(type="changed_stream", time=doc.time, by=person, doc=doc) e.desc = u"Stream changed to <b>%s</b>" % to_stream.name if from_stream: e.desc += u"from %s" % from_stream.name e.save() receivers = get_notification_receivers(doc, extra_notify) send_mail(request, receivers, settings.DEFAULT_FROM_EMAIL, u"Stream changed for draft %s" % doc.name, 'ietfworkflows/stream_updated_mail.txt', dict(doc=doc, entry=dict(from_stream=from_stream, to_stream=to_stream, transition_date=doc.time, person=person, comment=comment))) return ctype = ContentType.objects.get_for_model(doc) from_stream = get_stream_from_draft(doc) to_stream = set_stream_for_draft(doc, to_stream) entry = ObjectStreamHistoryEntry.objects.create( content_type=ctype, content_id=doc.pk, from_stream=from_stream and from_stream.name or '', to_stream=to_stream and to_stream.name or '', date=datetime.datetime.now(), comment=comment, person=person) notify_stream_entry(entry, extra_notify)
def make_notify_changed_event(request, doc, by, new_notify, time=None): # FOR REVIEW: This preserves the behavior from when # drafts and charters had separate edit_notify # functions. If it should be unified, there should # also be a migration function cause historic # events to match if doc.type.slug=='charter': event_type = 'changed_document' save_document_in_history(doc) else: event_type = 'added_comment' e = DocEvent(type=event_type, doc=doc, by=by) e.desc = "Notification list changed to %s" % (escape(new_notify) or "none") if doc.notify: e.desc += " from %s" % escape(doc.notify) if time: e.time = time e.save() return e
def edit_title(request, name): """Change the title for this status_change document.""" status_change = get_object_or_404(Document, type="statchg", name=name) if request.method == 'POST': form = ChangeTitleForm(request.POST) if form.is_valid(): status_change.title = form.cleaned_data['title'] c = DocEvent(type="added_comment", doc=status_change, rev=status_change.rev, by=request.user.person) c.desc = "Title changed to '%s'" % status_change.title c.save() status_change.save_with_history([c]) return redirect("ietf.doc.views_doc.document_main", name=status_change.name) else: init = {"title": status_change.title} form = ChangeTitleForm(initial=init) titletext = '%s-%s.txt' % (status_change.canonical_name(), status_change.rev) return render( request, 'doc/change_title.html', { 'form': form, 'doc': status_change, 'titletext': titletext, }, )
def downref_registry_add(request): title = "Add entry to the downref registry" login = request.user.person if request.method == 'POST': form = AddDownrefForm(request.POST) if form.is_valid(): drafts = form.cleaned_data['drafts'] rfc = form.cleaned_data['rfc'] for da in drafts: RelatedDocument.objects.create( source=da.document, target=rfc, relationship_id='downref-approval') c = DocEvent(type="downref_approved", doc=da.document, rev=da.document.rev, by=login) c.desc = "Downref to RFC %s approved by Last Call for %s-%s" % ( rfc.document.rfc_number(), da.name, da.document.rev) c.save() c = DocEvent(type="downref_approved", doc=rfc.document, rev=rfc.document.rev, by=login) c.desc = "Downref to RFC %s approved by Last Call for %s-%s" % ( rfc.document.rfc_number(), da.name, da.document.rev) c.save() return HttpResponseRedirect( urlreverse('ietf.doc.views_downref.downref_registry')) else: form = AddDownrefForm() return render(request, 'doc/downref_add.html', { "title": title, "add_downref_form": form, })
def update_rfc_log_from_protocol_page(rfc_names, rfc_must_published_later_than): """Add notices to RFC history log that IANA is now referencing the RFC.""" system = Person.objects.get(name="(System)") updated = [] docs = Document.objects.filter(docalias__name__in=rfc_names).exclude( docevent__type="rfc_in_iana_registry").filter( # only take those that were published after cutoff since we # have a big bunch of old RFCs that we unfortunately don't have data for docevent__type="published_rfc", docevent__time__gte=rfc_must_published_later_than ).distinct() for d in docs: e = DocEvent(doc=d) e.by = system e.type = "rfc_in_iana_registry" e.desc = "IANA registries were updated to include %s" % d.display_name() e.save() updated.append(d) return updated
def update_rfc_log_from_protocol_page(rfc_names, rfc_must_published_later_than): """Add notices to RFC history log that IANA is now referencing the RFC.""" system = Person.objects.get(name="(System)") updated = [] docs = Document.objects.filter(docalias__name__in=rfc_names).exclude( docevent__type="rfc_in_iana_registry").filter( # only take those that were published after cutoff since we # have a big bunch of old RFCs that we unfortunately don't have data for docevent__type="published_rfc", docevent__time__gte=rfc_must_published_later_than ).distinct() for d in docs: e = DocEvent(doc=d, rev=d.rev) e.by = system e.type = "rfc_in_iana_registry" e.desc = "IANA registries were updated to include %s" % d.display_name() e.save() updated.append(d) return updated
def edit_ad(request, name): """Change the shepherding Area Director for this status_change.""" status_change = get_object_or_404(Document, type="statchg", name=name) if request.method == 'POST': form = AdForm(request.POST) if form.is_valid(): status_change.ad = form.cleaned_data['ad'] c = DocEvent(type="added_comment", doc=status_change, rev=status_change.rev, by=request.user.person) c.desc = "Shepherding AD changed to " + status_change.ad.name c.save() status_change.save_with_history([c]) return redirect("ietf.doc.views_doc.document_main", name=status_change.name) else: init = {"ad": status_change.ad_id} form = AdForm(initial=init) titletext = '%s-%s.txt' % (status_change.canonical_name(), status_change.rev) return render( request, 'doc/change_ad.html', { 'form': form, 'doc': status_change, 'titletext': titletext, }, )
def edit_material_presentations(request, name, acronym=None, date=None, seq=None, week_day=None): doc = get_object_or_404(Document, name=name) if not (doc.type_id=='slides' and doc.get_state('slides').slug=='active'): raise Http404 group = doc.group if not (group.features.has_materials and can_manage_materials(request.user,group)): raise Http404 sorted_sessions = get_upcoming_manageable_sessions(request.user, doc, acronym, date, seq, week_day) if len(sorted_sessions)!=1: raise Http404 session = sorted_sessions[0] choices = [('notpresented','Not Presented')] choices.extend([(x,x) for x in doc.docevent_set.filter(type='new_revision').values_list('newrevisiondocevent__rev',flat=True)]) initial = {'version' : session.version if hasattr(session,'version') else 'notpresented'} if request.method == 'POST': form = MaterialVersionForm(request.POST,choices=choices) if form.is_valid(): new_selection = form.cleaned_data['version'] if initial['version'] != new_selection: if initial['version'] == 'notpresented': doc.sessionpresentation_set.create(session=session,rev=new_selection) c = DocEvent(type="added_comment", doc=doc, by=request.user.person) c.desc = "Added version %s to session: %s" % (new_selection,session) c.save() elif new_selection == 'notpresented': doc.sessionpresentation_set.filter(session=session).delete() c = DocEvent(type="added_comment", doc=doc, by=request.user.person) c.desc = "Removed from session: %s" % (session) c.save() else: doc.sessionpresentation_set.filter(session=session).update(rev=new_selection) c = DocEvent(type="added_comment", doc=doc, by=request.user.person) c.desc = "Revision for session %s changed to %s" % (session,new_selection) c.save() return redirect('doc_view',name=doc.name) else: form = MaterialVersionForm(choices=choices,initial=initial) return render(request, 'doc/material/edit_material_presentations.html', { 'session': session, 'doc': doc, 'form': form, })
def submit_existing(self, formats): # submit new revision of existing -> supply submitter info -> prev authors confirm draft = make_test_data() prev_author = draft.documentauthor_set.all()[0] # Make it such that one of the previous authors has an invalid email address bogus_email = ensure_person_email_info_exists('Bogus Person',None) DocumentAuthor.objects.create(document=draft,author=bogus_email,order=draft.documentauthor_set.latest('order').order+1) # pretend IANA reviewed it draft.set_state(State.objects.get(used=True, type="draft-iana-review", slug="not-ok")) # pretend it was approved to check that we notify the RFC Editor e = DocEvent(type="iesg_approved", doc=draft) e.time = draft.time e.by = Person.objects.get(name="(System)") e.desc = "The IESG approved the document" e.save() # make a discuss to see if the AD gets an email ballot_position = BallotPositionDocEvent() ballot_position.ballot = draft.latest_event(BallotDocEvent, type="created_ballot") ballot_position.pos_id = "discuss" ballot_position.type = "changed_ballot_position" ballot_position.doc = draft ballot_position.ad = ballot_position.by = Person.objects.get(user__username="******") ballot_position.save() name = draft.name rev = "%02d" % (int(draft.rev) + 1) group = draft.group # write the old draft in a file so we can check it's moved away old_rev = draft.rev with open(os.path.join(self.repository_dir, "%s-%s.txt" % (name, old_rev)), 'w') as f: f.write("a" * 2000) status_url = self.do_submission(name, rev, group, formats) # supply submitter info, then previous authors get a confirmation email mailbox_before = len(outbox) r = self.supply_extra_metadata(name, status_url, "Submitter Name", "*****@*****.**", replaces="") self.assertEqual(r.status_code, 302) status_url = r["Location"] r = self.client.get(status_url) self.assertEqual(r.status_code, 200) self.assertTrue("The submission is pending approval by the authors" in unicontent(r)) self.assertEqual(len(outbox), mailbox_before + 1) confirm_email = outbox[-1] self.assertTrue("Confirm submission" in confirm_email["Subject"]) self.assertTrue(name in confirm_email["Subject"]) self.assertTrue(prev_author.author.address in confirm_email["To"]) # submitter and new author can't confirm self.assertTrue("*****@*****.**" not in confirm_email["To"]) self.assertTrue("*****@*****.**" not in confirm_email["To"]) # Verify that mail wasn't sent to know invalid addresses self.assertTrue("unknown-email-" not in confirm_email["To"]) confirm_url = self.extract_confirm_url(confirm_email) # go to confirm page r = self.client.get(confirm_url) q = PyQuery(r.content) self.assertEqual(len(q('[type=submit]:contains("Confirm")')), 1) # confirm mailbox_before = len(outbox) r = self.client.post(confirm_url) self.assertEqual(r.status_code, 302) draft = Document.objects.get(docalias__name=name) self.assertEqual(draft.rev, rev) self.assertEqual(draft.group.acronym, name.split("-")[2]) self.assertEqual(draft.docevent_set.all()[1].type, "new_revision") self.assertEqual(draft.docevent_set.all()[1].by.name, "Submitter Name") self.assertTrue(not os.path.exists(os.path.join(self.repository_dir, "%s-%s.txt" % (name, old_rev)))) self.assertTrue(os.path.exists(os.path.join(self.archive_dir, "%s-%s.txt" % (name, old_rev)))) self.assertTrue(not os.path.exists(os.path.join(self.staging_dir, u"%s-%s.txt" % (name, rev)))) self.assertTrue(os.path.exists(os.path.join(self.repository_dir, u"%s-%s.txt" % (name, rev)))) self.assertEqual(draft.type_id, "draft") self.assertEqual(draft.stream_id, "ietf") self.assertEqual(draft.get_state_slug("draft-stream-%s" % draft.stream_id), "wg-doc") self.assertEqual(draft.get_state_slug("draft-iana-review"), "changed") self.assertEqual(draft.authors.count(), 1) self.assertEqual(draft.authors.all()[0].get_name(), "Author Name") self.assertEqual(draft.authors.all()[0].address, "*****@*****.**") self.assertEqual(len(outbox), mailbox_before + 3) self.assertTrue((u"I-D Action: %s" % name) in outbox[-3]["Subject"]) self.assertTrue((u"I-D Action: %s" % name) in draft.message_set.order_by("-time")[0].subject) self.assertTrue("Author Name" in unicode(outbox[-3])) self.assertTrue("i-d-announce@" in outbox[-3]['To']) self.assertTrue("New Version Notification" in outbox[-2]["Subject"]) self.assertTrue(name in unicode(outbox[-2])) self.assertTrue("mars" in unicode(outbox[-2])) self.assertTrue(draft.ad.role_email("ad").address in unicode(outbox[-2])) self.assertTrue(ballot_position.ad.role_email("ad").address in unicode(outbox[-2])) self.assertTrue("New Version Notification" in outbox[-1]["Subject"]) self.assertTrue(name in unicode(outbox[-1])) self.assertTrue("mars" in unicode(outbox[-1]))
def change_state(request, name, option=None): """Change state of an IESG review for IETF conflicts in other stream's documents, notifying parties as necessary and logging the change as a comment.""" review = get_object_or_404(Document, type="conflrev", name=name) login = request.user.get_profile() if request.method == 'POST': form = ChangeStateForm(request.POST) if form.is_valid(): clean = form.cleaned_data review_state = clean['review_state'] comment = clean['comment'].rstrip() if comment: c = DocEvent(type="added_comment", doc=review, by=login) c.desc = comment c.save() if review_state != review.get_state(): save_document_in_history(review) old_description = review.friendly_state() review.set_state(review_state) new_description = review.friendly_state() log_state_changed(request, review, login, new_description, old_description) review.time = datetime.datetime.now() review.save() if review_state.slug == "iesgeval": create_ballot_if_not_open(review, login, "conflrev") ballot = review.latest_event(BallotDocEvent, type="created_ballot") if has_role(request.user, "Area Director") and not review.latest_event( BallotPositionDocEvent, ad=login, ballot=ballot, type="changed_ballot_position"): # The AD putting a conflict review into iesgeval who doesn't already have a position is saying "yes" pos = BallotPositionDocEvent(doc=review, by=login) pos.ballot = ballot pos.type = "changed_ballot_position" pos.ad = login 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() send_conflict_eval_email(request, review) return redirect('doc_view', name=review.name) else: s = review.get_state() init = dict(review_state=s.pk if s else None) form = ChangeStateForm(initial=init) return render_to_response( 'doc/change_state.html', dict( form=form, doc=review, login=login, help_url=reverse('help_conflict_review_states'), ), context_instance=RequestContext(request))
def start_review(request, name): """Start the conflict review process, setting the initial shepherding AD, and possibly putting the review on a telechat.""" doc_to_review = get_object_or_404(Document, type="draft", name=name) if not doc_to_review.stream_id in ('ise', 'irtf'): raise Http404 # sanity check that there's not already a conflict review document for this document if [ rel.source for alias in doc_to_review.docalias_set.all() for rel in alias.relateddocument_set.filter( relationship='conflrev') ]: raise Http404 login = request.user.get_profile() if request.method == 'POST': form = StartReviewForm(request.POST) if form.is_valid(): if doc_to_review.name.startswith('draft-'): review_name = 'conflict-review-' + doc_to_review.name[6:] else: # This is a failsafe - and might be treated better as an error review_name = 'conflict-review-' + doc_to_review.name 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=form.cleaned_data['ad'], notify=form.cleaned_data['notify'], stream_id='ietf', group=iesg_group, ) conflict_review.save() conflict_review.set_state(form.cleaned_data['create_in_state']) DocAlias.objects.create(name=review_name, document=conflict_review) conflict_review.relateddocument_set.create( target=DocAlias.objects.get(name=doc_to_review.name), relationship_id='conflrev') c = DocEvent(type="added_comment", doc=conflict_review, by=login) c.desc = "IETF conflict review requested" c.save() c = DocEvent(type="added_comment", doc=doc_to_review, by=login) # Is it really OK to put html tags into comment text? c.desc = 'IETF conflict review initiated - see <a href="%s">%s</a>' % ( reverse('doc_view', kwargs={'name': conflict_review.name }), conflict_review.name) c.save() tc_date = form.cleaned_data['telechat_date'] if tc_date: update_telechat(request, conflict_review, login, tc_date) return HttpResponseRedirect(conflict_review.get_absolute_url()) else: # Take care to do the right thing during ietf chair and stream owner transitions ietf_chair_id = Role.objects.filter(group__acronym='ietf', name='chair')[0].person.id notify_addresses = [] notify_addresses.extend([ x.person.formatted_email() for x in Role.objects.filter( group__acronym=doc_to_review.stream.slug, name='chair') ]) notify_addresses.append("%s@%s" % (name, settings.TOOLS_SERVER)) init = { "ad": ietf_chair_id, "notify": u', '.join(notify_addresses), } form = StartReviewForm(initial=init) return render_to_response('doc/conflict_review/start.html', { 'form': form, 'doc_to_review': doc_to_review, }, context_instance=RequestContext(request))
def approve(request, name): """Approve this status change, setting the appropriate state and send the announcements to the right parties.""" status_change = get_object_or_404(Document, type="statchg", name=name) if status_change.get_state('statchg').slug not in ('appr-pend'): raise Http404 login = request.user.get_profile() AnnouncementFormSet = formset_factory(AnnouncementForm,extra=0) if request.method == 'POST': formset = AnnouncementFormSet(request.POST) if formset.is_valid(): save_document_in_history(status_change) old_description = status_change.friendly_state() status_change.set_state(State.objects.get(type='statchg', slug='appr-sent')) new_description = status_change.friendly_state() log_state_changed(request, status_change, login, new_description, old_description) close_open_ballots(status_change, login) e = DocEvent(doc=status_change, by=login) e.type = "iesg_approved" e.desc = "IESG has approved the status change" e.save() status_change.time = e.time status_change.save() for form in formset.forms: send_mail_preformatted(request,form.cleaned_data['announcement_text']) c = DocEvent(type="added_comment", doc=status_change, by=login) c.desc = "The following approval message was sent\n"+form.cleaned_data['announcement_text'] c.save() for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS): # Add a document event to each target c = DocEvent(type="added_comment", doc=rel.target.document, by=login) c.desc = "New status of %s approved by the IESG\n%s%s" % (newstatus(rel), settings.IDTRACKER_BASE_URL,reverse('doc_view', kwargs={'name': status_change.name})) c.save() return HttpResponseRedirect(status_change.get_absolute_url()) else: init = [] for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS): init.append({"announcement_text" : default_approval_text(status_change,rel), "label": "Announcement text for %s to %s"%(rel.target.document.canonical_name(),newstatus(rel)), }) formset = AnnouncementFormSet(initial=init) for form in formset.forms: form.fields['announcement_text'].label=form.label return render_to_response('doc/status_change/approve.html', dict( doc = status_change, formset = formset, ), context_instance=RequestContext(request))
def approve_ballot(request, name): """Approve ballot, sending out announcement, changing state.""" doc = get_object_or_404(Document, docalias__name=name) if not doc.get_state("draft-iesg"): raise Http404() 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 e = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text") if not e: e = generate_ballot_writeup(request, doc) ballot_writeup = e.text if "NOT be published" in approval_text: action = "do_not_publish" elif "To: RFC Editor" in approval_text: action = "to_rfc_editor" else: action = "to_announcement_list" # NOTE: according to Michelle Cotton <*****@*****.**> # (as per 2011-10-24) IANA is scraping these messages for # information so would like to know beforehand if the format # changes announcement = approval_text + "\n\n" + ballot_writeup if request.method == 'POST': if action == "do_not_publish": new_state = State.objects.get(used=True, type="draft-iesg", slug="dead") else: new_state = State.objects.get(used=True, type="draft-iesg", slug="ann") prev_state = doc.get_state("draft-iesg") prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS) 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) doc.set_state(new_state) doc.tags.remove(*prev_tags) # fixup document close_open_ballots(doc, login) e = DocEvent(doc=doc, by=login) if action == "do_not_publish": e.type = "iesg_disapproved" e.desc = "Do Not Publish note has been sent to the RFC Editor" else: e.type = "iesg_approved" e.desc = "IESG has approved the document" e.save() change_description = e.desc + " and state has been changed to %s" % doc.get_state("draft-iesg").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() email_state_changed(request, doc, change_description) email_ad(request, doc, doc.ad, login, change_description) # send announcement send_mail_preformatted(request, announcement) if action == "to_announcement_list": send_mail_preformatted(request, announcement, extra=extra_automation_headers(doc), override={ "To": "IANA <%s>"%settings.IANA_APPROVE_EMAIL, "CC": None, "Bcc": None, "Reply-To": None}) msg = infer_message(announcement) msg.by = login msg.save() msg.related_docs.add(doc) return HttpResponseRedirect(doc.get_absolute_url()) return render_to_response('doc/ballot/approve_ballot.html', dict(doc=doc, action=action, announcement=announcement), context_instance=RequestContext(request))
def edit_position(request, name, ballot_id): """Vote and edit discuss and comment on document as Area Director.""" doc = get_object_or_404(Document, docalias__name=name) ballot = get_object_or_404(BallotDocEvent, type="created_ballot", pk=ballot_id, doc=doc) ad = login = request.user.person if 'ballot_edit_return_point' in request.session: return_to_url = request.session['ballot_edit_return_point'] else: return_to_url = urlreverse("ietf.doc.views_doc.document_ballot", kwargs=dict(name=doc.name, ballot_id=ballot_id)) # if we're in the Secretariat, we can select an AD to act as stand-in for if has_role(request.user, "Secretariat"): ad_id = request.GET.get('ad') if not ad_id: raise Http404 ad = get_object_or_404(Person, pk=ad_id) old_pos = doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position", ad=ad, ballot=ballot) if request.method == 'POST': if not has_role( request.user, "Secretariat") and not ad.role_set.filter( name="ad", group__type="area", group__state="active"): # prevent pre-ADs from voting return HttpResponseForbidden( "Must be a proper Area Director in an active area to cast ballot" ) form = EditPositionForm(request.POST, ballot_type=ballot.ballot_type) if form.is_valid(): # save the vote clean = form.cleaned_data pos = BallotPositionDocEvent(doc=doc, rev=doc.rev, by=login) pos.type = "changed_ballot_position" pos.ballot = ballot pos.ad = ad pos.pos = clean["position"] pos.comment = clean["comment"].rstrip() pos.comment_time = old_pos.comment_time if old_pos else None pos.discuss = clean["discuss"].rstrip() if not pos.pos.blocking: pos.discuss = "" pos.discuss_time = old_pos.discuss_time if old_pos else None changes = [] added_events = [] # possibly add discuss/comment comments to history trail # so it's easy to see what's happened old_comment = old_pos.comment if old_pos else "" if pos.comment != old_comment: pos.comment_time = pos.time changes.append("comment") if pos.comment: e = DocEvent(doc=doc, rev=doc.rev) e.by = ad # otherwise we can't see who's saying it e.type = "added_comment" e.desc = "[Ballot comment]\n" + pos.comment added_events.append(e) old_discuss = old_pos.discuss if old_pos else "" if pos.discuss != old_discuss: pos.discuss_time = pos.time changes.append("discuss") if pos.pos.blocking: e = DocEvent(doc=doc, rev=doc.rev, by=login) e.by = ad # otherwise we can't see who's saying it e.type = "added_comment" e.desc = "[Ballot %s]\n" % pos.pos.name.lower() e.desc += pos.discuss added_events.append(e) # figure out a description if not old_pos and pos.pos.slug != "norecord": pos.desc = u"[Ballot Position Update] New position, %s, has been recorded for %s" % ( pos.pos.name, pos.ad.plain_name()) elif old_pos and pos.pos != old_pos.pos: pos.desc = "[Ballot Position Update] Position for %s has been changed to %s from %s" % ( pos.ad.plain_name(), pos.pos.name, old_pos.pos.name) if not pos.desc and changes: pos.desc = u"Ballot %s text updated for %s" % ( u" and ".join(changes), ad.plain_name()) # only add new event if we actually got a change if pos.desc: if login != ad: pos.desc += u" by %s" % login.plain_name() pos.save() for e in added_events: e.save( ) # save them after the position is saved to get later id for sorting order if request.POST.get("send_mail"): qstr = "" if request.GET.get('ad'): qstr += "?ad=%s" % request.GET.get('ad') return HttpResponseRedirect( urlreverse('ietf.doc.views_ballot.send_ballot_comment', kwargs=dict(name=doc.name, ballot_id=ballot_id)) + qstr) elif request.POST.get("Defer"): return redirect('ietf.doc.views_ballot.defer_ballot', name=doc) elif request.POST.get("Undefer"): return redirect('ietf.doc.views_ballot.undefer_ballot', name=doc) else: return HttpResponseRedirect(return_to_url) else: initial = {} if old_pos: initial['position'] = old_pos.pos.slug initial['discuss'] = old_pos.discuss initial['comment'] = old_pos.comment form = EditPositionForm(initial=initial, ballot_type=ballot.ballot_type) blocking_positions = dict((p.pk, p.name) for p in form.fields["position"].queryset.all() if p.blocking) ballot_deferred = doc.active_defer_event() return render( request, 'doc/ballot/edit_position.html', dict( doc=doc, form=form, ad=ad, return_to_url=return_to_url, old_pos=old_pos, ballot_deferred=ballot_deferred, ballot=ballot, show_discuss_text=old_pos and old_pos.pos.blocking, blocking_positions=json.dumps(blocking_positions), ))
def approve_ballot(request, name): """Approve ballot, sending out announcement, changing state.""" doc = get_object_or_404(Document, docalias__name=name) if not doc.get_state("draft-iesg"): raise Http404 login = request.user.person 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 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 error_duplicate_rfc_editor_note = False e = doc.latest_event(WriteupDocEvent, type="changed_rfc_editor_note_text") if e and (e.text != ""): if "RFC Editor Note" in ballot_writeup: error_duplicate_rfc_editor_note = True ballot_writeup += "\n\n" + e.text if error_duplicate_rfc_editor_note: return render(request, 'doc/draft/rfceditor_note_duplicate_error.html', {'doc': doc}) if "NOT be published" in approval_text: action = "do_not_publish" elif "To: RFC Editor" in approval_text: action = "to_rfc_editor" else: action = "to_announcement_list" # NOTE: according to Michelle Cotton <*****@*****.**> # (as per 2011-10-24) IANA is scraping these messages for # information so would like to know beforehand if the format # changes announcement = approval_text + "\n\n" + ballot_writeup if request.method == 'POST': if action == "do_not_publish": new_state = State.objects.get(used=True, type="draft-iesg", slug="dead") else: new_state = State.objects.get(used=True, type="draft-iesg", slug="ann") 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.POST.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( 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) # fixup document close_open_ballots(doc, login) e = DocEvent(doc=doc, rev=doc.rev, by=login) if action == "do_not_publish": e.type = "iesg_disapproved" e.desc = "Do Not Publish note has been sent to the RFC Editor" 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=[]) if e: events.append(e) doc.save_with_history(events) # send announcement send_mail_preformatted(request, announcement) if action == "to_announcement_list": addrs = gather_address_lists( 'ballot_approved_ietf_stream_iana').as_strings(compact=False) send_mail_preformatted(request, announcement, extra=extra_automation_headers(doc), override={ "To": addrs.to, "CC": addrs.cc, "Bcc": None, "Reply-To": None }) msg = infer_message(announcement) msg.by = login msg.save() msg.related_docs.add(doc) return HttpResponseRedirect(doc.get_absolute_url()) return render(request, 'doc/ballot/approve_ballot.html', dict(doc=doc, action=action, announcement=announcement))
def change_state(request, name, option=None): """Change state of an status-change document, notifying parties as necessary and logging the change as a comment.""" status_change = get_object_or_404(Document, type="statchg", name=name) login = request.user.person if request.method == 'POST': form = ChangeStateForm(request.POST) if form.is_valid(): clean = form.cleaned_data new_state = clean['new_state'] comment = clean['comment'].rstrip() if comment: c = DocEvent(type="added_comment", doc=status_change, by=login) c.desc = comment c.save() 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() if new_state.slug == "iesgeval": create_ballot_if_not_open(status_change, login, "statchg", e.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"): # The AD putting a status change into iesgeval who doesn't already have a position is saying "yes" pos = BallotPositionDocEvent(doc=status_change, by=login) pos.ballot = ballot pos.type = "changed_ballot_position" pos.ad = login 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() send_status_change_eval_email(request,status_change) if new_state.slug == "lc-req": request_last_call(request, status_change) return render_to_response('doc/draft/last_call_requested.html', dict(doc=status_change, url = status_change.get_absolute_url(), ), context_instance=RequestContext(request)) return redirect('doc_view', name=status_change.name) else: s = status_change.get_state() init = dict(new_state=s.pk if s else None, type='statchg', label='Status Change Evaluation State', ) form = ChangeStateForm(initial=init) return render_to_response('doc/change_state.html', dict(form=form, doc=status_change, login=login, help_url=reverse('state_help', kwargs=dict(type="status-change")), ), context_instance=RequestContext(request))