diff --git a/ietf/cookies/tests.py b/ietf/cookies/tests.py index d4530774c..b23304167 100644 --- a/ietf/cookies/tests.py +++ b/ietf/cookies/tests.py @@ -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*") \ No newline at end of file diff --git a/ietf/static/js/edit-meeting-schedule.js b/ietf/static/js/edit-meeting-schedule.js new file mode 100644 index 000000000..60bce13ea --- /dev/null +++ b/ietf/static/js/edit-meeting-schedule.js @@ -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"); + }); +}); + diff --git a/ietf/static/js/password_strength.js b/ietf/static/js/password_strength.js new file mode 100644 index 000000000..b7d12e2bc --- /dev/null +++ b/ietf/static/js/password_strength.js @@ -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); diff --git a/ietf/static/js/zxcvbn.js b/ietf/static/js/zxcvbn.js new file mode 100644 index 000000000..cdf07c40e --- /dev/null +++ b/ietf/static/js/zxcvbn.js @@ -0,0 +1 @@ +import "zxcvbn"; \ No newline at end of file diff --git a/ietf/templates/base/menu.html b/ietf/templates/base/menu.html index c126a1c22..4faebdc9a 100644 --- a/ietf/templates/base/menu.html +++ b/ietf/templates/base/menu.html @@ -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 %} -