コード例 #1
0
ファイル: milestones.py プロジェクト: mcr/ietfdb
def reset_charter_milestones(request, acronym):
    """Reset charter milestones to the currently in-use milestones."""
    login = request.user.get_profile()

    group = get_object_or_404(Group, acronym=acronym)

    if (not has_role(request.user, ("Area Director", "Secretariat")) and
        not group.role_set.filter(name="chair", person=login)):
        return HttpResponseForbidden("You are not chair of this group.")

    current_milestones = group.groupmilestone_set.filter(state="active")
    charter_milestones = group.groupmilestone_set.filter(state="charter")

    if request.method == 'POST':
        try:
            milestone_ids = [int(v) for v in request.POST.getlist("milestone")]
        except ValueError as e:
            return HttpResponseBadRequest("error in list of ids - %s" % e)

        # delete existing
        for m in charter_milestones:
            save_milestone_in_history(m)

            m.state_id = "deleted"
            m.save()

            DocEvent.objects.create(type="changed_charter_milestone",
                                    doc=group.charter,
                                    desc='Deleted milestone "%s"' % m.desc,
                                    by=login,
                                    )

        # add current
        for m in current_milestones.filter(id__in=milestone_ids):
            new = GroupMilestone.objects.create(group=m.group,
                                                state_id="charter",
                                                desc=m.desc,
                                                due=m.due,
                                                resolved=m.resolved,
                                                )
            new.docs = m.docs.all()

            DocEvent.objects.create(type="changed_charter_milestone",
                                    doc=group.charter,
                                    desc='Added milestone "%s", due %s, from current group milestones' % (new.desc, new.due.strftime("%B %Y")),
                                    by=login,
                                    )


        return redirect('wg_edit_charter_milestones', acronym=group.acronym)

    return render_to_response('wginfo/reset_charter_milestones.html',
                              dict(group=group,
                                   charter_milestones=charter_milestones,
                                   current_milestones=current_milestones,
                                   ),
                              context_instance=RequestContext(request))
コード例 #2
0
ファイル: milestones.py プロジェクト: algby/ietfdb
def reset_charter_milestones(request, group_type, acronym):
    """Reset charter milestones to the currently in-use milestones."""
    group = get_group_or_404(acronym, group_type)
    if not group.features.has_milestones:
        raise Http404
    
    if (not can_manage_group_type(request.user, group_type) and
        not group.role_set.filter(name="chair", person__user=request.user)):
        return HttpResponseForbidden("You are not chair of this group.")

    current_milestones = group.groupmilestone_set.filter(state="active")
    charter_milestones = group.groupmilestone_set.filter(state="charter")

    if request.method == 'POST':
        try:
            milestone_ids = [int(v) for v in request.POST.getlist("milestone")]
        except ValueError as e:
            return HttpResponseBadRequest("error in list of ids - %s" % e)

        # delete existing
        for m in charter_milestones:
            save_milestone_in_history(m)

            m.state_id = "deleted"
            m.save()

            DocEvent.objects.create(type="changed_charter_milestone",
                                    doc=group.charter,
                                    desc='Deleted milestone "%s"' % m.desc,
                                    by=request.user.person,
                                    )

        # add current
        for m in current_milestones.filter(id__in=milestone_ids):
            new = GroupMilestone.objects.create(group=m.group,
                                                state_id="charter",
                                                desc=m.desc,
                                                due=m.due,
                                                resolved=m.resolved,
                                                )
            new.docs = m.docs.all()

            DocEvent.objects.create(type="changed_charter_milestone",
                                    doc=group.charter,
                                    desc='Added milestone "%s", due %s, from current group milestones' % (new.desc, new.due.strftime("%B %Y")),
                                    by=request.user.person,
                                    )


        return redirect('group_edit_charter_milestones', group_type=group.type_id, acronym=group.acronym)

    return render(request, 'group/reset_charter_milestones.html',
                  dict(group=group,
                       charter_milestones=charter_milestones,
                       current_milestones=current_milestones,
                   ))
