From 0144ef366b6ea4a4bf9a110ae45d802bdb77e25a Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Tue, 20 May 2014 10:19:26 +0000 Subject: [PATCH] Add description field on group, enable most group info page views to work without a group type to pave the way for /group// URLs, make charter page more generic, enable it to handle descriptions and walk over all personnel instead of picking out specific types of roles, add a redirect view on /group// to lead to either documents/ or charter/, add simple group.features() class to be able to condition on group features rather than specific group types, adjust group pages menu accordingly - Legacy-Id: 7758 --- ietf/community/display.py | 2 +- ietf/doc/templatetags/ietf_filters.py | 4 - ietf/doc/views_doc.py | 2 +- ietf/group/features.py | 19 ++ ietf/group/info.py | 184 +++++++--- ...ion__add_field_grouphistory_description.py | 317 ++++++++++++++++++ ietf/group/models.py | 5 + ietf/group/urls.py | 14 + ietf/name/migrations/0020_sort_role_names.py | 207 ++++++++++++ ietf/templates/group/active_rgs.html | 2 +- ietf/templates/group/active_wgs.html | 2 +- ietf/templates/group/group_base.html | 13 +- ietf/templates/group/group_charter.html | 87 +---- .../group/group_entry_with_charter.txt | 2 +- 14 files changed, 721 insertions(+), 139 deletions(-) create mode 100644 ietf/group/features.py create mode 100644 ietf/group/migrations/0007_auto__add_field_group_description__add_field_grouphistory_description.py create mode 100644 ietf/name/migrations/0020_sort_role_names.py diff --git a/ietf/community/display.py b/ietf/community/display.py index d42769597..75d2ba421 100644 --- a/ietf/community/display.py +++ b/ietf/community/display.py @@ -88,7 +88,7 @@ class WGField(DisplayField): if raw: return document.group.acronym else: - return '%s' % (urlreverse('group_docs', kwargs=dict(group_type=document.group.type_id, acronym=document.group.acronym)), document.group.acronym) if (document.group and document.group.acronym != 'none') else '' + return '%s' % (urlreverse('group_home', kwargs=dict(group_type=document.group.type_id, acronym=document.group.acronym)), document.group.acronym) if (document.group and document.group.acronym != 'none') else '' class ADField(DisplayField): diff --git a/ietf/doc/templatetags/ietf_filters.py b/ietf/doc/templatetags/ietf_filters.py index 2a0b0e132..2d03d55f4 100644 --- a/ietf/doc/templatetags/ietf_filters.py +++ b/ietf/doc/templatetags/ietf_filters.py @@ -22,10 +22,6 @@ def expand_comma(value): long comma-separated lists.""" return value.replace(",", ", ") -@register.filter(name='format_charter') -def format_charter(value): - return value.replace("\n\n", "

