cherrypy-foundation 1.0.0__py3-none-any.whl → 1.0.0a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cherrypy_foundation/components/ColorModes.jinja +4 -5
- cherrypy_foundation/components/Datatable.jinja +2 -2
- cherrypy_foundation/components/Datatable.js +2 -2
- cherrypy_foundation/components/Field.jinja +6 -16
- cherrypy_foundation/components/Fields.jinja +2 -0
- cherrypy_foundation/components/Typeahead.css +1 -6
- cherrypy_foundation/components/Typeahead.jinja +2 -2
- cherrypy_foundation/components/__init__.py +2 -2
- cherrypy_foundation/components/tests/test_static.py +1 -1
- cherrypy_foundation/error_page.py +17 -20
- cherrypy_foundation/flash.py +15 -17
- cherrypy_foundation/form.py +2 -2
- cherrypy_foundation/logging.py +2 -2
- cherrypy_foundation/passwd.py +2 -2
- cherrypy_foundation/plugins/db.py +9 -35
- cherrypy_foundation/plugins/ldap.py +38 -46
- cherrypy_foundation/plugins/restapi.py +1 -1
- cherrypy_foundation/plugins/scheduler.py +84 -208
- cherrypy_foundation/plugins/smtp.py +46 -78
- cherrypy_foundation/plugins/tests/test_db.py +4 -4
- cherrypy_foundation/plugins/tests/test_ldap.py +3 -76
- cherrypy_foundation/plugins/tests/test_scheduler.py +50 -58
- cherrypy_foundation/plugins/tests/test_smtp.py +7 -40
- cherrypy_foundation/tests/__init__.py +0 -72
- cherrypy_foundation/tests/test_error_page.py +1 -7
- cherrypy_foundation/tests/test_passwd.py +2 -2
- cherrypy_foundation/tools/auth.py +38 -59
- cherrypy_foundation/tools/auth_mfa.py +88 -89
- cherrypy_foundation/tools/errors.py +27 -0
- cherrypy_foundation/tools/i18n.py +153 -246
- cherrypy_foundation/tools/jinja2.py +13 -29
- cherrypy_foundation/tools/ratelimit.py +27 -37
- cherrypy_foundation/tools/secure_headers.py +5 -1
- cherrypy_foundation/tools/sessions_timeout.py +21 -23
- cherrypy_foundation/tools/tests/locales/en/LC_MESSAGES/messages.mo +0 -0
- cherrypy_foundation/tools/tests/locales/{de → en}/LC_MESSAGES/messages.po +2 -2
- cherrypy_foundation/tools/tests/test_auth.py +4 -21
- cherrypy_foundation/tools/tests/test_i18n.py +6 -81
- cherrypy_foundation/tools/tests/test_ratelimit.py +2 -2
- cherrypy_foundation/url.py +25 -25
- cherrypy_foundation/widgets.py +2 -2
- cherrypy_foundation-1.0.0a1.dist-info/METADATA +42 -0
- {cherrypy_foundation-1.0.0.dist-info → cherrypy_foundation-1.0.0a1.dist-info}/RECORD +46 -65
- {cherrypy_foundation-1.0.0.dist-info → cherrypy_foundation-1.0.0a1.dist-info}/WHEEL +1 -1
- cherrypy_foundation/components/Flash.jinja +0 -13
- cherrypy_foundation/components/LocaleSelection.jinja +0 -13
- cherrypy_foundation/components/LocaleSelection.js +0 -26
- cherrypy_foundation/plugins/tests/test_scheduler_db.py +0 -107
- cherrypy_foundation/sessions.py +0 -93
- cherrypy_foundation/tests/templates/test_flash.html +0 -9
- cherrypy_foundation/tests/templates/test_form.html +0 -16
- cherrypy_foundation/tests/templates/test_url.html +0 -15
- cherrypy_foundation/tests/test_flash.py +0 -61
- cherrypy_foundation/tests/test_form.py +0 -148
- cherrypy_foundation/tests/test_logging.py +0 -78
- cherrypy_foundation/tests/test_sessions.py +0 -89
- cherrypy_foundation/tests/test_url.py +0 -161
- cherrypy_foundation/tools/tests/components/Button.jinja +0 -2
- cherrypy_foundation/tools/tests/locales/de/LC_MESSAGES/messages.mo +0 -0
- cherrypy_foundation/tools/tests/templates/test_jinja2.html +0 -11
- cherrypy_foundation/tools/tests/templates/test_jinjax.html +0 -9
- cherrypy_foundation/tools/tests/templates/test_jinjax_i18n.html +0 -22
- cherrypy_foundation/tools/tests/test_auth_mfa.py +0 -369
- cherrypy_foundation/tools/tests/test_jinja2.py +0 -153
- cherrypy_foundation/tools/tests/test_secure_headers.py +0 -200
- cherrypy_foundation-1.0.0.dist-info/METADATA +0 -71
- {cherrypy_foundation-1.0.0.dist-info → cherrypy_foundation-1.0.0a1.dist-info}/licenses/LICENSE.md +0 -0
- {cherrypy_foundation-1.0.0.dist-info → cherrypy_foundation-1.0.0a1.dist-info}/top_level.txt +0 -0
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
# Cherrypy-foundation
|
|
2
|
-
# Copyright (C) 2026 IKUS Software
|
|
3
|
-
#
|
|
4
|
-
# This program is free software: you can redistribute it and/or modify
|
|
5
|
-
# it under the terms of the GNU General Public License as published by
|
|
6
|
-
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
-
# (at your option) any later version.
|
|
8
|
-
#
|
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
# GNU General Public License for more details.
|
|
13
|
-
#
|
|
14
|
-
# You should have received a copy of the GNU General Public License
|
|
15
|
-
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
-
import importlib
|
|
17
|
-
from unittest import skipUnless
|
|
18
|
-
from urllib.parse import urlencode
|
|
19
|
-
|
|
20
|
-
import cherrypy
|
|
21
|
-
from cherrypy.test import helper
|
|
22
|
-
from parameterized import parameterized
|
|
23
|
-
from wtforms.fields import BooleanField, PasswordField, StringField, SubmitField
|
|
24
|
-
from wtforms.validators import InputRequired, Length
|
|
25
|
-
|
|
26
|
-
import cherrypy_foundation.tools.jinja2 # noqa
|
|
27
|
-
from cherrypy_foundation.form import CherryForm
|
|
28
|
-
from cherrypy_foundation.tools.i18n import gettext_lazy as _
|
|
29
|
-
|
|
30
|
-
HAS_JINJAX = importlib.util.find_spec("jinjax") is not None
|
|
31
|
-
|
|
32
|
-
env = cherrypy.tools.jinja2.create_env(
|
|
33
|
-
package_name=__package__,
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class LoginForm(CherryForm):
|
|
38
|
-
login = StringField(
|
|
39
|
-
_('User'),
|
|
40
|
-
validators=[
|
|
41
|
-
InputRequired(),
|
|
42
|
-
Length(max=256, message=_('User too long.')),
|
|
43
|
-
],
|
|
44
|
-
render_kw={
|
|
45
|
-
"placeholder": _('User'),
|
|
46
|
-
"autocorrect": "off",
|
|
47
|
-
"autocapitalize": "none",
|
|
48
|
-
"autocomplete": "off",
|
|
49
|
-
"autofocus": "autofocus",
|
|
50
|
-
},
|
|
51
|
-
)
|
|
52
|
-
password = PasswordField(
|
|
53
|
-
_('Password'),
|
|
54
|
-
validators=[
|
|
55
|
-
InputRequired(),
|
|
56
|
-
Length(max=256, message=_('Password too long.')),
|
|
57
|
-
],
|
|
58
|
-
render_kw={"placeholder": _("Password")},
|
|
59
|
-
)
|
|
60
|
-
persistent = BooleanField(
|
|
61
|
-
_('Remember me'),
|
|
62
|
-
# All `label-*` are assigned to the label tag.
|
|
63
|
-
render_kw={'container_class': 'col-sm-6', 'label-attr': 'FOO'},
|
|
64
|
-
)
|
|
65
|
-
submit = SubmitField(
|
|
66
|
-
_('Login'),
|
|
67
|
-
# All `container-*` are assigned to the container tag.
|
|
68
|
-
render_kw={"class": "btn-primary float-end", 'container_class': 'col-sm-6', 'container-attr': 'BAR'},
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
@cherrypy.tools.sessions()
|
|
73
|
-
@cherrypy.tools.jinja2(env=env)
|
|
74
|
-
class Root:
|
|
75
|
-
|
|
76
|
-
@cherrypy.expose
|
|
77
|
-
def index(self, **kwargs):
|
|
78
|
-
if 'login' not in cherrypy.session:
|
|
79
|
-
raise cherrypy.HTTPRedirect('/login')
|
|
80
|
-
return 'OK'
|
|
81
|
-
|
|
82
|
-
@cherrypy.expose
|
|
83
|
-
@cherrypy.tools.jinja2(template='test_form.html')
|
|
84
|
-
def login(self, **kwargs):
|
|
85
|
-
form = LoginForm()
|
|
86
|
-
if form.validate_on_submit():
|
|
87
|
-
# login user with cherrypy.tools.auth
|
|
88
|
-
cherrypy.session['login'] = True
|
|
89
|
-
raise cherrypy.HTTPRedirect('/')
|
|
90
|
-
return {'form': form}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@skipUnless(HAS_JINJAX, reason='Required jinjax')
|
|
94
|
-
class FormTest(helper.CPWebCase):
|
|
95
|
-
default_lang = None
|
|
96
|
-
interactive = False
|
|
97
|
-
|
|
98
|
-
@classmethod
|
|
99
|
-
def setup_server(cls):
|
|
100
|
-
cherrypy.tree.mount(Root(), '/')
|
|
101
|
-
|
|
102
|
-
def test_get_form(self):
|
|
103
|
-
# Given a form
|
|
104
|
-
# When querying the page that include this form
|
|
105
|
-
self.getPage("/login")
|
|
106
|
-
self.assertStatus(200)
|
|
107
|
-
# Then each field is render properly.
|
|
108
|
-
# 1. Check title
|
|
109
|
-
self.assertInBody('test-form')
|
|
110
|
-
# 2. Check user field
|
|
111
|
-
self.assertInBody('<label class="form-label" for="login">User</label>')
|
|
112
|
-
self.assertInBody(
|
|
113
|
-
'<input autocapitalize="none" autocomplete="off" autocorrect="off" autofocus="autofocus" class="form-control" id="login" maxlength="256" name="login" placeholder="User" required type="text" value="">'
|
|
114
|
-
)
|
|
115
|
-
# 3. Check password
|
|
116
|
-
self.assertInBody('<label class="form-label" for="password">Password</label>')
|
|
117
|
-
self.assertInBody(
|
|
118
|
-
'<input class="form-control" id="password" maxlength="256" name="password" placeholder="Password" required type="password" value="">'
|
|
119
|
-
)
|
|
120
|
-
# 4 Check remember me
|
|
121
|
-
self.assertInBody(
|
|
122
|
-
'<input class="form-check-input" container-class="col-sm-6" id="persistent" label-attr="FOO" name="persistent" type="checkbox" value="y">'
|
|
123
|
-
)
|
|
124
|
-
self.assertInBody('<label attr="FOO" class="form-check-label" for="persistent">Remember me</label>')
|
|
125
|
-
# 5. check submit button (regex matches because class could have different order with jinjax<=0.57)
|
|
126
|
-
self.assertInBody('<div attr="BAR"')
|
|
127
|
-
self.assertMatchesBody(
|
|
128
|
-
'<input class="(btn-primary ?|float-end ?|btn ?){3}" container-attr="BAR" container-class="col-sm-6" id="submit" name="submit" type="submit" value="Login">'
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
@parameterized.expand(
|
|
132
|
-
[
|
|
133
|
-
('myuser', 'mypassword', 0, 303, False),
|
|
134
|
-
('myuser', '', 0, 200, 'Password: This field is required.'),
|
|
135
|
-
('', 'mypassword', 0, 200, 'User: This field is required.'),
|
|
136
|
-
]
|
|
137
|
-
)
|
|
138
|
-
def test_post_form(self, login, password, persistent, expect_status, expect_error):
|
|
139
|
-
# Given a page with a form.
|
|
140
|
-
# When data is sent to the form.
|
|
141
|
-
self.getPage(
|
|
142
|
-
"/login", method='POST', body=urlencode({'login': login, 'password': password, 'persistent': persistent})
|
|
143
|
-
)
|
|
144
|
-
# Then page return a status
|
|
145
|
-
self.assertStatus(expect_status)
|
|
146
|
-
# Then page may return an error
|
|
147
|
-
if expect_error:
|
|
148
|
-
self.assertInBody(expect_error)
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
# CherryPy
|
|
2
|
-
# Copyright (C) 2026 IKUS Software
|
|
3
|
-
#
|
|
4
|
-
# This program is free software: you can redistribute it and/or modify
|
|
5
|
-
# it under the terms of the GNU General Public License as published by
|
|
6
|
-
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
-
# (at your option) any later version.
|
|
8
|
-
#
|
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
# GNU General Public License for more details.
|
|
13
|
-
#
|
|
14
|
-
# You should have received a copy of the GNU General Public License
|
|
15
|
-
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
-
|
|
17
|
-
import tempfile
|
|
18
|
-
from pathlib import Path
|
|
19
|
-
|
|
20
|
-
import cherrypy
|
|
21
|
-
from cherrypy.test import helper
|
|
22
|
-
|
|
23
|
-
from ..logging import setup_logging
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class Root:
|
|
27
|
-
|
|
28
|
-
@cherrypy.expose
|
|
29
|
-
def index(self):
|
|
30
|
-
return "OK"
|
|
31
|
-
|
|
32
|
-
@cherrypy.expose
|
|
33
|
-
def error(self):
|
|
34
|
-
cherrypy.log('error messages to be logged')
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class LoggingTest(helper.CPWebCase):
|
|
38
|
-
interactive = False
|
|
39
|
-
|
|
40
|
-
@classmethod
|
|
41
|
-
def setup_server(cls):
|
|
42
|
-
cls.tempdir = tempfile.TemporaryDirectory(prefix='cherrypy-foundation-', suffix='-logging')
|
|
43
|
-
cls.log_access_file = f'{cls.tempdir.name}/access.log'
|
|
44
|
-
cls.log_file = f'{cls.tempdir.name}/error.log'
|
|
45
|
-
setup_logging(log_file=cls.log_file, log_access_file=cls.log_access_file, level='DEBUG')
|
|
46
|
-
cherrypy.tree.mount(Root(), '/')
|
|
47
|
-
|
|
48
|
-
@classmethod
|
|
49
|
-
def teardown_class(cls):
|
|
50
|
-
# Delete temp folder
|
|
51
|
-
cls.tempdir.cleanup()
|
|
52
|
-
# Stop server
|
|
53
|
-
super().teardown_class()
|
|
54
|
-
# Reset logging to default.
|
|
55
|
-
# Re-enable screen logging
|
|
56
|
-
cherrypy.config.update({'log.screen': True, 'log.error_file': '', 'log.access_file': ''})
|
|
57
|
-
# Reset internal logger references
|
|
58
|
-
cherrypy.log.error_file = None
|
|
59
|
-
cherrypy.log.access_file = None
|
|
60
|
-
|
|
61
|
-
def test_logging_access(self):
|
|
62
|
-
mtime = Path(self.log_access_file).stat().st_mtime
|
|
63
|
-
# When page get queried
|
|
64
|
-
self.getPage('/')
|
|
65
|
-
# Then access files get updated
|
|
66
|
-
mtime2 = Path(self.log_access_file).stat().st_mtime
|
|
67
|
-
self.assertNotEqual(mtime, mtime2)
|
|
68
|
-
|
|
69
|
-
def test_logging_error(self):
|
|
70
|
-
data = Path(self.log_file).read_text()
|
|
71
|
-
self.assertNotIn('error messages to be logged', data)
|
|
72
|
-
# When page get queried
|
|
73
|
-
self.getPage('/error')
|
|
74
|
-
self.assertStatus(200)
|
|
75
|
-
# Then access files get updated
|
|
76
|
-
data2 = Path(self.log_file).read_text()
|
|
77
|
-
self.assertNotEqual(data, data2)
|
|
78
|
-
self.assertIn('error messages to be logged', data2)
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# Cherrypy-foundation
|
|
2
|
-
# Copyright (C) 2026 IKUS Software
|
|
3
|
-
#
|
|
4
|
-
# This program is free software: you can redistribute it and/or modify
|
|
5
|
-
# it under the terms of the GNU General Public License as published by
|
|
6
|
-
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
-
# (at your option) any later version.
|
|
8
|
-
#
|
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
# GNU General Public License for more details.
|
|
13
|
-
#
|
|
14
|
-
# You should have received a copy of the GNU General Public License
|
|
15
|
-
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
-
|
|
17
|
-
import os
|
|
18
|
-
import tempfile
|
|
19
|
-
|
|
20
|
-
import cherrypy
|
|
21
|
-
from cherrypy.test import helper
|
|
22
|
-
|
|
23
|
-
from cherrypy_foundation.sessions import FileSession, session_lock
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@cherrypy.tools.sessions(on=True, locking='explicit', storage_class=FileSession)
|
|
27
|
-
class Root:
|
|
28
|
-
|
|
29
|
-
@cherrypy.expose
|
|
30
|
-
def index(self, value='OK'):
|
|
31
|
-
if value:
|
|
32
|
-
with session_lock() as s:
|
|
33
|
-
s['value'] = value
|
|
34
|
-
return s['value']
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class FileSessionTest(helper.CPWebCase):
|
|
38
|
-
interactive = False
|
|
39
|
-
|
|
40
|
-
@classmethod
|
|
41
|
-
def setup_class(cls):
|
|
42
|
-
cls.tempdir = tempfile.TemporaryDirectory(prefix='cherrypy-foundation-', suffix='-file-session-test')
|
|
43
|
-
cls.storage_path = cls.tempdir.name
|
|
44
|
-
super().setup_class()
|
|
45
|
-
|
|
46
|
-
@classmethod
|
|
47
|
-
def teardown_class(cls):
|
|
48
|
-
cls.tempdir.cleanup()
|
|
49
|
-
super().teardown_class()
|
|
50
|
-
|
|
51
|
-
@classmethod
|
|
52
|
-
def setup_server(cls):
|
|
53
|
-
cherrypy.config.update(
|
|
54
|
-
{
|
|
55
|
-
'tools.sessions.storage_path': cls.storage_path,
|
|
56
|
-
}
|
|
57
|
-
)
|
|
58
|
-
cherrypy.tree.mount(Root(), '/')
|
|
59
|
-
|
|
60
|
-
@property
|
|
61
|
-
def _session_id(self):
|
|
62
|
-
"""Return session id from cookie."""
|
|
63
|
-
if hasattr(self, 'cookies') and self.cookies:
|
|
64
|
-
for unused, value in self.cookies:
|
|
65
|
-
for part in value.split(';'):
|
|
66
|
-
key, unused, value = part.partition('=')
|
|
67
|
-
if key == 'session_id':
|
|
68
|
-
return value
|
|
69
|
-
|
|
70
|
-
def test_get_page(self):
|
|
71
|
-
# Given a page with session enabled
|
|
72
|
-
# When the page get queried
|
|
73
|
-
self.getPage("/")
|
|
74
|
-
# Then a session is created with a id
|
|
75
|
-
self.assertStatus(200)
|
|
76
|
-
self.assertTrue(self._session_id)
|
|
77
|
-
# Then this session is created on disk.
|
|
78
|
-
s = FileSession(id=self._session_id, storage_path=self.storage_path)
|
|
79
|
-
self.assertTrue(s._exists())
|
|
80
|
-
# When session timeout and get clean-up
|
|
81
|
-
s.acquire_lock()
|
|
82
|
-
s.load()
|
|
83
|
-
s.timeout = 0
|
|
84
|
-
s.save()
|
|
85
|
-
s.clean_up()
|
|
86
|
-
# Then session get deleted
|
|
87
|
-
self.assertFalse(s._exists())
|
|
88
|
-
# Lock file also get deleted.
|
|
89
|
-
self.assertFalse(os.path.exists(s._get_file_path() + FileSession.LOCK_SUFFIX))
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
# Cherrypy-foundation
|
|
2
|
-
# Copyright (C) 2026 IKUS Software
|
|
3
|
-
#
|
|
4
|
-
# This program is free software: you can redistribute it and/or modify
|
|
5
|
-
# it under the terms of the GNU General Public License as published by
|
|
6
|
-
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
-
# (at your option) any later version.
|
|
8
|
-
#
|
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
# GNU General Public License for more details.
|
|
13
|
-
#
|
|
14
|
-
# You should have received a copy of the GNU General Public License
|
|
15
|
-
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
-
|
|
17
|
-
import cherrypy
|
|
18
|
-
from cherrypy.test import helper
|
|
19
|
-
|
|
20
|
-
import cherrypy_foundation.tools.jinja2 # noqa
|
|
21
|
-
|
|
22
|
-
from ..url import url_for
|
|
23
|
-
|
|
24
|
-
env = cherrypy.tools.jinja2.create_env(
|
|
25
|
-
package_name=__package__,
|
|
26
|
-
globals={
|
|
27
|
-
'url_for': url_for,
|
|
28
|
-
},
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class SubPage:
|
|
33
|
-
|
|
34
|
-
@cherrypy.expose
|
|
35
|
-
@cherrypy.tools.jinja2(template='test_url.html')
|
|
36
|
-
def index(self, **kwargs):
|
|
37
|
-
_relative = cherrypy.request.headers.get('-Relative')
|
|
38
|
-
return {'kwargs': {'_relative': _relative or None}}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
@cherrypy.tools.proxy(base='https://www.example.com')
|
|
42
|
-
class ProxiedPage:
|
|
43
|
-
|
|
44
|
-
@cherrypy.expose
|
|
45
|
-
@cherrypy.tools.jinja2(template='test_url.html')
|
|
46
|
-
def index(self, **kwargs):
|
|
47
|
-
_relative = cherrypy.request.headers.get('-Relative')
|
|
48
|
-
return {'kwargs': {'_relative': _relative or None}}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@cherrypy.tools.jinja2(env=env)
|
|
52
|
-
class Root:
|
|
53
|
-
sub_page = SubPage()
|
|
54
|
-
proxied = ProxiedPage()
|
|
55
|
-
|
|
56
|
-
@cherrypy.expose
|
|
57
|
-
@cherrypy.tools.jinja2(template='test_url.html')
|
|
58
|
-
def index(self, **kwargs):
|
|
59
|
-
_relative = cherrypy.request.headers.get('-Relative')
|
|
60
|
-
return {'kwargs': {'_relative': _relative or None}}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class UrlTest(helper.CPWebCase):
|
|
64
|
-
default_lang = None
|
|
65
|
-
interactive = False
|
|
66
|
-
|
|
67
|
-
@classmethod
|
|
68
|
-
def setup_server(cls):
|
|
69
|
-
cherrypy.tree.mount(Root(), '/')
|
|
70
|
-
|
|
71
|
-
def test_url_for(self):
|
|
72
|
-
self.assertEqual(url_for("foo", "bar"), 'http://127.0.0.1:54583/foo/bar')
|
|
73
|
-
self.assertEqual(url_for("foo", "bar", _relative='server'), '/foo/bar')
|
|
74
|
-
# Outside a request, relative url doesn't make alot of sens.
|
|
75
|
-
self.assertEqual(url_for("foo", "bar", _relative=1), '127.0.0.1:54583/foo/bar')
|
|
76
|
-
self.assertEqual(url_for("foo", "bar", _base='http://test.com'), 'http://test.com/foo/bar')
|
|
77
|
-
|
|
78
|
-
def test_get_page(self):
|
|
79
|
-
# Given a form
|
|
80
|
-
# When querying the page that include this form
|
|
81
|
-
self.getPage("/")
|
|
82
|
-
self.assertStatus(200)
|
|
83
|
-
# Then each field is render properly.
|
|
84
|
-
# 1. Check title
|
|
85
|
-
self.assertInBody('test-url')
|
|
86
|
-
# 2. Check user field
|
|
87
|
-
self.assertInBody(f'Empty: http://{self.HOST}:{self.PORT}/')
|
|
88
|
-
self.assertInBody(f'Dot: http://{self.HOST}:{self.PORT}/')
|
|
89
|
-
self.assertInBody(f'Dot page: http://{self.HOST}:{self.PORT}/my-page')
|
|
90
|
-
self.assertInBody(f'Slash: http://{self.HOST}:{self.PORT}/')
|
|
91
|
-
self.assertInBody(f'Page: http://{self.HOST}:{self.PORT}/my-page')
|
|
92
|
-
self.assertInBody(f'Slash page: http://{self.HOST}:{self.PORT}/my-page')
|
|
93
|
-
self.assertInBody(f'Query: http://{self.HOST}:{self.PORT}/my-page?bar=test+with+space&foo=1')
|
|
94
|
-
|
|
95
|
-
def test_get_page_relative_true(self):
|
|
96
|
-
# Given a form
|
|
97
|
-
# When querying the page that include this form
|
|
98
|
-
self.getPage("/", headers=[('_relative', '1')])
|
|
99
|
-
self.assertStatus(200)
|
|
100
|
-
# Then each field is render properly.
|
|
101
|
-
# 1. Check title
|
|
102
|
-
self.assertInBody('test-url')
|
|
103
|
-
# 2. Check user field
|
|
104
|
-
self.assertInBody('Empty: <br/>')
|
|
105
|
-
self.assertInBody('Dot: <br/>')
|
|
106
|
-
self.assertInBody('Dot page: my-page<br/>')
|
|
107
|
-
self.assertInBody('Slash: <br/>')
|
|
108
|
-
self.assertInBody('Page: my-page<br/>')
|
|
109
|
-
self.assertInBody('Slash page: my-page<br/>')
|
|
110
|
-
self.assertInBody('Query: my-page?bar=test+with+space&foo=1<br/>')
|
|
111
|
-
|
|
112
|
-
def test_get_page_relative_server(self):
|
|
113
|
-
# Given a form
|
|
114
|
-
# When querying the page that include this form
|
|
115
|
-
self.getPage("/", headers=[('_relative', 'server')])
|
|
116
|
-
self.assertStatus(200)
|
|
117
|
-
# Then each field is render properly.
|
|
118
|
-
# 1. Check title
|
|
119
|
-
self.assertInBody('test-url')
|
|
120
|
-
# 2. Check user field
|
|
121
|
-
self.assertInBody('Empty: /<br/>')
|
|
122
|
-
self.assertInBody('Dot: /<br/>')
|
|
123
|
-
self.assertInBody('Dot page: /my-page<br/>')
|
|
124
|
-
self.assertInBody('Slash: /<br/>')
|
|
125
|
-
self.assertInBody('Page: /my-page<br/>')
|
|
126
|
-
self.assertInBody('Slash page: /my-page<br/>')
|
|
127
|
-
self.assertInBody('Query: /my-page?bar=test+with+space&foo=1<br/>')
|
|
128
|
-
|
|
129
|
-
def test_get_page_proxied(self):
|
|
130
|
-
# Given a form
|
|
131
|
-
# When querying the page that include this form
|
|
132
|
-
self.getPage("/proxied/")
|
|
133
|
-
self.assertStatus(200)
|
|
134
|
-
# Then each field is render properly.
|
|
135
|
-
# 1. Check title
|
|
136
|
-
self.assertInBody('test-url')
|
|
137
|
-
# 2. Check user field
|
|
138
|
-
self.assertInBody('Empty: https://www.example.com/')
|
|
139
|
-
self.assertInBody('Dot: https://www.example.com/proxied/')
|
|
140
|
-
self.assertInBody('Dot page: https://www.example.com/proxied/my-page<br/>')
|
|
141
|
-
self.assertInBody('Slash: https://www.example.com/')
|
|
142
|
-
self.assertInBody('Page: https://www.example.com/my-page')
|
|
143
|
-
self.assertInBody('Slash page: https://www.example.com/my-page')
|
|
144
|
-
self.assertInBody('Query: https://www.example.com/my-page?bar=test+with+space&foo=1')
|
|
145
|
-
|
|
146
|
-
def test_get_sub_page(self):
|
|
147
|
-
# Given a form
|
|
148
|
-
# When querying the page that include this form
|
|
149
|
-
self.getPage("/sub-page/")
|
|
150
|
-
self.assertStatus(200)
|
|
151
|
-
# Then each field is render properly.
|
|
152
|
-
# 1. Check title
|
|
153
|
-
self.assertInBody('test-url')
|
|
154
|
-
# 2. Check user field
|
|
155
|
-
self.assertInBody(f'Empty: http://{self.HOST}:{self.PORT}/sub-page/')
|
|
156
|
-
self.assertInBody(f'Dot: http://{self.HOST}:{self.PORT}/sub-page/')
|
|
157
|
-
self.assertInBody(f'Dot page: http://{self.HOST}:{self.PORT}/sub-page/my-page')
|
|
158
|
-
self.assertInBody(f'Slash: http://{self.HOST}:{self.PORT}/')
|
|
159
|
-
self.assertInBody(f'Page: http://{self.HOST}:{self.PORT}/my-page')
|
|
160
|
-
self.assertInBody(f'Slash page: http://{self.HOST}:{self.PORT}/my-page')
|
|
161
|
-
self.assertInBody(f'Query: http://{self.HOST}:{self.PORT}/my-page?bar=test+with+space&foo=1')
|
|
Binary file
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="{{ get_translation().locale }}">
|
|
3
|
-
<head>
|
|
4
|
-
<title>test-jinja2</title>
|
|
5
|
-
{{ catalog.render_assets() }}
|
|
6
|
-
</head>
|
|
7
|
-
<body>
|
|
8
|
-
<!-- Selector -->
|
|
9
|
-
<div class="dropdown">
|
|
10
|
-
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
11
|
-
Dropdown button
|
|
12
|
-
</button>
|
|
13
|
-
<ul class="dropdown-menu">
|
|
14
|
-
<LocaleSelection />
|
|
15
|
-
</ul>
|
|
16
|
-
</div>
|
|
17
|
-
{{ get_language_name(get_translation().locale) }}<br/>
|
|
18
|
-
{% trans %}Some text to translate{% endtrans %}<br/>
|
|
19
|
-
{{ my_datetime | format_datetime(format='full') }}<br/>
|
|
20
|
-
{{ my_date | format_date(format='full') }}
|
|
21
|
-
</body>
|
|
22
|
-
</html>
|