Exemplo n.º 1
0
    def test_notification(self):
        draft = make_test_data()

        clist = CommunityList.objects.create(user=User.objects.get(username="******"))
        clist.added_docs.add(draft)
        SearchRule.objects.create(
            community_list=clist,
            rule_type="name_contains",
            state=State.objects.get(type="draft", slug="active"),
            text="test",
        )

        EmailSubscription.objects.create(community_list=clist, email=Email.objects.filter(person__user__username="******").first(), notify_on="significant")

        mailbox_before = len(outbox)
        active_state = State.objects.get(type="draft", slug="active")
        system = Person.objects.get(name="(System)")
        add_state_change_event(draft, system, None, active_state)
        self.assertEqual(len(outbox), mailbox_before)

        mailbox_before = len(outbox)
        rfc_state = State.objects.get(type="draft", slug="rfc")
        add_state_change_event(draft, system, active_state, rfc_state)
        self.assertEqual(len(outbox), mailbox_before + 1)
        self.assertTrue(draft.name in outbox[-1]["Subject"])
Exemplo n.º 2
0
def change_state(request, name, option=None):
    """Change state of an IESG review for IETF conflicts in other stream's documents, notifying parties as necessary
    and logging the change as a comment."""
    review = get_object_or_404(Document, type="conflrev", name=name)

    login = request.user.person

    if request.method == 'POST':
        form = ChangeStateForm(request.POST)
        if form.is_valid():
            clean = form.cleaned_data
            new_state = clean['review_state']
            comment = clean['comment'].rstrip()

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

            prev_state = review.get_state()
            if new_state != prev_state:
                save_document_in_history(review)

                review.set_state(new_state)
                add_state_change_event(review, login, prev_state, new_state)

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

                if new_state.slug == "iesgeval":
                    create_ballot_if_not_open(review, login, "conflrev")
                    ballot = review.latest_event(BallotDocEvent, type="created_ballot")
                    if has_role(request.user, "Area Director") and not review.latest_event(BallotPositionDocEvent, ad=login, ballot=ballot, type="changed_ballot_position"):

                        # The AD putting a conflict review into iesgeval who doesn't already have a position is saying "yes"
                        pos = BallotPositionDocEvent(doc=review, by=login)
                        pos.ballot = ballot
                        pos.type = "changed_ballot_position"
                        pos.ad = login
                        pos.pos_id = "yes"
                        pos.desc = "[Ballot Position Update] New position, %s, has been recorded for %s" % (pos.pos.name, pos.ad.plain_name())
                        pos.save()
                    send_conflict_eval_email(request,review)


            return redirect('doc_view', name=review.name)
    else:
        s = review.get_state()
        init = dict(review_state=s.pk if s else None)
        form = ChangeStateForm(initial=init)

    return render_to_response('doc/change_state.html',
                              dict(form=form,
                                   doc=review,
                                   login=login,
                                   help_url=reverse('state_help', kwargs=dict(type="conflict-review")),
                                   ),
                              context_instance=RequestContext(request))
Exemplo n.º 3
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()

            new_state_slug = 'appr-reqnopub-sent' if prev_state.slug == 'appr-reqnopub-pend' else 'appr-noprob-sent'
            new_state = State.objects.get(used=True, type="conflrev", slug=new_state_slug)
            save_document_in_history(review)

            review.set_state(new_state)
            add_state_change_event(review, login, prev_state, new_state)

            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))
Exemplo n.º 4
0
def do_undefer_ballot(request, doc):
    '''
    Helper function to perform undefer of ballot.  Takes the Request object, for use in 
    logging, and the Document object.
    '''
    login = request.user.person
    telechat_date = TelechatDate.objects.active().order_by("date")[0].date
    save_document_in_history(doc)

    new_state = doc.get_state()
    prev_tags = new_tags = []

    if doc.type_id == 'draft':
        new_state = State.objects.get(used=True, type="draft-iesg", slug='iesg-eva')
        prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
    elif doc.type_id in ['conflrev','statchg']:
        new_state = State.objects.get(used=True, type=doc.type_id, slug='iesgeval')

    prev_state = doc.get_state(new_state.type_id if new_state else None)

    doc.set_state(new_state)
    doc.tags.remove(*prev_tags)

    e = add_state_change_event(doc, login, prev_state, new_state, prev_tags=prev_tags, new_tags=new_tags)
    
    doc.time = (e and e.time) or datetime.datetime.now()
    doc.save()

    update_telechat(request, doc, login, telechat_date)
    email_state_changed(request, doc, e.desc)
    email_ballot_undeferred(request, doc, login.plain_name(), telechat_date)
Exemplo n.º 5
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()
Exemplo n.º 6
0
def do_withdraw(draft, request):
    '''
    Actions
    - change state to withdrawn
    - TODO move file to archive
    '''
    withdraw_type = request.POST.get('withdraw_type')

    prev_state = draft.get_state("draft")
    new_state = None
    if withdraw_type == 'ietf':
        new_state = State.objects.get(type="draft", slug="ietf-rm")
    elif withdraw_type == 'author':
        new_state = State.objects.get(type="draft", slug="auth-rm")

    if not new_state:
        return

    draft.set_state(new_state)

    e = add_state_change_event(draft, request.user.person, prev_state,
                               new_state)
    if e:
        draft.save_with_history([e])

    # send announcement
    form = EmailForm(request.POST)
    announcement_from_form(form.data, by=request.user.person)

    return
Exemplo n.º 7
0
def expire_last_call(doc):
    if doc.type_id == 'draft':
        new_state = State.objects.get(used=True, type="draft-iesg", slug="writeupw")
        e = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text")
        if e and "Relevant content can frequently be found in the abstract" not in e.text:
            # if boiler-plate text has been removed, we assume the
            # write-up has been written
            new_state = State.objects.get(used=True, type="draft-iesg", slug="goaheadw")
    elif doc.type_id == 'statchg':
        new_state = State.objects.get(used=True, type="statchg", slug="goahead")
    else:
        raise ValueError("Unexpected document type to expire_last_call(): %s" % doc.type)

    save_document_in_history(doc)

    prev_state = doc.get_state(new_state.type_id)
    doc.set_state(new_state)

    prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
    doc.tags.remove(*prev_tags)

    system = Person.objects.get(name="(System)")
    e = add_state_change_event(doc, system, prev_state, new_state, prev_tags=prev_tags, new_tags=[])
                    
    doc.time = (e and e.time) or datetime.datetime.now()
    doc.save()

    email_last_call_expired(doc)
Exemplo n.º 8
0
def change_state(request, name, option=None):
    """Change state of an IESG review for IETF conflicts in other stream's documents, notifying parties as necessary
    and logging the change as a comment."""
    review = get_object_or_404(Document, type="conflrev", name=name)

    login = request.user.person

    if request.method == 'POST':
        form = ChangeStateForm(request.POST)
        if form.is_valid():
            clean = form.cleaned_data
            new_state = clean['review_state']
            comment = clean['comment'].rstrip()

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

            prev_state = review.get_state()
            if new_state != prev_state:
                events = []

                review.set_state(new_state)
                events.append(add_state_change_event(review, login, prev_state, new_state))

                review.save_with_history(events)

                if new_state.slug == "iesgeval":
                    create_ballot_if_not_open(review, login, "conflrev")
                    ballot = review.latest_event(BallotDocEvent, type="created_ballot")
                    if has_role(request.user, "Area Director") and not review.latest_event(BallotPositionDocEvent, ad=login, ballot=ballot, type="changed_ballot_position"):

                        # The AD putting a conflict review into iesgeval who doesn't already have a position is saying "yes"
                        pos = BallotPositionDocEvent(doc=review, rev=review.rev, by=login)
                        pos.ballot = ballot
                        pos.type = "changed_ballot_position"
                        pos.ad = login
                        pos.pos_id = "yes"
                        pos.desc = "[Ballot Position Update] New position, %s, has been recorded for %s" % (pos.pos.name, pos.ad.plain_name())
                        pos.save()
                        # Consider mailing that position to 'ballot_saved'
                    send_conflict_eval_email(request,review)


            return redirect('ietf.doc.views_doc.document_main', name=review.name)
    else:
        s = review.get_state()
        init = dict(review_state=s.pk if s else None)
        form = ChangeStateForm(initial=init)

    return render(request, 'doc/change_state.html',
                              dict(form=form,
                                   doc=review,
                                   login=login,
                                   help_url=reverse('ietf.doc.views_help.state_help', kwargs=dict(type="conflict-review")),
                                   ))
Exemplo n.º 9
0
def last_call(request, name):
    """Edit the Last Call Text for this status change and possibly request IETF LC"""

    status_change = get_object_or_404(Document, type="statchg", name=name)

    login = request.user.person

    last_call_event = status_change.latest_event(WriteupDocEvent, type="changed_last_call_text")
    if not last_call_event:
        last_call_event = generate_last_call_text(request, status_change)

    form = LastCallTextForm(initial=dict(last_call_text=last_call_event.text))

    if request.method == 'POST':
        if "save_last_call_text" in request.POST or "send_last_call_request" in request.POST:
            form = LastCallTextForm(request.POST)
            if form.is_valid():
                t = form.cleaned_data['last_call_text']
                if t != last_call_event.text:
                    e = WriteupDocEvent(doc=status_change, by=login)
                    e.by = login
                    e.type = "changed_last_call_text"
                    e.desc = "Last call announcement was changed"
                    e.text = t
                    e.save()

                if "send_last_call_request" in request.POST:
                    save_document_in_history(status_change)

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

                    status_change.set_state(new_state)
                    e = add_state_change_event(status_change, login, prev_state, new_state)

                    status_change.time = (e and e.time) or datetime.datetime.now()
                    status_change.save()

                    request_last_call(request, status_change)

                    return render_to_response('doc/draft/last_call_requested.html',
                                              dict(doc=status_change,
                                                   url = status_change.get_absolute_url(),
                                                  ),
                                              context_instance=RequestContext(request))

        if "regenerate_last_call_text" in request.POST:
            e = generate_last_call_text(request,status_change)
            form = LastCallTextForm(initial=dict(last_call_text=e.text))
            
    return render_to_response('doc/status_change/last_call.html',
                               dict(doc=status_change,
                                    back_url = status_change.get_absolute_url(),
                                    last_call_event = last_call_event,
                                    last_call_form  = form,
                                   ),
                               context_instance = RequestContext(request))
