Beispiel #1
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))
Beispiel #2
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.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,
                                   ))
Beispiel #3
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))
Beispiel #4
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))
Beispiel #5
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))
Beispiel #6
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,
                  ))
Beispiel #7
0
    def test_change_state(self):
        make_test_data()

        group = Group.objects.get(acronym="ames")
        charter = group.charter

        url = urlreverse('ietf.doc.views_charter.change_state', kwargs=dict(name=charter.name))
        login_testing_unauthorized(self, "secretary", url)

        first_state = charter.get_state()

        # normal get
        r = self.client.get(url)
        self.assertEqual(r.status_code, 200)
        q = PyQuery(r.content)
        self.assertEqual(len(q('form select[name=charter_state]')), 1)
        
        # faulty post
        r = self.client.post(url, dict(charter_state="-12345"))
        self.assertEqual(r.status_code, 200)
        q = PyQuery(r.content)
        self.assertTrue(len(q('form .has-error')) > 0)
        self.assertEqual(charter.get_state(), first_state)
        
        # change state
        for slug in ("intrev", "extrev", "iesgrev"):
            s = State.objects.get(used=True, type="charter", slug=slug)
            events_before = charter.docevent_set.count()

            empty_outbox()
        
            r = self.client.post(url, dict(charter_state=str(s.pk), message="test message"))
            self.assertEqual(r.status_code, 302)
        
            charter = Document.objects.get(name="charter-ietf-%s" % group.acronym)
            self.assertEqual(charter.get_state_slug(), slug)
            events_now = charter.docevent_set.count()
            self.assertTrue(events_now > events_before)

            def find_event(t):
                return [e for e in charter.docevent_set.all()[:events_now - events_before] if e.type == t]

            self.assertTrue("state changed" in find_event("changed_state")[0].desc.lower())

            if slug in ("intrev", "extrev"):
                self.assertTrue(find_event("created_ballot"))

            self.assertEqual(len(outbox), 3 if slug=="intrev" else 2 )

            if slug=="intrev":
                self.assertIn("Internal WG Review", outbox[-3]['Subject'])
                self.assertIn("iab@", outbox[-3]['To'])
                self.assertIn("iesg@", outbox[-3]['To'])
                self.assertIn("A new IETF WG", outbox[-3].get_payload())
                body = outbox[-3].get_payload()
                for word in ["Chairs", "Ames Man <*****@*****.**>",
                    "Secretaries", "Secretary <*****@*****.**>",
                    "Assigned Area Director", "Areað Irector <*****@*****.**>",
                    "Mailing list", "*****@*****.**",
                    "Charter", "Milestones"]:
                    self.assertIn(word, body)

            self.assertIn("state changed", outbox[-2]['Subject'].lower())
            self.assertIn("iesg-secretary@", outbox[-2]['To'])
            body = outbox[-2].get_payload()
            for word in ["WG", "Charter", ]:
                self.assertIn(word, body)

            self.assertIn("State Update Notice", outbox[-1]['Subject'])
            self.assertIn("ames-chairs@", outbox[-1]['To'])
            body = outbox[-1].get_payload()
            for word in ["State changed", "Datatracker URL", ]:
                self.assertIn(word, body)

        by = Person.objects.get(user__username="******")
        for slug in ('extrev','iesgrev'):
            close_open_ballots(charter,by)
            r = self.client.post(url, dict(charter_state=str(State.objects.get(used=True,type='charter',slug=slug).pk) ))
            self.assertTrue(r.status_code,302)
            charter = Document.objects.get(name="charter-ietf-%s" % group.acronym)
            self.assertTrue(charter.ballot_open('approve'))


        # Exercise internal review of a recharter
        group = Group.objects.get(acronym="mars")
        charter = group.charter
        url = urlreverse('ietf.doc.views_charter.change_state', kwargs=dict(name=charter.name))
        empty_outbox()
        r = self.client.post(url, dict(charter_state=str(State.objects.get(used=True,type="charter",slug="intrev").pk), message="test"))
        self.assertEqual(r.status_code, 302)
        self.assertTrue("A new charter" in outbox[-3].get_payload())