コード例 #3
0
ファイル: milestones.py プロジェクト: qiujianben/ietfdb
def reset_charter_milestones(request, acronym):
    """Reset charter milestones to the currently in-use milestones."""
    login = request.user.get_profile()

    group = get_object_or_404(Group, acronym=acronym)

    if (not has_role(request.user, ("Area Director", "Secretariat"))
            and not group.role_set.filter(name="chair", person=login)):
        return HttpResponseForbidden("You are not chair of this group.")

    current_milestones = group.groupmilestone_set.filter(state="active")
    charter_milestones = group.groupmilestone_set.filter(state="charter")

    if request.method == 'POST':
        try:
            milestone_ids = [int(v) for v in request.POST.getlist("milestone")]
        except ValueError as e:
            return HttpResponseBadRequest("error in list of ids - %s" % e)

        # delete existing
        for m in charter_milestones:
            save_milestone_in_history(m)

            m.state_id = "deleted"
            m.save()

            DocEvent.objects.create(
                type="changed_charter_milestone",
                doc=group.charter,
                desc='Deleted milestone "%s"' % m.desc,
                by=login,
            )

        # add current
        for m in current_milestones.filter(id__in=milestone_ids):
            new = GroupMilestone.objects.create(
                group=m.group,
                state_id="charter",
                desc=m.desc,
                due=m.due,
                resolved=m.resolved,
            )
            new.docs = m.docs.all()

            DocEvent.objects.create(
                type="changed_charter_milestone",
                doc=group.charter,
                desc=
                'Added milestone "%s", due %s, from current group milestones' %
                (new.desc, new.due.strftime("%B %Y")),
                by=login,
            )

        return redirect('wg_edit_charter_milestones', acronym=group.acronym)

    return render_to_response('wginfo/reset_charter_milestones.html',
                              dict(
                                  group=group,
                                  charter_milestones=charter_milestones,
                                  current_milestones=current_milestones,
                              ),
                              context_instance=RequestContext(request))
コード例 #4
0
ファイル: milestones.py プロジェクト: qiujianben/ietfdb
    def save_milestone_form(f):
        c = f.cleaned_data

        if f.milestone:
            m = f.milestone

            named_milestone = 'milestone "%s"' % m.desc
            if milestone_set == "charter":
                named_milestone = "charter " + named_milestone

            if c["delete"]:
                save_milestone_in_history(m)

                m.state_id = "deleted"
                m.save()

                return 'Deleted %s' % named_milestone

            # compute changes
            history = None

            changes = ['Changed %s' % named_milestone]

            if m.state_id == "review" and not needs_review and c[
                    "accept"] != "noaction":
                if not history:
                    history = save_milestone_in_history(m)

                if c["accept"] == "accept":
                    m.state_id = "active"
                    changes.append(
                        "set state to active from review, accepting new milestone"
                    )
                elif c["accept"] == "reject":
                    m.state_id = "deleted"
                    changes.append(
                        "set state to deleted from review, rejecting new milestone"
                    )

            if c["desc"] != m.desc and not needs_review:
                if not history:
                    history = save_milestone_in_history(m)
                m.desc = c["desc"]
                changes.append('set description to "%s"' % m.desc)

            c_due = due_month_year_to_date(c)
            if c_due != m.due:
                if not history:
                    history = save_milestone_in_history(m)
                changes.append(
                    'set due date to %s from %s' %
                    (c_due.strftime("%B %Y"), m.due.strftime("%B %Y")))
                m.due = c_due

            resolved = c["resolved"]
            if resolved != m.resolved:
                if resolved and not m.resolved:
                    changes.append('resolved as "%s"' % resolved)
                elif not resolved and m.resolved:
                    changes.append("reverted to not being resolved")
                elif resolved and m.resolved:
                    changes.append('set resolution to "%s"' % resolved)

                if not history:
                    history = save_milestone_in_history(m)

                m.resolved = resolved

            new_docs = set(c["docs"])
            old_docs = set(m.docs.all())
            if new_docs != old_docs:
                added = new_docs - old_docs
                if added:
                    changes.append('added %s to milestone' %
                                   ", ".join(d.name for d in added))

                removed = old_docs - new_docs
                if removed:
                    changes.append('removed %s from milestone' %
                                   ", ".join(d.name for d in removed))

                if not history:
                    history = save_milestone_in_history(m)

                m.docs = new_docs

            if len(changes) > 1:
                m.save()

                return ", ".join(changes)

        else:  # new milestone
            m = f.milestone = GroupMilestone()
            set_attributes_from_form(f, m)
            m.save()

            m.docs = c["docs"]

            named_milestone = 'milestone "%s"' % m.desc
            if milestone_set == "charter":
                named_milestone = "charter " + named_milestone

            if m.state_id in ("active", "charter"):
                return 'Added %s, due %s' % (named_milestone,
                                             m.due.strftime("%B %Y"))
            elif m.state_id == "review":
                return 'Added %s for review, due %s' % (
                    named_milestone, m.due.strftime("%B %Y"))