").replace("\n","
\n") - @register.filter def indent(value, numspaces=2): replacement = "\n" + " " * int(numspaces) diff --git a/ietf/doc/views_doc.py b/ietf/doc/views_doc.py index 4c5ad4c88..133ab5ea0 100644 --- a/ietf/doc/views_doc.py +++ b/ietf/doc/views_doc.py @@ -243,7 +243,7 @@ def document_main(request, name, rev=None): elif group.type_id in ("rg", "wg"): submission = "%s %s" % (group.acronym, group.type) if group.type_id == "wg": - submission = "%s" % (urlreverse("group_docs", kwargs=dict(group_type=doc.group.type_id, acronym=doc.group.acronym)), submission) + submission = "%s" % (urlreverse("group_home", kwargs=dict(group_type=doc.group.type_id, acronym=doc.group.acronym)), submission) if doc.stream_id and doc.get_state_slug("draft-stream-%s" % doc.stream_id) == "c-adopt": submission = "candidate for %s" % submission diff --git a/ietf/group/features.py b/ietf/group/features.py new file mode 100644 index 000000000..532dfc06a --- /dev/null +++ b/ietf/group/features.py @@ -0,0 +1,19 @@ +class GroupFeatures(object): + """Configuration of group pages and processes to have this collected + in one place rather than scattered over the group page views.""" + + has_milestones = False + has_chartering_process = False + has_documents = False + customize_workflow = False + default_tab = "group_charter" + + def __init__(self, group): + if group.type_id in ("wg", "rg"): + self.has_milestones = True + self.has_chartering_process = True + self.has_documents = True + self.customize_workflow = True + self.default_tab = "group_docs" + elif group.type_id in ("team",): + self.has_documents = True diff --git a/ietf/group/info.py b/ietf/group/info.py index 4068873f4..22a17a2d6 100644 --- a/ietf/group/info.py +++ b/ietf/group/info.py @@ -38,11 +38,12 @@ from tempfile import mkstemp from django.shortcuts import get_object_or_404, render from django.template.loader import render_to_string -from django.http import HttpResponse, Http404 +from django.http import HttpResponse, Http404, HttpResponseRedirect from django.conf import settings from django.core.urlresolvers import reverse as urlreverse from django.views.decorators.cache import cache_page from django.db.models import Q +from django.utils.safestring import mark_safe from ietf.doc.views_search import SearchForm, retrieve_search_results from ietf.doc.models import State, DocAlias, RelatedDocument @@ -58,10 +59,31 @@ def roles(group, role_name): def fill_in_charter_info(group, include_drafts=False): group.areadirector = group.ad.role_email("ad", group.parent) if group.ad else None - group.chairs = roles(group, "chair") - group.techadvisors = roles(group, "techadv") - group.editors = roles(group, "editor") - group.secretaries = roles(group, "secr") + + personnel = {} + for r in Role.objects.filter(group=group).select_related("email", "person", "name"): + if r.name_id not in personnel: + personnel[r.name_id] = [] + personnel[r.name_id].append(r) + + if group.parent and group.parent.type_id == "area" and group.ad and "ad" not in personnel: + ad_roles = list(Role.objects.filter(group=group.parent, name="ad", person=group.ad)) + if ad_roles: + personnel["ad"] = ad_roles + + group.personnel = [] + for role_name_slug, roles in personnel.iteritems(): + label = roles[0].name.name + if len(roles) > 1: + if label.endswith("y"): + label = label[:-1] + "ies" + else: + label += "s" + + group.personnel.append((role_name_slug, label, roles)) + + group.personnel.sort(key=lambda t: t[2][0].name.order) + milestone_state = "charter" if group.state_id == "proposed" else "active" group.milestones = group.groupmilestone_set.filter(state=milestone_state).order_by('due') @@ -70,18 +92,6 @@ def fill_in_charter_info(group, include_drafts=False): else: group.charter_text = u"Not chartered yet." - if include_drafts: - aliases = DocAlias.objects.filter(document__type="draft", document__group=group).select_related('document').order_by("name") - group.drafts = [] - group.rfcs = [] - for a in aliases: - if a.name.startswith("draft"): - group.drafts.append(a) - else: - group.rfcs.append(a) - a.rel = RelatedDocument.objects.filter(source=a.document).distinct() - a.invrel = RelatedDocument.objects.filter(target=a).distinct() - def extract_last_name(role): return role.person.name_parts()[3] @@ -113,6 +123,32 @@ def wg_summary_acronym(request, group_type): 'groups': groups }, content_type='text/plain; charset=UTF-8') +def fill_in_wg_roles(group): + def get_roles(slug, default): + for role_slug, label, roles in group.personnel: + if slug == role_slug: + return roles + return default + + group.chairs = get_roles("chair", []) + ads = get_roles("ad", []) + group.areadirector = ads[0] if ads else None + group.techadvisors = get_roles("techadv", []) + group.editors = get_roles("editor", []) + group.secretaries = get_roles("secr", []) + +def fill_in_wg_drafts(group): + aliases = DocAlias.objects.filter(document__type="draft", document__group=group).select_related('document').order_by("name") + group.drafts = [] + group.rfcs = [] + for a in aliases: + if a.name.startswith("draft"): + group.drafts.append(a) + else: + group.rfcs.append(a) + a.rel = RelatedDocument.objects.filter(source=a.document).distinct() + a.invrel = RelatedDocument.objects.filter(target=a).distinct() + def wg_charters(request, group_type): if group_type != "wg": raise Http404 @@ -121,7 +157,9 @@ def wg_charters(request, group_type): area.ads = sorted(roles(area, "ad"), key=extract_last_name) area.groups = Group.objects.filter(parent=area, type="wg", state="active").order_by("name") for group in area.groups: - fill_in_charter_info(group, include_drafts=True) + fill_in_charter_info(group) + fill_in_wg_roles(group) + fill_in_wg_drafts(group) group.area = area return render(request, 'group/1wg-charters.txt', { 'areas': areas }, @@ -137,7 +175,9 @@ def wg_charters_by_acronym(request, group_type): groups = Group.objects.filter(type="wg", state="active").exclude(parent=None).order_by("acronym") for group in groups: - fill_in_charter_info(group, include_drafts=True) + fill_in_charter_info(group) + fill_in_wg_roles(group) + fill_in_wg_drafts(group) group.area = areas.get(group.parent_id) return render(request, 'group/1wg-charters-by-acronym.txt', { 'groups': groups }, @@ -216,29 +256,52 @@ def concluded_groups(request): return render(request, 'group/concluded_groups.html', dict(group_types=group_types)) -def construct_group_menu_context(request, group, selected, others): +def construct_group_menu_context(request, group, selected, group_type, others): """Return context with info for the group menu filled in.""" + kwargs = dict(acronym=group.acronym) + if group_type: + kwargs["group_type"] = group_type + + # entries + entries = [] + if group.features().has_documents: + entries.append(("Documents", urlreverse("ietf.group.info.group_documents", kwargs=kwargs))) + entries.append(("Charter", urlreverse("ietf.group.info.group_charter", kwargs=kwargs))) + entries.append(("History", urlreverse("ietf.group.info.history", kwargs=kwargs))) + if group.features().has_documents: + entries.append(("Dependency Graph", urlreverse("ietf.group.info.dependencies_pdf", kwargs=kwargs))) + + if group.list_archive.startswith("http:") or group.list_archive.startswith("https:") or group.list_archive.startswith("ftp:"): + entries.append((mark_safe("List Archive »"), group.list_archive)) + if group.has_tools_page(): + entries.append((mark_safe("Tools %s Page »" % group.type.name), "https://tools.ietf.org/%s/%s/" % (group.type_id, group.acronym))) + + + # actions actions = [] is_chair = group.has_role(request.user, "chair") can_manage = can_manage_group_type(request.user, group.type_id) - if group.state_id != "proposed" and (is_chair or can_manage): - actions.append((u"Add or edit milestones", urlreverse("group_edit_milestones", kwargs=dict(group_type=group.type_id, acronym=group.acronym)))) + if group.features().has_milestones: + if group.state_id != "proposed" and (is_chair or can_manage): + actions.append((u"Add or edit milestones", urlreverse("group_edit_milestones", kwargs=kwargs))) if group.state_id != "conclude" and can_manage: - actions.append((u"Edit group", urlreverse("group_edit", kwargs=dict(group_type=group.type_id, acronym=group.acronym)))) + actions.append((u"Edit group", urlreverse("group_edit", kwargs=kwargs))) - if is_chair or can_manage: - actions.append((u"Customize workflow", urlreverse("ietf.group.edit.customize_workflow", kwargs=dict(group_type=group.type_id, acronym=group.acronym)))) + if group.features().customize_workflow and (is_chair or can_manage): + actions.append((u"Customize workflow", urlreverse("ietf.group.edit.customize_workflow", kwargs=kwargs))) if group.state_id in ("active", "dormant") and can_manage: - actions.append((u"Request closing group", urlreverse("ietf.group.edit.conclude", kwargs=dict(group_type=group.type_id, acronym=group.acronym)))) + actions.append((u"Request closing group", urlreverse("ietf.group.edit.conclude", kwargs=kwargs))) d = { "group": group, - "selected": selected, + "selected_menu_entry": selected, + "menu_entries": entries, "menu_actions": actions, + "group_type": group_type, } d.update(others) @@ -278,22 +341,37 @@ def search_for_group_documents(group): return docs, meta, docs_related, meta_related -def group_documents(request, group_type, acronym): - group = get_object_or_404(Group, type=group_type, acronym=acronym) +def get_group_or_404(acronym, group_type): + """Helper to overcome the schism between group-type prefixed URLs and generic.""" + possible_groups = Group.objects.all() + if group_type: + possible_groups = possible_groups.filter(type=group_type) + + return get_object_or_404(possible_groups, acronym=acronym) + +def group_home(request, acronym, group_type=None): + group = get_group_or_404(acronym, group_type) + kwargs = dict(acronym=group.acronym) + if group_type: + kwargs["group_type"] = group_type + return HttpResponseRedirect(urlreverse(group.features().default_tab, kwargs=kwargs)) + +def group_documents(request, acronym, group_type=None): + group = get_group_or_404(acronym, group_type) docs, meta, docs_related, meta_related = search_for_group_documents(group) return render(request, 'group/group_documents.html', - construct_group_menu_context(request, group, "documents", { + construct_group_menu_context(request, group, "documents", group_type, { 'docs': docs, 'meta': meta, 'docs_related': docs_related, 'meta_related': meta_related })) -def group_documents_txt(request, group_type, acronym): +def group_documents_txt(request, acronym, group_type=None): """Return tabulator-separated rows with documents for group.""" - group = get_object_or_404(Group, type=group_type, acronym=acronym) + group = get_group_or_404(acronym, group_type) docs, meta, docs_related, meta_related = search_for_group_documents(group) @@ -316,39 +394,45 @@ def group_documents_txt(request, group_type, acronym): return HttpResponse(u"\n".join(rows), content_type='text/plain; charset=UTF-8') -def group_charter(request, group_type, acronym): - group = get_object_or_404(Group, type=group_type, acronym=acronym) +def group_charter(request, acronym, group_type=None): + group = get_group_or_404(acronym, group_type) - fill_in_charter_info(group, include_drafts=False) - group.delegates = roles(group, "delegate") + fill_in_charter_info(group) e = group.latest_event(type__in=("changed_state", "requested_close",)) requested_close = group.state_id != "conclude" and e and e.type == "requested_close" - long_group_types = dict( - wg="Working Group", - rg="Research Group", - ) + verbose_group_types = { + "wg": "Working Group", + "rg": "Research Group", + "team": "Team", + } can_manage = can_manage_group_type(request.user, group.type_id) + if group.features().has_chartering_process: + description = group.charter_text + else: + description = group.description or "No description entered yet." + return render(request, 'group/group_charter.html', - construct_group_menu_context(request, group, "charter", { + construct_group_menu_context(request, group, "charter", group_type, { "milestones_in_review": group.groupmilestone_set.filter(state="review"), "milestone_reviewer": milestone_reviewer_for_group_type(group_type), "requested_close": requested_close, - "long_group_type":long_group_types.get(group_type, "Group"), + "verbose_group_type": verbose_group_types.get(group.type_id, "Group"), "can_manage": can_manage, + "description": description, })) -def history(request, group_type, acronym): - group = get_object_or_404(Group, acronym=acronym) +def history(request, acronym, group_type=None): + group = get_group_or_404(acronym, group_type) events = group.groupevent_set.all().select_related('by').order_by('-time', '-id') return render(request, 'group/history.html', - construct_group_menu_context(request, group, "history", { + construct_group_menu_context(request, group, "history", group_type, { "events": events, })) @@ -470,19 +554,17 @@ def make_dot(group): dict( nodes=nodes, edges=edges ) ) -def dependencies_dot(request, group_type, acronym): - - group = get_object_or_404(Group, acronym=acronym) +def dependencies_dot(request, acronym, group_type=None): + group = get_group_or_404(acronym, group_type) return HttpResponse(make_dot(group), content_type='text/plain; charset=UTF-8' ) @cache_page ( 60 * 60 ) -def dependencies_pdf(request, group_type, acronym): +def dependencies_pdf(request, acronym, group_type=None): + group = get_group_or_404(acronym, group_type) - group = get_object_or_404(Group, acronym=acronym) - dothandle,dotname = mkstemp() os.close(dothandle) dotfile = open(dotname,"w") diff --git a/ietf/group/migrations/0007_auto__add_field_group_description__add_field_grouphistory_description.py b/ietf/group/migrations/0007_auto__add_field_group_description__add_field_grouphistory_description.py new file mode 100644 index 000000000..e9266e459 --- /dev/null +++ b/ietf/group/migrations/0007_auto__add_field_group_description__add_field_grouphistory_description.py @@ -0,0 +1,317 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'Group.description' + db.add_column(u'group_group', 'description', + self.gf('django.db.models.fields.TextField')(default='', blank=True), + keep_default=False) + + # Adding field 'GroupHistory.description' + db.add_column(u'group_grouphistory', 'description', + self.gf('django.db.models.fields.TextField')(default='', blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Group.description' + db.delete_column(u'group_group', 'description') + + # Deleting field 'GroupHistory.description' + db.delete_column(u'group_grouphistory', 'description') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'doc.document': { + 'Meta': {'object_name': 'Document'}, + 'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': u"orm['person.Person']"}), + 'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['person.Email']", 'symmetrical': 'False', 'through': u"orm['doc.DocumentAuthor']", 'blank': 'True'}), + 'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}), + 'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}), + 'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}), + 'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}), + 'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': u"orm['person.Person']"}), + 'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}), + 'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.StreamName']", 'null': 'True', 'blank': 'True'}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'}) + }, + u'doc.documentauthor': { + 'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['person.Email']"}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['doc.Document']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}) + }, + u'doc.state': { + 'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'previous_states'", 'blank': 'True', 'to': u"orm['doc.State']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['doc.StateType']"}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'doc.statetype': { + 'Meta': {'object_name': 'StateType'}, + 'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'}) + }, + u'group.changestategroupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'ChangeStateGroupEvent', '_ormbases': [u'group.GroupEvent']}, + u'groupevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['group.GroupEvent']", 'unique': 'True', 'primary_key': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.GroupStateName']"}) + }, + u'group.group': { + 'Meta': {'object_name': 'Group'}, + 'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': u"orm['doc.Document']"}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), + 'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.GroupStateName']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.GroupTypeName']", 'null': 'True'}), + 'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'group.groupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'GroupEvent'}, + 'by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['person.Person']"}), + 'desc': ('django.db.models.fields.TextField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['group.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'group.grouphistory': { + 'Meta': {'object_name': 'GroupHistory'}, + 'acronym': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': u"orm['group.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), + 'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.GroupStateName']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.GroupTypeName']", 'null': 'True'}), + 'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'group.groupmilestone': { + 'Meta': {'ordering': "['due', 'id']", 'object_name': 'GroupMilestone'}, + 'desc': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'docs': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['doc.Document']", 'symmetrical': 'False', 'blank': 'True'}), + 'due': ('django.db.models.fields.DateField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['group.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'resolved': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.GroupMilestoneStateName']"}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + u'group.groupmilestonehistory': { + 'Meta': {'ordering': "['due', 'id']", 'object_name': 'GroupMilestoneHistory'}, + 'desc': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'docs': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['doc.Document']", 'symmetrical': 'False', 'blank': 'True'}), + 'due': ('django.db.models.fields.DateField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['group.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'milestone': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': u"orm['group.GroupMilestone']"}), + 'resolved': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.GroupMilestoneStateName']"}), + 'time': ('django.db.models.fields.DateTimeField', [], {}) + }, + u'group.groupstatetransitions': { + 'Meta': {'object_name': 'GroupStateTransitions'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['group.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'previous_groupstatetransitions_states'", 'symmetrical': 'False', 'to': u"orm['doc.State']"}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['doc.State']"}) + }, + u'group.groupurl': { + 'Meta': {'object_name': 'GroupURL'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['group.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) + }, + u'group.milestonegroupevent': { + 'Meta': {'ordering': "['-time', 'id']", 'object_name': 'MilestoneGroupEvent', '_ormbases': [u'group.GroupEvent']}, + u'groupevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['group.GroupEvent']", 'unique': 'True', 'primary_key': 'True'}), + 'milestone': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['group.GroupMilestone']"}) + }, + u'group.role': { + 'Meta': {'object_name': 'Role'}, + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['person.Email']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['group.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.RoleName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['person.Person']"}) + }, + u'group.rolehistory': { + 'Meta': {'object_name': 'RoleHistory'}, + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['person.Email']"}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['group.GroupHistory']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['name.RoleName']"}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['person.Person']"}) + }, + u'name.doctagname': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.doctypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.groupmilestonestatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupMilestoneStateName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.groupstatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.grouptypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.intendedstdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.rolename': { + 'Meta': {'ordering': "['order']", 'object_name': 'RoleName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.stdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.streamname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StreamName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'person.email': { + 'Meta': {'object_name': 'Email'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['person.Person']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}) + }, + u'person.person': { + 'Meta': {'object_name': 'Person'}, + 'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}), + 'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['group'] \ No newline at end of file diff --git a/ietf/group/models.py b/ietf/group/models.py index 7ea66a8d1..e66572b37 100644 --- a/ietf/group/models.py +++ b/ietf/group/models.py @@ -17,6 +17,7 @@ class GroupInfo(models.Model): state = models.ForeignKey(GroupStateName, null=True) type = models.ForeignKey(GroupTypeName, null=True) parent = models.ForeignKey('Group', blank=True, null=True) + description = models.TextField(blank=True) ad = models.ForeignKey(Person, verbose_name="AD", blank=True, null=True) list_email = models.CharField(max_length=64, blank=True) list_subscribe = models.CharField(max_length=255, blank=True) @@ -79,6 +80,10 @@ class Group(GroupInfo): def bg_color(self): return bg_group_colors[self.upcase_acronym] + def features(self): + from ietf.group.features import GroupFeatures + return GroupFeatures(self) + def json_url(self): return "/group/%s.json" % (self.acronym,) diff --git a/ietf/group/urls.py b/ietf/group/urls.py index ea049c7e5..f3cf567b3 100644 --- a/ietf/group/urls.py +++ b/ietf/group/urls.py @@ -7,6 +7,20 @@ urlpatterns = patterns('', (r'^chartering/$', 'ietf.group.info.chartering_groups'), (r'^chartering/create/(?P(wg|rg))/$', 'ietf.group.edit.edit', {'action': "charter"}, "group_create"), (r'^concluded/$', 'ietf.group.info.concluded_groups'), + (r'^(?P[a-zA-Z0-9-._]+)/$', 'ietf.group.info.group_home', None, "group_home"), + (r'^(?P[a-zA-Z0-9-._]+)/documents/$', 'ietf.group.info.group_documents', None, "group_docs"), + (r'^(?P[a-zA-Z0-9-._]+)/charter/$', 'ietf.group.info.group_charter', None, 'group_charter'), + (r'^(?P[a-zA-Z0-9-._]+)/history/$', 'ietf.group.info.history'), + (r'^(?P[a-zA-Z0-9-._]+)/deps/dot/$', 'ietf.group.info.dependencies_dot'), + (r'^(?P[a-zA-Z0-9-._]+)/deps/pdf/$', 'ietf.group.info.dependencies_pdf'), + (r'^(?P[a-zA-Z0-9-._]+)/init-charter/', 'ietf.group.edit.submit_initial_charter'), + (r'^(?P[a-zA-Z0-9-._]+)/edit/$', 'ietf.group.edit.edit', {'action': "edit"}, "group_edit"), + (r'^(?P[a-zA-Z0-9-._]+)/conclude/$', 'ietf.group.edit.conclude'), + (r'^(?P[a-zA-Z0-9-._]+)/milestones/$', 'ietf.group.milestones.edit_milestones', {'milestone_set': "current"}, "group_edit_milestones"), + (r'^(?P[a-zA-Z0-9-._]+)/milestones/charter/$', 'ietf.group.milestones.edit_milestones', {'milestone_set': "charter"}, "group_edit_charter_milestones"), + (r'^(?P[a-zA-Z0-9-._]+)/milestones/charter/reset/$', 'ietf.group.milestones.reset_charter_milestones', None, "group_reset_charter_milestones"), + (r'^(?P[a-zA-Z0-9-._]+)/ajax/searchdocs/$', 'ietf.group.milestones.ajax_search_docs', None, "group_ajax_search_docs"), + (r'^(?P[a-zA-Z0-9-._]+)/workflow/$', 'ietf.group.edit.customize_workflow'), ) diff --git a/ietf/name/migrations/0020_sort_role_names.py b/ietf/name/migrations/0020_sort_role_names.py new file mode 100644 index 000000000..e15a11004 --- /dev/null +++ b/ietf/name/migrations/0020_sort_role_names.py @@ -0,0 +1,207 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + orm.RoleName.objects.filter(slug="chair").update(order=1) + orm.RoleName.objects.filter(slug="ad").update(order=2) + orm.RoleName.objects.filter(slug="pre-ad").update(order=3) + orm.RoleName.objects.filter(slug="editor").update(order=5) + orm.RoleName.objects.filter(slug="secr").update(order=6) + orm.RoleName.objects.filter(slug="techadv").update(order=4) + orm.RoleName.objects.filter(slug="execdir").update(order=2) + orm.RoleName.objects.filter(slug="admdir").update(order=3) + orm.RoleName.objects.filter(slug="liaiman").update(order=4) + orm.RoleName.objects.filter(slug="auth").update(order=5) + orm.RoleName.objects.filter(slug="delegate").update(order=6) + orm.RoleName.objects.filter(slug="atlarge").update(order=10) + orm.RoleName.objects.filter(slug="member").update(order=7) + orm.RoleName.objects.filter(slug="liaison").update(order=11) + orm.RoleName.objects.filter(slug="advisor").update(order=4) + orm.RoleName.objects.filter(slug="announce").update(order=12) + + def backwards(self, orm): + "Write your backwards methods here." + + models = { + u'name.ballotpositionname': { + 'Meta': {'ordering': "['order']", 'object_name': 'BallotPositionName'}, + 'blocking': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.constraintname': { + 'Meta': {'ordering': "['order']", 'object_name': 'ConstraintName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'penalty': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.dbtemplatetypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'DBTemplateTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.docrelationshipname': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocRelationshipName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'revname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.docremindertypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocReminderTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.doctagname': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.doctypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.draftsubmissionstatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'DraftSubmissionStateName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'previous_states'", 'blank': 'True', 'to': u"orm['name.DraftSubmissionStateName']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.feedbacktype': { + 'Meta': {'ordering': "['order']", 'object_name': 'FeedbackType'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.groupmilestonestatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupMilestoneStateName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.groupstatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.grouptypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.intendedstdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.liaisonstatementpurposename': { + 'Meta': {'ordering': "['order']", 'object_name': 'LiaisonStatementPurposeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.meetingtypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'MeetingTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.nomineepositionstate': { + 'Meta': {'ordering': "['order']", 'object_name': 'NomineePositionState'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.rolename': { + 'Meta': {'ordering': "['order']", 'object_name': 'RoleName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.sessionstatusname': { + 'Meta': {'ordering': "['order']", 'object_name': 'SessionStatusName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.stdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.streamname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StreamName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + u'name.timeslottypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'TimeSlotTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + } + } + + complete_apps = ['name'] + symmetrical = True diff --git a/ietf/templates/group/active_rgs.html b/ietf/templates/group/active_rgs.html index 58b8ca7b4..b6f3c6aeb 100644 --- a/ietf/templates/group/active_rgs.html +++ b/ietf/templates/group/active_rgs.html @@ -22,7 +22,7 @@ {% for group in groups %} - + diff --git a/ietf/templates/group/active_wgs.html b/ietf/templates/group/active_wgs.html index d631a2405..a9ce6e530 100644 --- a/ietf/templates/group/active_wgs.html +++ b/ietf/templates/group/active_wgs.html @@ -80,7 +80,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{{ group.acronym }}{{ group.acronym }} {{ group.name }} {% for chair in group.chairs %}{{ chair.person.plain_name }}{% if not forloop.last %}, {% endif %}{% endfor %}
{% for group in area.groups %} - + diff --git a/ietf/templates/group/group_base.html b/ietf/templates/group/group_base.html index d605d803a..ec1e0c381 100644 --- a/ietf/templates/group/group_base.html +++ b/ietf/templates/group/group_base.html @@ -66,16 +66,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Documents | - Charter | - History - | Dependency Graph - {% if group.list_archive|startswith:"http:" or group.list_archive|startswith:"https:" or group.list_archive|startswith:"ftp:" %} - | List Archive » - {% endif %} - {% if group.has_tools_page %} - | Tools {{ group.type.name }} Page » - {% endif %} + {% for name, url in menu_entries %} + {{ name }} {% if not forloop.last %} | {% endif %} + {% endfor %}
{% if menu_actions %} diff --git a/ietf/templates/group/group_charter.html b/ietf/templates/group/group_charter.html index 1481229e3..9fb5ca5ba 100644 --- a/ietf/templates/group/group_charter.html +++ b/ietf/templates/group/group_charter.html @@ -3,11 +3,6 @@ {% load ietf_filters %} {% block group_subtitle %}Charter{% endblock %} -{% block morecss %} -{{ block.super }} -h2 a.button { margin-left: 0.5em; font-size: 13px; } -{% endblock %} - {% block group_content %}
@@ -39,6 +34,7 @@ is occasionally incorrect.
+ {% if group.features.has_chartering_process %} + {% endif %} + {% for slug, label, roles in group.personnel %} - + + {% endfor %} - {% if group.parent.type_id == "area" %} - - - - {% endif %} - - {% if group.techadvisors %} - - - - - {% endif %} - - {% if group.editors %} - - - - - {% endif %} - - {% if group.secretaries %} - - - - - {% endif %} - - {% if group.delegates %} - - - - - {% endif %} - + {% if group.list_email %} + {% endif %} {% if group.state_id != "conclude" %} @@ -152,17 +99,19 @@ is occasionally incorrect. {% endif %} {% endwith %} -

Charter for {% if group.state_id == "proposed" %}Proposed{% endif %} {{ long_group_type }}

+

Charter for {% if group.state_id == "proposed" %}Proposed{% endif %} {{ verbose_group_type }}

-

{{ group.charter_text|escape|format_charter|safe }}

+

{{ description|linebreaks }}

-

{% if group.state_id == "proposed" %}Proposed{% endif %} Milestones

+{% if group.features.has_milestones %} +

{% if group.state_id == "proposed" %}Proposed{% endif %} Milestones

-{% include "group/milestones.html" with milestones=group.milestones %} + {% include "group/milestones.html" with milestones=group.milestones %} -{% if milestones_in_review %} -

+ {{ milestones_in_review|length }} new milestone{{ milestones_in_review|pluralize }} -currently in {{ milestone_reviewer }} review.

+ {% if milestones_in_review %} +

+ {{ milestones_in_review|length }} new milestone{{ milestones_in_review|pluralize }} + currently in {{ milestone_reviewer }} review.

+ {% endif %} {% endif %} {% endblock %} diff --git a/ietf/templates/group/group_entry_with_charter.txt b/ietf/templates/group/group_entry_with_charter.txt index abde2531a..cfce907fb 100644 --- a/ietf/templates/group/group_entry_with_charter.txt +++ b/ietf/templates/group/group_entry_with_charter.txt @@ -13,7 +13,7 @@ {% for ad in group.area.ads %} {{ ad.person.plain_name }} <{{ ad.email.address }}> {% endfor %} {% if group.areadirector %} {{ group.area.name }} Advisor: - {{ group.areadirector.person.plain_name }} <{{ group.areadirector.address }}> + {{ group.areadirector.person.plain_name }} <{{ group.areadirector.email.address }}> {% endif %}{% if group.techadvisors %} Tech Advisor{{ group.techadvisors|pluralize }}: {% for techadvisor in group.techadvisors %} {{ techadvisor.person.plain_name }} <{{ techadvisor.email.address }}>
{{ group.acronym }}{{ group.acronym }} {% for ad in area.ads %}{% if ad.person_id == group.ad_id %}{% endif %}{% endfor %} {{ group.name }} {% for chair in group.chairs %}{{ chair.person.plain_name }}{% if not forloop.last %}, {% endif %}{% endfor %}
Charter: @@ -52,77 +48,28 @@ is occasionally incorrect. {% endif %}
Personnel
Chair{{ group.chairs|pluralize }}:{{ label }}: - {% for chair in group.chairs %} - {{ chair.person.plain_name }} <{{ chair.email.address }}>
+ {% for r in roles %} + {{ r.person.plain_name }} <{{ r.email.address }}>
{% endfor %}
Area Director: - {% if group.areadirector %} - {{ group.areadirector.person.plain_name }} <{{ group.areadirector.address }}> - {% else %}?{% endif %} -
Tech Advisor{{ group.techadvisors|pluralize }}: - {% for techadvisor in group.techadvisors %} - {{ techadvisor.person.plain_name }} <{{ techadvisor.email.address }}>
- {% endfor %} -
Editor{{ group.editors|pluralize }}: - {% for editor in group.editors %} - {{ editor.person.plain_name }} <{{ editor.email.address }}>
- {% endfor %} -
Secretar{{ group.secretaries|pluralize:"y,ies" }}: - {% for secretary in group.secretaries %} - {{ secretary.person.plain_name }} <{{ secretary.email.address }}>
- {% endfor %} -
Delegate{{ group.delegates|pluralize }}: - {% for delegate in group.delegates %} - {{ delegate.person.plain_name }} <{{ delegate.email.address }}>
- {% endfor %} -
Mailing List
Address:{{ group.list_email|urlize }}
To Subscribe:{{ group.list_subscribe|urlize }}
Archive:{{ group.list_archive|urlize }}
Jabber Chat