Exemplo n.º 10
0
    def test_rfceditor_undo(self):
        draft = make_test_data()

        e1 = add_state_change_event(
            draft, Person.objects.get(name="(System)"), None,
            State.objects.get(used=True, type="draft-rfceditor", slug="auth"))
        e1.desc = "First"
        e1.save()

        e2 = add_state_change_event(
            draft, Person.objects.get(name="(System)"), None,
            State.objects.get(used=True, type="draft-rfceditor", slug="edit"))
        e2.desc = "Second"
        e2.save()

        url = urlreverse('ietf.sync.views.rfceditor_undo')
        login_testing_unauthorized(self, "rfc", url)

        # get
        r = self.client.get(url)
        self.assertEquals(r.status_code, 200)
        self.assertTrue(e2.doc_id in r.content)

        # delete e2
        deleted_before = DeletedEvent.objects.count()

        r = self.client.post(url, dict(event=e2.id))
        self.assertEquals(r.status_code, 302)

        self.assertEquals(StateDocEvent.objects.filter(id=e2.id).count(), 0)
        self.assertEquals(draft.get_state("draft-rfceditor").slug, "auth")
        self.assertEquals(DeletedEvent.objects.count(), deleted_before + 1)

        # delete e1
        draft.state_cache = None
        r = self.client.post(url, dict(event=e1.id))
        self.assertEquals(draft.get_state("draft-rfceditor"), None)

        # let's just test we can recover
        e = DeletedEvent.objects.all().order_by("-time", "-id")[0]

        e.content_type.model_class().objects.create(**json.loads(e.json))
        self.assertTrue(StateDocEvent.objects.filter(desc="First", doc=draft))
Exemplo n.º 11
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,
                                   ))
Exemplo n.º 12
0
    def test_rfceditor_undo(self):
        draft = make_test_data()

        e1 = add_state_change_event(draft, Person.objects.get(name="(System)"), None,
                                   State.objects.get(used=True, type="draft-rfceditor", slug="auth"))
        e1.desc = "First"
        e1.save()

        e2 = add_state_change_event(draft, Person.objects.get(name="(System)"), None,
                                   State.objects.get(used=True, type="draft-rfceditor", slug="edit"))
        e2.desc = "Second"
        e2.save()
        
        url = urlreverse('ietf.sync.views.rfceditor_undo')
        login_testing_unauthorized(self, "rfc", url)

        # get
        r = self.client.get(url)
        self.assertEqual(r.status_code, 200)
        self.assertTrue(e2.doc_id in unicontent(r))

        # delete e2
        deleted_before = DeletedEvent.objects.count()

        r = self.client.post(url, dict(event=e2.id))
        self.assertEqual(r.status_code, 302)

        self.assertEqual(StateDocEvent.objects.filter(id=e2.id).count(), 0)
        self.assertEqual(draft.get_state("draft-rfceditor").slug, "auth")
        self.assertEqual(DeletedEvent.objects.count(), deleted_before + 1)

        # delete e1
        draft.state_cache = None
        r = self.client.post(url, dict(event=e1.id))
        self.assertEqual(draft.get_state("draft-rfceditor"), None)

        # let's just test we can recover
        e = DeletedEvent.objects.all().order_by("-time", "-id")[0]

        e.content_type.model_class().objects.create(**json.loads(e.json))
        self.assertTrue(StateDocEvent.objects.filter(desc="First", doc=draft))
Exemplo n.º 13
0
def defer_ballot(request, name):
    """Signal post-pone of ballot, notifying relevant parties."""
    doc = get_object_or_404(Document, docalias__name=name)
    if doc.type_id not in ('draft','conflrev','statchg'):
        raise Http404()
    interesting_state = dict(draft='draft-iesg',conflrev='conflrev',statchg='statchg')
    state = doc.get_state(interesting_state[doc.type_id])
    if not state or state.slug=='defer' or not doc.telechat_date():
        raise Http404()

    login = request.user.person
    telechat_date = TelechatDate.objects.active().order_by("date")[1].date

    if request.method == 'POST':
        save_document_in_history(doc)

        new_state = doc.get_state()
        prev_tags = new_tags = []

        if doc.type_id == 'draft':
            new_state = State.objects.get(used=True, type="draft-iesg", slug='defer')
            prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
        elif doc.type_id in ['conflrev','statchg']:
            new_state = State.objects.get(used=True, type=doc.type_id, slug='defer')

        prev_state = doc.get_state(new_state.type_id if new_state else None)

        doc.set_state(new_state)
        doc.tags.remove(*prev_tags)

        e = add_state_change_event(doc, login, prev_state, new_state, prev_tags=prev_tags, new_tags=new_tags)
        
        doc.time = (e and e.time) or datetime.datetime.now()
        doc.save()

        email_state_changed(request, doc, e.desc)

        update_telechat(request, doc, login, telechat_date)
        email_ballot_deferred(request, doc, login.plain_name(), telechat_date)

        return HttpResponseRedirect(doc.get_absolute_url())
  
    return render_to_response('doc/ballot/defer_ballot.html',
                              dict(doc=doc,
                                   telechat_date=telechat_date,
                                   back_url=doc.get_absolute_url()),
                              context_instance=RequestContext(request))
Exemplo n.º 14
0
def do_undefer_ballot(request, doc):
    '''
    Helper function to perform undefer of ballot.  Takes the Request object, for use in 
    logging, and the Document object.
    '''
    by = request.user.person
    telechat_date = TelechatDate.objects.active().order_by("date")[0].date

    new_state = doc.get_state()
    prev_tags = []
    new_tags = []

    if doc.type_id == 'draft':
        new_state = State.objects.get(used=True,
                                      type="draft-iesg",
                                      slug='iesg-eva')
        prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
    elif doc.type_id in ['conflrev', 'statchg']:
        new_state = State.objects.get(used=True,
                                      type=doc.type_id,
                                      slug='iesgeval')

    prev_state = doc.get_state(new_state.type_id if new_state else None)

    doc.set_state(new_state)
    doc.tags.remove(*prev_tags)

    events = []
    state_change_event = add_state_change_event(doc,
                                                by,
                                                prev_state,
                                                new_state,
                                                prev_tags=prev_tags,
                                                new_tags=new_tags)
    if state_change_event:
        events.append(state_change_event)

    e = update_telechat(request, doc, by, telechat_date)
    if e:
        events.append(e)

    if events:
        doc.save_with_history(events)

    email_ballot_undeferred(request, doc, by.plain_name(), telechat_date)
Exemplo n.º 15
0
def expire_last_call(doc):
    if doc.type_id == 'draft':
        new_state = State.objects.get(used=True,
                                      type="draft-iesg",
                                      slug="writeupw")
        e = doc.latest_event(WriteupDocEvent,
                             type="changed_ballot_writeup_text")
        if e and "Relevant content can frequently be found in the abstract" not in e.text:
            # if boiler-plate text has been removed, we assume the
            # write-up has been written
            new_state = State.objects.get(used=True,
                                          type="draft-iesg",
                                          slug="goaheadw")
    elif doc.type_id == 'statchg':
        new_state = State.objects.get(used=True,
                                      type="statchg",
                                      slug="goahead")
    else:
        raise ValueError("Unexpected document type to expire_last_call(): %s" %
                         doc.type)

    prev_state = doc.get_state(new_state.type_id)
    doc.set_state(new_state)

    prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
    doc.tags.remove(*prev_tags)

    system = Person.objects.get(name="(System)")
    e = add_state_change_event(doc,
                               system,
                               prev_state,
                               new_state,
                               prev_tags=prev_tags,
                               new_tags=[])
    if e:
        doc.save_with_history([e])

    email_last_call_expired(doc)
Exemplo n.º 16
0
Arquivo: expire.py Projeto: ekr/ietfdb
def expire_draft(doc):
    # clean up files
    move_draft_files_to_archive(doc, doc.rev)

    system = Person.objects.get(name="(System)")

    events = []

    # change the state
    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=[])
            if e:
                events.append(e)

    events.append(DocEvent.objects.create(doc=doc, rev=doc.rev, by=system, type="expired_document", desc="Document has expired"))

    doc.set_state(State.objects.get(used=True, type="draft", slug="expired"))
    doc.save_with_history(events)
Exemplo n.º 17
0
def update_drafts_from_queue(drafts):
    tag_mapping = {
        'IANA': DocTagName.objects.get(slug='iana'),
        'REF': DocTagName.objects.get(slug='ref')
    }

    slookup = dict((s.slug, s) for s in State.objects.filter(
        used=True, type=StateType.objects.get(slug="draft-rfceditor")))
    state_mapping = {
        'AUTH': slookup['auth'],
        'AUTH48': slookup['auth48'],
        'AUTH48-DONE': slookup['auth48-done'],
        'EDIT': slookup['edit'],
        'IANA': slookup['iana'],
        'IESG': slookup['iesg'],
        'ISR': slookup['isr'],
        'ISR-AUTH': slookup['isr-auth'],
        'REF': slookup['ref'],
        'RFC-EDITOR': slookup['rfc-edit'],
        'TO': slookup['timeout'],
        'MISSREF': slookup['missref'],
    }

    system = Person.objects.get(name="(System)")

    warnings = []

    names = [t[0] for t in drafts]

    drafts_in_db = dict(
        (d.name, d) for d in Document.objects.filter(type="draft",
                                                     docalias__name__in=names))

    changed = set()

    for name, date_received, state, tags, missref_generation, stream, auth48, cluster, refs in drafts:
        if name not in drafts_in_db:
            warnings.append("unknown document %s" % name)
            continue

        if not state or state not in state_mapping:
            warnings.append("unknown state '%s'" % state)
            continue

        d = drafts_in_db[name]

        prev_state = d.get_state("draft-rfceditor")
        next_state = state_mapping[state]

        # check if we've noted it's been received
        if d.get_state_slug(
                "draft-iesg"
        ) == "ann" and not prev_state and not d.latest_event(
                DocEvent, type="rfc_editor_received_announcement"):
            e = DocEvent(doc=d,
                         by=system,
                         type="rfc_editor_received_announcement")
            e.desc = "Announcement was received by RFC Editor"
            e.save()
            send_mail_text(
                None, "*****@*****.**", None,
                '%s in RFC Editor queue' % d.name,
                'The announcement for %s has been received by the RFC Editor.'
                % d.name)

        if prev_state != next_state:
            save_document_in_history(d)

            d.set_state(next_state)

            e = add_state_change_event(d, system, prev_state, next_state)

            if auth48:
                e.desc = re.sub(r"(<b>.*</b>)",
                                "<a href=\"%s\">\\1</a>" % auth48, e.desc)
                e.save()

            changed.add(name)

        t = DocTagName.objects.filter(slug__in=tags)
        if set(t) != set(d.tags.all()):
            d.tags = t
            changed.add(name)

    # remove tags and states for those not in the queue anymore
    for d in Document.objects.exclude(docalias__name__in=names).filter(
            states__type="draft-rfceditor").distinct():
        d.tags.remove(*tag_mapping.values())
        d.unset_state("draft-rfceditor")
        # we do not add a history entry here - most likely we already
        # have something that explains what happened
        changed.add(name)

    return changed, warnings
