More fixes

- Legacy-Id: 19742
This commit is contained in:
Lars Eggert 2021-12-02 11:07:50 +00:00
parent e3b430d2ec
commit 406aa1e5a0
12 changed files with 1842 additions and 552 deletions

View file

@ -1,439 +1,514 @@
# Copyright The IETF Trust 2015-2020, All Rights Reserved
# -*- coding: utf-8 -*-
from pyquery import PyQuery
from http.cookies import SimpleCookie
from django.urls import reverse as urlreverse
from django.conf import settings
import debug # pyflakes:ignore
import debug # pyflakes:ignore
from ietf.utils.test_utils import TestCase
class CookieTests(TestCase):
def test_settings_defaults(self):
r = self.client.get(urlreverse("ietf.cookies.views.preferences"))
self.assertEqual(r.status_code, 200)
self.assertListEqual([], list(r.cookies.keys()))
q = PyQuery(r.content)
if settings.USER_PREFERENCE_DEFAULTS['full_draft'] == 'off':
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
else:
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/14"]').contents(), ['14 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/14"]').contents(), ['14 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/off"]').contents(), ['Off'])
def q(r, q):
return PyQuery(r.content)(
'div a.active[href="/accounts/settings/' + q + '"]'
).text()
def test_settings_defaults_from_cookies(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '7', str('expires_soon') : 7, str('left_menu'): 'on', })
r = self.client.get(urlreverse("ietf.cookies.views.preferences"))
def qn(r, q):
return PyQuery(r.content)(
'div a.active[href^="/accounts/settings/' + q + '"]'
).text()
class CookieTests(TestCase):
def r(self, c, **kwargs):
r = self.client.get(urlreverse("ietf.cookies.views." + c, **kwargs))
self.assertEqual(r.status_code, 200)
return r
def test_settings_defaults(self):
r = self.r("preferences")
self.assertListEqual([], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/7"]').contents(), ['7 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/7"]').contents(), ['7 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/on"]').contents(), ['On'])
def test_settings_values_from_cookies_garbage(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'foo', str('new_enough') : 'foo', str('expires_soon') : 'foo', str('left_menu'): 'foo', })
r = self.client.get(urlreverse("ietf.cookies.views.preferences"))
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
if settings.USER_PREFERENCE_DEFAULTS['full_draft'] == 'off':
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
if settings.USER_PREFERENCE_DEFAULTS["full_draft"] == "off":
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
else:
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/14"]').contents(), ['14 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/14"]').contents(), ['14 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/off"]').contents(), ['Off'])
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(q(r, "new_enough/14"), r"\s*14 days\s*")
self.assertRegex(q(r, "expires_soon/14"), r"\s*14 days\s*")
self.assertRegex(q(r, "left_menu/off"), r"\s*Off\s*")
def test_settings_defaults_from_cookies(self):
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "7",
str("expires_soon"): 7,
str("left_menu"): "on",
}
)
r = self.r("preferences")
self.assertListEqual([], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/7"), r"\s*7 days\s*")
self.assertRegex(q(r, "expires_soon/7"), r"\s*7 days\s*")
self.assertRegex(q(r, "left_menu/on"), r"\s*On\s*")
def test_settings_values_from_cookies_garbage(self):
self.client.cookies = SimpleCookie(
{
str("full_draft"): "foo",
str("new_enough"): "foo",
str("expires_soon"): "foo",
str("left_menu"): "foo",
}
)
r = self.r("preferences")
if settings.USER_PREFERENCE_DEFAULTS["full_draft"] == "off":
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
else:
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(q(r, "new_enough/14"), r"\s*14 days\s*")
self.assertRegex(q(r, "expires_soon/14"), r"\s*14 days\s*")
self.assertRegex(q(r, "left_menu/off"), r"\s*Off\s*")
def test_settings_values_from_cookies_random(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'zappa', str('new_enough') : '365', str('expires_soon') : '5', str('left_menu'): 'zappa', })
r = self.client.get(urlreverse("ietf.cookies.views.preferences"))
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
if settings.USER_PREFERENCE_DEFAULTS['full_draft'] == 'off':
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.client.cookies = SimpleCookie(
{
str("full_draft"): "zappa",
str("new_enough"): "365",
str("expires_soon"): "5",
str("left_menu"): "zappa",
}
)
r = self.r("preferences")
if settings.USER_PREFERENCE_DEFAULTS["full_draft"] == "off":
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
else:
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href^="/accounts/settings/new_enough/"]').contents(), [])
self.assertEqual(q('div a.active[href^="/accounts/settings/expires_soon/"]').contents(), [])
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/off"]').contents(), ['Off'])
#
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertNotRegexpMatches(r.content, r'ietf-highlight-y.*new_enough')
# self.assertNotRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon')
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(qn(r, "new_enough"), r"\s*\s*")
self.assertRegex(qn(r, "expires_soon"), r"\s*\s*")
self.assertRegex(q(r, "left_menu/off"), r"\s*Off\s*")
def test_settings_values_from_cookies_1(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'on', str('new_enough') : '90', str('expires_soon') : 7, str('left_menu'): 'off', })
r = self.client.get(urlreverse("ietf.cookies.views.preferences"))
self.assertEqual(r.status_code, 200)
self.client.cookies = SimpleCookie(
{
str("full_draft"): "on",
str("new_enough"): "90",
str("expires_soon"): 7,
str("left_menu"): "off",
}
)
r = self.r("preferences")
self.assertListEqual([], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/90"]').contents(), ['90 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/7"]').contents(), ['7 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/off"]').contents(), ['Off'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*on')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*90 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*7 days')
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(q(r, "new_enough/90"), r"\s*90 days\s*")
self.assertRegex(q(r, "expires_soon/7"), r"\s*7 days\s*")
self.assertRegex(q(r, "left_menu/off"), r"\s*Off\s*")
def test_settings_values_from_cookies_2(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '60', str('expires_soon') : 14, str('left_menu'): 'on', })
r = self.client.get(urlreverse("ietf.cookies.views.preferences"))
self.assertEqual(r.status_code, 200)
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "60",
str("expires_soon"): 14,
str("left_menu"): "on",
}
)
r = self.r("preferences")
self.assertListEqual([], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/60"]').contents(), ['60 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/14"]').contents(), ['14 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/on"]').contents(), ['On'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*60 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*14 days')
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/60"), r"\s*60 days\s*")
self.assertRegex(q(r, "expires_soon/14"), r"\s*14 days\s*")
self.assertRegex(q(r, "left_menu/on"), r"\s*On\s*")
def test_settings_values_from_cookies_3(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'on', str('new_enough') : '30', str('expires_soon') : 21, str('left_menu'): 'off'})
r = self.client.get(urlreverse("ietf.cookies.views.preferences"))
self.assertEqual(r.status_code, 200)
self.client.cookies = SimpleCookie(
{
str("full_draft"): "on",
str("new_enough"): "30",
str("expires_soon"): 21,
str("left_menu"): "off",
}
)
r = self.r("preferences")
self.assertListEqual([], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/30"]').contents(), ['30 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/21"]').contents(), ['21 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/off"]').contents(), ['Off'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*on')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*30 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*21 days')
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(q(r, "new_enough/30"), r"\s*30 days\s*")
self.assertRegex(q(r, "expires_soon/21"), r"\s*21 days\s*")
self.assertRegex(q(r, "left_menu/off"), r"\s*Off\s*")
def test_settings_values_from_cookies_4(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '21', str('expires_soon') : 30, str('left_menu'): 'on', })
r = self.client.get(urlreverse("ietf.cookies.views.preferences"))
self.assertEqual(r.status_code, 200)
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "21",
str("expires_soon"): 30,
str("left_menu"): "on",
}
)
r = self.r("preferences")
self.assertListEqual([], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/21"]').contents(), ['21 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/30"]').contents(), ['30 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/on"]').contents(), ['On'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*21 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*30 days')
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/21"), r"\s*21 days\s*")
self.assertRegex(q(r, "expires_soon/30"), r"\s*30 days\s*")
self.assertRegex(q(r, "left_menu/on"), r"\s*On\s*")
def test_settings_values_from_cookies_5(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'on', str('new_enough') : '14', str('expires_soon') : 60, str('left_menu'): 'off', })
r = self.client.get(urlreverse("ietf.cookies.views.preferences"))
self.assertEqual(r.status_code, 200)
self.client.cookies = SimpleCookie(
{
str("full_draft"): "on",
str("new_enough"): "14",
str("expires_soon"): 60,
str("left_menu"): "off",
}
)
r = self.r("preferences")
self.assertListEqual([], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/14"]').contents(), ['14 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/60"]').contents(), ['60 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/off"]').contents(), ['Off'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*on')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*14 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*60 days')
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(q(r, "new_enough/14"), r"\s*14 days\s*")
self.assertRegex(q(r, "expires_soon/60"), r"\s*60 days\s*")
self.assertRegex(q(r, "left_menu/off"), r"\s*Off\s*")
def test_settings_values_from_cookies_6(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '7', str('expires_soon') : 90, str('left_menu'): 'on', })
r = self.client.get(urlreverse("ietf.cookies.views.preferences"))
self.assertEqual(r.status_code, 200)
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "7",
str("expires_soon"): 90,
str("left_menu"): "on",
}
)
r = self.r("preferences")
self.assertListEqual([], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/7"]').contents(), ['7 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/90"]').contents(), ['90 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/on"]').contents(), ['On'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*7 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*90 days')
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/7"), r"\s*7 days\s*")
self.assertRegex(q(r, "expires_soon/90"), r"\s*90 days\s*")
self.assertRegex(q(r, "left_menu/on"), r"\s*On\s*")
def test_full_draft(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '14', str('expires_soon') : 14})
r = self.client.get(urlreverse("ietf.cookies.views.full_draft")) # no value: reset
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('full_draft')].value, '')
self.assertListEqual([str('full_draft')], list(r.cookies.keys()))
q = PyQuery(r.content)
if settings.USER_PREFERENCE_DEFAULTS['full_draft'] == 'off':
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "14",
str("expires_soon"): 14,
}
)
r = self.r("full_draft") # no value: reset
self.assertEqual(r.cookies[str("full_draft")].value, "")
self.assertListEqual([str("full_draft")], list(r.cookies.keys()))
if settings.USER_PREFERENCE_DEFAULTS["full_draft"] == "off":
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
else:
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/14"]').contents(), ['14 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/14"]').contents(), ['14 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*14 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*14 days')
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(q(r, "new_enough/14"), r"\s*14 days\s*")
self.assertRegex(q(r, "expires_soon/14"), r"\s*14 days\s*")
def test_full_draft_on(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '14', str('expires_soon') : 14})
r = self.client.get(urlreverse("ietf.cookies.views.full_draft", kwargs=dict(enabled="on")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('full_draft')].value, 'on')
self.assertListEqual([str('full_draft')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*on')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "14",
str("expires_soon"): 14,
}
)
r = self.r("full_draft", kwargs=dict(enabled="on"))
self.assertEqual(r.cookies[str("full_draft")].value, "on")
self.assertListEqual([str("full_draft")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
def test_full_draft_off(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '14', str('expires_soon') : 14})
r = self.client.get(urlreverse("ietf.cookies.views.full_draft", kwargs=dict(enabled="off")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('full_draft')].value, 'off')
self.assertListEqual([str('full_draft')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
# self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/14"]').contents(), ['14 days'])
# self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/14"]').contents(), ['14 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "14",
str("expires_soon"): 14,
}
)
r = self.r("full_draft", kwargs=dict(enabled="off"))
self.assertEqual(r.cookies[str("full_draft")].value, "off")
self.assertListEqual([str("full_draft")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
def test_full_draft_foo(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '14', str('expires_soon') : 14})
r = self.client.get(urlreverse("ietf.cookies.views.full_draft", kwargs=dict(enabled="foo")))
self.assertEqual(r.status_code, 200)
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "14",
str("expires_soon"): 14,
}
)
r = self.r("full_draft", kwargs=dict(enabled="foo"))
self.assertListEqual([], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
# self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/14"]').contents(), ['14 days'])
# self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/14"]').contents(), ['14 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
def test_left_menu(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '14', str('expires_soon') : 14, str('left_menu'): 'on', })
r = self.client.get(urlreverse("ietf.cookies.views.left_menu")) # no value: reset
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('left_menu')].value, '')
self.assertListEqual([str('left_menu')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/14"]').contents(), ['14 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/14"]').contents(), ['14 days'])
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "14",
str("expires_soon"): 14,
str("left_menu"): "on",
}
)
r = self.r("left_menu") # no value: reset
self.assertEqual(r.cookies[str("left_menu")].value, "")
self.assertListEqual([str("left_menu")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "left_menu/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/14"), r"\s*14 days\s*")
self.assertRegex(q(r, "expires_soon/14"), r"\s*14 days\s*")
def test_left_menu_on(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '14', str('expires_soon') : 14, str('left_menu'): 'off', })
r = self.client.get(urlreverse("ietf.cookies.views.left_menu", kwargs=dict(enabled="on")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('left_menu')].value, 'on')
self.assertListEqual([str('left_menu')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/on"]').contents(), ['On'])
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "14",
str("expires_soon"): 14,
str("left_menu"): "off",
}
)
r = self.r("left_menu", kwargs=dict(enabled="on"))
self.assertEqual(r.cookies[str("left_menu")].value, "on")
self.assertListEqual([str("left_menu")], list(r.cookies.keys()))
self.assertRegex(q(r, "left_menu/on"), r"\s*On\s*")
def test_left_menu_off(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '14', str('expires_soon') : 14, str('left_menu'): 'off', })
r = self.client.get(urlreverse("ietf.cookies.views.left_menu", kwargs=dict(enabled="off")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('left_menu')].value, 'off')
self.assertListEqual([str('left_menu')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/off"]').contents(), ['Off'])
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "14",
str("expires_soon"): 14,
str("left_menu"): "off",
}
)
r = self.r("left_menu", kwargs=dict(enabled="off"))
self.assertEqual(r.cookies[str("left_menu")].value, "off")
self.assertListEqual([str("left_menu")], list(r.cookies.keys()))
self.assertRegex(q(r, "left_menu/off"), r"\s*Off\s*")
def test_left_menu_foo(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '14', str('expires_soon') : 14, str('left_menu'): 'off', })
r = self.client.get(urlreverse("ietf.cookies.views.left_menu", kwargs=dict(enabled="foo")))
self.assertEqual(r.status_code, 200)
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "14",
str("expires_soon"): 14,
str("left_menu"): "off",
}
)
r = self.r("left_menu", kwargs=dict(enabled="foo"))
self.assertListEqual([], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/left_menu/off"]').contents(), ['Off'])
self.assertRegex(q(r, "left_menu/off"), r"\s*Off\s*")
def test_new_enough(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '14', str('expires_soon') : 14})
r = self.client.get(urlreverse("ietf.cookies.views.new_enough")) # no value: reset
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('new_enough')].value, '')
self.assertListEqual([str('new_enough')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/14"]').contents(), ['14 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/14"]').contents(), ['14 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*14 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*14 days')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "14",
str("expires_soon"): 14,
}
)
r = self.r("new_enough") # no value: reset
self.assertEqual(r.cookies[str("new_enough")].value, "")
self.assertListEqual([str("new_enough")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/14"), r"\s*14 days\s*")
self.assertRegex(q(r, "expires_soon/14"), r"\s*14 days\s*")
def test_new_enough_7(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'on', str('new_enough') : '14', str('expires_soon') : 21})
r = self.client.get(urlreverse("ietf.cookies.views.new_enough", kwargs=dict(days="7")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('new_enough')].value, '7')
self.assertListEqual([str('new_enough')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/7"]').contents(), ['7 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/21"]').contents(), ['21 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*on')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*7 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*21 days')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "on",
str("new_enough"): "14",
str("expires_soon"): 21,
}
)
r = self.r("new_enough", kwargs=dict(days="7"))
self.assertEqual(r.cookies[str("new_enough")].value, "7")
self.assertListEqual([str("new_enough")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(q(r, "new_enough/7"), r"\s*7 days\s*")
self.assertRegex(q(r, "expires_soon/21"), r"\s*21 days\s*")
def test_new_enough_14(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'on', str('new_enough') : '7', str('expires_soon') : 99})
r = self.client.get(urlreverse("ietf.cookies.views.new_enough", kwargs=dict(days="14")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('new_enough')].value, '14')
self.assertListEqual([str('new_enough')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/14"]').contents(), ['14 days'])
self.assertEqual(q('div a.active[href^="/accounts/settings/expires_soon/14"]').contents(), [])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*on')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*14 days')
# self.assertNotRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "on",
str("new_enough"): "7",
str("expires_soon"): 99,
}
)
r = self.r("new_enough", kwargs=dict(days="14"))
self.assertEqual(r.cookies[str("new_enough")].value, "14")
self.assertListEqual([str("new_enough")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(q(r, "new_enough/14"), r"\s*14 days\s*")
self.assertRegex(qn(r, "expires_soon/14"), r"\s*\s*")
def test_new_enough_21(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'on', str('new_enough') : '14', str('expires_soon') : 90})
r = self.client.get(urlreverse("ietf.cookies.views.new_enough", kwargs=dict(days="21")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('new_enough')].value, '21')
self.assertListEqual([str('new_enough')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/21"]').contents(), ['21 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/90"]').contents(), ['90 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*on')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*21 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*90 days')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "on",
str("new_enough"): "14",
str("expires_soon"): 90,
}
)
r = self.r("new_enough", kwargs=dict(days="21"))
self.assertEqual(r.cookies[str("new_enough")].value, "21")
self.assertListEqual([str("new_enough")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(q(r, "new_enough/21"), r"\s*21 days\s*")
self.assertRegex(q(r, "expires_soon/90"), r"\s*90 days\s*")
def test_new_enough_30(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '14', str('expires_soon') : 7})
r = self.client.get(urlreverse("ietf.cookies.views.new_enough", kwargs=dict(days="30")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('new_enough')].value, '30')
self.assertListEqual([str('new_enough')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/30"]').contents(), ['30 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/7"]').contents(), ['7 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*30 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*7 days')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "14",
str("expires_soon"): 7,
}
)
r = self.r("new_enough", kwargs=dict(days="30"))
self.assertEqual(r.cookies[str("new_enough")].value, "30")
self.assertListEqual([str("new_enough")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/30"), r"\s*30 days\s*")
self.assertRegex(q(r, "expires_soon/7"), r"\s*7 days\s*")
def test_new_enough_60(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '14', str('expires_soon') : 14})
r = self.client.get(urlreverse("ietf.cookies.views.new_enough", kwargs=dict(days="60")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('new_enough')].value, '60')
self.assertListEqual([str('new_enough')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/60"]').contents(), ['60 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/14"]').contents(), ['14 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*60 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*14 days')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "14",
str("expires_soon"): 14,
}
)
r = self.r("new_enough", kwargs=dict(days="60"))
self.assertEqual(r.cookies[str("new_enough")].value, "60")
self.assertListEqual([str("new_enough")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/60"), r"\s*60 days\s*")
self.assertRegex(q(r, "expires_soon/14"), r"\s*14 days\s*")
def test_new_enough_90(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('new_enough') : '22', str('expires_soon') : 60})
r = self.client.get(urlreverse("ietf.cookies.views.new_enough", kwargs=dict(days="90")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('new_enough')].value, '90')
self.assertListEqual([str('new_enough')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/90"]').contents(), ['90 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/60"]').contents(), ['60 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*90 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*60 days')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("new_enough"): "22",
str("expires_soon"): 60,
}
)
r = self.r("new_enough", kwargs=dict(days="90"))
self.assertEqual(r.cookies[str("new_enough")].value, "90")
self.assertListEqual([str("new_enough")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/90"), r"\s*90 days\s*")
self.assertRegex(q(r, "expires_soon/60"), r"\s*60 days\s*")
def test_expires_soon(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('expires_soon') : '14', str('new_enough') : 14})
r = self.client.get(urlreverse("ietf.cookies.views.expires_soon")) # no value: reset
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('expires_soon')].value, '')
self.assertListEqual([str('expires_soon')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/14"]').contents(), ['14 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/14"]').contents(), ['14 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*14 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*14 days')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("expires_soon"): "14",
str("new_enough"): 14,
}
)
r = self.r("expires_soon") # no value: reset
self.assertEqual(r.cookies[str("expires_soon")].value, "")
self.assertListEqual([str("expires_soon")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/14"), r"\s*14 days\s*")
self.assertRegex(q(r, "expires_soon/14"), r"\s*14 days\s*")
def test_expires_soon_7(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'on', str('expires_soon') : '14', str('new_enough') : 21})
r = self.client.get(urlreverse("ietf.cookies.views.expires_soon", kwargs=dict(days="7")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('expires_soon')].value, '7')
self.assertListEqual([str('expires_soon')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/21"]').contents(), ['21 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/7"]').contents(), ['7 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*on')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*7 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*21 days')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "on",
str("expires_soon"): "14",
str("new_enough"): 21,
}
)
r = self.r("expires_soon", kwargs=dict(days="7"))
self.assertEqual(r.cookies[str("expires_soon")].value, "7")
self.assertListEqual([str("expires_soon")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(q(r, "new_enough/21"), r"\s*21 days\s*")
self.assertRegex(q(r, "expires_soon/7"), r"\s*7 days\s*")
def test_expires_soon_14(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'on', str('expires_soon') : '7', str('new_enough') : 99})
r = self.client.get(urlreverse("ietf.cookies.views.expires_soon", kwargs=dict(days="14")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('expires_soon')].value, '14')
self.assertListEqual([str('expires_soon')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href^="/accounts/settings/new_enough/"]').contents(), [])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/14"]').contents(),['14 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*on')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*14 days')
# self.assertNotRegexpMatches(r.content, r'ietf-highlight-y.*new_enough')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "on",
str("expires_soon"): "7",
str("new_enough"): 99,
}
)
r = self.r("expires_soon", kwargs=dict(days="14"))
self.assertEqual(r.cookies[str("expires_soon")].value, "14")
self.assertListEqual([str("expires_soon")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(qn(r, "new_enough"), r"\s*\s*")
self.assertRegex(q(r, "expires_soon/14"), r"\s*14 days\s*")
def test_expires_soon_21(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'on', str('expires_soon') : '14', str('new_enough') : 90})
r = self.client.get(urlreverse("ietf.cookies.views.expires_soon", kwargs=dict(days="21")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('expires_soon')].value, '21')
self.assertListEqual([str('expires_soon')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/on"]').contents(), ['On'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/90"]').contents(), ['90 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/21"]').contents(), ['21 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*on')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*21 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*90 days')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "on",
str("expires_soon"): "14",
str("new_enough"): 90,
}
)
r = self.r("expires_soon", kwargs=dict(days="21"))
self.assertEqual(r.cookies[str("expires_soon")].value, "21")
self.assertListEqual([str("expires_soon")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/on"), r"\s*On\s*")
self.assertRegex(q(r, "new_enough/90"), r"\s*90 days\s*")
self.assertRegex(q(r, "expires_soon/21"), r"\s*21 days\s*")
def test_expires_soon_30(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('expires_soon') : '14', str('new_enough') : 7})
r = self.client.get(urlreverse("ietf.cookies.views.expires_soon", kwargs=dict(days="30")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('expires_soon')].value, '30')
self.assertListEqual([str('expires_soon')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/7"]').contents(), ['7 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/30"]').contents(), ['30 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*30 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*7 days')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("expires_soon"): "14",
str("new_enough"): 7,
}
)
r = self.r("expires_soon", kwargs=dict(days="30"))
self.assertEqual(r.cookies[str("expires_soon")].value, "30")
self.assertListEqual([str("expires_soon")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/7"), r"\s*7 days\s*")
self.assertRegex(q(r, "expires_soon/30"), r"\s*30 days\s*")
def test_expires_soon_60(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('expires_soon') : '14', str('new_enough') : 14})
r = self.client.get(urlreverse("ietf.cookies.views.expires_soon", kwargs=dict(days="60")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('expires_soon')].value, '60')
self.assertListEqual([str('expires_soon')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/14"]').contents(), ['14 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/60"]').contents(), ['60 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*60 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*14 days')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("expires_soon"): "14",
str("new_enough"): 14,
}
)
r = self.r("expires_soon", kwargs=dict(days="60"))
self.assertEqual(r.cookies[str("expires_soon")].value, "60")
self.assertListEqual([str("expires_soon")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/14"), r"\s*14 days\s*")
self.assertRegex(q(r, "expires_soon/60"), r"\s*60 days\s*")
def test_expires_soon_90(self):
self.client.cookies = SimpleCookie({str('full_draft'): 'off', str('expires_soon') : '22', str('new_enough') : 60})
r = self.client.get(urlreverse("ietf.cookies.views.expires_soon", kwargs=dict(days="90")))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.cookies[str('expires_soon')].value, '90')
self.assertListEqual([str('expires_soon')], list(r.cookies.keys()))
q = PyQuery(r.content)
self.assertEqual(q('div a.active[href="/accounts/settings/full_draft/off"]').contents(), ['Off'])
self.assertEqual(q('div a.active[href="/accounts/settings/new_enough/60"]').contents(), ['60 days'])
self.assertEqual(q('div a.active[href="/accounts/settings/expires_soon/90"]').contents(), ['90 days'])
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*full_draft.*off')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*expires_soon.*90 days')
# self.assertRegexpMatches(r.content, r'ietf-highlight-y.*new_enough.*60 days')
self.client.cookies = SimpleCookie(
{
str("full_draft"): "off",
str("expires_soon"): "22",
str("new_enough"): 60,
}
)
r = self.r("expires_soon", kwargs=dict(days="90"))
self.assertEqual(r.cookies[str("expires_soon")].value, "90")
self.assertListEqual([str("expires_soon")], list(r.cookies.keys()))
self.assertRegex(q(r, "full_draft/off"), r"\s*Off\s*")
self.assertRegex(q(r, "new_enough/60"), r"\s*60 days\s*")
self.assertRegex(q(r, "expires_soon/90"), r"\s*90 days\s*")