コード例 #5
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.get_profile()

    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

        new_state = GroupStateName.objects.get(slug="active")
        if group.state != new_state:
            save_group_in_history(group)
            prev_state = group.state
            group.state = new_state
            group.time = e.time
            group.save()

            # create an event for the wg state change, too
            e = ChangeStateGroupEvent(group=group, type="changed_state")
            e.time = group.time
            e.by = login
            e.state_id = "active"
            e.desc = "Charter approved, group active"
            e.save()

            change_description += " and %s state has been changed to %s" % (
                group.type.name, new_state.name)

        e = log_state_changed(request, charter, login, prev_charter_state)

        # according to spec, 00-02 becomes 01, so copy file and record new revision
        try:
            old = os.path.join(
                charter.get_file_path(),
                '%s-%s.txt' % (charter.canonical_name(), charter.rev))
            new = os.path.join(
                charter.get_file_path(),
                '%s-%s.txt' % (charter.canonical_name(),
                               next_approved_revision(charter.rev)))
            shutil.copy(old, new)
        except IOError:
            return HttpResponse(
                "There was an error copying %s to %s" %
                ('%s-%s.txt' %
                 (charter.canonical_name(), charter.rev), '%s-%s.txt' %
                 (charter.canonical_name(), next_approved_revision(
                     charter.rev))))

        e = NewRevisionDocEvent(doc=charter, by=login, type="new_revision")
        e.rev = next_approved_revision(charter.rev)
        e.desc = "New version available: <b>%s-%s.txt</b>" % (
            charter.canonical_name(), e.rev)
        e.save()

        charter.rev = e.rev
        charter.time = e.time
        charter.save()

        email_secretariat(request, group, "state-%s" % new_charter_state.slug,
                          change_description)

        # 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('wgcharter/approve.html',
                              dict(charter=charter, announcement=announcement),
                              context_instance=RequestContext(request))
コード例 #6
0
ファイル: milestones.py プロジェクト: ekr/ietfdb
def reset_charter_milestones(request, group_type, acronym):
    """Reset charter milestones to the currently in-use milestones."""
    group = get_group_or_404(acronym, group_type)
    if not group.features.has_milestones:
        raise Http404

    if not can_manage_group(request.user, group):
        return HttpResponseForbidden(
            "You are not authorized to change the milestones for this group.")

    current_milestones = group.groupmilestone_set.filter(state="active")
    charter_milestones = group.groupmilestone_set.filter(state="charter")

    if request.method == 'POST':
        try:
            milestone_ids = [int(v) for v in request.POST.getlist("milestone")]
        except ValueError as e:
            return HttpResponseBadRequest("error in list of ids - %s" % e)

        # delete existing
        for m in charter_milestones:
            save_milestone_in_history(m)

            m.state_id = "deleted"
            m.save()

            DocEvent.objects.create(
                type="changed_charter_milestone",
                doc=group.charter,
                rev=group.charter.rev,
                desc='Deleted milestone "%s"' % m.desc,
                by=request.user.person,
            )

        # add current
        for m in current_milestones.filter(id__in=milestone_ids):
            new = GroupMilestone.objects.create(
                group=m.group,
                state_id="charter",
                desc=m.desc,
                due=m.due,
                resolved=m.resolved,
            )
            new.docs = m.docs.all()

            DocEvent.objects.create(
                type="changed_charter_milestone",
                doc=group.charter,
                rev=group.charter.rev,
                desc=
                'Added milestone "%s", due %s, from current group milestones' %
                (new.desc, new.due.strftime("%B %Y")),
                by=request.user.person,
            )

        return redirect('ietf.group.milestones.edit_milestones;charter',
                        group_type=group.type_id,
                        acronym=group.acronym)

    return render(
        request, 'group/reset_charter_milestones.html',
        dict(
            group=group,
            charter_milestones=charter_milestones,
            current_milestones=current_milestones,
        ))
