Merged in ^/trunk@17782 (just ahead of release 6.130.0)
- Legacy-Id: 17783
This commit is contained in:
commit
154876a12a
|
@ -61,4 +61,4 @@ $DTDIR/ietf/manage.py fetch_meeting_attendance --latest 2
|
|||
$DTDIR/ietf/bin/send-review-reminders
|
||||
|
||||
# Purge old request_profiler records
|
||||
$DTDIR/ietf/manage.py purge_request_profiler_records
|
||||
$DTDIR/ietf/manage.py purge_request_profiler_records -d2
|
||||
|
|
16
bin/dump-to-names-json
Normal file
16
bin/dump-to-names-json
Normal file
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script provides a limited selected dump of database content with the
|
||||
# purpose of generating a test fixture that provides the test data needed
|
||||
# by the test suite.
|
||||
#
|
||||
# The generated data fixture is sorted and normalized in order to produce
|
||||
# minimal commit diffs which reflect only actual changes in the fixture data,
|
||||
# without apparent changes resulting only from ordering changes.
|
||||
|
||||
set -x
|
||||
ietf/manage.py dumpdata --indent 1 doc.State doc.BallotType doc.StateType \
|
||||
mailtrigger.MailTrigger mailtrigger.Recipient name utils.VersionInfo \
|
||||
group.GroupFeatures stats.CountryAlias dbtemplate.DBTemplate \
|
||||
| jq --sort-keys "sort_by(.model, .pk)" \
|
||||
| jq '[.[] | select(.model!="dbtemplate.dbtemplate" or .pk==354)]' > ietf/name/fixtures/names.json
|
|
@ -16,7 +16,5 @@ source $DTDIR/env/bin/activate
|
|||
|
||||
logger -p user.info -t cron "Running $DTDIR/bin/every15m"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Send mail scheduled to go out at certain times
|
||||
$DTDIR/ietf/bin/send-scheduled-mail all
|
||||
|
|
|
@ -138,6 +138,7 @@ def check_html_valid(url, response, args):
|
|||
key = re.sub("/dir/[a-z0-9-]+/", "/dir/foo/", key)
|
||||
key = re.sub("/draft-[a-z0-9-]+/", "/draft-foo/", key)
|
||||
key = re.sub("/group/[a-z0-9-]+/", "/group/foo/", key)
|
||||
key = re.sub("/html/[a-z0-9-]+", "/html/foo/", key)
|
||||
key = re.sub("/ipr/search/.*", "/ipr/search/", key)
|
||||
key = re.sub("/meeting/[-0-9a-z]+/agenda/[0-9a-z]+/", "/meeting/nn/agenda/foo/", key)
|
||||
key = re.sub("/release/[0-9dev.]+/", "/release/n.n.n/", key)
|
||||
|
|
|
@ -20,3 +20,6 @@ logger -p user.info -t cron "Running $DTDIR/bin/weekly"
|
|||
|
||||
$DTDIR/ietf/manage.py send_apikey_usage_emails
|
||||
|
||||
# Send notifications about coming expirations
|
||||
$DTDIR/ietf/bin/notify-expirations
|
||||
|
||||
|
|
|
@ -20,19 +20,16 @@ c = BuildmasterConfig = {}
|
|||
# slave name and password must be configured on the slave.
|
||||
from buildbot.buildslave import BuildSlave
|
||||
c['slaves'] = [
|
||||
BuildSlave("datatracker_lin_py27_1", datatracker_lin_py27_1_pw),
|
||||
BuildSlave("datatracker_lin_py27_2", datatracker_lin_py27_2_pw),
|
||||
BuildSlave("datatracker_lin_py27_3", datatracker_lin_py27_3_pw),
|
||||
BuildSlave("datatracker_osx_py27_4", datatracker_osx_py27_4_pw),
|
||||
BuildSlave("datatracker_lin_py27_5", datatracker_lin_py27_5_pw),
|
||||
BuildSlave("datatracker_lin_py27_6", datatracker_lin_py27_6_pw),
|
||||
#
|
||||
BuildSlave("datatracker_lin_py36_1", datatracker_lin_py36_1_pw),
|
||||
BuildSlave("datatracker_lin_py36_2", datatracker_lin_py36_2_pw),
|
||||
BuildSlave("datatracker_lin_py36_3", datatracker_lin_py36_3_pw),
|
||||
BuildSlave("datatracker_lin_py36_4", datatracker_lin_py36_4_pw),
|
||||
BuildSlave("datatracker_lin_py36_5", datatracker_lin_py36_5_pw),
|
||||
BuildSlave("datatracker_lin_py36_6", datatracker_lin_py36_6_pw),
|
||||
BuildSlave("dunkelfelder_lin_py36_1", dunkelfelder_lin_py36_1_pw),
|
||||
BuildSlave("dunkelfelder_lin_py36_2", dunkelfelder_lin_py36_2_pw),
|
||||
BuildSlave("dunkelfelder_lin_py36_3", dunkelfelder_lin_py36_3_pw),
|
||||
BuildSlave("dunkelfelder_lin_py36_4", dunkelfelder_lin_py36_4_pw),
|
||||
|
||||
BuildSlave("dornfelder_lin_py36_1", dornfelder_lin_py36_1_pw),
|
||||
BuildSlave("dornfelder_lin_py36_2", dornfelder_lin_py36_2_pw),
|
||||
BuildSlave("dornfelder_lin_py36_3", dornfelder_lin_py36_3_pw),
|
||||
BuildSlave("dornfelder_lin_py36_4", dornfelder_lin_py36_4_pw),
|
||||
]
|
||||
|
||||
# 'protocols' contains information about protocols which master will use for
|
||||
|
@ -93,7 +90,7 @@ c['schedulers'] = [
|
|||
# Periodic Schedulers
|
||||
Nightly(name="lin_test_old_libs", hour=16, minute=12, branch="trunk", builderNames=["Verify Minimum Libs"],),
|
||||
Nightly(name="lin_test_libs", hour=16, minute=42, branch="trunk", builderNames=["Verify Latest Libs"],),
|
||||
Nightly(name="crawler", hour=9, minute=00, branch="trunk", onlyIfChanged=True, builderNames=["Test-Crawler"],),
|
||||
Nightly(name="crawler", hour=23, minute=00, branch="trunk", onlyIfChanged=True, builderNames=["Test-Crawler"],),
|
||||
|
||||
# Force schedulers
|
||||
ForceScheduler(name="force_pyflakes", builderNames=["Check PyFlakes"]),
|
||||
|
@ -311,6 +308,7 @@ c['builders'] = []
|
|||
# -*- section Builder_Run_pyflakes -*-
|
||||
|
||||
factory = BuildFactory()
|
||||
factory.addStep(SetPropertiesFromEnv(variables=['HOME',]))
|
||||
factory.addStep(SVN(
|
||||
username='buildbot@tools.ietf.org',
|
||||
descriptionDone="svn update",
|
||||
|
@ -320,7 +318,13 @@ factory.addStep(SVN(
|
|||
repourl=Interpolate('https://svn.tools.ietf.org/svn/tools/ietfdb/%(src::branch:~trunk)s'),
|
||||
descriptionSuffix=[Interpolate('%(src::branch)s %(src::revision)s')],
|
||||
))
|
||||
factory.addStep(SetPropertiesFromEnv(variables=['HOME',]))
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="install requirements",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
haltOnFailure=True,
|
||||
usePTY=False,
|
||||
command=["pip", "install", "-r", "requirements.txt"],
|
||||
))
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="seting up settings_local.py",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
|
@ -338,21 +342,23 @@ factory.addStep(PyFlakes(
|
|||
factory.addStep(ShellCommand(
|
||||
descriptionDone="mark as passed",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
flunkOnFailure=False,
|
||||
usePTY=False,
|
||||
command=["svn", "--username=buildbot@tools.ietf.org", "--non-interactive",
|
||||
"propset", "--revprop", "-r", Property('got_revision'), "test:pyflakes", "passed" ],
|
||||
))
|
||||
|
||||
c['builders'].append(BuilderConfig(name="Check PyFlakes", factory=factory, category="1. trunk",
|
||||
slavenames=["datatracker_lin_py36_1", "datatracker_lin_py36_4", ]))
|
||||
slavenames=["dunkelfelder_lin_py36_1", "dornfelder_lin_py36_1", ]))
|
||||
c['builders'].append(BuilderConfig(name="[branch] Check PyFlakes", factory=factory, category="2. branch",
|
||||
slavenames=["datatracker_lin_py36_2", ]))
|
||||
slavenames=["dunkelfelder_lin_py36_2", "dornfelder_lin_py36_2", ]))
|
||||
c['builders'].append(BuilderConfig(name="[personal] Check PyFlakes", factory=factory, category="3. personal",
|
||||
slavenames=["datatracker_lin_py36_3", ]))
|
||||
slavenames=["dunkelfelder_lin_py36_2",]))
|
||||
|
||||
# -*- section Builder_TestSuite -*-
|
||||
|
||||
factory = BuildFactory()
|
||||
factory.addStep(SetPropertiesFromEnv(variables=['HOME',]))
|
||||
factory.addStep(SVN(
|
||||
username='buildbot@tools.ietf.org',
|
||||
descriptionDone="svn update",
|
||||
|
@ -362,7 +368,7 @@ factory.addStep(SVN(
|
|||
repourl=Interpolate('https://svn.tools.ietf.org/svn/tools/ietfdb/%(src::branch:~trunk)s'),
|
||||
descriptionSuffix=[Interpolate('%(src::branch)s %(src::revision)s')],
|
||||
))
|
||||
factory.addStep(RemovePYCs(workdir=Interpolate('build/%(src::branch)s')))
|
||||
factory.addStep(RemovePYCs(workdir=Interpolate('build/%(src::branch)s'), usePTY=False))
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="remove tmp-* dirs",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
|
@ -377,7 +383,6 @@ factory.addStep(ShellCommand(
|
|||
usePTY=False,
|
||||
command=["pip", "install", "-r", "requirements.txt"],
|
||||
))
|
||||
factory.addStep(SetPropertiesFromEnv(variables=['HOME',]))
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="copy settings_local.py",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
|
@ -403,22 +408,32 @@ factory.addStep(UnitTest(
|
|||
factory.addStep(ShellCommand(
|
||||
descriptionDone="mark as passed",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
flunkOnFailure=False,
|
||||
usePTY=False,
|
||||
command=["svn", "--username=buildbot@tools.ietf.org", "--non-interactive",
|
||||
"propset", "--revprop", "-r", Property('got_revision'), "test:unittest", "passed" ],
|
||||
))
|
||||
|
||||
c['builders'].append(BuilderConfig(name="Test Suite", factory=factory, category="1. trunk",
|
||||
slavenames=["datatracker_lin_py36_1", "datatracker_lin_py36_4", ]))
|
||||
slavenames=["dunkelfelder_lin_py36_1", "dornfelder_lin_py36_1", ]))
|
||||
c['builders'].append(BuilderConfig(name="[branch] Test Suite", factory=factory, category="2. branch",
|
||||
slavenames=["datatracker_lin_py36_2", ]))
|
||||
slavenames=["dunkelfelder_lin_py36_2", "dornfelder_lin_py36_2", ]))
|
||||
c['builders'].append(BuilderConfig(name="[personal] Test Suite", factory=factory, category="3. personal",
|
||||
slavenames=["datatracker_lin_py36_3", ]))
|
||||
slavenames=["dunkelfelder_lin_py36_2", "dornfelder_lin_py36_2", ]))
|
||||
|
||||
|
||||
# -*- section Builder_TestCrawler -*-
|
||||
|
||||
factory = BuildFactory()
|
||||
factory.addStep(SetPropertiesFromEnv(variables=['HOME',]))
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="update database",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
haltOnFailure=True,
|
||||
usePTY=False,
|
||||
timeout=3600, # 1 hour
|
||||
command=["docker/updatedb", "-q"],
|
||||
))
|
||||
factory.addStep(SVN(
|
||||
username='buildbot@tools.ietf.org',
|
||||
descriptionDone="svn update",
|
||||
|
@ -428,7 +443,7 @@ factory.addStep(SVN(
|
|||
repourl=Interpolate('https://svn.tools.ietf.org/svn/tools/ietfdb/%(src::branch:~trunk)s'),
|
||||
descriptionSuffix=[Interpolate('%(src::branch)s %(src::revision)s')],
|
||||
))
|
||||
factory.addStep(RemovePYCs(workdir=Interpolate('build/%(src::branch)s')))
|
||||
factory.addStep(RemovePYCs(workdir=Interpolate('build/%(src::branch)s'), usePTY=False))
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="install requirements",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
|
@ -436,7 +451,6 @@ factory.addStep(ShellCommand(
|
|||
usePTY=False,
|
||||
command=["pip", "install", "-r", "requirements.txt"],
|
||||
))
|
||||
factory.addStep(SetPropertiesFromEnv(variables=['HOME',]))
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="copy settings_local.py",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
|
@ -451,6 +465,14 @@ factory.addStep(ShellCommand(
|
|||
usePTY=False,
|
||||
command=["ietf/manage.py", "migrate"],
|
||||
))
|
||||
# This will not only do a prelimnary sanity check, but also patch libs as needed:
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="run django checks",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
haltOnFailure=True,
|
||||
usePTY=False,
|
||||
command=["ietf/manage.py", "check"],
|
||||
))
|
||||
factory.addStep(TestCrawlerShellCommand(
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
haltOnFailure=True,
|
||||
|
@ -461,13 +483,14 @@ factory.addStep(TestCrawlerShellCommand(
|
|||
factory.addStep(ShellCommand(
|
||||
descriptionDone="mark as passed",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
flunkOnFailure=False,
|
||||
usePTY=False,
|
||||
command=["svn", "--username=buildbot@tools.ietf.org", "--non-interactive",
|
||||
"propset", "--revprop", "-r", Property('got_revision'), "test:crawler", "passed" ],
|
||||
))
|
||||
|
||||
c['builders'].append(BuilderConfig(name="Test-Crawler", factory=factory, category="1. trunk",
|
||||
slavenames=["datatracker_lin_py36_6", ]))
|
||||
slavenames=["dunkelfelder_lin_py36_4", ]))
|
||||
|
||||
|
||||
# -*- section Builder_Verify_Old_Libs -*-
|
||||
|
@ -479,6 +502,7 @@ c['builders'].append(BuilderConfig(name="Test-Crawler", factory=factory, categor
|
|||
# dependencies.
|
||||
|
||||
factory = BuildFactory()
|
||||
factory.addStep(SetPropertiesFromEnv(variables=['HOME',]))
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="remove tweaked requirements",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
|
@ -497,7 +521,7 @@ factory.addStep(SVN(
|
|||
repourl=Interpolate('https://svn.tools.ietf.org/svn/tools/ietfdb/%(src::branch:~trunk)s'),
|
||||
descriptionSuffix=[Interpolate('%(src::branch)s %(src::revision)s')],
|
||||
))
|
||||
factory.addStep(RemovePYCs(workdir=Interpolate('build/%(src::branch)s')))
|
||||
factory.addStep(RemovePYCs(workdir=Interpolate('build/%(src::branch)s'), usePTY=False))
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="edit requirements",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
|
@ -512,7 +536,6 @@ factory.addStep(ShellCommand(
|
|||
usePTY=False,
|
||||
command=["pip", "install", "--upgrade", "-r", "requirements.txt"],
|
||||
))
|
||||
factory.addStep(SetPropertiesFromEnv(variables=['HOME',]))
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="seting up settings_local.py",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
|
@ -542,10 +565,10 @@ factory.addStep(UnitTest(
|
|||
command=["ietf/manage.py", "test", "--settings=settings_sqlitetest", "--verbosity=2", ],
|
||||
))
|
||||
c['builders'].append(BuilderConfig(name="Verify Minimum Libs", factory=factory, category="1. trunk",
|
||||
slavenames=["datatracker_lin_py36_5", ]))
|
||||
slavenames=["dornfelder_lin_py36_3", ]))
|
||||
|
||||
|
||||
# -*- section Builder_Dependencies -*-
|
||||
# -*- section Verify_Latest_Libs -*-
|
||||
|
||||
# This build runs pip install --upgrade, to make sure that we install the latest version of all
|
||||
# dependencies, in order to get an indication if/when an incompatibility turns up with a new
|
||||
|
@ -554,6 +577,7 @@ c['builders'].append(BuilderConfig(name="Verify Minimum Libs", factory=factory,
|
|||
# dependencies.
|
||||
|
||||
factory = BuildFactory()
|
||||
factory.addStep(SetPropertiesFromEnv(variables=['HOME',]))
|
||||
factory.addStep(SVN(
|
||||
username='buildbot@tools.ietf.org',
|
||||
descriptionDone="svn update",
|
||||
|
@ -564,7 +588,7 @@ factory.addStep(SVN(
|
|||
repourl=Interpolate('https://svn.tools.ietf.org/svn/tools/ietfdb/%(src::branch:~trunk)s'),
|
||||
descriptionSuffix=[Interpolate('%(src::branch)s %(src::revision)s')],
|
||||
))
|
||||
factory.addStep(RemovePYCs(workdir=Interpolate('build/%(src::branch)s')))
|
||||
factory.addStep(RemovePYCs(workdir=Interpolate('build/%(src::branch)s'), usePTY=False))
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="install/upgrade requirements",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
|
@ -572,7 +596,6 @@ factory.addStep(ShellCommand(
|
|||
usePTY=False,
|
||||
command=["pip", "install", "--upgrade", "-r", "requirements.txt"],
|
||||
))
|
||||
factory.addStep(SetPropertiesFromEnv(variables=['HOME',]))
|
||||
factory.addStep(ShellCommand(
|
||||
descriptionDone="seting up settings_local.py",
|
||||
workdir=Interpolate('build/%(src::branch)s'),
|
||||
|
@ -603,7 +626,7 @@ factory.addStep(UnitTest(
|
|||
))
|
||||
|
||||
c['builders'].append(BuilderConfig(name="Verify Latest Libs", factory=factory, category="1. trunk",
|
||||
slavenames=["datatracker_lin_py36_5", ]))
|
||||
slavenames=["dornfelder_lin_py36_3", ]))
|
||||
|
||||
|
||||
####### STATUS TARGETS
|
||||
|
@ -673,7 +696,7 @@ c['status'].append(mail.MailNotifier(
|
|||
# installation's html.WebStatus home page (linked to the
|
||||
# 'titleURL') and is embedded in the title of the waterfall HTML page.
|
||||
|
||||
c['title'] = "IETF Datatracker"
|
||||
c['title'] = "Buildbot: IETF Datatracker"
|
||||
c['titleURL'] = "https://datatracker.ietf.org/"
|
||||
|
||||
# the 'buildbotURL' string should point to the location where the buildbot's
|
||||
|
|
|
@ -158,7 +158,7 @@ class DocumentInfo(models.Model):
|
|||
else:
|
||||
self._cached_base_name = "%s-%s.txt" % (self.name, self.rev)
|
||||
elif self.type_id in ["slides", "agenda", "minutes", "bluesheets", ] and self.meeting_related():
|
||||
self._cached_base_name = "%s-%s.txt" % self.canonical_name()
|
||||
self._cached_base_name = "%s-%s.txt" % (self.canonical_name(), self.rev)
|
||||
elif self.type_id == 'review':
|
||||
# TODO: This will be wrong if a review is updated on the same day it was created (or updated more than once on the same day)
|
||||
self._cached_base_name = "%s.txt" % self.name
|
||||
|
|
|
@ -256,7 +256,9 @@ def document_main(request, name, rev=None):
|
|||
|
||||
if "pdf" not in found_types:
|
||||
file_urls.append(("pdf", settings.TOOLS_ID_PDF_URL + doc.name + "-" + doc.rev + ".pdf"))
|
||||
file_urls.append(("htmlized", settings.TOOLS_ID_HTML_URL + doc.name + "-" + doc.rev))
|
||||
#file_urls.append(("htmlized", settings.TOOLS_ID_HTML_URL + doc.name + "-" + doc.rev))
|
||||
file_urls.append(("htmlized (tools)", settings.TOOLS_ID_HTML_URL + doc.name + "-" + doc.rev))
|
||||
file_urls.append(("htmlized", urlreverse('ietf.doc.views_doc.document_html', kwargs=dict(name=doc.name, rev=doc.rev))))
|
||||
|
||||
# latest revision
|
||||
latest_revision = doc.latest_event(NewRevisionDocEvent, type="new_revision")
|
||||
|
@ -683,7 +685,7 @@ def document_html(request, name, rev=None):
|
|||
|
||||
doc = docs.get()
|
||||
if not os.path.exists(doc.get_file_name()):
|
||||
raise Http404("Document not found: %s" % doc.get_base_name())
|
||||
raise Http404("File not found: %s" % doc.get_file_name())
|
||||
|
||||
top = render_document_top(request, doc, "status", name)
|
||||
if not rev and not name.startswith('rfc'):
|
||||
|
|
|
@ -18,6 +18,15 @@ class GroupFactory(factory.DjangoModelFactory):
|
|||
list_email = factory.LazyAttribute(lambda a: '%s@ietf.org'% a.acronym)
|
||||
uses_milestone_dates = True
|
||||
|
||||
@factory.lazy_attribute
|
||||
def parent(self):
|
||||
if self.type_id in ['wg','ag']:
|
||||
return GroupFactory(type_id='area')
|
||||
elif self.type_id in ['rg']:
|
||||
return GroupFactory(acronym='irtf', type_id='irtf')
|
||||
else:
|
||||
return None
|
||||
|
||||
class ReviewTeamFactory(GroupFactory):
|
||||
|
||||
type_id = 'review'
|
||||
|
|
26
ietf/group/migrations/0024_add_groupman_authroles.py
Normal file
26
ietf/group/migrations/0024_add_groupman_authroles.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.29 on 2020-05-04 13:10
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
import jsonfield.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0023_use_milestone_dates_default_to_true'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='groupfeatures',
|
||||
name='groupman_authroles',
|
||||
field=jsonfield.fields.JSONField(default=['Secretariat'], max_length=128),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='historicalgroupfeatures',
|
||||
name='groupman_authroles',
|
||||
field=jsonfield.fields.JSONField(default=['Secretariat'], max_length=128),
|
||||
),
|
||||
]
|
47
ietf/group/migrations/0025_populate_groupman_authroles.py
Normal file
47
ietf/group/migrations/0025_populate_groupman_authroles.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.29 on 2020-05-01 12:54
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
authroles_map = {
|
||||
'adhoc': ['Secretariat'],
|
||||
'admin': ['Secretariat'],
|
||||
'ag': ['Secretariat', 'Area Director'],
|
||||
'area': ['Secretariat'],
|
||||
'dir': ['Secretariat'],
|
||||
'iab': ['Secretariat'],
|
||||
'iana': ['Secretariat'],
|
||||
'iesg': ['Secretariat'],
|
||||
'ietf': ['Secretariat'],
|
||||
'individ': [],
|
||||
'irtf': ['Secretariat'],
|
||||
'ise': ['Secretariat'],
|
||||
'isoc': ['Secretariat'],
|
||||
'nomcom': ['Secretariat'],
|
||||
'program': ['Secretariat', 'IAB'],
|
||||
'review': ['Secretariat'],
|
||||
'rfcedtyp': ['Secretariat'],
|
||||
'rg': ['Secretariat', 'IRTF Chair'],
|
||||
'sdo': ['Secretariat'],
|
||||
'team': ['Secretariat'],
|
||||
'wg': ['Secretariat', 'Area Director'],
|
||||
}
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
GroupFeatures = apps.get_model('group', 'GroupFeatures')
|
||||
for type_id, authroles in authroles_map.items():
|
||||
GroupFeatures.objects.filter(type_id=type_id).update(groupman_authroles=authroles)
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
pass
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0024_add_groupman_authroles'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward, reverse),
|
||||
]
|
36
ietf/group/migrations/0026_programs_meet.py
Normal file
36
ietf/group/migrations/0026_programs_meet.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.29 on 2020-05-01 12:54
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
GroupFeatures = apps.get_model('group', 'GroupFeatures')
|
||||
program = GroupFeatures.objects.get(type_id='program')
|
||||
program.has_meetings = True
|
||||
program.matman_roles = ['lead', 'chair', 'secr']
|
||||
program.docman_roles = ['lead', 'chair', 'secr']
|
||||
program.groupman_roles = ['lead', 'chair', 'secr']
|
||||
program.role_order = ['lead', 'chair', 'secr']
|
||||
program.save()
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
GroupFeatures = apps.get_model('group', 'GroupFeatures')
|
||||
program = GroupFeatures.objects.get(type_id='program')
|
||||
program.has_meetings = False
|
||||
program.matman_roles = ['lead', 'secr']
|
||||
program.docman_roles = ['lead', 'secr']
|
||||
program.groupman_roles = ['lead', 'secr']
|
||||
program.role_order = ['lead', 'secr']
|
||||
program.save()
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0025_populate_groupman_authroles'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward, reverse),
|
||||
]
|
23
ietf/group/migrations/0027_programs_have_parents.py
Normal file
23
ietf/group/migrations/0027_programs_have_parents.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.29 on 2020-05-08 09:02
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
Group = apps.get_model('group','Group')
|
||||
iab = Group.objects.get(acronym='iab')
|
||||
Group.objects.filter(type_id='program').update(parent=iab)
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
pass # No point in removing the parents
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0026_programs_meet'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward, reverse),
|
||||
]
|
|
@ -65,9 +65,6 @@ class GroupInfo(models.Model):
|
|||
kwargs["group_type"] = self.type_id
|
||||
return urlreverse(self.features.about_page, kwargs=kwargs)
|
||||
|
||||
def interim_approval_roles(self):
|
||||
return list(set([ role for role in self.parent.role_set.filter(name__in=['ad', 'chair']) ]))
|
||||
|
||||
def is_bof(self):
|
||||
return self.state_id in ["bof", "bof-conc"]
|
||||
|
||||
|
@ -238,6 +235,7 @@ class GroupFeatures(models.Model):
|
|||
admin_roles = jsonfield.JSONField(max_length=64, blank=False, default=["chair"]) # Trac Admin
|
||||
docman_roles = jsonfield.JSONField(max_length=128, blank=False, default=["ad","chair","delegate","secr"])
|
||||
groupman_roles = jsonfield.JSONField(max_length=128, blank=False, default=["ad","chair",])
|
||||
groupman_authroles = jsonfield.JSONField(max_length=128, blank=False, default=["Secretariat",])
|
||||
matman_roles = jsonfield.JSONField(max_length=128, blank=False, default=["ad","chair","delegate","secr"])
|
||||
role_order = jsonfield.JSONField(max_length=128, blank=False, default=["chair","secr","member"],
|
||||
help_text="The order in which roles are shown, for instance on photo pages. Enter valid JSON.")
|
||||
|
|
|
@ -264,7 +264,7 @@ class GroupPagesTests(TestCase):
|
|||
can_edit = {
|
||||
'wg' : ['secretary','ad'],
|
||||
'rg' : ['secretary','irtf-chair'],
|
||||
'ag' : ['secretary', ],
|
||||
'ag' : ['secretary', 'ad' ],
|
||||
'team' : ['secretary',], # The code currently doesn't let ads edit teams or directorates. Maybe it should.
|
||||
'dir' : ['secretary',],
|
||||
'review' : ['secretary',],
|
||||
|
|
|
@ -15,7 +15,7 @@ import debug # pyflakes:ignore
|
|||
from ietf.community.models import CommunityList, SearchRule
|
||||
from ietf.community.utils import reset_name_contains_index_for_rule, can_manage_community_list
|
||||
from ietf.doc.models import Document, State
|
||||
from ietf.group.models import Group, RoleHistory, Role
|
||||
from ietf.group.models import Group, RoleHistory, Role, GroupFeatures
|
||||
from ietf.ietfauth.utils import has_role
|
||||
from ietf.name.models import GroupTypeName
|
||||
from ietf.person.models import Email
|
||||
|
@ -105,6 +105,7 @@ def save_milestone_in_history(milestone):
|
|||
|
||||
return h
|
||||
|
||||
# TODO: rework this using features.groupman_authroles
|
||||
def can_manage_group_type(user, group, type_id=None):
|
||||
if not user.is_authenticated:
|
||||
return False
|
||||
|
@ -125,8 +126,11 @@ def can_manage_group_type(user, group, type_id=None):
|
|||
return has_role(user, ('Secretariat'))
|
||||
|
||||
def can_manage_group(user, group):
|
||||
if can_manage_group_type(user, group):
|
||||
return True
|
||||
if not user.is_authenticated:
|
||||
return False
|
||||
for authrole in group.features.groupman_authroles:
|
||||
if has_role(user, authrole):
|
||||
return True
|
||||
return group.has_role(user, group.features.groupman_roles)
|
||||
|
||||
def milestone_reviewer_for_group_type(group_type):
|
||||
|
@ -141,6 +145,18 @@ def can_manage_materials(user, group):
|
|||
def can_manage_session_materials(user, group, session):
|
||||
return has_role(user, 'Secretariat') or (group.has_role(user, group.features.matman_roles) and not session.is_material_submission_cutoff())
|
||||
|
||||
# Maybe this should be cached...
|
||||
def can_manage_some_groups(user):
|
||||
if not user.is_authenticated:
|
||||
return False
|
||||
for gf in GroupFeatures.objects.all():
|
||||
for authrole in gf.groupman_authroles:
|
||||
if has_role(user, authrole):
|
||||
return True
|
||||
if Role.objects.filter(name__in=gf.groupman_roles, group__type_id=gf.type_id, person__user=user).exists():
|
||||
return True
|
||||
return False
|
||||
|
||||
def can_provide_status_update(user, group):
|
||||
if not group.features.acts_like_wg:
|
||||
return False
|
||||
|
|
|
@ -70,6 +70,9 @@ def has_role(user, role_names, *args, **kwargs):
|
|||
"RG Secretary": Q(person=person,name="secr", group__type="rg", group__state__in=["active","proposed"]),
|
||||
"AG Secretary": Q(person=person,name="secr", group__type="ag", group__state__in=["active"]),
|
||||
"Team Chair": Q(person=person,name="chair", group__type="team", group__state="active"),
|
||||
"Program Lead": Q(person=person,name="lead", group__type="program", group__state="active"),
|
||||
"Program Secretary": Q(person=person,name="secr", group__type="program", group__state="active"),
|
||||
"Program Chair": Q(person=person,name="chair", group__type="program", group__state="active"),
|
||||
"Nomcom Chair": Q(person=person, name="chair", group__type="nomcom", group__acronym__icontains=kwargs.get('year', '0000')),
|
||||
"Nomcom Advisor": Q(person=person, name="advisor", group__type="nomcom", group__acronym__icontains=kwargs.get('year', '0000')),
|
||||
"Nomcom": Q(person=person, group__type="nomcom", group__acronym__icontains=kwargs.get('year', '0000')),
|
||||
|
|
|
@ -166,6 +166,8 @@ class Recipient(models.Model):
|
|||
addrs.extend(group.role_set.filter(name='ad').values_list('email__address',flat=True))
|
||||
if group.type_id=='rg':
|
||||
addrs.extend(Recipient.objects.get(slug='stream_managers').gather(**{'streams':['irtf']}))
|
||||
elif group.type_id=='program':
|
||||
addrs.extend(Recipient.objects.get(slug='iab').gather(**{}))
|
||||
return addrs
|
||||
|
||||
def gather_group_secretaries(self, **kwargs):
|
||||
|
|
|
@ -15,7 +15,7 @@ from django.forms import BaseInlineFormSet
|
|||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.models import Document, DocAlias, State, NewRevisionDocEvent
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.models import Group, GroupFeatures
|
||||
from ietf.ietfauth.utils import has_role
|
||||
from ietf.meeting.models import Session, Meeting, Schedule, countries, timezones
|
||||
from ietf.meeting.helpers import get_next_interim_number, make_materials_directories
|
||||
|
@ -100,8 +100,7 @@ class InterimSessionInlineFormSet(BaseInlineFormSet):
|
|||
return # formset doesn't have cleaned_data
|
||||
|
||||
class InterimMeetingModelForm(forms.ModelForm):
|
||||
# TODO: Should area groups get to schedule Interims?
|
||||
group = GroupModelChoiceField(queryset=Group.objects.filter(type__in=('wg', 'rg', 'ag'), state__in=('active', 'proposed', 'bof')).order_by('acronym'), required=False)
|
||||
group = GroupModelChoiceField(queryset=Group.objects.filter(type_id__in=GroupFeatures.objects.filter(has_meetings=True).values_list('type_id',flat=True), state__in=('active', 'proposed', 'bof')).order_by('acronym'), required=False)
|
||||
in_person = forms.BooleanField(required=False)
|
||||
meeting_type = forms.ChoiceField(choices=(
|
||||
("single", "Single"),
|
||||
|
@ -156,13 +155,15 @@ class InterimMeetingModelForm(forms.ModelForm):
|
|||
return # don't reduce group options
|
||||
q_objects = Q()
|
||||
if has_role(self.user, "Area Director"):
|
||||
q_objects.add(Q(type="wg", state__in=("active", "proposed", "bof")), Q.OR)
|
||||
q_objects.add(Q(type__in=["wg", "ag"], state__in=("active", "proposed", "bof")), Q.OR)
|
||||
if has_role(self.user, "IRTF Chair"):
|
||||
q_objects.add(Q(type="rg", state__in=("active", "proposed")), Q.OR)
|
||||
if has_role(self.user, "WG Chair"):
|
||||
q_objects.add(Q(type="wg", state__in=("active", "proposed", "bof"), role__person=self.person, role__name="chair"), Q.OR)
|
||||
if has_role(self.user, "RG Chair"):
|
||||
q_objects.add(Q(type="rg", state__in=("active", "proposed"), role__person=self.person, role__name="chair"), Q.OR)
|
||||
if has_role(self.user, "Program Lead") or has_role(self.user, "Program Chair"):
|
||||
q_objects.add(Q(type="program", state__in=("active", "proposed"), role__person=self.person, role__name__in=["chair", "lead"]), Q.OR)
|
||||
|
||||
queryset = Group.objects.filter(q_objects).distinct().order_by('acronym')
|
||||
self.fields['group'].queryset = queryset
|
||||
|
|
|
@ -21,6 +21,7 @@ import debug # pyflakes:ignore
|
|||
|
||||
from ietf.doc.models import Document
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.utils import can_manage_some_groups, can_manage_group
|
||||
from ietf.ietfauth.utils import has_role, user_is_person
|
||||
from ietf.liaisons.utils import get_person_for_user
|
||||
from ietf.mailtrigger.utils import gather_address_lists
|
||||
|
@ -324,11 +325,14 @@ def can_approve_interim_request(meeting, user):
|
|||
if not session:
|
||||
return False
|
||||
group = session.group
|
||||
if group.type.slug == 'wg':
|
||||
if group.type.slug in ['wg','ag']:
|
||||
if group.parent.role_set.filter(name='ad', person=person) or group.role_set.filter(name='ad', person=person):
|
||||
return True
|
||||
if group.type.slug == 'rg' and group.parent.role_set.filter(name='chair', person=person):
|
||||
return True
|
||||
if group.type.slug == 'program':
|
||||
if person.role_set.filter(group__acronym='iab', name='member'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
@ -336,14 +340,13 @@ def can_edit_interim_request(meeting, user):
|
|||
'''Returns True if the user can edit the interim meeting request'''
|
||||
if meeting.type.slug != 'interim':
|
||||
return False
|
||||
if has_role(user, 'Secretariat'):
|
||||
if has_role(user, 'Secretariat'): # Consider removing - can_manage_group should handle this
|
||||
return True
|
||||
person = get_person_for_user(user)
|
||||
session = meeting.session_set.first()
|
||||
if not session:
|
||||
return False
|
||||
group = session.group
|
||||
if group.role_set.filter(name='chair', person=person):
|
||||
if can_manage_group(user, group):
|
||||
return True
|
||||
elif can_approve_interim_request(meeting, user):
|
||||
return True
|
||||
|
@ -352,29 +355,17 @@ def can_edit_interim_request(meeting, user):
|
|||
|
||||
|
||||
def can_request_interim_meeting(user):
|
||||
if has_role(user, ('Secretariat', 'Area Director', 'WG Chair', 'IRTF Chair', 'RG Chair')):
|
||||
return True
|
||||
return False
|
||||
|
||||
return can_manage_some_groups(user)
|
||||
|
||||
def can_view_interim_request(meeting, user):
|
||||
'''Returns True if the user can see the pending interim request in the pending interim view'''
|
||||
if meeting.type.slug != 'interim':
|
||||
return False
|
||||
if has_role(user, 'Secretariat'):
|
||||
return True
|
||||
person = get_person_for_user(user)
|
||||
session = meeting.session_set.first()
|
||||
if not session:
|
||||
return False
|
||||
group = session.group
|
||||
if has_role(user, 'Area Director') and group.type.slug == 'wg':
|
||||
return True
|
||||
if has_role(user, 'IRTF Chair') and group.type.slug == 'rg':
|
||||
return True
|
||||
if group.role_set.filter(name='chair', person=person):
|
||||
return True
|
||||
return False
|
||||
return can_manage_group(user, group)
|
||||
|
||||
|
||||
def create_interim_meeting(group, date, city='', country='', timezone='UTC',
|
||||
|
@ -512,11 +503,17 @@ def send_interim_approval_request(meetings):
|
|||
else:
|
||||
is_series = False
|
||||
approver_set = set()
|
||||
for role in group.interim_approval_roles():
|
||||
approver = "%s of the %s" % ( role.name.name, role.group.name)
|
||||
approver_set.add(approver)
|
||||
for authrole in group.features.groupman_authroles: # NOTE: This makes an assumption that the authroles are exactly the set of approvers
|
||||
approver_set.add(authrole)
|
||||
approvers = list(approver_set)
|
||||
context = locals() # TODO Unnecessarily complex, context needs to only contain what the template needs
|
||||
context = {
|
||||
'group': group,
|
||||
'is_series': is_series,
|
||||
'meetings': meetings,
|
||||
'approvers': approvers,
|
||||
'requester': requester,
|
||||
'approval_urls': approval_urls,
|
||||
}
|
||||
send_mail(None,
|
||||
to_email,
|
||||
from_email,
|
||||
|
|
|
@ -793,7 +793,7 @@ class SchedTimeSessAssignment(models.Model):
|
|||
if not self.timeslot:
|
||||
components.append("unknown")
|
||||
|
||||
if not self.session or not (getattr(self.session, "historic_group") or self.session.group):
|
||||
if not self.session or not (getattr(self.session, "historic_group", None) or self.session.group):
|
||||
components.append("unknown")
|
||||
else:
|
||||
components.append(self.timeslot.time.strftime("%Y-%m-%d-%a-%H%M"))
|
||||
|
|
|
@ -26,7 +26,8 @@ from django.db.models import F
|
|||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.models import Document
|
||||
from ietf.group.models import Group, Role
|
||||
from ietf.group.models import Group, Role, GroupFeatures
|
||||
from ietf.group.utils import can_manage_group
|
||||
from ietf.person.models import Person
|
||||
from ietf.meeting.helpers import can_approve_interim_request, can_view_interim_request
|
||||
from ietf.meeting.helpers import send_interim_approval_request
|
||||
|
@ -37,7 +38,7 @@ from ietf.meeting.test_data import make_meeting_test_data, make_interim_meeting
|
|||
from ietf.meeting.utils import finalize, condition_slide_order
|
||||
from ietf.meeting.utils import add_event_info_to_session_qs
|
||||
from ietf.meeting.views import session_draft_list
|
||||
from ietf.name.models import SessionStatusName, ImportantDateName
|
||||
from ietf.name.models import SessionStatusName, ImportantDateName, RoleName
|
||||
from ietf.utils.decorators import skip_coverage
|
||||
from ietf.utils.mail import outbox, empty_outbox, get_payload
|
||||
from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent
|
||||
|
@ -1242,6 +1243,12 @@ class SessionDetailsTests(TestCase):
|
|||
self.assertTrue(all([x in unicontent(r) for x in ('slides','agenda','minutes','draft')]))
|
||||
self.assertNotContains(r, 'deleted')
|
||||
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(q('h2#session_%s div#session-buttons-%s' % (session.id, session.id)),
|
||||
'Session detail page does not contain session tool buttons')
|
||||
self.assertFalse(q('h2#session_%s div#session-buttons-%s span.fa-arrows-alt' % (session.id, session.id)),
|
||||
'The session detail page is incorrectly showing the "Show meeting materials" button')
|
||||
|
||||
def test_session_details_past_interim(self):
|
||||
group = GroupFactory.create(type_id='wg',state_id='active')
|
||||
chair = RoleFactory(name_id='chair',group=group)
|
||||
|
@ -1491,8 +1498,7 @@ class InterimTests(TestCase):
|
|||
self.assertContains(r, 'IETF 72')
|
||||
# cancelled session
|
||||
q = PyQuery(r.content)
|
||||
# self.assertIn('CANCELLED', q('[id*="-ames"]').text())
|
||||
self.assertIn('CANCELLED', q('tr>td>a>span').text())
|
||||
self.assertIn('CANCELLED', q('tr>td.text-right>span').text())
|
||||
self.check_interim_tabs(url)
|
||||
|
||||
def test_upcoming_ical(self):
|
||||
|
@ -1555,7 +1561,8 @@ class InterimTests(TestCase):
|
|||
r = self.client.get("/meeting/interim/request/")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(Group.objects.filter(type__in=('wg', 'rg', 'ag'), state__in=('active', 'proposed')).count(),
|
||||
Group.objects.filter(type_id__in=GroupFeatures.objects.filter(has_meetings=True).values_list('type_id',flat=True), state__in=('active', 'proposed', 'bof'))
|
||||
self.assertEqual(Group.objects.filter(type_id__in=GroupFeatures.objects.filter(has_meetings=True).values_list('type_id',flat=True), state__in=('active', 'proposed', 'bof')).count(),
|
||||
len(q("#id_group option")) - 1) # -1 for options placeholder
|
||||
self.client.logout()
|
||||
|
||||
|
@ -1939,6 +1946,28 @@ class InterimTests(TestCase):
|
|||
user = User.objects.get(username='ameschairman')
|
||||
self.assertFalse(can_view_interim_request(meeting=meeting,user=user))
|
||||
|
||||
def test_can_manage_group(self):
|
||||
make_meeting_test_data()
|
||||
# unprivileged user
|
||||
user = User.objects.get(username='plain')
|
||||
group = Group.objects.get(acronym='mars')
|
||||
self.assertFalse(can_manage_group(user=user,group=group))
|
||||
# Secretariat
|
||||
user = User.objects.get(username='secretary')
|
||||
self.assertTrue(can_manage_group(user=user,group=group))
|
||||
# related AD
|
||||
user = User.objects.get(username='ad')
|
||||
self.assertTrue(can_manage_group(user=user,group=group))
|
||||
# other AD
|
||||
user = User.objects.get(username='ops-ad')
|
||||
self.assertTrue(can_manage_group(user=user,group=group))
|
||||
# WG Chair
|
||||
user = User.objects.get(username='marschairman')
|
||||
self.assertTrue(can_manage_group(user=user,group=group))
|
||||
# Other WG Chair
|
||||
user = User.objects.get(username='ameschairman')
|
||||
self.assertFalse(can_manage_group(user=user,group=group))
|
||||
|
||||
def test_interim_request_details(self):
|
||||
make_meeting_test_data()
|
||||
meeting = add_event_info_to_session_qs(Session.objects.filter(meeting__type='interim', group__acronym='mars')).filter(current_status='apprw').first().meeting
|
||||
|
@ -1983,13 +2012,6 @@ class InterimTests(TestCase):
|
|||
make_meeting_test_data()
|
||||
meeting = add_event_info_to_session_qs(Session.objects.filter(meeting__type='interim', group__acronym='mars')).filter(current_status='apprw').first().meeting
|
||||
url = urlreverse('ietf.meeting.views.interim_request_details', kwargs={'number': meeting.number})
|
||||
# ensure no cancel button for unauthorized user
|
||||
self.client.login(username="ameschairman", password="ameschairman+password")
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q("a.btn:contains('Cancel')")), 0)
|
||||
# ensure cancel button for authorized user
|
||||
self.client.login(username="marschairman", password="marschairman+password")
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
@ -2793,3 +2815,175 @@ class SessionTests(TestCase):
|
|||
})
|
||||
self.assertEqual(r.status_code,302)
|
||||
self.assertEqual(len(outbox),1)
|
||||
|
||||
class HasMeetingsTests(TestCase):
|
||||
def setUp(self):
|
||||
self.materials_dir = self.tempdir('materials')
|
||||
#
|
||||
self.saved_agenda_path = settings.AGENDA_PATH
|
||||
#
|
||||
settings.AGENDA_PATH = self.materials_dir
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.materials_dir)
|
||||
#
|
||||
settings.AGENDA_PATH = self.saved_agenda_path
|
||||
|
||||
def do_request_interim(self, url, group, user, meeting_count):
|
||||
login_testing_unauthorized(self,user.username, url)
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(q('#id_group option[value="%d"]'%group.pk))
|
||||
date = datetime.date.today() + datetime.timedelta(days=30+meeting_count)
|
||||
time = datetime.datetime.now().time().replace(microsecond=0,second=0)
|
||||
remote_instructions = 'Use webex'
|
||||
agenda = 'Intro. Slides. Discuss.'
|
||||
agenda_note = 'On second level'
|
||||
meeting_count = Meeting.objects.filter(number__contains='-%s-'%group.acronym, date__year=date.year).count()
|
||||
next_num = "%02d" % (meeting_count+1)
|
||||
data = {'group':group.pk,
|
||||
'meeting_type':'single',
|
||||
'city':'',
|
||||
'country':'',
|
||||
'time_zone':'UTC',
|
||||
'session_set-0-date':date.strftime("%Y-%m-%d"),
|
||||
'session_set-0-time':time.strftime('%H:%M'),
|
||||
'session_set-0-requested_duration':'03:00:00',
|
||||
'session_set-0-remote_instructions':remote_instructions,
|
||||
'session_set-0-agenda':agenda,
|
||||
'session_set-0-agenda_note':agenda_note,
|
||||
'session_set-TOTAL_FORMS':1,
|
||||
'session_set-INITIAL_FORMS':0,
|
||||
'session_set-MIN_NUM_FORMS':0,
|
||||
'session_set-MAX_NUM_FORMS':1000}
|
||||
|
||||
r = self.client.post(urlreverse("ietf.meeting.views.interim_request"),data)
|
||||
self.assertRedirects(r,urlreverse('ietf.meeting.views.upcoming'))
|
||||
meeting = Meeting.objects.order_by('id').last()
|
||||
self.assertEqual(meeting.type_id,'interim')
|
||||
self.assertEqual(meeting.date,date)
|
||||
self.assertEqual(meeting.number,'interim-%s-%s-%s' % (date.year, group.acronym, next_num))
|
||||
self.client.logout()
|
||||
|
||||
|
||||
def create_role_for_authrole(self, authrole):
|
||||
role = None
|
||||
if authrole == 'Secretariat':
|
||||
role = RoleFactory.create(group__acronym='secretariat',name_id='secr')
|
||||
elif authrole == 'Area Director':
|
||||
role = RoleFactory.create(name_id='ad', group__type_id='area')
|
||||
elif authrole == 'IAB':
|
||||
role = RoleFactory.create(name_id='member', group__acronym='iab')
|
||||
elif authrole == 'IRTF Chair':
|
||||
role = RoleFactory.create(name_id='chair', group__acronym='irtf')
|
||||
if role is None:
|
||||
self.assertIsNone("Can't test authrole:"+authrole)
|
||||
self.assertNotEqual(role, None)
|
||||
return role
|
||||
|
||||
|
||||
def test_can_request_interim(self):
|
||||
|
||||
url = urlreverse('ietf.meeting.views.interim_request')
|
||||
for gf in GroupFeatures.objects.filter(has_meetings=True):
|
||||
meeting_count = 0
|
||||
for role in gf.groupman_roles:
|
||||
role = RoleFactory(group__type_id=gf.type_id, name_id=role)
|
||||
self.do_request_interim(url, role.group, role.person.user, meeting_count)
|
||||
for authrole in gf.groupman_authroles:
|
||||
group = GroupFactory(type_id=gf.type_id)
|
||||
role = self.create_role_for_authrole(authrole)
|
||||
self.do_request_interim(url, group, role.person.user, 0)
|
||||
|
||||
|
||||
def test_cannot_request_interim(self):
|
||||
|
||||
url = urlreverse('ietf.meeting.views.interim_request')
|
||||
|
||||
self.client.login(username='secretary', password='secretary+password')
|
||||
nomeetings = []
|
||||
for gf in GroupFeatures.objects.exclude(has_meetings=True):
|
||||
nomeetings.append(GroupFactory(type_id=gf.type_id))
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
for group in nomeetings:
|
||||
self.assertFalse(q('#id_group option[value="%d"]'%group.pk))
|
||||
self.client.logout()
|
||||
|
||||
all_role_names = set(RoleName.objects.values_list('slug',flat=True))
|
||||
for gf in GroupFeatures.objects.filter(has_meetings=True):
|
||||
for role_name in all_role_names - set(gf.groupman_roles):
|
||||
role = RoleFactory(group__type_id=gf.type_id,name_id=role_name)
|
||||
self.client.login(username=role.person.user.username, password=role.person.user.username+'+password')
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 403)
|
||||
self.client.logout()
|
||||
|
||||
def test_appears_on_upcoming(self):
|
||||
url = urlreverse('ietf.meeting.views.upcoming')
|
||||
for gf in GroupFeatures.objects.filter(has_meetings=True):
|
||||
session = SessionFactory(
|
||||
group__type_id = gf.type_id,
|
||||
meeting__type_id='interim',
|
||||
meeting__date = datetime.datetime.today()+datetime.timedelta(days=30),
|
||||
status_id='sched',
|
||||
)
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertIn(session.meeting.number, q('.interim-meeting-link').text())
|
||||
|
||||
|
||||
def test_appears_on_pending(self):
|
||||
url = urlreverse('ietf.meeting.views.interim_pending')
|
||||
for gf in GroupFeatures.objects.filter(has_meetings=True):
|
||||
group = GroupFactory(type_id=gf.type_id)
|
||||
meeting_date = datetime.datetime.today() + datetime.timedelta(days=30)
|
||||
session = SessionFactory(
|
||||
group=group,
|
||||
meeting__type_id='interim',
|
||||
meeting__date = meeting_date,
|
||||
meeting__number = 'interim-%d-%s-00'%(meeting_date.year,group.acronym),
|
||||
status_id='apprw',
|
||||
)
|
||||
for role_name in gf.groupman_roles:
|
||||
role = RoleFactory(group=group, name_id=role_name)
|
||||
self.client.login(username=role.person.user.username, password=role.person.user.username+'+password')
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertIn(session.meeting.number, q('.interim-meeting-link').text())
|
||||
self.client.logout()
|
||||
for authrole in gf.groupman_authroles:
|
||||
role = self.create_role_for_authrole(authrole)
|
||||
self.client.login(username=role.person.user.username, password=role.person.user.username+'+password')
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertIn(session.meeting.number, q('.interim-meeting-link').text())
|
||||
self.client.logout()
|
||||
|
||||
|
||||
def test_appears_on_announce(self):
|
||||
url = urlreverse('ietf.meeting.views.interim_announce')
|
||||
login_testing_unauthorized(self,"secretary",url)
|
||||
sessions=[]
|
||||
for gf in GroupFeatures.objects.filter(has_meetings=True):
|
||||
group = GroupFactory(type_id=gf.type_id)
|
||||
meeting_date = datetime.datetime.today() + datetime.timedelta(days=30)
|
||||
session = SessionFactory(
|
||||
group=group,
|
||||
meeting__type_id='interim',
|
||||
meeting__date = meeting_date,
|
||||
meeting__number = 'interim-%d-%s-00'%(meeting_date.year,group.acronym),
|
||||
status_id='scheda',
|
||||
)
|
||||
sessions.append(session)
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
for session in sessions:
|
||||
self.assertIn(session.meeting.number, q('.interim-meeting-link').text())
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ from django.views.generic import RedirectView
|
|||
from ietf.doc.fields import SearchableDocumentsField
|
||||
from ietf.doc.models import Document, State, DocEvent, NewRevisionDocEvent, DocAlias
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.utils import can_manage_session_materials
|
||||
from ietf.group.utils import can_manage_session_materials, can_manage_some_groups, can_manage_group
|
||||
from ietf.person.models import Person
|
||||
from ietf.person.name import plain_name
|
||||
from ietf.ietfauth.utils import role_required, has_role
|
||||
|
@ -82,6 +82,7 @@ from ietf.secr.proceedings.utils import handle_upload_file
|
|||
from ietf.secr.proceedings.proc_utils import (get_progress_stats, post_process, import_audio_files,
|
||||
create_recording)
|
||||
from ietf.utils.decorators import require_api_key
|
||||
from ietf.utils.history import find_history_replacements_active_at
|
||||
from ietf.utils.log import assertion
|
||||
from ietf.utils.mail import send_mail_message, send_mail_text
|
||||
from ietf.utils.pipe import pipe
|
||||
|
@ -96,7 +97,7 @@ from .forms import (InterimMeetingModelForm, InterimAnnounceForm, InterimSession
|
|||
def get_interim_menu_entries(request):
|
||||
'''Setup menu entries for interim meeting view tabs'''
|
||||
entries = []
|
||||
if has_role(request.user, ('Area Director','Secretariat','IRTF Chair','WG Chair', 'RG Chair')):
|
||||
if can_manage_some_groups(request.user):
|
||||
entries.append(("Upcoming", reverse("ietf.meeting.views.upcoming")))
|
||||
entries.append(("Pending", reverse("ietf.meeting.views.interim_pending")))
|
||||
if has_role(request.user, "Secretariat"):
|
||||
|
@ -601,7 +602,7 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
|
|||
|
||||
session_parents = sorted(set(
|
||||
s.group.parent for s in sessions
|
||||
if s.group and s.group.parent and s.group.parent.type_id == 'area' or s.group.parent.acronym == 'irtf'
|
||||
if s.group and s.group.parent and (s.group.parent.type_id == 'area' or s.group.parent.acronym == 'irtf')
|
||||
), key=lambda p: p.acronym)
|
||||
for i, p in enumerate(session_parents):
|
||||
rgb_color = cubehelix(i, len(session_parents))
|
||||
|
@ -609,7 +610,7 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
|
|||
|
||||
# dig out historic AD names
|
||||
ad_names = {}
|
||||
session_groups = set(s.group for s in sessions if s.group and s.group.parent.type_id == 'area')
|
||||
session_groups = set(s.group for s in sessions if s.group and s.group.parent and s.group.parent.type_id == 'area')
|
||||
meeting_time = datetime.datetime.combine(meeting.date, datetime.time(0, 0, 0))
|
||||
|
||||
for group_id, history_time, name in Person.objects.filter(rolehistory__name='ad', rolehistory__group__group__in=session_groups, rolehistory__group__time__lte=meeting_time).values_list('rolehistory__group__group', 'rolehistory__group__time', 'name').order_by('rolehistory__group__time'):
|
||||
|
@ -1508,7 +1509,7 @@ def meeting_requests(request, num=None):
|
|||
s.current_status_name = status_names.get(s.current_status, s.current_status)
|
||||
s.requested_by_person = session_requesters.get(s.requested_by)
|
||||
|
||||
groups_not_meeting = Group.objects.filter(state='Active',type__in=['wg','rg','ag','bof']).exclude(acronym__in = [session.group.acronym for session in sessions]).order_by("parent__acronym","acronym").prefetch_related("parent")
|
||||
groups_not_meeting = Group.objects.filter(state='Active',type__in=['wg','rg','ag','bof','program']).exclude(acronym__in = [session.group.acronym for session in sessions]).order_by("parent__acronym","acronym").prefetch_related("parent")
|
||||
|
||||
return render(request, "meeting/requests.html",
|
||||
{"meeting": meeting, "sessions":sessions,
|
||||
|
@ -1532,9 +1533,22 @@ def session_details(request, num, acronym):
|
|||
if not sessions:
|
||||
raise Http404
|
||||
|
||||
# Find the time of the meeting, so that we can look back historically
|
||||
# for what the group was called at the time.
|
||||
meeting_time = datetime.datetime.combine(meeting.date, datetime.time())
|
||||
|
||||
groups = list(set([ s.group for s in sessions ]))
|
||||
group_replacements = find_history_replacements_active_at(groups, meeting_time)
|
||||
|
||||
status_names = {n.slug: n.name for n in SessionStatusName.objects.all()}
|
||||
for session in sessions:
|
||||
|
||||
session.historic_group = None
|
||||
if session.group:
|
||||
session.historic_group = group_replacements.get(session.group_id)
|
||||
if session.historic_group:
|
||||
session.historic_group.historic_parent = None
|
||||
|
||||
session.type_counter = Counter()
|
||||
ss = session.timeslotassignments.filter(schedule=meeting.schedule).order_by('timeslot__time')
|
||||
if ss:
|
||||
|
@ -1587,6 +1601,7 @@ def session_details(request, num, acronym):
|
|||
'can_manage_materials' : can_manage,
|
||||
'can_view_request': can_view_request,
|
||||
'thisweek': datetime.date.today()-datetime.timedelta(days=7),
|
||||
'now': datetime.datetime.now(),
|
||||
})
|
||||
|
||||
class SessionDraftsForm(forms.Form):
|
||||
|
@ -2392,8 +2407,12 @@ def interim_skip_announcement(request, number):
|
|||
'meeting': meeting})
|
||||
|
||||
|
||||
@role_required('Area Director', 'Secretariat', 'IRTF Chair', 'WG Chair', 'RG Chair')
|
||||
@login_required
|
||||
def interim_pending(request):
|
||||
|
||||
if not can_manage_some_groups(request.user):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
'''View which shows interim meeting requests pending approval'''
|
||||
meetings = data_for_meetings_overview(Meeting.objects.filter(type='interim').order_by('date'), interim_status='apprw')
|
||||
|
||||
|
@ -2411,8 +2430,12 @@ def interim_pending(request):
|
|||
'meetings': meetings})
|
||||
|
||||
|
||||
@role_required('Area Director', 'Secretariat', 'IRTF Chair', 'WG Chair', 'RG Chair')
|
||||
@login_required
|
||||
def interim_request(request):
|
||||
|
||||
if not can_manage_some_groups(request.user):
|
||||
return HttpResponseForbidden("You don't have permission to request any interims")
|
||||
|
||||
'''View for requesting an interim meeting'''
|
||||
SessionFormset = inlineformset_factory(
|
||||
Meeting,
|
||||
|
@ -2497,15 +2520,15 @@ def interim_request(request):
|
|||
"formset": formset})
|
||||
|
||||
|
||||
@role_required('Area Director', 'Secretariat', 'IRTF Chair', 'WG Chair', 'RG Chair')
|
||||
@login_required
|
||||
def interim_request_cancel(request, number):
|
||||
'''View for cancelling an interim meeting request'''
|
||||
meeting = get_object_or_404(Meeting, number=number)
|
||||
first_session = meeting.session_set.first()
|
||||
session_status = current_session_status(first_session)
|
||||
group = first_session.group
|
||||
if not can_view_interim_request(meeting, request.user):
|
||||
if not can_manage_group(request.user, group):
|
||||
return HttpResponseForbidden("You do not have permissions to cancel this meeting request")
|
||||
session_status = current_session_status(first_session)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = InterimCancelForm(request.POST)
|
||||
|
@ -2538,10 +2561,13 @@ def interim_request_cancel(request, number):
|
|||
})
|
||||
|
||||
|
||||
@role_required('Area Director', 'Secretariat', 'IRTF Chair', 'WG Chair', 'RG Chair')
|
||||
@login_required
|
||||
def interim_request_details(request, number):
|
||||
'''View details of an interim meeting reqeust'''
|
||||
'''View details of an interim meeting request'''
|
||||
meeting = get_object_or_404(Meeting, number=number)
|
||||
group = meeting.session_set.first().group
|
||||
if not can_manage_group(request.user, group):
|
||||
return HttpResponseForbidden("You do not have permissions to manage this meeting request")
|
||||
sessions = meeting.session_set.all()
|
||||
can_edit = can_edit_interim_request(meeting, request.user)
|
||||
can_approve = can_approve_interim_request(meeting, request.user)
|
||||
|
@ -2582,7 +2608,7 @@ def interim_request_details(request, number):
|
|||
"can_approve": can_approve})
|
||||
|
||||
|
||||
@role_required('Area Director', 'Secretariat', 'IRTF Chair', 'WG Chair', 'RG Chair')
|
||||
@login_required
|
||||
def interim_request_edit(request, number):
|
||||
'''Edit details of an interim meeting reqeust'''
|
||||
meeting = get_object_or_404(Meeting, number=number)
|
||||
|
@ -2645,7 +2671,7 @@ def past(request):
|
|||
|
||||
def upcoming(request):
|
||||
'''List of upcoming meetings'''
|
||||
today = datetime.date.today()
|
||||
today = datetime.date.today()-datetime.timedelta(days=7)
|
||||
|
||||
# Get ietf meetings starting 7 days ago, and interim meetings starting today
|
||||
ietf_meetings = Meeting.objects.filter(type_id='ietf', date__gte=today-datetime.timedelta(days=7))
|
||||
|
@ -2684,6 +2710,7 @@ def upcoming(request):
|
|||
'menu_actions': actions,
|
||||
'menu_entries': menu_entries,
|
||||
'selected_menu_entry': selected_menu_entry,
|
||||
'now': datetime.datetime.now()
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
[
|
||||
{
|
||||
"fields": {
|
||||
"content": "{% autoescape off %}{{ assigner.ascii }} has assigned {{ reviewer.person.ascii }} as a reviewer for this document.\n\n{% if prev_team_reviews %}This team has completed other reviews of this document:{% endif %}{% for assignment in prev_team_reviews %}\n- {{ assignment.completed_on }} {{ assignment.reviewer.person.ascii }} -{% if assignment.reviewed_rev %}{{ assignment.reviewed_rev }}{% else %}{{ assignment.review_request.requested_rev }}{% endif %} {{ assignment.result.name }} \n{% endfor %}{% endautoescape %}\n",
|
||||
"content": "{% autoescape off %}{{ assigner.ascii }} has assigned {{ reviewer.person.ascii }} as a reviewer for this document.\r\n\r\n{% if prev_team_reviews %}This team has completed other reviews of this document:{% endif %}{% for assignment in prev_team_reviews %}\r\n- {{ assignment.completed_on }} {{ assignment.reviewer.person.ascii }} -{% if assignment.reviewed_rev %}{{ assignment.reviewed_rev }}{% else %}{{ assignment.review_request.requested_rev }}{% endif %} {{ assignment.result.name }} \r\n{% endfor %}{% endautoescape %}",
|
||||
"group": null,
|
||||
"path": "/group/defaults/email/review_assigned.txt",
|
||||
"title": "Default template for review assignment email",
|
||||
"type": "django",
|
||||
"variables": null
|
||||
"variables": ""
|
||||
},
|
||||
"model": "dbtemplate.dbtemplate",
|
||||
"pk": 354
|
||||
|
@ -2484,6 +2484,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\",\"lead\",\"delegate\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": true,
|
||||
|
@ -2514,6 +2515,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2544,6 +2546,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\",\"delegate\",\"secr\"]",
|
||||
"groupman_authroles": "[\"Secretariat\",\"Area Director\"]",
|
||||
"groupman_roles": "[\"ad\",\"chair\",\"delegate\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2574,6 +2577,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"ad\",\"delegate\",\"secr\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"ad\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2604,6 +2608,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"ad\",\"secr\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2634,6 +2639,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2664,6 +2670,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2694,6 +2701,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\",\"delegate\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2724,6 +2732,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\",\"delegate\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2754,6 +2763,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"auth\"]",
|
||||
"groupman_authroles": "[]",
|
||||
"groupman_roles": "[]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2784,6 +2794,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\",\"delegate\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2814,6 +2825,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\",\"delegate\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2844,6 +2856,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2874,6 +2887,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\",\"advisor\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2903,21 +2917,22 @@
|
|||
"custom_group_roles": true,
|
||||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"lead\",\"secr\"]",
|
||||
"groupman_roles": "[\"lead\",\"secr\"]",
|
||||
"docman_roles": "[\"lead\",\"chair\",\"secr\"]",
|
||||
"groupman_authroles": "[\"Secretariat\",\"IAB\"]",
|
||||
"groupman_roles": "[\"lead\",\"chair\",\"secr\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
"has_documents": true,
|
||||
"has_meetings": false,
|
||||
"has_meetings": true,
|
||||
"has_milestones": true,
|
||||
"has_nonsession_materials": false,
|
||||
"has_reviews": false,
|
||||
"has_session_materials": false,
|
||||
"is_schedulable": false,
|
||||
"material_types": "[\"slides\"]",
|
||||
"matman_roles": "[\"lead\",\"secr\"]",
|
||||
"matman_roles": "[\"lead\",\"chair\",\"secr\"]",
|
||||
"req_subm_approval": false,
|
||||
"role_order": "[\"lead\",\"secr\"]",
|
||||
"role_order": "[\"lead\",\"chair\",\"secr\"]",
|
||||
"show_on_agenda": false
|
||||
},
|
||||
"model": "group.groupfeatures",
|
||||
|
@ -2934,6 +2949,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.review_requests",
|
||||
"docman_roles": "[\"secr\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"ad\",\"secr\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2964,6 +2980,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -2994,6 +3011,7 @@
|
|||
"customize_workflow": true,
|
||||
"default_tab": "ietf.group.views.group_documents",
|
||||
"docman_roles": "[\"chair\",\"delegate\",\"secr\"]",
|
||||
"groupman_authroles": "[\"Secretariat\",\"IRTF Chair\"]",
|
||||
"groupman_roles": "[\"chair\",\"delegate\"]",
|
||||
"has_chartering_process": true,
|
||||
"has_default_jabber": true,
|
||||
|
@ -3024,6 +3042,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"liaiman\",\"matman\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -3054,6 +3073,7 @@
|
|||
"customize_workflow": false,
|
||||
"default_tab": "ietf.group.views.group_about",
|
||||
"docman_roles": "[\"chair\"]",
|
||||
"groupman_authroles": "[\"Secretariat\"]",
|
||||
"groupman_roles": "[\"chair\"]",
|
||||
"has_chartering_process": false,
|
||||
"has_default_jabber": false,
|
||||
|
@ -3084,6 +3104,7 @@
|
|||
"customize_workflow": true,
|
||||
"default_tab": "ietf.group.views.group_documents",
|
||||
"docman_roles": "[\"chair\",\"delegate\",\"secr\"]",
|
||||
"groupman_authroles": "[\"Secretariat\",\"Area Director\"]",
|
||||
"groupman_roles": "[\"ad\",\"chair\",\"delegate\",\"secr\"]",
|
||||
"has_chartering_process": true,
|
||||
"has_default_jabber": true,
|
||||
|
@ -5603,8 +5624,8 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"editor_label": "(1)",
|
||||
"desc": "",
|
||||
"editor_label": "(1)",
|
||||
"name": "Conflicts with",
|
||||
"order": 0,
|
||||
"penalty": 100000,
|
||||
|
@ -5616,9 +5637,10 @@
|
|||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
"editor_label": "time_relation",
|
||||
"name": "Preference for time between sessions",
|
||||
"order": 0,
|
||||
"penalty": 100000,
|
||||
"penalty": 1000,
|
||||
"used": true
|
||||
},
|
||||
"model": "name.constraintname",
|
||||
|
@ -5627,6 +5649,7 @@
|
|||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
"editor_label": "timerange",
|
||||
"name": "Can't meet within timerange",
|
||||
"order": 0,
|
||||
"penalty": 100000,
|
||||
|
@ -5638,9 +5661,10 @@
|
|||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
"editor_label": "wg_adjacent",
|
||||
"name": "Request for adjacent scheduling with another WG",
|
||||
"order": 0,
|
||||
"penalty": 100000,
|
||||
"penalty": 10000,
|
||||
"used": true
|
||||
},
|
||||
"model": "name.constraintname",
|
||||
|
@ -9065,7 +9089,7 @@
|
|||
"desc": "IESG discussions on the document have raised some issues that need to be brought to the attention of the authors/WG, but those issues have not been written down yet. (It is common for discussions during a telechat to result in such situations. An AD may raise a possible issue during a telechat and only decide as a result of that discussion whether the issue is worth formally writing up and bringing to the attention of the authors/WG). A document stays in the \"Point Raised - Writeup Needed\" state until *ALL* IESG comments that have been raised have been documented.",
|
||||
"name": "Point Raised - writeup needed",
|
||||
"order": 1,
|
||||
"used": true
|
||||
"used": false
|
||||
},
|
||||
"model": "name.doctagname",
|
||||
"pk": "point"
|
||||
|
@ -10181,6 +10205,17 @@
|
|||
"model": "name.importantdatename",
|
||||
"pk": "idcutoff"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"default_offset_days": 70,
|
||||
"desc": "Announcement of whether conditions have improved enough to hold an in-person meeting in Madrid, or if IETF 108 will be held as a virtual meeting",
|
||||
"name": "IETF 108 Go-ahead Announcement",
|
||||
"order": 0,
|
||||
"used": false
|
||||
},
|
||||
"model": "name.importantdatename",
|
||||
"pk": "ietf-108-go-ahead"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"default_offset_days": -82,
|
||||
|
@ -11268,6 +11303,16 @@
|
|||
"model": "name.rolename",
|
||||
"pk": "chair"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
"name": "Communications Director",
|
||||
"order": 0,
|
||||
"used": true
|
||||
},
|
||||
"model": "name.rolename",
|
||||
"pk": "comdir"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
|
@ -11420,7 +11465,7 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "Provides log-in permission to restricted Trac instances",
|
||||
"desc": "Provides log-in permission to restricted Trac instances. Used by the generate_apache_perms management command, called from ../../scripts/Cron-runner",
|
||||
"name": "Trac Editor",
|
||||
"order": 0,
|
||||
"used": true
|
||||
|
@ -11500,8 +11545,8 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "WebEx support",
|
||||
"name": "WebEx session",
|
||||
"desc": "Web streaming support",
|
||||
"name": "WebEx",
|
||||
"order": 0,
|
||||
"used": true
|
||||
},
|
||||
|
@ -14436,9 +14481,9 @@
|
|||
"fields": {
|
||||
"command": "xym",
|
||||
"switch": "--version",
|
||||
"time": "2020-02-19T00:13:43.554",
|
||||
"time": "2020-05-10T00:12:51.809",
|
||||
"used": true,
|
||||
"version": "xym 0.4"
|
||||
"version": "xym 0.4.8"
|
||||
},
|
||||
"model": "utils.versioninfo",
|
||||
"pk": 1
|
||||
|
@ -14447,9 +14492,9 @@
|
|||
"fields": {
|
||||
"command": "pyang",
|
||||
"switch": "--version",
|
||||
"time": "2020-02-19T00:13:44.450",
|
||||
"time": "2020-05-10T00:12:53.489",
|
||||
"used": true,
|
||||
"version": "pyang 2.1.1"
|
||||
"version": "pyang 2.2.1"
|
||||
},
|
||||
"model": "utils.versioninfo",
|
||||
"pk": 2
|
||||
|
@ -14458,9 +14503,9 @@
|
|||
"fields": {
|
||||
"command": "yanglint",
|
||||
"switch": "--version",
|
||||
"time": "2020-02-19T00:13:44.597",
|
||||
"time": "2020-05-10T00:12:53.919",
|
||||
"used": true,
|
||||
"version": "yanglint 0.14.80"
|
||||
"version": "yanglint SO 1.6.7"
|
||||
},
|
||||
"model": "utils.versioninfo",
|
||||
"pk": 3
|
||||
|
@ -14469,9 +14514,9 @@
|
|||
"fields": {
|
||||
"command": "xml2rfc",
|
||||
"switch": "--version",
|
||||
"time": "2020-02-19T00:13:45.481",
|
||||
"time": "2020-05-10T00:12:56.462",
|
||||
"used": true,
|
||||
"version": "xml2rfc 2.40.0"
|
||||
"version": "xml2rfc 2.44.0"
|
||||
},
|
||||
"model": "utils.versioninfo",
|
||||
"pk": 4
|
||||
|
|
|
@ -353,7 +353,10 @@ class PersonalApiKey(models.Model):
|
|||
def validate_key(cls, s):
|
||||
import struct, hashlib, base64
|
||||
assert isinstance(s, bytes)
|
||||
key = base64.urlsafe_b64decode(s)
|
||||
try:
|
||||
key = base64.urlsafe_b64decode(s)
|
||||
except Exception:
|
||||
return None
|
||||
id, salt, hash = struct.unpack(KEY_STRUCT, key)
|
||||
k = cls.objects.filter(id=id)
|
||||
if not k.exists():
|
||||
|
|
|
@ -29,7 +29,8 @@ from ietf.mailtrigger.utils import gather_address_lists
|
|||
# -------------------------------------------------
|
||||
# Globals
|
||||
# -------------------------------------------------
|
||||
AUTHORIZED_ROLES=('WG Chair','WG Secretary','RG Chair','IAB Group Chair','Area Director','Secretariat','Team Chair','IRTF Chair')
|
||||
# TODO: This needs to be replaced with something that pays attention to groupfeatures
|
||||
AUTHORIZED_ROLES=('WG Chair','WG Secretary','RG Chair','IAB Group Chair','Area Director','Secretariat','Team Chair','IRTF Chair','Program Chair','Program Lead','Program Secretary')
|
||||
|
||||
# -------------------------------------------------
|
||||
# Helper Functions
|
||||
|
@ -319,7 +320,10 @@ def confirm(request, acronym):
|
|||
)
|
||||
if 'resources' in form.data:
|
||||
new_session.resources.set(session_data['resources'])
|
||||
if int(form.data.get('joint_for_session', '-1')) == count:
|
||||
jfs = form.data.get('joint_for_session', '-1')
|
||||
if not jfs: # jfs might be ''
|
||||
jfs = '-1'
|
||||
if int(jfs) == count:
|
||||
groups_split = form.cleaned_data.get('joint_with_groups').replace(',',' ').split()
|
||||
joint = Group.objects.filter(acronym__in=groups_split)
|
||||
new_session.joint_with_groups.set(joint)
|
||||
|
|
|
@ -771,6 +771,25 @@ ul.progress-section {
|
|||
|
||||
.btn .fa-stack { width: 1em; height: 1em; }
|
||||
.btn .fa-stack .fa-stack-1x { line-height: 80%; }
|
||||
.fa-stack-1 {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 1.28571429em;
|
||||
height: 1em;
|
||||
vertical-align: inherit;
|
||||
}
|
||||
.fa-stack-sm {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 0.7172em;
|
||||
line-height: inherit;
|
||||
}
|
||||
.fa-stack-xs {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 0.5em;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
|
|
75
ietf/static/ietf/font-datatracker/README.txt
Executable file
75
ietf/static/ietf/font-datatracker/README.txt
Executable file
|
@ -0,0 +1,75 @@
|
|||
This webfont is generated by http://fontello.com open source project.
|
||||
|
||||
|
||||
================================================================================
|
||||
Please, note, that you should obey original font licenses, used to make this
|
||||
webfont pack. Details available in LICENSE.txt file.
|
||||
|
||||
- Usually, it's enough to publish content of LICENSE.txt file somewhere on your
|
||||
site in "About" section.
|
||||
|
||||
- If your project is open-source, usually, it will be ok to make LICENSE.txt
|
||||
file publicly available in your repository.
|
||||
|
||||
- Fonts, used in Fontello, don't require a clickable link on your site.
|
||||
But any kind of additional authors crediting is welcome.
|
||||
================================================================================
|
||||
|
||||
|
||||
Comments on archive content
|
||||
---------------------------
|
||||
|
||||
- /font/* - fonts in different formats
|
||||
|
||||
- /css/* - different kinds of css, for all situations. Should be ok with
|
||||
twitter bootstrap. Also, you can skip <i> style and assign icon classes
|
||||
directly to text elements, if you don't mind about IE7.
|
||||
|
||||
- demo.html - demo file, to show your webfont content
|
||||
|
||||
- LICENSE.txt - license info about source fonts, used to build your one.
|
||||
|
||||
- config.json - keeps your settings. You can import it back into fontello
|
||||
anytime, to continue your work
|
||||
|
||||
|
||||
Why so many CSS files ?
|
||||
-----------------------
|
||||
|
||||
Because we like to fit all your needs :)
|
||||
|
||||
- basic file, <your_font_name>.css - is usually enough, it contains @font-face
|
||||
and character code definitions
|
||||
|
||||
- *-ie7.css - if you need IE7 support, but still don't wish to put char codes
|
||||
directly into html
|
||||
|
||||
- *-codes.css and *-ie7-codes.css - if you like to use your own @font-face
|
||||
rules, but still wish to benefit from css generation. That can be very
|
||||
convenient for automated asset build systems. When you need to update font -
|
||||
no need to manually edit files, just override old version with archive
|
||||
content. See fontello source code for examples.
|
||||
|
||||
- *-embedded.css - basic css file, but with embedded WOFF font, to avoid
|
||||
CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain.
|
||||
We strongly recommend to resolve this issue by `Access-Control-Allow-Origin`
|
||||
server headers. But if you ok with dirty hack - this file is for you. Note,
|
||||
that data url moved to separate @font-face to avoid problems with <IE9, when
|
||||
string is too long.
|
||||
|
||||
- animate.css - use it to get ideas about spinner rotation animation.
|
||||
|
||||
|
||||
Attention for server setup
|
||||
--------------------------
|
||||
|
||||
You MUST setup server to reply with proper `mime-types` for font files -
|
||||
otherwise some browsers will fail to show fonts.
|
||||
|
||||
Usually, `apache` already has necessary settings, but `nginx` and other
|
||||
webservers should be tuned. Here is list of mime types for our file extensions:
|
||||
|
||||
- `application/vnd.ms-fontobject` - eot
|
||||
- `application/x-font-woff` - woff
|
||||
- `application/x-font-ttf` - ttf
|
||||
- `image/svg+xml` - svg
|
24
ietf/static/ietf/font-datatracker/config.json
Executable file
24
ietf/static/ietf/font-datatracker/config.json
Executable file
File diff suppressed because one or more lines are too long
58
ietf/static/ietf/font-datatracker/css/datatracker.css
Executable file
58
ietf/static/ietf/font-datatracker/css/datatracker.css
Executable file
|
@ -0,0 +1,58 @@
|
|||
@font-face {
|
||||
font-family: 'datatracker';
|
||||
src: url('../font/datatracker.eot?60587374');
|
||||
src: url('../font/datatracker.eot?60587374#iefix') format('embedded-opentype'),
|
||||
url('../font/datatracker.woff2?60587374') format('woff2'),
|
||||
url('../font/datatracker.woff?60587374') format('woff'),
|
||||
url('../font/datatracker.ttf?60587374') format('truetype'),
|
||||
url('../font/datatracker.svg?60587374#datatracker') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
|
||||
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
|
||||
/*
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
@font-face {
|
||||
font-family: 'datatracker';
|
||||
src: url('../font/datatracker.svg?60587374#datatracker') format('svg');
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
.dt {
|
||||
font-family: "datatracker";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
speak: none;
|
||||
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
width: 1em;
|
||||
margin-right: .2em;
|
||||
text-align: center;
|
||||
/* opacity: .8; */
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
/* Animation center compensation - margins should be symmetric */
|
||||
/* remove if not needed */
|
||||
margin-left: .2em;
|
||||
|
||||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Font smoothing. That was taken from TWBS */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
|
||||
.fd-meetecho:before { content: '\e800'; } /* '' */
|
48
ietf/static/ietf/font-datatracker/css/font-datatracker.css
Executable file
48
ietf/static/ietf/font-datatracker/css/font-datatracker.css
Executable file
|
@ -0,0 +1,48 @@
|
|||
@font-face {
|
||||
font-family: 'font-datatracker';
|
||||
src: url('../font/font-datatracker.eot?60587374');
|
||||
src: url('../font/font-datatracker.eot?60587374#iefix') format('embedded-opentype'),
|
||||
url('../font/font-datatracker.woff2?60587374') format('woff2'),
|
||||
url('../font/font-datatracker.woff?60587374') format('woff'),
|
||||
url('../font/font-datatracker.ttf?60587374') format('truetype'),
|
||||
url('../font/font-datatracker.svg?60587374#font-datatracker') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.fd {
|
||||
font-family: "font-datatracker";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
speak: none;
|
||||
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
width: 1em;
|
||||
margin-right: .2em;
|
||||
text-align: center;
|
||||
/* opacity: .8; */
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
/* Animation center compensation - margins should be symmetric */
|
||||
/* remove if not needed */
|
||||
margin-left: .2em;
|
||||
|
||||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Font smoothing. That was taken from TWBS */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
|
||||
.fd-meetecho:before { content: '\e800'; } /* '' */
|
BIN
ietf/static/ietf/font-datatracker/font/datatracker.eot
Executable file
BIN
ietf/static/ietf/font-datatracker/font/datatracker.eot
Executable file
Binary file not shown.
12
ietf/static/ietf/font-datatracker/font/datatracker.svg
Executable file
12
ietf/static/ietf/font-datatracker/font/datatracker.svg
Executable file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 6.7 KiB |
BIN
ietf/static/ietf/font-datatracker/font/datatracker.ttf
Executable file
BIN
ietf/static/ietf/font-datatracker/font/datatracker.ttf
Executable file
Binary file not shown.
BIN
ietf/static/ietf/font-datatracker/font/datatracker.woff
Executable file
BIN
ietf/static/ietf/font-datatracker/font/datatracker.woff
Executable file
Binary file not shown.
BIN
ietf/static/ietf/font-datatracker/font/datatracker.woff2
Executable file
BIN
ietf/static/ietf/font-datatracker/font/datatracker.woff2
Executable file
Binary file not shown.
BIN
ietf/static/ietf/font-datatracker/font/font-datatracker.eot
Executable file
BIN
ietf/static/ietf/font-datatracker/font/font-datatracker.eot
Executable file
Binary file not shown.
12
ietf/static/ietf/font-datatracker/font/font-datatracker.svg
Executable file
12
ietf/static/ietf/font-datatracker/font/font-datatracker.svg
Executable file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 6.7 KiB |
BIN
ietf/static/ietf/font-datatracker/font/font-datatracker.ttf
Executable file
BIN
ietf/static/ietf/font-datatracker/font/font-datatracker.ttf
Executable file
Binary file not shown.
BIN
ietf/static/ietf/font-datatracker/font/font-datatracker.woff
Executable file
BIN
ietf/static/ietf/font-datatracker/font/font-datatracker.woff
Executable file
Binary file not shown.
BIN
ietf/static/ietf/font-datatracker/font/font-datatracker.woff2
Executable file
BIN
ietf/static/ietf/font-datatracker/font/font-datatracker.woff2
Executable file
Binary file not shown.
|
@ -133,7 +133,8 @@ def validate_submission_rev(name, rev):
|
|||
|
||||
expected = 0
|
||||
existing_revs = [int(i.rev) for i in Document.objects.filter(name=name) if i.rev and i.rev.isdigit() ]
|
||||
log.assertion('[ i.rev for i in Document.objects.filter(name=name) if not (i.rev and i.rev.isdigit()) ]', [])
|
||||
unexpected_revs = [ i.rev for i in Document.objects.filter(name=name) if not (i.rev and i.rev.isdigit()) ] # pyflakes:ignore
|
||||
log.assertion('unexpected_revs', [])
|
||||
if existing_revs:
|
||||
expected = max(existing_revs) + 1
|
||||
|
||||
|
|
|
@ -178,9 +178,9 @@
|
|||
document attributes are necessary for an application is
|
||||
available for all documents at the relative url <code>doc.json</code>, e.g.,
|
||||
<code>{% url 'ietf.doc.views_doc.document_json' name='draft-ietf-poised95-std-proc-3' %}</code>
|
||||
<a href="{% url 'ietf.doc.views_doc.document_json' name='draft-ietf-poised95-std-proc-3' %}"><span class="fa fa-external-link"/></a>.
|
||||
<a href="{% url 'ietf.doc.views_doc.document_json' name='draft-ietf-poised95-std-proc-3' %}"><span class="fa fa-external-link"></span></a>.
|
||||
You can also specify an RFC: <code>{% url 'ietf.doc.views_doc.document_json' name='rfc2026' %}</code>
|
||||
<a href="{% url 'ietf.doc.views_doc.document_json' name='rfc2026' %}"><span class="fa fa-external-link"/></a>.
|
||||
<a href="{% url 'ietf.doc.views_doc.document_json' name='rfc2026' %}"><span class="fa fa-external-link"></span></a>.
|
||||
No API key is needed to access this.
|
||||
|
||||
</p>
|
||||
|
@ -327,6 +327,7 @@
|
|||
To verify a signature and get the verified data using Python with the
|
||||
<a href="https://jwcrypto.readthedocs.io/en/latest/">jwcrypto</a> module,
|
||||
you could do:
|
||||
</p>
|
||||
<pre>
|
||||
from jwcrypto import jwk, jws
|
||||
|
||||
|
@ -339,7 +340,6 @@ jwstoken.deserialize(data)
|
|||
jwstoken.verify(key)
|
||||
payload = jwstoken.payload
|
||||
</pre>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
{% endcomment %}
|
||||
|
||||
<link rel="stylesheet" href="{% static 'font-awesome/css/font-awesome.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'ietf/font-datatracker/css/font-datatracker.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'ietf/bootstrap/css/bootstrap.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'ietf/bootstrap/css/bootstrap-theme.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'ietf/css/ietf.css' %}">
|
||||
|
|
|
@ -229,15 +229,12 @@
|
|||
<span class="label label-danger pull-right">CANCELLED</span>
|
||||
{% endif %}
|
||||
|
||||
{% if item.session.agenda %}
|
||||
{% include "meeting/session_agenda_include.html" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="col-md-2">
|
||||
<td class="col-md-2 text-right">
|
||||
<span class="hidden-xs">
|
||||
{% if item.timeslot.type.slug == 'other' %}
|
||||
{% if item.session.agenda %}
|
||||
{% include "meeting/session_buttons_include.html" %}
|
||||
{% include "meeting/session_buttons_include.html" with show_agenda=True session=item.session meeting=schedule.meeting %}
|
||||
{% else %}
|
||||
{% for slide in item.session.slides %}
|
||||
<a href="{{slide.get_href}}">{{ slide.title|clean_whitespace }}</a>
|
||||
|
@ -332,12 +329,10 @@
|
|||
<br><span class="text-danger">{{item.session.agenda_note}}</span>
|
||||
{% endif %}
|
||||
|
||||
{% include "meeting/session_agenda_include.html" %}
|
||||
|
||||
</td>
|
||||
<td class="text-nowrap text-right">
|
||||
<span class="hidden-xs">
|
||||
{% include "meeting/session_buttons_include.html" %}
|
||||
{% include "meeting/session_buttons_include.html" with show_agenda=True session=item.session meeting=schedule.meeting %}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<td>{{ meeting.date }}</td>
|
||||
<td>{{ meeting.responsible_group.acronym }}</td>
|
||||
<td>
|
||||
<a href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">{{ meeting.number }}</a>
|
||||
<a class="interim-meeting-link" href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">{{ meeting.number }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -40,11 +40,7 @@
|
|||
<td>{{ meeting.date }}</td>
|
||||
<td>{{ meeting.responsible_group.acronym }}</td>
|
||||
<td>
|
||||
{% if meeting.type_id == "interim" %}
|
||||
<a href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">{{ meeting.number }}{% if meeting.interim_meeting_cancelled %} <span class="label label-warning">CANCELLED</span>{% endif %}</a>
|
||||
{% else %}
|
||||
<a href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">IETF - {{ meeting.number }}</a>
|
||||
{% endif %}
|
||||
<a class="interim-meeting-link" href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">{{ meeting.number }}{% if meeting.interim_meeting_cancelled %} <span class="label label-warning">CANCELLED</span>{% endif %}</a>
|
||||
</td>
|
||||
<td>{% if meeting.can_approve %}<span class="label label-success">can be approved</span>{% endif %}</td>
|
||||
</tr>
|
||||
|
|
|
@ -1,20 +1,26 @@
|
|||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load textfilters %}
|
||||
{% load origin %}
|
||||
{% origin %}
|
||||
{% if session.agenda %}
|
||||
{% with session.official_timeslotassignment as item %}
|
||||
{% load staticfiles %}
|
||||
{% load textfilters %}
|
||||
{% origin %}
|
||||
{% if session.agenda and show_agenda %}
|
||||
{% include "meeting/session_agenda_include.html" %}
|
||||
<!-- agenda pop-up button -->
|
||||
<a class="" data-toggle="modal" data-target="#modal-{{item.slug}}" title="Show meeting materials"><span class="fa fa-fw fa-arrows-alt"></span></a>
|
||||
<!-- materials tar file -->
|
||||
<a class="" href="/meeting/{{meeting.number}}/agenda/{{session.group.acronym}}-drafts.tgz" title="Download meeting materials as .tar archive"><span class="fa fa-fw fa-file-archive-o"></span></a>
|
||||
<a class="" href="/meeting/{{meeting.number}}/agenda/{{session.historic_group.acronym}}-drafts.tgz" title="Download meeting materials as .tar archive"><span class="fa fa-fw fa-file-archive-o"></span></a>
|
||||
<!-- materials PDF file -->
|
||||
<a class="" href="/meeting/{{ meeting.number }}/agenda/{{session.group.acronym}}-drafts.pdf" title="Download meeting materials as PDF file"><span class="fa fa-fw fa-file-pdf-o"></span></a>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
<a class="" href="/meeting/{{ meeting.number }}/agenda/{{session.historic_group.acronym}}-drafts.pdf" title="Download meeting materials as PDF file"><span class="fa fa-fw fa-file-pdf-o"></span></a>
|
||||
{% endif %}
|
||||
<!-- etherpad -->
|
||||
<a class="" href="https://etherpad.ietf.org:9009/p/notes-ietf-{{ meeting.number }}?useMonospaceFont=true" title="Etherpad for note-takers"><span class="fa fa-fw fa-edit"></span></a>
|
||||
{% if item.timeslot.type.slug == 'plenary' %}
|
||||
<a class="" href="https://etherpad.ietf.org:9009/p/notes-ietf-{{ meeting.number }}-plenary?useMonospaceFont=true" title="Etherpad for note-takers"><span class="fa fa-fw fa-edit"></span></a>
|
||||
{% else %}
|
||||
<a class="" href="https://etherpad.ietf.org:9009/p/notes-ietf-{{ meeting.number }}-{{session.historic_group.acronym}}?useMonospaceFont=true" title="Etherpad for note-takers"><span class="fa fa-fw fa-edit"></span></a>
|
||||
{% endif %}
|
||||
|
||||
{# show stream buttons up till end of session, then show archive buttons #}
|
||||
{% if now < item.timeslot.end_time %}
|
||||
<!-- Jabber -->
|
||||
<a class="" href="xmpp:{{session.jabber_room_name}}@jabber.ietf.org?join" title="Jabber room for {{session.jabber_room_name}}"><span class="fa fa-fw fa-lightbulb-o"></span></a>
|
||||
<!-- webex -->
|
||||
|
@ -26,17 +32,60 @@
|
|||
{% elif session.remote_instructions|first_url %}
|
||||
<a class=""
|
||||
href="{{ session.remote_instructions|first_url }}"
|
||||
title="Webex session"><span class="fa fa-fw fa-phone"></span>
|
||||
title="Session call-in"><span class="fa fa-fw fa-phone"></span>
|
||||
</a>
|
||||
{% elif item.timeslot.location.webex_url %}
|
||||
<a class=""
|
||||
href="{{item.timeslot.location.webex_url|format:session }}"
|
||||
title="Webex session"><span class="fa fa-fw fa-phone"></span>
|
||||
</a>
|
||||
<!-- Video stream (meetecho) -->
|
||||
{% elif item.timeslot.location.video_stream_url %}
|
||||
<a class=""
|
||||
href="{{item.timeslot.location.video_stream_url|format:session }}"
|
||||
title="Meetecho video stream"><span class="fa fa-fw fa-video-camera"></span>
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="">
|
||||
<span class="fa fa-fw fa-phone" style="color: #ddd;"
|
||||
title="No webex info found in remote instructions or agenda note"></span>
|
||||
title="No webex or meetecho info found in remote instructions or agenda note"></span>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<!-- Jabber -->
|
||||
<a class="" href="https://www.ietf.org/jabber/logs/{{session.jabber_room_name}}?C=M;O=D" title="Jabber logs for {{session.jabber_room_name}}">
|
||||
<span class="fa-stack-1"><i class="fa fa-fw fa-file-o fa-stack-1x"></i><i class="fa fa-fw fa-lightbulb-o fa-stack-sm"></i></span>
|
||||
</a>
|
||||
{% with session.recordings as recordings %}
|
||||
{% if recordings %}
|
||||
{# There's no guaranteed order, so this is a bit messy: #}
|
||||
<!-- Audio -->
|
||||
{% for r in recordings %}{% with href=r.get_href %}
|
||||
{% if 'audio' in href %}
|
||||
<a class="" href="{{ href }}" title="{{ r.title }}"><span class="fa fa-fw fa-file-audio-o"></span></a>
|
||||
{% endif %}
|
||||
{% endwith %}{% endfor %}
|
||||
<!-- YouTube -->
|
||||
{% for r in recordings %}{% with href=r.get_href %}
|
||||
{% if 'youtu' in href %}
|
||||
<a class="" href="{{ href }}" title="{{ r.title }}"><span class="fa fa-fw fa-file-video-o"></span></a>
|
||||
{% endif %}
|
||||
{% endwith %}{% endfor %}
|
||||
<!-- Any other recordings -->
|
||||
{% for r in recordings %}{% with href=r.get_href %}
|
||||
{% if not 'audio' in href and not 'youtu' in href %}
|
||||
<a class="" href="{{ href }}" title="{{ r.title }}"><span class="fa fa-fw fa-file-o"></span></a>
|
||||
{% endif %}
|
||||
{% endwith %}{% endfor %}
|
||||
{% elif item.timeslot.location.video_stream_url %}
|
||||
<a class=""
|
||||
href="http://www.meetecho.com/ietf{{meeting.number}}/recordings#{{session.historic_group.acronym.upper}}"
|
||||
title="Meetecho session recording"><span class="fd fa-fw fd-meetecho"></span></a>
|
||||
{% elif show_empty %}
|
||||
<span class="fa fa-fw"></span>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
|
@ -2,112 +2,95 @@
|
|||
{% load origin %}
|
||||
{% load staticfiles %}
|
||||
{% load textfilters %}
|
||||
|
||||
{% origin %}
|
||||
|
||||
{% if item.session.agenda %}
|
||||
<button class="btn btn-default btn-xs" data-toggle="modal" data-target="#modal-{{item.slug}}" title="Show meeting materials"><span class="fa fa-arrows-alt"></span></button>
|
||||
<a class="btn btn-default btn-xs" href="/meeting/{{schedule.meeting.number}}/agenda/{{item.session.historic_group.acronym}}-drafts.tgz" title="Download meeting materials as .tar archive"><span class="fa fa-file-archive-o"></span></a>
|
||||
<a class="btn btn-default btn-xs" href="/meeting/{{ schedule.meeting.number }}/agenda/{{item.session.historic_group.acronym}}-drafts.pdf" title="Download meeting materials as PDF file"><span class="fa fa-file-pdf-o"></span></a>
|
||||
{% endif %}
|
||||
<div id="session-buttons-{{session.pk}}">
|
||||
{% if session.agenda and show_agenda %}
|
||||
{% include "meeting/session_agenda_include.html" %}
|
||||
<!-- agenda pop-up button -->
|
||||
<a class="" data-toggle="modal" data-target="#modal-{{item.slug}}" title="Show meeting materials"><span class="fa fa-fw fa-arrows-alt"></span></a>
|
||||
<!-- materials tar file -->
|
||||
<a class="" href="/meeting/{{meeting.number}}/agenda/{{session.historic_group.acronym}}-drafts.tgz" title="Download meeting materials as .tar archive"><span class="fa fa-fw fa-file-archive-o"></span></a>
|
||||
<!-- materials PDF file -->
|
||||
<a class="" href="/meeting/{{ meeting.number }}/agenda/{{session.historic_group.acronym}}-drafts.pdf" title="Download meeting materials as PDF file"><span class="fa fa-fw fa-file-pdf-o"></span></a>
|
||||
{% endif %}
|
||||
|
||||
{% if item.timeslot.type.slug == 'plenary' %}
|
||||
<a class="btn btn-default btn-xs" href="https://etherpad.ietf.org:9009/p/notes-ietf-{{ schedule.meeting.number }}-plenary?useMonospaceFont=true" title="Etherpad for note-takers"><span class="fa fa-edit"></span></a>
|
||||
{% else %}
|
||||
<a class="btn btn-default btn-xs" href="https://etherpad.ietf.org:9009/p/notes-ietf-{{ schedule.meeting.number }}-{{item.session.historic_group.acronym}}?useMonospaceFont=true" title="Etherpad for note-takers"><span class="fa fa-edit"></span></a>
|
||||
{% endif %}
|
||||
<!-- etherpad -->
|
||||
{% if item.timeslot.type.slug == 'plenary' %}
|
||||
<a class="" href="https://etherpad.ietf.org:9009/p/notes-ietf-{{ meeting.number }}-plenary?useMonospaceFont=true" title="Etherpad for note-takers"><span class="fa fa-fw fa-edit"></span></a>
|
||||
{% else %}
|
||||
<a class="" href="https://etherpad.ietf.org:9009/p/notes-ietf-{{ meeting.number }}-{{session.historic_group.acronym}}?useMonospaceFont=true" title="Etherpad for note-takers"><span class="fa fa-fw fa-edit"></span></a>
|
||||
{% endif %}
|
||||
|
||||
{# show stream buttons up till end of session, then show archive buttons #}
|
||||
{% if now < item.timeslot.end_time %}
|
||||
<!-- Jabber -->
|
||||
<a class="btn btn-default btn-xs"
|
||||
href="xmpp:{{item.session.jabber_room_name}}@jabber.ietf.org?join"
|
||||
title="Jabber room for {{item.session.jabber_room_name}}"><span class="fa fa-lightbulb-o"></span>
|
||||
</a>
|
||||
|
||||
<!-- Video stream (meetecho) -->
|
||||
{% if item.timeslot.location.video_stream_url %}
|
||||
<a class="btn btn-default btn-xs"
|
||||
href="{{ item.timeslot.location.video_stream_url|format:item.session }}"
|
||||
title="Meetecho video stream"><span class="fa fa-video-camera"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<!-- Audio stream -->
|
||||
{% if item.timeslot.location.audio_stream_url %}
|
||||
<a class="btn btn-default btn-xs"
|
||||
href="{{item.timeslot.location.audio_stream_url|format:item.session }}"
|
||||
title="Audio stream"><span class="glyphicon glyphicon-headphones"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<!-- WebEx -->
|
||||
{% if "https://ietf.webex.com" in item.session.agenda_note|first_url %}
|
||||
<a class="btn btn-default btn-xs"
|
||||
href="{{ item.session.agenda_note|first_url }}"
|
||||
title="Webex session"><span class="fa fa-phone"></span>
|
||||
</a>
|
||||
{% else %}
|
||||
{% if item.timeslot.location.webex_url %}
|
||||
<a class="btn btn-default btn-xs"
|
||||
href="{{item.timeslot.location.webex_url|format:item.session }}"
|
||||
title="Webex session"><span class="fa fa-phone"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
|
||||
<!-- Jabber logs -->
|
||||
{% if schedule.meeting.number|add:"0" >= 60 %}
|
||||
<a class="btn btn-default btn-xs"
|
||||
href="https://www.ietf.org/jabber/logs/{{item.session.jabber_room_name}}"
|
||||
title="Jabber logs for {{item.session.jabber_room_name}}">
|
||||
<span class="fa fa-stack">
|
||||
<i class="fa fa-file-o fa-stack-1x"></i>
|
||||
<i class="fa fa-lightbulb-o fa-stack-1x"></i>
|
||||
</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<!-- Video recording -->
|
||||
{% if schedule.meeting.number|add:"0" >= 80 %}
|
||||
{% with item.session.recordings as recordings %}
|
||||
{% if recordings %}
|
||||
<!-- There's no guaranteed order, so this is a bit messy: -->
|
||||
<!-- First, the audio recordings, if any -->
|
||||
{% for r in recordings %}
|
||||
{% if r.get_href and 'audio' in r.get_href %}
|
||||
<a class="btn btn-default btn-xs" href="{{ r.get_href }}" title="{{ r.title}}">
|
||||
<span class="fa fa-file-audio-o"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<!-- Then the youtube recordings -->
|
||||
{% for r in recordings %}
|
||||
{% if r.get_href and 'youtu' in r.get_href %}
|
||||
<a class="btn btn-default btn-xs" href="{{ r.get_href }}" title="{{ r.title }}">
|
||||
<span class="fa fa-file-video-o"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<!-- Finally, any other recordings -->
|
||||
{% for r in recordings %}
|
||||
{% if r.get_href and not 'audio' in r.get_href and not 'youtu' in r.get_href %}
|
||||
<a class="btn btn-default btn-xs" href="{{ r.get_href }}" title="{{ r.title }}">
|
||||
<span class="fa fa-file-o"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if item.timeslot.location.video_stream_url %}
|
||||
<a class="btn btn-default btn-xs"
|
||||
href="http://www.meetecho.com/ietf{{schedule.meeting.number}}/recordings#{{item.session.historic_group.acronym.upper}}"
|
||||
title="Meetecho session recording"><img src="{% static 'ietf/images/meetecho-icon.svg' %}" alt="Meetecho Stream" width="12px">
|
||||
</a>
|
||||
{# show stream buttons up till end of session, then show archive buttons #}
|
||||
{% if now < item.timeslot.end_time %}
|
||||
<!-- Jabber -->
|
||||
<a class=""
|
||||
href="xmpp:{{session.jabber_room_name}}@jabber.ietf.org?join"
|
||||
title="Jabber room for {{session.jabber_room_name}}"><span class="fa fa-fw fa-lightbulb-o"></span></a>
|
||||
<!-- Video stream (meetecho) -->
|
||||
{% if item.timeslot.location.video_stream_url %}
|
||||
<a class=""
|
||||
href="{{item.timeslot.location.video_stream_url|format:session }}"
|
||||
title="Meetecho video stream"><span class="fa fa-fw fa-video-camera"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<!-- Audio stream -->
|
||||
{% if item.timeslot.location.audio_stream_url %}
|
||||
<a class=""
|
||||
href="{{item.timeslot.location.audio_stream_url|format:session }}"
|
||||
title="Audio stream"><span class="glyphicon glyphicon-headphones"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<!-- WebEx -->
|
||||
{% if "webex.com/" in session.agenda_note|first_url %}
|
||||
<a class=""
|
||||
href="{{ session.agenda_note|first_url }}"
|
||||
title="Webex session"><span class="fa fa-fw fa-phone"></span>
|
||||
</a>
|
||||
{% elif item.timeslot.location.webex_url %}
|
||||
<a class=""
|
||||
href="{{item.timeslot.location.webex_url|format:session }}"
|
||||
title="Webex session"><span class="fa fa-fw fa-phone"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<!-- Jabber logs -->
|
||||
{% if meeting.number|add:"0" >= 60 %}
|
||||
<a class="" href="https://www.ietf.org/jabber/logs/{{session.jabber_room_name}}?C=M;O=D" title="Jabber logs for {{session.jabber_room_name}}">
|
||||
<span class="fa-stack-1"><i class="fa fa-fw fa-file-o fa-stack-1x"></i><i class="fa fa-fw fa-lightbulb-o fa-stack-sm"></i></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<!-- Recordings -->
|
||||
{% if meeting.number|add:"0" >= 80 %}
|
||||
{% with session.recordings as recordings %}
|
||||
{% if recordings %}
|
||||
{# There's no guaranteed order, so this is a bit messy: #}
|
||||
<!-- First, the audio recordings, if any -->
|
||||
{% for r in recordings %}
|
||||
{% if r.get_href and 'audio' in r.get_href %}
|
||||
<a class="" href="{{ r.get_href }}" title="{{ r.title}}"><span class="fa fa-fw fa-file-audio-o"></span></a>
|
||||
{% endif %}
|
||||
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Audio recording -->
|
||||
{# <a class="btn btn-default btn-xs" href="" title="Audio recording"><span class="fa fa-file-audio-o"></span></a>#}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<!-- Then the youtube recordings -->
|
||||
{% for r in recordings %}
|
||||
{% if r.get_href and 'youtu' in r.get_href %}
|
||||
<a class="" href="{{ r.get_href }}" title="{{ r.title }}"><span class="fa fa-fw fa-file-video-o"></span></a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<!-- Finally, any other recordings -->
|
||||
{% for r in recordings %}
|
||||
{% if r.get_href and not 'audio' in r.get_href and not 'youtu' in r.get_href %}
|
||||
<a class="" href="{{ r.get_href }}" title="{{ r.title }}"><span class="fa fa-fw fa-file-o"></span></a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% if item.timeslot.location.video_stream_url %}
|
||||
<a class=""
|
||||
href="http://www.meetecho.com/ietf{{meeting.number}}/recordings#{{session.historic_group.acronym.upper}}"
|
||||
title="Meetecho session recording"><span class="fd fa-fw fd-meetecho"></span></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<h1>{{ meeting }} : {{ acronym }}
|
||||
{% if meeting.date >= thisweek %}
|
||||
<a class="regular pull-right" title="icalendar entry for {{acronym}}@{{meeting.number}}" href="{% url 'ietf.meeting.views.ical_agenda' num=meeting.number acronym=acronym %}"><span class="fa fa-calendar"></span></a>
|
||||
<a class="regular pull-right" title="icalendar entry for {{acronym}}@{{meeting.number}}" href="{% url 'ietf.meeting.views.ical_agenda' num=meeting.number acronym=acronym %}"><span class="fa fa-fw fa-calendar"></span> </a>
|
||||
{% endif %}
|
||||
</h1>
|
||||
|
||||
|
|
|
@ -1,144 +1,158 @@
|
|||
{% load origin ietf_filters textfilters tz dateformat %}{% origin %}
|
||||
|
||||
{% for session in sessions %}
|
||||
<h2 class="anchor-target" id="session_{{session.pk}}">{% if sessions|length > 1 %}Session {{ forloop.counter }} : {% endif %}
|
||||
{% for time in session.times %}{% if not forloop.first %}, {% endif %} {{time|dateformat:"l Y-m-d H:i T"}} {% if time.tzinfo.zone != "UTC" %}<span class="small">({{time|utc|dateformat:"H:i T"}})</span>{% endif %}{% endfor %}
|
||||
{% if session.cancelled %}<small class="label label-warning">CANCELLED</small>{% else %}{{ session.status }}{% endif %}
|
||||
{% if session.name %} : {{ session.name }}{% endif %}
|
||||
{% if meeting.date >= thisweek %}
|
||||
<a class="regular pull-right" title="icalendar entry for {{acronym}} session {{ forloop.counter }}" href="{% url 'ietf.meeting.views.ical_agenda' num=meeting.number session_id=session.id %}"><span class="fa fa-calendar"></span></a>
|
||||
{% endif %}
|
||||
</h2>
|
||||
{% if session.agenda_note %}<h3>{{session.agenda_note}}</h3>{% endif %}
|
||||
{% with item=session.official_timeslotassignment %}
|
||||
<h2 class="anchor-target" id="session_{{session.pk}}">{% if sessions|length > 1 %}Session {{ forloop.counter }} : {% endif %}
|
||||
{% for time in session.times %}{% if not forloop.first %}, {% endif %} {{time|dateformat:"l Y-m-d H:i T"}} {% if time.tzinfo.zone != "UTC" %}<span class="small">({{time|utc|dateformat:"H:i T"}})</span>{% endif %}{% endfor %}
|
||||
{% if session.cancelled %}<small class="label label-warning">CANCELLED</small>{% else %}{{ session.status }}{% endif %}
|
||||
{% if session.name %} : {{ session.name }}{% endif %}
|
||||
{% if not session.cancelled %}
|
||||
<span class="regular pull-right">
|
||||
{% if meeting.type.slug == 'interim' %}
|
||||
{% include "meeting/interim_session_buttons.html" with show_agenda=False show_empty=False %}
|
||||
{% else %}
|
||||
{% with schedule=meeting.schedule %}
|
||||
{% include "meeting/session_buttons_include.html" %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
<!-- iCalendar item -->
|
||||
{% if now < item.timeslot.end_time %}
|
||||
<a title="icalendar entry for {{acronym}} session {{ forloop.counter }}" href="{% url 'ietf.meeting.views.ical_agenda' num=meeting.number session_id=session.id %}"><span class="fa fa-fw fa-calendar-o"></span> </a>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</h2>
|
||||
{% if session.agenda_note %}<h3>{{session.agenda_note}}</h3>{% endif %}
|
||||
|
||||
{% if can_manage_materials %}
|
||||
{% if session.current_status == 'sched' or session.current_status == 'schedw' %}
|
||||
<div class="buttonlist">
|
||||
{% if can_view_request %}
|
||||
<a class="btn btn-default" href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">Meeting Details</a>
|
||||
{% if can_manage_materials %}
|
||||
{% if session.current_status == 'sched' or session.current_status == 'schedw' %}
|
||||
<div class="buttonlist">
|
||||
{% if can_view_request %}
|
||||
<a class="btn btn-default" href="{% url 'ietf.meeting.views.interim_request_details' number=meeting.number %}">Meeting Details</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if not session.type_counter.agenda %}
|
||||
<span class="label label-warning">This session does not yet have an agenda</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if meeting.type.slug == 'interim' and session.remote_instructions %}
|
||||
<div>
|
||||
<b>Remote instructions:</b>
|
||||
{% if "https://ietf.webex.com" in session.agenda_note|first_url %}
|
||||
<a class=""
|
||||
href="{{ session.agenda_note|first_url }}"
|
||||
title="Webex session"><span class="fa fa-fw fa-phone"></span>
|
||||
</a>
|
||||
{% elif "https://ietf.webex.com" in session.remote_instructions|first_url %}
|
||||
<a class=""
|
||||
href="{{ session.remote_instructions|first_url }}"
|
||||
title="Webex session"><span class="fa fa-fw fa-phone"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{{ session.remote_instructions }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Agenda, Minutes, and Bluesheets</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-condensed table-striped">
|
||||
{% for pres in session.filtered_artifacts %}
|
||||
<tr>
|
||||
{% url 'ietf.doc.views_doc.document_main' name=pres.document.name as url %}
|
||||
<td>
|
||||
<a href="{{pres.document.get_href}}">{{pres.document.title}}</a>
|
||||
<a href="{{url}}">({{ pres.document.name }})</a>
|
||||
</td>
|
||||
{% if user|has_role:"Secretariat" or can_manage_materials %}
|
||||
<td class="col-md-2">
|
||||
{% if pres.document.type.slug == 'minutes' %}
|
||||
{% url 'ietf.meeting.views.upload_session_minutes' session_id=session.pk num=session.meeting.number as upload_url %}
|
||||
{% elif pres.document.type.slug == 'agenda' %}
|
||||
{% url 'ietf.meeting.views.upload_session_agenda' session_id=session.pk num=session.meeting.number as upload_url %}
|
||||
{% else %}
|
||||
{% url 'ietf.meeting.views.upload_session_bluesheets' session_id=session.pk num=session.meeting.number as upload_url %}
|
||||
{% endif %}
|
||||
{% if pres.document.type.slug != 'bluesheets' or user|has_role:"Secretariat" or meeting.type.slug == 'interim' and can_manage_materials %}
|
||||
<a class="btn btn-default btn-sm pull-right" href="{{upload_url}}">Upload Revision</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% if can_manage_materials %}
|
||||
{% if not session.type_counter.agenda %}
|
||||
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_agenda' session_id=session.pk num=session.meeting.number %}">Upload Agenda</a>
|
||||
{% endif %}
|
||||
{% if not session.type_counter.minutes %}
|
||||
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_minutes' session_id=session.pk num=session.meeting.number %}">Upload Minutes</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if user|has_role:"Secretariat" and not session.type_counter.bluesheets or meeting.type.slug == 'interim' and can_manage_materials and not session.type_counter.bluesheets %}
|
||||
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_bluesheets' session_id=session.pk num=session.meeting.number %}">Upload Bluesheets</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if not session.type_counter.agenda %}
|
||||
<span class="label label-warning">This session does not yet have an agenda</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if meeting.type.slug == 'interim' and session.remote_instructions %}
|
||||
<div>
|
||||
<b>Remote instructions:</b>
|
||||
{% if "https://ietf.webex.com" in session.agenda_note|first_url %}
|
||||
<a class=""
|
||||
href="{{ session.agenda_note|first_url }}"
|
||||
title="Webex session"><span class="fa fa-fw fa-phone"></span>
|
||||
</a>
|
||||
{% elif "https://ietf.webex.com" in session.remote_instructions|first_url %}
|
||||
<a class=""
|
||||
href="{{ session.remote_instructions|first_url }}"
|
||||
title="Webex session"><span class="fa fa-fw fa-phone"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{{ session.remote_instructions }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Agenda, Minutes, and Bluesheets</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-condensed table-striped">
|
||||
{% for pres in session.filtered_artifacts %}
|
||||
<tr>
|
||||
{% url 'ietf.doc.views_doc.document_main' name=pres.document.name as url %}
|
||||
<td>
|
||||
<a href="{{pres.document.get_href}}">{{pres.document.title}}</a>
|
||||
<a href="{{url}}">({{ pres.document.name }})</a>
|
||||
</td>
|
||||
{% if user|has_role:"Secretariat" or can_manage_materials %}
|
||||
<td class="col-md-2">
|
||||
{% if pres.document.type.slug == 'minutes' %}
|
||||
{% url 'ietf.meeting.views.upload_session_minutes' session_id=session.pk num=session.meeting.number as upload_url %}
|
||||
{% elif pres.document.type.slug == 'agenda' %}
|
||||
{% url 'ietf.meeting.views.upload_session_agenda' session_id=session.pk num=session.meeting.number as upload_url %}
|
||||
{% else %}
|
||||
{% url 'ietf.meeting.views.upload_session_bluesheets' session_id=session.pk num=session.meeting.number as upload_url %}
|
||||
{% endif %}
|
||||
{% if pres.document.type.slug != 'bluesheets' or user|has_role:"Secretariat" or meeting.type.slug == 'interim' and can_manage_materials %}
|
||||
<a class="btn btn-default btn-sm pull-right" href="{{upload_url}}">Upload Revision</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% if can_manage_materials %}
|
||||
{% if not session.type_counter.agenda %}
|
||||
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_agenda' session_id=session.pk num=session.meeting.number %}">Upload Agenda</a>
|
||||
{% endif %}
|
||||
{% if not session.type_counter.minutes %}
|
||||
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_minutes' session_id=session.pk num=session.meeting.number %}">Upload Minutes</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if user|has_role:"Secretariat" and not session.type_counter.bluesheets or meeting.type.slug == 'interim' and can_manage_materials and not session.type_counter.bluesheets %}
|
||||
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_bluesheets' session_id=session.pk num=session.meeting.number %}">Upload Bluesheets</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" data-toggle="tooltip" title="Drag and drop to reorder slides">Slides</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-condensed table-striped slides" id="slides_{{session.pk}}">
|
||||
<tbody session="{{session.pk}}" addToSession="{% url 'ietf.meeting.views.ajax_add_slides_to_session' session_id=session.pk num=session.meeting.number %}" removeFromSession="{% url 'ietf.meeting.views.ajax_remove_slides_from_session' session_id=session.pk num=session.meeting.number %}" reorderInSession="{% url 'ietf.meeting.views.ajax_reorder_slides_in_session' session_id=session.pk num=session.meeting.number %}">
|
||||
{% for pres in session.filtered_slides %}
|
||||
<tr name="{{pres.document.name}}">
|
||||
{% url 'ietf.doc.views_doc.document_main' name=pres.document.name as url %}
|
||||
<td>
|
||||
<a href="{{pres.document.get_href}}">{{pres.document.title}} </a>
|
||||
<a href="{{url}}">({{ pres.document.name }}) </a>
|
||||
</td>
|
||||
{% if can_manage_materials %}
|
||||
<td class="col-md-2">
|
||||
<a class="btn btn-default btn-sm pull-right" href="{% url 'ietf.meeting.views.upload_session_slides' session_id=session.pk num=session.meeting.number name=pres.document.name %}">Upload Revision</a>
|
||||
<a class="btn btn-default btn-sm pull-right" href="{% url 'ietf.meeting.views.remove_sessionpresentation' session_id=session.pk num=session.meeting.number name=pres.document.name %}">Remove</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if can_manage_materials %}
|
||||
<a id="uploadslides" class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_slides' session_id=session.pk num=session.meeting.number %}">Upload New Slides</a>
|
||||
{% elif request.user.is_authenticated and not session.is_material_submission_cutoff %}
|
||||
<a id="proposeslides" class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.propose_session_slides' session_id=session.pk num=session.meeting.number %}">Propose Slides</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if can_manage_materials %}
|
||||
<div class="panel-footer small">Drag-and-drop to reorder slides</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Drafts
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-condensed table-striped">
|
||||
{% for pres in session.filtered_drafts %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" data-toggle="tooltip" title="Drag and drop to reorder slides">Slides</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-condensed table-striped slides" id="slides_{{session.pk}}">
|
||||
<tbody session="{{session.pk}}" addToSession="{% url 'ietf.meeting.views.ajax_add_slides_to_session' session_id=session.pk num=session.meeting.number %}" removeFromSession="{% url 'ietf.meeting.views.ajax_remove_slides_from_session' session_id=session.pk num=session.meeting.number %}" reorderInSession="{% url 'ietf.meeting.views.ajax_reorder_slides_in_session' session_id=session.pk num=session.meeting.number %}">
|
||||
{% for pres in session.filtered_slides %}
|
||||
<tr name="{{pres.document.name}}">
|
||||
{% url 'ietf.doc.views_doc.document_main' name=pres.document.name as url %}
|
||||
<a href="{{url}}">{{pres.document.title}} ({{ pres.document.name }}) {% if pres.rev %}Version {{pres.rev}}{% endif %}</a>
|
||||
</td>
|
||||
{% if can_manage_materials %}
|
||||
<td class="col-md-2">
|
||||
<a class="btn btn-default btn-sm pull-right" href="{% url 'ietf.meeting.views.remove_sessionpresentation' session_id=session.pk num=session.meeting.number name=pres.document.name %}">Remove</a>
|
||||
<td>
|
||||
<a href="{{pres.document.get_href}}">{{pres.document.title}} </a>
|
||||
<a href="{{url}}">({{ pres.document.name }}) </a>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% if can_manage_materials %}
|
||||
<td class="col-md-2">
|
||||
<a class="btn btn-default btn-sm pull-right" href="{% url 'ietf.meeting.views.upload_session_slides' session_id=session.pk num=session.meeting.number name=pres.document.name %}">Upload Revision</a>
|
||||
<a class="btn btn-default btn-sm pull-right" href="{% url 'ietf.meeting.views.remove_sessionpresentation' session_id=session.pk num=session.meeting.number name=pres.document.name %}">Remove</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if can_manage_materials %}
|
||||
<a id="uploadslides" class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_slides' session_id=session.pk num=session.meeting.number %}">Upload New Slides</a>
|
||||
{% elif request.user.is_authenticated and not session.is_material_submission_cutoff %}
|
||||
<a id="proposeslides" class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.propose_session_slides' session_id=session.pk num=session.meeting.number %}">Propose Slides</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if can_manage_materials %}
|
||||
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.add_session_drafts' session_id=session.pk num=session.meeting.number %}">
|
||||
Link additional drafts to session
|
||||
</a>
|
||||
<div class="panel-footer small">Drag-and-drop to reorder slides</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Drafts
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-condensed table-striped">
|
||||
{% for pres in session.filtered_drafts %}
|
||||
<tr>
|
||||
<td>
|
||||
{% url 'ietf.doc.views_doc.document_main' name=pres.document.name as url %}
|
||||
<a href="{{url}}">{{pres.document.title}} ({{ pres.document.name }}) {% if pres.rev %}Version {{pres.rev}}{% endif %}</a>
|
||||
</td>
|
||||
{% if can_manage_materials %}
|
||||
<td class="col-md-2">
|
||||
<a class="btn btn-default btn-sm pull-right" href="{% url 'ietf.meeting.views.remove_sessionpresentation' session_id=session.pk num=session.meeting.number name=pres.document.name %}">Remove</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% if can_manage_materials %}
|
||||
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.add_session_drafts' session_id=session.pk num=session.meeting.number %}">
|
||||
Link additional drafts to session
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
|
|
|
@ -20,7 +20,14 @@
|
|||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
|
||||
<h1>Upcoming Meetings</h1>
|
||||
<h1>Upcoming Meetings
|
||||
<span class="regular pull-right">
|
||||
<a title="iCalendar subscription for upcoming meetings" href="webcal://{{request.get_host}}{% url 'ietf.meeting.views.upcoming_ical' %}">
|
||||
<span class="fa fa-stack-1"><i class="fa fa-fw fa-calendar-o fa-stack-1x"></i><i class="fa fa-fw fa-repeat fa-stack-xs"></i></span>
|
||||
</a>
|
||||
<a title="iCalendar entry for upcoming meetings" href="{% url 'ietf.meeting.views.upcoming_ical' %}"><span class="fa fa-calendar"></span></a>
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p>For more on regular IETF meetings see <a href="https://www.ietf.org/meeting/upcoming.html">here</a></p>
|
||||
|
||||
|
@ -60,7 +67,7 @@
|
|||
{% with meeting=entry %}
|
||||
<td>{{ meeting.date }} - {{ meeting.end }}</td>
|
||||
<td>ietf</td>
|
||||
<td><a href="{% url 'ietf.meeting.views.agenda' num=meeting.number %}">IETF {{ meeting.number }}</a></td>
|
||||
<td><a class="ietf-meeting-link" href="{% url 'ietf.meeting.views.agenda' num=meeting.number %}">IETF {{ meeting.number }}</a></td>
|
||||
<td></td>
|
||||
{% endwith %}
|
||||
{% elif entry|classname == 'Session' %}
|
||||
|
@ -68,11 +75,17 @@
|
|||
<td>{{ session.official_timeslotassignment.timeslot.utc_start_time | date:"Y-m-d H:i"}} - {{ session.official_timeslotassignment.timeslot.utc_end_time | date:"H:i e" }}</td>
|
||||
<td><a href="{% url 'ietf.group.views.group_home' acronym=session.group.acronym %}">{{ session.group.acronym }}</a></td>
|
||||
<td>
|
||||
<a href="{% url 'ietf.meeting.views.session_details' num=session.meeting.number acronym=session.group.acronym %}">{{ session.meeting.number }}{% if session.current_status == 'canceled' %} <span class="label label-warning">CANCELLED</span>{% endif %}</a>
|
||||
</td>
|
||||
<td class='text-right'>
|
||||
{% include "meeting/interim_session_buttons.html" %}
|
||||
<a class="interim-meeting-link" href="{% url 'ietf.meeting.views.session_details' num=session.meeting.number acronym=session.group.acronym %}">{{ session.meeting.number }}</a>
|
||||
</td>
|
||||
{% if session.current_status == 'canceled' %}
|
||||
<td class='text-right'>
|
||||
<span class="label label-warning">CANCELLED</span>
|
||||
</td>
|
||||
{% else %}
|
||||
<td class='text-right'>
|
||||
{% include "meeting/interim_session_buttons.html" with show_agenda=True %}
|
||||
</td>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<td><span class="label-warning">Unexpected entry type: {{entry|classname}}</span></td>
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
<h2 class="anchor-target" id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://datatracker.ietf.org/doc/rfc2026/">The Internet Standards Process (RFC 2026)</a></li>
|
||||
<li><a href="https://datatracker.ietf.org/doc/rfc8713/">IAB, IESG, IETF Trust, and IETF LLC Selection, Confirmation, and Recall Process: Operation of the IETF Nominating and Recall Committees (RFC 8713) (Also BCP10)
|
||||
<li><a href="https://datatracker.ietf.org/doc/rfc8713/">IAB, IESG, IETF Trust, and IETF LLC Selection, Confirmation, and Recall Process: Operation of the IETF Nominating and Recall Committees (RFC 8713) (Also BCP10)</a></li>
|
||||
<li><a href="https://datatracker.ietf.org/doc/rfc3797/">Publicly Verifiable Nominations Committee (NomCom) Random Selection (RFC 3797)</a></li>
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -84,8 +84,10 @@
|
|||
{% if alias_data %}
|
||||
<table class="table table-condensed">
|
||||
<thead>
|
||||
<th>Affiliation</th>
|
||||
<th>Alias</th>
|
||||
<tr>
|
||||
<th>Affiliation</th>
|
||||
<th>Alias</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
{% for name, alias in alias_data %}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
{# Copyright The IETF Trust 2015, All Rights Reserved #}{% load origin %}{% origin %}
|
||||
<p>
|
||||
|
||||
Please send reports about submission problems to
|
||||
<a href="mailto:ietf-draft-submission@ietf.org">ietf-action@ietf.org</a>, or, if you feel
|
||||
this is a bug, please report it to the Tools Team using the Bug Report links at the bottom
|
||||
of the page.
|
||||
Please send reports about submission tool bugs to the Tools Team using one
|
||||
of the Bug Report links at the bottom of the page.
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
If you need to request manual posting of an Internet-Draft, please send the
|
||||
draft and the reason for manual posting to <a href="mailto:idsubmission@ietf.org">idsubmission@ietf.org</a>.
|
||||
|
||||
</p>
|
||||
|
|
|
@ -162,14 +162,7 @@
|
|||
|
||||
<h3>Problem report</h3>
|
||||
|
||||
<p>
|
||||
|
||||
Please send reports about submission problems to
|
||||
<a href="mailto:ietf-draft-submission@ietf.org">ietf-action@ietf.org</a>, or, if you feel
|
||||
there is a bug, please report it to the Tools Team using the Bug Report links at the bottom
|
||||
of the page.
|
||||
|
||||
</p>
|
||||
{% include "submit/problem-reports-footer.html" %}
|
||||
|
||||
<p>
|
||||
The specification for this tool can be found in <a href="https://www.ietf.org/rfc/rfc4228.txt?number=4228">RFC 4228</a>.
|
||||
|
|
Loading…
Reference in a new issue