View file

@ -0,0 +1,826 @@
/* globals alert, jQuery, moment */
jQuery(document).ready(function () {
let content = jQuery(".edit-meeting-schedule");
/* Drag data stored via the drag event dataTransfer interface is only accessible on
* dragstart and dragend events. Other drag events can see only the MIME types that have
* data. Use a non-registered type to identify our session drags. Unregistered MIME
* types are strongly discouraged by RFC6838, but we are not actually attempting to
* exchange data with anything outside this script so that really does not apply. */
const dnd_mime_type = 'text/x.session-drag';
const meetingTimeZone = content.data('timezone');
const lockSeconds = Number(content.data('lock-seconds') || 0);
function reportServerError(xhr, textStatus, error) {
let errorText = error || textStatus;
if (xhr && xhr.responseText)
errorText += "\n\n" + xhr.responseText;
alert("Error: " + errorText);
}
/**
* Time to treat as current time for computing whether to lock timeslots
* @returns {*} Moment object equal to lockSeconds in the future
*/
function effectiveNow() {
return moment().add(lockSeconds, 'seconds');
}
let sessions = content.find(".session").not(".readonly");
let sessionConstraints = sessions.find('.constraints > span');
let timeslots = content.find(".timeslot");
let timeslotLabels = content.find(".time-label");
let swapDaysButtons = content.find('.swap-days');
let swapTimeslotButtons = content.find('.swap-timeslot-col');
let days = content.find(".day-flow .day");
let officialSchedule = content.hasClass('official-schedule');
// hack to work around lack of position sticky support in old browsers, see https://caniuse.com/#feat=css-sticky
if (content.find(".scheduling-panel").css("position") != "sticky") {
content.find(".scheduling-panel").css("position", "fixed");
content.css("padding-bottom", "14em");
}
/**
* Parse a timestamp using meeting-local time zone if the timestamp does not specify one.
*/
function parseISOTimestamp(s) {
return moment.tz(s, moment.ISO_8601, meetingTimeZone);
}
function startMoment(timeslot) {
return parseISOTimestamp(timeslot.data('start'));
}
function endMoment(timeslot) {
return parseISOTimestamp(timeslot.data('end'));
}
function findTimeslotsOverlapping(intervals) {
let res = [];
timeslots.each(function () {
var timeslot = jQuery(this);
let start = startMoment(timeslot);
let end = endMoment(timeslot);
for (let i = 0; i < intervals.length; ++i) {
if (end >= intervals[i][0] && intervals[i][1] >= start) {
res.push(timeslot);
break;
}
}
});
return res;
}
// selecting
function selectSessionElement(element) {
sessions.removeClass("other-session-selected");
if (element) {
sessions.not(element).removeClass("selected");
jQuery(element).addClass("selected");
showConstraintHints(element);
showTimeSlotTypeIndicators(element.dataset.type);
let sessionInfoContainer = content.find(".scheduling-panel .session-info-container");
sessionInfoContainer.html(jQuery(element).find(".session-info").html());
sessionInfoContainer.find("[data-original-title]").tooltip();
sessionInfoContainer.find(".time").text(jQuery(element).closest(".timeslot").data('scheduledatlabel'));
sessionInfoContainer.find(".other-session").each(function () {
let otherSessionElement = sessions.filter("#session" + this.dataset.othersessionid).first();
let scheduledAt = otherSessionElement.closest(".timeslot").data('scheduledatlabel');
let timeElement = jQuery(this).find(".time");
otherSessionElement.addClass("other-session-selected");
if (scheduledAt)
timeElement.text(timeElement.data("scheduled").replace("{time}", scheduledAt));
else
timeElement.text(timeElement.data("notscheduled"));
});
}
else {
sessions.removeClass("selected");
showConstraintHints();
resetTimeSlotTypeIndicators();
content.find(".scheduling-panel .session-info-container").html("");
}
}
/**
* Mark or unmark a session that conflicts with the selected session
*
* @param constraintElt The element corresponding to the specific constraint
* @param wouldViolate True to mark or false to unmark
*/
function setSessionWouldViolate(constraintElt, wouldViolate) {
constraintElt = jQuery(constraintElt);
let constraintDiv = constraintElt.closest('div.session'); // find enclosing session div
constraintDiv.toggleClass('would-violate-hint', wouldViolate); // mark the session container
constraintElt.toggleClass('would-violate-hint', wouldViolate); // and the specific constraint
}
/**
* Mark or unmark a timeslot that conflicts with the selected session
*
* If wholeInterval is true, marks the entire column in addition to the timeslot.
* This currently works by setting the class for the timeslot and the time-label
* in its column. Because this is called for every timeslot in the interval, the
* overall effect is to highlight the entire column.
*
* @param timeslotElt Timeslot element to be marked/unmarked
* @param wouldViolate True to mark or false to unmark
* @param wholeInterval Should the entire time interval be flagged or just the timeslot?
*/
function setTimeslotWouldViolate(timeslotElt, wouldViolate, wholeInterval) {
timeslotElt = jQuery(timeslotElt);
timeslotElt.toggleClass('would-violate-hint', wouldViolate);
if (wholeInterval) {
let index = timeslotElt.index(); // position of this timeslot relative to its container
let label = timeslotElt
.closest('div.room-group')
.find('div.time-header .time-label')
.get(index); // get time-label corresponding to this timeslot
jQuery(label).toggleClass('would-violate-hint', wouldViolate);
}
}
/**
* Remove all would-violate-hint classes on timeslots
*/
function resetTimeslotsWouldViolate() {
timeslots.removeClass("would-violate-hint");
timeslotLabels.removeClass("would-violate-hint");
}
/**
* Remove all would-violate-hint classes on sessions and their formatted constraints
*/
function resetSessionsWouldViolate() {
sessions.removeClass("would-violate-hint");
sessionConstraints.removeClass("would-violate-hint");
}
function showConstraintHints(selectedSession) {
let sessionId = selectedSession ? selectedSession.id.slice("session".length) : null;
// hints on the sessions
resetSessionsWouldViolate();
if (sessionId) {
sessionConstraints.each(function () {
let sessionIds = this.dataset.sessions;
if (sessionIds && (sessionIds.split(",").indexOf(sessionId) !== -1)) {
setSessionWouldViolate(this, true);
}
});
}
// hints on timeslots
resetTimeslotsWouldViolate();
if (selectedSession) {
let intervals = [];
timeslots.filter(":has(.session .constraints > span.would-violate-hint)").each(function () {
intervals.push(
[parseISOTimestamp(this.dataset.start), parseISOTimestamp(this.dataset.end)]
);
});
let overlappingTimeslots = findTimeslotsOverlapping(intervals);
for (let i = 0; i < overlappingTimeslots.length; ++i) {
setTimeslotWouldViolate(overlappingTimeslots[i], true, true);
}
// check room sizes
let attendees = +selectedSession.dataset.attendees;
if (attendees) {
timeslots.not(".would-violate-hint").each(function () {
if (attendees > +jQuery(this).closest(".timeslots").data("roomcapacity")) {
setTimeslotWouldViolate(this, true, false);
}
});
}
}
}
/**
* Remove timeslot classes indicating timeslot type disagreement
*/
function resetTimeSlotTypeIndicators() {
timeslots.removeClass('wrong-timeslot-type');
}
/**
* Add timeslot classes indicating timeslot type disagreement
*
* @param timeslot_type
*/
function showTimeSlotTypeIndicators(timeslot_type) {
timeslots.removeClass('wrong-timeslot-type');
timeslots.filter('[data-type!="' + timeslot_type + '"]').addClass('wrong-timeslot-type');
}
/**
* Should this timeslot be treated as a future timeslot?
*
* @param timeslot timeslot to test
* @param now (optional) threshold time (defaults to effectiveNow())
* @returns Boolean true if the timeslot is in the future
*/
function isFutureTimeslot(timeslot, now) {
// resist the temptation to use native JS Date parsing, it is hopelessly broken
const timeslot_time = startMoment(timeslot);
return timeslot_time.isAfter(now || effectiveNow());
}
function hidePastTimeslotHints() {
timeslots.removeClass('past-hint');
}
function showPastTimeslotHints() {
timeslots.filter('.past').addClass('past-hint');
}
function updatePastTimeslots() {
const now = effectiveNow();
// mark timeslots
timeslots.filter(
':not(.past)'
).filter(
(_, ts) => !isFutureTimeslot(jQuery(ts), now)
).addClass('past');
// hide swap day/timeslot column buttons
if (officialSchedule) {
swapDaysButtons.filter(
(_, elt) => parseISOTimestamp(elt.dataset.start).isSameOrBefore(now, 'day')
).hide();
swapTimeslotButtons.filter(
(_, elt) => parseISOTimestamp(elt.dataset.start).isSameOrBefore(now, 'minute')
).hide();
}
}
function canEditSession(session) {
if (!officialSchedule) {
return true;
}
const timeslot = jQuery(session).closest('div.timeslot');
if (timeslot.length === 0) {
return true;
}
return isFutureTimeslot(timeslot);
}
content.on("click", function (event) {
if (jQuery(event.target).is(".session-info-container") || jQuery(event.target).closest(".session-info-container").length > 0)
return;
selectSessionElement(null);
});
sessions.on("click", function (event) {
event.stopPropagation();
// do not allow hidden sessions to be selected
if (!jQuery(this).hasClass('hidden-parent')) {
selectSessionElement(this);
}
});
// Was this drag started by dragging a session?
function isSessionDragEvent(event) {
return Boolean(event.originalEvent.dataTransfer.getData(dnd_mime_type));
}
/**
* Get the session element being dragged
*
* @param event drag-related event
*/
function getDraggedSession(event) {
if (!isSessionDragEvent(event)) {
return null;
}
const sessionId = event.originalEvent.dataTransfer.getData(dnd_mime_type);
const sessionElements = sessions.filter("#" + sessionId);
if (sessionElements.length > 0) {
return sessionElements[0];
}
return null;
}
/**
* Can a session be dropped in this element?
*
* Drop is allowed in drop-zones that are in unassigned-session or timeslot containers
* not marked as 'past'.
*/
function sessionDropAllowed(dropElement, sessionElement) {
const relevant_parent = dropElement.closest('.timeslot, .unassigned-sessions');
if (!relevant_parent || !sessionElement) {
return false;
}
if (officialSchedule && relevant_parent.classList.contains('past')) {
return false;
}
return !relevant_parent.dataset.type || (
relevant_parent.dataset.type === sessionElement.dataset.type
);
}
if (!content.find(".edit-grid").hasClass("read-only")) {
// dragging
sessions.on("dragstart", function (event) {
if (canEditSession(this)) {
event.originalEvent.dataTransfer.setData(dnd_mime_type, this.id);
jQuery(this).addClass("dragging");
selectSessionElement(this);
showPastTimeslotHints();
} else {
event.preventDefault(); // do not start the drag
}
});
sessions.on("dragend", function () {
jQuery(this).removeClass("dragging");
hidePastTimeslotHints();
});
sessions.prop('draggable', true);
// dropping
let dropElements = content.find(".timeslot .drop-target,.unassigned-sessions .drop-target");
dropElements.on('dragenter', function (event) {
if (sessionDropAllowed(this, getDraggedSession(event))) {
event.preventDefault(); // default action is signalling that this is not a valid target
jQuery(this).parent().addClass("dropping");
}
});
dropElements.on('dragover', function (event) {
// we don't actually need this event, except we need to signal
// that this is a valid drop target, by cancelling the default
// action
if (sessionDropAllowed(this, getDraggedSession(event))) {
event.preventDefault();
}
});
dropElements.on('dragleave', function (event) {
// skip dragleave events if they are to children
const leaving_child = event.originalEvent.currentTarget.contains(event.originalEvent.relatedTarget);
if (!leaving_child && sessionDropAllowed(this, getDraggedSession(event))) {
jQuery(this).parent().removeClass('dropping');
}
});
dropElements.on('drop', function (event) {
let dropElement = jQuery(this);
const sessionElement = getDraggedSession(event);
if (!sessionElement) {
// not drag event or not from a session we recognize
dropElement.parent().removeClass("dropping");
return;
}
if (!sessionDropAllowed(this, sessionElement)) {
dropElement.parent().removeClass("dropping"); // just in case
return; // drop not allowed
}
event.preventDefault(); // prevent opening as link
let dragParent = jQuery(sessionElement).parent();
if (dragParent.is(this)) {
dropElement.parent().removeClass("dropping");
return;
}
let dropParent = dropElement.parent();
function failHandler(xhr, textStatus, error) {
dropElement.parent().removeClass("dropping");
reportServerError(xhr, textStatus, error);
}
function done(response) {
dropElement.parent().removeClass("dropping");
if (!response.success) {
reportServerError(null, null, response);
return;
}
dropElement.append(sessionElement); // move element
if (response.tombstone)
dragParent.append(response.tombstone);
updateCurrentSchedulingHints();
if (dropParent.hasClass("unassigned-sessions"))
sortUnassigned();
}
if (dropParent.hasClass("unassigned-sessions")) {
jQuery.ajax({
url: window.location.href,
method: "post",
timeout: 5 * 1000,
data: {
action: "unassign",
session: sessionElement.id.slice("session".length)
}
}).fail(failHandler).done(done);
}
else {
jQuery.ajax({
url: window.location.href,
method: "post",
data: {
action: "assign",
session: sessionElement.id.slice("session".length),
timeslot: dropParent.attr("id").slice("timeslot".length)
},
timeout: 5 * 1000
}).fail(failHandler).done(done);
}
});
// Helpers for swap days / timeslots
// Enable or disable a swap modal's submit button
let updateSwapSubmitButton = function (modal, inputName) {
modal.find("button[type=submit]").prop(
"disabled",
modal.find("input[name='" + inputName + "']:checked").length === 0
);
};
// Disable a particular swap modal radio input
let updateSwapRadios = function (labels, radios, disableValue, datePrecision) {
labels.removeClass('text-muted');
radios.prop('disabled', false);
radios.prop('checked', false);
// disable the input requested by value
let disableInput = radios.filter('[value="' + disableValue + '"]');
if (disableInput) {
disableInput.parent().addClass('text-muted');
disableInput.prop('disabled', true);
}
if (officialSchedule) {
// disable any that have passed
const now=effectiveNow();
const past_radios = radios.filter(
(_, radio) => parseISOTimestamp(radio.dataset.start).isSameOrBefore(now, datePrecision)
);
past_radios.parent().addClass('text-muted');
past_radios.prop('disabled', true);
}
return disableInput; // return the input that was specifically disabled, if any
};
// swap days
let swapDaysModal = content.find("#swap-days-modal");
let swapDaysLabels = swapDaysModal.find(".modal-body label");
let swapDaysRadios = swapDaysLabels.find('input[name=target_day]');
let updateSwapDaysSubmitButton = function () {
updateSwapSubmitButton(swapDaysModal, 'target_day')
};
// handler to prep and open the modal
content.find(".swap-days").on("click", function () {
let originDay = this.dataset.dayid;
let originRadio = updateSwapRadios(swapDaysLabels, swapDaysRadios, originDay, 'day');
// Fill in label in the modal title
swapDaysModal.find(".modal-title .day").text(jQuery.trim(originRadio.parent().text()));
// Fill in the hidden form fields
swapDaysModal.find("input[name=source_day]").val(originDay);
updateSwapDaysSubmitButton();
swapDaysModal.modal('show'); // show via JS so it won't open until it is initialized
});
swapDaysRadios.on("change", function () {updateSwapDaysSubmitButton()});
// swap timeslot columns
let swapTimeslotsModal = content.find('#swap-timeslot-col-modal');
let swapTimeslotsLabels = swapTimeslotsModal.find(".modal-body label");
let swapTimeslotsRadios = swapTimeslotsLabels.find('input[name=target_timeslot]');
let updateSwapTimeslotsSubmitButton = function () {
updateSwapSubmitButton(swapTimeslotsModal, 'target_timeslot');
};
// handler to prep and open the modal
content.find('.swap-timeslot-col').on('click', function() {
let roomGroup = this.closest('.room-group').dataset;
updateSwapRadios(swapTimeslotsLabels, swapTimeslotsRadios, this.dataset.timeslotPk, 'minute');
// show only options for this room group
swapTimeslotsModal.find('.room-group').hide();
swapTimeslotsModal.find('.room-group-' + roomGroup.index).show();
// Fill in label in the modal title
swapTimeslotsModal.find('.modal-title .origin-label').text(this.dataset.originLabel);
// Fill in the hidden form fields
swapTimeslotsModal.find('input[name="origin_timeslot"]').val(this.dataset.timeslotPk);
swapTimeslotsModal.find('input[name="rooms"]').val(roomGroup.rooms);
// Open the modal via JS so it won't open until it is initialized
updateSwapTimeslotsSubmitButton();
swapTimeslotsModal.modal('show');
});
swapTimeslotsRadios.on("change", function () {updateSwapTimeslotsSubmitButton()});
}
// hints for the current schedule
function updateSessionConstraintViolations() {
// do a sweep on sessions sorted by start time
let scheduledSessions = [];
sessions.each(function () {
let timeslot = jQuery(this).closest(".timeslot");
if (timeslot.length === 1) {
scheduledSessions.push({
start: startMoment(timeslot),
end: endMoment(timeslot),
id: this.id.slice('session'.length),
element: jQuery(this),
timeslot: timeslot.get(0)
});
}
});
scheduledSessions.sort(function (a, b) {
if (a.start < b.start)
return -1;
if (a.start > b.start)
return 1;
return 0;
});
let currentlyOpen = {};
let openedIndex = 0;
for (let i = 0; i < scheduledSessions.length; ++i) {
let s = scheduledSessions[i];
// prune
for (let sessionIdStr in currentlyOpen) {
if (currentlyOpen[sessionIdStr].end <= s.start)
delete currentlyOpen[sessionIdStr];
}
// expand
while (openedIndex < scheduledSessions.length && scheduledSessions[openedIndex].start < s.end) {
let toAdd = scheduledSessions[openedIndex];
currentlyOpen[toAdd.id] = toAdd;
++openedIndex;
}
// check for violated constraints
s.element.find(".constraints > span").each(function () {
let sessionIds = this.dataset.sessions;
let violated = sessionIds && sessionIds.split(",").filter(function (v) {
return (v != s.id
&& v in currentlyOpen
// ignore errors within the same timeslot
// under the assumption that the sessions
// in the timeslot happen sequentially
&& s.timeslot != currentlyOpen[v].timeslot);
}).length > 0;
jQuery(this).toggleClass("violated-hint", violated);
});
}
}
function updateTimeSlotDurationViolations() {
timeslots.each(function () {
let total = 0;
jQuery(this).find(".session").each(function () {
total += +jQuery(this).data("duration");
});
jQuery(this).toggleClass("overfull", total > +jQuery(this).data("duration"));
});
}
function updateAttendeesViolations() {
sessions.each(function () {
let roomCapacity = jQuery(this).closest(".timeslots").data("roomcapacity");
if (roomCapacity && this.dataset.attendees)
jQuery(this).toggleClass("too-many-attendees", +this.dataset.attendees > +roomCapacity);
});
}
function updateCurrentSchedulingHints() {
updateSessionConstraintViolations();
updateAttendeesViolations();
updateTimeSlotDurationViolations();
}
updateCurrentSchedulingHints();
// sorting unassigned
function sortArrayWithKeyFunctions(array, keyFunctions) {
function compareArrays(a, b) {
for (let i = 1; i < a.length; ++i) {
let ai = a[i];
let bi = b[i];
if (ai > bi)
return 1;
else if (ai < bi)
return -1;
}
return 0;
}
let arrayWithSortKeys = array.map(function (a) {
let res = [a];
for (let i = 0; i < keyFunctions.length; ++i)
res.push(keyFunctions[i](a));
return res;
});
arrayWithSortKeys.sort(compareArrays);
return arrayWithSortKeys.map(function (l) {
return l[0];
});
}
function sortUnassigned() {
let sortBy = content.find("select[name=sort_unassigned]").val();
function extractId(e) {
return e.id.slice("session".length);
}
function extractName(e) {
let labelElement = e.querySelector(".session-label");
return labelElement ? labelElement.innerHTML : '';
}
function extractParent(e) {
let parentElement = e.querySelector(".session-parent");
return parentElement ? parentElement.innerHTML : '';
}
function extractDuration(e) {
return +e.dataset.duration;
}
function extractComments(e) {
return e.querySelector(".session-info .comments") ? 0 : 1;
}
const keyFunctionMap = {
name: [extractName, extractDuration, extractId],
parent: [extractParent, extractName, extractDuration, extractId],
duration: [extractDuration, extractParent, extractName, extractId],
comments: [extractComments, extractParent, extractName, extractDuration, extractId]
};
let keyFunctions = keyFunctionMap[sortBy];
let unassignedSessionsContainer = content.find(".unassigned-sessions .drop-target");
let sortedSessions = sortArrayWithKeyFunctions(unassignedSessionsContainer.children(".session").toArray(), keyFunctions);
for (let i = 0; i < sortedSessions.length; ++i)
unassignedSessionsContainer.append(sortedSessions[i]);
}
content.find("select[name=sort_unassigned]").on("change click", function () {
sortUnassigned();
});
sortUnassigned();
// toggling visible sessions by session parents
let sessionParentInputs = content.find(".session-parent-toggles input");
function setSessionHiddenParent(sess, hide) {
sess.toggleClass('hidden-parent', hide);
sess.prop('draggable', !hide);
}
function updateSessionParentToggling() {
let checked = [];
sessionParentInputs.filter(":checked").each(function () {
checked.push(".parent-" + this.value);
});
setSessionHiddenParent(sessions.not(".untoggleable-by-parent").filter(checked.join(",")), false);
setSessionHiddenParent(sessions.not(".untoggleable-by-parent").not(checked.join(",")), true);
}
sessionParentInputs.on("click", updateSessionParentToggling);
updateSessionParentToggling();
// Toggling timeslot types
let timeSlotTypeInputs = content.find('.timeslot-type-toggles input');
function updateTimeSlotTypeToggling() {
let checked = [];
timeSlotTypeInputs.filter(":checked").each(function () {
checked.push("[data-type=" + this.value + "]");
});
sessions.filter(checked.join(",")).removeClass('hidden-timeslot-type');
sessions.not(checked.join(",")).addClass('hidden-timeslot-type');
timeslots.filter(checked.join(",")).removeClass('hidden-timeslot-type');
timeslots.not(checked.join(",")).addClass('hidden-timeslot-type');
}
if (timeSlotTypeInputs.length > 0) {
timeSlotTypeInputs.on("change", updateTimeSlotTypeToggling);
updateTimeSlotTypeToggling();
content.find('#timeslot-group-toggles-modal .timeslot-type-toggles .select-all').get(0).addEventListener(
'click',
function() {
timeSlotTypeInputs.prop('checked', true);
updateTimeSlotTypeToggling();
});
content.find('#timeslot-group-toggles-modal .timeslot-type-toggles .clear-all').get(0).addEventListener(
'click',
function() {
timeSlotTypeInputs.prop('checked', false);
updateTimeSlotTypeToggling();
});
}
// Toggling session purposes
let sessionPurposeInputs = content.find('.session-purpose-toggles input');
function updateSessionPurposeToggling(evt) {
let checked = [];
sessionPurposeInputs.filter(":checked").each(function () {
checked.push(".purpose-" + this.value);
});
sessions.filter(checked.join(",")).removeClass('hidden-purpose');
sessions.not(checked.join(",")).addClass('hidden-purpose');
}
if (sessionPurposeInputs.length > 0) {
sessionPurposeInputs.on("change", updateSessionPurposeToggling);
updateSessionPurposeToggling();
content.find('#session-toggles-modal .select-all').get(0).addEventListener(
'click',
function() {
sessionPurposeInputs.prop('checked', true);
updateSessionPurposeToggling();
});
content.find('#session-toggles-modal .clear-all').get(0).addEventListener(
'click',
function() {
sessionPurposeInputs.prop('checked', false);
updateSessionPurposeToggling();
});
}
// toggling visible timeslots
let timeSlotGroupInputs = content.find("#timeslot-group-toggles-modal .modal-body .individual-timeslots input");
function updateTimeSlotGroupToggling() {
let checked = [];
timeSlotGroupInputs.filter(":checked").each(function () {
checked.push("." + this.value);
});
timeslots.filter(checked.join(",")).removeClass("hidden");
timeslots.not(checked.join(",")).addClass("hidden");
days.each(function () {
jQuery(this).toggle(jQuery(this).find(".timeslot:not(.hidden)").length > 0);
});
}
timeSlotGroupInputs.on("click change", updateTimeSlotGroupToggling);
content.find('#timeslot-group-toggles-modal .timeslot-group-buttons .select-all').get(0).addEventListener(
'click',
function() {
timeSlotGroupInputs.prop('checked', true);
updateTimeSlotGroupToggling();
});
content.find('#timeslot-group-toggles-modal .timeslot-group-buttons .clear-all').get(0).addEventListener(
'click',
function() {
timeSlotGroupInputs.prop('checked', false);
updateTimeSlotGroupToggling();
});
updateTimeSlotGroupToggling();
updatePastTimeslots();
setInterval(updatePastTimeslots, 10 * 1000 /* ms */);
// session info
content.find(".session-info-container").on("mouseover", ".other-session", function (event) {
sessions.filter("#session" + this.dataset.othersessionid).addClass("highlight");
}).on("mouseleave", ".other-session", function (event) {
sessions.filter("#session" + this.dataset.othersessionid).removeClass("highlight");
});
});

