Example #1
0
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))
Example #2
0
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))
Example #3
0
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))
Example #4
0
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()
Example #5
0
File: utils.py Project: mcr/ietfdb
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
Example #6
0
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))
Example #7
0
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()
Example #8
0
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
Example #9
0
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),
        ))
Example #10
0
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))
Example #11
0
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))
Example #12
0
def approve(request, name):
    """Approve charter, changing state, fixing revision, copying file to final location."""
    charter = get_object_or_404(Document, type="charter", name=name)
    group = charter.group

    by = request.user.person

    e = charter.latest_event(WriteupDocEvent,
                             type="changed_action_announcement")
    if not e:
        announcement = default_action_text(group, charter, by).text
    else:
        announcement = e.text

    if request.method == 'POST':
        new_charter_state = State.objects.get(used=True,
                                              type="charter",
                                              slug="approved")
        prev_charter_state = charter.get_state()

        charter.set_state(new_charter_state)

        close_open_ballots(charter, by)

        events = []
        # approve
        e = DocEvent(doc=charter, rev=charter.rev, 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, by)
        if group_state_change_event:
            change_description += " and group state has been changed to %s" % group.state.name

        e = add_state_change_event(charter, by, prev_charter_state,
                                   new_charter_state)
        if e:
            events.append(e)

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

        # move milestones over
        milestones_to_delete = list(
            group.groupmilestone_set.filter(state__in=("active", "review")))

        for m in group.groupmilestone_set.filter(state="charter"):
            # see if we got this milestone already (i.e. it was copied
            # verbatim to the charter)
            found = False
            for i, o in enumerate(milestones_to_delete):
                if o.desc == m.desc and o.due == m.due and set(
                        o.docs.all()) == set(m.docs.all()):
                    found = True
                    break

            if found:
                # keep existing, whack charter milestone
                if not o.state_id == "active":
                    save_milestone_in_history(o)
                    o.state_id = "active"
                    o.save()
                    MilestoneGroupEvent.objects.create(
                        group=group,
                        type="changed_milestone",
                        by=by,
                        desc=
                        "Changed milestone \"%s\", set state to active from review"
                        % o.desc,
                        milestone=o)

                del milestones_to_delete[i]

                # don't generate a DocEvent for this, it's implicit in the approval event
                save_milestone_in_history(m)
                m.state_id = "deleted"
                m.save()
            else:
                # move charter milestone
                save_milestone_in_history(m)
                m.state_id = "active"
                m.save()

                MilestoneGroupEvent.objects.create(
                    group=group,
                    type="changed_milestone",
                    by=by,
                    desc="Added milestone \"%s\", due %s, from approved charter"
                    % (m.desc, m.due),
                    milestone=m)

        for m in milestones_to_delete:
            save_milestone_in_history(m)
            m.state_id = "deleted"
            m.save()

            MilestoneGroupEvent.objects.create(
                group=group,
                type="changed_milestone",
                by=by,
                desc="Deleted milestone \"%s\", not present in approved charter"
                % m.desc,
                milestone=m)

        # send announcement
        send_mail_preformatted(request, announcement)

        return HttpResponseRedirect(charter.get_absolute_url())

    return render(request, 'doc/charter/approve.html',
                  dict(charter=charter, announcement=announcement))