コード例 #7
0
ファイル: milestones.py プロジェクト: mcr/ietfdb
    def save_milestone_form(f):
        c = f.cleaned_data

        if f.milestone:
            m = f.milestone

            named_milestone = 'milestone "%s"' % m.desc
            if milestone_set == "charter":
                named_milestone = "charter " + named_milestone

            if c["delete"]:
                save_milestone_in_history(m)

                m.state_id = "deleted"
                m.save()

                return 'Deleted %s' % named_milestone

            # compute changes
            history = None

            changes = ['Changed %s' % named_milestone]

            if m.state_id == "review" and not needs_review and c["accept"] != "noaction":
                if not history:
                    history = save_milestone_in_history(m)

                if c["accept"] == "accept":
                    m.state_id = "active"
                    changes.append("set state to active from review, accepting new milestone")
                elif c["accept"] == "reject":
                    m.state_id = "deleted"
                    changes.append("set state to deleted from review, rejecting new milestone")


            if c["desc"] != m.desc and not needs_review:
                if not history:
                    history = save_milestone_in_history(m)
                m.desc = c["desc"]
                changes.append('set description to "%s"' % m.desc)


            c_due = due_month_year_to_date(c)
            if c_due != m.due:
                if not history:
                    history = save_milestone_in_history(m)
                changes.append('set due date to %s from %s' % (c_due.strftime("%B %Y"), m.due.strftime("%B %Y")))
                m.due = c_due

            resolved = c["resolved"]
            if resolved != m.resolved:
                if resolved and not m.resolved:
                    changes.append('resolved as "%s"' % resolved)
                elif not resolved and m.resolved:
                    changes.append("reverted to not being resolved")
                elif resolved and m.resolved:
                    changes.append('set resolution to "%s"' % resolved)

                if not history:
                    history = save_milestone_in_history(m)

                m.resolved = resolved

            new_docs = set(c["docs"])
            old_docs = set(m.docs.all())
            if new_docs != old_docs:
                added = new_docs - old_docs
                if added:
                    changes.append('added %s to milestone' % ", ".join(d.name for d in added))

                removed = old_docs - new_docs
                if removed:
                    changes.append('removed %s from milestone' % ", ".join(d.name for d in removed))

                if not history:
                    history = save_milestone_in_history(m)

                m.docs = new_docs

            if len(changes) > 1:
                m.save()

                return ", ".join(changes)

        else: # new milestone
            m = f.milestone = GroupMilestone()
            set_attributes_from_form(f, m)
            m.save()

            m.docs = c["docs"]

            named_milestone = 'milestone "%s"' % m.desc
            if milestone_set == "charter":
                named_milestone = "charter " + named_milestone

            if m.state_id in ("active", "charter"):
                return 'Added %s, due %s' % (named_milestone, m.due.strftime("%B %Y"))
            elif m.state_id == "review":
                return 'Added %s for review, due %s' % (named_milestone, m.due.strftime("%B %Y"))
コード例 #8
0
ファイル: views_charter.py プロジェクト: wpjesus/codematch
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))
コード例 #9
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))
コード例 #10
0
ファイル: views.py プロジェクト: mcr/ietfdb
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.get_profile()

    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

        new_state = GroupStateName.objects.get(slug="active")
        if group.state != new_state:
            save_group_in_history(group)
            prev_state = group.state
            group.state = new_state
            group.time = e.time
            group.save()

            # create an event for the wg state change, too
            e = ChangeStateGroupEvent(group=group, type="changed_state")
            e.time = group.time
            e.by = login
            e.state_id = "active"
            e.desc = "Charter approved, group active"
            e.save()

            change_description += " and %s state has been changed to %s" % (group.type.name, new_state.name)

        e = log_state_changed(request, charter, login, prev_charter_state)

        # according to spec, 00-02 becomes 01, so copy file and record new revision
        try:
            old = os.path.join(charter.get_file_path(), '%s-%s.txt' % (charter.canonical_name(), charter.rev))
            new = os.path.join(charter.get_file_path(), '%s-%s.txt' % (charter.canonical_name(), next_approved_revision(charter.rev)))
            shutil.copy(old, new)
        except IOError:
            return HttpResponse("There was an error copying %s to %s" %
                                ('%s-%s.txt' % (charter.canonical_name(), charter.rev),
                                 '%s-%s.txt' % (charter.canonical_name(), next_approved_revision(charter.rev))))

        e = NewRevisionDocEvent(doc=charter, by=login, type="new_revision")
        e.rev = next_approved_revision(charter.rev)
        e.desc = "New version available: <b>%s-%s.txt</b>" % (charter.canonical_name(), e.rev)
        e.save()

        charter.rev = e.rev
        charter.time = e.time
        charter.save()

        email_secretariat(request, group, "state-%s" % new_charter_state.slug, change_description)

        # 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('wgcharter/approve.html',
                              dict(charter=charter,
                                   announcement=announcement),
                              context_instance=RequestContext(request))