View file

@ -0,0 +1,134 @@
// Taken from django-password-strength, with changes to use the bower-managed zxcvbn.js The
// bower-managed zxcvbn.js is kept up-to-date to a larger extent than the copy packaged with
// the django-password-strength component.
(function($, window, document, undefined){
window.djangoPasswordStrength = {
config: {
passwordClass: 'password_strength',
confirmationClass: 'password_confirmation'
},
init: function (config) {
var self = this;
// Setup configuration
if ($.isPlainObject(config)) {
$.extend(self.config, config);
}
self.initListeners();
},
initListeners: function() {
var self = this;
var body = $('body');
$('.' + self.config.passwordClass).on('keyup', function() {
var password_strength_bar = $(this).parent().find('.password_strength_bar');
var password_strength_info = $(this).parent().find('.password_strength_info');
var password_strength_offline_info = $(this).parent().parent().parent().find('.password_strength_offline_info');
if( $(this).val() ) {
var result = zxcvbn( $(this).val() );
if( result.score < 3 ) {
password_strength_bar.removeClass('progress-bar-success').addClass('progress-bar-warning');
password_strength_info.find('.label').removeClass('hidden');
} else {
password_strength_bar.removeClass('progress-bar-warning').addClass('progress-bar-success');
password_strength_info.find('.label').addClass('hidden');
}
password_strength_bar.width( ((result.score+1)/5)*100 + '%' ).attr('aria-valuenow', result.score + 1);
// henrik@levkowetz.com -- this is the only changed line:
password_strength_info.find('.password_strength_time').html(result.crack_times_display.online_no_throttling_10_per_second);
password_strength_info.removeClass('hidden');
password_strength_offline_info.find('.password_strength_time').html(result.crack_times_display.offline_slow_hashing_1e4_per_second);
password_strength_offline_info.removeClass('hidden');
} else {
password_strength_bar.removeClass('progress-bar-success').addClass('progress-bar-warning');
password_strength_bar.width( '0%' ).attr('aria-valuenow', 0);
password_strength_info.addClass('hidden');
}
self.match_passwords($(this));
});
var timer = null;
$('.' + self.config.confirmationClass).on('keyup', function() {
var password_field;
var confirm_with = $(this).data('confirm-with');
if( confirm_with ) {
password_field = $('#' + confirm_with);
} else {
password_field = $('.' + self.config.passwordClass);
}
if (timer !== null) clearTimeout(timer);
timer = setTimeout(function(){
self.match_passwords(password_field);
}, 400);
});
},
display_time: function(seconds) {
var minute = 60;
var hour = minute * 60;
var day = hour * 24;
var month = day * 31;
var year = month * 12;
var century = year * 100;
// Provide fake gettext for when it is not available
if( typeof gettext !== 'function' ) { gettext = function(text) { return text; }; };
if( seconds < minute ) return gettext('only an instant');
if( seconds < hour) return (1 + Math.ceil(seconds / minute)) + ' ' + gettext('minutes');
if( seconds < day) return (1 + Math.ceil(seconds / hour)) + ' ' + gettext('hours');
if( seconds < month) return (1 + Math.ceil(seconds / day)) + ' ' + gettext('days');
if( seconds < year) return (1 + Math.ceil(seconds / month)) + ' ' + gettext('months');
if( seconds < century) return (1 + Math.ceil(seconds / year)) + ' ' + gettext('years');
return gettext('centuries');
},
match_passwords: function(password_field, confirmation_fields) {
var self = this;
// Optional parameter: if no specific confirmation field is given, check all
if( confirmation_fields === undefined ) { confirmation_fields = $('.' + self.config.confirmationClass) }
if( confirmation_fields === undefined ) { return; }
var password = password_field.val();
confirmation_fields.each(function(index, confirm_field) {
var confirm_value = $(confirm_field).val();
var confirm_with = $(confirm_field).data('confirm-with');
if( confirm_with && confirm_with == password_field.attr('id')) {
if( confirm_value && password ) {
if (confirm_value === password) {
$(confirm_field).parent().find('.password_strength_info').addClass('hidden');
} else {
$(confirm_field).parent().find('.password_strength_info').removeClass('hidden');
}
} else {
$(confirm_field).parent().find('.password_strength_info').addClass('hidden');
}
}
});
// If a password field other than our own has been used, add the listener here
if( !password_field.hasClass(self.config.passwordClass) && !password_field.data('password-listener') ) {
password_field.on('keyup', function() {
self.match_passwords($(this));
});
password_field.data('password-listener', true);
}
}
};
// Call the init for backwards compatibility
djangoPasswordStrength.init();
})(jQuery, window, document);