Exemplo n.º 18
0
def change_state(request, name, option=None):
    """Change state of an status-change document, notifying parties as necessary
       and logging the change as a comment."""
    status_change = get_object_or_404(Document, type="statchg", name=name)

    login = request.user.person

    if request.method == 'POST':
        form = ChangeStateForm(request.POST)
        if form.is_valid():
            clean = form.cleaned_data
            new_state = clean['new_state']
            comment = clean['comment'].rstrip()

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

            prev_state = status_change.get_state()
            if new_state != prev_state:
                save_document_in_history(status_change)

                status_change.set_state(new_state)
                e = add_state_change_event(status_change, login, prev_state, new_state)

                status_change.time = e.time
                status_change.save()

                if new_state.slug == "iesgeval":
                    create_ballot_if_not_open(status_change, login, "statchg", e.time)
                    ballot = status_change.latest_event(BallotDocEvent, type="created_ballot")
                    if has_role(request.user, "Area Director") and not status_change.latest_event(BallotPositionDocEvent, ad=login, ballot=ballot, type="changed_ballot_position"):

                        # The AD putting a status change into iesgeval who doesn't already have a position is saying "yes"
                        pos = BallotPositionDocEvent(doc=status_change, by=login)
                        pos.ballot = ballot
                        pos.type = "changed_ballot_position"
                        pos.ad = login
                        pos.pos_id = "yes"
                        pos.desc = "[Ballot Position Update] New position, %s, has been recorded for %s" % (pos.pos.name, pos.ad.plain_name())
                        pos.save()

                    send_status_change_eval_email(request,status_change)


                if new_state.slug == "lc-req":
                    request_last_call(request, status_change)
                    return render_to_response('doc/draft/last_call_requested.html',
                                              dict(doc=status_change,
                                                   url = status_change.get_absolute_url(),
                                                  ),
                                              context_instance=RequestContext(request))

            return redirect('doc_view', name=status_change.name)
    else:
        s = status_change.get_state()
        init = dict(new_state=s.pk if s else None,
                    type='statchg',
                    label='Status Change Evaluation State',
                   )
        form = ChangeStateForm(initial=init)

    return render_to_response('doc/change_state.html',
                              dict(form=form,
                                   doc=status_change,
                                   login=login,
                                   help_url=reverse('state_help', kwargs=dict(type="status-change")),
                                   ),
                              context_instance=RequestContext(request))
Exemplo n.º 19
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():

            save_document_in_history(status_change)

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

            status_change.set_state(new_state)
            add_state_change_event(status_change, login, prev_state, new_state)

            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=STATUSCHANGE_RELATIONS):
                # 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=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_to_response('doc/status_change/approve.html',
                              dict(
                                   doc = status_change,
                                   formset = formset,
                                   ),
                              context_instance=RequestContext(request))
Exemplo n.º 20
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))
Exemplo n.º 21
0
def make_last_call(request, name):
    """Make last call for Internet Draft, sending out announcement."""
    doc = get_object_or_404(Document, docalias__name=name)
    if not (doc.get_state("draft-iesg") or doc.get_state("statchg")):
        raise Http404

    login = request.user.person

    e = doc.latest_event(WriteupDocEvent, type="changed_last_call_text")
    if not e:
        if doc.type.slug != 'draft':
            raise Http404
        e = generate_last_call_announcement(request, doc)
    announcement = e.text

    if request.method == 'POST':
        form = MakeLastCallForm(request.POST)
        if form.is_valid():
            send_mail_preformatted(request, announcement)
            if doc.type.slug == 'draft':
                send_mail_preformatted(request, announcement, extra=extra_automation_headers(doc),
                                       override={ "To": "IANA <*****@*****.**>", "CC": None, "Bcc": None, "Reply-To": None})

            msg = infer_message(announcement)
            msg.by = login
            msg.save()
            msg.related_docs.add(doc)

            save_document_in_history(doc)

            new_state = doc.get_state()
            prev_tags = new_tags = []

            if doc.type.slug == 'draft':
                new_state = State.objects.get(used=True, type="draft-iesg", slug='lc')
                prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
            elif doc.type.slug == 'statchg':
                new_state = State.objects.get(used=True, type="statchg", slug='in-lc')

            prev_state = doc.get_state(new_state.type_id)

            doc.set_state(new_state)
            doc.tags.remove(*prev_tags)

            e = add_state_change_event(doc, login, prev_state, new_state, prev_tags=prev_tags, new_tags=new_tags)

            doc.time = (e and e.time) or datetime.datetime.now()
            doc.save()

            change_description = "Last call has been made for %s and state has been changed to %s" % (doc.name, new_state.name)

            email_state_changed(request, doc, change_description)
            email_ad(request, doc, doc.ad, login, change_description)
            
            e = LastCallDocEvent(doc=doc, by=login)
            e.type = "sent_last_call"
            e.desc = "The following Last Call announcement was sent out:<br><br>"
            e.desc += announcement

            if form.cleaned_data['last_call_sent_date'] != e.time.date():
                e.time = datetime.datetime.combine(form.cleaned_data['last_call_sent_date'], e.time.time())
            e.expires = form.cleaned_data['last_call_expiration_date']
            e.save()

            # update IANA Review state
            if doc.type.slug == 'draft':
                prev_state = doc.get_state("draft-iana-review")
                if not prev_state:
                    next_state = State.objects.get(used=True, type="draft-iana-review", slug="need-rev")
                    doc.set_state(next_state)
                    add_state_change_event(doc, login, prev_state, next_state)

            return HttpResponseRedirect(doc.get_absolute_url())
    else:
        initial = {}
        initial["last_call_sent_date"] = datetime.date.today()
        if doc.type.slug == 'draft':
            # This logic is repeated in the code that edits last call text - why?
            expire_days = 14
            if doc.group.type_id in ("individ", "area"):
                expire_days = 28
            templ = 'doc/draft/make_last_call.html'
        else:
            expire_days=28
            templ = 'doc/status_change/make_last_call.html'

        initial["last_call_expiration_date"] = datetime.date.today() + datetime.timedelta(days=expire_days)
        
        form = MakeLastCallForm(initial=initial)
  
    return render_to_response(templ,
                              dict(doc=doc,
                                   form=form,
                                   announcement=announcement,
                                  ),
                              context_instance=RequestContext(request))
Exemplo n.º 22
0
def edit_material(request, name=None, acronym=None, action=None, doc_type=None):
    # the materials process is not very developed, so at the moment we
    # handle everything through the same view/form

    if action == "new":
        group = get_object_or_404(Group, acronym=acronym)
        if not group.features.has_materials:
            raise Http404

        doc = None
        document_type = get_object_or_404(DocTypeName, slug=doc_type)
    else:
        doc = get_object_or_404(Document, name=name)
        group = doc.group
        document_type = doc.type

    if not can_manage_materials(request.user, group):
        return HttpResponseForbidden("You don't have permission to access this view")

    if request.method == 'POST':
        form = UploadMaterialForm(document_type, action, group, doc, request.POST, request.FILES)

        if form.is_valid():
            if action == "new":
                doc = Document()
                doc.type = document_type
                doc.group = group
                doc.rev = "00"
                doc.name = form.cleaned_data["name"]
                prev_rev = None
            else:
                save_document_in_history(doc)
                prev_rev = doc.rev

            prev_title = doc.title
            prev_state = doc.get_state()

            if "title" in form.cleaned_data:
                doc.title = form.cleaned_data["title"]

            if "abstract" in form.cleaned_data:
                doc.abstract = form.cleaned_data["abstract"]

            doc.time = datetime.datetime.now()

            if "material" in form.fields:
                if action != "new":
                    doc.rev = "%02d" % (int(doc.rev) + 1)

                f = form.cleaned_data["material"]
                file_ext = os.path.splitext(f.name)[1]

                with open(os.path.join(doc.get_file_path(), doc.name + "-" + doc.rev + file_ext), 'wb+') as dest:
                    for chunk in f.chunks():
                        dest.write(chunk)

            doc.save()

            if action == "new":
                DocAlias.objects.get_or_create(name=doc.name, document=doc)

            if prev_rev != doc.rev:
                e = NewRevisionDocEvent(type="new_revision", doc=doc, rev=doc.rev)
                e.time = doc.time
                e.by = request.user.person
                e.desc = "New version available: <b>%s-%s</b>" % (doc.name, doc.rev)
                e.save()
                
            if prev_title != doc.title:
                e = DocEvent(doc=doc, by=request.user.person, type='changed_document')
                e.desc = u"Changed title to <b>%s</b>" % doc.title
                if prev_title:
                    e.desc += u" from %s" % prev_title
                e.time = doc.time
                e.save()

            if "state" in form.cleaned_data and form.cleaned_data["state"] != prev_state:
                doc.set_state(form.cleaned_data["state"])
                add_state_change_event(doc, request.user.person, prev_state, form.cleaned_data["state"])

            return redirect("doc_view", name=doc.name)
    else:
        form = UploadMaterialForm(document_type, action, group, doc)

    return render(request, 'doc/material/edit_material.html', {
        'group': group,
        'form': form,
        'action': action,
        'document_type': document_type,
        'doc_name': doc.name if doc else "",
    })
Exemplo n.º 23
0
def change_state(request, name, option=None):
    """Change state of an status-change document, notifying parties as necessary
       and logging the change as a comment."""
    status_change = get_object_or_404(Document, type="statchg", name=name)

    login = request.user.person

    if request.method == 'POST':
        form = ChangeStateForm(request.POST)
        if form.is_valid():
            clean = form.cleaned_data
            new_state = clean['new_state']
            comment = clean['comment'].rstrip()

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

            prev_state = status_change.get_state()
            if new_state != prev_state:
                status_change.set_state(new_state)
                events = []
                events.append(
                    add_state_change_event(status_change, login, prev_state,
                                           new_state))
                status_change.save_with_history(events)

                if new_state.slug == "iesgeval":
                    create_ballot_if_not_open(status_change, login, "statchg",
                                              status_change.time)
                    ballot = status_change.latest_event(BallotDocEvent,
                                                        type="created_ballot")
                    if has_role(request.user, "Area Director"
                                ) and not status_change.latest_event(
                                    BallotPositionDocEvent,
                                    ad=login,
                                    ballot=ballot,
                                    type="changed_ballot_position"):

                        # The AD putting a status change into iesgeval who doesn't already have a position is saying "yes"
                        pos = BallotPositionDocEvent(doc=status_change,
                                                     rev=status_change.rev,
                                                     by=login)
                        pos.ballot = ballot
                        pos.type = "changed_ballot_position"
                        pos.ad = login
                        pos.pos_id = "yes"
                        pos.desc = "[Ballot Position Update] New position, %s, has been recorded for %s" % (
                            pos.pos.name, pos.ad.plain_name())
                        pos.save()

                    send_status_change_eval_email(request, status_change)

                if new_state.slug == "lc-req":
                    request_last_call(request, status_change)
                    return render(
                        request, 'doc/draft/last_call_requested.html',
                        dict(
                            doc=status_change,
                            url=status_change.get_absolute_url(),
                        ))

            return redirect('ietf.doc.views_doc.document_main',
                            name=status_change.name)
    else:
        s = status_change.get_state()
        init = dict(
            new_state=s.pk if s else None,
            type='statchg',
            label='Status Change Evaluation State',
        )
        form = ChangeStateForm(initial=init)

    return render(
        request, 'doc/change_state.html',
        dict(
            form=form,
            doc=status_change,
            login=login,
            help_url=reverse('ietf.doc.views_help.state_help',
                             kwargs=dict(type="status-change")),
        ))
