From 328ecb08c300e3bee80a16ee64373d17661aa4fd Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Tue, 31 Jan 2012 17:38:27 +0000 Subject: [PATCH 01/72] Replace old charter branches with new branch based on conversion branch and some preliminary work on generalizing document handling [[Split portion of a mixed commit.]] - Legacy-Id: 3883.1 --- ietf/doc/proxy.py | 18 +-- ietf/group/proxy.py | 2 +- ietf/idrfc/generate_fixtures.py | 4 +- ietf/idrfc/urls.py | 9 +- ietf/idrfc/views_doc.py | 53 +++++- ietf/iesg/views.py | 37 +++-- ietf/ietfauth/urls.py | 1 - ietf/ipr/views.py | 2 +- ietf/templates/base.html | 2 +- ietf/templates/base_leftmenu.html | 2 + ietf/templates/iesg/agenda_wg.html | 14 +- ietf/templates/iesg/agenda_wg.txt | 6 +- ietf/templates/iesg/moderator_wg.html | 9 +- ietf/templates/wgcharter/wg_tab_base.html | 17 +- ietf/templates/wgcharter/wg_tab_charter.html | 2 +- ietf/templates/wginfo/wg_charterREDESIGN.html | 152 +++++++++++------- ietf/wgcharter/views.py | 13 +- ietf/wgcharter/views_ballot.py | 30 ++-- ietf/wginfo/views.py | 19 ++- redesign/importing/import-docs.py | 21 ++- redesign/importing/import-meetings.py | 11 +- redesign/importing/import-persons.py | 11 +- redesign/importing/import-reused-tables.py | 15 +- redesign/importing/import-roles.py | 7 +- 24 files changed, 287 insertions(+), 170 deletions(-) diff --git a/ietf/doc/proxy.py b/ietf/doc/proxy.py index 52be66ad0..d66d613c6 100644 --- a/ietf/doc/proxy.py +++ b/ietf/doc/proxy.py @@ -36,7 +36,7 @@ class InternetDraft(Document): #group = models.ForeignKey(Acronym, db_column='group_acronym_id') @property def group(self): - from group.proxy import Acronym as AcronymProxy + from ietf.group.proxy import Acronym as AcronymProxy g = super(InternetDraft, self).group return AcronymProxy().from_object(g) if g else None #filename = models.CharField(max_length=255, unique=True) @@ -365,13 +365,13 @@ class InternetDraft(Document): @property def mark_by(self): e = self.latest_event() - from person.proxy import IESGLogin as IESGLoginProxy + from ietf.person.proxy import IESGLogin as IESGLoginProxy return IESGLoginProxy().from_object(e.by) if e else None # job_owner = models.ForeignKey(IESGLogin, db_column='job_owner', related_name='documents') @property def job_owner(self): - from person.proxy import IESGLogin as IESGLoginProxy + from ietf.person.proxy import IESGLogin as IESGLoginProxy return IESGLoginProxy().from_object(self.ad) if self.ad else None #event_date = models.DateField(null=True) @@ -383,7 +383,7 @@ class InternetDraft(Document): #area_acronym = models.ForeignKey(Area) @property def area_acronym(self): - from group.proxy import Area + from ietf.group.proxy import Area g = super(InternetDraft, self).group # be careful with group which is proxied if g and g.type_id != "individ": return Area().from_object(g.parent) @@ -462,7 +462,7 @@ class InternetDraft(Document): @property def resurrect_requested_by(self): e = self.latest_event(type__in=("requested_resurrect", "completed_resurrect")) - from person.proxy import IESGLogin as IESGLoginProxy + from ietf.person.proxy import IESGLogin as IESGLoginProxy return IESGLoginProxy().from_object(e.by) if e and e.type == "requested_resurrect" else None #approved_in_minute = models.IntegerField(null=True, blank=True) @@ -522,7 +522,7 @@ class InternetDraft(Document): @property def an_sent_by(self): e = self.latest_event(type="iesg_approved") - from person.proxy import IESGLogin as IESGLoginProxy + from ietf.person.proxy import IESGLogin as IESGLoginProxy return IESGLoginProxy().from_object(e.by) if e else None #defer = models.BooleanField() @@ -535,7 +535,7 @@ class InternetDraft(Document): @property def defer_by(self): e = self.latest_event(type="changed_document", desc__startswith="State changed to IESG Evaluation - Defer") - from person.proxy import IESGLogin as IESGLoginProxy + from ietf.person.proxy import IESGLogin as IESGLoginProxy return IESGLoginProxy().from_object(e.by) if e else None #defer_date = models.DateField(null=True, blank=True) @@ -572,7 +572,7 @@ class InternetDraft(Document): # return remarks def active_positions(self): """Returns a list of dicts, with AD and Position tuples""" - from person.proxy import IESGLogin as IESGLoginProxy + from ietf.person.proxy import IESGLogin as IESGLoginProxy from ietf.doc.utils import active_ballot_positions res = [] @@ -892,7 +892,7 @@ class DraftLikeDocAlias(DocAlias): @property def ipr(self): - from ipr.models import IprDraftProxy + from ietf.ipr.models import IprDraftProxy return IprDraftProxy.objects.filter(doc_alias=self.pk) class Meta: diff --git a/ietf/group/proxy.py b/ietf/group/proxy.py index 595c6a6ea..2784003bc 100644 --- a/ietf/group/proxy.py +++ b/ietf/group/proxy.py @@ -138,7 +138,7 @@ class IETFWG(Group): #meeting_scheduled = models.CharField(blank=True, max_length=3) @property def meeting_scheduled(self): - from meeting.models import Meeting + from ietf.meeting.models import Meeting latest_meeting = Meeting.objects.order_by('-date')[0] return "YES" if self.session_set.filter(meeting=latest_meeting) else "NO" #email_address = models.CharField(blank=True, max_length=60) diff --git a/ietf/idrfc/generate_fixtures.py b/ietf/idrfc/generate_fixtures.py index 2de048dd9..d7979f79a 100755 --- a/ietf/idrfc/generate_fixtures.py +++ b/ietf/idrfc/generate_fixtures.py @@ -14,8 +14,8 @@ setup_environ(settings) # script from django.core.serializers import serialize from django.db.models import Q -from idtracker.models import * -from iesg.models import * +from ietf.idtracker.models import * +from ietf.iesg.models import * def output(name, qs): try: diff --git a/ietf/idrfc/urls.py b/ietf/idrfc/urls.py index 1585d6673..74ab929dd 100644 --- a/ietf/idrfc/urls.py +++ b/ietf/idrfc/urls.py @@ -40,10 +40,13 @@ urlpatterns = patterns('', (r'^active/$', views_search.active), (r'^in-last-call/$', views_search.in_last_call), url(r'^ad/(?P[A-Za-z0-9.-]+)/$', views_search.by_ad, name="doc_search_by_ad"), - - url(r'^(?P[A-Za-z0-9.-]+)/((?Pballot|writeup|history)/)?$', views_doc.document_main, name="doc_view"), + + url(r'^(?P[A-Za-z0-9.-]+)/$', views_doc.document_main, name="doc_view"), + url(r'^(?P[A-Za-z0-9.-]+)/history/$', views_doc.document_history), + url(r'^(?P[A-Za-z0-9.-]+)/writeup/$', views_doc.document_writeup), + url(r'^(?P[A-Za-z0-9.-]+)/ballot/$', views_doc.document_ballot), (r'^(?P[A-Za-z0-9.-]+)/doc.json$', views_doc.document_debug), - (r'^(?P[A-Za-z0-9.-]+)/_ballot.data$', views_doc.document_ballot), + (r'^(?P[A-Za-z0-9.-]+)/_ballot.data$', views_doc.ballot_html), # why is this url so weird instead of just ballot.html? (r'^(?P[A-Za-z0-9.-]+)/ballot.tsv$', views_doc.ballot_tsv), (r'^(?P[A-Za-z0-9.-]+)/ballot.json$', views_doc.ballot_json), diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py index 4ccbf6d09..482cae255 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/idrfc/views_doc.py @@ -51,6 +51,52 @@ from ietf.idrfc.models import RfcIndex, DraftVersions from ietf.idrfc.idrfc_wrapper import BallotWrapper, IdWrapper, RfcWrapper from ietf.ietfworkflows.utils import get_full_info_for_draft +def render_document_top(request, doc, tab): + tabs = [] + tabs.append(("Document", "document", urlreverse("idrfc.views_doc.document_main", kwargs=dict(name=doc.name)))) + + if doc_type == "draft": + tabs.append(("IESG Evaluation Record", "ballot", urlreverse("idrfc.views_doc.document_ballot", kwargs=dict(name=doc.name)))) + elif doc_type == "charter": + tabs.append(("IESG Review", "ballot", urlreverse("idrfc.views_doc.document_ballot", kwargs=dict(name=doc.name)))) + + tabs.append(("IESG Writeups", "writeup", urlreverse("idrfc.views_doc.document_writeup", kwargs=dict(name=doc.name)))) + tabs.append(("History", "history", urlreverse("idrfc.views_doc.document_history", kwargs=dict(name=doc.name)))) + + return render_to_string("idrfc/document_top.html", + dict(doc=doc, + tabs=tabs, + selected=tab)) + + +def document_main(request, name): + if name.startswith("ietf-charter-"): + # FIXME: render top + # render content + # refactor history similarly? or use directly + # refactor writeup, generalize on names and links to edit + # refactor ballot to have multiple ballot typesiet + + return render_to_response("idrfc/doc_tab_document.html", + {'content1':content1, + 'content2':content2, + 'doc': doc, + 'tab': "document", + 'include_text':include_text(request)}, + context_instance=RequestContext(request)); + + + return document_main_idrfc(request, name, "document") + +def document_history(request, name): + return document_main_idrfc(request, name, "history") + +def document_writeup(request, name): + return document_main_idrfc(request, name, "writeup") + +def document_ballot(request, name): + return document_main_idrfc(request, name, "ballot") + def document_debug(request, name): r = re.compile("^rfc([1-9][0-9]*)$") m = r.match(name) @@ -114,9 +160,7 @@ def document_main_rfc(request, rfc_number, tab): context_instance=RequestContext(request)); @decorator_from_middleware(GZipMiddleware) -def document_main(request, name, tab): - if tab is None: - tab = "document" +def document_main_idrfc(request, name, tab): r = re.compile("^rfc([1-9][0-9]*)$") m = r.match(name) if m: @@ -288,7 +332,7 @@ def get_ballot(name): ballot = BallotWrapper(id) return ballot, doc -def document_ballot(request, name): +def ballot_html(request, name): ballot, doc = get_ballot(name) return render_to_response('idrfc/doc_ballot.html', {'ballot':ballot, 'doc':doc}, context_instance=RequestContext(request)) @@ -301,3 +345,4 @@ def ballot_json(request, name): response = HttpResponse(mimetype='text/plain') response.write(json.dumps(ballot.dict(), indent=2)) return response + diff --git a/ietf/iesg/views.py b/ietf/iesg/views.py index c550c3152..67b779775 100644 --- a/ietf/iesg/views.py +++ b/ietf/iesg/views.py @@ -33,6 +33,9 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import codecs, re, os, glob +import datetime +import tarfile + from ietf.idtracker.models import IDInternal, InternetDraft,AreaGroup, Position, IESGLogin, Acronym from django.views.generic.list_detail import object_list from django.views.generic.simple import direct_to_template @@ -50,8 +53,8 @@ from ietf.idrfc.utils import update_telechat from ietf.ietfauth.decorators import group_required from ietf.idtracker.templatetags.ietf_filters import in_group from ietf.ipr.models import IprRfc, IprDraft, IprDetail -import datetime -import tarfile +from redesign.doc.models import TelechatDocEvent +from redesign.group.models import Group def date_threshold(): """Return the first day of the month that is 185 days ago.""" @@ -208,6 +211,23 @@ def get_doc_sectionREDESIGN(id): s = s + "1" return s +def get_wg_section(wg): + s = "" + charter_slug = None + if wg.charter: + charter_slug = wg.charter.get_state_slug() + if wg.state_id == "proposed": + if charter_slug == "intrev": + s = '411' + elif charter_slug == "iesgrev": + s = '412' + elif wg.state_id == "active": + if charter_slug == "intrev": + s = '421' + elif charter_slug == "iesgrev": + s = '422' + return s + if settings.USE_DB_REDESIGN_PROXY_CLASSES: get_doc_section = get_doc_sectionREDESIGN @@ -253,15 +273,14 @@ def agenda_docs(date, next_agenda): return res def agenda_wg_actions(date): - mapping = {12:'411', 13:'412',22:'421',23:'422'} - matches = WGAction.objects.filter(agenda=1,telechat_date=date,category__in=mapping.keys()).order_by('category') - res = {} - for o in matches: - section_key = "s"+mapping[o.category] + matches = Group.objects.filter(charter__docevent__telechatdocevent__telechat_date=date) + + res = dict(("s%s%s%s" % (i, j, k), []) for i in range(2, 5) for j in range (1, 4) for k in range(1, 4)) + for wg in matches: + section_key = "s" + get_wg_section(wg) if section_key not in res: res[section_key] = [] - area = AreaGroup.objects.get(group=o.group_acronym) - res[section_key].append({'obj':o, 'area':str(area.area)}) + res[section_key].append({'obj':wg}) return res def agenda_management_issues(date): diff --git a/ietf/ietfauth/urls.py b/ietf/ietfauth/urls.py index 3c5986d5b..7e69f4c20 100644 --- a/ietf/ietfauth/urls.py +++ b/ietf/ietfauth/urls.py @@ -18,5 +18,4 @@ urlpatterns += patterns('ietf.ietfauth.views', url(r'^reset/$', 'password_reset_view', name='password_reset'), url(r'^reset/confirm/(?P[\w.@+-]+)/(?P[\d]+)/(?P[\w]+)/(?P[a-f0-9]+)/$', 'confirm_password_reset', name='confirm_password_reset'), url(r'^ajax/check_username/$', 'ajax_check_username', name='ajax_check_username'), - ) diff --git a/ietf/ipr/views.py b/ietf/ipr/views.py index 17aab5539..ef33f391c 100644 --- a/ietf/ipr/views.py +++ b/ietf/ipr/views.py @@ -49,7 +49,7 @@ def list_drafts(request): mimetype="text/plain") def list_draftsREDESIGN(request): - from ipr.models import IprDocAlias + from ietf.ipr.models import IprDocAlias docipr = {} diff --git a/ietf/templates/base.html b/ietf/templates/base.html index 61a8f45b3..875bc5f96 100644 --- a/ietf/templates/base.html +++ b/ietf/templates/base.html @@ -65,7 +65,7 @@ IETF.user_groups = {{ user|user_roles_json }};
{% if user.is_authenticated %} {{ user }} {% else %} -Sign In +Sign In {% endif %}
{% endif %} diff --git a/ietf/templates/base_leftmenu.html b/ietf/templates/base_leftmenu.html index 5d4c48db8..a9a9fdb48 100644 --- a/ietf/templates/base_leftmenu.html +++ b/ietf/templates/base_leftmenu.html @@ -42,11 +42,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  • My Documents
  • Next Telechat
  • Discusses
  • +
  • Working Groups
  • {# FIXME: wgcharter
  • Working Groups
  • #} {% endif %} {% if user|in_group:"Secretariat" %}
  • Secretariat
  • Telechat Dates
  • +
  • Working Groups
  • {# FIXME: wgcharter
  • Working Groups
  • #} {% endif %} {% if user %} diff --git a/ietf/templates/iesg/agenda_wg.html b/ietf/templates/iesg/agenda_wg.html index 9d6edc402..1d7025a70 100644 --- a/ietf/templates/iesg/agenda_wg.html +++ b/ietf/templates/iesg/agenda_wg.html @@ -43,20 +43,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% endif %} -{{wg.area|upper}} -{{ wg.obj.status_date|date:"M d"}} +{{wg.obj.parent.name|upper}} +{{ wg.obj.time|date:"M d"}} - -{{ wg.obj.group_acronym.name|escape }} ({{wg.obj.group_acronym}}) + +{{ wg.obj.name|escape }} ({{wg.obj.acronym}}) -{% if wg.obj.token_name %} -Token:{{ wg.obj.token_name|escape }} -{% endif %} -{% if wg.obj.note %} -Note: {{wg.obj.note|escape}} -{% endif %} {% if forloop.last %} diff --git a/ietf/templates/iesg/agenda_wg.txt b/ietf/templates/iesg/agenda_wg.txt index fa1d09a62..3d444ec2d 100644 --- a/ietf/templates/iesg/agenda_wg.txt +++ b/ietf/templates/iesg/agenda_wg.txt @@ -35,11 +35,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {{ title2 }} {% endif %}{{ title3 }} {% for wg in section_wgs %} - o {{ wg.obj.group_acronym.name }} ({{wg.obj.group_acronym}}) -{% if wg.obj.token_name %} Token: {{ wg.obj.token_name }} -{% endif %} -{% if wg.obj.note %} {% filter wordwrap:"68"|indent|indent %}Note: {{wg.obj.note|striptags}}{% endfilter %} -{% endif %} + o {{ wg.obj.name }} ({{wg.obj.acronym}}) {% empty %} NONE {% endfor %} diff --git a/ietf/templates/iesg/moderator_wg.html b/ietf/templates/iesg/moderator_wg.html index 14a4565af..36c02c0ea 100644 --- a/ietf/templates/iesg/moderator_wg.html +++ b/ietf/templates/iesg/moderator_wg.html @@ -36,14 +36,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {{ title2 }}
    {{ title3 }} ({{ forloop.counter }} of {{ section_wgs|length }}) -

    {{ wg.obj.group_acronym.name }} ({{wg.obj.group_acronym}})
    -{% if wg.obj.token_name %} -Token: {{ wg.obj.token_name }} -{% endif %}

    - -{% if wg.obj.note %} -

    Note: {{wg.obj.note|striptags}}

    -{% endif %} +

    {{ wg.obj.name }} ({{wg.obj.acronym}})
    {% if title3|startswith:"4.1.1" %}

    Does anyone have an objection to the charter being sent for diff --git a/ietf/templates/wgcharter/wg_tab_base.html b/ietf/templates/wgcharter/wg_tab_base.html index c55982e5b..24ea97658 100644 --- a/ietf/templates/wgcharter/wg_tab_base.html +++ b/ietf/templates/wgcharter/wg_tab_base.html @@ -21,8 +21,7 @@ Copyright The IETF Trust 2011, All Rights Reserved {% if user|in_group:"Area_Director,Secretariat" %} {% if not snapshot %}

    -{% ifnotequal wg.charter.get_state_slug "notrev" %} -{% ifnotequal wg.charter.get_state_slug "approved" %} +{% if wg.charter.get_state_slug != "notrev" and wg.charter.get_state_slug != "approved" %} Abandon effort Change state {% ifnotequal wg.state_id "conclude" %} @@ -30,19 +29,7 @@ Copyright The IETF Trust 2011, All Rights Reserved {% endifnotequal %} {% else %} Recharter -{% endifnotequal %} -{% else %} -Recharter -{% endifnotequal %} - -{% ifequal wg.state_id "active" %}{% ifequal wg.charter.get_state_slug "approved" %} -Conclude WG -{% endifequal %}{% endifequal %} - -{% ifnotequal wg.state_id "conclude" %} -Edit WG -{% endifnotequal %} - +{% endif %}
    {% endif %}{# if not snapshot #} diff --git a/ietf/templates/wgcharter/wg_tab_charter.html b/ietf/templates/wgcharter/wg_tab_charter.html index 666f163f1..ba8f8a1ae 100644 --- a/ietf/templates/wgcharter/wg_tab_charter.html +++ b/ietf/templates/wgcharter/wg_tab_charter.html @@ -35,7 +35,7 @@ Snapshots: {% for d in versions reversed %}{% if forloop.first %}{% ifno
    WG State: {{ wg.state|safe }} -{% ifnotequal wg.state_id "conclude" %}Charter State: {{ wg.charter.get_state|safe }} {% ifequal wg.state_id "proposed" %}{% ifnotequal wg.charter.get_state_slug "notrev" %}(Initial Chartering){% endifnotequal %}{% else %}{% ifnotequal wg.charter.get_state_slug "approved" %}(Rechartering){% endifnotequal %}{% endifequal %}{% endifnotequal %} +{% ifnotequal wg.state_id "conclude" %}Charter State: {{ wg.charter.get_state|safe }} {% ifequal wg.state_id "proposed" %}{% ifnotequal wg.charter.get_state_slug "notrev" %}(Initial Chartering){% endifnotequal %}{% else %}{% ifnotequal wg.charter.get_state_slug "approved" %}(Rechartering){% endifnotequal %}{% endifequal %}{% endifnotequal %} {% ifequal wg.state_id "proposed" %} {% if wg.comments %} Reason for chartering:{{ wg.comments }} diff --git a/ietf/templates/wginfo/wg_charterREDESIGN.html b/ietf/templates/wginfo/wg_charterREDESIGN.html index 563eeabb6..c2cd259f8 100644 --- a/ietf/templates/wginfo/wg_charterREDESIGN.html +++ b/ietf/templates/wginfo/wg_charterREDESIGN.html @@ -36,80 +36,110 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% block wg_titledetail %}Charter{% endblock %} {% block wg_content %} -
    {% if concluded %} Note: The data for concluded WGs is occasionally incorrect. {% endif %} - - - + - - - - - - -{% if wg.techadvisors %} - - - -{% endif %} -{% if wg.editors %} - - -{% endif %} -{% if wg.secretaries %} - - -{% endif %} + + + + - - - + - - - + {% if wg.parent %} + + {% endif %} -{% if not concluded %} - - - + - - -{% endif %} + + + + + + + + + + + + + + + + {% if wg.techadvisors %} + + + + + {% endif %} + {% if wg.editors %} + + + {% endif %} + {% if wg.secretaries %} + + + + + {% endif %} + + + + + + + + {% if not concluded %} + + + + + {% endif %}
    -Personnel -
    Group
    Chair{{ wg.chairs|pluralize }}: -{% for chair in wg.chairs %} -{{ chair.person.name }} <{{ chair.address }}>
    -{% endfor %} -
    Area Director: -{% if not wg.ad %}?{% else %} -{{ wg.ad.name }} <{{ wg.areadirector.address }}>{% endif %} -
    Tech Advisor{{ wg.techadvisors|pluralize }}: -{% for techadvisor in wg.techadvisors %} -{{ techadvisor.person.name }} <{{ techadvisor.address }}>
    -{% endfor %} -
    Editor{{ wg.editors|pluralize }}: -{% for editor in wg.editors %} -{{ editor.person.name }} <{{ editor.address }}>
    -{% endfor %} -
    Secretar{{ wg.secretaries|pluralize:"y,ies" }}: -{% for secretary in wg.secretaries %} -{{ secretary.person.name }} <{{ secretary.address }}>
    -{% endfor %} -
    Name:{{ wg.name }}
    -
    Mailing List -
    Acronym:{{ wg.acronym }}
    Address:{{ wg.email_address|urlize }}
    To Subscribe:{{ wg.email_subscribe|urlize }}
    Archive:{{ wg.clean_email_archive|urlize }}
    Area:{{ wg.parent.name }} ({{ wg.parent.acronym }})
    -
    Jabber Chat -
    State:{{ wg.state.name }}
    Room Address:xmpp:{{wg}}@jabber.ietf.org
    Logs:http://jabber.ietf.org/logs/{{wg}}/
    Charter: + {% if wg.charter %} + {{ wg.charter.name }}-{{ wg.charter.rev }} ({{ wg.charter.get_state.name }}) + {% else %} + none + {% if user|has_role:"Area Director,Secretariat" %} + - Submit Charter + {% endif %} + {% endif %} +
    Personnel
    Chair{{ wg.chairs|pluralize }}: + {% for chair in wg.chairs %} + {{ chair.person.plain_name }} <{{ chair.address }}>
    + {% endfor %} +
    Area Director: + {% if not wg.ad %}?{% else %} + {{ wg.ad.plain_name }} <{{ wg.areadirector.address }}>{% endif %} +
    Tech Advisor{{ wg.techadvisors|pluralize }}: + {% for techadvisor in wg.techadvisors %} + {{ techadvisor.person.plain_name }} <{{ techadvisor.address }}>
    + {% endfor %} +
    Editor{{ wg.editors|pluralize }}: + {% for editor in wg.editors %} + {{ editor.person.plain_name }} <{{ editor.address }}>
    + {% endfor %} +
    Secretar{{ wg.secretaries|pluralize:"y,ies" }}: + {% for secretary in wg.secretaries %} + {{ secretary.person.plain_name }} <{{ secretary.address }}>
    + {% endfor %} +
    Mailing List
    Address:{{ wg.email_address|urlize }}
    To Subscribe:{{ wg.email_subscribe|urlize }}
    Archive:{{ wg.clean_email_archive|urlize }}
    Jabber Chat
    Room Address:xmpp:{{ wg.acronym }}@jabber.ietf.org
    Logs:http://jabber.ietf.org/logs/{{ wg.acronym }}/
    + +{% if user|has_role:"Area Director,Secretariat" %} +
    + {% for name, url in actions %} + {{ name }} + {% if not forloop.last %}|{% endif %} + {% endfor %} +
    +{% endif %}
    {% if wg.additional_urls %} diff --git a/ietf/wgcharter/views.py b/ietf/wgcharter/views.py index 1b8e44237..53bec4cc4 100644 --- a/ietf/wgcharter/views.py +++ b/ietf/wgcharter/views.py @@ -21,6 +21,7 @@ from ietf.wgcharter.utils import * from ietf.utils.history import find_history_active_at from ietf.idtracker.templatetags.ietf_filters import format_textarea, fill +# FIXME: delete def _get_html(key, filename): f = None try: @@ -70,13 +71,13 @@ def wg_main(request, name, rev, tab): prev_list_archive = list(set([x.list_archive for x in wg.history_set.exclude(list_archive=wg.list_archive) if x.list_archive != u''])) if prev_list_archive != [u'']: info['prev_list_archive'] = prev_list_archive - info['chairs'] = [x.email.person.name for x in wg.role_set.filter(name__slug="chair")] + info['chairs'] = [x.person.plain_name() for x in wg.role_set.filter(name__slug="chair")] if hasattr(gh, 'rolehistory_set'): - info['history_chairs'] = [x.email.person.name for x in gh.rolehistory_set.filter(name__slug="chair")] + info['history_chairs'] = [x.person.plain_name() for x in gh.rolehistory_set.filter(name__slug="chair")] else: - 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")] + info['history_chairs'] = [x.person.plain_name() for x in gh.role_set.filter(name__slug="chair")] + info['secr'] = [x.person.plain_name() for x in wg.role_set.filter(name__slug="secr")] + info['techadv'] = [x.person.plain_name() for x in wg.role_set.filter(name__slug="techadv")] if ch: file_path = wg.charter.get_file_path() # Get from wg.charter @@ -153,7 +154,7 @@ def _get_history(wg, versions=None): charter_history = find_history_active_at(wg.charter, e.time) info['version'] = charter_history.rev if charter_history else wg.charter.rev info['text'] = e.desc - info['by'] = e.by.name + info['by'] = e.by.plain_name() info['textSnippet'] = truncatewords_html(format_textarea(fill(info['text'], 80)), 25) info['snipped'] = info['textSnippet'][-3:] == "..." if e.type == "new_revision": diff --git a/ietf/wgcharter/views_ballot.py b/ietf/wgcharter/views_ballot.py index 7021f4176..a0668c482 100644 --- a/ietf/wgcharter/views_ballot.py +++ b/ietf/wgcharter/views_ballot.py @@ -32,10 +32,10 @@ def default_action_text(wg, charter, user, action): e.desc = "WG action text was changed" info = {} - info['chairs'] = [{ 'name': x.email.person.name, 'email': x.email.address} for x in wg.role_set.filter(name="Chair")] - info['secr'] = [{ 'name': x.email.person.name, 'email': x.email.address} for x in wg.role_set.filter(name="Secr")] - info['techadv'] = [{ 'name': x.email.person.name, 'email': x.email.address} for x in wg.role_set.filter(name="Techadv")] - info['ad'] = {'name': wg.ad.name, 'email': wg.ad.email_address().address } if wg.ad else None, + info['chairs'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Chair")] + info['secr'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Secr")] + info['techadv'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Techadv")] + info['ad'] = {'name': wg.ad.plain_name(), 'email': wg.ad.role_email("ad").address } if wg.ad else None, info['list'] = wg.list_email if wg.list_email else None, info['list_subscribe'] = str(wg.list_subscribe) if wg.list_subscribe else None, info['list_archive'] = str(wg.list_archive) if wg.list_archive else None, @@ -64,10 +64,10 @@ def default_review_text(wg, charter, user): e.type = "changed_review_announcement" e.desc = "WG review text was changed" info = {} - info['chairs'] = [{ 'name': x.person.name, 'email': x.email.address} for x in wg.role_set.filter(name="Chair")] - info['secr'] = [{ 'name': x.person.name, 'email': x.email.address} for x in wg.role_set.filter(name="Secr")] - info['techadv'] = [{ 'name': x.person.name, 'email': x.email.address} for x in wg.role_set.filter(name="Techadv")] - info['ad'] = {'name': wg.ad.name, 'email': wg.ad.role_email("ad").address } if wg.ad else None, + info['chairs'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Chair")] + info['secr'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Secr")] + info['techadv'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Techadv")] + info['ad'] = {'name': wg.ad.plain_name(), 'email': wg.ad.role_email("ad").address } if wg.ad else None, info['list'] = wg.list_email if wg.list_email else None, info['list_subscribe'] = wg.list_subscribe if wg.list_subscribe else None, info['list_archive'] = wg.list_archive if wg.list_archive else None, @@ -205,15 +205,15 @@ def edit_position(request, name): if not old_pos and pos.pos.slug != "norecord": pos.desc = u"[Ballot Position Update] New position, %s, has been recorded for %s" % (pos.pos.name, pos.ad.name) elif old_pos and pos.pos != old_pos.pos: - pos.desc = "[Ballot Position Update] Position for %s has been changed to %s from %s" % (pos.ad.name, pos.pos.name, old_pos.pos.name) + pos.desc = "[Ballot Position Update] Position for %s has been changed to %s from %s" % (pos.ad.plain_name(), pos.pos.name, old_pos.pos.name) if not pos.desc and changes: - pos.desc = u"Ballot %s text updated for %s" % (u" and ".join(changes), ad.name) + pos.desc = u"Ballot %s text updated for %s" % (u" and ".join(changes), ad.plain_name()) # only add new event if we actually got a change if pos.desc: if login != ad: - pos.desc += u" by %s" % login.name + pos.desc += u" by %s" % login.plain_name() pos.save() @@ -302,13 +302,13 @@ def send_ballot_comment(request, name): c = pos.comment subj.append("COMMENT") - ad_name_genitive = ad.name + "'" if ad.name.endswith('s') else ad.name + "'s" + ad_name_genitive = ad.plain_name() + "'" if ad.plain_name().endswith('s') else ad.plain_name() + "'s" subject = "%s %s on %s" % (ad_name_genitive, pos.pos.name if pos.pos else "No Position", charter.name + "-" + charter.rev) if subj: subject += ": (with %s)" % " and ".join(subj) body = render_to_string("wgcharter/ballot_comment_mail.txt", - dict(block_comment=d, comment=c, ad=ad.name, charter=charter, pos=pos.pos)) + dict(block_comment=d, comment=c, ad=ad.plain_name(), charter=charter, pos=pos.pos)) frm = ad.formatted_email() to = "The IESG " @@ -467,7 +467,7 @@ def ballot_writeupnotes(request, name): pos.type = "changed_ballot_position" pos.ad = login pos.pos_id = "yes" - pos.desc = "[Ballot Position Update] New position, %s, has been recorded for %s" % (pos.pos.name, pos.ad.name) + pos.desc = "[Ballot Position Update] New position, %s, has been recorded for %s" % (pos.pos.name, pos.ad.plain_name()) pos.save() msg = generate_issue_ballot_mail(request, charter) @@ -476,7 +476,7 @@ def ballot_writeupnotes(request, name): e = DocEvent(doc=charter, by=login) e.by = login e.type = "sent_ballot_announcement" - e.desc = "Ballot has been issued by %s" % login.name + e.desc = "Ballot has been issued" e.save() return render_to_response('wgcharter/ballot_issued.html', diff --git a/ietf/wginfo/views.py b/ietf/wginfo/views.py index be68ec5db..c06091b65 100644 --- a/ietf/wginfo/views.py +++ b/ietf/wginfo/views.py @@ -36,6 +36,7 @@ from django.shortcuts import get_object_or_404, render_to_response from django.template import RequestContext, loader from django.http import HttpResponse from django.conf import settings +from django.core.urlresolvers import reverse as urlreverse from ietf.idtracker.models import Area, IETFWG from ietf.idrfc.views_search import SearchForm, search_query from ietf.idrfc.idrfc_wrapper import IdRfcWrapper @@ -149,17 +150,25 @@ def wg_charter(request, acronym): if settings.USE_DB_REDESIGN_PROXY_CLASSES: fill_in_charter_info(wg) + actions = [] + if wg.state_id != "conclude": + actions.append(("Edit WG", urlreverse("wg_edit_info", kwargs=dict(name=wg.acronym)))) + + if wg.state_id == "active" and (not wg.charter or wg.charter.get_state_slug() == "approved"): + actions.append(("Conclude WG", urlreverse("wg_conclude", kwargs=dict(name=wg.acronym)))) + + context = get_wg_menu_context(wg, "charter") + context.update(dict( + actions=actions)) + return render_to_response('wginfo/wg_charterREDESIGN.html', - dict(wg=wg, - concluded=concluded, - proposed=proposed, - selected='charter'), + context, RequestContext(request)) return render_to_response('wginfo/wg_charter.html', {'wg': wg, 'concluded':concluded, 'proposed': proposed, 'selected':'charter'}, RequestContext(request)) def get_wg_menu_context(wg, selected): - # it would probably be better to refactor this file into rendering + # it would probably be better to refactor wginfo into rendering # the menu separately instead of each view having to include the information return dict(wg=wg, concluded=wg.state_id == "conclude", proposed=wg.state_id == "proposed", selected=selected) diff --git a/redesign/importing/import-docs.py b/redesign/importing/import-docs.py index f165c65cb..9091e1110 100755 --- a/redesign/importing/import-docs.py +++ b/redesign/importing/import-docs.py @@ -27,9 +27,12 @@ from ietf.wgchairs.models import ProtoWriteUp from workflows.models import State as StateOld -document_name_to_import = None +import_docs_from = document_name_to_import = None if len(sys.argv) > 1: - document_name_to_import = sys.argv[1] + try: + import_docs_from = datetime.datetime.strptime(sys.argv[1], "%Y-%m-%d") + except: + document_name_to_import = sys.argv[1] dont_save_queries() @@ -225,6 +228,8 @@ def iesg_login_is_secretary(l): # Amy has two users, for some reason, we sometimes get the wrong one return l.user_level == IESGLogin.SECRETARIAT_LEVEL or (l.first_name == "Amy" and l.last_name == "Vezza") +old_internetdraft_content_type_id = ContentType.objects.using("legacy").get(app_label="idtracker", model="internetdraft").pk + # regexps for parsing document comments date_re_str = "(?P[0-9][0-9][0-9][0-9])-(?P[0-9][0-9]?)-(?P[0-9][0-9]?)" @@ -765,15 +770,15 @@ def import_from_idinternal(d, idinternal): all_drafts = InternetDraft.objects.all().order_by('pk').select_related() +if import_docs_from: + all_drafts = all_drafts.filter(last_modified_date__gte=import_docs_from) | all_drafts.filter(idinternal__event_date__gte=import_docs_from) + if document_name_to_import: if document_name_to_import.startswith("rfc"): all_drafts = all_drafts.filter(rfc_number=document_name_to_import[3:]) else: all_drafts = all_drafts.filter(filename=document_name_to_import) -#all_drafts = all_drafts[all_drafts.count() - 1000:] -#all_drafts = all_drafts.none() -old_internetdraft_content_type_id = ContentType.objects.using("legacy").get(app_label="idtracker", model="internetdraft").pk for index, o in enumerate(all_drafts.iterator()): print "importing", o.id_document_tag, o.filename, index, "ballot %s" % o.idinternal.ballot_id if o.idinternal and o.idinternal.ballot_id else "" @@ -1093,7 +1098,11 @@ if all_drafts.count() != InternetDraft.objects.count(): else: # if we didn't process all drafts, limit the RFCs to the ones we # did process - all_rfcs = all_rfcs.filter(rfc_number__in=set(d.rfc_number for d in all_drafts if d.rfc_number)) + rfc_numbers = set(d.rfc_number for d in all_drafts if d.rfc_number) + if import_docs_from: + all_rfcs = all_rfcs.filter(rfc_number__in=rfc_numbers) | all_rfcs.filter(rfc_published_date__gte=import_docs_from) + else: + all_rfcs = all_rfcs.filter(rfc_number__in=rfc_numbers) for index, o in enumerate(all_rfcs.iterator()): print "importing rfc%s" % o.rfc_number, index diff --git a/redesign/importing/import-meetings.py b/redesign/importing/import-meetings.py index 5ab169fdd..9c3772f85 100755 --- a/redesign/importing/import-meetings.py +++ b/redesign/importing/import-meetings.py @@ -24,6 +24,11 @@ from redesign.importing.utils import old_person_to_person, dont_save_queries from ietf.name.models import * from ietf.name.utils import name +import_meetings_from = None +if len(sys.argv) > 1: + import_meetings_from = datetime.datetime.strptime(sys.argv[1], "%Y-%m-%d") + + dont_save_queries() # imports Meeting, MeetingVenue, MeetingRoom, NonSession, @@ -294,7 +299,11 @@ def import_materials(wg_meeting_session, session): obviously_bogus_date = datetime.date(1970, 1, 1) -for o in WgMeetingSession.objects.all().order_by("pk").iterator(): +all_sessions = WgMeetingSession.objects.all().order_by("pk") +if import_meetings_from: + all_sessions = all_sessions.filter(last_modified_date__gte=import_meetings_from) + +for o in all_sessions.iterator(): # num_session is unfortunately not quite reliable, seems to be # right for 1 or 2 but not 3 and it's sometimes null sessions = o.num_session or 1 diff --git a/redesign/importing/import-persons.py b/redesign/importing/import-persons.py index e2350d4f2..c64e469d5 100755 --- a/redesign/importing/import-persons.py +++ b/redesign/importing/import-persons.py @@ -28,6 +28,11 @@ from redesign.importing.utils import * # should probably import # PersonOrOrgInfo/PostalAddress/EmailAddress/PhoneNumber fully +import_docs_from = None +if len(sys.argv) > 1: + import_docs_from = datetime.datetime.strptime(sys.argv[1], "%Y-%m-%d") + + # make sure special system user/email is created print "creating (System) person and email" try: @@ -174,7 +179,11 @@ for o in PersonOrOrgInfo.objects.filter(wgproceedingsactivities__id__gte=1).orde email = get_or_create_email(o, create_fake=True) # IDAuthor persons -for o in IDAuthor.objects.all().order_by('id').select_related('person').iterator(): +all_authors = IDAuthor.objects.all().order_by('id').select_related('person') +if import_docs_from: + all_authors = all_authors.filter(document__last_modified_date__gte=import_docs_from) + +for o in all_authors.iterator(): print "importing IDAuthor", o.id, o.person_id, o.person.first_name.encode('utf-8'), o.person.last_name.encode('utf-8') email = get_or_create_email(o, create_fake=True) diff --git a/redesign/importing/import-reused-tables.py b/redesign/importing/import-reused-tables.py index 2a6a46107..a82d8add7 100755 --- a/redesign/importing/import-reused-tables.py +++ b/redesign/importing/import-reused-tables.py @@ -16,6 +16,7 @@ management.setup_environ(settings) from django.db.models import TextField, CharField +from django.contrib.sites.models import Site from ietf.redirects.models import Redirect, Suffix, Command from ietf.iesg.models import TelechatAgendaItem, WGAction from ietf.ipr.models import IprSelecttype, IprLicensing, IprDetail, IprContact, IprNotification, IprUpdate @@ -24,10 +25,12 @@ from django.contrib.auth.models import User known_models = { 'base': [User], - 'others': [Redirect, Suffix, Command, + 'others': [Site, + Redirect, Suffix, Command, TelechatAgendaItem, WGAction, IprSelecttype, IprLicensing, IprDetail, IprContact, IprNotification, IprUpdate, - IdSubmissionStatus, IdSubmissionDetail, IdApprovedDetail, TempIdAuthors] + IdSubmissionStatus, IdSubmissionDetail, IdApprovedDetail, + TempIdAuthors] } models_to_copy = known_models[sys.argv[1]] @@ -53,7 +56,6 @@ def insert_many_including_pk(objects, using="default", table=None): for o in objects: pars = [] for f in fields: - #print f.name, f.pre_save(o, True) pars.append(f.get_db_prep_save(f.pre_save(o, True), connection=con)) parameters.append(pars) @@ -79,7 +81,12 @@ def clean_chunk(model, chunk): for model in models_to_copy: sys.stdout.write("copying %s " % model._meta.object_name) sys.stdout.flush() - table_name = "%s_%s" % (model._meta.app_label, model._meta.object_name.lower()) + + irregular_models = [Site] + if model in irregular_models: + table_name = Site._meta.db_table + else: + table_name = "%s_%s" % (model._meta.app_label, model._meta.object_name.lower()) for chunk in queryset_chunks(model.objects.using("legacy").all(), 1000): clean_chunk(model, chunk) diff --git a/redesign/importing/import-roles.py b/redesign/importing/import-roles.py index 0289c1acd..cbd3dedfc 100755 --- a/redesign/importing/import-roles.py +++ b/redesign/importing/import-roles.py @@ -221,7 +221,12 @@ for o in IESGLogin.objects.all(): if email and o.user_level == IESGLogin.SECRETARIAT_LEVEL: if not Role.objects.filter(name=secretary_role, person=email.person): Role.objects.create(name=secretary_role, group=Group.objects.get(acronym="secretariat"), person=email.person, email=email) - + u = email.person.user + if u: + u.is_staff = True + u.is_superuser = True + u.save() + # AreaDirector for o in AreaDirector.objects.all(): if not o.area: From 618e308ac0c2278b09af853b82f82725138cb423 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 15 Mar 2012 16:01:59 +0000 Subject: [PATCH 02/72] Add WG chartering/rechartering overview page, missing ballot icon pending on getting ballot situation cleared up, but otherwise done. - Legacy-Id: 4087 --- ietf/doc/utils.py | 10 ++++++++++ ietf/wginfo/urls.py | 1 + ietf/wginfo/views.py | 17 +++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/ietf/doc/utils.py b/ietf/doc/utils.py index 83530d53d..2fa85b156 100644 --- a/ietf/doc/utils.py +++ b/ietf/doc/utils.py @@ -51,6 +51,16 @@ def get_rfc_number(doc): qs = doc.docalias_set.filter(name__startswith='rfc') return qs[0].name[3:] if qs else None +def get_chartering_type(doc): + chartering = "" + if doc.get_state_slug() not in ("notrev", "approved"): + if doc.group.state_id == "proposed": + chartering = "initial" + elif doc.group.state_id == "active": + chartering = "rechartering" + + return chartering + def augment_with_telechat_date(docs): """Add a telechat_date attribute to each document with the scheduled telechat or None if it's not scheduled.""" diff --git a/ietf/wginfo/urls.py b/ietf/wginfo/urls.py index 62936669d..b3bd5d949 100644 --- a/ietf/wginfo/urls.py +++ b/ietf/wginfo/urls.py @@ -13,6 +13,7 @@ urlpatterns = patterns('', (r'^1wg-summary-by-acronym.txt', views.wg_summary_acronym), (r'^1wg-charters.txt', views.wg_charters), (r'^1wg-charters-by-acronym.txt', views.wg_charters_by_acronym), + (r'^chartering/$', views.chartering_wgs), (r'^(?P[a-zA-Z0-9-]+)/documents/txt/$', views.wg_documents_txt), (r'^(?P[a-zA-Z0-9-]+)/$', views.wg_documents_html), (r'^(?P[a-zA-Z0-9-]+)/charter/$', views.wg_charter), diff --git a/ietf/wginfo/views.py b/ietf/wginfo/views.py index c06091b65..e04cdcdfd 100644 --- a/ietf/wginfo/views.py +++ b/ietf/wginfo/views.py @@ -42,6 +42,8 @@ from ietf.idrfc.views_search import SearchForm, search_query from ietf.idrfc.idrfc_wrapper import IdRfcWrapper from ietf.ipr.models import IprDetail from ietf.group.models import Group +from ietf.doc.models import State +from ietf.doc.utils import get_chartering_type, augment_with_telechat_date def fill_in_charter_info(wg, include_drafts=False): @@ -111,6 +113,21 @@ def wg_dirREDESIGN(request): if settings.USE_DB_REDESIGN_PROXY_CLASSES: wg_dir = wg_dirREDESIGN +def chartering_wgs(request): + charter_states = State.objects.filter(type="charter").exclude(slug__in=("approved", "notrev")) + groups = Group.objects.filter(type="wg", charter__states__in=charter_states).select_related("state", "charter") + + augment_with_telechat_date([g.charter for g in groups]) + + for g in groups: + g.chartering_type = get_chartering_type(g.charter) + + return render_to_response('wginfo/chartering_wgs.html', + dict(charter_states=charter_states, + groups=groups), + RequestContext(request)) + + def wg_documents(request, acronym): wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1) concluded = (wg.status_id != 1 and wg.status_id != 4) From 63a433aa6dd14acaed4936aa921ece118f2f1517 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 15 Mar 2012 16:02:48 +0000 Subject: [PATCH 03/72] Add template for new chartering overview page. - Legacy-Id: 4088 --- ietf/templates/wginfo/chartering_wgs.html | 49 +++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 ietf/templates/wginfo/chartering_wgs.html diff --git a/ietf/templates/wginfo/chartering_wgs.html b/ietf/templates/wginfo/chartering_wgs.html new file mode 100644 index 000000000..feb050618 --- /dev/null +++ b/ietf/templates/wginfo/chartering_wgs.html @@ -0,0 +1,49 @@ +{% extends "base.html" %} + +{% block title %}Chartering or Re-Chartering Working Groups{% endblock %} + +{% block content %} +

    Chartering or Re-Chartering Working Groups

    + +

    Groups with a charter in state +{% for s in charter_states %}{% if not forloop.first %}, {% if forloop.last %}or {% endif %}{% endif %}{{ s.name }}{% endfor %}.

    + +{% if not groups %} +

    No groups found.

    +{% else %} + + + + + + + +{% for g in groups %} + + + + + + + +{% endfor %} +
    AcronymCharterDateStatus
    + {{ g.acronym }} + + {{ g.name }} + {{ g.charter.time|date:"Y-m-d" }} + {{ g.charter.get_state.name }} + {% if g.chartering_type == "initial" %}(Initial Chartering){% endif %} + {% if g.chartering_type == "recharter" %}(Rechartering){% endif %} + {% if not g.chartering_type and g.state_id != "active" %}({{ g.state.name }}){% endif %} + + {% if g.charter.telechat_date %}
    IESG Telechat: {{ g.charter.telechat_date|date:"Y-m-d" }}{% endif %} +
    + {% comment %} + FIXME: add this back in when ballot situation is clear + {% if g.charter.get_state_slug == "iesgrev" %}{% wg_ballot_icon g.acronym %}{% endif %} + {% endcomment %} +
    +{% endif %} + +{% endblock %} From 4112ff58dee50c5c39e9490e16cdce75d46cf2c8 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 15 Mar 2012 16:03:54 +0000 Subject: [PATCH 04/72] Add support for not splitting output - Legacy-Id: 4089 --- ietf/idrfc/markup_txt.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ietf/idrfc/markup_txt.py b/ietf/idrfc/markup_txt.py index 9ef26d471..b4bb5d6f0 100644 --- a/ietf/idrfc/markup_txt.py +++ b/ietf/idrfc/markup_txt.py @@ -34,7 +34,7 @@ from django.utils.html import escape import string import re -def markup(content): +def markup(content, split=True): # normalize line endings to LF only content = content.replace("\r\n", "\n") content = content.replace("\r", "\n") @@ -63,8 +63,10 @@ def markup(content): content = re.sub("\n\n([0-9]+\\.|[A-Z]\\.[0-9]|Appendix|Status of|Abstract|Table of|Full Copyright|Copyright|Intellectual Property|Acknowled|Author|Index)(.*)(?=\n\n)", """\n\n\g<1>\g<2>""", content) - n = content.find("\n", 5000) - content1 = "
    "+content[:n+1]+"
    \n" - content2 = "
    "+content[n+1:]+"
    \n" - - return (content1, content2) + if split: + n = content.find("\n", 5000) + content1 = "
    "+content[:n+1]+"
    \n" + content2 = "
    "+content[n+1:]+"
    \n" + return (content1, content2) + else: + return "
    " + content + "
    \n" From 43bef3929f06f856fb36a2fbcb0c2316db136dc1 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 15 Mar 2012 16:17:04 +0000 Subject: [PATCH 05/72] Generalize add comment view slightly so it can be used with charters. - Legacy-Id: 4090 --- ietf/idrfc/views_edit.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ietf/idrfc/views_edit.py b/ietf/idrfc/views_edit.py index 2300ddafe..d3ed79254 100644 --- a/ietf/idrfc/views_edit.py +++ b/ietf/idrfc/views_edit.py @@ -772,10 +772,8 @@ def add_comment(request, name): @group_required('Area_Director', 'Secretariat', 'IANA') def add_commentREDESIGN(request, name): - """Add comment to Internet Draft.""" + """Add comment to history of document.""" doc = get_object_or_404(Document, docalias__name=name) - if not doc.get_state("draft-iesg"): - raise Http404() login = request.user.get_profile() @@ -789,8 +787,9 @@ def add_commentREDESIGN(request, name): e.desc = c e.save() - email_owner(request, doc, doc.ad, login, - "A new comment added by %s" % login.name) + if doc.type_id == "draft": + email_owner(request, doc, doc.ad, login, + "A new comment added by %s" % login.name) return HttpResponseRedirect(doc.get_absolute_url()) else: form = AddCommentForm() From a1b5671eada5d010965e6ec93fd75f0a37031cb1 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 15 Mar 2012 16:38:56 +0000 Subject: [PATCH 06/72] Preliminary generalization of /doc/ tabs with top factored out, main page being specific, writeup page generic with some specific code to setup writeups (only charter ported), history page being generic (I-D/RFC not ported, needs two event hack fixes), and ballot page not done, pending on multi-ballot solution. - Legacy-Id: 4091 --- ietf/idrfc/urls.py | 4 +- ietf/idrfc/views_doc.py | 228 ++++++++++++++++++--- ietf/templates/idrfc/document_charter.html | 109 ++++++++++ ietf/templates/idrfc/document_history.html | 88 ++++++++ ietf/templates/idrfc/document_top.html | 9 + ietf/templates/idrfc/document_writeup.html | 24 +++ 6 files changed, 429 insertions(+), 33 deletions(-) create mode 100644 ietf/templates/idrfc/document_charter.html create mode 100644 ietf/templates/idrfc/document_history.html create mode 100644 ietf/templates/idrfc/document_top.html create mode 100644 ietf/templates/idrfc/document_writeup.html diff --git a/ietf/idrfc/urls.py b/ietf/idrfc/urls.py index 74ab929dd..62e3b05d8 100644 --- a/ietf/idrfc/urls.py +++ b/ietf/idrfc/urls.py @@ -41,10 +41,10 @@ urlpatterns = patterns('', (r'^in-last-call/$', views_search.in_last_call), url(r'^ad/(?P[A-Za-z0-9.-]+)/$', views_search.by_ad, name="doc_search_by_ad"), - url(r'^(?P[A-Za-z0-9.-]+)/$', views_doc.document_main, name="doc_view"), + url(r'^(?P[A-Za-z0-9.-]+)/((?P[0-9-]+)/)?$', views_doc.document_main, name="doc_view"), url(r'^(?P[A-Za-z0-9.-]+)/history/$', views_doc.document_history), url(r'^(?P[A-Za-z0-9.-]+)/writeup/$', views_doc.document_writeup), - url(r'^(?P[A-Za-z0-9.-]+)/ballot/$', views_doc.document_ballot), + url(r'^(?P[A-Za-z0-9.-]+)/ballot/((?P[A-Za-z0-9.-]+)/)?$', views_doc.document_ballot), (r'^(?P[A-Za-z0-9.-]+)/doc.json$', views_doc.document_debug), (r'^(?P[A-Za-z0-9.-]+)/_ballot.data$', views_doc.ballot_html), # why is this url so weird instead of just ballot.html? (r'^(?P[A-Za-z0-9.-]+)/ballot.tsv$', views_doc.ballot_tsv), diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py index 482cae255..c20b4530d 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/idrfc/views_doc.py @@ -34,7 +34,7 @@ import re, os from datetime import datetime, time from django.http import HttpResponse, Http404 -from django.shortcuts import render_to_response, get_object_or_404 +from django.shortcuts import render_to_response, get_object_or_404, redirect from django.template import RequestContext from django.template.loader import render_to_string from django.template.defaultfilters import truncatewords_html @@ -50,52 +50,219 @@ from ietf.idrfc import markup_txt from ietf.idrfc.models import RfcIndex, DraftVersions from ietf.idrfc.idrfc_wrapper import BallotWrapper, IdWrapper, RfcWrapper from ietf.ietfworkflows.utils import get_full_info_for_draft +from ietf.doc.models import Document, DocEvent, NewRevisionDocEvent, WriteupDocEvent +from ietf.utils.history import find_history_active_at +from ietf.ietfauth.decorators import has_role + def render_document_top(request, doc, tab): tabs = [] - tabs.append(("Document", "document", urlreverse("idrfc.views_doc.document_main", kwargs=dict(name=doc.name)))) + tabs.append(("Document", "document", urlreverse("ietf.idrfc.views_doc.document_main", kwargs=dict(name=doc.name)))) - if doc_type == "draft": - tabs.append(("IESG Evaluation Record", "ballot", urlreverse("idrfc.views_doc.document_ballot", kwargs=dict(name=doc.name)))) - elif doc_type == "charter": - tabs.append(("IESG Review", "ballot", urlreverse("idrfc.views_doc.document_ballot", kwargs=dict(name=doc.name)))) + if doc.type_id == "draft": + # if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot: + tabs.append(("IESG Evaluation Record", "ballot", urlreverse("ietf.idrfc.views_doc.document_ballot", kwargs=dict(name=doc.name)))) + elif doc.type_id == "charter": + tabs.append(("IESG Review", "ballot", urlreverse("ietf.idrfc.views_doc.document_ballot", kwargs=dict(name=doc.name)))) - tabs.append(("IESG Writeups", "writeup", urlreverse("idrfc.views_doc.document_writeup", kwargs=dict(name=doc.name)))) - tabs.append(("History", "history", urlreverse("idrfc.views_doc.document_history", kwargs=dict(name=doc.name)))) + # FIXME: if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot: + tabs.append(("IESG Writeups", "writeup", urlreverse("ietf.idrfc.views_doc.document_writeup", kwargs=dict(name=doc.name)))) + tabs.append(("History", "history", urlreverse("ietf.idrfc.views_doc.document_history", kwargs=dict(name=doc.name)))) + + name = doc.canonical_name() + if name.startswith("rfc"): + name = "RFC %s" % name[3:] + else: + name += "-" + doc.rev return render_to_string("idrfc/document_top.html", dict(doc=doc, tabs=tabs, - selected=tab)) + selected=tab, + name=name)) -def document_main(request, name): - if name.startswith("ietf-charter-"): - # FIXME: render top - # render content - # refactor history similarly? or use directly - # refactor writeup, generalize on names and links to edit - # refactor ballot to have multiple ballot typesiet +def document_main(request, name, rev=None): + if name.lower().startswith("draft") or name.lower().startswith("rfc"): + if rev != None: # no support for old revisions at the moment + raise Http404() + return document_main_idrfc(request, name, tab="document") - return render_to_response("idrfc/doc_tab_document.html", - {'content1':content1, - 'content2':content2, - 'doc': doc, - 'tab': "document", - 'include_text':include_text(request)}, - context_instance=RequestContext(request)); + doc = get_object_or_404(Document, docalias__name=name) + + revisions = [ doc.rev ] + for h in doc.history_set.order_by("-time"): + if not h.rev in revisions: + revisions.append(h.rev) + + snapshot = False + + if rev != None: + if rev == doc.rev: + return redirect('doc_view', name=name) + + # find the entry in the history + for h in doc.history_set.order_by("-time"): + if rev == h.rev: + snapshot = True + doc = h + break + + if not snapshot: + return redirect('doc_view', name=name) + + # find old group, too + gh = find_history_active_at(doc.group, doc.time) + if gh: + doc.group = gh + + top = render_document_top(request, doc, "document") - return document_main_idrfc(request, name, "document") + if doc.type_id == "charter": + # FIXME: add editing of charters/telechat date + # FIXME: check sanity of edit buttons "Recharter" + # FIXME: clean up wgcharter code redundant with this + + filename = doc.name + "-" + doc.rev + ".txt" + + content = _get_html(filename, os.path.join(settings.CHARTER_PATH, filename), split=False) + + telechat = None + if not snapshot: + telechat = doc.latest_event(type="scheduled_for_telechat") + + return render_to_response("idrfc/document_charter.html", + dict(doc=doc, + top=top, + chartering=get_chartering_type(doc), + content=content, + txt_url=settings.CHARTER_TXT_URL + filename, + revisions=revisions, + snapshot=snapshot, + telechat=telechat, + ), + context_instance=RequestContext(request)) + + raise Http404() + def document_history(request, name): - return document_main_idrfc(request, name, "history") + # todo: remove need for specific handling of drafts by porting the + # two event text hacks + if name.lower().startswith("draft") or name.lower().startswith("rfc"): + return document_main_idrfc(request, name, "history") + + + doc = get_object_or_404(Document, docalias__name=name) + top = render_document_top(request, doc, "history") + + diff_documents = [ doc ] + diff_documents.extend(Document.objects.filter(docalias__relateddocument__source=doc, docalias__relateddocument__relationship="replaces")) + + # pick up revisions from events + diff_revisions = [] + seen = set() + + diffable = name.startswith("draft") or name.startswith("charter") + + if diffable: + for e in NewRevisionDocEvent.objects.filter(type="new_revision", doc__in=diff_documents).select_related('doc').order_by("-time", "-id"): + if not (e.doc.name, e.rev) in seen: + seen.add((e.doc.name, e.rev)) + + url = "" + if name.startswith("charter"): + url = settings.CHARTER_TXT_URL + e.doc.name + e.rev + ".txt" + elif name.startswith("draft"): + # rfcdiff tool has special support for IDs + url = e.doc.name + "-" + e.rev + + diff_revisions.append((e.doc.name, e.rev, e.time, url)) + + # grab event history + events = doc.docevent_set.all().order_by("-time", "-id").select_related("by") + + # fill in revision numbers + event_revisions = list(NewRevisionDocEvent.objects.filter(doc=doc).order_by('time', 'id').values('rev', 'time')) + + cur_rev = doc.rev + if doc.get_state_slug() == "rfc": + cur_rev = "RFC" + + for e in events: + while event_revisions and e.time < event_revisions[-1]["time"]: + event_revisions.pop() + + if event_revisions: + cur_rev = event_revisions[-1]["rev"] + else: + cur_rev = "00" + + e.rev = cur_rev + + # add snippets + for e in events: + e.desc_snippet = truncatewords_html(format_textarea(fill(e.desc, 80)), 3) + if not e.desc_snippet.endswith("..."): + e.desc_snippet = None + + return render_to_response("idrfc/document_history.html", + dict(doc=doc, + top=top, + diff_revisions=diff_revisions, + events=events, + ), + context_instance=RequestContext(request)) def document_writeup(request, name): - return document_main_idrfc(request, name, "writeup") + if name.lower().startswith("draft") or name.lower().startswith("rfc"): + # todo: migrate idrfc to pattern below + return document_main_idrfc(request, name, "writeup") -def document_ballot(request, name): - return document_main_idrfc(request, name, "ballot") + doc = get_object_or_404(Document, docalias__name=name) + top = render_document_top(request, doc, "writeup") + + writeups = [] + if doc.type_id == "charter": + e = doc.latest_event(WriteupDocEvent, type="changed_review_announcement") + writeups.append(("WG Review Announcement", + e.text if e else "", + urlreverse("ietf.wgcharter.views_ballot.announcement_text", kwargs=dict(name=doc.group.acronym, ann="review")))) + + e = doc.latest_event(WriteupDocEvent, type="changed_action_announcement") + writeups.append(("WG Action Announcement", + e.text if e else "", + urlreverse("ietf.wgcharter.views_ballot.announcement_text", kwargs=dict(name=doc.group.acronym, ann="action")))) + + e = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text") + writeups.append(("Ballot Announcement", + e.text if e else "", + urlreverse("ietf.wgcharter.views_ballot.ballot_writeupnotes", kwargs=dict(name=doc.group.acronym)))) + + if not writeups: + raise Http404() + + return render_to_response("idrfc/document_writeup.html", + dict(doc=doc, + top=top, + writeups=writeups, + can_edit=has_role(request.user, ("Area Director", "Secretariat")), + ), + context_instance=RequestContext(request)) + + + +def document_ballot(request, name, ballot=None): + if name.lower().startswith("draft") or name.lower().startswith("rfc"): + return document_main_idrfc(request, name, "ballot") + + doc = get_object_or_404(Document, docalias__name=name) + top = render_document_top(request, doc, "ballot") + + # FIXME: port implementation from wgcharter + + raise Http404() def document_debug(request, name): r = re.compile("^rfc([1-9][0-9]*)$") @@ -109,7 +276,7 @@ def document_debug(request, name): doc = IdWrapper(draft=id) return HttpResponse(doc.to_json(), mimetype='text/plain') -def _get_html(key, filename): +def _get_html(key, filename, split=True): f = None try: f = open(filename, 'rb') @@ -119,8 +286,7 @@ def _get_html(key, filename): finally: if f: f.close() - (c1,c2) = markup_txt.markup(raw_content) - return (c1,c2) + return markup_txt.markup(raw_content, split) def include_text(request): include_text = request.GET.get( 'include_text' ) diff --git a/ietf/templates/idrfc/document_charter.html b/ietf/templates/idrfc/document_charter.html new file mode 100644 index 000000000..1e8db5c32 --- /dev/null +++ b/ietf/templates/idrfc/document_charter.html @@ -0,0 +1,109 @@ +{% extends "base.html" %} + +{% load ietf_filters %} + +{% block title %}{{ doc.name }}-{{ doc.rev }}{% endblock %} + +{% block pagehead %} + +{% endblock %} + +{% block content %} +{{ top|safe }} + +
    + Snapshots: + + {% for rev in revisions %} + {{ rev }} + {% endfor %} + +
    + +
    +
    + {% if snapshot %}Snapshot of{% endif %} + {% if doc.get_state_slug != "approved" %}Proposed{% endif %} + Charter for {{ doc.group.name }} + ({{ doc.group.acronym }} {{ doc.group.type.name }}) +
    + + + + + + + + + + + + {% if chartering %} + + {% if doc.group.comments %} + + {% if chartering == "initial" %}{% endif %} + {% if chartering == "rechartering" %}{% endif %} + + + {% endif %} + + {% if not snapshot %} + + + + + {% endif %} + + + + + + {% endif %} + + +
    WG State:{{ doc.group.state.name }}
    Charter State: + {{ doc.get_state.name }} + {% if chartering == "initial" %}(Initial Chartering){% endif %} + {% if chartering == "rechartering" %}(Rechartering){% endif %} + + {% if not snapshot and user|has_role:"Area Director,Secretariat" %} + - Change state + {% endif %} +
    Reason for chartering:Reason for rechartering:{{ doc.group.comments }}
    Telechat: + {% if not doc.telechat %}Not on agenda{% else %}{{ doc.telechat.date|date:"Y-m-d" }}{% endif %} + {% if user|has_role:"Area Director,Secretariat" %} + - Change + {% endif %} +

    Last updated: {{ doc.time|date:"Y-m-d" }}

    + +{% if not snapshot and user|has_role:"Area Director,Secretariat" %} + +{% if chartering %} + +{% if doc.group.state_id != "conclude" %} +Edit charter +{% endif %} + +Abandon effort + +{% else %} +Recharter +{% endif %} + +{% endif %} + + +
    + +

    Other versions: plain text

    + +

    Charter {{ doc.name }}-{{ doc.rev }}

    + +
    +{{ content|fill:"80"|safe|linebreaksbr|keep_spacing|sanitize_html|safe }} +
    + + +{% endblock %} + diff --git a/ietf/templates/idrfc/document_history.html b/ietf/templates/idrfc/document_history.html new file mode 100644 index 000000000..f6060c57c --- /dev/null +++ b/ietf/templates/idrfc/document_history.html @@ -0,0 +1,88 @@ +{% extends "base.html" %} + +{% load ietf_filters %} + +{% block title %}History for {{ doc.name }}-{{ doc.rev }}{% endblock %} + +{% block pagehead %} + +{% endblock %} + +{% block content %} +{{ top|safe }} + +{% if diff_revisions %} +
    +

    Diffs

    + +
    + + + + + + + + +
    + + + + + + +
    + + +
    +
    +
    +{% endif %} + +

    Document history

    +{% if user|has_role:"Area Director,Secretariat,IANA" %} + +{% endif %} + + + + + + {% for e in events %} + + + + + + + {% endfor %} + +
    DateVersionByText
    {{ e.time|date:"Y-m-d" }}{{ e.rev }}{{ e.by|escape }}{% if e.desc_snippet %} +
    {{ e.desc_snippet|safe }} [show all]
    + + {% else %} + {{ e.desc|fill:"80"|safe|urlize|linebreaksbr|keep_spacing|sanitize_html|safe }} + {% endif %} +
    +{% endblock content %} + +{% block content_end %} + +{% endblock content_end %} diff --git a/ietf/templates/idrfc/document_top.html b/ietf/templates/idrfc/document_top.html new file mode 100644 index 000000000..585e3b38c --- /dev/null +++ b/ietf/templates/idrfc/document_top.html @@ -0,0 +1,9 @@ +

    {{ doc.title }}
    {{ name }}

    + +
    +
      + {% for name, t, url in tabs %} +
    • {{ name }}
    • + {% endfor %} +
    +
    diff --git a/ietf/templates/idrfc/document_writeup.html b/ietf/templates/idrfc/document_writeup.html new file mode 100644 index 000000000..b125ed80c --- /dev/null +++ b/ietf/templates/idrfc/document_writeup.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} + +{% block title %}Writeups for {{ doc.name }}-{{ doc.rev }}{% endblock %} + +{% block pagehead %} + +{% endblock %} + +{% block content %} +{{ top|safe }} + +{% for title, text, url in writeups %} +
    +

    {{ title }}

    + +{% if can_edit %}Edit {{ title }}{% endif %} + +
    +{{ text }}
    +
    +
    +{% endfor%} + +{% endblock content %} From fb139041debcd8dbfc71d27158c65574da37ae28 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 15 Mar 2012 17:54:43 +0000 Subject: [PATCH 07/72] Fix commented FIXME links, linking to new chartering/rechartering WG page instead. - Legacy-Id: 4092 --- ietf/templates/base_leftmenu.html | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ietf/templates/base_leftmenu.html b/ietf/templates/base_leftmenu.html index a9a9fdb48..890cb7940 100644 --- a/ietf/templates/base_leftmenu.html +++ b/ietf/templates/base_leftmenu.html @@ -42,14 +42,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  • My Documents
  • Next Telechat
  • Discusses
  • -
  • Working Groups
  • - {# FIXME: wgcharter
  • Working Groups
  • #} {% endif %} {% if user|in_group:"Secretariat" %}
  • Secretariat
  • Telechat Dates
  • -
  • Working Groups
  • - {# FIXME: wgcharter
  • Working Groups
  • #} {% endif %} {% if user %} {% get_user_managed_streams user as stream_list %} @@ -69,7 +65,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  • Active WGs
  • - {# FIXME: wgcharter
  • Proposed WGs
  • #} +
  • Chartering WGs
  • Concluded WGs
  • Non-WG Lists
  • @@ -86,7 +82,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  • Upcoming
  • Other Documents
  • - {# FIXME: wgcharter
  • WG Charters
  • #}
  • IPR Disclosures
  • Liaison Statements
  • IESG Agenda
  • From 5cfc72937d5f1d3714a5a800c5e208388809fd6d Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 15 Mar 2012 17:56:41 +0000 Subject: [PATCH 08/72] Fix missing import - Legacy-Id: 4093 --- ietf/idrfc/views_doc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py index c20b4530d..15f3243f8 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/idrfc/views_doc.py @@ -51,6 +51,7 @@ from ietf.idrfc.models import RfcIndex, DraftVersions from ietf.idrfc.idrfc_wrapper import BallotWrapper, IdWrapper, RfcWrapper from ietf.ietfworkflows.utils import get_full_info_for_draft from ietf.doc.models import Document, DocEvent, NewRevisionDocEvent, WriteupDocEvent +from ietf.doc.utils import get_chartering_type from ietf.utils.history import find_history_active_at from ietf.ietfauth.decorators import has_role From c7d9839b1c7d46996377b323e5f47119c18f2c14 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 15 Mar 2012 17:57:12 +0000 Subject: [PATCH 09/72] Fix get_absolute_url to make it point to /doc/ page for charters - Legacy-Id: 4094 --- ietf/doc/models.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ietf/doc/models.py b/ietf/doc/models.py index 83b770d8d..1872d52a1 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -144,14 +144,11 @@ class Document(DocumentInfo): def get_absolute_url(self): name = self.name - if self.type_id == "charter": - return urlreverse('wg_view', kwargs={ 'name': self.group.acronym }) - elif self.type_id == "draft": - if self.get_state_slug() == "rfc": - aliases = self.docalias_set.filter(name__startswith="rfc") - if aliases: - name = aliases[0].name - return urlreverse('doc_view', kwargs={ 'name': name }) + if self.type_id == "draft" and self.get_state_slug() == "rfc": + aliases = self.docalias_set.filter(name__startswith="rfc") + if aliases: + name = aliases[0].name + return urlreverse('doc_view', kwargs={ 'name': name }, urlconf="ietf.urls") def file_tag(self): return u"<%s>" % self.filename_with_rev() @@ -201,6 +198,10 @@ class DocHistory(DocumentInfo): authors = models.ManyToManyField(Email, through=DocHistoryAuthor, blank=True) def __unicode__(self): return unicode(self.doc.name) + + def canonical_name(self): + return self.name + class Meta: verbose_name = "document history" verbose_name_plural = "document histories" From 1bf9ec8542eda4c2b547872343772c1ace549beb Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 15 Mar 2012 17:59:11 +0000 Subject: [PATCH 10/72] Add missing Javascript file. - Legacy-Id: 4095 --- static/js/doc-history.js | 5 +++++ static/js/history.js | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 static/js/doc-history.js delete mode 100644 static/js/history.js diff --git a/static/js/doc-history.js b/static/js/doc-history.js new file mode 100644 index 000000000..eaae6ca6f --- /dev/null +++ b/static/js/doc-history.js @@ -0,0 +1,5 @@ +jQuery(function () { + jQuery("table.history .snippet .showAll").click(function () { + jQuery(this).parents(".snippet").hide().siblings(".full").show(); + }); +}); diff --git a/static/js/history.js b/static/js/history.js deleted file mode 100644 index 843c8f79a..000000000 --- a/static/js/history.js +++ /dev/null @@ -1,5 +0,0 @@ -jQuery(function () { - jQuery("table.history .snipped .showAll").click(function () { - jQuery(this).parents("snipped").hide().siblings("full").show(); - }); -}); From 00f2b0d0c2849bc0e581f9a76f288181af6e20f3 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 15 Mar 2012 18:01:50 +0000 Subject: [PATCH 11/72] Remove superfluous wgcharter search views. - Legacy-Id: 4096 --- ietf/wgcharter/urls.py | 6 +- ietf/wgcharter/views.py | 11 ++ ietf/wgcharter/views_search.py | 296 --------------------------------- 3 files changed, 12 insertions(+), 301 deletions(-) delete mode 100644 ietf/wgcharter/views_search.py diff --git a/ietf/wgcharter/urls.py b/ietf/wgcharter/urls.py index 042088d0c..37f8a3702 100644 --- a/ietf/wgcharter/urls.py +++ b/ietf/wgcharter/urls.py @@ -8,12 +8,8 @@ urlpatterns = patterns('django.views.generic.simple', url(r'^help/state/$', 'direct_to_template', { 'template': 'wgcharter/states.html', 'extra_context': { 'states': State.objects.filter(type="charter") } }, name='help_charter_states'), ) urlpatterns += patterns('', - (r'^/?$', views_search.search_main), url(r'^create/$', views_edit.edit_info, name="wg_create"), - url(r'^search/$', views_search.search_results, name="wg_search"), - (r'^searchPerson/$', views_search.search_person), - url(r'^area/(?P[A-Za-z0-9.-]+)/$', views_search.by_area, name="wg_search_by_area"), - url(r'^in_process/$', views_search.in_process, name="wg_search_in_process"), + (r'^searchPerson/$', views.search_person), # FIXME: fix URL url(r'^(?P[A-Za-z0-9._+-]+)/((?P[0-9][0-9](-[0-9][0-9])?)/)?((?Pballot|writeup|history)/)?$', views.wg_main, name="wg_view"), (r'^(?P[A-Za-z0-9._+-]+)/_ballot.data$', views.wg_ballot), url(r'^(?P[A-Za-z0-9._+-]+)/edit/state/$', views_edit.change_state, name='wg_change_state'), diff --git a/ietf/wgcharter/views.py b/ietf/wgcharter/views.py index 53bec4cc4..535aadcab 100644 --- a/ietf/wgcharter/views.py +++ b/ietf/wgcharter/views.py @@ -243,3 +243,14 @@ def wg_ballot(request, name): info['pos_no_record'] = no_record return render_to_response('wgcharter/wg_ballot.html', {'info':info, 'wg':wg, 'doc': doc}, context_instance=RequestContext(request)) + +def json_emails(l): + result = [] + for p in l: + result.append({"id": p.address + "", "name": p.person.plain_name() + " <" + p.address + ">"}) + return simplejson.dumps(result) + +def search_person(request): + if request.method == 'GET': + emails = Email.objects.filter(person__name__istartswith=request.GET.get('q','')).order_by('person__name') + return HttpResponse(json_emails(emails), mimetype='application/json') diff --git a/ietf/wgcharter/views_search.py b/ietf/wgcharter/views_search.py deleted file mode 100644 index 9d5faac58..000000000 --- a/ietf/wgcharter/views_search.py +++ /dev/null @@ -1,296 +0,0 @@ -# Copyright The IETF Trust 2011, All Rights Reserved - -import re, os -import datetime -from django import forms -from django.shortcuts import render_to_response, redirect -from django.db.models import Q -from django.template import RequestContext -from django.views.decorators.cache import cache_page -from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponsePermanentRedirect -from django.conf import settings -from django.utils import simplejson - -from ietf.doc.models import Document, State -from ietf.name.models import GroupStateName -from ietf.group.models import Group -from ietf.person.models import Person, Email -from ietf.doc.utils import augment_with_telechat_date - -class SearchForm(forms.Form): - nameacronym = forms.CharField(required=False) - - inprocess = forms.BooleanField(required=False,initial=True) - active = forms.BooleanField(required=False,initial=False) - concluded = forms.BooleanField(required=False, initial=False) - - by = forms.ChoiceField(choices=[(x,x) for x in ('acronym','state','ad','area','anyfield', 'eacronym')], required=False, initial='wg', label='Foobar') - state = forms.ModelChoiceField(GroupStateName.objects.all(), label="WG state", empty_label="any state", required=False) - charter_state = forms.ModelChoiceField(State.objects.filter(type="charter"), label="Charter state", empty_label="any state", required=False) - ad = forms.ChoiceField(choices=(), required=False) - area = forms.ModelChoiceField(Group.objects.filter(type="area", state="active").order_by('name'), empty_label="any area", required=False) - anyfield= forms.CharField(required=False) - eacronym = forms.CharField(required=False) - - def __init__(self, *args, **kwargs): - super(SearchForm, self).__init__(*args, **kwargs) - responsible = Document.objects.values_list('ad', flat=True).distinct() - active_ads = list(Person.objects.filter(email__role__name="ad", - email__role__group__type="area", - email__role__group__state="active").distinct()) - inactive_ads = list(Person.objects.filter(pk__in=responsible) - .exclude(pk__in=[x.pk for x in active_ads])) - extract_last_name = lambda x: x.name_parts()[3] - active_ads.sort(key=extract_last_name) - inactive_ads.sort(key=extract_last_name) - - self.fields['ad'].choices = c = [('', 'any AD')] + [(ad.pk, ad.plain_name()) for ad in active_ads] + [('', '------------------')] + [(ad.pk, ad.name) for ad in inactive_ads] - - def clean_nameacronym(self): - value = self.cleaned_data.get('nameacronym','') - return value - - def clean(self): - q = self.cleaned_data - # Reset query['by'] if needed - for k in ('ad', 'area', 'anyfield', 'eacronym'): - if (q['by'] == k) and not q[k]: - q['by'] = None - if (q['by'] == 'state') and not (q.get('state') or q.get('charter_state')): - q['by'] = None - # Reset other fields - for k in ('ad', 'area', 'anyfield', 'eacronym'): - if q['by'] != k: - self.data[k] = "" - q[k] = "" - if q['by'] != 'state': - self.data['state'] = "" - self.data['charter_state'] = "" - q['state'] = "" - q['charter_state'] = "" - return q - -def search_query(query_original, sort_by=None): - query = dict(query_original.items()) - - # Non-ASCII strings don't match anything; this check - # is currently needed to avoid complaints from MySQL. - for k in ['nameacronym','anyfield','eacronym']: - try: - tmp = str(query.get(k, '')) - except: - query[k] = '*NOSUCH*' - - # Search - MAX = 500 - maxReached = False - - q_obj = Q(type__slug="wg", state__slug__in=("proposed", "active", "conclude")) - - s_obj = Q() - if query["inprocess"]: - s_obj |= Q(charter__states__type="charter", charter__states__slug__in=("infrev", "intrev", "extrev", "iesgrev")) & Q(state__slug__in=("proposed", "active")) - if query["active"]: - s_obj |= Q(charter__states__type="charter", charter__states__slug="approved") & Q(state__slug="active") - if query["concluded"]: - s_obj |= Q(state__slug="conclude") | Q(charter__states__type="charter", charter__states__slug="notrev") - - results = Group.objects.filter(q_obj & s_obj).select_related("charter") - - prefix = "" - q_objs = [] - # name - if query["nameacronym"]: - results = results.filter(Q(name__icontains=query["nameacronym"]) | Q(acronym__icontains=query["nameacronym"])) - # radio choices - by = query["by"] - if by == "state": - q_objs = [] - if query['state']: - q_objs.append(Q(state=query['state'])) - if query['charter_state']: - q_objs.append(Q(charter__states__type="charter", charter__states__slug=query['charter_state'])) - results = results.filter(*q_objs) - elif by == "ad": - results = results.filter(ad=query["ad"]) - elif by == "area": - results = results.filter(parent=query["area"]) - elif by == "anyfield": - q_obj = Q() - q_obj |= Q(state__name__icontains=query['anyfield']) - q_obj |= Q(charter__states__type="charter", charter__states__name__icontains=query['anyfield']) - q_obj |= Q(ad__name__icontains=query['anyfield']) - q_obj |= Q(parent__name__icontains=query['anyfield']) - q_obj |= Q(history_set__acronym__icontains=query['anyfield']) - results = list(results.filter(q_obj)) - # Search charter texts - m = re.compile(query['anyfield'], re.IGNORECASE) - if query['nameacronym']: - file_set = Group.objects.filter(type="wg", name__icontains=query["nameacronym"]) - else: - file_set = Group.objects.filter(type="wg") - for g in file_set: - charter = g.charter - 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() - - results = list(results[:MAX]) - if len(results) == MAX: - maxReached = True - - # sort - def sort_key(g): - res = [] - - if sort_by == "acronym": - res.append(g.acronym) - elif sort_by == "name": - res.append(g.name) - elif sort_by == "date": - res.append(str(g.time or datetime.date(1990, 1, 1))) - elif sort_by == "status": - if g.charter: - s = g.charter.get_state() - if s: - res.append(s.order) - # Sort secondary by group state - res.append(g.state.name) - - return res - - results.sort(key=sort_key) - - meta = {} - if maxReached: - meta['max'] = MAX - if query['by']: - meta['advanced'] = True - - augment_with_telechat_date([r.charter for r in results]) - - return (results,meta) - -def generate_query_string(request, ignore_list): - """Recreates the parameter string from the given request, and - returns it as a string. - Any parameter names present in ignore_list shall not be put - in the result string. - """ - params = [] - for i in request.GET: - if not i in ignore_list: - params.append(i + "=" + request.GET[i]) - return "?" + "&".join(params) - -def search_results(request): - if len(request.REQUEST.items()) == 0: - return search_main(request) - form = SearchForm(dict(request.REQUEST.items())) - if not form.is_valid(): - return HttpResponseBadRequest("form not valid?", mimetype="text/plain") - - sort_by = None - if "sortBy" in request.GET: - sort_by = request.GET["sortBy"] - - (results,meta) = search_query(form.cleaned_data, sort_by) - - meta['searching'] = True - meta['by'] = form.cleaned_data['by'] - meta['rqps'] = generate_query_string(request, ['sortBy']) - # With a later Django we can do this from the template (incude with tag) - # Pass the headers and their sort key names - meta['hdrs'] = [{'htitle': 'Acronym', 'htype':'acronym'}, - {'htitle': 'Name', 'htype':'name'}, - {'htitle': 'Date', 'htype':'date'}, - {'htitle': 'Status', 'htype':'status', 'colspan':'2'}, - ] - if 'ajax' in request.REQUEST and request.REQUEST['ajax']: - return render_to_response('wgcharter/search_results.html', {'recs':results, 'meta':meta}, context_instance=RequestContext(request)) - elif len(results) == 1: - wg = results[0] - return redirect('wg_view', name=wg.acronym) - else: - return render_to_response('wgcharter/search_main.html', {'form':form, 'recs':results,'meta':meta}, context_instance=RequestContext(request)) - - -def search_main(request): - form = SearchForm() - return render_to_response('wgcharter/search_main.html', {'form':form}, context_instance=RequestContext(request)) - -def by_area(request, name): - area_id = None - area_name = None - for a in Group.objects.filter(type="area"): - if name == a.acronym: - area_id = a.id - area_name = a.name - break - if not area_id: - raise Http404 - form = SearchForm({'inprocess': True, 'active': True, 'concluded': True, 'by':'area','area':area_id}) - if not form.is_valid(): - raise ValueError("form did not validate") - (results,meta) = search_query(form.cleaned_data) - meta['searching'] = True - meta['by'] = form.cleaned_data['by'] - meta['rqps'] = generate_query_string(request, ['sortBy']) - # With a later Django we can do this from the template (incude with tag) - # Pass the headers and their sort key names - meta['hdrs'] = [{'htitle': 'Acronym', 'htype':'acronym'}, - {'htitle': 'Name', 'htype':'name'}, - {'htitle': 'Date', 'htype':'date'}, - {'htitle': 'Status', 'htype':'status', 'colspan':'2'}, - ] - fresults = [] - for r in results: - if r.state_id == "proposed" and r.charter.get_state_slug() == "notrev": - if r.charter.latest_event(desc__icontains="abandoned"): - if r.charter.latest_event(desc__icontains="abandoned").time > datetime.datetime.now() - datetime.timedelta(days=31): - # Abandoned recently - fresults.append(r) - else: - if not r.state_id == "conclude": - fresults.append(r) - - fresults.sort(key=lambda g: str(g.time or datetime.date(1990, 1, 1)), reverse=True) - return render_to_response('wgcharter/by_area.html', {'form':form, 'recs':fresults,'meta':meta, 'area_name':area_name}, context_instance=RequestContext(request)) - -def in_process(request): - results = Group.objects.filter(type="wg", - charter__states__slug__in=['infrev', 'intrev', 'extrev', 'iesgrev'], - charter__states__type="charter").order_by('-time').select_related("charter") - augment_with_telechat_date([r.charter for r in results]) - - meta = {} - meta['searching'] = True - meta['by'] = 'state' - meta['rqps'] = generate_query_string(request, ['sortBy']) - # With a later Django we can do this from the template (incude with tag) - # Pass the headers and their sort key names - meta['hdrs'] = [{'htitle': 'Acronym', 'htype':'acronym'}, - {'htitle': 'Name', 'htype':'name'}, - {'htitle': 'Date', 'htype':'date'}, - {'htitle': 'Status', 'htype':'status', 'colspan':'2'}, - ] - return render_to_response('wgcharter/in_process.html', {'recs':results,'meta':meta}, context_instance=RequestContext(request)) - -def json_emails(l): - result = [] - for p in l: - result.append({"id": p.address + "", "name": p.person.plain_name() + " <" + p.address + ">"}) - return simplejson.dumps(result) - -def search_person(request): - if request.method == 'GET': - emails = Email.objects.filter(person__name__istartswith=request.GET.get('q','')).order_by('person__name') - return HttpResponse(json_emails(emails), mimetype='application/json') From 3b9964ef0916c04a73af948b2da61d388c19db67 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Tue, 20 Mar 2012 18:09:22 +0000 Subject: [PATCH 12/72] Add telechat edit page, remove some dead code, fix some bugs. - Legacy-Id: 4143 --- ietf/templates/idrfc/document_charter.html | 6 +- .../wgcharter/edit_telechat_date.html | 29 +++ ietf/wgcharter/urls.py | 2 +- ietf/wgcharter/utils.py | 15 +- ietf/wgcharter/views_edit.py | 196 +++++++++--------- 5 files changed, 133 insertions(+), 115 deletions(-) create mode 100644 ietf/templates/wgcharter/edit_telechat_date.html diff --git a/ietf/templates/idrfc/document_charter.html b/ietf/templates/idrfc/document_charter.html index 1e8db5c32..5b1b6c0cc 100644 --- a/ietf/templates/idrfc/document_charter.html +++ b/ietf/templates/idrfc/document_charter.html @@ -58,11 +58,11 @@ {% if not snapshot %} - Telechat: + IESG telechat: - {% if not doc.telechat %}Not on agenda{% else %}{{ doc.telechat.date|date:"Y-m-d" }}{% endif %} + {% if not telechat %}Not on agenda{% else %}{{ telechat.telechat_date|date:"Y-m-d" }}{% endif %} {% if user|has_role:"Area Director,Secretariat" %} - - Change + - Change {% endif %} diff --git a/ietf/templates/wgcharter/edit_telechat_date.html b/ietf/templates/wgcharter/edit_telechat_date.html new file mode 100644 index 000000000..390a197b2 --- /dev/null +++ b/ietf/templates/wgcharter/edit_telechat_date.html @@ -0,0 +1,29 @@ +{% extends "base.html" %} + +{% block title %} +Set Telechat Date for {{ doc.name }} +{% endblock %} + +{% block morecss %} +form.telechat-date td.actions { + padding-top: 1em; +} +{% endblock %} + +{% block content %} +{% load ietf_filters %} +

    Set Telechat Date for {{ doc.name }}

    + +
    + + {{ form.as_table }} + + + + +
    + Back + +
    +
    +{% endblock %} diff --git a/ietf/wgcharter/urls.py b/ietf/wgcharter/urls.py index 37f8a3702..f744f11fa 100644 --- a/ietf/wgcharter/urls.py +++ b/ietf/wgcharter/urls.py @@ -14,9 +14,9 @@ urlpatterns += patterns('', (r'^(?P[A-Za-z0-9._+-]+)/_ballot.data$', views.wg_ballot), url(r'^(?P[A-Za-z0-9._+-]+)/edit/state/$', views_edit.change_state, name='wg_change_state'), url(r'^(?P[A-Za-z0-9._+-]+)/edit/(?P