1
ietf/static/js/zxcvbn.js Normal file
View file

@ -0,0 +1 @@
import "zxcvbn";

View file

@ -1,173 +1,412 @@
{# bs5ok #}
{# Copyright The IETF Trust 2015-2019, All Rights Reserved #}
{% load origin %}
{% origin %}
{% load ietf_filters managed_groups wg_menu active_groups_menu group_filters %}
{% if flavor != 'top' %}
{% include "base/menu_user.html" %}
{% endif %}
<li class="nav-item dropdown">
{% if flavor == "top" %}
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-auto-close="false" data-bs-toggle="dropdown" aria-expanded="false">
<a href="#"
class="nav-link dropdown-toggle"
role="button"
data-bs-auto-close="false"
data-bs-toggle="dropdown"
aria-expanded="false">
Groups
</a>
<ul class="dropdown-menu {% if flavor == 'top' %}mt-n1{% else %}ms-n1{% endif %}">
{% else %}
<span class="fw-bolder">Groups</span>
{% endif %}
{%if flavor == 'top' %}<li class="dropdown-header">By area/parent</li>{% endif %}
{% wg_menu flavor %}
<li class="dropend">
<a class="dropdown-item dropdown-toggle {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.group.views.active_groups" %}">Other</a>
{% active_groups_menu flavor %}
{% else %}
<span class="fw-bolder">Groups</span>
{% endif %}
{% if flavor == 'top' %}<li class="dropdown-header">By area/parent</li>{% endif %}
{% wg_menu flavor %}
<li class="dropend">
<a class="dropdown-item dropdown-toggle {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.group.views.active_groups" %}">
Other
</a>
{% active_groups_menu flavor %}
</li>
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li {% if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>New work</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.group.views.chartering_groups" %}">
Chartering groups
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.group.views.bofs" group_type="wg" %}">
BOFs
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.doc.views_bofreq.bof_requests" %}">
BOF Requests
</a>
</li>
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li {% if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>Other groups</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.group.views.concluded_groups" %}">
Concluded groups
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url 'ietf.mailinglists.views.nonwg' %}">
Non-WG lists
</a>
</li>
{% if flavor == "top" %}</ul>{% endif %}
</li>
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li {%if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>New work</li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.group.views.chartering_groups" %}">Chartering groups</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.group.views.bofs" group_type="wg" %}">BOFs</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.doc.views_bofreq.bof_requests" %}">BOF Requests</a></li>
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li {%if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>Other groups</li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.group.views.concluded_groups" %}">Concluded groups</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url 'ietf.mailinglists.views.nonwg' %}">Non-WG lists</a></li>
{% if flavor == "top" %}</ul>{% endif %}
</li>
<li class="nav-item dropdown">
{% if flavor == "top" %}
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Documents
</a>
<ul class="dropdown-menu {% if flavor == 'top' %}mt-n1{% else %}ms-n1{% endif %}">
{% else %}
<span class="fw-bolder">Documents</span>
{% endif %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.doc.views_search.search" %}">Search</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.doc.views_search.recent_drafts" %}">Recent drafts</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.submit.views.upload_submission" %}">Draft submission</a></li>
{% if user and user.is_authenticated %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.community.views.view_list" user.username %}">My tracked docs</a></li>
{% if user|has_role:"Area Director,Secretariat" %}
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url 'ietf.doc.views_status_change.rfc_status_changes' %}">RFC status changes</a></li>
{% endif %}
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url 'ietf.doc.views_ballot.irsg_ballot_status' %}">IRSG ballot status</a></li>
{% if user|has_role:"WG Chair,RG Chair" %}
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li {%if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>Manage</li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.submit.views.approvals" %}">Approve a draft</a></li>
{% for g in user|docman_groups %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.group.views.group_documents" g.acronym %}">{{ g.acronym }} {{ g.type.slug }} docs</a></li>
{% endfor %}
{% for g in user|matman_groups %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.group.views.meetings" g.acronym %}">{{ g.acronym }} {{ g.type.slug }} meetings</a></li>
{% endfor %}
{% endif %}
{% if user|has_role:"Review Team Secretary" %}
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li {%if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>Review Teams</li>
{% for g in user|managed_review_groups %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.group.views.review_requests" g.acronym %}">{{ g.acronym }} reviews</a></li>
{% endfor %}
{% endif %}
{% if user|active_nomcoms %}
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li {%if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>NomComs</li>
{% for g in user|active_nomcoms %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.nomcom.views.private_index" g.nomcom_set.first.year %}">{{ g.acronym|capfirst }}</a></li>
{% endfor %}
{% endif %}
{% endif %}
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li {%if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>RFC streams</li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.group.views.stream_documents" acronym="iab" %}">IAB</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.group.views.stream_documents" acronym="irtf" %}">IRTF</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.group.views.stream_documents" acronym="ise" %}">ISE</a></li>
{% if flavor == 'top' %}</ul>{% endif %}
</li>
<li class="nav-item dropdown">
{% if flavor == "top" %}
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Meetings
</a>
<ul class="dropdown-menu {% if flavor == 'top' %}mt-n1{% else %}ms-n1{% endif %}">
{% else %}
<span class="fw-bolder">Meetings</span>
{% endif %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/meeting/agenda/">Agenda</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/meeting/materials/">Materials</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/meeting/floor-plan/">Floor plan</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="https://www.ietf.org/how/meetings/register/">Registration</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url 'ietf.meeting.views.important_dates' %}">Important dates</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/secr/sreq/">Request a session</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/meeting/requests">Session requests</a></li>
{% if flavor == 'top' %}
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li {%if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>New work</li>
<li class="dropdown-header">Upcoming meetings</li>
{% endif %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/meeting/upcoming">Upcoming meetings</a></li>
{% if flavor == 'top' %}
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li {%if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>New work</li>
<li class="dropdown-header">Past meetings</li>
{% endif %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/meeting/past">Past meetings</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="https://www.ietf.org/how/meetings/past/">Meeting proceedings</a></li>
{% if flavor == 'top' %}</ul>{% endif %}
</li>
<li class="nav-item dropdown">
{% if flavor == "top" %}
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Other
</a>
<ul class="dropdown-menu {% if flavor == 'top' %}mt-n1{% else %}ms-n1{% endif %}">
{% else %}
<span class="fw-bolder">Other</span>
{% endif %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/ipr/">IPR disclosures</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/liaison/">Liaison statements</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/iesg/agenda/">IESG agenda</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url 'ietf.nomcom.views.index' %}">NomComs</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/doc/downref/">Downref registry</a></li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url "ietf.stats.views.stats_index" %}">Statistics</a>
<ul class="dropdown-menu {% if flavor == 'top' %}mt-n1{% else %}ms-n1{% endif %}">
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url 'ietf.stats.views.document_stats' %}">Drafts/RFCs</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url 'ietf.stats.views.meeting_stats' %}">Meetings</a></li>
{% if user and user.is_authenticated %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url 'ietf.stats.views.review_stats' %}">Reviews</a></li>
<li class="nav-item dropdown">
{% if flavor == "top" %}
<a href="#"
class="nav-link dropdown-toggle"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false">
Documents
</a>
<ul class="dropdown-menu {% if flavor == 'top' %}mt-n1{% else %}ms-n1{% endif %}">
{% else %}
<span class="fw-bolder">Documents</span>
{% endif %}
</ul>
</li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/group/edu/materials/">Tutorials</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="/api/">API Help</a></li>
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="{% url 'ietf.release.views.release' %}">Release notes</a></li>
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li><a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}" href="https://trac.ietf.org/trac/ietfdb/newticket"><span class="bi bi-bug"></span> Report a bug</a></li>
{% if flavor == 'top' %}</ul>{% endif %}
</li>
{% if flavor == 'top' %}
{% include "base/menu_user.html" %}
{% endif %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.doc.views_search.search" %}">
Search
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.doc.views_search.recent_drafts" %}">
Recent drafts
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.submit.views.upload_submission" %}">
Draft submission
</a>
</li>
{% if user and user.is_authenticated %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.community.views.view_list" user.username %}">
My tracked docs
</a>
</li>
{% if user|has_role:"Area Director,Secretariat" %}
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url 'ietf.doc.views_status_change.rfc_status_changes' %}">
RFC status changes
</a>
</li>
{% endif %}
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url 'ietf.doc.views_ballot.irsg_ballot_status' %}">
IRSG ballot status
</a>
</li>
{% if user|has_role:"WG Chair,RG Chair" %}
{% if flavor == 'top' %}<li class="dropdown-divider"></li>{% endif %}
<li {% if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>Manage</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.submit.views.approvals" %}">
Approve a draft
</a>
</li>
{% for g in user|docman_groups %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.group.views.group_documents" g.acronym %}">
{{ g.acronym }} {{ g.type.slug }} docs
</a>
</li>
{% endfor %}
{% for g in user|matman_groups %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.group.views.meetings" g.acronym %}">
{{ g.acronym }} {{ g.type.slug }} meetings
</a>
</li>
{% endfor %}
{% endif %}
{% if user|has_role:"Review Team Secretary" %}
{% if flavor == 'top' %}
<li class="dropdown-divider">
</li>
{% endif %}
<li {% if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>
Review Teams
</li>
{% for g in user|managed_review_groups %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.group.views.review_requests" g.acronym %}">
{{ g.acronym }} reviews
</a>
</li>
{% endfor %}
{% endif %}
{% if user|active_nomcoms %}
{% if flavor == 'top' %}
<li class="dropdown-divider">
</li>
{% endif %}
<li {% if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>
NomComs
</li>
{% for g in user|active_nomcoms %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.nomcom.views.private_index" g.nomcom_set.first.year %}">
{{ g.acronym|capfirst }}
</a>
</li>
{% endfor %}
{% endif %}
{% endif %}
{% if flavor == 'top' %}
<li class="dropdown-divider">
</li>
{% endif %}
<li {% if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>
RFC streams
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.group.views.stream_documents" acronym="iab" %}">
IAB
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.group.views.stream_documents" acronym="irtf" %}">
IRTF
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.group.views.stream_documents" acronym="ise" %}">
ISE
</a>
</li>
{% if flavor == 'top' %}</ul>{% endif %}
</li>
<li class="nav-item dropdown">
{% if flavor == "top" %}
<a href="#"
class="nav-link dropdown-toggle"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false">
Meetings
</a>
<ul class="dropdown-menu {% if flavor == 'top' %}mt-n1{% else %}ms-n1{% endif %}">
{% else %}
<span class="fw-bolder">
Meetings
</span>
{% endif %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/meeting/agenda/">
Agenda
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/meeting/materials/">
Materials
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/meeting/floor-plan/">
Floor plan
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="https://www.ietf.org/how/meetings/register/">
Registration
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url 'ietf.meeting.views.important_dates' %}">
Important dates
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/secr/sreq/">
Request a session
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/meeting/requests">
Session requests
</a>
</li>
{% if flavor == 'top' %}
{% if flavor == 'top' %}
<li class="dropdown-divider">
</li>
{% endif %}
<li {% if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>
Upcoming meetings
</li>
{% endif %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/meeting/upcoming">
Upcoming meetings
</a>
</li>
{% if flavor == 'top' %}
{% if flavor == 'top' %}
<li class="dropdown-divider">
</li>
{% endif %}
<li {% if flavor == 'top' %}class="dropdown-header"{% else %}class="nav-item fw-bolder"{% endif %}>
Past meetings
</li>
{% endif %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/meeting/past">
Past meetings
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="https://www.ietf.org/how/meetings/past/">
Meeting proceedings
</a>
</li>
{% if flavor == 'top' %}</ul>{% endif %}
</li>
<li class="nav-item dropdown">
{% if flavor == "top" %}
<a href="#"
class="nav-link dropdown-toggle"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false">
Other
</a>
<ul class="dropdown-menu {% if flavor == 'top' %}mt-n1{% else %}ms-n1{% endif %}">
{% else %}
<span class="fw-bolder">
Other
</span>
{% endif %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/ipr/">
IPR disclosures
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/liaison/">
Liaison statements
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/iesg/agenda/">
IESG agenda
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url 'ietf.nomcom.views.index' %}">
NomComs
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/doc/downref/">
Downref registry
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url "ietf.stats.views.stats_index" %}">
Statistics
</a>
<ul class="dropdown-menu {% if flavor == 'top' %}mt-n1{% else %}ms-n1{% endif %}">
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url 'ietf.stats.views.document_stats' %}">
Drafts/RFCs
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url 'ietf.stats.views.meeting_stats' %}">
Meetings
</a>
</li>
{% if user and user.is_authenticated %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url 'ietf.stats.views.review_stats' %}">
Reviews
</a>
</li>
{% endif %}
</ul>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/group/edu/materials/">
Tutorials
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="/api/">
API Help
</a>
</li>
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="{% url 'ietf.release.views.release' %}">
Release notes
</a>
</li>
{% if flavor == 'top' %}
<li class="dropdown-divider">
</li>
{% endif %}
<li>
<a class="dropdown-item {% if flavor != 'top' %}text-wrap link-primary{% endif %}"
href="https://trac.ietf.org/trac/ietfdb/newticket">
<span class="bi bi-bug">
</span>
Report a bug
</a>
</li>
{% if flavor == 'top' %}</ul>{% endif %}
</li>
{% if flavor == 'top' %}
{% include "base/menu_user.html" %}
{% endif %}

View file

@ -1,22 +1,24 @@
{# bs5ok #}
{% extends "base.html" %}
{# Copyright The IETF Trust 2015-2020, All Rights Reserved #}
{% load origin %}
{% load staticfiles %}
{% load ietf_filters %}
{% load django_bootstrap5 %}
{% block content %}
{% origin %}
<h1>{% block title %}{% if schedule %}Copy agenda {{ schedule.name }} to new agenda{% else %}New agenda{% endif %}{% endblock %}</h1>
<h1>
{% block title %}
{% if schedule %}
Copy agenda {{ schedule.name }} to new agenda
{% else %}
New agenda
{% endif %}
{% endblock %}
</h1>
<form method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% bootstrap_form form layout="horizontal" %}
<button type="submit" class="btn btn-primary">Create agenda</button>
</form>
{% endblock %}
{% endblock %}

View file

@ -1,36 +1,34 @@
{# bs5ok #}
{% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %}
{% load static %}
{% load ietf_filters %}
{% load django_bootstrap5 %}
{% block title %}IETF {{ meeting.number }} Meeting Agenda: {{schedule.owner}} / {{ schedule.name }}{% endblock %}
{% block title %}IETF {{ meeting.number }} Meeting Agenda: {{ schedule.owner }} / {{ schedule.name }}{% endblock %}
{% block content %}
{% origin %}
<h1>IETF {{meeting.number}}</h1>
<h2>Schedule: {{schedule.owner}}/{{schedule.name}} ({{schedule.official_token }})
<h1>IETF {{ meeting.number }}</h1>
<h2>Schedule: {{ schedule.owner }}/{{ schedule.name }} ({{ schedule.official_token }})</h2>
<div class="my-3">
{% if not schedule.is_official %}
<a class="btn btn-primary btn-sm" href="{% url 'ietf.meeting.views.make_schedule_official' num=meeting.number owner=schedule.owner.email_address name=schedule.name %}">Make this the official schedule</a>
<a class="btn btn-warning btn-sm" href="{% url 'ietf.meeting.views.delete_schedule' num=meeting.number owner=schedule.owner.email_address name=schedule.name %}">Delete this schedule</a>
<a class="btn btn-primary"
href="{% url 'ietf.meeting.views.make_schedule_official' num=meeting.number owner=schedule.owner.email_address name=schedule.name %}">
Make this the official schedule
</a>
<a class="btn btn-warning"
href="{% url 'ietf.meeting.views.delete_schedule' num=meeting.number owner=schedule.owner.email_address name=schedule.name %}">
Delete this schedule
</a>
{% endif %}
</h2>
</div>
<div>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_form form %}
{% bootstrap_form form layout="horizontal" %}
<input class="btn btn-primary" type="submit" value="Save" name="save">
<a href="{% url 'ietf.meeting.views.list_schedules' num=meeting.number %}" class="btn btn-primary">Cancel</a>
<a href="{% url 'ietf.meeting.views.list_schedules' num=meeting.number %}"
class="btn btn-secondary">Cancel</a>
</form>
</div>
{% endblock %}
{% endblock %}

View file

@ -15,7 +15,7 @@
{% endif %}
{% for schedules, own, label in schedule_groups %}
<div class="panel ">
<div class="panel">
<div class="card-header">
{{ label }}
{% if own %}
@ -39,12 +39,12 @@
{% for schedule in schedules %}
<tr>
<td>
<a href="{% url "ietf.meeting.views.edit_schedule" meeting.number schedule.owner_email schedule.name %}" title="Show regular sessions in agenda">{{ schedule.name }}</a>
<a href="{% url "ietf.meeting.views.edit_meeting_schedule" meeting.number schedule.owner_email schedule.name %}" title="Show regular sessions in agenda">{{ schedule.name }}</a>
</td>
<td>{{ schedule.owner }}</td>
<td>
{% if schedule.origin %}
<a href="{% url "ietf.meeting.views.edit_schedule" meeting.number schedule.origin.owner_email schedule.origin.name %}">{{ schedule.origin.name }}</a>
<a href="{% url "ietf.meeting.views.edit_meeting_schedule" meeting.number schedule.origin.owner_email schedule.origin.name %}">{{ schedule.origin.name }}</a>
<a href="{% url "ietf.meeting.views.diff_schedules" meeting.number %}?from_schedule={{ schedule.origin.name|urlencode }}&to_schedule={{ schedule.name|urlencode }}" title="{{ schedule.changes_from_origin }} change{{ schedule.changes_from_origin|pluralize }} from {{ schedule.origin.name }}">+{{ schedule.changes_from_origin }}</a>
{% endif %}
</td>

View file

@ -10,7 +10,7 @@
{% block js %}
{{ block.super }}
<script type="text/javascript" src="{% static 'zxcvbn/zxcvbn.js' %}"></script>
<script type="text/javascript" src="{% static 'ietf/js/zxcvbn.js' %}"></script>
<script type="text/javascript" src="{% static 'ietf/js/password_strength.js' %}"></script>
{% endblock %}

View file

@ -9,7 +9,7 @@
{% block js %}
{{ block.super }}
<script type="text/javascript" src="{% static 'zxcvbn/zxcvbn.js' %}"></script>
<script type="text/javascript" src="{% static 'ietf/js/zxcvbn.js' %}"></script>
<script type="text/javascript" src="{% static 'ietf/js/password_strength.js' %}"></script>
{% endblock %}

13
package-lock.json generated
View file

@ -20,7 +20,8 @@
"moment": "^2.29.1",
"moment-timezone": "^0.5.34",
"select2": "^4.1.0-rc.0",
"select2-bootstrap-5-theme": "^1.2.0"
"select2-bootstrap-5-theme": "^1.2.0",
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"@parcel/transformer-sass": "^2.0.1",
@ -8925,6 +8926,11 @@
"engines": {
"node": ">= 6"
}
},
"node_modules/zxcvbn": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/zxcvbn/-/zxcvbn-4.4.2.tgz",
"integrity": "sha1-KOwXzwl0PtyrBW3dixsGJizHPDA="
}
},
"dependencies": {
@ -15648,6 +15654,11 @@
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"dev": true
},
"zxcvbn": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/zxcvbn/-/zxcvbn-4.4.2.tgz",
"integrity": "sha1-KOwXzwl0PtyrBW3dixsGJizHPDA="
}
}
}

View file

@ -15,7 +15,8 @@
"moment": "^2.29.1",
"moment-timezone": "^0.5.34",
"select2": "^4.1.0-rc.0",
"select2-bootstrap-5-theme": "^1.2.0"
"select2-bootstrap-5-theme": "^1.2.0",
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"@parcel/transformer-sass": "^2.0.1",
@ -39,6 +40,7 @@
"ietf/static/js/datepicker.js",
"ietf/static/js/doc-search.js",
"ietf/static/js/document_timeline.js",
"ietf/static/js/edit-meeting-schedule.js",
"ietf/static/js/flot.js",
"ietf/static/js/fullcalendar.js",
"ietf/static/js/highcharts-export-data.js",
@ -52,12 +54,14 @@
"ietf/static/js/manage-community-list.js",
"ietf/static/js/moment-timezone-with-data-10-year-range.js",
"ietf/static/js/moment.js",
"ietf/static/js/password_strength.js",
"ietf/static/js/review-stats.js",
"ietf/static/js/room_params.js",
"ietf/static/js/select2.js",
"ietf/static/js/stats.js",
"ietf/static/js/timezone.js",
"ietf/static/js/week-view.js"
"ietf/static/js/week-view.js",
"ietf/static/js/zxcvbn.js"
],
"targets": {
"default": {