Exemplo n.º 24
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))
Exemplo n.º 25
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))
Exemplo n.º 26
0
def post_submission(request, submission):
    system = Person.objects.get(name="(System)")

    try:
        draft = Document.objects.get(name=submission.name)
        save_document_in_history(draft)
    except Document.DoesNotExist:
        draft = Document(name=submission.name)
        draft.intended_std_level = None

    prev_rev = draft.rev

    draft.type_id = "draft"
    draft.time = datetime.datetime.now()
    draft.title = submission.title
    group = submission.group or Group.objects.get(type="individ")
    if not (group.type_id == "individ" and draft.group and draft.group.type_id == "area"):
        # don't overwrite an assigned area if it's still an individual
        # submission
        draft.group_id = group.pk
    draft.rev = submission.rev
    draft.pages = submission.pages
    draft.abstract = submission.abstract
    was_rfc = draft.get_state_slug() == "rfc"

    if not draft.stream:
        stream_slug = None
        if draft.name.startswith("draft-iab-"):
            stream_slug = "iab"
        elif draft.name.startswith("draft-irtf-"):
            stream_slug = "irtf"
        elif draft.name.startswith("draft-ietf-") and (draft.group.type_id != "individ" or was_rfc):
            stream_slug = "ietf"

        if stream_slug:
            draft.stream = StreamName.objects.get(slug=stream_slug)

    draft.expires = datetime.datetime.now() + datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
    draft.save()

    submitter_parsed = submission.submitter_parsed()
    if submitter_parsed["name"] and submitter_parsed["email"]:
        submitter = ensure_person_email_info_exists(submitter_parsed["name"], submitter_parsed["email"]).person
        submitter_info = u'%s <%s>' % (submitter_parsed["name"], submitter_parsed["email"])
    else:
        submitter = system
        submitter_info = system.name

    draft.set_state(State.objects.get(used=True, type="draft", slug="active"))
    DocAlias.objects.get_or_create(name=submission.name, document=draft)

    update_authors(draft, submission)

    trouble = rebuild_reference_relations(draft, filename=os.path.join(settings.IDSUBMIT_STAGING_PATH, '%s-%s.txt' % (submission.name, submission.rev)))
    if trouble:
        log('Rebuild_reference_relations trouble: %s'%trouble)

    # new revision event
    e = NewRevisionDocEvent(type="new_revision", doc=draft, rev=draft.rev)
    e.time = draft.time #submission.submission_date
    e.by = submitter
    e.desc = "New version available: <b>%s-%s.txt</b>" % (draft.name, draft.rev)
    e.save()

    if draft.stream_id == "ietf" and draft.group.type_id == "wg" and draft.rev == "00":
        # automatically set state "WG Document"
        draft.set_state(State.objects.get(used=True, type="draft-stream-%s" % draft.stream_id, slug="wg-doc"))

    if draft.get_state_slug("draft-iana-review") in ("ok-act", "ok-noact", "not-ok"):
        prev_state = draft.get_state("draft-iana-review")
        next_state = State.objects.get(used=True, type="draft-iana-review", slug="changed")
        draft.set_state(next_state)
        add_state_change_event(draft, submitter, prev_state, next_state)

    # clean up old files
    if prev_rev != draft.rev:
        from ietf.doc.expire import move_draft_files_to_archive
        move_draft_files_to_archive(draft, prev_rev)

    # automatic state changes
    state_change_msg = ""

    if not was_rfc and draft.tags.filter(slug="need-rev"):
        draft.tags.remove("need-rev")
        draft.tags.add("ad-f-up")

        e = DocEvent(type="changed_document", doc=draft)
        e.desc = "Sub state has been changed to <b>AD Followup</b> from <b>Revised ID Needed</b>"
        e.by = system
        e.save()

        state_change_msg = e.desc

    move_files_to_repository(submission)
    submission.state = DraftSubmissionStateName.objects.get(slug="posted")

    new_replaces, new_possibly_replaces = update_replaces_from_submission(request, submission, draft)

    announce_to_lists(request, submission)
    announce_new_version(request, submission, draft, state_change_msg)
    announce_to_authors(request, submission)

    if new_possibly_replaces:
        send_review_possibly_replaces_request(request, draft, submitter_info)

    submission.save()
Exemplo n.º 27
0
def doc_detail(request, date, name):
    '''
    This view displays the ballot information for the document, and lets the user make
    changes to ballot positions and document state.
    '''
    doc = get_object_or_404(Document, docalias__name=name)

    # As of Datatracker v4.32, Conflict Review (conflrev) Document Types can
    # be added to the Telechat agenda.  If Document.type_id == draft use draft-iesg
    # for state type
    state_type = doc.type_id
    if doc.type_id == 'draft':
        state_type = 'draft-iesg'

    login = request.user.person

    if doc.active_ballot():
        ballots = doc.active_ballot().active_ad_positions()  # returns dict of ad:ballotpositiondocevent
    else:
        ballots = []

    # setup form initials
    initial_ballot = []
    open_positions = 0
    for key in sorted(ballots, key = lambda a: a.name_parts()[3]):
        initial_ballot.append({'name':key.name,'id':key.id,'position':ballots[key].pos.slug if ballots[key] else None})
        if ballots[key] and ballots[key].pos.slug == 'norecord':
            open_positions += 1
        elif not ballots[key]:
            open_positions += 1

    tags = doc.tags.filter(slug__in=TELECHAT_TAGS)
    tag = tags[0].pk if tags else None

    writeup = get_doc_writeup(doc)

    initial_state = {'state':doc.get_state(state_type).pk,
                     'substate':tag}

    BallotFormset = formset_factory(BallotForm, extra=0)
    agenda = agenda_data(date=date)
    header = get_section_header(doc, agenda)

    # nav button logic
    doc_list = get_doc_list(agenda)
    nav_start = nav_end = False
    if doc == doc_list[0]:
        nav_start = True
    if doc == doc_list[-1]:
        nav_end = True

    if request.method == 'POST':
        button_text = request.POST.get('submit', '')

        # logic from doc/views_ballot.py EditPosition
        if button_text == 'update_ballot':
            formset = BallotFormset(request.POST, initial=initial_ballot)
            state_form = ChangeStateForm(initial=initial_state)
            has_changed = False
            for form in formset.forms:
                if form.is_valid() and form.changed_data:
                    # create new BallotPositionDocEvent
                    clean = form.cleaned_data
                    ad = Person.objects.get(id=clean['id'])
                    pos = BallotPositionDocEvent(doc=doc,by=login)
                    pos.type = "changed_ballot_position"
                    pos.ad = ad
                    pos.ballot = doc.latest_event(BallotDocEvent, type="created_ballot")
                    pos.pos = clean['position']
                    if form.initial['position'] == None:
                        pos.desc = '[Ballot Position Update] New position, %s, has been recorded for %s by %s' % (pos.pos.name, ad.name, login.name)
                    else:
                        pos.desc = '[Ballot Position Update] Position for %s has been changed to %s by %s' % (ad.name, pos.pos.name, login.name)
                    pos.save()
                    has_changed = True

            if has_changed:
                messages.success(request,'Ballot position changed.')
            return redirect('telechat_doc_detail', date=date, name=name)

        # logic from doc/views_draft.py change_state
        elif button_text == 'update_state':
            formset = BallotFormset(initial=initial_ballot)
            state_form = ChangeStateForm(request.POST, initial=initial_state)
            if state_form.is_valid():
                prev_state = doc.get_state(state_type)

                new_state = state_form.cleaned_data['state']
                tag = state_form.cleaned_data['substate']

                # tag handling is a bit awkward since the UI still works
                # as if IESG tags are a substate
                prev_tags = doc.tags.filter(slug__in=TELECHAT_TAGS)
                new_tags = [tag] if tag else []

                if state_form.changed_data:
                    save_document_in_history(doc)

                    if 'state' in state_form.changed_data:
                        doc.set_state(new_state)

                    if 'substate' in state_form.changed_data:
                        doc.tags.remove(*prev_tags)
                        doc.tags.add(*new_tags)

                    e = add_state_change_event(doc, login, prev_state, new_state,
                                               prev_tags=prev_tags, new_tags=new_tags)
                    doc.time = (e and e.time) or datetime.datetime.now()
                    doc.save()

                    email_state_changed(request, doc, e.desc, 'doc_state_edited')
    
                    if new_state.slug == "lc-req":
                        request_last_call(request, doc)

                messages.success(request,'Document state updated')
                return redirect('telechat_doc_detail', date=date, name=name)
    else:
        formset = BallotFormset(initial=initial_ballot)
        state_form = ChangeStateForm(initial=initial_state)

        # if this is a conflict review document add referenced document
        if doc.type_id == 'conflrev':
            conflictdoc = doc.relateddocument_set.get(relationship__slug='conflrev').target.document
        else:
            conflictdoc = None

    return render_to_response('telechat/doc.html', {
        'date': date,
        'document': doc,
        'conflictdoc': conflictdoc,
        'agenda': agenda,
        'formset': formset,
        'header': header,
        'open_positions': open_positions,
        'state_form': state_form,
        'writeup': writeup,
        'nav_start': nav_start,
        'nav_end': nav_end},
        RequestContext(request, {}),
    )
Exemplo n.º 28
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))
Exemplo n.º 29
0
def last_call(request, name):
    """Edit the Last Call Text for this status change and possibly request IETF LC"""

    status_change = get_object_or_404(Document, type="statchg", name=name)

    login = request.user.person

    last_call_event = status_change.latest_event(WriteupDocEvent,
                                                 type="changed_last_call_text")
    if not last_call_event:
        last_call_event = generate_last_call_text(request, status_change)

    form = LastCallTextForm(initial=dict(last_call_text=last_call_event.text))

    if request.method == 'POST':
        if "save_last_call_text" in request.POST or "send_last_call_request" in request.POST:
            form = LastCallTextForm(request.POST)
            if form.is_valid():
                events = []

                t = form.cleaned_data['last_call_text']
                if t != last_call_event.text:
                    e = WriteupDocEvent(doc=status_change,
                                        rev=status_change.rev,
                                        by=login)
                    e.by = login
                    e.type = "changed_last_call_text"
                    e.desc = "Last call announcement was changed"
                    e.text = t
                    e.save()

                    events.append(e)

                if "send_last_call_request" in request.POST:
                    prev_state = status_change.get_state()
                    new_state = State.objects.get(type='statchg',
                                                  slug='lc-req')

                    status_change.set_state(new_state)
                    e = add_state_change_event(status_change, login,
                                               prev_state, new_state)
                    if e:
                        events.append(e)

                    if events:
                        status_change.save_with_history(events)

                    request_last_call(request, status_change)

                    return render(
                        request, 'doc/draft/last_call_requested.html',
                        dict(
                            doc=status_change,
                            url=status_change.get_absolute_url(),
                        ))

        if "regenerate_last_call_text" in request.POST:
            e = generate_last_call_text(request, status_change)
            form = LastCallTextForm(initial=dict(last_call_text=e.text))

    return render(
        request,
        'doc/status_change/last_call.html',
        dict(
            doc=status_change,
            back_url=status_change.get_absolute_url(),
            last_call_event=last_call_event,
            last_call_form=form,
        ),
    )
