From b73c5358e7c1e8266cff44954b92764b8336af25 Mon Sep 17 00:00:00 2001
From: Martin Qvist <tin@laenke.io>
Date: Mon, 22 Aug 2011 19:54:25 +0000
Subject: [PATCH] Added corrections and tests as discussed with Ole.  -
 Legacy-Id: 3349

---
 ietf/settings.py                              |   2 +
 ietf/templates/wgrecord/add_comment.html      |   2 +-
 ietf/templates/wgrecord/approve_ballot.html   |   2 +-
 ietf/templates/wgrecord/change_state.html     |   7 +-
 ietf/templates/wgrecord/conclude.html         |   4 +-
 ietf/templates/wgrecord/edit_info.html        |   2 +-
 ietf/templates/wgrecord/edit_position.html    |   2 +-
 ietf/templates/wgrecord/record_ballot.html    |   6 +-
 .../wgrecord/record_ballot_list.html          |   2 +-
 .../wgrecord/record_tab_charter.html          |   2 +-
 .../wgrecord/record_tab_history.html          |   2 +-
 .../wgrecord/record_tab_writeup.html          |   8 +-
 .../templates/wgrecord/search_result_row.html |   2 +-
 ietf/templates/wgrecord/status_columns.html   |   4 +-
 ietf/templates/wgrecord/submit.html           |   2 +-
 ietf/utils/test_data.py                       |  14 +
 ietf/wgrecord/feeds.py                        |  16 +-
 ietf/wgrecord/mails.py                        |   2 +-
 ietf/wgrecord/models.py                       |   0
 .../{rec_ballot_icon.py => wg_ballot_icon.py} |  14 +-
 ietf/wgrecord/tests.py                        | 345 +++++++++++++++++-
 ietf/wgrecord/testurl.list                    |  55 +++
 ietf/wgrecord/urls.py                         |  14 +-
 ietf/wgrecord/utils.py                        |  39 +-
 ietf/wgrecord/views_ballot.py                 |  12 +-
 ietf/wgrecord/views_edit.py                   |  67 ++--
 ietf/wgrecord/views_rec.py                    |  34 +-
 ietf/wgrecord/views_search.py                 |  42 ++-
 ietf/wgrecord/views_submit.py                 |  11 +-
 redesign/doc/models.py                        |   4 +-
 static/js/base.js                             |   6 +-
 ...rec-change-state.js => wg-change-state.js} |   5 +
 ...c-edit-position.js => wg-edit-position.js} |   0
 33 files changed, 587 insertions(+), 142 deletions(-)
 create mode 100644 ietf/wgrecord/models.py
 rename ietf/wgrecord/templatetags/{rec_ballot_icon.py => wg_ballot_icon.py} (88%)
 create mode 100644 ietf/wgrecord/testurl.list
 rename static/js/{rec-change-state.js => wg-change-state.js} (84%)
 rename static/js/{rec-edit-position.js => wg-edit-position.js} (100%)

diff --git a/ietf/settings.py b/ietf/settings.py
index 95db6b130..4b08d1c57 100644
--- a/ietf/settings.py
+++ b/ietf/settings.py
@@ -177,6 +177,8 @@ MAX_WG_DELEGATES = 3
 INTERNET_DRAFT_PATH = '/a/www/ietf-ftp/internet-drafts/'
 INTERNET_DRAFT_PDF_PATH = '/a/www/ietf-datatracker/pdf/'
 RFC_PATH = '/a/www/ietf-ftp/rfc/'
+CHARTER_PATH = '/a/www/ietf-ftp/charters/'
+CHARTER_TXT_URL = 'http://www.ietf.org/charters/'
 AGENDA_PATH = '/a/www/www6s/proceedings/'
 AGENDA_PATH_PATTERN = '/a/www/www6s/proceedings/%(meeting)s/agenda/%(wg)s.%(ext)s'
 MINUTES_PATH_PATTERN = '/a/www/www6s/proceedings/%(meeting)s/minutes/%(wg)s.%(ext)s'