Example #13
0
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))
Example #14
0
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 'HTTP_REFERER' in request.META:
        return_to_url = request.META['HTTP_REFERER']
    else:
        return_to_url = urlreverse("doc_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

            if clean['return_to_url']:
              return_to_url = clean['return_to_url']

            pos = BallotPositionDocEvent(doc=doc, 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)
                    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, 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 = "?return_to_url=%s" % return_to_url
                if request.GET.get('ad'):
                    qstr += "&ad=%s" % request.GET.get('ad')
                return HttpResponseRedirect(urlreverse("doc_send_ballot_comment", kwargs=dict(name=doc.name, ballot_id=ballot_id)) + qstr)
            elif request.POST.get("Defer"):
                return redirect("doc_defer_ballot", name=doc)
            elif request.POST.get("Undefer"):
                return redirect("doc_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
            
        if return_to_url:
            initial['return_to_url'] = return_to_url
            
        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_to_response('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),
                                   ),
                              context_instance=RequestContext(request))
Example #15
0
def approve(request, name):
    """Approve charter, changing state, fixing revision, copying file to final location."""
    charter = get_object_or_404(Document, type="charter", name=name)
    group = charter.group

    login = request.user.person

    e = charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
    if not e:
        announcement = default_action_text(group, charter, login).text
    else:
        announcement = e.text

    if request.method == 'POST':
        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)

        # approve
        e = DocEvent(doc=charter, by=login)
        e.type = "iesg_approved"
        e.desc = "IESG has approved the charter"
        e.save()

        change_description = e.desc

        group_state_change_event = change_group_state_after_charter_approval(group, login)
        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)

        fix_charter_revision_after_approval(charter, login)

        email_admin_re_charter(request, group, "Charter state changed to %s" % new_charter_state.name, change_description,'charter_state_edit_admin_needed')

        # move milestones over
        milestones_to_delete = list(group.groupmilestone_set.filter(state__in=("active", "review")))

        for m in group.groupmilestone_set.filter(state="charter"):
            # see if we got this milestone already (i.e. it was copied
            # verbatim to the charter)
            found = False
            for i, o in enumerate(milestones_to_delete):
                if o.desc == m.desc and o.due == m.due and set(o.docs.all()) == set(m.docs.all()):
                    found = True
                    break

            if found:
                # keep existing, whack charter milestone
                if not o.state_id == "active":
                    save_milestone_in_history(o)
                    o.state_id = "active"
                    o.save()
                    MilestoneGroupEvent.objects.create(
                        group=group, type="changed_milestone", by=login,
                        desc="Changed milestone \"%s\", set state to active from review" % o.desc,
                        milestone=o)

                del milestones_to_delete[i]

                # don't generate a DocEvent for this, it's implicit in the approval event
                save_milestone_in_history(m)
                m.state_id = "deleted"
                m.save()
            else:
                # move charter milestone
                save_milestone_in_history(m)
                m.state_id = "active"
                m.save()

                MilestoneGroupEvent.objects.create(
                    group=group, type="changed_milestone", by=login,
                    desc="Added milestone \"%s\", due %s, from approved charter" % (m.desc, m.due),
                    milestone=m)

        for m in milestones_to_delete:
            save_milestone_in_history(m)
            m.state_id = "deleted"
            m.save()

            MilestoneGroupEvent.objects.create(
                group=group, type="changed_milestone", by=login,
                desc="Deleted milestone \"%s\", not present in approved charter" % m.desc,
                milestone=m)

        # send announcement
        send_mail_preformatted(request, announcement)

        return HttpResponseRedirect(charter.get_absolute_url())

    return render_to_response('doc/charter/approve.html',
                              dict(charter=charter,
                                   announcement=announcement),
                              context_instance=RequestContext(request))
Example #16
0
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))
Example #17
0
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.person

    AnnouncementFormSet = formset_factory(AnnouncementForm, extra=0)

    if request.method == 'POST':

        formset = AnnouncementFormSet(request.POST)

        if formset.is_valid():

            prev_state = status_change.get_state()
            new_state = State.objects.get(type='statchg', slug='appr-sent')

            status_change.set_state(new_state)

            events = []
            events.append(
                add_state_change_event(status_change, login, prev_state,
                                       new_state))

            close_open_ballots(status_change, login)

            e = DocEvent(doc=status_change, rev=status_change.rev, by=login)
            e.type = "iesg_approved"
            e.desc = "IESG has approved the status change"
            e.save()
            events.append(e)

            status_change.save_with_history(events)

            for form in formset.forms:

                send_mail_preformatted(request,
                                       form.cleaned_data['announcement_text'])

                c = DocEvent(type="added_comment",
                             doc=status_change,
                             rev=status_change.rev,
                             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=STATUSCHANGE_RELATIONS):
                # Add a document event to each target
                c = DocEvent(type="added_comment",
                             doc=rel.target.document,
                             rev=rel.target.document.rev,
                             by=login)
                c.desc = "New status of %s approved by the IESG\n%s%s" % (
                    newstatus(rel), settings.IDTRACKER_BASE_URL,
                    reverse('ietf.doc.views_doc.document_main',
                            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=STATUSCHANGE_RELATIONS):
            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(request, 'doc/status_change/approve.html',
                  dict(
                      doc=status_change,
                      formset=formset,
                  ))