Exemplo n.º 30
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,
                  ))
Exemplo n.º 31
0
Arquivo: utils.py Projeto: mcr/ietfdb
def perform_postREDESIGN(request, submission):
    system = Person.objects.get(name="(System)")

    group_id = submission.group_acronym_id or NONE_WG
    try:
        draft = Document.objects.get(name=submission.filename)
        save_document_in_history(draft)
    except Document.DoesNotExist:
        draft = Document(name=submission.filename)
        draft.intended_std_level = None

    prev_rev = draft.rev

    draft.type_id = "draft"
    draft.time = datetime.datetime.now()
    draft.title = submission.id_document_name
    if not (group_id == NONE_WG and draft.group and draft.group.type_id == "area"):
        # don't overwrite an assigned area if it's still an individual
        # submission
        draft.group_id = group_id
    draft.rev = submission.revision
    draft.pages = submission.txt_page_count
    draft.abstract = submission.abstract
    was_rfc = draft.get_state_slug() == "rfc"

    if not draft.stream:
        stream_slug = None
        if draft.name.startswith("draft-iab-"):
            stream_slug = "iab"
        elif draft.name.startswith("draft-irtf-"):
            stream_slug = "irtf"
        elif draft.name.startswith("draft-ietf-") and (draft.group.type_id != "individ" or was_rfc):
            stream_slug = "ietf"

        if stream_slug:
            draft.stream = StreamName.objects.get(slug=stream_slug)

    draft.expires = datetime.datetime.now() + datetime.timedelta(settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
    draft.save()

    a = submission.tempidauthors_set.filter(author_order=0)
    if a:
        submitter = ensure_person_email_info_exists(a[0]).person
    else:
        submitter = system

    draft.set_state(State.objects.get(used=True, type="draft", slug="active"))
    DocAlias.objects.get_or_create(name=submission.filename, document=draft)

    update_authors(draft, submission)

    # new revision event
    e = NewRevisionDocEvent(type="new_revision", doc=draft, rev=draft.rev)
    e.time = draft.time #submission.submission_date
    e.by = submitter
    e.desc = "New version available: <b>%s-%s.txt</b>" % (draft.name, draft.rev)
    e.save()

    if draft.stream_id == "ietf" and draft.group.type_id == "wg" and draft.rev == "00":
        # automatically set state "WG Document"
        draft.set_state(State.objects.get(used=True, type="draft-stream-%s" % draft.stream_id, slug="wg-doc"))

    if draft.get_state_slug("draft-iana-review") in ("ok-act", "ok-noact", "not-ok"):
        prev_state = draft.get_state("draft-iana-review")
        next_state = State.objects.get(used=True, type="draft-iana-review", slug="changed")
        draft.set_state(next_state)
        add_state_change_event(draft, submitter, prev_state, next_state)

    # clean up old files
    if prev_rev != draft.rev:
        from ietf.idrfc.expire import move_draft_files_to_archive
        move_draft_files_to_archive(draft, prev_rev)

    # automatic state changes
    state_change_msg = ""

    if not was_rfc and draft.tags.filter(slug="need-rev"):
        draft.tags.remove("need-rev")
        draft.tags.add("ad-f-up")

        e = DocEvent(type="changed_document", doc=draft)
        e.desc = "Sub state has been changed to <b>AD Followup</b> from <b>Revised ID Needed</b>"
        e.by = system
        e.save()

        state_change_msg = e.desc

    move_docs(submission)
    submission.status_id = POSTED

    announce_to_lists(request, submission)
    announce_new_version(request, submission, draft, state_change_msg)
    announce_to_authors(request, submission)

    submission.save()
Exemplo n.º 32
0
def post_submission(request, submission, approvedDesc):
    system = Person.objects.get(name="(System)")
    submitter_parsed = submission.submitter_parsed()
    if submitter_parsed["name"] and submitter_parsed["email"]:
        submitter, _ = ensure_person_email_info_exists(
            submitter_parsed["name"], submitter_parsed["email"])
        submitter_info = u'%s <%s>' % (submitter_parsed["name"],
                                       submitter_parsed["email"])
    else:
        submitter = system
        submitter_info = system.name

    # update draft attributes
    try:
        draft = Document.objects.get(name=submission.name)
    except Document.DoesNotExist:
        draft = Document.objects.create(name=submission.name, type_id="draft")

    prev_rev = draft.rev

    draft.type_id = "draft"
    draft.title = submission.title
    group = submission.group or Group.objects.get(type="individ")
    if not (group.type_id == "individ" and draft.group
            and draft.group.type_id == "area"):
        # don't overwrite an assigned area if it's still an individual
        # submission
        draft.group = group
    draft.rev = submission.rev
    draft.pages = submission.pages
    draft.abstract = submission.abstract
    was_rfc = draft.get_state_slug() == "rfc"

    if not draft.stream:
        stream_slug = None
        if draft.name.startswith("draft-iab-"):
            stream_slug = "iab"
        elif draft.name.startswith("draft-irtf-"):
            stream_slug = "irtf"
        elif draft.name.startswith("draft-ietf-") and (
                draft.group.type_id != "individ" or was_rfc):
            stream_slug = "ietf"

        if stream_slug:
            draft.stream = StreamName.objects.get(slug=stream_slug)

    draft.expires = datetime.datetime.now() + datetime.timedelta(
        settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)

    events = []

    if draft.rev == '00':
        # Add all the previous submission events as docevents
        events += post_rev00_submission_events(draft, submission, submitter)

    # Add an approval docevent
    e = SubmissionDocEvent.objects.create(
        type="new_submission",
        doc=draft,
        by=system,
        desc=approvedDesc,
        submission=submission,
        rev=submission.rev,
    )
    events.append(e)

    # new revision event
    e = NewRevisionDocEvent.objects.create(
        type="new_revision",
        doc=draft,
        rev=draft.rev,
        by=submitter,
        desc="New version available: <b>%s-%s.txt</b>" %
        (draft.name, draft.rev),
    )
    events.append(e)

    # update related objects
    DocAlias.objects.get_or_create(name=submission.name, document=draft)

    draft.set_state(State.objects.get(used=True, type="draft", slug="active"))

    update_authors(draft, submission)

    draft.formal_languages = submission.formal_languages.all()

    trouble = rebuild_reference_relations(
        draft,
        filename=os.path.join(settings.IDSUBMIT_STAGING_PATH,
                              '%s-%s.txt' % (submission.name, submission.rev)))
    if trouble:
        log.log('Rebuild_reference_relations trouble: %s' % trouble)

    if draft.stream_id == "ietf" and draft.group.type_id == "wg" and draft.rev == "00":
        # automatically set state "WG Document"
        draft.set_state(
            State.objects.get(used=True,
                              type="draft-stream-%s" % draft.stream_id,
                              slug="wg-doc"))

    # automatic state changes for IANA review
    if draft.get_state_slug("draft-iana-review") in ("ok-act", "ok-noact",
                                                     "not-ok"):
        prev_state = draft.get_state("draft-iana-review")
        next_state = State.objects.get(used=True,
                                       type="draft-iana-review",
                                       slug="changed")
        draft.set_state(next_state)
        e = add_state_change_event(draft, system, prev_state, next_state)
        if e:
            events.append(e)

    state_change_msg = ""

    if not was_rfc and draft.tags.filter(slug="need-rev"):
        draft.tags.remove("need-rev")
        draft.tags.add("ad-f-up")

        e = DocEvent(type="changed_document", doc=draft, rev=draft.rev)
        e.desc = "Sub state has been changed to <b>AD Followup</b> from <b>Revised ID Needed</b>"
        e.by = system
        e.save()
        events.append(e)

        state_change_msg = e.desc

    if draft.stream_id == "ietf" and draft.group.type_id == "wg" and draft.rev == "00":
        # automatically set state "WG Document"
        draft.set_state(
            State.objects.get(used=True,
                              type="draft-stream-%s" % draft.stream_id,
                              slug="wg-doc"))

    # save history now that we're done with changes to the draft itself
    draft.save_with_history(events)

    # clean up old files
    if prev_rev != draft.rev:
        from ietf.doc.expire import move_draft_files_to_archive
        move_draft_files_to_archive(draft, prev_rev)

    move_files_to_repository(submission)
    submission.state = DraftSubmissionStateName.objects.get(slug="posted")

    new_replaces, new_possibly_replaces = update_replaces_from_submission(
        request, submission, draft)

    update_name_contains_indexes_with_new_doc(draft)

    announce_to_lists(request, submission)
    announce_new_version(request, submission, draft, state_change_msg)
    announce_to_authors(request, submission)

    if new_possibly_replaces:
        send_review_possibly_replaces_request(request, draft, submitter_info)

    submission.draft = draft
    submission.save()
Exemplo n.º 33
0
def edit_material(request,
                  name=None,
                  acronym=None,
                  action=None,
                  doc_type=None):
    # the materials process is not very developed, so at the moment we
    # handle everything through the same view/form

    if action == "new":
        group = get_object_or_404(Group, acronym=acronym)
        if not group.features.has_materials:
            raise Http404

        doc = None
        document_type = get_object_or_404(DocTypeName, slug=doc_type)
    else:
        doc = get_object_or_404(Document, name=name)
        group = doc.group
        document_type = doc.type

    if document_type not in DocTypeName.objects.filter(
            slug__in=group.features.material_types
    ) and document_type.slug not in [
            'minutes',
            'agenda',
            'bluesheets',
    ]:
        raise Http404

    if not can_manage_materials(request.user, group):
        return HttpResponseForbidden(
            "You don't have permission to access this view")

    if request.method == 'POST':
        form = UploadMaterialForm(document_type, action, group, doc,
                                  request.POST, request.FILES)

        if form.is_valid():
            events = []

            if action == "new":
                doc = Document.objects.create(type=document_type,
                                              group=group,
                                              rev="00",
                                              name=form.cleaned_data["name"])

                prev_rev = None
            else:
                prev_rev = doc.rev

            prev_title = doc.title
            prev_state = doc.get_state()
            prev_abstract = doc.abstract

            if "title" in form.cleaned_data:
                doc.title = form.cleaned_data["title"]

            if "abstract" in form.cleaned_data:
                doc.abstract = form.cleaned_data["abstract"]

            if "material" in form.fields:
                if action != "new":
                    doc.rev = "%02d" % (int(doc.rev) + 1)

                f = form.cleaned_data["material"]
                file_ext = os.path.splitext(f.name)[1]

                with open(
                        os.path.join(doc.get_file_path(),
                                     doc.name + "-" + doc.rev + file_ext),
                        'wb+') as dest:
                    for chunk in f.chunks():
                        dest.write(chunk)

            if action == "new":
                DocAlias.objects.get_or_create(name=doc.name, document=doc)

            if prev_rev != doc.rev:
                e = NewRevisionDocEvent(type="new_revision",
                                        doc=doc,
                                        rev=doc.rev)
                e.by = request.user.person
                e.desc = "New version available: <b>%s-%s</b>" % (doc.name,
                                                                  doc.rev)
                e.save()
                events.append(e)

            if prev_title != doc.title:
                e = DocEvent(doc=doc,
                             rev=doc.rev,
                             by=request.user.person,
                             type='changed_document')
                e.desc = u"Changed title to <b>%s</b>" % doc.title
                if prev_title:
                    e.desc += u" from %s" % prev_title
                e.save()
                events.append(e)

            if prev_abstract != doc.abstract:
                e = DocEvent(doc=doc,
                             rev=doc.rev,
                             by=request.user.person,
                             type='changed_document')
                e.desc = u"Changed abstract to <b>%s</b>" % doc.abstract
                if prev_abstract:
                    e.desc += u" from %s" % prev_abstract
                e.save()
                events.append(e)

            if "state" in form.cleaned_data and form.cleaned_data[
                    "state"] != prev_state:
                doc.set_state(form.cleaned_data["state"])
                e = add_state_change_event(doc, request.user.person,
                                           prev_state,
                                           form.cleaned_data["state"])
                events.append(e)

            if events:
                doc.save_with_history(events)

            return redirect("ietf.doc.views_doc.document_main", name=doc.name)
    else:
        form = UploadMaterialForm(document_type, action, group, doc)

    return render(
        request, 'doc/material/edit_material.html', {
            'group': group,
            'form': form,
            'action': action,
            'document_type': document_type,
            'doc_name': doc.name if doc else "",
        })
Exemplo n.º 34
0
def lastcalltext(request, name):
    """Editing of the last call text"""
    doc = get_object_or_404(Document, docalias__name=name)
    if not doc.get_state("draft-iesg"):
        raise Http404()

    login = request.user.person

    existing = doc.latest_event(WriteupDocEvent, type="changed_last_call_text")
    if not existing:
        existing = generate_last_call_announcement(request, doc)
        
    form = LastCallTextForm(initial=dict(last_call_text=existing.text))

    if request.method == 'POST':
        if "save_last_call_text" in request.POST or "send_last_call_request" in request.POST:
            form = LastCallTextForm(request.POST)
            if form.is_valid():
                t = form.cleaned_data['last_call_text']
                if t != existing.text:
                    e = WriteupDocEvent(doc=doc, by=login)
                    e.by = login
                    e.type = "changed_last_call_text"
                    e.desc = "Last call announcement was changed"
                    e.text = t
                    e.save()
                
                if "send_last_call_request" in request.POST:
                    save_document_in_history(doc)

                    prev_state = doc.get_state("draft-iesg")
                    new_state = State.objects.get(used=True, type="draft-iesg", slug='lc-req')

                    prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)

                    doc.set_state(new_state)
                    doc.tags.remove(*prev_tags)

                    e = add_state_change_event(doc, login, prev_state, new_state, prev_tags=prev_tags, new_tags=[])

                    doc.time = (e and e.time) or datetime.datetime.now()
                    doc.save()

                    email_state_changed(request, doc, e.desc)
                    email_ad(request, doc, doc.ad, login, e.desc)

                    request_last_call(request, doc)
                    
                    return render_to_response('doc/draft/last_call_requested.html',
                                              dict(doc=doc),
                                              context_instance=RequestContext(request))
        
        if "regenerate_last_call_text" in request.POST:
            e = generate_last_call_announcement(request, doc)
            
            # make sure form has the updated text
            form = LastCallTextForm(initial=dict(last_call_text=e.text))


    s = doc.get_state("draft-iesg")
    can_request_last_call = s.order < 27
    can_make_last_call = s.order < 20
    
    need_intended_status = ""
    if not doc.intended_std_level:
        need_intended_status = doc.file_tag()

    return render_to_response('doc/ballot/lastcalltext.html',
                              dict(doc=doc,
                                   back_url=doc.get_absolute_url(),
                                   last_call_form=form,
                                   can_request_last_call=can_request_last_call,
                                   can_make_last_call=can_make_last_call,
                                   need_intended_status=need_intended_status,
                                   ),
                              context_instance=RequestContext(request))