diff --git a/ietf/templates/wgrecord/add_comment.html b/ietf/templates/wgrecord/add_comment.html
index f52b25ebe..1db80c507 100644
--- a/ietf/templates/wgrecord/add_comment.html
+++ b/ietf/templates/wgrecord/add_comment.html
@@ -27,7 +27,7 @@ form.add-comment .actions {
   <tr>
     <td></td>
     <td class="actions">
-      <a href="{% url record_view name=wg.acronym %}">Back</a>
+      <a href="{% url wg_view_record name=wg.acronym %}">Back</a>
       <input type="submit" value="Add comment"/>
     </td>
   </tr>
diff --git a/ietf/templates/wgrecord/approve_ballot.html b/ietf/templates/wgrecord/approve_ballot.html
index eb6d5e0aa..01426c601 100644
--- a/ietf/templates/wgrecord/approve_ballot.html
+++ b/ietf/templates/wgrecord/approve_ballot.html
@@ -30,7 +30,7 @@ form.approve-ballot .announcement {
   </div>
 
   <div class="actions">
-    <a href="{% url record_view name=wg.acronym %}">Back</a>
+    <a href="{% url wg_view_record name=wg.acronym %}">Back</a>
     <input type="submit" value="Send out the announcement, close ballot and update revision"/>
   </div>
 </form>
diff --git a/ietf/templates/wgrecord/change_state.html b/ietf/templates/wgrecord/change_state.html
index 59d175aad..5992b32d0 100644
--- a/ietf/templates/wgrecord/change_state.html
+++ b/ietf/templates/wgrecord/change_state.html
@@ -43,7 +43,7 @@ form.change-state .actions {
     {% endfor %}
     <tr>
       <td colspan="2" class="actions">
-        <a href="{% url record_view name=wg.acronym %}">Back</a>
+        <a href="{% url wg_view_record name=wg.acronym %}">Back</a>
         <input type="submit" value="Save"/>
       </td>
     </tr>
@@ -68,10 +68,9 @@ form.change-state .actions {
   var message = {
    "infrev": "The WG {{ wg.name }} ({{ wg.acronym }}) has been set to Informal IESG review by {{ login.name }}",
    "intrev": "The WG {{ wg.name }} ({{ wg.acronym }}) has been set to Internal review by {{ login.name }}. Please place it on the next IESG telechat and inform the IAB.",
-   "extrev": "The WG {{ wg.name }} ({{ wg.acronym }}) has been set to External review by {{ login.name }}. Please send out the external review announcement to the appropriate lists.\n\nSend the announcement to other SDOs: Yes\nAdditional recipients of the announcement: ",
-   "approved": "The WG {{ wg.name }} ({{ wg.acronym }}) has been approved. Please publish the charter and sent the appropriate announcements."
+   "extrev": "The WG {{ wg.name }} ({{ wg.acronym }}) has been set to External review by {{ login.name }}. Please send out the external review announcement to the appropriate lists.\n\nSend the announcement to other SDOs: Yes\nAdditional recipients of the announcement: "
   };
 
 </script>
-<script type="text/javascript" src="/js/rec-change-state.js"></script>
+<script type="text/javascript" src="/js/wg-change-state.js"></script>
 {% endblock %}
diff --git a/ietf/templates/wgrecord/conclude.html b/ietf/templates/wgrecord/conclude.html
index 1231ec395..a66911cad 100644
--- a/ietf/templates/wgrecord/conclude.html
+++ b/ietf/templates/wgrecord/conclude.html
@@ -3,7 +3,7 @@
 {% block title %}Request closing of WG {{ wg.acronym }}{% endblock %}
 
 {% block morecss %}
-#id_comment {
+#id_instructions {
   width: 40em;
 }
 
@@ -28,7 +28,7 @@ form.conclude .actions {
     {{ form.as_table }}
     <tr>
       <td colspan="2" class="actions">
-        <a href="{% url record_view name=wg.acronym %}">Back</a>
+        <a href="{% url wg_view_record name=wg.acronym %}">Back</a>
         <input type="submit" value="Send request"/>
       </td>
     </tr>
diff --git a/ietf/templates/wgrecord/edit_info.html b/ietf/templates/wgrecord/edit_info.html
index 260d6b0db..a38849ce6 100644
--- a/ietf/templates/wgrecord/edit_info.html
+++ b/ietf/templates/wgrecord/edit_info.html
@@ -78,7 +78,7 @@ Create WG record
       <td></td>
       <td class="actions">
 	{% if wg %}
-          <a href="{% url record_view name=wg.acronym %}">Back</a>
+          <a href="{% url wg_view_record name=wg.acronym %}">Back</a>
 	{% endif %}
         <input type="submit" value="Save"/>
       </td>
diff --git a/ietf/templates/wgrecord/edit_position.html b/ietf/templates/wgrecord/edit_position.html
index 59608f38a..64e00439c 100644
--- a/ietf/templates/wgrecord/edit_position.html
+++ b/ietf/templates/wgrecord/edit_position.html
@@ -71,5 +71,5 @@ form.position-form .comment {
 {% endblock %}
 
 {% block content_end %}
-<script type="text/javascript" src="/js/rec-edit-position.js"></script>
+<script type="text/javascript" src="/js/wg-edit-position.js"></script>
 {% endblock %}
diff --git a/ietf/templates/wgrecord/record_ballot.html b/ietf/templates/wgrecord/record_ballot.html
index 095ea36c4..5a32b29ba 100644
--- a/ietf/templates/wgrecord/record_ballot.html
+++ b/ietf/templates/wgrecord/record_ballot.html
@@ -6,10 +6,10 @@ Copyright The IETF Trust 2011, All Rights Reserved
 
 {% if user|in_group:"Area_Director,Secretariat" %}
 {% if user|in_group:"Area_Director" %}
-<div style="margin-top:8px; margin-bottom:8px;"><span id="rec_ballot_button" class="yui-button yui-link-button"><span class="first-child"><a href="{% url rec_edit_position name=wg.acronym %}">Edit position</a></span></span></div>
+<div style="margin-top:8px; margin-bottom:8px;"><span id="wg_ballot_button" class="yui-button yui-link-button"><span class="first-child"><a href="{% url wg_edit_position name=wg.acronym %}">Edit position</a></span></span></div>
 {% endif %}
 {% if user|in_group:"Secretariat" %}
-<div style="margin-top:8px; margin-bottom:8px;"><span id="rec_ballot_button" class="yui-button yui-link-button"><span class="first-child"><a href="{% url rec_approve_ballot name=wg.acronym %}">Approve ballot</a></span></span></div>
+<div style="margin-top:8px; margin-bottom:8px;"><span id="wg_ballot_button" class="yui-button yui-link-button"><span class="first-child"><a href="{% url wg_approve_ballot name=wg.acronym %}">Approve ballot</a></span></span></div>
 {% endif %}
 {% endif %}
 
@@ -27,7 +27,7 @@ Copyright The IETF Trust 2011, All Rights Reserved
 
 <p><span class="square" style="background:white;"></span><b>No Record</b><br/>
 {% for p in info.pos_no_record %}
-<a{% if user|in_group:"Secretariat" %} href="{% url rec_edit_position name=wg.acronym %}?ad={{ p.id }}" title="Click to edit the position of {{ p.name }}"{% endif %}>{{p.name}}</a><br/>
+<a{% if user|in_group:"Secretariat" %} href="{% url wg_edit_position name=wg.acronym %}?ad={{ p.id }}" title="Click to edit the position of {{ p.name }}"{% endif %}>{{p.name}}{% if user|in_group:"Secretariat" %}</a>{% endif %}<br/>
 {% empty %}
 <i>none</i>
 {% endfor %}
diff --git a/ietf/templates/wgrecord/record_ballot_list.html b/ietf/templates/wgrecord/record_ballot_list.html
index 72a81c0de..db513edb2 100644
--- a/ietf/templates/wgrecord/record_ballot_list.html
+++ b/ietf/templates/wgrecord/record_ballot_list.html
@@ -1,6 +1,6 @@
 {% load ietf_filters %}
 {% for p in positions %}
-{% if p.is_old_ad %}[{%endif%}<a{% if user|in_group:"Secretariat" %} href="{% url rec_edit_position name=wg.acronym %}?ad={{ p.ad_id }}" title="Click to edit the position of {{ p.ad }}"{% endif %}>{{p.ad}}</a>{% if p.is_old_ad %}]{%endif%}{% if p.comment or p.block_comment %}&nbsp;<a href="#{{p.ad|slugify}}"><img src="/images/comment.png" width="14" height="12" alt="*" border="0"/></a>{% endif %}<br/>
+{% if p.is_old_ad %}[{%endif%}<a{% if user|in_group:"Secretariat" %} href="{% url wg_edit_position name=wg.acronym %}?ad={{ p.ad_id }}" title="Click to edit the position of {{ p.ad }}"{% endif %}>{{p.ad}}</a>{% if p.is_old_ad %}]{%endif%}{% if p.comment or p.block_comment %}&nbsp;<a href="#{{p.ad|slugify}}"><img src="/images/comment.png" width="14" height="12" alt="*" border="0"/></a>{% endif %}<br/>
 {% if p.old_positions %}<span class="was">(was {{p.old_positions|join:", "}})</span><br/>{%endif%}
 {% empty %}
 <i>none</i>
diff --git a/ietf/templates/wgrecord/record_tab_charter.html b/ietf/templates/wgrecord/record_tab_charter.html
index 027743c49..6a7b9230a 100644
--- a/ietf/templates/wgrecord/record_tab_charter.html
+++ b/ietf/templates/wgrecord/record_tab_charter.html
@@ -7,7 +7,7 @@ Copyright The IETF Trust 2011, All Rights Reserved
 {% load ietf_filters %}
 
 {% block record_revision %}
-Snapshots: {% if not snapshot %}<strong>{% else %}<a href="{% url record_view name=wg.acronym %}">{% endif %}current{% if not snapshot %}</strong>{% else %}</a>{% endif %} {% for d in versions reversed %}{% ifnotequal d.rev wg.charter.rev %}{% ifequal snapshot d.rev %}<strong>{% else %}<a href="{% url record_view name=wg.acronym %}{{d.rev}}/">{% endifequal %}{{ d.rev }}{% ifequal snapshot d.rev %}</strong>{% else %}</a>{% endifequal %} {% endifnotequal %}{% endfor %}
+Snapshots: {% if not snapshot %}<strong>{% else %}<a href="{% url wg_view_record name=wg.acronym %}">{% endif %}current{% if not snapshot %}</strong>{% else %}</a>{% endif %} {% for d in versions reversed %}{% ifnotequal d.rev wg.charter.rev %}{% ifequal snapshot d.rev %}<strong>{% else %}<a href="{% url wg_view_record name=wg.acronym %}{{d.rev}}/">{% endifequal %}{{ d.rev }}{% ifequal snapshot d.rev %}</strong>{% else %}</a>{% endifequal %} {% endifnotequal %}{% endfor %}
 {% endblock %}
 
 {% block record_metatable %}
diff --git a/ietf/templates/wgrecord/record_tab_history.html b/ietf/templates/wgrecord/record_tab_history.html
index 638ff50a5..f681ad914 100644
--- a/ietf/templates/wgrecord/record_tab_history.html
+++ b/ietf/templates/wgrecord/record_tab_history.html
@@ -10,7 +10,7 @@ Copyright The IETF Trust 2011, All Rights Reserved
 <h2 style="margin-top:1em;">WG History</h2>
 {% if user|in_group:"Area_Director,Secretariat" %}
 <div style="margin-bottom:8px" id="history_actions">
-  <span id="rec_add_comment_button" class="yui-button yui-link-button" style="margin-left:2px;"><span class="first-child"><a href="{% url rec_add_comment name=wg.acronym %}">Add comment</a></span></span>
+  <span id="wg_add_comment_button" class="yui-button yui-link-button" style="margin-left:2px;"><span class="first-child"><a href="{% url wg_add_comment name=wg.acronym %}">Add comment</a></span></span>
 </div>
 {% endif %}
 
diff --git a/ietf/templates/wgrecord/record_tab_writeup.html b/ietf/templates/wgrecord/record_tab_writeup.html
index 47ec5e61b..f080021d1 100644
--- a/ietf/templates/wgrecord/record_tab_writeup.html
+++ b/ietf/templates/wgrecord/record_tab_writeup.html
@@ -10,8 +10,8 @@ Copyright The IETF Trust 2011, All Rights Reserved
 {% if user|in_group:"Area_Director,Secretariat" %}
 <div style="background:#E0E0FF">
 <p align=right>
-<span id="rec_edit_announce_button" class="yui-button yui-link-button"><span class="first-child">
-<a href="{% url rec_announcement_text name=wg.acronym ann="review" %}">Edit WG Review Announcement</a>
+<span id="wg_edit_announce_button" class="yui-button yui-link-button"><span class="first-child">
+<a href="{% url wg_announcement_text name=wg.acronym ann="review" %}">Edit WG Review Announcement</a>
 </span></span>
 </p>
 {% endif %}
@@ -24,8 +24,8 @@ Copyright The IETF Trust 2011, All Rights Reserved
 {% if user|in_group:"Area_Director,Secretariat" %}
 <div style="background:#E0E0FF">
 <p align=right>
-<span id="rec_edit_announce_button" class="yui-button yui-link-button"><span class="first-child">
-<a href="{% url rec_announcement_text name=wg.acronym ann="action" %}">Edit WG Action Announcement</a>
+<span id="wg_edit_announce_button" class="yui-button yui-link-button"><span class="first-child">
+<a href="{% url wg_announcement_text name=wg.acronym ann="action" %}">Edit WG Action Announcement</a>
 </span></span>
 </p>
 {% endif %}
diff --git a/ietf/templates/wgrecord/search_result_row.html b/ietf/templates/wgrecord/search_result_row.html
index 18a109661..695940dba 100644
--- a/ietf/templates/wgrecord/search_result_row.html
+++ b/ietf/templates/wgrecord/search_result_row.html
@@ -5,7 +5,7 @@ Copyright The IETF Trust 2011, All Rights Reserved
 {% load ietf_filters %}
 <tr class="{% cycle oddrow,evenrow %}">
 <td class="acronym">
-<a href="{% url record_view name=wg.acronym %}">{{ wg.acronym|safe }}</a>
+<a href="{% url wg_view_record name=wg.acronym %}">{{ wg.acronym|safe }}</a>
 </td>
 <td class="title">{{ wg.name }}</td>
 {% include "wgrecord/date_column.html" %}
diff --git a/ietf/templates/wgrecord/status_columns.html b/ietf/templates/wgrecord/status_columns.html
index cb735d174..84e8d3095 100644
--- a/ietf/templates/wgrecord/status_columns.html
+++ b/ietf/templates/wgrecord/status_columns.html
@@ -1,7 +1,7 @@
 {% comment %}
 Copyright The IETF Trust 2011, All Rights Reserved
 {% endcomment %}
-{% load ietf_filters ietf_streams %}{% load rec_ballot_icon %}
+{% load ietf_filters ietf_streams %}{% load wg_ballot_icon %}
 <td class="status">
 {% if wg.charter %}
 {{ wg.charter.charter_state|safe }}
@@ -13,5 +13,5 @@ Copyright The IETF Trust 2011, All Rights Reserved
 {% block extra_status %}{% endblock %}
 </td>
 <td class="ballot">
-{% ifequal wg.charter.charter_state_id "iesgrev" %}{% rec_ballot_icon wg.acronym %}{% endifequal %}
+{% ifequal wg.charter.charter_state_id "iesgrev" %}{% wg_ballot_icon wg.acronym %}{% endifequal %}
 </td>
diff --git a/ietf/templates/wgrecord/submit.html b/ietf/templates/wgrecord/submit.html
index 45206229b..166994c6b 100644
--- a/ietf/templates/wgrecord/submit.html
+++ b/ietf/templates/wgrecord/submit.html
@@ -40,7 +40,7 @@ Charter submission for {{ wg.acronym }}
     <tr>
       <td></td>
       <td class="actions">
-        <a href="{% url record_view name=wg.acronym %}">Back</a>
+        <a href="{% url wg_view_record name=wg.acronym %}">Back</a>
         <input type="submit" value="Submit"/>
       </td>
     </tr>
diff --git a/ietf/utils/test_data.py b/ietf/utils/test_data.py
index 4e2f5fa41..e825097f2 100644
--- a/ietf/utils/test_data.py
+++ b/ietf/utils/test_data.py
@@ -60,6 +60,20 @@ def make_test_data():
         group=area,
         email=email)
 
+    # ex-ad
+    u = User.objects.create(username="exad")
+    ad = p = Person.objects.create(
+        name="Exaread Irector",
+        ascii="Exaread Irector",
+        user=u)
+    email = Email.objects.create(
+        address="exaread@ietf.org",
+        person=p)
+    Role.objects.create(
+        name_id="ex-ad",
+        group=area,
+        email=email)
+
     # create a bunch of ads for swarm tests
     for i in range(1, 10):
         u = User.objects.create(username="ad%s" % i)
diff --git a/ietf/wgrecord/feeds.py b/ietf/wgrecord/feeds.py
index ac90f4206..74dbaed07 100644
--- a/ietf/wgrecord/feeds.py
+++ b/ietf/wgrecord/feeds.py
@@ -28,7 +28,7 @@ class GroupComments(Feed):
     def link(self, obj):
 	if obj is None:
 	    raise FeedDoesNotExist
-	return reverse('record_view', kwargs={'name': obj.acronym})
+	return reverse('wg_view_record', kwargs={'name': obj.acronym})
 
     def description(self, obj):
 	return self.title(obj)
@@ -38,13 +38,13 @@ class GroupComments(Feed):
         for h in history:
             gh = find_history_active_at(obj, h['date'])
             if gh:
-                h['chairs'] = map(lambda x: x.email.person.name, gh.rolehistory_set.filter(name__slug="chair"))
-                h['secr'] = map(lambda x: x.email.person.name, gh.rolehistory_set.filter(name__slug="secr"))
-                h['techadv'] = map(lambda x: x.email.person.name, gh.rolehistory_set.filter(name__slug="techadv"))
+                h['chairs'] = [x.email.person.name for x in gh.rolehistory_set.filter(name__slug="chair")]
+                h['secr'] = [x.email.person.name for x in gh.rolehistory_set.filter(name__slug="secr")]
+                h['techadv'] = [x.email.person.name for x in gh.rolehistory_set.filter(name__slug="techadv")]
             else:
-                h['chairs'] = map(lambda x: x.email.person.name, obj.role_set.filter(name__slug="chair"))
-                h['secr'] = map(lambda x: x.email.person.name, obj.role_set.filter(name__slug="secr"))
-                h['techadv'] = map(lambda x: x.email.person.name, obj.role_set.filter(name__slug="techadv"))
+                h['chairs'] = [x.email.person.name for x in obj.role_set.filter(name__slug="chair")]
+                h['secr'] = [x.email.person.name for x in obj.role_set.filter(name__slug="secr")]
+                h['techadv'] = [x.email.person.name for x in obj.role_set.filter(name__slug="techadv")]
             dh = find_history_active_at(obj.charter, h['date'])
             if dh:
                 h['rev'] = dh.rev
@@ -59,7 +59,7 @@ class GroupComments(Feed):
         return history
 
     def item_link(self, obj):
-        return reverse('record_view', kwargs={'name': obj['group'].acronym})
+        return reverse('wg_view_record', kwargs={'name': obj['group'].acronym})
 
     def item_pubdate(self, obj):
 	return obj['date']
diff --git a/ietf/wgrecord/mails.py b/ietf/wgrecord/mails.py
index 8e36f68e6..03da1318b 100644
--- a/ietf/wgrecord/mails.py
+++ b/ietf/wgrecord/mails.py
@@ -32,5 +32,5 @@ def email_secretariat(request, wg, type, text):
               "Regarding WG %s: %s" % (wg.acronym, types[type]),
               "wgrecord/email_secretariat.txt",
               dict(text=text,
-                   url=settings.IDTRACKER_BASE_URL + urlreverse('record_view', kwargs=dict(name=wg.acronym))))
+                   url=settings.IDTRACKER_BASE_URL + urlreverse('wg_view_record', kwargs=dict(name=wg.acronym))))
 
diff --git a/ietf/wgrecord/models.py b/ietf/wgrecord/models.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/ietf/wgrecord/templatetags/rec_ballot_icon.py b/ietf/wgrecord/templatetags/wg_ballot_icon.py
similarity index 88%
rename from ietf/wgrecord/templatetags/rec_ballot_icon.py
rename to ietf/wgrecord/templatetags/wg_ballot_icon.py
index ab490b721..712e36e4f 100644
--- a/ietf/wgrecord/templatetags/rec_ballot_icon.py
+++ b/ietf/wgrecord/templatetags/wg_ballot_icon.py
@@ -42,11 +42,7 @@ def render_ballot_icon(context, name):
     latest_positions = []
     for p in active_ads:
         p_pos = list(GroupBallotPositionDocEvent.objects.filter(doc=doc, ad=p).order_by("-time"))
-        if p_pos == []:
-            pos = GroupBallotPositionDocEvent(doc=doc, ad=p, by=p)
-            pos.save()
-            latest_positions.append(pos)
-        else:
+        if p_pos != []:
             latest_positions.append(p_pos[0])
     for p in latest_positions:
         if not p.pos_id:
@@ -66,12 +62,12 @@ def render_ballot_icon(context, name):
     return render_ballot_icon2(wg.acronym, red,yellow,green,gray,blank, my, adId)+"<!-- adId="+str(adId)+" my="+str(my)+"-->"
 
 def render_ballot_icon2(acronym, red,yellow,green,gray,blank, my, adId):
-    edit_position_url = urlreverse('rec_edit_position', kwargs=dict(name=acronym))
+    edit_position_url = urlreverse('wg_edit_position', kwargs=dict(name=acronym))
     if adId:
-        res_cm = ' oncontextmenu="editRecBallot(\''+str(edit_position_url)+'\');return false;"'
+        res_cm = ' oncontextmenu="editWGBallot(\''+str(edit_position_url)+'\');return false;"'
     else:
         res_cm = ''
-    res = '<table class="ballot_icon" title="IESG Review (click to show more, right-click to edit position)" onclick="showRecBallot(\'' + acronym + '\',\'' + str(edit_position_url) + '\')"'+res_cm+'>'
+    res = '<table class="ballot_icon" title="IESG Review (click to show more, right-click to edit position)" onclick="showWGBallot(\'' + acronym + '\',\'' + str(edit_position_url) + '\')"'+res_cm+'>'
     for y in range(3):
         res = res + "<tr>"
         for x in range(5):
@@ -115,7 +111,7 @@ def do_ballot_icon(parser, token):
         raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[0]
     return BallotIconNode(docName)
 
-register.tag('rec_ballot_icon', do_ballot_icon)
+register.tag('wg_ballot_icon', do_ballot_icon)
 
 @register.filter
 def my_position(doc, user):
diff --git a/ietf/wgrecord/tests.py b/ietf/wgrecord/tests.py
index a646f98d6..7132b1f22 100644
--- a/ietf/wgrecord/tests.py
+++ b/ietf/wgrecord/tests.py
@@ -2,14 +2,40 @@
 
 import os
 import unittest
+import django.test
 from django.conf import settings
 from ietf.utils.test_utils import SimpleUrlTestCase
+from ietf.utils.test_runner import mail_outbox
+from ietf.utils.test_data import make_test_data
+from ietf.utils.test_utils import SimpleUrlTestCase, RealDatabaseTest, login_testing_unauthorized
 
-class WgRecUrlTestCase(SimpleUrlTestCase):
+import datetime
+from pyquery import PyQuery
+from tempfile import NamedTemporaryFile
+
+from django.contrib.auth.models import User
+from doc.models import *
+from group.models import *
+from name.models import *
+from person.models import *
+from name.utils import name
+
+from utils import *
+
+class WgUrlTestCase(SimpleUrlTestCase):
     def testUrls(self):
         self.doTestUrls(__file__)
 
-class WgRecFileTestCase(unittest.TestCase):
+    def setUp(self, *args, **kwargs):
+        super(WgUrlTestCase, self).setUp(*args, **kwargs)
+        # Make test data (because we use the new schema)
+        make_test_data()
+        # Make sure all relevant names are created 
+        type_charter = name(DocTypeName, "charter", "Charter")
+        active = name(GroupStateName, "active", "Active")
+        approved = name(CharterDocStateName, "approved", "Approved")
+
+class WgFileTestCase(django.test.TestCase):
     def testFileExistence(self):
         print "     Testing if WG charter texts exist locally"
         fpath = os.path.join(settings.CHARTER_PATH, "charter-ietf-example-01.txt")
@@ -19,4 +45,317 @@ class WgRecFileTestCase(unittest.TestCase):
             print "Remember to set CHARTER_PATH in settings_local.py\n"
         else:
             print "OK   (seem to exist)"
-    
+
+class WgStateTestCase(django.test.TestCase):
+    fixtures = ['names']
+
+    def test_change_state(self):
+        make_test_data()
+        # Make sure all relevant names are created 
+        type_charter = name(DocTypeName, "charter", "Charter")
+        active = name(GroupStateName, "active", "Active")
+        notrev=name(CharterDocStateName, slug="notrev", name="Not currently under review")
+        infrev=name(CharterDocStateName, slug="infrev", name="Informal IESG review")
+        intrev=name(CharterDocStateName, slug="intrev", name="Internal review")
+        extrev=name(CharterDocStateName, slug="extrev", name="External review")
+        iesgrev=name(CharterDocStateName, slug="iesgrev", name="IESG review")
+        approved=name(CharterDocStateName, slug="approved", name="Approved")
+
+        # And make a charter for group
+        group = Group.objects.get(acronym="mars")
+        charter = set_or_create_charter(group)
+        
+        charter.charter_state = infrev
+        charter.save()
+
+        # -- Test change state --
+        url = urlreverse('wg_change_state', kwargs=dict(name=group.acronym))
+        login_testing_unauthorized(self, "secretary", url)
+
+        first_state = charter.charter_state
+
+        # normal get
+        r = self.client.get(url)
+        self.assertEquals(r.status_code, 200)
+        q = PyQuery(r.content)
+        self.assertEquals(len(q('form select[name=state]')), 1)
+        
+        # faulty post
+        r = self.client.post(url, dict(state="foobarbaz"))
+        self.assertEquals(r.status_code, 200)
+        q = PyQuery(r.content)
+        self.assertTrue(len(q('form ul.errorlist')) > 0)
+        self.assertEquals(charter.charter_state, first_state)
+        
+        # change state
+        for s in ("intrev", "extrev", "iesgrev", "approved"):
+            events_before = charter.docevent_set.count()
+            mailbox_before = len(mail_outbox)
+        
+            r = self.client.post(url, dict(state="active", charter_state=s, message="test message"))
+            self.assertEquals(r.status_code, 302)
+        
+            charter = Document.objects.get(name="charter-ietf-%s" % group.acronym)
+            self.assertEquals(charter.charter_state_id, s)
+            self.assertEquals(charter.docevent_set.count(), events_before + 1)
+            self.assertTrue("State changed" in charter.docevent_set.all()[0].desc)
+            if s == "extrev":
+                self.assertEquals(len(mail_outbox), mailbox_before + 2)
+                self.assertTrue("State changed" in mail_outbox[-1]['Subject'])
+                self.assertTrue("State changed" in mail_outbox[-2]['Subject'])
+            else:
+                self.assertEquals(len(mail_outbox), mailbox_before + 1)
+                if s == "approved":
+                    self.assertTrue("Charter approved" in mail_outbox[-1]['Subject'])
+                else:
+                    self.assertTrue("State changed" in mail_outbox[-1]['Subject'])
+                    
+    def test_conclude(self):
+        make_test_data()
+        # Make sure all relevant names are created 
+        type_charter = name(DocTypeName, "charter", "Charter")
+        active = name(GroupStateName, "active", "Active")
+        notrev=name(CharterDocStateName, slug="notrev", name="Not currently under review")
+        infrev=name(CharterDocStateName, slug="infrev", name="Informal IESG review")
+        intrev=name(CharterDocStateName, slug="intrev", name="Internal review")
+        extrev=name(CharterDocStateName, slug="extrev", name="External review")
+        iesgrev=name(CharterDocStateName, slug="iesgrev", name="IESG review")
+        approved=name(CharterDocStateName, slug="approved", name="Approved")
+
+        # And make a charter for group
+        group = Group.objects.get(acronym="mars")
+        charter = set_or_create_charter(group)
+        
+        charter.charter_state = approved
+        charter.save()
+        
+        # -- Test conclude WG --
+        url = urlreverse('wg_conclude', kwargs=dict(name=group.acronym))
+        login_testing_unauthorized(self, "secretary", url)
+
+        # normal get
+        r = self.client.get(url)
+        self.assertEquals(r.status_code, 200)
+        q = PyQuery(r.content)
+        self.assertEquals(len(q('form textarea[name=instructions]')), 1)
+        
+        # faulty post
+        r = self.client.post(url, dict(instructions="")) # No instructions
+        self.assertEquals(r.status_code, 200)
+        q = PyQuery(r.content)
+        self.assertTrue(len(q('form ul.errorlist')) > 0)
+        group = Group.objects.get(acronym="mars")
+
+        # conclusion request
+        r = self.client.post(url, dict(instructions="Test instructions"))
+        self.assertEquals(r.status_code, 302)
+        # The WG remains active until the state is set to conclude via change_state
+        self.assertEquals(group.state_id, "active") 
+
+class WgInfoTestCase(django.test.TestCase):
+    fixtures = ['names']
+
+    def test_create(self):
+        make_test_data()
+        # Make sure all relevant names are created 
+        type_charter = name(DocTypeName, "charter", "Charter")
+        active = name(GroupStateName, "active", "Active")
+        notrev=name(CharterDocStateName, slug="notrev", name="Not currently under review")
+        infrev=name(CharterDocStateName, slug="infrev", name="Informal IESG review")
+        intrev=name(CharterDocStateName, slug="intrev", name="Internal review")
+        extrev=name(CharterDocStateName, slug="extrev", name="External review")
+        iesgrev=name(CharterDocStateName, slug="iesgrev", name="IESG review")
+        approved=name(CharterDocStateName, slug="approved", name="Approved")
+
+        # -- Test WG creation --
+        url = urlreverse('wg_create')
+        login_testing_unauthorized(self, "secretary", url)
+
+        num_wgs = len(Group.objects.filter(type="wg"))
+
+        # normal get
+        r = self.client.get(url)
+        self.assertEquals(r.status_code, 200)
+        q = PyQuery(r.content)
+        self.assertEquals(len(q('form input[name=acronym]')), 1)
+        
+        # faulty post
+        r = self.client.post(url, dict(acronym="foobarbaz")) # No name
+        self.assertEquals(r.status_code, 200)
+        q = PyQuery(r.content)
+        self.assertTrue(len(q('form ul.errorlist')) > 0)
+        self.assertEquals(len(Group.objects.filter(type="wg")), num_wgs)
+
+        # creation
+        r = self.client.post(url, dict(acronym="testwg", name="Testing WG"))
+        self.assertEquals(r.status_code, 302)
+        self.assertEquals(len(Group.objects.filter(type="wg")), num_wgs + 1)
+        group = Group.objects.get(acronym="testwg")
+        self.assertEquals(group.name, "Testing WG")
+        # check that a charter was created with the correct name
+        self.assertEquals(group.charter.name, "charter-ietf-testwg")
+        # and that it has no revision
+        self.assertEquals(group.charter.rev, "")
+
+
+    def test_edit_info(self):
+        make_test_data()
+        # Make sure all relevant names are created 
+        type_charter = name(DocTypeName, "charter", "Charter")
+        active = name(GroupStateName, "active", "Active")
+        notrev=name(CharterDocStateName, slug="notrev", name="Not currently under review")
+        infrev=name(CharterDocStateName, slug="infrev", name="Informal IESG review")
+        intrev=name(CharterDocStateName, slug="intrev", name="Internal review")
+        extrev=name(CharterDocStateName, slug="extrev", name="External review")
+        iesgrev=name(CharterDocStateName, slug="iesgrev", name="IESG review")
+        approved=name(CharterDocStateName, slug="approved", name="Approved")
+
+        # And make a charter for group
+        group = Group.objects.get(acronym="mars")
+        charter = set_or_create_charter(group)
+        
+        url = urlreverse('wg_edit_info', kwargs=dict(name=group.acronym))
+        login_testing_unauthorized(self, "secretary", url)
+
+        # normal get
+        r = self.client.get(url)
+        self.assertEquals(r.status_code, 200)
+        q = PyQuery(r.content)
+        self.assertEquals(len(q('form select[name=parent]')), 1)
+        self.assertEquals(len(q('form input[name=acronym]')), 1)
+
+        # faulty post
+        Group.objects.create(name="Collision Test Group", acronym="collide")
+        r = self.client.post(url, dict(acronym="collide"))
+        self.assertEquals(r.status_code, 200)
+        q = PyQuery(r.content)
+        self.assertTrue(len(q('form ul.errorlist')) > 0)
+
+        # Create old acronym
+        group.acronym = "oldmars"
+        group.save()
+        save_group_in_history(group)
+        group.acronym = "mars"
+        group.save()
+
+        # post with warning
+        r = self.client.post(url, dict(acronym="oldmars"))
+        self.assertEquals(r.status_code, 200)
+        q = PyQuery(r.content)
+        self.assertTrue(len(q('form ul.errorlist')) > 0)
+        
+        # edit info
+        r = self.client.post(url,
+                             dict(name="Mars Not Special Interest Group",
+                                  acronym="mnsig",
+                                  parent=2,
+                                  ad=1,
+                                  chairs="aread@ietf.org",
+                                  secr="aread@ietf.org",
+                                  techadv="aread@ietf.org",
+                                  list_email="mars@mail",
+                                  list_subscribe="subscribe.mars",
+                                  list_archive="archive.mars",
+                                  urls="http://mars.mars (MARS site)"
+                                  ))
+        self.assertEquals(r.status_code, 302)
+
+        group = Group.objects.get(acronym="mnsig")
+        self.assertEquals(group.name, "Mars Not Special Interest Group")
+        self.assertEquals(group.parent_id, 2)
+        self.assertEquals(group.ad.name, "Aread Irector")
+        for k in ("chair", "secr", "techadv"):
+            self.assertEquals(group.role_set.filter(name="chair")[0].email.address, "aread@ietf.org")
+        self.assertEquals(group.list_email, "mars@mail")
+        self.assertEquals(group.list_subscribe, "subscribe.mars")
+        self.assertEquals(group.list_archive, "archive.mars")
+        self.assertEquals(group.groupurl_set.all()[0].url, "http://mars.mars")
+        self.assertEquals(group.groupurl_set.all()[0].name, "MARS site")
+
+    def test_edit_telechat_date(self):
+        make_test_data()
+        # Make sure all relevant names are created 
+        type_charter = name(DocTypeName, "charter", "Charter")
+        active = name(GroupStateName, "active", "Active")
+        notrev=name(CharterDocStateName, slug="notrev", name="Not currently under review")
+        infrev=name(CharterDocStateName, slug="infrev", name="Informal IESG review")
+        intrev=name(CharterDocStateName, slug="intrev", name="Internal review")
+        extrev=name(CharterDocStateName, slug="extrev", name="External review")
+        iesgrev=name(CharterDocStateName, slug="iesgrev", name="IESG review")
+        approved=name(CharterDocStateName, slug="approved", name="Approved")
+
+        # And make a charter for group
+        group = Group.objects.get(acronym="mars")
+        charter = set_or_create_charter(group)
+        
+        url = urlreverse('wg_edit_info', kwargs=dict(name=group.acronym))
+        login_testing_unauthorized(self, "secretary", url)
+
+        from ietf.iesg.models import TelechatDates
+
+        # add to telechat
+        self.assertTrue(not charter.latest_event(TelechatDocEvent, "scheduled_for_telechat"))
+        telechat_date = TelechatDates.objects.all()[0].date1.isoformat()
+        r = self.client.post(url, dict(name=group.name, acronym=group.acronym, telechat_date=telechat_date))
+        self.assertEquals(r.status_code, 302)
+
+        charter = Document.objects.get(name=charter.name)
+        self.assertTrue(charter.latest_event(TelechatDocEvent, "scheduled_for_telechat"))
+        self.assertEquals(charter.latest_event(TelechatDocEvent, "scheduled_for_telechat").telechat_date, TelechatDates.objects.all()[0].date1)
+
+        # change telechat
+        telechat_date = TelechatDates.objects.all()[0].date2.isoformat()
+        r = self.client.post(url, dict(name=group.name, acronym=group.acronym, telechat_date=telechat_date))
+        self.assertEquals(r.status_code, 302)
+
+        charter = Document.objects.get(name=charter.name)
+        self.assertEquals(charter.latest_event(TelechatDocEvent, "scheduled_for_telechat").telechat_date, TelechatDates.objects.all()[0].date2)
+
+        # remove from agenda
+        telechat_date = ""
+        r = self.client.post(url, dict(name=group.name, acronym=group.acronym, telechat_date=telechat_date))
+        self.assertEquals(r.status_code, 302)
+
+        charter = Document.objects.get(name=charter.name)
+        self.assertTrue(not charter.latest_event(TelechatDocEvent, "scheduled_for_telechat").telechat_date)
+
+    def test_submit_charter(self):
+        make_test_data()
+        # Make sure all relevant names are created 
+        type_charter = name(DocTypeName, "charter", "Charter")
+        active = name(GroupStateName, "active", "Active")
+        notrev=name(CharterDocStateName, slug="notrev", name="Not currently under review")
+        infrev=name(CharterDocStateName, slug="infrev", name="Informal IESG review")
+        intrev=name(CharterDocStateName, slug="intrev", name="Internal review")
+        extrev=name(CharterDocStateName, slug="extrev", name="External review")
+        iesgrev=name(CharterDocStateName, slug="iesgrev", name="IESG review")
+        approved=name(CharterDocStateName, slug="approved", name="Approved")
+
+        # And make a charter for group
+        group = Group.objects.get(acronym="mars")
+        charter = set_or_create_charter(group)
+
+        url = urlreverse('wg_submit', kwargs=dict(name=group.acronym))
+        login_testing_unauthorized(self, "secretary", url)
+
+        # normal get
+        r = self.client.get(url)
+        self.assertEquals(r.status_code, 200)
+        q = PyQuery(r.content)
+        self.assertEquals(len(q('form input[name=txt]')), 1)
+
+        prev_rev = charter.rev
+
+        file = NamedTemporaryFile()
+        file.write("Test content")
+        file.seek(0)
+
+        r = self.client.post(url, dict(txt=file))
+        self.assertEquals(r.status_code, 302)
+
+        file.close()
+
+        charter = Document.objects.get(name="charter-ietf-mars")
+        self.assertEquals(charter.rev, next_revision(prev_rev))
+        self.assertTrue("new_revision" in charter.latest_event().type)
+
diff --git a/ietf/wgrecord/testurl.list b/ietf/wgrecord/testurl.list
new file mode 100644
index 000000000..7d1eb8c91
--- /dev/null
+++ b/ietf/wgrecord/testurl.list
@@ -0,0 +1,55 @@
+200	/
+200	/wgrecord/
+
+# In IESG process
+200  	/wgrecord/in_process/
+
+# by AD
+# current AD -- needs to be updated at some point
+200	/wgrecord/ad/aread.irector/
+# former AD
+200	/wgrecord/ad/exaread.irector/
+404	/wgrecord/ad/no.body/
+
+# create
+302	/wgrecord/create/
+
+# WG
+200	/wgrecord/mars/
+200     /wgrecord/mars/00-00/
+200	/wgrecord/mars/_ballot.data
+
+# Edit WG
+302     /wgrecord/mars/edit/state/
+302     /wgrecord/mars/edit/info/
+302     /wgrecord/mars/edit/conclude/
+302     /wgrecord/mars/edit/addcomment/
+302     /wgrecord/mars/edit/action/
+302     /wgrecord/mars/edit/review/
+
+# ballots
+302     /wgrecord/mars/edit/position/
+302     /wgrecord/mars/edit/sendballotcomment/
+302     /wgrecord/mars/edit/approveballot/
+
+# submission of charters
+302     /wgrecord/mars/submit/
+
+# search
+200	/wgrecord/search/
+302	/wgrecord/search/?name=martian
+200     /wgrecord/search/?name=something
+200     /wgrecord/search/?name=something&by=acronym&acronym=some
+200	/wgrecord/search/?name=something&by=state&state=active&charter_state=
+200	/wgrecord/search/?name=something&by=state&state=&charter_state=approved
+200	/wgrecord/search/?name=something&by=ad&ad=1
+200     /wgrecord/search/?name=something&by=area&area=2
+200	/wgrecord/search/?name=something&by=anyfield&anyfield=something
+200	/wgrecord/search/?name=something&by=eacronym&eacronym=someold
+
+# searchPerson (ajax)
+200     /wgrecord/searchPerson/
+
+# 
+
+
diff --git a/ietf/wgrecord/urls.py b/ietf/wgrecord/urls.py
index 7be41f3a2..d42a72dcd 100644
--- a/ietf/wgrecord/urls.py
+++ b/ietf/wgrecord/urls.py
@@ -14,16 +14,16 @@ urlpatterns += patterns('',
     (r'^searchPerson/$', views_search.search_person),
     url(r'^ad/(?P<name>[A-Za-z0-9.-]+)/$', views_search.by_ad, name="wg_search_by_ad"),
     url(r'^in_process/$', views_search.in_process, name="wg_search_in_process"),
-    url(r'^(?P<name>[A-Za-z0-9._-]+)/((?P<rev>[0-9][0-9](-[0-9][0-9])?)/)?((?P<tab>ballot|writeup|history)/)?$', views_rec.record_main, name="record_view"),
-    (r'^(?P<name>[A-Za-z0-9._-]+)/_ballot.data$', views_rec.record_ballot),
+    url(r'^(?P<name>[A-Za-z0-9._-]+)/((?P<rev>[0-9][0-9](-[0-9][0-9])?)/)?((?P<tab>ballot|writeup|history)/)?$', views_rec.wg_main, name="wg_view_record"),
+    (r'^(?P<name>[A-Za-z0-9._-]+)/_ballot.data$', views_rec.wg_ballot),
     url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/state/$', views_edit.change_state, name='wg_change_state'),
     url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/info/$', views_edit.edit_info, name='wg_edit_info'),
     url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/conclude/$', views_edit.conclude, name='wg_conclude'),
-    url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/addcomment/$', views_edit.add_comment, name='rec_add_comment'),
-    url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/(?P<ann>action|review)/$', views_ballot.announcement_text, name='rec_announcement_text'),
-    url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/position/$', views_ballot.edit_position, name='rec_edit_position'),
-    url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/sendballotcomment/$', views_ballot.send_ballot_comment, name='rec_send_ballot_comment'),
-    url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/approveballot/$', views_ballot.approve_ballot, name='rec_approve_ballot'),
+    url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/addcomment/$', views_edit.add_comment, name='wg_add_comment'),
+    url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/(?P<ann>action|review)/$', views_ballot.announcement_text, name='wg_announcement_text'),
+    url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/position/$', views_ballot.edit_position, name='wg_edit_position'),
+    url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/sendballotcomment/$', views_ballot.send_ballot_comment, name='wg_send_ballot_comment'),
+    url(r'^(?P<name>[A-Za-z0-9._-]+)/edit/approveballot/$', views_ballot.approve_ballot, name='wg_approve_ballot'),
     url(r'^(?P<name>[A-Za-z0-9._-]+)/submit/$', views_submit.submit, name='wg_submit'),
 
 )
diff --git a/ietf/wgrecord/utils.py b/ietf/wgrecord/utils.py
index d64f664a3..385192a43 100644
--- a/ietf/wgrecord/utils.py
+++ b/ietf/wgrecord/utils.py
@@ -1,9 +1,28 @@
 from django.conf import settings
 import re
 
-from redesign.group.models import GroupEvent
+from datetime import datetime
+from group.models import GroupEvent
+from doc.models import Document
 from ietf.utils.history import find_history_active_at
 
+def set_or_create_charter(wg):
+    try:
+        charter = Document.objects.get(name="charter-ietf-" + wg.acronym)
+    except Document.DoesNotExist:
+        charter = Document.objects.create(
+            name="charter-ietf-%s" % wg.acronym,
+            time=datetime.now(),
+            type_id="charter",
+            title=wg.name,
+            group=wg,
+            abstract=wg.name,
+            rev="",
+            )
+    wg.charter = charter
+    wg.save()
+    return charter
+
 def add_wg_comment(request, wg, text, ballot=None):
     if request:
         login = request.user.get_profile()
@@ -29,6 +48,24 @@ def log_state_changed(request, doc, by, prev_state, note=''):
     e.save()
     return e
 
+def log_group_state_changed(request, wg, by, note=''):
+    from group.models import GroupEvent
+
+    e = GroupEvent(group=wg, by=by)
+    if wg.state_id == "proposed":
+        e.type = "proposed"
+    elif wg.state_id == "active":
+        e.type = "started"
+    elif wg.state_id == "conclude":
+        e.type = "concluded"
+    e.desc = u"%s group" % e.type.capitalize()
+
+    if note:
+        e.desc += "<br>%s" % note
+
+    e.save()
+    return e
+
 def log_info_changed(request, wg, by, type=None, note=''):
     from group.models import GroupEvent
 
diff --git a/ietf/wgrecord/views_ballot.py b/ietf/wgrecord/views_ballot.py
index 21f936605..e03f05a12 100644
--- a/ietf/wgrecord/views_ballot.py
+++ b/ietf/wgrecord/views_ballot.py
@@ -96,7 +96,7 @@ def edit_position(request, name):
     except ObjectDoesNotExist:
         wglist = GroupHistory.objects.filter(acronym=name)
         if wglist:
-            return redirect('rec_edit_position', name=wglist[0].group.acronym)
+            return redirect('wg_edit_position', name=wglist[0].group.acronym)
         else:
             raise Http404
 
@@ -193,7 +193,7 @@ def edit_position(request, name):
                 qstr = "?return_to_url=%s" % return_to_url
                 if request.GET.get('ad'):
                     qstr += "&ad=%s" % request.GET.get('ad')
-                return HttpResponseRedirect(urlreverse("rec_send_ballot_comment", kwargs=dict(name=wg.acronym)) + qstr)
+                return HttpResponseRedirect(urlreverse("wg_send_ballot_comment", kwargs=dict(name=wg.acronym)) + qstr)
             else:
                 return HttpResponseRedirect(return_to_url)
     else:
@@ -226,7 +226,7 @@ def send_ballot_comment(request, name):
     except ObjectDoesNotExist:
         wglist = GroupHistory.objects.filter(acronym=name)
         if wglist:
-            return redirect('rec_send_ballot_comment', name=wglist[0].group.acronym)
+            return redirect('wg_send_ballot_comment', name=wglist[0].group.acronym)
         else:
             raise Http404
 
@@ -315,7 +315,7 @@ def announcement_text(request, name, ann):
     except ObjectDoesNotExist:
         wglist = GroupHistory.objects.filter(acronym=name)
         if wglist:
-            return redirect('rec_announcement_text', name=wglist[0].group.acronym)
+            return redirect('wg_announcement_text', name=wglist[0].group.acronym)
         else:
             raise Http404
 
@@ -349,7 +349,7 @@ def announcement_text(request, name, ann):
                 
                 doc.time = e.time
                 doc.save()
-        return redirect('record_view', name=wg.acronym)
+        return redirect('wg_view_record', name=wg.acronym)
     return render_to_response('wgrecord/announcement_text.html',
                               dict(doc=doc,
                                    announcement=ann,
@@ -366,7 +366,7 @@ def approve_ballot(request, name):
     except ObjectDoesNotExist:
         wglist = GroupHistory.objects.filter(acronym=name)
         if wglist:
-            return redirect('rec_approve_ballot', name=wglist[0].group.acronym)
+            return redirect('wg_approve_ballot', name=wglist[0].group.acronym)
         else:
             raise Http404
 
diff --git a/ietf/wgrecord/views_edit.py b/ietf/wgrecord/views_edit.py
index 2f8112e0b..017bea759 100644
--- a/ietf/wgrecord/views_edit.py
+++ b/ietf/wgrecord/views_edit.py
@@ -9,7 +9,7 @@ from django import forms
 from django.forms.util import ErrorList
 from django.core.exceptions import ObjectDoesNotExist
 
-from utils import log_state_changed, log_info_changed, update_telechat
+from utils import log_state_changed, log_group_state_changed, log_info_changed, update_telechat, add_wg_comment, set_or_create_charter
 from mails import email_secretariat
 from ietf.ietfauth.decorators import group_required
 from ietf.iesg.models import TelechatDates
@@ -19,7 +19,6 @@ from name.models import CharterDocStateName, GroupStateName, GroupTypeName, DocT
 from person.models import Person, Email
 from group.models import Group, GroupEvent, GroupHistory, GroupURL, Role, RoleHistory, save_group_in_history
 
-from utils import add_wg_comment
 from views_search import json_emails
     
 class ChangeStateForm(forms.Form):
@@ -45,14 +44,14 @@ def change_state(request, name):
     # Get WG by acronym, redirecting if there's a newer acronym
     try:
         wg = Group.objects.get(acronym=name)
+        charter = set_or_create_charter(wg)
     except ObjectDoesNotExist:
         wglist = GroupHistory.objects.filter(acronym=name)
         if wglist:
             return redirect('wg_change_state', name=wglist[0].group.acronym)
         else:
             raise Http404
-    # Get charter
-    charter = wg.charter if wg.charter else None
+
     initial_review = charter.latest_event(InitialReviewDocEvent, type="initial_review")
 
     login = request.user.get_profile()
@@ -60,7 +59,7 @@ def change_state(request, name):
     if request.method == 'POST':
         form = ChangeStateForm(request.POST)
         if form.is_valid():
-            if initial_review and form.cleaned_data['charter_state'].slug != "infrev" and initial_review.expires > datetime.now() and not form.cleaned_data['confirm_state']:
+            if charter.charter_state_id == "infrev" and initial_review and form.cleaned_data['charter_state'].slug != "infrev" and initial_review.expires > datetime.now() and not form.cleaned_data['confirm_state']:
                 form._errors['charter_state'] = "warning"
             else:
                 state = form.cleaned_data['state']
@@ -95,6 +94,8 @@ def change_state(request, name):
 
                     prev = wg.state
                     wg.state = state
+
+                    ge = log_group_state_changed(request, wg, login, comment)
                 
                     wg.save()
                 if change:
@@ -115,7 +116,7 @@ def change_state(request, name):
                             e.desc = "IESG process started in state <b>%s</b>" % charter.charter_state.name
                             e.save()
 
-                        if form.cleaned_data["initial_time"] != 0:
+                        if form.cleaned_data["charter_state"].slug == "infrev" and form.cleaned_data["initial_time"] and form.cleaned_data["initial_time"] != 0:
                             e = InitialReviewDocEvent()
                             e.type = "initial_review"
                             e.by = login
@@ -124,7 +125,7 @@ def change_state(request, name):
                             e.desc = "Initial review time expires %s" % e.expires.strftime("%Y-%m-%d")
                             e.save()
                 
-                return redirect('record_view', name=wg.acronym)
+                return redirect('wg_view_record', name=wg.acronym)
     else:
         if wg.state_id != "proposed":
             states = CharterDocStateName.objects.filter(slug__in=["infrev", "intrev", "extrev", "iesgrev", "approved"])
@@ -212,6 +213,7 @@ def edit_info(request, name=None):
     if request.path_info == reverse('wg_edit_info', kwargs={'name': name}):
         # Editing. Get group
         wg = get_object_or_404(Group, acronym=name)
+        charter = set_or_create_charter(wg)
         new_wg = False
     elif request.path_info == reverse('wg_create'):
         wg = None
@@ -219,14 +221,15 @@ def edit_info(request, name=None):
 
     login = request.user.get_profile()
 
-    if wg and wg.charter:
-        e = wg.charter.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
+    if not new_wg:
+        e = charter.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
         initial_telechat_date = e.telechat_date if e else None
     else:
         initial_telechat_date = None
 
     if request.method == 'POST':
         form = EditInfoForm(request.POST, initial=dict(telechat_date=initial_telechat_date))
+    
         if form.is_valid():
             if (new_wg or form.cleaned_data['acronym'] != wg.acronym) and not_valid_acronym(form.cleaned_data['acronym']) and not form.cleaned_data['confirm_acronym']:
                 try:
@@ -254,17 +257,9 @@ def edit_info(request, name=None):
                     e.save()
                 if not wg.charter:
                     # Create adjoined charter
-                    try:
-                        charter = Document.objects.get(name="charter-ietf-"+r["acronym"])
-                    except ObjectDoesNotExist:
-                        charter = Document(type=DocTypeName.objects.get(name="Charter"), 
-                                           title=r["name"], 
-                                           abstract=r["name"], 
-                                           name="charter-ietf-" + r["acronym"],
-                                           )
-                        charter.charter_state = CharterDocStateName.objects.get(slug="infrev")
-                        charter.group = wg
-                        charter.save()
+                    charter = set_or_create_charter(wg)
+                    charter.charter_state = CharterDocStateName.objects.get(slug="infrev")
+                    charter.save()
 
                     e = DocEvent(doc=charter, type="started_iesg_process")
                     e.time = datetime.now()
@@ -340,7 +335,7 @@ def edit_info(request, name=None):
                     attr = attr_role[0]
                     rname = attr_role[1]
                     new = get_sorted_string(attr, ",")
-                    old = map(lambda x: x.email.address, wg.role_set.filter(name__name=rname).order_by('email__address'))
+                    old = [x.email.address for x in wg.role_set.filter(name__name=rname).order_by('email__address')]
                     if new != old:
                         # Remove old roles and save them in history
                         for role in wg.role_set.filter(name__name=rname):
@@ -354,7 +349,7 @@ def edit_info(request, name=None):
 
                 # update urls
                 new_urls = get_sorted_string('urls', '\n')
-                old_urls = map(lambda x: x.url + " (" + x.name + ")", wg.groupurl_set.order_by('url'))
+                old_urls = [x.url + " (" + x.name + ")" for x in wg.groupurl_set.order_by('url')]
                 if new_urls != old_urls:
                     # Remove old urls
                     for u in wg.groupurl_set.all():
@@ -377,21 +372,21 @@ def edit_info(request, name=None):
                 if new_wg:
                     return redirect('wg_change_state', name=wg.acronym)
                 else:
-                    return redirect('record_view', name=wg.acronym)
+                    return redirect('wg_view_record', name=wg.acronym)
     else:
-        if wg:
-            init = dict(name=wg.name if wg.name else None,
+        if not new_wg:
+            init = dict(name=wg.name,
                         acronym=wg.acronym,
-                        chairs=json_emails(map(lambda x: x.email, wg.role_set.filter(name="Chair"))),
-                        secretaries=json_emails(map(lambda x: x.email, wg.role_set.filter(name="Secr"))),
-                        techadv=json_emails(map(lambda x: x.email, wg.role_set.filter(name="Techadv"))),
+                        chairs=json_emails([x.email for x in wg.role_set.filter(name="Chair")]),
+                        secretaries=json_emails([x.email for x in wg.role_set.filter(name="Secr")]),
+                        techadv=json_emails([x.email for x in wg.role_set.filter(name="Techadv")]),
                         charter=wg.charter.name if wg.charter else None,
                         ad=wg.ad.id if wg.ad else None,
                         parent=wg.parent.id if wg.parent else None,
                         list_email=wg.list_email if wg.list_email else None,
                         list_subscribe=wg.list_subscribe if wg.list_subscribe else None,
                         list_archive=wg.list_archive if wg.list_archive else None,
-                        urls=string.join(map(lambda x: x.url + " (" + x.name + ")", wg.groupurl_set.all()), "\n"),
+                        urls=string.join([x.url + " (" + x.name + ")" for x in wg.groupurl_set.all()], "\n"),
                         comments=wg.comments if wg.comments else None,
                         telechat_date=initial_telechat_date,
                         )
@@ -408,7 +403,7 @@ def edit_info(request, name=None):
                               context_instance=RequestContext(request))
 
 class ConcludeForm(forms.Form):
-    comment = forms.CharField(widget=forms.Textarea, label="Instructions", required=False)
+    instructions = forms.CharField(widget=forms.Textarea, required=True)
 
 @group_required('Area_Director','Secretariat')
 def conclude(request, name):
@@ -427,15 +422,11 @@ def conclude(request, name):
     if request.method == 'POST':
         form = ConcludeForm(request.POST)
         if form.is_valid():
-            comment = form.cleaned_data['comment']
-            save_group_in_history(wg)
-            
-            wg.state = GroupStateName.objects.get(name="Concluded")
-            wg.save()
+            instructions = form.cleaned_data['instructions']
 
-            email_secretariat(request, wg, "conclude", comment)
+            email_secretariat(request, wg, "conclude", instructions)
 
-            return redirect('record_view', name=wg.acronym)
+            return redirect('wg_view_record', name=wg.acronym)
     else:
         form = ConcludeForm()
 
@@ -463,7 +454,7 @@ def add_comment(request, name):
 
             #email_owner(request, doc, doc.ad, login,
             #            "A new comment added by %s" % login.name)
-            return redirect('record_view', name=wg.acronym)
+            return redirect('wg_view_record', name=wg.acronym)
     else:
         form = AddCommentForm()
   
diff --git a/ietf/wgrecord/views_rec.py b/ietf/wgrecord/views_rec.py
index f260371db..a40d1d5a1 100644
--- a/ietf/wgrecord/views_rec.py
+++ b/ietf/wgrecord/views_rec.py
@@ -35,7 +35,7 @@ def _get_html(key, filename):
     return content
 
 @decorator_from_middleware(GZipMiddleware)
-def record_main(request, name, rev, tab):
+def wg_main(request, name, rev, tab):
     if tab is None:
 	tab = "charter"
     try:
@@ -43,10 +43,13 @@ def record_main(request, name, rev, tab):
     except ObjectDoesNotExist:
         wglist = GroupHistory.objects.filter(acronym=name)
         if wglist:
-            return redirect('record_view', name=wglist[0].group.acronym)
+            return redirect('wg_view_record', name=wglist[0].group.acronym)
         else:
             raise Http404
 
+    if not wg.charter:
+        create_empty_charter(wg)
+
     if rev != None:
         charter = get_charter_for_revision(wg.charter, rev)
         gh = get_group_for_revision(wg, rev)
@@ -56,23 +59,23 @@ def record_main(request, name, rev, tab):
 
     info = {}
 
-    info['prev_acronyms'] = list(set(map(lambda x: x.acronym, wg.history_set.exclude(acronym=wg.acronym))))
-    prev_list_email = list(set(map(lambda x: x.list_email, wg.history_set.exclude(list_email=wg.list_email))))
+    info['prev_acronyms'] = list(set([x.acronym for x in wg.history_set.exclude(acronym=wg.acronym)]))
+    prev_list_email = list(set([x.list_email for x in wg.history_set.exclude(list_email=wg.list_email)]))
     if prev_list_email != [u'']:
         info['prev_list_email'] = prev_list_email
-    prev_list_subscribe = list(set(map(lambda x: x.list_email, wg.history_set.exclude(list_subscribe=wg.list_subscribe))))
+    prev_list_subscribe = list(set([x.list_email for x in wg.history_set.exclude(list_subscribe=wg.list_subscribe)]))
     if prev_list_subscribe != [u'']:
         info['prev_list_subscribe'] = prev_list_subscribe    
-    prev_list_archive = list(set(map(lambda x: x.list_archive, wg.history_set.exclude(list_archive=wg.list_archive))))
+    prev_list_archive = list(set([x.list_archive for x in wg.history_set.exclude(list_archive=wg.list_archive)]))
     if prev_list_archive != [u'']:
         info['prev_list_archive'] = prev_list_archive
-    info['chairs'] = map(lambda x: x.email.person.name, wg.role_set.filter(name__slug="chair"))
+    info['chairs'] = [x.email.person.name for x in wg.role_set.filter(name__slug="chair")]
     if hasattr(gh, 'rolehistory_set'):
-        info['history_chairs'] = map(lambda x: x.email.person.name, gh.rolehistory_set.filter(name__slug="chair"))
+        info['history_chairs'] = [x.email.person.name for x in gh.rolehistory_set.filter(name__slug="chair")]
     else:
-        info['history_chairs'] = map(lambda x: x.email.person.name, gh.role_set.filter(name__slug="chair"))
-    info['secr'] = map(lambda x: x.email.person.name, wg.role_set.filter(name__slug="secr"))
-    info['techadv'] = map(lambda x: x.email.person.name, wg.role_set.filter(name__slug="techadv"))
+        info['history_chairs'] = [x.email.person.name for x in gh.role_set.filter(name__slug="chair")]
+    info['secr'] = [x.email.person.name for x in wg.role_set.filter(name__slug="secr")]
+    info['techadv'] = [x.email.person.name for x in wg.role_set.filter(name__slug="techadv")]
 
     if charter:
         content = _get_html(
@@ -109,7 +112,8 @@ def record_main(request, name, rev, tab):
     versions = _get_versions(wg.charter) # Important: wg.charter not charter
     history = _get_history(wg)
 
-    info['last_update'] = history[0]['date']
+    if history:
+        info['last_update'] = history[0]['date']
 
     charter_text_url = charter.get_txt_url()
 
@@ -181,13 +185,13 @@ def _get_versions(charter, include_replaced=True):
         ov.append({"name": charter.name, "rev": charter.rev, "date":charter.time})
     return ov
 
-def record_ballot(request, name):
+def wg_ballot(request, name):
     try:
         wg = Group.objects.get(acronym=name)
     except ObjectDoesNotExist:
         wglist = GroupHistory.objects.filter(acronym=name)
         if wglist:
-            return redirect('record_view', name=wglist[0].group.acronym)
+            return redirect('wg_view_record', name=wglist[0].group.acronym)
         else:
             raise Http404
 
@@ -203,7 +207,7 @@ def record_ballot(request, name):
     latest_positions = []
     no_record = []
     for p in active_ads:
-        p_pos = list(GroupBallotPositionDocEvent.objects.filter(doc=doc, ad=p).order_by("-time"))
+        p_pos = list(GroupBallotPositionDocEvent.objects.filter(doc=wg.charter, ad=p).order_by("-time"))
         if p_pos != []:
             latest_positions.append(p_pos[0])
         else:
diff --git a/ietf/wgrecord/views_search.py b/ietf/wgrecord/views_search.py
index 99ef1a3c0..95ea7e4e7 100644
--- a/ietf/wgrecord/views_search.py
+++ b/ietf/wgrecord/views_search.py
@@ -101,27 +101,31 @@ def search_query(query_original, sort_by=None):
     elif by == "area":
         results = results.filter(parent=query["area"])
     elif by == "anyfield":
-        q_objs = []
-        q_objs.append(Q(name__icontains=query['anyfield']))
-        q_objs.append(Q(acronym__icontains=query['anyfield']))
-        q_objs.append(Q(state__name__icontains=query['anyfield']))
-        q_objs.append(Q(charter__charter_state__name__icontains=query['anyfield']))
-        q_objs.append(Q(ad__name__icontains=query['anyfield']))
-        q_objs.append(Q(parent__name__icontains=query['anyfield']))
-        q_objs.append(Q(history_set__acronym__icontains=query['anyfield']))
-        results = list(results.filter(reduce(lambda x, y: x | y, q_objs)))
+        q_objs = Q()
+        q_objs |= Q(acronym__icontains=query['anyfield'])
+        q_objs |= Q(state__name__icontains=query['anyfield'])
+        q_objs |= Q(charter__charter_state__name__icontains=query['anyfield'])
+        q_objs |= Q(ad__name__icontains=query['anyfield'])
+        q_objs |= Q(parent__name__icontains=query['anyfield'])
+        q_objs |= Q(history_set__acronym__icontains=query['anyfield'])
+        results = list(results.filter(*q_objs))
         # Search charter texts
         m = re.compile(query['anyfield'], re.IGNORECASE)
-        for g in Group.objects.filter(type="wg"):
+        if query['name']:
+            file_set = Group.objects.filter(type="wg", name__icontains=query["name"])
+        else:
+            file_set = Group.objects.filter(type="wg")
+        for g in file_set:
             charter = g.charter
-            try:
-                file = open(os.path.join(charter.get_file_path(), charter.name+"-"+charter.rev+".txt"))
-                for line in file:
-                    if m.search(line):
-                        results.append(g)
-                        break
-            except IOError:
-                pass # Pass silently for files not found
+            if charter:
+                try:
+                    file = open(os.path.join(charter.get_file_path(), charter.name+"-"+charter.rev+".txt"))
+                    for line in file:
+                        if m.search(line):
+                            results.append(g)
+                            break
+                except IOError:
+                    pass # Pass silently for files not found
     elif by == "eacronym":
         results = results.filter(history_set__acronym__icontains=query["eacronym"]).distinct()
 
@@ -192,7 +196,7 @@ def search_results(request):
         return render_to_response('wgrecord/search_results.html', {'recs':results, 'meta':meta}, context_instance=RequestContext(request))
     elif len(results)==1:
         wg = results[0]
-        return redirect('record_view', name=wg.acronym)
+        return redirect('wg_view_record', name=wg.acronym)
     else:
         return render_to_response('wgrecord/search_main.html', {'form':form, 'recs':results,'meta':meta}, context_instance=RequestContext(request))
         
diff --git a/ietf/wgrecord/views_submit.py b/ietf/wgrecord/views_submit.py
index 19c94df6c..b8ae2c566 100644
--- a/ietf/wgrecord/views_submit.py
+++ b/ietf/wgrecord/views_submit.py
@@ -8,20 +8,18 @@ from django.shortcuts import render_to_response, get_object_or_404, redirect
 from django.core.urlresolvers import reverse
 from django.template import RequestContext
 
+from ietf.ietfauth.decorators import group_required
 from django.core.exceptions import ObjectDoesNotExist
 from group.models import save_group_in_history
 from doc.models import Document, DocHistory, DocEvent, save_document_in_history
 from redesign.group.models import Group
 
 from django.conf import settings
-from utils import next_revision
+from utils import next_revision, set_or_create_charter
 
 class UploadForm(forms.Form):
     txt = forms.FileField(label=".txt format", required=True)
 
-    def __init__(self, *args, **kwargs):
-        super(UploadForm, self).__init__(*args, **kwargs)
-
     def save(self, wg):
         for ext in ['txt']:
             fd = self.cleaned_data[ext]
@@ -33,6 +31,7 @@ class UploadForm(forms.Form):
                 destination.write(chunk)
             destination.close()
 
+@group_required('Area_Director','Secretariat')
 def submit(request, name):
     # Get WG by acronym, redirecting if there's a newer acronym
     try:
@@ -44,7 +43,7 @@ def submit(request, name):
         else:
             raise Http404
     # Get charter
-    charter = wg.charter if wg.charter else None
+    charter = set_or_create_charter(wg)
 
     login = request.user.get_profile()
 
@@ -70,7 +69,7 @@ def submit(request, name):
             charter.time = datetime.now()
             charter.save()
 
-            return HttpResponseRedirect(reverse('record_view', kwargs={'name': wg.acronym}))
+            return HttpResponseRedirect(reverse('wg_view_record', kwargs={'name': wg.acronym}))
     else:
         form = UploadForm()
     return render_to_response('wgrecord/submit.html',
diff --git a/redesign/doc/models.py b/redesign/doc/models.py
index c02b128a1..19028e00d 100644
--- a/redesign/doc/models.py
+++ b/redesign/doc/models.py
@@ -54,7 +54,7 @@ class DocumentInfo(models.Model):
             raise NotImplemented
 
     def get_txt_url(self):
-        if self.type.slug == "charter":
+        if self.type_id == "charter":
             return "http://www.ietf.org/charters/"
         else:
             raise NotImplemented
@@ -97,7 +97,7 @@ class Document(DocumentInfo):
 
     def get_absolute_url(self):
         name = self.name
-        if self.type.slug == "charter":
+        if self.type_id == "charter":
             return urlreverse('record_view', kwargs={ 'name': self.group.acronym })
         else:
             if self.state == "rfc":
diff --git a/static/js/base.js b/static/js/base.js
index 2fbb36d8c..d0e6b38c2 100644
--- a/static/js/base.js
+++ b/static/js/base.js
@@ -75,7 +75,7 @@ function editBallot(editPositionUrl) {
     window.open(editPositionUrl);
 }
 
-function showRecBallot(acronym, editPositionUrl) {
+function showWGBallot(acronym, editPositionUrl) {
     var handleEditPosition = function() {
         IETF.ballotDialog.hide();
         window.location = IETF.editPositionUrl;
@@ -87,7 +87,7 @@ function showRecBallot(acronym, editPositionUrl) {
 
     if (!IETF.ballotDialog) {
         el = document.createElement("div");
-        el.innerHTML = '<div id="ballot_dialog" style="visibility:hidden;"><div class="hd">Positions for <span id="ballot_dialog_name">draft-ietf-foo-bar</span></span></div><div class="bd">  <div id="ballot_dialog_body" style="overflow-y:scroll; height:400px;"></div>   </div></div>';
+        el.innerHTML = '<div id="ballot_dialog" style="visibility:hidden;"><div class="hd">Positions for <span id="ballot_dialog_name">wgacronym</span></span></div><div class="bd">  <div id="ballot_dialog_body" style="overflow-y:scroll; height:400px;"></div>   </div></div>';
         document.getElementById("ietf-extras").appendChild(el);
 
         var buttons = [{text:"Close", handler:handleClose, isDefault:true}];
@@ -116,7 +116,7 @@ function showRecBallot(acronym, editPositionUrl) {
             argument: null
    	  }, null);
 }
-function editRecBallot(editPositionUrl) {
+function editWGBallot(editPositionUrl) {
     window.open(editPositionUrl);
 }
 
diff --git a/static/js/rec-change-state.js b/static/js/wg-change-state.js
similarity index 84%
rename from static/js/rec-change-state.js
rename to static/js/wg-change-state.js
index 413f2677a..49673cc1e 100644
--- a/static/js/rec-change-state.js
+++ b/static/js/wg-change-state.js
@@ -5,6 +5,7 @@ jQuery(document).ready(function () {
     }
 
     function setMessageDraft(state) {
+      if (jQuery("#id_state").val() != "conclude") {
 	if (message[state]) {
 	    if (state == "infrev") {
 		initial_time.show();
@@ -17,6 +18,9 @@ jQuery(document).ready(function () {
 	} else {
             jQuery("#id_message").val("");
 	}
+      } else {
+            jQuery("#id_message").val("");
+      }
     }
     
     jQuery("#id_charter_state").click(function (e) {
@@ -24,4 +28,5 @@ jQuery(document).ready(function () {
     });
 
     jQuery("#id_charter_state").click();
+    
 });
diff --git a/static/js/rec-edit-position.js b/static/js/wg-edit-position.js
similarity index 100%
rename from static/js/rec-edit-position.js
rename to static/js/wg-edit-position.js