More fixes
- Legacy-Id: 19742
This commit is contained in:
parent
e3b430d2ec
commit
406aa1e5a0
|
@ -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*")
|
826
ietf/static/js/edit-meeting-schedule.js
Normal file
826
ietf/static/js/edit-meeting-schedule.js
Normal 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");
|
||||
});
|
||||
});
|
||||
|
134
ietf/static/js/password_strength.js
Normal file
134
ietf/static/js/password_strength.js
Normal 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
1
ietf/static/js/zxcvbn.js
Normal file
|
@ -0,0 +1 @@
|
|||
import "zxcvbn";
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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>
|
||||
|
|
|
@ -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 %}
|
||||
|
||||
|
|
|
@ -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
13
package-lock.json
generated
|
@ -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="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
Loading…
Reference in a new issue