Exemplo n.º 35
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))
Exemplo n.º 36
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)),
        ))
Exemplo n.º 37
0
def defer_ballot(request, name):
    """Signal post-pone of ballot, notifying relevant parties."""
    doc = get_object_or_404(Document, docalias__name=name)
    if doc.type_id not in ('draft', 'conflrev', 'statchg'):
        raise Http404
    interesting_state = dict(draft='draft-iesg',
                             conflrev='conflrev',
                             statchg='statchg')
    state = doc.get_state(interesting_state[doc.type_id])
    if not state or state.slug == 'defer' or not doc.telechat_date():
        raise Http404

    login = request.user.person
    telechat_date = TelechatDate.objects.active().order_by("date")[1].date

    if request.method == 'POST':
        new_state = doc.get_state()
        prev_tags = []
        new_tags = []

        if doc.type_id == 'draft':
            new_state = State.objects.get(used=True,
                                          type="draft-iesg",
                                          slug='defer')
            prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
        elif doc.type_id in ['conflrev', 'statchg']:
            new_state = State.objects.get(used=True,
                                          type=doc.type_id,
                                          slug='defer')

        prev_state = doc.get_state(new_state.type_id if new_state else None)

        doc.set_state(new_state)
        doc.tags.remove(*prev_tags)

        events = []

        state_change_event = add_state_change_event(doc,
                                                    login,
                                                    prev_state,
                                                    new_state,
                                                    prev_tags=prev_tags,
                                                    new_tags=new_tags)
        if state_change_event:
            events.append(state_change_event)

        e = update_telechat(request, doc, login, telechat_date)
        if e:
            events.append(e)

        doc.save_with_history(events)

        email_ballot_deferred(request, doc, login.plain_name(), telechat_date)

        return HttpResponseRedirect(doc.get_absolute_url())

    return render(
        request, 'doc/ballot/defer_ballot.html',
        dict(doc=doc,
             telechat_date=telechat_date,
             back_url=doc.get_absolute_url()))
Exemplo n.º 38
0
Arquivo: iana.py Projeto: mcr/ietfdb
def update_history_with_changes(changes, send_email=True):
    """Take parsed changes from IANA and apply them. Note that we
    expect to get these chronologically sorted, otherwise the change
    descriptions generated may not be right."""

    # build up state lookup
    states = {}

    slookup = dict((s.slug, s)
                   for s in State.objects.filter(used=True, type=StateType.objects.get(slug="draft-iana-action")))
    states["action"] = {
        "": slookup["newdoc"],
        "In Progress": slookup["inprog"],
        "Open": slookup["inprog"],
        "pre-approval In Progress": slookup["inprog"],
        "Waiting on Authors": slookup["waitauth"],
        "Author": slookup["waitauth"],
        "Waiting on ADs": slookup["waitad"],
        "Waiting on AD": slookup["waitad"],
        "AD": slookup["waitad"],
        "Waiting on WGC": slookup["waitwgc"],
        "WGC": slookup["waitwgc"],
        "Waiting on RFC-Editor": slookup["waitrfc"],
        "Waiting on RFC Editor": slookup["waitrfc"],
        "RFC-Editor": slookup["waitrfc"],
        "RFC-Ed-ACK": slookup["rfcedack"],
        "RFC-Editor-ACK": slookup["rfcedack"],
        "Completed": slookup["rfcedack"],
        "On Hold": slookup["onhold"],
        "No IC": slookup["noic"],
    }

    slookup = dict((s.slug, s)
                  for s in State.objects.filter(used=True, type=StateType.objects.get(slug="draft-iana-review")))
    states["review"] = {
        "IANA Review Needed": slookup["need-rev"],
        "IANA - Review Needed": slookup["need-rev"],
        "IANA OK - Actions Needed": slookup["ok-act"],
        "IANA OK - No Actions Needed": slookup["ok-noact"],
        "IANA Not OK": slookup["not-ok"],
        "IANA - Not OK": slookup["not-ok"],
        "Version Changed - Review Needed": slookup["changed"],
        }

    # so it turns out IANA has made a mistake and are including some
    # wrong states, we'll have to skip those
    wrong_action_states = ("Waiting on Reviewer", "Review Complete", "Last Call",
                           "Last Call - Questions", "Evaluation", "Evaluation -  Questions",
                           "With Reviewer", "IESG Notification Received", "Watiing on Last Call",
                           "IANA Comments Submitted", "Waiting on Last Call")

    system = Person.objects.get(name="(System)")

    added_events = []
    warnings = []

    for c in changes:
        docname = c['doc']
        timestamp = datetime.datetime.strptime(c["time"], "%Y-%m-%d %H:%M:%S")
        timestamp = utc_to_local_timezone(timestamp) # timestamps are in UTC

        if c['type'] in ("iana_state", "iana_review"):
            if c['type'] == "iana_state":
                kind = "action"

                if c["state"] in wrong_action_states:
                    warnings.append("Wrong action state '%s' encountered in changes from IANA" % c["state"])
                    continue
            else:
                kind = "review"

            if c["state"] not in states[kind]:
                warnings.append("Unknown IANA %s state %s (%s)" % (kind, c["state"], timestamp))
                continue

            state = states[kind][c["state"]]
            state_type = "draft-iana-%s" % kind

            if state.slug in ("need-rev", "changed"):
                # the Datatracker is the ultimate source of these
                # states, so skip them
                continue

            e = StateDocEvent.objects.filter(type="changed_state", time=timestamp,
                                             state_type=state_type, state=state)
            if not e:
                try:
                    doc = Document.objects.get(docalias__name=docname)
                except Document.DoesNotExist:
                    warnings.append("Document %s not found" % docname)
                    continue

                # the naive way of extracting prev_state here means
                # that we assume these changes are cronologically
                # applied
                prev_state = doc.get_state(state_type)
                e = add_state_change_event(doc, system, prev_state, state, timestamp)

                if e:
                    # for logging purposes
                    e.json = c
                    added_events.append(e)

                if not StateDocEvent.objects.filter(doc=doc, time__gt=timestamp, state_type=state_type):
                    save_document_in_history(doc)
                    doc.set_state(state)

                    if send_email and (state != prev_state):
                        email_state_changed(None, doc, "IANA %s state changed to %s" % (kind, state.name))
                        email_owner(None, doc, doc.ad, system, "IANA %s state changed to %s" % (kind, state.name))

                if doc.time < timestamp:
                    doc.time = timestamp
                    doc.save()

    return added_events, warnings
