diff --git a/README b/README deleted file mode 100644 index 18bdec71f..000000000 --- a/README +++ /dev/null @@ -1,25 +0,0 @@ -This is the "facelift" datatracker branch that uses Twitter Bootstrap for -the UI. - -You need to install a few new django extensions: - https://pypi.python.org/pypi/django-widget-tweaks - https://pypi.python.org/pypi/django-bootstrap3 - https://pypi.python.org/pypi/django-typogrify - -The meta goal of this effort is: *** NO CHANGES TO THE PYTHON CODE *** - -Whenever changes to the python code are made, they can only fix HTML bugs, -or add comments (tagged with "FACELIFT") about functionality that can be -removed once the facelift templates become default. Or they need to add -functionality that is only called from the new facelift templates. - -Javascript that is only used on one template goes into that template. -Javascript that is used by more than one template goes into ietf.js. - -CSS that is only used on one template goes into that template. -CSS that is used by more than one template goes into ietf.css. No CSS in the -templates or - god forbid - style tags! (And no CSS or HTML styling in -python code!!) - -Templates that use jquery or bootstrap plugins include the css in the pagehead -block, and the js in the js block. diff --git a/TODO b/TODO deleted file mode 100644 index 994c859d2..000000000 --- a/TODO +++ /dev/null @@ -1,11 +0,0 @@ -Major pieces not facelifted: milestone editing, liaison editing, WG workflow customization - -Use affix for navigation on active_wgs.html - -Figure out why {% if debug %} does not work in the text templates under ietf/templates_facelift/community/public. - -Make django generate HTML5 date inputs or use a js-based datepicker. - -Deferring ballots does not work. (Seems to be an upstream bug.) - -Make tables that are too wide to usefully work on small screens responsive. See http://getbootstrap.com/css/#tables-responsive diff --git a/ietf/community/templatetags/community_tags.py b/ietf/community/templatetags/community_tags.py index 52995063b..1797bb99b 100644 --- a/ietf/community/templatetags/community_tags.py +++ b/ietf/community/templatetags/community_tags.py @@ -1,6 +1,5 @@ from django import template from django.template.loader import render_to_string -from django.conf import settings from ietf.community.models import CommunityList from ietf.group.models import Role @@ -10,7 +9,7 @@ register = template.Library() class CommunityListNode(template.Node): - + def __init__(self, user, var_name): self.user = user self.var_name = var_name @@ -58,13 +57,13 @@ def show_field(field, doc): class CommunityListViewNode(template.Node): - + def __init__(self, clist): self.clist = clist def render(self, context): clist = self.clist.resolve(context) - if settings.DEBUG or not clist.cached: + if not clist.cached: clist.cached = render_to_string('community/raw_view.html', {'cl': clist, 'dc': clist.get_display_config()}) diff --git a/ietf/doc/templatetags/ballot_icon.py b/ietf/doc/templatetags/ballot_icon.py index 142437685..23b5f99e4 100644 --- a/ietf/doc/templatetags/ballot_icon.py +++ b/ietf/doc/templatetags/ballot_icon.py @@ -87,32 +87,35 @@ def ballot_icon(context, doc): positions = list(doc.active_ballot().active_ad_positions().items()) positions.sort(key=sort_key) - res = ['' % ( + edit_position_url = "" + if has_role(user, "Area Director"): + edit_position_url = urlreverse('ietf.doc.views_ballot.edit_position', kwargs=dict(name=doc.name, ballot_id=ballot.pk)) + + title = "IESG positions (click to show more%s)" % (", right-click to edit position" if edit_position_url else "") + + res = ['
' % ( + urlreverse("doc_ballot", kwargs=dict(name=doc.name, ballot_id=ballot.pk)), urlreverse("ietf.doc.views_doc.ballot_popup", kwargs=dict(name=doc.name, ballot_id=ballot.pk)), - ballot.pk)] + edit_position_url, + title + )] res.append("") for i, (ad, pos) in enumerate(positions): if i > 0 and i % 5 == 0: - res.append("") + res.append("") + res.append("") c = "position-%s" % (pos.pos.slug if pos else "norecord") if user_is_person(user, ad): c += " my" - res.append('' % c) + res.append('') - i = i + 1 - - res.append("
' % c) - # add sufficient table calls to last row to avoid HTML validation warning - while (i + 1) % 5 != 0: - res.append('
") - # XXX FACELIFT: Loading via href will go away in bootstrap 4. - # See http://getbootstrap.com/javascript/#modals-usage - res.append('' % ballot.pk) + res.append("") + res.append("") return "".join(res) @@ -134,8 +137,7 @@ def ballotposition(doc, user): @register.filter -# FACELIFT: added flavor argument for styling -def state_age_colored(doc, flavor=""): +def state_age_colored(doc): if doc.type_id == 'draft': if not doc.get_state_slug() in ["active", "rfc"]: # Don't show anything for expired/withdrawn/replaced drafts @@ -154,7 +156,7 @@ def state_age_colored(doc, flavor=""): except IndexError: state_date = datetime.date(1990,1,1) days = (datetime.date.today() - state_date).days - # loosely based on + # loosely based on # http://trac.tools.ietf.org/group/iesg/trac/wiki/PublishPath if iesg_state == "lc": goal1 = 30 @@ -178,26 +180,16 @@ def state_age_colored(doc, flavor=""): goal1 = 14 goal2 = 28 if days > goal2: - if flavor == "facelift": - class_name = "label label-danger" - else: - class_name = "ietf-small ietf-highlight-r" + class_name = "ietf-small ietf-highlight-r" elif days > goal1: - if flavor == "facelift": - class_name = "label label-warning" - else: - class_name = "ietf-small ietf-highlight-y" + class_name = "ietf-small ietf-highlight-y" else: class_name = "ietf-small" if days > goal1: title = ' title="Goal is <%d days"' % (goal1,) else: title = '' - # It's too bad that this function returns HTML; this makes it hard to - # style. For the facelift, I therefore needed to add a new "flavor" - # parameter, which is ugly. - return mark_safe('%sfor %d day%s%s' % ( - class_name, title, '(' if flavor != "facelift" else "", days, - 's' if days != 1 else '', '(' if flavor != "facelift" else "" )) + return mark_safe('(for %d day%s)' % ( + class_name, title, days, 's' if days != 1 else '')) else: return "" diff --git a/ietf/doc/templatetags/ietf_filters.py b/ietf/doc/templatetags/ietf_filters.py index e0c7e1b8d..75329966c 100644 --- a/ietf/doc/templatetags/ietf_filters.py +++ b/ietf/doc/templatetags/ietf_filters.py @@ -9,7 +9,7 @@ from email.utils import parseaddr from ietf.doc.models import ConsensusDocEvent from django import template from django.utils.html import escape, fix_ampersands -from django.template.defaultfilters import truncatewords_html, linebreaksbr, stringfilter, urlize, striptags +from django.template.defaultfilters import truncatewords_html, linebreaksbr, stringfilter, urlize from django.template import resolve_variable from django.utils.safestring import mark_safe, SafeData from django.utils.html import strip_tags @@ -48,12 +48,12 @@ def parse_email_list(value): u'joe@example.org, fred@example.com' Parsing a non-string should return the input value, rather than fail: - + >>> parse_email_list(['joe@example.org', 'fred@example.com']) ['joe@example.org', 'fred@example.com'] - + Null input values should pass through silently: - + >>> parse_email_list('') '' @@ -87,7 +87,7 @@ def fix_angle_quotes(value): if "<" in value: value = re.sub("<([\w\-\.]+@[\w\-\.]+)>", "<\1>", value) return value - + # there's an "ahref -> a href" in GEN_UTIL # but let's wait until we understand what that's for. @register.filter(name='make_one_per_line') @@ -99,7 +99,7 @@ def make_one_per_line(value): 'a\\nb\\nc' Pass through non-strings: - + >>> make_one_per_line([1, 2]) [1, 2] @@ -110,7 +110,7 @@ def make_one_per_line(value): return re.sub(", ?", "\n", value) else: return value - + @register.filter(name='timesum') def timesum(value): """ @@ -222,7 +222,7 @@ def rfclink(string): URL for that RFC. """ string = str(string); - return "//tools.ietf.org/html/rfc" + string; + return "http://tools.ietf.org/html/rfc" + string; @register.filter(name='urlize_ietf_docs', is_safe=True, needs_autoescape=True) def urlize_ietf_docs(string, autoescape=None): @@ -274,7 +274,7 @@ def truncate_ellipsis(text, arg): return escape(text[:num-1])+"…" else: return escape(text) - + @register.filter def split(text, splitter=None): return text.split(splitter) @@ -375,7 +375,7 @@ def linebreaks_lf(text): @register.filter(name='clean_whitespace') def clean_whitespace(text): """ - Map all ASCII control characters (0x00-0x1F) to spaces, and + Map all ASCII control characters (0x00-0x1F) to spaces, and remove unnecessary spaces. """ text = re.sub("[\000-\040]+", " ", text) @@ -384,7 +384,7 @@ def clean_whitespace(text): @register.filter(name='unescape') def unescape(text): """ - Unescape  />/< + Unescape  />/< """ text = text.replace(">", ">") text = text.replace("<", "<") @@ -423,7 +423,7 @@ def has_role(user, role_names): @register.filter def stable_dictsort(value, arg): """ - Like dictsort, except it's stable (preserves the order of items + Like dictsort, except it's stable (preserves the order of items whose sort key is the same). See also bug report http://code.djangoproject.com/ticket/12110 """ @@ -448,10 +448,10 @@ def format_history_text(text): if text.startswith("This was part of a ballot set with:"): full = urlize_ietf_docs(full) - full = mark_safe(keep_spacing(linebreaksbr(urlize_html(sanitize_html(full))))) + full = mark_safe(keep_spacing(linebreaksbr(urlize(sanitize_html(full))))) snippet = truncatewords_html(full, 25) if snippet != full: - return mark_safe(u'
%s
' % (snippet, full)) + return mark_safe(u'
%s[show all]
' % (snippet, full)) return full @register.filter @@ -512,66 +512,3 @@ def consensus(doc): else: return "Unknown" -# FACELIFT: The following filters are only used by the facelift UI: - -@register.filter -def pos_to_label(text): - """Return a valid Bootstrap3 label type for a ballot position.""" - return { - 'Yes': 'success', - 'No Objection': 'info', - 'Abstain': 'warning', - 'Discuss': 'danger', - 'Block': 'danger', - 'Recuse': 'default', - }.get(str(text), 'blank') - -@register.filter -def capfirst_allcaps(text): - from django.template import defaultfilters - """Like capfirst, except it doesn't lowercase words in ALL CAPS.""" - result = text - i = False - for token in re.split("(\W+)", striptags(text)): - if not re.match("^[A-Z]+$", token): - if not i: - result = result.replace(token, token.capitalize()) - i = True - else: - result = result.replace(token, token.lower()) - return result - -@register.filter -def lower_allcaps(text): - from django.template import defaultfilters - """Like lower, except it doesn't lowercase words in ALL CAPS.""" - result = text - i = False - for token in re.split("(\W+)", striptags(text)): - if not re.match("^[A-Z]+$", token): - result = result.replace(token, token.lower()) - return result - -# See https://djangosnippets.org/snippets/2072/ and -# https://stackoverflow.com/questions/9939248/how-to-prevent-django-basic-inlines-from-autoescaping -@register.filter -def urlize_html(html, autoescape=False): - """ - Returns urls found in an (X)HTML text node element as urls via Django urlize filter. - """ - try: - from BeautifulSoup import BeautifulSoup - from django.utils.html import urlize - except ImportError: - if settings.DEBUG: - raise template.TemplateSyntaxError, "Error in urlize_html The Python BeautifulSoup libraries aren't installed." - return html - else: - soup = BeautifulSoup(html) - - textNodes = soup.findAll(text=True) - for textNode in textNodes: - urlizedText = urlize(textNode, autoescape=autoescape) - textNode.replaceWith(BeautifulSoup(urlizedText)) - - return str(soup) diff --git a/ietf/doc/templatetags/wg_menu.py b/ietf/doc/templatetags/wg_menu.py index 477df82b0..98960c7a7 100644 --- a/ietf/doc/templatetags/wg_menu.py +++ b/ietf/doc/templatetags/wg_menu.py @@ -43,32 +43,24 @@ area_short_names = { 'rai':'RAI' } -# FACELIFT: Function is called with "facelift" flavor from the new UI code. -# The old code (and flavoring) can be remove eventually. @register.simple_tag -def wg_menu(flavor=""): - res = cache.get('wgmenu' + flavor) +def wg_menu(): + res = cache.get('base_left_wgmenu') if res: return res areas = Group.objects.filter(type="area", state="active").order_by('acronym') - wgs = Group.objects.filter(type="wg", state="active", parent__in=areas).order_by("acronym") - rgs = Group.objects.filter(type="rg", state="active").order_by("acronym") + groups = Group.objects.filter(type="wg", state="active", parent__in=areas).order_by("acronym") for a in areas: a.short_area_name = area_short_names.get(a.acronym) or a.name if a.short_area_name.endswith(" Area"): a.short_area_name = a.short_area_name[:-len(" Area")] - a.active_groups = [g for g in wgs if g.parent_id == a.id] + a.active_groups = [g for g in groups if g.parent_id == a.id] areas = [a for a in areas if a.active_groups] - if flavor == "facelift": - res = render_to_string('base/menu_wg.html', {'areas':areas, 'rgs':rgs}) - elif flavor == "modal": - res = render_to_string('base/menu_wg_modal.html', {'areas':areas, 'rgs':rgs}) - else: - res = render_to_string('base/wg_menu.html', {'areas':areas, 'rgs':rgs}) - cache.set('wgmenu' + flavor, res, 30*60) + res = render_to_string('base/wg_menu.html', {'areas':areas}) + cache.set('base_left_wgmenu', res, 30*60) return res diff --git a/ietf/doc/views_charter.py b/ietf/doc/views_charter.py index 2b80aee9f..7963bdac4 100644 --- a/ietf/doc/views_charter.py +++ b/ietf/doc/views_charter.py @@ -13,7 +13,7 @@ from django.contrib.auth.decorators import login_required import debug # pyflakes:ignore from ietf.doc.models import ( Document, DocHistory, State, DocEvent, BallotDocEvent, - BallotPositionDocEvent, InitialReviewDocEvent, NewRevisionDocEvent, + BallotPositionDocEvent, InitialReviewDocEvent, NewRevisionDocEvent, WriteupDocEvent, save_document_in_history ) from ietf.doc.utils import ( add_state_change_event, close_open_ballots, create_ballot_if_not_open, get_chartering_type ) @@ -33,7 +33,7 @@ from ietf.group.mails import email_iesg_secretary_re_charter class ChangeStateForm(forms.Form): charter_state = forms.ModelChoiceField(State.objects.filter(used=True, type="charter"), label="Charter state", empty_label=None, required=False) initial_time = forms.IntegerField(initial=0, label="Review time", help_text="(in weeks)", required=False) - message = forms.CharField(widget=forms.Textarea, help_text="Leave blank to change state without notifying the Secretariat", required=False, label=mark_safe("Message to the Secretariat")) + message = forms.CharField(widget=forms.Textarea, help_text="Leave blank to change state without notifying the Secretariat", required=False, label=mark_safe("Message to
Secretariat")) comment = forms.CharField(widget=forms.Textarea, help_text="Optional comment for the charter history", required=False) def __init__(self, *args, **kwargs): self.hide = kwargs.pop('hide', None) @@ -47,7 +47,7 @@ class ChangeStateForm(forms.Form): # hide requested fields if self.hide: for f in self.hide: - self.fields[f].widget = forms.HiddenInput() + self.fields[f].widget = forms.HiddenInput @login_required def change_state(request, name, option=None): @@ -101,7 +101,7 @@ def change_state(request, name, option=None): e.state_id = group.state.slug e.desc = "Group state changed to %s from %s" % (group.state, oldstate) e.save() - + else: charter_state = State.objects.get(used=True, type="charter", slug="approved") charter_rev = approved_revision(charter.rev) @@ -327,12 +327,12 @@ def submit(request, name=None, option=None): e.desc = "New version available: %s-%s.txt" % (charter.canonical_name(), charter.rev) e.rev = charter.rev e.save() - + # Save file on disk form.save(group, charter.rev) if option in ['initcharter','recharter'] and charter.ad == None: - charter.ad = group.ad + charter.ad = group.ad charter.time = datetime.datetime.now() charter.save() @@ -405,7 +405,7 @@ def announcement_text(request, name, ann): e.desc = "%s %s text was changed" % (group.type.name, ann) e.text = t e.save() - + charter.time = e.time charter.save() @@ -440,7 +440,7 @@ class BallotWriteupForm(forms.Form): def clean_ballot_writeup(self): return self.cleaned_data["ballot_writeup"].replace("\r", "") - + @role_required('Area Director','Secretariat') def ballot_writeupnotes(request, name): """Editing of ballot write-up and notes""" @@ -453,13 +453,13 @@ def ballot_writeupnotes(request, name): login = request.user.person approval = charter.latest_event(WriteupDocEvent, type="changed_action_announcement") - + existing = charter.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text") if not existing: existing = generate_ballot_writeup(request, charter) reissue = charter.latest_event(DocEvent, type="sent_ballot_announcement") - + form = BallotWriteupForm(initial=dict(ballot_writeup=existing.text)) if request.method == 'POST' and ("save_ballot_writeup" in request.POST or "send_ballot" in request.POST): @@ -644,7 +644,7 @@ def approve(request, name): send_mail_preformatted(request, announcement) return HttpResponseRedirect(charter.get_absolute_url()) - + return render_to_response('doc/charter/approve.html', dict(charter=charter, announcement=announcement), diff --git a/ietf/doc/views_search.py b/ietf/doc/views_search.py index c6629d634..365c594e4 100644 --- a/ietf/doc/views_search.py +++ b/ietf/doc/views_search.py @@ -148,7 +148,7 @@ def fill_in_search_attributes(docs): for d in docs: if isinstance(d,DocAlias): d = d.document - rel_this_doc = d.all_related_that_doc(['replaces','obs']) + rel_this_doc = d.all_related_that_doc(['replaces','obs']) for rel in rel_this_doc: rel_id_camefrom.setdefault(rel.document.pk,[]).append(d.pk) rel_docs += [x.document for x in rel_this_doc] @@ -240,7 +240,7 @@ def retrieve_search_results(form, all_types=False): """Takes a validated SearchForm and return the results.""" if not form.is_valid(): raise ValueError("SearchForm doesn't validate: %s" % form.errors) - + query = form.cleaned_data types=[]; @@ -282,7 +282,7 @@ def retrieve_search_results(form, all_types=False): if query["olddrafts"]: allowed_draft_states.extend(['repl', 'expired', 'auth-rm', 'ietf-rm']) - docs = docs.filter(Q(states__slug__in=allowed_draft_states) | + docs = docs.filter(Q(states__slug__in=allowed_draft_states) | ~Q(type__slug='draft')).distinct() # radio choices @@ -365,7 +365,7 @@ def retrieve_search_results(form, all_types=False): meta['headers'] = [{'title': 'Document', 'key':'document'}, {'title': 'Title', 'key':'title'}, {'title': 'Date', 'key':'date'}, - {'title': 'Status', 'key':'status'}, + {'title': 'Status', 'key':'status', 'colspan':'2'}, {'title': 'IPR', 'key':'ipr'}, {'title': 'AD / Shepherd', 'key':'ad'}] @@ -440,14 +440,14 @@ def ad_dashboard_group(doc): return '%s Internet-Draft' % doc.get_state('draft').name elif doc.type.slug=='conflrev': if doc.get_state_slug('conflrev') in ('appr-reqnopub-sent','appr-noprob-sent'): - return 'Approved Conflict Review' + return 'Approved Conflict Review' elif doc.get_state_slug('conflrev') in ('appr-reqnopub-pend','appr-noprob-pend','appr-reqnopub-pr','appr-noprob-pr'): return "%s Conflict Review" % State.objects.get(type__slug='draft-iesg',slug='approved') else: return '%s Conflict Review' % doc.get_state('conflrev') elif doc.type.slug=='statchg': if doc.get_state_slug('statchg') in ('appr-sent',): - return 'Approved Status Change' + return 'Approved Status Change' if doc.get_state_slug('statchg') in ('appr-pend','appr-pr'): return '%s Status Change' % State.objects.get(type__slug='draft-iesg',slug='approved') else: @@ -461,7 +461,7 @@ def ad_dashboard_group(doc): return "Document" def ad_dashboard_sort_key(doc): - + if doc.type.slug=='draft' and doc.get_state_slug('draft') == 'rfc': return "21%04d" % int(doc.rfc_number()) if doc.type.slug=='statchg' and doc.get_state_slug('statchg') == 'appr-sent': @@ -474,26 +474,26 @@ def ad_dashboard_sort_key(doc): seed = ad_dashboard_group(doc) if doc.type.slug=='conflrev' and doc.get_state_slug('conflrev') == 'adrev': - state = State.objects.get(type__slug='draft-iesg',slug='ad-eval') + state = State.objects.get(type__slug='draft-iesg',slug='ad-eval') return "1%d%s" % (state.order,seed) if doc.type.slug=='charter': if doc.get_state_slug('charter') in ('notrev','infrev'): return "100%s" % seed elif doc.get_state_slug('charter') == 'intrev': - state = State.objects.get(type__slug='draft-iesg',slug='ad-eval') + state = State.objects.get(type__slug='draft-iesg',slug='ad-eval') return "1%d%s" % (state.order,seed) elif doc.get_state_slug('charter') == 'extrev': - state = State.objects.get(type__slug='draft-iesg',slug='lc') + state = State.objects.get(type__slug='draft-iesg',slug='lc') return "1%d%s" % (state.order,seed) elif doc.get_state_slug('charter') == 'iesgrev': - state = State.objects.get(type__slug='draft-iesg',slug='iesg-eva') + state = State.objects.get(type__slug='draft-iesg',slug='iesg-eva') return "1%d%s" % (state.order,seed) if doc.type.slug=='statchg' and doc.get_state_slug('statchg') == 'adrev': - state = State.objects.get(type__slug='draft-iesg',slug='ad-eval') + state = State.objects.get(type__slug='draft-iesg',slug='ad-eval') return "1%d%s" % (state.order,seed) - + if seed.startswith('Needs Shepherd'): return "100%s" % seed if seed.endswith(' Document'): diff --git a/ietf/group/edit.py b/ietf/group/edit.py index bc490d8ba..2d9ce0942 100644 --- a/ietf/group/edit.py +++ b/ietf/group/edit.py @@ -39,7 +39,7 @@ class GroupForm(forms.Form): list_email = forms.CharField(max_length=64, required=False) list_subscribe = forms.CharField(max_length=255, required=False) list_archive = forms.CharField(max_length=255, required=False) - urls = forms.CharField(widget=forms.Textarea, label="Additional URLs", help_text="Format: https://site/path (Optional description). Separate multiple entries with newline. Prefer HTTPS URLs where possible.", required=False) + urls = forms.CharField(widget=forms.Textarea, label="Additional URLs", help_text="Format: http://site/path (Optional description). Separate multiple entries with newline.", required=False) def __init__(self, *args, **kwargs): self.group = kwargs.pop('group', None) @@ -60,7 +60,7 @@ class GroupForm(forms.Form): self.confirm_msg = "" self.autoenable_confirm = False if self.group: - self.fields['acronym'].widget.attrs['readonly'] = "" + self.fields['acronym'].widget.attrs['readonly'] = True if self.group_type == "rg": self.fields['ad'].widget = forms.HiddenInput() @@ -149,7 +149,7 @@ def get_or_create_initial_charter(group, group_type): ) charter.save() charter.set_state(State.objects.get(used=True, type="charter", slug="notrev")) - + # Create an alias as well DocAlias.objects.create(name=charter.name, document=charter) @@ -220,12 +220,12 @@ def edit(request, group_type=None, acronym=None, action="edit"): group.charter = get_or_create_initial_charter(group, group_type) changes = [] - + def desc(attr, new, old): entry = "%(attr)s changed to %(new)s from %(old)s" if new_group: entry = "%(attr)s changed to %(new)s" - + return entry % dict(attr=attr, new=new, old=old) def diff(attr, name): diff --git a/ietf/group/views_stream.py b/ietf/group/views_stream.py index 6fe223703..48790beb3 100644 --- a/ietf/group/views_stream.py +++ b/ietf/group/views_stream.py @@ -24,13 +24,11 @@ def stream_documents(request, acronym): streams = [ s.slug for s in StreamName.objects.all().exclude(slug__in=['ietf', 'legacy']) ] if not acronym in streams: raise Http404("No such stream: %s" % acronym) - group = get_object_or_404(Group, acronym=acronym) - editable = has_role(request.user, "Secretariat") or group.has_role(request.user, "chair") stream = StreamName.objects.get(slug=acronym) form = SearchForm({'by':'stream', 'stream':acronym, 'rfcs':'on', 'activedrafts':'on'}) docs, meta = retrieve_search_results(form) - return render_to_response('group/stream_documents.html', {'stream':stream, 'docs':docs, 'meta':meta, 'editable':editable }, context_instance=RequestContext(request)) + return render_to_response('group/stream_documents.html', {'stream':stream, 'docs':docs, 'meta':meta }, context_instance=RequestContext(request)) class StreamEditForm(forms.Form): delegates = AutocompletedEmailsField(required=False, only_users=True) @@ -64,7 +62,7 @@ def stream_edit(request, acronym): for e in new: Role.objects.get_or_create(name_id=slug, email=e, group=group, person=e.person) - return redirect("ietf.group.views_stream.streams") + return redirect("ietf.group.views.streams") else: form = StreamEditForm(initial=dict(delegates=Email.objects.filter(role__group=group, role__name="delegate"))) @@ -74,4 +72,4 @@ def stream_edit(request, acronym): 'form': form, }, context_instance=RequestContext(request)) - + diff --git a/ietf/iesg/agenda.py b/ietf/iesg/agenda.py index 8ab95e000..eb0d9f212 100644 --- a/ietf/iesg/agenda.py +++ b/ietf/iesg/agenda.py @@ -85,50 +85,50 @@ def get_doc_section(doc): def agenda_sections(): return OrderedDict([ ('1', {'title':"Administrivia"}), - ('1.1', {'title':"Roll call"}), - ('1.2', {'title':"Bash the agenda"}), - ('1.3', {'title':"Approval of the minutes of past telechats"}), - ('1.4', {'title':"List of remaining action items from last telechat"}), - ('2', {'title':"Protocol actions"}), - ('2.1', {'title':"WG submissions"}), - ('2.1.1', {'title':"New items", 'docs': []}), - ('2.1.2', {'title':"Returning items", 'docs':[]}), - ('2.1.3', {'title':"For action", 'docs':[]}), - ('2.2', {'title':"Individual submissions"}), - ('2.2.1', {'title':"New items", 'docs':[]}), - ('2.2.2', {'title':"Returning items", 'docs':[]}), - ('2.2.3', {'title':"For action", 'docs':[]}), - ('2.3', {'title':"Status changes"}), - ('2.3.1', {'title':"New items", 'docs':[]}), - ('2.3.2', {'title':"Returning items", 'docs':[]}), - ('2.3.3', {'title':"For action", 'docs':[]}), - ('3', {'title':"Document actions"}), - ('3.1', {'title':"WG submissions"}), - ('3.1.1', {'title':"New items", 'docs':[]}), - ('3.1.2', {'title':"Returning items", 'docs':[]}), - ('3.1.3', {'title':"For action", 'docs':[]}), - ('3.2', {'title':"Individual submissions via AD"}), - ('3.2.1', {'title':"New items", 'docs':[]}), - ('3.2.2', {'title':"Returning items", 'docs':[]}), - ('3.2.3', {'title':"For action", 'docs':[]}), - ('3.3', {'title':"Status changes"}), - ('3.3.1', {'title':"New items", 'docs':[]}), - ('3.3.2', {'title':"Returning items", 'docs':[]}), - ('3.3.3', {'title':"For action", 'docs':[]}), - ('3.4', {'title':"IRTF and Independent Submission stream documents"}), - ('3.4.1', {'title':"New items", 'docs':[]}), - ('3.4.2', {'title':"Returning items", 'docs':[]}), - ('3.4.3', {'title':"For action", 'docs':[]}), - ('4', {'title':"Working Group actions"}), - ('4.1', {'title':"WG creation"}), - ('4.1.1', {'title':"Proposed for IETF review", 'docs':[]}), - ('4.1.2', {'title':"Proposed for approval", 'docs':[]}), - ('4.2', {'title':"WG rechartering"}), - ('4.2.1', {'title':"Under evaluation for IETF review", 'docs':[]}), - ('4.2.2', {'title':"Proposed for approval", 'docs':[]}), - ('5', {'title':"IAB news we can use"}), - ('6', {'title':"Management issues"}), - ('7', {'title':"Working Group news"}), + ('1.1', {'title':"Roll Call"}), + ('1.2', {'title':"Bash the Agenda"}), + ('1.3', {'title':"Approval of the Minutes of Past Telechats"}), + ('1.4', {'title':"List of Remaining Action Items from Last Telechat"}), + ('2', {'title':"Protocol Actions"}), + ('2.1', {'title':"WG Submissions"}), + ('2.1.1', {'title':"New Items", 'docs': []}), + ('2.1.2', {'title':"Returning Items", 'docs':[]}), + ('2.1.3', {'title':"For Action", 'docs':[]}), + ('2.2', {'title':"Individual Submissions"}), + ('2.2.1', {'title':"New Items", 'docs':[]}), + ('2.2.2', {'title':"Returning Items", 'docs':[]}), + ('2.2.3', {'title':"For Action", 'docs':[]}), + ('2.3', {'title':"Status Changes"}), + ('2.3.1', {'title':"New Items", 'docs':[]}), + ('2.3.2', {'title':"Returning Items", 'docs':[]}), + ('2.3.3', {'title':"For Action", 'docs':[]}), + ('3', {'title':"Document Actions"}), + ('3.1', {'title':"WG Submissions"}), + ('3.1.1', {'title':"New Items", 'docs':[]}), + ('3.1.2', {'title':"Returning Items", 'docs':[]}), + ('3.1.3', {'title':"For Action", 'docs':[]}), + ('3.2', {'title':"Individual Submissions Via AD"}), + ('3.2.1', {'title':"New Items", 'docs':[]}), + ('3.2.2', {'title':"Returning Items", 'docs':[]}), + ('3.2.3', {'title':"For Action", 'docs':[]}), + ('3.3', {'title':"Status Changes"}), + ('3.3.1', {'title':"New Items", 'docs':[]}), + ('3.3.2', {'title':"Returning Items", 'docs':[]}), + ('3.3.3', {'title':"For Action", 'docs':[]}), + ('3.4', {'title':"IRTF and Independent Submission Stream Documents"}), + ('3.4.1', {'title':"New Items", 'docs':[]}), + ('3.4.2', {'title':"Returning Items", 'docs':[]}), + ('3.4.3', {'title':"For Action", 'docs':[]}), + ('4', {'title':"Working Group Actions"}), + ('4.1', {'title':"WG Creation"}), + ('4.1.1', {'title':"Proposed for IETF Review", 'docs':[]}), + ('4.1.2', {'title':"Proposed for Approval", 'docs':[]}), + ('4.2', {'title':"WG Rechartering"}), + ('4.2.1', {'title':"Under Evaluation for IETF Review", 'docs':[]}), + ('4.2.2', {'title':"Proposed for Approval", 'docs':[]}), + ('5', {'title':"IAB News We Can Use"}), + ('6', {'title':"Management Issues"}), + ('7', {'title':"Working Group News"}), ]) def fill_in_agenda_administrivia(date, sections): @@ -185,7 +185,7 @@ def fill_in_agenda_docs(date, sections, matches=None): # prune empty "For action" sections empty_for_action = [n for n, section in sections.iteritems() - if section["title"] == "For action" and not section["docs"]] + if section["title"] == "For Action" and not section["docs"]] for num in empty_for_action: del sections[num] diff --git a/ietf/iesg/views.py b/ietf/iesg/views.py index 4b87a99d5..cd7b155d0 100644 --- a/ietf/iesg/views.py +++ b/ietf/iesg/views.py @@ -2,24 +2,24 @@ # Portion Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). # All rights reserved. Contact: Pasi Eronen -# +# # Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions +# modification, are permitted provided that the following conditions # are met: -# +# # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. -# +# # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. -# +# # * Neither the name of the Nokia Corporation and/or its # subsidiary(-ies) nor the names of its contributors may be used # to endorse or promote products derived from this software # without specific prior written permission. -# +# # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -58,9 +58,6 @@ from ietf.iesg.models import TelechatDate from ietf.ietfauth.utils import has_role, role_required, user_is_person from ietf.person.models import Person -# FACELIFT: -from ietf.doc.views_search import fill_in_search_attributes - def review_decisions(request, year=None): events = DocEvent.objects.filter(type__in=("iesg_disapproved", "iesg_approved")) @@ -179,8 +176,8 @@ def agenda(request, date=None): data = agenda_data(date) if has_role(request.user, ["Area Director", "IAB Chair", "Secretariat"]): - data["sections"]["1.1"]["title"] = data["sections"]["1.1"]["title"].replace("Roll call", 'Roll Call') - data["sections"]["1.3"]["title"] = data["sections"]["1.3"]["title"].replace("minutes", 'Minutes') + data["sections"]["1.1"]["title"] = data["sections"]["1.1"]["title"].replace("Roll Call", 'Roll Call') + data["sections"]["1.3"]["title"] = data["sections"]["1.3"]["title"].replace("Minutes", 'Minutes') request.session['ballot_edit_return_point'] = request.path_info return render_to_response("iesg/agenda.html", { @@ -306,7 +303,7 @@ class RescheduleForm(forms.Form): def __init__(self, *args, **kwargs): dates = kwargs.pop('telechat_dates') - + super(self.__class__, self).__init__(*args, **kwargs) # telechat choices @@ -363,9 +360,6 @@ def agenda_documents(request): telechats = [] for date in dates: sections = agenda_sections() - # FACELIFT: augment the docs with the search attributes, since we're using - # the search_result_row view to display them (which expects them) - fill_in_search_attributes(docs_by_date[date]) fill_in_agenda_docs(date, sections, docs_by_date[date]) telechats.append({ diff --git a/ietf/ietfauth/forms.py b/ietf/ietfauth/forms.py index b5af137ea..94cc54d1e 100644 --- a/ietf/ietfauth/forms.py +++ b/ietf/ietfauth/forms.py @@ -217,7 +217,7 @@ class PersonForm(ModelForm): # Make sure the alias table contains any new and/or old names. old_names = set([x.name for x in Alias.objects.filter(person=self.instance)]) - curr_names = set([x for x in [self.instance.name, + curr_names = set([x for x in [self.instance.name, self.instance.ascii, self.instance.ascii_short, self.data['name'], diff --git a/ietf/ipr/models.py b/ietf/ipr/models.py index bec7cc8c2..09395a46c 100644 --- a/ietf/ipr/models.py +++ b/ietf/ipr/models.py @@ -12,8 +12,8 @@ LICENSE_CHOICES = ( (3, 'c) Reasonable and Non-Discriminatory License to All Implementers with Possible Royalty/Fee.'), (4, 'd) Licensing Declaration to be Provided Later (implies a willingness' ' to commit to the provisions of a), b), or c) above to all implementers;' - ' otherwise, the next option - "Unwilling to Commit to the Provisions of' - ' a), b), or c) Above" - must be selected).'), + ' otherwise, the next option "Unwilling to Commit to the Provisions of' + ' a), b), or c) Above". - must be selected).'), (5, 'e) Unwilling to Commit to the Provisions of a), b), or c) Above.'), (6, 'f) See Text Below for Licensing Declaration.'), ) @@ -27,10 +27,10 @@ SELECT_CHOICES = ( (2, 'NO'), ) STATUS_CHOICES = ( - ( 0, "Waiting for approval" ), - ( 1, "Approved and Posted" ), - ( 2, "Rejected by Administrator" ), - ( 3, "Removed by Request" ), + ( 0, "Waiting for approval" ), + ( 1, "Approved and Posted" ), + ( 2, "Rejected by Administrator" ), + ( 3, "Removed by Request" ), ) class IprDetail(models.Model): @@ -45,35 +45,35 @@ class IprDetail(models.Model): legacy_title_2 = models.CharField(blank=True, null=True, db_column="additional_old_title2", max_length=255) # Patent holder fieldset - legal_name = models.CharField("Legal name", db_column="p_h_legal_name", max_length=255) + legal_name = models.CharField("Legal Name", db_column="p_h_legal_name", max_length=255) # Patent Holder Contact fieldset # self.contact.filter(contact_type=1) # IETF Contact fieldset # self.contact.filter(contact_type=3) - + # Related IETF Documents fieldset rfc_number = models.IntegerField(null=True, editable=False, blank=True) # always NULL id_document_tag = models.IntegerField(null=True, editable=False, blank=True) # always NULL - other_designations = models.CharField("Designations for other contributions", blank=True, max_length=255) + other_designations = models.CharField(blank=True, max_length=255) document_sections = models.TextField("Specific document sections covered", blank=True, max_length=255, db_column='disclouser_identify') # Patent Information fieldset - patents = models.TextField("Patent, serial, publication, registration, or application/file number(s)", db_column="p_applications", max_length=255) - date_applied = models.CharField("Date(s) granted or applied for", max_length=255) + patents = models.TextField("Patent Applications", db_column="p_applications", max_length=255) + date_applied = models.CharField(max_length=255) country = models.CharField(max_length=255) notes = models.TextField("Additional notes", db_column="p_notes", blank=True) - is_pending = models.IntegerField("Unpublished pending patent application", blank=True, null=True, choices=SELECT_CHOICES, db_column="selecttype") - applies_to_all = models.IntegerField("Applies to all IPR owned by submitter", blank=True, null=True, choices=SELECT_CHOICES, db_column="selectowned") + is_pending = models.IntegerField("Unpublished Pending Patent Application", blank=True, null=True, choices=SELECT_CHOICES, db_column="selecttype") + applies_to_all = models.IntegerField("Applies to all IPR owned by Submitter", blank=True, null=True, choices=SELECT_CHOICES, db_column="selectowned") # Licensing Declaration fieldset licensing_option = models.IntegerField(null=True, blank=True, choices=LICENSE_CHOICES) lic_opt_a_sub = models.IntegerField(null=True, editable=False, choices=STDONLY_CHOICES) lic_opt_b_sub = models.IntegerField(null=True, editable=False, choices=STDONLY_CHOICES) lic_opt_c_sub = models.IntegerField(null=True, editable=False, choices=STDONLY_CHOICES) - comments = models.TextField("Licensing comments", blank=True) - lic_checkbox = models.BooleanField("The individual submitting this template represents and warrants that all terms and conditions that must be satisfied for implementers of any covered IETF specification to obtain a license have been disclosed in this IPR disclosure statement.", default=False) + comments = models.TextField("Licensing Comments", blank=True) + lic_checkbox = models.BooleanField("All terms and conditions has been disclosed", default=False) # Other notes fieldset @@ -119,8 +119,8 @@ class IprContact(models.Model): name = models.CharField(max_length=255) title = models.CharField(blank=True, max_length=255) department = models.CharField(blank=True, max_length=255) - address1 = models.CharField("Address", blank=True, max_length=255) - address2 = models.CharField("Address (continued)", blank=True, max_length=255) + address1 = models.CharField(blank=True, max_length=255) + address2 = models.CharField(blank=True, max_length=255) telephone = models.CharField(blank=True, max_length=25) fax = models.CharField(blank=True, max_length=25) email = models.EmailField(max_length=255) diff --git a/ietf/ipr/new.py b/ietf/ipr/new.py index 9ddbc4d75..4d77975b9 100644 --- a/ietf/ipr/new.py +++ b/ietf/ipr/new.py @@ -16,19 +16,19 @@ from ietf.ipr.view_sections import section_table # ---------------------------------------------------------------- # Create base forms from models -# ---------------------------------------------------------------- +# ---------------------------------------------------------------- phone_re = re.compile(r'^\+?[0-9 ]*(\([0-9]+\))?[0-9 -]+( ?x ?[0-9]+)?$') phone_error_message = """Phone numbers may have a leading "+", and otherwise only contain numbers [0-9]; dash, period or space; parentheses, and an optional extension number indicated by 'x'.""" class BaseIprForm(forms.ModelForm): licensing_option = forms.IntegerField(widget=forms.RadioSelect(choices=LICENSE_CHOICES), required=False) - is_pending = forms.IntegerField(widget=forms.RadioSelect(choices=((1, "Yes"), (2, "No"))), required=False) - applies_to_all = forms.IntegerField(widget=forms.RadioSelect(choices=((1, "Yes"), (2, "No"))), required=False) + is_pending = forms.IntegerField(widget=forms.RadioSelect(choices=((1, "YES"), (2, "NO"))), required=False) + applies_to_all = forms.IntegerField(widget=forms.RadioSelect(choices=((1, "YES"), (2, "NO"))), required=False) class Meta: model = IprDetail exclude = ('rfc_document', 'id_document_tag') # 'legacy_url_0','legacy_url_1','legacy_title_1','legacy_url_2','legacy_title_2') - + class BaseContactForm(forms.ModelForm): telephone = forms.RegexField(phone_re, error_message=phone_error_message, required=False) fax = forms.RegexField(phone_re, error_message=phone_error_message, required=False) @@ -68,9 +68,9 @@ def new(request, type, update=None, submitter=None): class IprForm(BaseIprForm): holder_contact = None - rfclist = forms.CharField(label="RFC numbers", required=False) - draftlist = forms.CharField(label="Internet-Draft filenames (draft-...)", required=False) - stdonly_license = forms.BooleanField(label="Above licensing declaration is limited solely to standards-track IETF documents", required=False) + rfclist = forms.CharField(required=False) + draftlist = forms.CharField(required=False) + stdonly_license = forms.BooleanField(required=False) hold_contact_is_submitter = forms.BooleanField(required=False) ietf_contact_is_submitter = forms.BooleanField(required=False) if section_list.get("holder_contact", False): @@ -98,16 +98,16 @@ def new(request, type, update=None, submitter=None): rfclist_initial = "" if update: rfclist_initial = " ".join(a.doc_alias.name.upper() for a in IprDocAlias.objects.filter(doc_alias__name__startswith="rfc", ipr=update)) - self.base_fields["rfclist"] = forms.CharField(label="RFC numbers", required=False, initial=rfclist_initial) + self.base_fields["rfclist"] = forms.CharField(required=False, initial=rfclist_initial) draftlist_initial = "" if update: draftlist_initial = " ".join(a.doc_alias.name + ("-%s" % a.rev if a.rev else "") for a in IprDocAlias.objects.filter(ipr=update).exclude(doc_alias__name__startswith="rfc")) - self.base_fields["draftlist"] = forms.CharField(label="Internet-Draft filenames (draft-...)", required=False, initial=draftlist_initial) + self.base_fields["draftlist"] = forms.CharField(required=False, initial=draftlist_initial) if section_list.get("holder_contact", False): self.base_fields["hold_contact_is_submitter"] = forms.BooleanField(required=False) if section_list.get("ietf_contact", False): self.base_fields["ietf_contact_is_submitter"] = forms.BooleanField(required=False) - self.base_fields["stdonly_license"] = forms.BooleanField(label="Above licensing declaration is limited solely to standards-track IETF documents", required=False) + self.base_fields["stdonly_license"] = forms.BooleanField(required=False) BaseIprForm.__init__(self, *args, **kw) # Special validation code @@ -184,7 +184,7 @@ def new(request, type, update=None, submitter=None): data["generic"] = section_list["generic"] data["status"] = "0" data["comply"] = "1" - + for src in ["hold", "ietf"]: if "%s_contact_is_submitter" % src in data: for subfield in ["name", "title", "department", "address1", "address2", "telephone", "fax", "email"]: @@ -202,7 +202,7 @@ def new(request, type, update=None, submitter=None): legal_name_genitive = data['legal_name'] + "'" if data['legal_name'].endswith('s') else data['legal_name'] + "'s" if type == "generic": - instance.title = legal_name_genitive + " General License Statement" + instance.title = legal_name_genitive + " General License Statement" elif type == "specific": data["ipr_summary"] = get_ipr_summary(form.cleaned_data) instance.title = legal_name_genitive + """ Statement about IPR related to %(ipr_summary)s""" % data @@ -295,7 +295,7 @@ def update(request, ipr_id=None): """Update a specific IPR disclosure""" ipr = get_object_or_404(IprDetail, ipr_id=ipr_id) if not ipr.status in [1,3]: - raise Http404 + raise Http404 type = "specific" if ipr.generic: type = "generic" @@ -311,8 +311,8 @@ def update(request, ipr_id=None): class UpdateForm(BaseContactForm): def __init__(self, *args, **kwargs): super(UpdateForm, self).__init__(*args, **kwargs) - self.fields["update_auth"] = forms.BooleanField(label="I am authorized to update this IPR disclosure, and I understand that notification of this update will be provided to the submitter of the original IPR disclosure and to the Patent Holder's Contact.") - + self.fields["update_auth"] = forms.BooleanField() + if request.method == 'POST': form = UpdateForm(request.POST) else: diff --git a/ietf/meeting/urls.py b/ietf/meeting/urls.py index 3ab323d17..a4443f1fe 100644 --- a/ietf/meeting/urls.py +++ b/ietf/meeting/urls.py @@ -9,7 +9,8 @@ from ietf.meeting import ajax urlpatterns = patterns('', (r'^(?P\d+)/materials.html$', views.materials), (r'^agenda/$', views.agenda), - (r'^agenda(-utc)?(?P.html)?$', views.agenda), + (r'^(?Pagenda-utc)(?P.html)?$', views.agenda), + (r'^agenda(?P.html)?$', views.agenda), (r'^agenda(?P.txt)$', views.agenda), (r'^agenda(?P.csv)$', views.agenda), (r'^agenda/edit$', views.edit_agenda), @@ -27,7 +28,8 @@ urlpatterns = patterns('', (r'^(?P\d+)/agenda/(?P[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P[A-Za-z0-9-:_]+)/sessions.json$', ajax.scheduledsessions_json), (r'^(?P\d+)/agenda/(?P[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P[A-Za-z0-9-:_]+).json$', ajax.agenda_infourl), (r'^(?P\d+)/agenda/edit$', views.edit_agenda), - (r'^(?P\d+)/agenda(-utc)?(?P.html)?/?$', views.agenda), + (r'^(?P\d+)/agenda(?P.html)?/?$', views.agenda), + (r'^(?P\d+)/(?Pagenda-utc)(?P.html)?/?$', views.agenda), (r'^(?P\d+)/requests.html$', RedirectView.as_view(url='/meeting/%(num)s/requests', permanent=True)), (r'^(?P\d+)/requests$', views.meeting_requests), (r'^(?P\d+)/agenda(?P.txt)$', views.agenda), diff --git a/ietf/nomcom/forms.py b/ietf/nomcom/forms.py index 7fba3b598..f6d7e3880 100644 --- a/ietf/nomcom/forms.py +++ b/ietf/nomcom/forms.py @@ -11,7 +11,7 @@ from ietf.dbtemplate.forms import DBTemplateForm from ietf.group.models import Group, Role from ietf.ietfauth.utils import role_required from ietf.name.models import RoleName, FeedbackTypeName, NomineePositionStateName -from ietf.nomcom.models import ( NomCom, Nomination, Nominee, NomineePosition, +from ietf.nomcom.models import ( NomCom, Nomination, Nominee, NomineePosition, Position, Feedback, ReminderDates ) from ietf.nomcom.utils import (NOMINATION_RECEIPT_TEMPLATE, FEEDBACK_RECEIPT_TEMPLATE, get_user_email, validate_private_key, validate_public_key, @@ -378,7 +378,7 @@ class MergeForm(BaseNomcomForm, forms.Form): class NominateForm(BaseNomcomForm, forms.ModelForm): - comments = forms.CharField(label="Candidate's qualifications for the position", + comments = forms.CharField(label="Candidate's Qualifications for the Position:", widget=forms.Textarea()) confirmation = forms.BooleanField(label='Email comments back to me as confirmation', help_text="If you want to get a confirmation mail containing your feedback in cleartext, \ @@ -400,7 +400,6 @@ class NominateForm(BaseNomcomForm, forms.ModelForm): 'candidate_email', 'candidate_phone', 'comments'] - self.fields['nominator_email'].label = 'Nominator email' if self.nomcom: self.fields['position'].queryset = Position.objects.get_by_nomcom(self.nomcom).opened() self.fields['comments'].help_text = self.nomcom.initial_text @@ -462,7 +461,7 @@ class NominateForm(BaseNomcomForm, forms.ModelForm): # send receipt email to nominator if confirmation: if author: - subject = 'Nomination receipt' + subject = 'Nomination Receipt' from_email = settings.NOMCOM_FROM_EMAIL to_email = author.address context = {'nominee': nominee.email.person.name, @@ -480,15 +479,15 @@ class NominateForm(BaseNomcomForm, forms.ModelForm): class FeedbackForm(BaseNomcomForm, forms.ModelForm): - position_name = forms.CharField(label='Position', + position_name = forms.CharField(label='position', widget=forms.TextInput(attrs={'size': '40'})) - nominee_name = forms.CharField(label='Nominee name', + nominee_name = forms.CharField(label='nominee name', widget=forms.TextInput(attrs={'size': '40'})) - nominee_email = forms.CharField(label='Nominee email', + nominee_email = forms.CharField(label='nominee email', widget=forms.TextInput(attrs={'size': '40'})) - nominator_email = forms.CharField(label='Commenter email') + nominator_email = forms.CharField(label='commenter email') - comments = forms.CharField(label='Comments on this nominee', + comments = forms.CharField(label='Comments on this candidate', widget=forms.Textarea()) confirmation = forms.BooleanField(label='Email comments back to me as confirmation', help_text="If you want to get a confirmation mail containing your feedback in cleartext, \ diff --git a/ietf/nomcom/models.py b/ietf/nomcom/models.py index 0948d925c..b7c9ab723 100644 --- a/ietf/nomcom/models.py +++ b/ietf/nomcom/models.py @@ -38,7 +38,7 @@ class NomCom(models.Model): upload_to=upload_path_handler, blank=True, null=True) group = models.ForeignKey(Group) - send_questionnaire = models.BooleanField(verbose_name='Send questionnaires automatically', default=False, + send_questionnaire = models.BooleanField(verbose_name='Send questionnaires automatically"', default=False, help_text='If you check this box, questionnaires are sent automatically after nominations') reminder_interval = models.PositiveIntegerField(help_text='If the nomcom user sets the interval field then a cron command will \ send reminders to the nominees who have not responded using \ diff --git a/ietf/nomcom/templatetags/nomcom_tags.py b/ietf/nomcom/templatetags/nomcom_tags.py index 85a023123..43f421a6a 100644 --- a/ietf/nomcom/templatetags/nomcom_tags.py +++ b/ietf/nomcom/templatetags/nomcom_tags.py @@ -41,8 +41,12 @@ def add_num_nominations(user, position, nominee): nominees__in=[nominee], author=author, type='comment').count() + if count: + mark = """*""" + else: + mark = """ """ - return '%s ' % (count, nominee.email.address, position, count) + return '%s ' % (count, nominee.email.address, position, mark) @register.filter @@ -72,7 +76,7 @@ def decrypt(string, request, year, plain=False): code, out, error = pipe(command % (settings.OPENSSL_COMMAND, encrypted_file.name), key) if code != 0: - log("openssl error: %s:\n Error %s: %s" %(command, code, error)) + log("openssl error: %s:\n Error %s: %s" %(command, code, error)) os.unlink(encrypted_file.name) diff --git a/ietf/nomcom/views.py b/ietf/nomcom/views.py index d4dfc4a17..f0a757d4c 100644 --- a/ietf/nomcom/views.py +++ b/ietf/nomcom/views.py @@ -56,7 +56,7 @@ def index(request): nomcom.ann_url = None return render_to_response('nomcom/index.html', {'nomcom_list': nomcom_list,}, RequestContext(request)) - + def year_index(request, year): nomcom = get_nomcom_by_year(year) @@ -70,21 +70,21 @@ def year_index(request, year): def announcements(request): address_re = re.compile("<.*>") - + nomcoms = Group.objects.filter(type="nomcom") regimes = [] - + for n in nomcoms: e = GroupEvent.objects.filter(group=n, type="changed_state", changestategroupevent__state="active").order_by('time')[:1] n.start_year = e[0].time.year if e else 0 e = GroupEvent.objects.filter(group=n, type="changed_state", changestategroupevent__state="conclude").order_by('time')[:1] n.end_year = e[0].time.year if e else n.start_year + 1 - r = n.role_set.select_related().filter(name="chair") - chair = None - if r: - chair = r[0] + r = n.role_set.select_related().filter(name="chair") + chair = None + if r: + chair = r[0] announcements = Message.objects.filter(related_groups=n).order_by('-time') for a in announcements: diff --git a/ietf/person/forms.py b/ietf/person/forms.py deleted file mode 100644 index 6c34da439..000000000 --- a/ietf/person/forms.py +++ /dev/null @@ -1,44 +0,0 @@ -import json - -from django.utils.html import escape -from django.utils.functional import lazy -from django import forms -from django.core.urlresolvers import reverse as urlreverse - -import debug # pyflakes:ignore - -from ietf.person.models import Email - -def json_emails(emails): - if isinstance(emails, basestring): - emails = Email.objects.filter(address__in=[x.strip() for x in emails.split(",") if x.strip()]).select_related("person") - return json.dumps([{"id": e.address + "", "name": escape(u"%s <%s>" % (e.person.name, e.address))} for e in emails]) - -class EmailsField(forms.CharField): - """Multi-select field using jquery.tokeninput.js. Since the API of - tokeninput" is asymmetric, we have to pass it a JSON - representation on the way out and parse the ids coming back as a - comma-separated list on the way in.""" - - def __init__(self, *args, **kwargs): - kwargs["max_length"] = 1000 - if not "help_text" in kwargs: - kwargs["help_text"] = "Type in name to search for person." - super(EmailsField, self).__init__(*args, **kwargs) - self.widget.attrs["class"] = "tokenized-field" - self.widget.attrs["data-ajax-url"] = lazy(urlreverse, str)("ajax_search_emails") # make this lazy to prevent initialization problem - - def parse_tokenized_value(self, value): - return Email.objects.filter(address__in=[x.strip() for x in value.split(",") if x.strip()]).select_related("person") - - def prepare_value(self, value): - if not value: - return "" - if isinstance(value, str) or isinstance(value, unicode): - value = self.parse_tokenized_value(value) - return json_emails(value) - - def clean(self, value): - value = super(EmailsField, self).clean(value) - return self.parse_tokenized_value(value) - diff --git a/ietf/settings.py b/ietf/settings.py index 573c9f16e..8ad8ace33 100644 --- a/ietf/settings.py +++ b/ietf/settings.py @@ -14,7 +14,7 @@ except ImportError: BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # a place to put ajax logs if necessary. -LOG_DIR = '/var/log/datatracker' +LOG_DIR = '/var/log/datatracker' import sys sys.path.append(os.path.abspath(BASE_DIR + "/..")) @@ -63,9 +63,9 @@ DATABASES = { } DATABASE_TEST_OPTIONS = { - # Comment this out if your database doesn't support InnoDB - 'init_command': 'SET storage_engine=InnoDB', -} + # Comment this out if your database doesn't support InnoDB + 'init_command': 'SET storage_engine=InnoDB', + } # Local time zone for this installation. Choices can be found here: # http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE @@ -87,11 +87,10 @@ USE_I18N = False USE_TZ = False -MEDIA_URL = '//www.ietf.org/' +MEDIA_URL = 'http://www.ietf.org/' STATIC_URL = "/" STATIC_ROOT = os.path.abspath(BASE_DIR + "/../static/") -STATIC_URL = STATIC_ROOT + '/' WSGI_APPLICATION = "ietf.wsgi.application" @@ -234,35 +233,8 @@ INSTALLED_APPS = ( 'ietf.secr.sreq', 'ietf.nomcom', 'ietf.dbtemplate', - # FACELIFT: apps for facelift UI - 'widget_tweaks', - 'typogrify', - 'bootstrap3', - 'mathfilters', ) -# Settings for django-bootstrap3 -# See http://django-bootstrap3.readthedocs.org/en/latest/settings.html -BOOTSTRAP3 = { - # Label class to use in horizontal forms - 'horizontal_label_class': 'col-md-2', - - # Field class to use in horiozntal forms - 'horizontal_field_class': 'col-md-10', - - # Set HTML required attribute on required fields - 'set_required': True, - - # Set placeholder attributes to label if no placeholder is provided - 'set_placeholder': False, - - # Class to indicate required - 'form_required_class': 'bootstrap3-required', - - # Class to indicate error - 'form_error_class': 'bootstrap3-error', -} - INTERNAL_IPS = ( # AMS servers '64.170.98.32', @@ -274,7 +246,7 @@ INTERNAL_IPS = ( ) # no slash at end -IDTRACKER_BASE_URL = "//datatracker.ietf.org" +IDTRACKER_BASE_URL = "http://datatracker.ietf.org" RFCDIFF_PREFIX = "//www.ietf.org/rfcdiff" # Valid values: @@ -315,22 +287,22 @@ INTERNET_DRAFT_ARCHIVE_DIR = '/a/www/www6s/draft-archive' MEETING_RECORDINGS_DIR = '/a/www/audio' # Mailing list info URL for lists hosted on the IETF servers -MAILING_LIST_INFO_URL = "//www.ietf.org/mailman/listinfo/%(list_addr)s" +MAILING_LIST_INFO_URL = "https://www.ietf.org/mailman/listinfo/%(list_addr)s" # Ideally, more of these would be local -- but since we don't support # versions right now, we'll point to external websites DOC_HREFS = { - "charter": "//www.ietf.org/charter/{doc.name}-{doc.rev}.txt", - "draft": "//www.ietf.org/archive/id/{doc.name}-{doc.rev}.txt", - "slides": "//www.ietf.org/slides/{doc.name}-{doc.rev}", - "conflrev": "//www.ietf.org/cr/{doc.name}-{doc.rev}.txt", - "statchg": "//www.ietf.org/sc/{doc.name}-{doc.rev}.txt", + "charter": "http://www.ietf.org/charter/{doc.name}-{doc.rev}.txt", + "draft": "http://www.ietf.org/archive/id/{doc.name}-{doc.rev}.txt", + "slides": "http://www.ietf.org/slides/{doc.name}-{doc.rev}", + "conflrev": "http://www.ietf.org/cr/{doc.name}-{doc.rev}.txt", + "statchg": "http://www.ietf.org/sc/{doc.name}-{doc.rev}.txt", } MEETING_DOC_HREFS = { "agenda": "/meeting/{meeting}/agenda/{doc.group.acronym}/", - "minutes": "/www.ietf.org/proceedings/{meeting}/minutes/{doc.external_url}", - "slides": "/www.ietf.org/proceedings/{meeting}/slides/{doc.external_url}", + "minutes": "http://www.ietf.org/proceedings/{meeting}/minutes/{doc.external_url}", + "slides": "http://www.ietf.org/proceedings/{meeting}/slides/{doc.external_url}", "recording": "{doc.external_url}", } @@ -355,15 +327,15 @@ IANA_APPROVE_EMAIL = "drafts-approval@icann.org" # Put real password in settings_local.py IANA_SYNC_PASSWORD = "secret" -IANA_SYNC_CHANGES_URL = "//datatracker.iana.org:4443/data-tracker/changes" -IANA_SYNC_PROTOCOLS_URL = "//www.iana.org/protocols/" +IANA_SYNC_CHANGES_URL = "https://datatracker.iana.org:4443/data-tracker/changes" +IANA_SYNC_PROTOCOLS_URL = "http://www.iana.org/protocols/" RFC_TEXT_RSYNC_SOURCE="ftp.rfc-editor.org::rfcs-text-only" RFC_EDITOR_SYNC_PASSWORD="secret" -RFC_EDITOR_SYNC_NOTIFICATION_URL = "//www.rfc-editor.org/parser/parser.php" -RFC_EDITOR_QUEUE_URL = "//www.rfc-editor.org/queue2.xml" -RFC_EDITOR_INDEX_URL = "//www.rfc-editor.org/rfc/rfc-index.xml" +RFC_EDITOR_SYNC_NOTIFICATION_URL = "http://www.rfc-editor.org/parser/parser.php" +RFC_EDITOR_QUEUE_URL = "http://www.rfc-editor.org/queue2.xml" +RFC_EDITOR_INDEX_URL = "http://www.rfc-editor.org/rfc/rfc-index.xml" # Liaison Statement Tool settings LIAISON_UNIVERSAL_FROM = 'Liaison Statement Management Tool ' @@ -399,7 +371,7 @@ INTERNET_DRAFT_DAYS_TO_EXPIRE = 185 IDSUBMIT_REPOSITORY_PATH = INTERNET_DRAFT_PATH IDSUBMIT_STAGING_PATH = '/a/www/www6s/staging/' -IDSUBMIT_STAGING_URL = '//www.ietf.org/staging/' +IDSUBMIT_STAGING_URL = 'http://www.ietf.org/staging/' IDSUBMIT_IDNITS_BINARY = '/a/www/ietf-datatracker/scripts/idnits' IDSUBMIT_MAX_PLAIN_DRAFT_SIZE = 6291456 # Max size of the txt draft in bytes @@ -442,7 +414,7 @@ SECR_AUTH_UNRESTRICTED_URLS = ( (r'^/secr/sreq/'), ) SECR_BLUE_SHEET_PATH = '/a/www/ietf-datatracker/documents/blue_sheet.rtf' -SECR_BLUE_SHEET_URL = '//datatracker.ietf.org/documents/blue_sheet.rtf' +SECR_BLUE_SHEET_URL = 'https://datatracker.ietf.org/documents/blue_sheet.rtf' SECR_INTERIM_LISTING_DIR = '/a/www/www6/meeting/interim' SECR_MAX_UPLOAD_SIZE = 40960000 SECR_PROCEEDINGS_DIR = '/a/www/www6s/proceedings/' @@ -479,16 +451,19 @@ BADNESS_MUCHTOOBIG = 500 SELENIUM_TESTS = False SELENIUM_TESTS_ONLY = False -# Set debug apps in DEV_APPS settings_local -DEV_APPS = () +# Path to the email alias lists. Used by ietf.utils.aliases +DRAFT_ALIASES_PATH = "/a/postfix/draft-aliases" +DRAFT_VIRTUAL_PATH = "/a/postfix/draft-virtual" + +GROUP_ALIASES_PATH = "/a/postfix/group-aliases" +GROUP_VIRTUAL_PATH = "/a/postfix/group-virtual" + +POSTCONFIRM_PATH = "/a/postconfirm/test-wrapper" # Put the production SECRET_KEY in settings_local.py, and also any other # sensitive or site-specific changes. DO NOT commit settings_local.py to svn. from settings_local import * # pyflakes:ignore -# Add DEV_APPS to INSTALLED_APPS -INSTALLED_APPS += DEV_APPS - # We provide a secret key only for test and development modes. It's # absolutely vital that django fails to start in production mode unless a # secret key has been provided elsewhere, not in this file which is diff --git a/ietf/submit/forms.py b/ietf/submit/forms.py index 02b816123..975f5797c 100644 --- a/ietf/submit/forms.py +++ b/ietf/submit/forms.py @@ -47,20 +47,20 @@ class UploadForm(forms.Form): ietf_monday = Meeting.get_ietf_monday() if now.date() >= (first_cut_off-timedelta(days=settings.CUTOFF_WARNING_DAYS)) and now.date() < first_cut_off: - self.cutoff_warning = ( 'The pre-meeting cut-off date for new documents (i.e., version -00 Internet-Drafts) is %s at %02sh UTC.' % (first_cut_off, settings.CUTOFF_HOUR) + - 'The pre-meeting cut-off date for revisions to existing documents is %s at %02sh UTC.' % (second_cut_off, settings.CUTOFF_HOUR) ) + self.cutoff_warning = ( 'The pre-meeting cut-off date for new documents (i.e., version -00 Internet-Drafts) is %s at %02sh UTC.
' % (first_cut_off, settings.CUTOFF_HOUR) + + 'The pre-meeting cut-off date for revisions to existing documents is %s at %02sh UTC.
' % (second_cut_off, settings.CUTOFF_HOUR) ) elif now.date() >= first_cut_off and now.date() < second_cut_off: # We are in the first_cut_off if now.date() == first_cut_off and now.hour < settings.CUTOFF_HOUR: self.cutoff_warning = 'The pre-meeting cut-off date for new documents (i.e., version -00 Internet-Drafts) is %s, at %02sh UTC. After that, you will not be able to submit a new document until %s, at %sh UTC' % (first_cut_off, settings.CUTOFF_HOUR, ietf_monday, settings.CUTOFF_HOUR, ) else: # No 00 version allowed - self.cutoff_warning = 'The pre-meeting cut-off date for new documents (i.e., version -00 Internet-Drafts) was %s at %sh UTC. You will not be able to submit a new document until %s, at %sh UTC. You can still submit a version -01 or higher Internet-Draft until %sh UTC, %s' % (first_cut_off, settings.CUTOFF_HOUR, ietf_monday, settings.CUTOFF_HOUR, settings.CUTOFF_HOUR, second_cut_off, ) + self.cutoff_warning = 'The pre-meeting cut-off date for new documents (i.e., version -00 Internet-Drafts) was %s at %sh UTC. You will not be able to submit a new document until %s, at %sh UTC.
You can still submit a version -01 or higher Internet-Draft until %sh UTC, %s' % (first_cut_off, settings.CUTOFF_HOUR, ietf_monday, settings.CUTOFF_HOUR, settings.CUTOFF_HOUR, second_cut_off, ) self.in_first_cut_off = True elif now.date() >= second_cut_off and now.date() < ietf_monday: if now.date() == second_cut_off and now.hour < settings.CUTOFF_HOUR: # We are in the first_cut_off yet - self.cutoff_warning = 'The pre-meeting cut-off date for new documents (i.e., version -00 Internet-Drafts) was %s at %02sh UTC. You will not be able to submit a new document until %s, at %02sh UTC. The I-D submission tool will be shut down at %02sh UTC today, and reopened at %02sh UTC on %s' % (first_cut_off, settings.CUTOFF_HOUR, ietf_monday, settings.CUTOFF_HOUR, settings.CUTOFF_HOUR, settings.CUTOFF_HOUR, ietf_monday) + self.cutoff_warning = 'The pre-meeting cut-off date for new documents (i.e., version -00 Internet-Drafts) was %s at %02sh UTC. You will not be able to submit a new document until %s, at %02sh UTC.
The I-D submission tool will be shut down at %02sh UTC today, and reopened at %02sh UTC on %s' % (first_cut_off, settings.CUTOFF_HOUR, ietf_monday, settings.CUTOFF_HOUR, settings.CUTOFF_HOUR, settings.CUTOFF_HOUR, ietf_monday) self.in_first_cut_off = True else: # Completely shut down of the tool - self.cutoff_warning = 'The cut-off time for the I-D submission was %02dh UTC, %s. The I-D submission tool will be reopened at %02dh local time at the IETF meeting location, %s.' % (settings.CUTOFF_HOUR, second_cut_off, settings.CUTOFF_HOUR, ietf_monday) + self.cutoff_warning = 'The cut-off time for the I-D submission was %02dh UTC, %s.
The I-D submission tool will be reopened at %02dh local time at the IETF meeting location, %s.' % (settings.CUTOFF_HOUR, second_cut_off, settings.CUTOFF_HOUR, ietf_monday) self.shutdown = True def clean_file(self, field_name, parser_class): @@ -116,7 +116,7 @@ class UploadForm(forms.Form): # check existing existing = Submission.objects.filter(name=self.parsed_draft.filename, rev=self.parsed_draft.revision).exclude(state__in=("posted", "cancel")) if existing: - raise forms.ValidationError(mark_safe('Submission with same name and revision is currently being processed. Check the status here.' % urlreverse("submit_submission_status", kwargs={ 'submission_id': existing[0].pk }))) + raise forms.ValidationError(mark_safe('Submission with same name and revision is currently being processed. Check the status here' % urlreverse("submit_submission_status", kwargs={ 'submission_id': existing[0].pk }))) # cut-off if self.parsed_draft.revision == '00' and self.in_first_cut_off: @@ -227,7 +227,7 @@ class EditSubmissionForm(forms.ModelForm): pages = forms.IntegerField(required=True) abstract = forms.CharField(widget=forms.Textarea, required=True) - note = forms.CharField(label=mark_safe(u'Comment to the Secretariat'), widget=forms.Textarea, required=False) + note = forms.CharField(label=mark_safe(u'Comment to
the Secretariat'), widget=forms.Textarea, required=False) class Meta: model = Submission diff --git a/ietf/submit/templatetags/submit_tags.py b/ietf/submit/templatetags/submit_tags.py index 9fcb913d8..5692db021 100644 --- a/ietf/submit/templatetags/submit_tags.py +++ b/ietf/submit/templatetags/submit_tags.py @@ -17,7 +17,7 @@ def show_submission_files(context, submission): exists = True elif submission.state_id == "posted": continue - result.append({'name': '%s' % ext[1:], + result.append({'name': '[%s version]' % ext[1:].upper(), 'exists': exists, 'url': '%s%s-%s%s' % (settings.IDSUBMIT_STAGING_URL, submission.name, submission.rev, ext)}) return {'files': result} @@ -27,16 +27,15 @@ def show_submission_files(context, submission): def two_pages_decorated_with_errors(submission, errors): pages = submission.first_two_pages or '' if 'rev' not in errors.keys(): - return mark_safe('
%s
' % escape(pages)) - result = '
\n'
+        return mark_safe('
%s
' % escape(pages)) + result = '
\n'
     for line in pages.split('\n'):
         if line.find('%s-%s' % (submission.name, submission.rev)) > -1:
-            result += '
' + result += '
'
             result += escape(line)
             result += '\n'
-            result += '\n'
+            result += '
\n'
         else:
             result += escape(line)
             result += '\n'
-    result += '
pre>\n' return mark_safe(result) diff --git a/ietf/submit/utils.py b/ietf/submit/utils.py index d01847241..79020b7f8 100644 --- a/ietf/submit/utils.py +++ b/ietf/submit/utils.py @@ -39,7 +39,7 @@ def validate_submission(submission): for ext in submission.file_types.split(','): source = os.path.join(settings.IDSUBMIT_STAGING_PATH, '%s-%s%s' % (submission.name, submission.rev, ext)) if not os.path.exists(source): - errors['files'] = '"%s" was not found in the staging area. We recommend you that you cancel this submission and upload your files again.' % os.path.basename(source) + errors['files'] = '"%s" was not found in the staging area.
We recommend you that you cancel this submission and upload your files again.' % os.path.basename(source) break if not submission.title: diff --git a/ietf/templates/base/menu.html b/ietf/templates/base/menu.html deleted file mode 100644 index 762c842c5..000000000 --- a/ietf/templates/base/menu.html +++ /dev/null @@ -1,153 +0,0 @@ -{% load wg_menu %} -{% load streams_menu %} -{% load ietf_filters community_tags %} - -
  • - {% if flavor == "top" %}{% endif %} - {##} - {% if user.is_authenticated %} {{ user }} {% else %} User {% endif %} - {% if flavor == "top" %} - - {% endif %} - -
  • - {% if flavor == "top" %}{% endif %} - {##} - Groups - {% if flavor == "top" %} - - {% endif %} - -
  • - {% if flavor == "top" %}{% endif %} - {##} - Documents - {% if flavor == "top" %} - - {% endif %} - -
  • - {% if flavor == "top" %}{% endif %} - {##} - Meetings - {% if flavor == "top" %} - - {% endif %} - -
  • - {% if flavor == "top" %}{% endif %} - {##} - Other - {% if flavor == "top" %} - - {% endif %} diff --git a/ietf/templates/base/menu_wg.html b/ietf/templates/base/menu_wg.html deleted file mode 100644 index e9e72cd6e..000000000 --- a/ietf/templates/base/menu_wg.html +++ /dev/null @@ -1,19 +0,0 @@ -{% for area in areas %} -
  • -{% endfor %} - - diff --git a/ietf/templates/base/menu_wg_modal.html b/ietf/templates/base/menu_wg_modal.html deleted file mode 100644 index 377bbe1f8..000000000 --- a/ietf/templates/base/menu_wg_modal.html +++ /dev/null @@ -1,51 +0,0 @@ -{# widthratio rounds up, is useless #} -{% load mathfilters %} - -{% with cols=areas|length|add:1 %} -{% with colw=100|div:cols %} -
    - - - - {% for area in areas %} - - {% endfor %} - - - - - - {% for area in areas %} - - {% endfor %} - - - -
    - {{area.acronym|upper}} - - IRTF -
    -
    - {% for group in area.active_groups %} - - {% endfor %} -
    -
    -
    - {% for group in rgs %} - - {% endfor %} -
    -
    -
    -{% endwith %} -{% endwith %} diff --git a/ietf/templates/community/customize_display.html b/ietf/templates/community/customize_display.html index fb77c4475..8976eeca8 100644 --- a/ietf/templates/community/customize_display.html +++ b/ietf/templates/community/customize_display.html @@ -1,24 +1,18 @@ -{% load bootstrap3 %} +

    Display customization

    -{% bootstrap_messages %} +
    {% csrf_token %} +

    Sort method

    + {{ display_form.sort_method }} - - {% csrf_token %} - {% bootstrap_form display_form %} - -
    - - {% for field in dc.get_display_fields_config %} -
    - -
    - {% endfor %} -
    - - {% buttons %} - - {% endbuttons %} +

    Show fields

    +
    + {% for field in dc.get_display_fields_config %} +
    + + +
    + {% endfor %} +
    +

    +
    diff --git a/ietf/templates/community/manage_clist.html b/ietf/templates/community/manage_clist.html index 47bee283f..cbaf0a5a4 100644 --- a/ietf/templates/community/manage_clist.html +++ b/ietf/templates/community/manage_clist.html @@ -1,130 +1,124 @@ -{% extends "ietf.html" %} - -{% load bootstrap3 %} +{% extends "base.html" %} {% block title %}{{ cl.long_name }}{% endblock %} {% block content %}

    {{ cl.long_name }}

    - -{% bootstrap_messages %} - -