Beispiel #8
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))
Beispiel #9
0
def change_state(request, name, option=None):
    """Change state of charter, notifying parties as necessary and
    logging the change 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")

    chartering_type = get_chartering_type(charter)

    initial_review = charter.latest_event(InitialReviewDocEvent, type="initial_review")
    if charter.get_state_slug() != "infrev" or (initial_review and initial_review.expires < datetime.datetime.now()) or chartering_type == "rechartering":
        initial_review = None

    login = request.user.person

    if request.method == 'POST':
        form = ChangeStateForm(request.POST, group=group)
        if form.is_valid():
            clean = form.cleaned_data
            charter_rev = charter.rev

            if option in ("initcharter", "recharter"):
                if group.type_id == "wg":
                    charter_state = State.objects.get(used=True, type="charter", slug="infrev")
                else:
                    charter_state = clean['charter_state']

                # make sure we have the latest revision set, if we
                # abandoned a charter before, we could have reset the
                # revision to latest approved
                prev_revs = charter.history_set.order_by('-rev')[:1]
                if prev_revs and prev_revs[0].rev > charter_rev:
                    charter_rev = prev_revs[0].rev

                if "-" not in charter_rev:
                    charter_rev = charter_rev + "-00"
            elif option == "abandon":
                oldstate = group.state
                if oldstate.slug in ("proposed", "bof", "unknown"):
                    charter_state = State.objects.get(used=True, type="charter", slug="notrev")
                    #TODO : set an abandoned state and leave some comments here
                    group.state = GroupStateName.objects.get(slug='abandon')
                    group.save()
                    e = ChangeStateGroupEvent(group=group, type="changed_state")
                    e.time = group.time
                    e.by = login
                    e.state_id = group.state.slug
                    e.desc = "Group state changed to %s from %s" % (group.state, oldstate)
                    e.save()

                else:
                    charter_state = State.objects.get(used=True, type="charter", slug="approved")
                    charter_rev = approved_revision(charter.rev)
            else:
                charter_state = clean['charter_state']

            comment = clean['comment'].rstrip()
            message = clean['message']

            if charter_state != charter.get_state():
                # Charter state changed
                save_document_in_history(charter)

                prev_state = charter.get_state()
                new_state = charter_state
                charter.set_state(new_state)
                charter.rev = charter_rev

                if option != "abandon":
                    add_state_change_event(charter, login, prev_state, new_state)
                else:
                    # kill hanging ballots
                    close_open_ballots(charter, login)

                    # Special log for abandoned efforts
                    e = DocEvent(type="changed_document", doc=charter, by=login)
                    e.desc = "IESG has abandoned the chartering effort"
                    e.save()

                if comment:
                    c = DocEvent(type="added_comment", doc=charter, by=login)
                    c.desc = comment
                    c.save()

                charter.time = datetime.datetime.now()
                charter.save()

                if charter_state.slug == 'intrev':
                    email_charter_internal_review(request,charter)

                if message or charter_state.slug == "intrev" or charter_state.slug == "extrev":
                    email_admin_re_charter(request, group, "Charter state changed to %s" % charter_state.name, message,'charter_state_edit_admin_needed')

                # TODO - do we need a seperate set of recipients for state changes to charters vrs other kind of documents
                email_state_changed(request, charter, "State changed to %s." % charter_state, 'doc_state_edited')

                if charter_state.slug == "intrev" and group.type_id == "wg":
                    if request.POST.get("ballot_wo_extern"):
                        create_ballot_if_not_open(charter, login, "r-wo-ext")
                    else:
                        create_ballot_if_not_open(charter, login, "r-extrev")
                    default_review_text(group, charter, login)
                    default_action_text(group, charter, login)
                elif charter_state.slug == "iesgrev":
                    create_ballot_if_not_open(charter, login, "approve")
                elif charter_state.slug == "approved":
                    change_group_state_after_charter_approval(group, login)
                    fix_charter_revision_after_approval(charter, login)

            if charter_state.slug == "infrev" and clean["initial_time"] and clean["initial_time"] != 0:
                e = InitialReviewDocEvent(type="initial_review", by=login, doc=charter)
                e.expires = datetime.datetime.now() + datetime.timedelta(weeks=clean["initial_time"])
                e.desc = "Initial review time expires %s" % e.expires.strftime("%Y-%m-%d")
                e.save()

            return redirect('doc_view', name=charter.name)
    else:
        hide = ['initial_time']
        s = charter.get_state()
        init = dict(charter_state=s.pk if s and option != "recharter" else None)

        if option == "abandon":
            hide = ['initial_time', 'charter_state']

        if group.type_id == "wg":
            if option == "recharter":
                hide = ['initial_time', 'charter_state', 'message']
                init = dict()
            elif option == "initcharter":
                hide = ['charter_state']
                init = dict(initial_time=1, message='%s has initiated chartering of the proposed %s:\n "%s" (%s).' % (login.plain_name(), group.type.name, group.name, group.acronym))
            elif option == "abandon":
                hide = ['initial_time', 'charter_state']
                init = dict(message='%s has abandoned the chartering effort on the %s:\n "%s" (%s).' % (login.plain_name(), group.type.name, group.name, group.acronym))
        form = ChangeStateForm(hide=hide, initial=init, group=group)

    prev_charter_state = None
    charter_hists = DocHistory.objects.filter(doc=charter).exclude(states__type="charter", states__slug=charter.get_state_slug()).order_by("-time")[:1]
    if charter_hists:
        prev_charter_state = charter_hists[0].get_state()

    title = {
        "initcharter": "Initiate chartering of %s %s" % (group.acronym, group.type.name),
        "recharter": "Recharter %s %s" % (group.acronym, group.type.name),
        "abandon": "Abandon effort on %s %s" % (group.acronym, group.type.name),
        }.get(option)
    if not title:
        title = "Change chartering state of %s %s" % (group.acronym, group.type.name)

    def state_pk(slug):
        return State.objects.get(used=True, type="charter", slug=slug).pk

    info_msg = {}
    if group.type_id == "wg":
        info_msg[state_pk("infrev")] = 'The proposed charter for %s "%s" (%s) has been set to Informal IESG review by %s.' % (group.type.name, group.name, group.acronym, login.plain_name())
        info_msg[state_pk("intrev")] = 'The proposed charter for %s "%s" (%s) has been set to Internal review by %s.\nPlease place it on the next IESG telechat if it has not already been placed.' % (group.type.name, group.name, group.acronym, login.plain_name())
        info_msg[state_pk("extrev")] = 'The proposed charter for %s "%s" (%s) has been set to External review by %s.\nPlease send out the external review announcement to the appropriate lists.\n\nSend the announcement to other SDOs: Yes\nAdditional recipients of the announcement: ' % (group.type.name, group.name, group.acronym, login.plain_name())

    states_for_ballot_wo_extern = State.objects.none()
    if group.type_id == "wg":
        states_for_ballot_wo_extern = State.objects.filter(used=True, type="charter", slug="intrev").values_list("pk", flat=True)

    return render_to_response('doc/charter/change_state.html',
                              dict(form=form,
                                   doc=group.charter,
                                   login=login,
                                   option=option,
                                   prev_charter_state=prev_charter_state,
                                   title=title,
                                   initial_review=initial_review,
                                   chartering_type=chartering_type,
                                   info_msg=json.dumps(info_msg),
                                   states_for_ballot_wo_extern=json.dumps(list(states_for_ballot_wo_extern)),
                                   ),
                              context_instance=RequestContext(request))
Beispiel #10
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))
Beispiel #11
0
def change_state(request, name, option=None):
    """Change state of charter, notifying parties as necessary and
    logging the change 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")

    chartering_type = get_chartering_type(charter)

    initial_review = charter.latest_event(InitialReviewDocEvent,
                                          type="initial_review")
    if charter.get_state_slug() != "infrev" or (
            initial_review and initial_review.expires <
            datetime.datetime.now()) or chartering_type == "rechartering":
        initial_review = None

    by = request.user.person

    if request.method == 'POST':
        form = ChangeStateForm(request.POST, group=group)
        if form.is_valid():
            clean = form.cleaned_data
            charter_rev = charter.rev

            if option in ("initcharter", "recharter"):
                if group.type_id == "wg":
                    charter_state = State.objects.get(used=True,
                                                      type="charter",
                                                      slug="infrev")
                else:
                    charter_state = clean['charter_state']

                # make sure we have the latest revision set, if we
                # abandoned a charter before, we could have reset the
                # revision to latest approved
                prev_revs = charter.history_set.order_by('-rev')[:1]
                if prev_revs and prev_revs[0].rev > charter_rev:
                    charter_rev = prev_revs[0].rev

                if "-" not in charter_rev:
                    charter_rev = charter_rev + "-00"
            elif option == "abandon":
                oldstate = group.state
                if oldstate.slug in ("proposed", "bof", "unknown"):
                    charter_state = State.objects.get(used=True,
                                                      type="charter",
                                                      slug="notrev")
                    #TODO : set an abandoned state and leave some comments here
                    group.state = GroupStateName.objects.get(slug='abandon')
                    group.save()
                    e = ChangeStateGroupEvent(group=group,
                                              type="changed_state")
                    e.time = group.time
                    e.by = by
                    e.state_id = group.state.slug
                    e.desc = "Group state changed to \"%s\" from \"%s\"" % (
                        group.state, oldstate)
                    e.save()

                else:
                    charter_state = State.objects.get(used=True,
                                                      type="charter",
                                                      slug="approved")
                    charter_rev = approved_revision(charter.rev)
            else:
                charter_state = clean['charter_state']

            comment = clean['comment'].rstrip()
            message = clean['message']

            if charter_state != charter.get_state():
                events = []
                prev_state = charter.get_state()
                new_state = charter_state
                charter.set_state(new_state)
                charter.rev = charter_rev

                if option != "abandon":
                    e = add_state_change_event(charter, by, prev_state,
                                               new_state)
                    if e:
                        events.append(e)
                else:
                    # kill hanging ballots
                    close_open_ballots(charter, by)

                    # Special log for abandoned efforts
                    e = DocEvent(type="changed_document",
                                 doc=charter,
                                 rev=charter.rev,
                                 by=by)
                    e.desc = "Chartering effort abandoned"
                    e.save()
                    events.append(e)

                if comment:
                    events.append(
                        DocEvent.objects.create(type="added_comment",
                                                doc=charter,
                                                rev=charter.rev,
                                                by=by,
                                                desc=comment))

                charter.save_with_history(events)

                if charter_state.slug == 'intrev':
                    email_charter_internal_review(request, charter)

                if message or charter_state.slug == "intrev" or charter_state.slug == "extrev":
                    email_admin_re_charter(
                        request, group,
                        "Charter state changed to \"%s\"" % charter_state.name,
                        message, 'charter_state_edit_admin_needed')

                # TODO - do we need a seperate set of recipients for state changes to charters vrs other kind of documents
                email_state_changed(request, charter,
                                    "State changed to %s." % charter_state,
                                    'doc_state_edited')

                if charter_state.slug == "intrev" and group.type_id == "wg":
                    if request.POST.get("ballot_wo_extern"):
                        create_ballot_if_not_open(charter, by, "r-wo-ext")
                    else:
                        create_ballot_if_not_open(charter, by, "r-extrev")
                    (e1, e2) = default_review_text(group, charter, by)
                    e1.save()
                    e2.save()
                    e = default_action_text(group, charter, by)
                    e.save()
                elif charter_state.slug in ["extrev", "iesgrev"]:
                    create_ballot_if_not_open(charter, by, "approve")
                elif charter_state.slug == "approved":
                    change_group_state_after_charter_approval(group, by)
                    fix_charter_revision_after_approval(charter, by)

            if charter_state.slug == "infrev" and clean[
                    "initial_time"] and clean["initial_time"] != 0:
                e = InitialReviewDocEvent(type="initial_review",
                                          by=by,
                                          doc=charter,
                                          rev=charter.rev)
                e.expires = datetime.datetime.now() + datetime.timedelta(
                    weeks=clean["initial_time"])
                e.desc = "Initial review time expires %s" % e.expires.strftime(
                    "%Y-%m-%d")
                e.save()

            return redirect('ietf.doc.views_doc.document_main',
                            name=charter.name)
    else:
        hide = ['initial_time']
        s = charter.get_state()
        init = dict(
            charter_state=s.pk if s and option != "recharter" else None)

        if option == "abandon":
            hide = ['initial_time', 'charter_state']

        if group.type_id == "wg":
            if option == "recharter":
                hide = ['initial_time', 'charter_state', 'message']
                init = dict()
            elif option == "initcharter":
                hide = ['charter_state']
                init = dict(
                    initial_time=1,
                    message=
                    '%s has initiated chartering of the proposed %s:\n "%s" (%s).'
                    % (by.plain_name(), group.type.name, group.name,
                       group.acronym))
            elif option == "abandon":
                hide = ['initial_time', 'charter_state']
                init = dict(
                    message=
                    '%s has abandoned the chartering effort on the %s:\n "%s" (%s).'
                    % (by.plain_name(), group.type.name, group.name,
                       group.acronym))
        form = ChangeStateForm(hide=hide, initial=init, group=group)

    prev_charter_state = None
    charter_hists = DocHistory.objects.filter(doc=charter).exclude(
        states__type="charter",
        states__slug=charter.get_state_slug()).order_by("-time")[:1]
    if charter_hists:
        prev_charter_state = charter_hists[0].get_state()

    title = {
        "initcharter":
        "Initiate chartering of %s %s" % (group.acronym, group.type.name),
        "recharter":
        "Recharter %s %s" % (group.acronym, group.type.name),
        "abandon":
        "Abandon effort on %s %s" % (group.acronym, group.type.name),
    }.get(option)
    if not title:
        title = "Change chartering state of %s %s" % (group.acronym,
                                                      group.type.name)

    def state_pk(slug):
        return State.objects.get(used=True, type="charter", slug=slug).pk

    info_msg = {}
    if group.type_id == "wg":
        info_msg[state_pk(
            "infrev"
        )] = 'The proposed charter for %s "%s" (%s) has been set to Informal IESG review by %s.' % (
            group.type.name, group.name, group.acronym, by.plain_name())
        info_msg[state_pk(
            "intrev"
        )] = 'The proposed charter for %s "%s" (%s) has been set to Internal review by %s.\nPlease place it on the next IESG telechat if it has not already been placed.' % (
            group.type.name, group.name, group.acronym, by.plain_name())
        info_msg[state_pk(
            "extrev"
        )] = 'The proposed charter for %s "%s" (%s) has been set to External review by %s.\nPlease send out the external review announcement to the appropriate lists.\n\nSend the announcement to other SDOs: Yes\nAdditional recipients of the announcement: ' % (
            group.type.name, group.name, group.acronym, by.plain_name())

    states_for_ballot_wo_extern = State.objects.none()
    if group.type_id == "wg":
        states_for_ballot_wo_extern = State.objects.filter(
            used=True, type="charter", slug="intrev").values_list("pk",
                                                                  flat=True)

    return render(
        request, 'doc/charter/change_state.html',
        dict(
            form=form,
            doc=group.charter,
            option=option,
            prev_charter_state=prev_charter_state,
            title=title,
            initial_review=initial_review,
            chartering_type=chartering_type,
            info_msg=json.dumps(info_msg),
            states_for_ballot_wo_extern=json.dumps(
                list(states_for_ballot_wo_extern)),
        ))