Exemplo n.º 39
0
def lastcalltext(request, name):
    """Editing of the last call text"""
    doc = get_object_or_404(Document, docalias__name=name)
    if not doc.get_state("draft-iesg"):
        raise Http404

    login = request.user.person

    existing = doc.latest_event(WriteupDocEvent, type="changed_last_call_text")
    if not existing:
        existing = generate_last_call_announcement(request, doc)

    form = LastCallTextForm(initial=dict(last_call_text=existing.text))

    if request.method == 'POST':
        if "save_last_call_text" in request.POST or "send_last_call_request" in request.POST:
            form = LastCallTextForm(request.POST)
            if form.is_valid():
                t = form.cleaned_data['last_call_text']
                if t != existing.text:
                    e = WriteupDocEvent(doc=doc, rev=doc.rev, by=login)
                    e.by = login
                    e.type = "changed_last_call_text"
                    e.desc = "Last call announcement was changed"
                    e.text = t
                    e.save()
                elif existing.pk == None:
                    existing.save()

                if "send_last_call_request" in request.POST:
                    prev_state = doc.get_state("draft-iesg")
                    new_state = State.objects.get(used=True,
                                                  type="draft-iesg",
                                                  slug='lc-req')

                    prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)

                    doc.set_state(new_state)
                    doc.tags.remove(*prev_tags)

                    e = add_state_change_event(doc,
                                               login,
                                               prev_state,
                                               new_state,
                                               prev_tags=prev_tags,
                                               new_tags=[])

                    if e:
                        doc.save_with_history([e])

                    request_last_call(request, doc)

                    return render(request,
                                  'doc/draft/last_call_requested.html',
                                  dict(doc=doc))

        if "regenerate_last_call_text" in request.POST:
            e = generate_last_call_announcement(request, doc)
            e.save()

            # make sure form has the updated text
            form = LastCallTextForm(initial=dict(last_call_text=e.text))

    s = doc.get_state("draft-iesg")
    can_request_last_call = s.order < 27
    can_make_last_call = s.order < 20

    need_intended_status = ""
    if not doc.intended_std_level:
        need_intended_status = doc.file_tag()

    return render(
        request, 'doc/ballot/lastcalltext.html',
        dict(
            doc=doc,
            back_url=doc.get_absolute_url(),
            last_call_form=form,
            can_request_last_call=can_request_last_call,
            can_make_last_call=can_make_last_call,
            need_intended_status=need_intended_status,
        ))
Exemplo n.º 40
0
def perform_postREDESIGN(request, submission):
    system = Person.objects.get(name="(System)")

    group_id = submission.group_acronym_id or NONE_WG
    try:
        draft = Document.objects.get(name=submission.filename)
        save_document_in_history(draft)
    except Document.DoesNotExist:
        draft = Document(name=submission.filename)
        draft.intended_std_level = None

    prev_rev = draft.rev

    draft.type_id = "draft"
    draft.time = datetime.datetime.now()
    draft.title = submission.id_document_name
    if not (group_id == NONE_WG and draft.group
            and draft.group.type_id == "area"):
        # don't overwrite an assigned area if it's still an individual
        # submission
        draft.group_id = group_id
    draft.rev = submission.revision
    draft.pages = submission.txt_page_count
    draft.abstract = submission.abstract
    was_rfc = draft.get_state_slug() == "rfc"

    if not draft.stream:
        stream_slug = None
        if draft.name.startswith("draft-iab-"):
            stream_slug = "iab"
        elif draft.name.startswith("draft-irtf-"):
            stream_slug = "irtf"
        elif draft.name.startswith("draft-ietf-") and (
                draft.group.type_id != "individ" or was_rfc):
            stream_slug = "ietf"

        if stream_slug:
            draft.stream = StreamName.objects.get(slug=stream_slug)

    draft.expires = datetime.datetime.now() + datetime.timedelta(
        settings.INTERNET_DRAFT_DAYS_TO_EXPIRE)
    draft.save()

    a = submission.tempidauthors_set.filter(author_order=0)
    if a:
        submitter = ensure_person_email_info_exists(a[0]).person
    else:
        submitter = system

    draft.set_state(State.objects.get(used=True, type="draft", slug="active"))
    DocAlias.objects.get_or_create(name=submission.filename, document=draft)

    update_authors(draft, submission)

    # new revision event
    e = NewRevisionDocEvent(type="new_revision", doc=draft, rev=draft.rev)
    e.time = draft.time  #submission.submission_date
    e.by = submitter
    e.desc = "New version available: <b>%s-%s.txt</b>" % (draft.name,
                                                          draft.rev)
    e.save()

    if draft.stream_id == "ietf" and draft.group.type_id == "wg" and draft.rev == "00":
        # automatically set state "WG Document"
        draft.set_state(
            State.objects.get(used=True,
                              type="draft-stream-%s" % draft.stream_id,
                              slug="wg-doc"))

    if draft.get_state_slug("draft-iana-review") in ("ok-act", "ok-noact",
                                                     "not-ok"):
        prev_state = draft.get_state("draft-iana-review")
        next_state = State.objects.get(used=True,
                                       type="draft-iana-review",
                                       slug="changed")
        draft.set_state(next_state)
        add_state_change_event(draft, submitter, prev_state, next_state)

    # clean up old files
    if prev_rev != draft.rev:
        from ietf.idrfc.expire import move_draft_files_to_archive
        move_draft_files_to_archive(draft, prev_rev)

    # automatic state changes
    state_change_msg = ""

    if not was_rfc and draft.tags.filter(slug="need-rev"):
        draft.tags.remove("need-rev")
        draft.tags.add("ad-f-up")

        e = DocEvent(type="changed_document", doc=draft)
        e.desc = "Sub state has been changed to <b>AD Followup</b> from <b>Revised ID Needed</b>"
        e.by = system
        e.save()

        state_change_msg = e.desc

    move_docs(submission)
    submission.status_id = POSTED

    announce_to_lists(request, submission)
    announce_new_version(request, submission, draft, state_change_msg)
    announce_to_authors(request, submission)

    submission.save()
Exemplo n.º 41
0
def make_last_call(request, name):
    """Make last call for Internet Draft, sending out announcement."""
    doc = get_object_or_404(Document, docalias__name=name)
    if not (doc.get_state("draft-iesg") or doc.get_state("statchg")):
        raise Http404

    login = request.user.person

    announcement_event = doc.latest_event(WriteupDocEvent,
                                          type="changed_last_call_text")
    if not announcement_event:
        if doc.type_id != 'draft':
            raise Http404
        announcement_event = generate_last_call_announcement(request, doc)
    announcement = announcement_event.text

    if request.method == 'POST':
        form = MakeLastCallForm(request.POST)
        if form.is_valid():
            if announcement_event.pk == None:
                announcement_event.save()

            send_mail_preformatted(request, announcement)
            if doc.type.slug == 'draft':
                addrs = gather_address_lists('last_call_issued_iana',
                                             doc=doc).as_strings(compact=False)
                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)

            new_state = doc.get_state()
            prev_tags = []
            new_tags = []
            events = []

            if doc.type.slug == 'draft':
                new_state = State.objects.get(used=True,
                                              type="draft-iesg",
                                              slug='lc')
                prev_tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
            elif doc.type.slug == 'statchg':
                new_state = State.objects.get(used=True,
                                              type="statchg",
                                              slug='in-lc')

            prev_state = doc.get_state(new_state.type_id)

            doc.set_state(new_state)
            doc.tags.remove(*prev_tags)

            e = add_state_change_event(doc,
                                       login,
                                       prev_state,
                                       new_state,
                                       prev_tags=prev_tags,
                                       new_tags=new_tags)
            if e:
                events.append(e)
            expiration_date = form.cleaned_data['last_call_expiration_date']
            e = LastCallDocEvent(doc=doc, rev=doc.rev, by=login)
            e.type = "sent_last_call"
            e.desc = "The following Last Call announcement was sent out (ends %s):<br><br>" % expiration_date
            e.desc += announcement

            if form.cleaned_data['last_call_sent_date'] != e.time.date():
                e.time = datetime.datetime.combine(
                    form.cleaned_data['last_call_sent_date'], e.time.time())
            e.expires = expiration_date
            e.save()
            events.append(e)

            # update IANA Review state
            if doc.type.slug == 'draft':
                prev_state = doc.get_state("draft-iana-review")
                if not prev_state:
                    next_state = State.objects.get(used=True,
                                                   type="draft-iana-review",
                                                   slug="need-rev")
                    doc.set_state(next_state)
                    e = add_state_change_event(doc, login, prev_state,
                                               next_state)
                    if e:
                        events.append(e)

            doc.save_with_history(events)

            return HttpResponseRedirect(doc.get_absolute_url())
    else:
        initial = {}
        initial["last_call_sent_date"] = datetime.date.today()
        if doc.type.slug == 'draft':
            # This logic is repeated in the code that edits last call text - why?
            expire_days = 14
            if doc.group.type_id in ("individ", "area"):
                expire_days = 28
            templ = 'doc/draft/make_last_call.html'
        else:
            expire_days = 28
            templ = 'doc/status_change/make_last_call.html'

        initial["last_call_expiration_date"] = datetime.date.today(
        ) + datetime.timedelta(days=expire_days)

        form = MakeLastCallForm(initial=initial)

    return render(request, templ,
                  dict(
                      doc=doc,
                      form=form,
                      announcement=announcement,
                  ))
Exemplo n.º 42
0
Arquivo: iana.py Projeto: ekr/ietfdb
def update_history_with_changes(changes, send_email=True):
    """Take parsed changes from IANA and apply them. Note that we
    expect to get these chronologically sorted, otherwise the change
    descriptions generated may not be right."""

    # build up state lookup
    states = {}

    slookup = dict((s.slug, s)
                   for s in State.objects.filter(used=True, type=StateType.objects.get(slug="draft-iana-action")))
    states["action"] = {
        "": slookup["newdoc"],
        "In Progress": slookup["inprog"],
        "Open": slookup["inprog"],
        "pre-approval In Progress": slookup["inprog"],
        "Waiting on Authors": slookup["waitauth"],
        "Author": slookup["waitauth"],
        "Waiting on ADs": slookup["waitad"],
        "Waiting on AD": slookup["waitad"],
        "AD": slookup["waitad"],
        "Waiting on WGC": slookup["waitwgc"],
        "WGC": slookup["waitwgc"],
        "Waiting on RFC-Editor": slookup["waitrfc"],
        "Waiting on RFC Editor": slookup["waitrfc"],
        "RFC-Editor": slookup["waitrfc"],
        "RFC-Ed-ACK": slookup["rfcedack"],
        "RFC-Editor-ACK": slookup["rfcedack"],
        "Completed": slookup["rfcedack"],
        "On Hold": slookup["onhold"],
        "No IC": slookup["noic"],
    }

    slookup = dict((s.slug, s)
                  for s in State.objects.filter(used=True, type=StateType.objects.get(slug="draft-iana-review")))
    states["review"] = {
        "IANA Review Needed": slookup["need-rev"],
        "IANA - Review Needed": slookup["need-rev"],
        "IANA OK - Actions Needed": slookup["ok-act"],
        "IANA OK - No Actions Needed": slookup["ok-noact"],
        "IANA Not OK": slookup["not-ok"],
        "IANA - Not OK": slookup["not-ok"],
        "Version Changed - Review Needed": slookup["changed"],
        }

    # so it turns out IANA has made a mistake and are including some
    # wrong states, we'll have to skip those
    wrong_action_states = ("Waiting on Reviewer", "Review Complete", "Last Call",
                           "Last Call - Questions", "Evaluation", "Evaluation -  Questions",
                           "With Reviewer", "IESG Notification Received", "Watiing on Last Call",
                           "IANA Comments Submitted", "Waiting on Last Call")

    system = Person.objects.get(name="(System)")

    added_events = []
    warnings = []

    for c in changes:
        docname = c['doc']
        timestamp = datetime.datetime.strptime(c["time"], "%Y-%m-%d %H:%M:%S")
        timestamp = utc_to_local_timezone(timestamp) # timestamps are in UTC

        if c['type'] in ("iana_state", "iana_review"):
            if c['type'] == "iana_state":
                kind = "action"

                if c["state"] in wrong_action_states:
                    warnings.append("Wrong action state '%s' encountered in changes from IANA" % c["state"])
                    continue
            else:
                kind = "review"

            if c["state"] not in states[kind]:
                warnings.append("Unknown IANA %s state %s (%s)" % (kind, c["state"], timestamp))
                continue

            state = states[kind][c["state"]]
            state_type = "draft-iana-%s" % kind

            if state.slug in ("need-rev", "changed"):
                # the Datatracker is the ultimate source of these
                # states, so skip them
                continue

            e = StateDocEvent.objects.filter(type="changed_state", time=timestamp,
                                             state_type=state_type, state=state)
            if not e:
                try:
                    doc = Document.objects.get(docalias__name=docname)
                except Document.DoesNotExist:
                    warnings.append("Document %s not found" % docname)
                    continue

                # the naive way of extracting prev_state here means
                # that we assume these changes are cronologically
                # applied
                prev_state = doc.get_state(state_type)
                e = add_state_change_event(doc, system, prev_state, state, timestamp=timestamp)

                if e:
                    # for logging purposes
                    e.json = c
                    added_events.append(e)

                if not StateDocEvent.objects.filter(doc=doc, time__gt=timestamp, state_type=state_type):
                    doc.set_state(state)

                    if e:
                        doc.save_with_history([e])

                    if send_email and (state != prev_state):
                        email_state_changed(None, doc, "IANA %s state changed to \"%s\"" % (kind, state.name),'doc_iana_state_changed')


    return added_events, warnings
Exemplo n.º 43
0
Arquivo: views.py Projeto: ekr/ietfdb
def doc_detail(request, date, name):
    '''
    This view displays the ballot information for the document, and lets the user make
    changes to ballot positions and document state.
    '''
    doc = get_object_or_404(Document, docalias__name=name)
    if not is_doc_on_telechat(doc, date):
        messages.warning(
            request,
            'Dcoument: {name} is not on the Telechat agenda for {date}'.format(
                name=doc.name, date=date))
        return redirect('ietf.secr.telechat.views.doc', date=date)

    # As of Datatracker v4.32, Conflict Review (conflrev) Document Types can
    # be added to the Telechat agenda.  If Document.type_id == draft use draft-iesg
    # for state type
    state_type = doc.type_id
    if doc.type_id == 'draft':
        state_type = 'draft-iesg'

    login = request.user.person

    if doc.active_ballot():
        ballots = doc.active_ballot().active_ad_positions(
        )  # returns dict of ad:ballotpositiondocevent
    else:
        ballots = []

    # setup form initials
    initial_ballot = []
    open_positions = 0
    for key in sorted(ballots, key=lambda a: a.name_parts()[3]):
        initial_ballot.append({
            'name':
            key.name,
            'id':
            key.id,
            'position':
            ballots[key].pos.slug if ballots[key] else None
        })
        if ballots[key] and ballots[key].pos.slug == 'norecord':
            open_positions += 1
        elif not ballots[key]:
            open_positions += 1

    tags = doc.tags.filter(slug__in=TELECHAT_TAGS)
    tag = tags[0].pk if tags else None

    writeup = get_doc_writeup(doc)

    initial_state = {'state': doc.get_state(state_type).pk, 'substate': tag}

    # need to use curry here to pass custom variable to form init
    if doc.active_ballot():
        ballot_type = doc.active_ballot().ballot_type
    else:
        ballot_type = BallotType.objects.get(doc_type='draft')
    BallotFormset = formset_factory(BallotForm, extra=0)
    BallotFormset.form.__init__ = curry(BallotForm.__init__,
                                        ballot_type=ballot_type)

    agenda = agenda_data(date=date)
    header = get_section_header(doc, agenda)

    # nav button logic
    doc_list = get_doc_list(agenda)
    nav_start = nav_end = False
    if doc == doc_list[0]:
        nav_start = True
    if doc == doc_list[-1]:
        nav_end = True

    if request.method == 'POST':
        button_text = request.POST.get('submit', '')

        # logic from doc/views_ballot.py EditPosition
        if button_text == 'update_ballot':
            formset = BallotFormset(request.POST, initial=initial_ballot)
            state_form = ChangeStateForm(initial=initial_state)
            has_changed = False
            for form in formset.forms:
                if form.is_valid() and form.changed_data:
                    # create new BallotPositionDocEvent
                    clean = form.cleaned_data
                    ad = Person.objects.get(id=clean['id'])
                    pos = BallotPositionDocEvent(doc=doc,
                                                 rev=doc.rev,
                                                 by=login)
                    pos.type = "changed_ballot_position"
                    pos.ad = ad
                    pos.ballot = doc.latest_event(BallotDocEvent,
                                                  type="created_ballot")
                    pos.pos = clean['position']
                    if form.initial['position'] == None:
                        pos.desc = '[Ballot Position Update] New position, %s, has been recorded for %s by %s' % (
                            pos.pos.name, ad.name, login.name)
                    else:
                        pos.desc = '[Ballot Position Update] Position for %s has been changed to %s by %s' % (
                            ad.name, pos.pos.name, login.name)
                    pos.save()
                    has_changed = True

            if has_changed:
                messages.success(request, 'Ballot position changed.')
            return redirect('ietf.secr.telechat.views.doc_detail',
                            date=date,
                            name=name)

        # logic from doc/views_draft.py change_state
        elif button_text == 'update_state':
            formset = BallotFormset(initial=initial_ballot)
            state_form = ChangeStateForm(request.POST, initial=initial_state)
            if state_form.is_valid():
                prev_state = doc.get_state(state_type)

                new_state = state_form.cleaned_data['state']
                tag = state_form.cleaned_data['substate']

                # tag handling is a bit awkward since the UI still works
                # as if IESG tags are a substate
                prev_tags = doc.tags.filter(slug__in=TELECHAT_TAGS)
                new_tags = [tag] if tag else []

                if state_form.changed_data:
                    if 'state' in state_form.changed_data:
                        doc.set_state(new_state)

                    if 'substate' in state_form.changed_data:
                        doc.tags.remove(*prev_tags)
                        doc.tags.add(*new_tags)

                    e = add_state_change_event(doc,
                                               login,
                                               prev_state,
                                               new_state,
                                               prev_tags=prev_tags,
                                               new_tags=new_tags)
                    if e:
                        doc.save_with_history([e])

                    email_state_changed(request, doc, e.desc,
                                        'doc_state_edited')

                    if new_state.slug == "lc-req":
                        request_last_call(request, doc)

                messages.success(request, 'Document state updated')
                return redirect('ietf.secr.telechat.views.doc_detail',
                                date=date,
                                name=name)
    else:
        formset = BallotFormset(initial=initial_ballot)
        state_form = ChangeStateForm(initial=initial_state)

        # if this is a conflict review document add referenced document
        if doc.type_id == 'conflrev':
            conflictdoc = doc.relateddocument_set.get(
                relationship__slug='conflrev').target.document
        else:
            conflictdoc = None

    return render(
        request,
        'telechat/doc.html',
        {
            'ballot_type': ballot_type,
            'date': date,
            'document': doc,
            'conflictdoc': conflictdoc,
            'agenda': agenda,
            'formset': formset,
            'header': header,
            'open_positions': open_positions,
            'state_form': state_form,
            'writeup': writeup,
            'nav_start': nav_start,
            'nav_end': nav_end
        },
    )
Exemplo n.º 44
0
def update_drafts_from_queue(drafts):
    tag_mapping = {
        'IANA': DocTagName.objects.get(slug='iana'),
        'REF':  DocTagName.objects.get(slug='ref')
    }

    slookup = dict((s.slug, s)
                   for s in State.objects.filter(used=True, type=StateType.objects.get(slug="draft-rfceditor")))
    state_mapping = {
        'AUTH': slookup['auth'],
        'AUTH48': slookup['auth48'],
        'AUTH48-DONE': slookup['auth48-done'],
        'EDIT': slookup['edit'],
        'IANA': slookup['iana'],
        'IESG': slookup['iesg'],
        'ISR': slookup['isr'],
        'ISR-AUTH': slookup['isr-auth'],
        'REF': slookup['ref'],
        'RFC-EDITOR': slookup['rfc-edit'],
        'TO': slookup['timeout'],
        'MISSREF': slookup['missref'],
    }

    system = Person.objects.get(name="(System)")

    warnings = []

    names = [t[0] for t in drafts]

    drafts_in_db = dict((d.name, d)
                        for d in Document.objects.filter(type="draft", docalias__name__in=names))

    changed = set()

    for name, date_received, state, tags, missref_generation, stream, auth48, cluster, refs in drafts:
        if name not in drafts_in_db:
            warnings.append("unknown document %s" % name)
            continue

        if not state or state not in state_mapping:
            warnings.append("unknown state '%s'" % state)
            continue

        d = drafts_in_db[name]

        prev_state = d.get_state("draft-rfceditor")
        next_state = state_mapping[state]

        # check if we've noted it's been received
        if d.get_state_slug("draft-iesg") == "ann" and not prev_state and not d.latest_event(DocEvent, type="rfc_editor_received_announcement"):
            e = DocEvent(doc=d, by=system, type="rfc_editor_received_announcement")
            e.desc = "Announcement was received by RFC Editor"
            e.save()
            send_mail_text(None, "*****@*****.**", None,
                           '%s in RFC Editor queue' % d.name,
                           'The announcement for %s has been received by the RFC Editor.' % d.name)


        if prev_state != next_state:
            save_document_in_history(d)

            d.set_state(next_state)

            e = add_state_change_event(d, system, prev_state, next_state)

            if auth48:
                e.desc = re.sub(r"(<b>.*</b>)", "<a href=\"%s\">\\1</a>" % auth48, e.desc)
                e.save()

            changed.add(name)

        t = DocTagName.objects.filter(slug__in=tags)
        if set(t) != set(d.tags.all()):
            d.tags = t
            changed.add(name)


    # remove tags and states for those not in the queue anymore
    for d in Document.objects.exclude(docalias__name__in=names).filter(states__type="draft-rfceditor").distinct():
        d.tags.remove(*tag_mapping.values())
        d.unset_state("draft-rfceditor")
        # we do not add a history entry here - most likely we already
        # have something that explains what happened
        changed.add(name)

    return changed, warnings