cherrypy-foundation 1.0.0__py3-none-any.whl → 1.0.0a2__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 +2 -4
- 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 +3 -3
- 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 +1 -1
- cherrypy_foundation/plugins/ldap.py +25 -27
- cherrypy_foundation/plugins/restapi.py +1 -1
- cherrypy_foundation/plugins/scheduler.py +3 -14
- cherrypy_foundation/plugins/smtp.py +2 -8
- cherrypy_foundation/plugins/tests/test_db.py +2 -2
- cherrypy_foundation/plugins/tests/test_ldap.py +3 -76
- cherrypy_foundation/plugins/tests/test_scheduler.py +1 -1
- cherrypy_foundation/plugins/tests/test_smtp.py +1 -31
- cherrypy_foundation/tests/__init__.py +0 -72
- cherrypy_foundation/tests/templates/test_form.html +1 -7
- cherrypy_foundation/tests/test_error_page.py +1 -7
- cherrypy_foundation/tests/test_form.py +11 -40
- cherrypy_foundation/tests/test_passwd.py +2 -2
- cherrypy_foundation/tools/auth.py +27 -31
- cherrypy_foundation/tools/auth_mfa.py +83 -87
- cherrypy_foundation/tools/errors.py +27 -0
- cherrypy_foundation/tools/i18n.py +151 -235
- cherrypy_foundation/tools/jinja2.py +2 -15
- cherrypy_foundation/tools/ratelimit.py +18 -32
- cherrypy_foundation/tools/secure_headers.py +1 -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/templates/test_jinja2.html +1 -2
- cherrypy_foundation/tools/tests/templates/test_jinja2_i18n.html +11 -0
- cherrypy_foundation/tools/tests/templates/test_jinjax.html +2 -3
- cherrypy_foundation/tools/tests/test_auth.py +3 -20
- cherrypy_foundation/tools/tests/test_auth_mfa.py +4 -6
- cherrypy_foundation/tools/tests/test_i18n.py +6 -81
- cherrypy_foundation/tools/tests/test_jinja2.py +5 -35
- 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.0a2.dist-info/METADATA +42 -0
- {cherrypy_foundation-1.0.0.dist-info → cherrypy_foundation-1.0.0a2.dist-info}/RECORD +53 -64
- {cherrypy_foundation-1.0.0.dist-info → cherrypy_foundation-1.0.0a2.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_url.html +0 -15
- cherrypy_foundation/tests/test_flash.py +0 -61
- 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/locales/de/LC_MESSAGES/messages.mo +0 -0
- cherrypy_foundation/tools/tests/templates/test_jinjax_i18n.html +0 -22
- 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.0a2.dist-info}/licenses/LICENSE.md +0 -0
- {cherrypy_foundation-1.0.0.dist-info → cherrypy_foundation-1.0.0a2.dist-info}/top_level.txt +0 -0
cherrypy_foundation/url.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Copyright (C)
|
|
1
|
+
# CherryPy Foundation
|
|
2
|
+
# Copyright (C) 2025 IKUS Software inc.
|
|
3
3
|
#
|
|
4
4
|
# This program is free software: you can redistribute it and/or modify
|
|
5
5
|
# it under the terms of the GNU General Public License as published by
|
|
@@ -14,12 +14,10 @@
|
|
|
14
14
|
# You should have received a copy of the GNU General Public License
|
|
15
15
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
16
|
|
|
17
|
-
from urllib.parse import urljoin
|
|
18
|
-
|
|
19
17
|
import cherrypy
|
|
20
18
|
|
|
21
19
|
|
|
22
|
-
def url_for(*args,
|
|
20
|
+
def url_for(*args, relative=None, **kwargs):
|
|
23
21
|
"""
|
|
24
22
|
Generate a URL for the given endpoint/path (*args) with query params (**kwargs).
|
|
25
23
|
|
|
@@ -35,32 +33,34 @@ def url_for(*args, _relative=None, _base=None, **kwargs):
|
|
|
35
33
|
- Integers are appended as path segments.
|
|
36
34
|
- When path == "", existing request query parameters are merged (kwargs win).
|
|
37
35
|
"""
|
|
38
|
-
|
|
39
|
-
qs = [(k, v) for k, v in sorted(kwargs.items()) if v is not None]
|
|
40
|
-
|
|
41
|
-
path = []
|
|
36
|
+
path = ""
|
|
42
37
|
for chunk in args:
|
|
43
|
-
if
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
path.
|
|
47
|
-
elif isinstance(chunk, str):
|
|
48
|
-
path.append(chunk)
|
|
38
|
+
if isinstance(chunk, str):
|
|
39
|
+
if not chunk.startswith('.'):
|
|
40
|
+
path += "/"
|
|
41
|
+
path += chunk.rstrip("/")
|
|
49
42
|
elif isinstance(chunk, int):
|
|
50
|
-
path
|
|
43
|
+
path += "/"
|
|
44
|
+
path += str(chunk)
|
|
45
|
+
elif hasattr(chunk, '__url_for__') and callable(chunk.__url_for__):
|
|
46
|
+
path += "/"
|
|
47
|
+
path += str(chunk.__url_for__())
|
|
48
|
+
elif hasattr(chunk, 'url_for'):
|
|
49
|
+
path += "/"
|
|
50
|
+
path += str(chunk.url_for)
|
|
51
51
|
else:
|
|
52
52
|
raise ValueError('invalid positional arguments, url_for accept str, bytes, int: %r' % chunk)
|
|
53
|
-
path = '/'.join(path)
|
|
54
53
|
# When path is empty, we are browsing the same page.
|
|
55
54
|
# Let keep the original query_string to avoid loosing it.
|
|
56
|
-
if
|
|
55
|
+
if path == "":
|
|
57
56
|
params = cherrypy.request.params.copy()
|
|
58
57
|
params.update(kwargs)
|
|
59
58
|
qs = [(k, v) for k, v in sorted(params.items()) if v is not None]
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
# Outside a request, use
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
else:
|
|
60
|
+
qs = [(k, v) for k, v in sorted(kwargs.items()) if v is not None]
|
|
61
|
+
# Outside a request, use the external_url as base if defined
|
|
62
|
+
base = None
|
|
63
|
+
if not cherrypy.request.app:
|
|
64
|
+
cfg = cherrypy.tree.apps[''].cfg
|
|
65
|
+
base = cfg.external_url
|
|
66
|
+
return cherrypy.url(path=path, qs=qs, relative=relative, base=base)
|
cherrypy_foundation/widgets.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Copyright (C) 2020-
|
|
1
|
+
# CherryPy Foundation
|
|
2
|
+
# Copyright (C) 2020-2025 IKUS Software
|
|
3
3
|
#
|
|
4
4
|
# This program is free software: you can redistribute it and/or modify
|
|
5
5
|
# it under the terms of the GNU General Public License as published by
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cherrypy-foundation
|
|
3
|
+
Version: 1.0.0a2
|
|
4
|
+
Summary: CherryPy Foundation
|
|
5
|
+
Author-email: Patrik Dufresne <patrik@ikus-soft.com>
|
|
6
|
+
License: GPLv3
|
|
7
|
+
Project-URL: Homepage, https://gitlab.com/ikus-soft/cherrypy-foundation
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Framework :: CherryPy
|
|
10
|
+
Classifier: Intended Audience :: System Administrators
|
|
11
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Python: <4,>=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE.md
|
|
18
|
+
Requires-Dist: babel
|
|
19
|
+
Requires-Dist: CherryPy
|
|
20
|
+
Requires-Dist: Jinja2
|
|
21
|
+
Requires-Dist: jinjax
|
|
22
|
+
Requires-Dist: pytz
|
|
23
|
+
Requires-Dist: WTForms>=3.2.1
|
|
24
|
+
Provides-Extra: test
|
|
25
|
+
Requires-Dist: ldap3; extra == "test"
|
|
26
|
+
Requires-Dist: apscheduler; extra == "test"
|
|
27
|
+
Requires-Dist: sqlalchemy; extra == "test"
|
|
28
|
+
Requires-Dist: parameterized; extra == "test"
|
|
29
|
+
Requires-Dist: pytest; extra == "test"
|
|
30
|
+
Requires-Dist: selenium; extra == "test"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# Cherrypy-foundation
|
|
34
|
+
|
|
35
|
+
<p align="center">
|
|
36
|
+
<a href="LICENSE"><img alt="License" src="https://img.shields.io/badge/license-GPL--3.0-orange"></a>
|
|
37
|
+
<a href="https://gitlab.com/ikus-soft/cherrypy-foundation/pipelines"><img alt="Build" src="https://gitlab.com/ikus-soft/cherrypy-foundation/badges/master/pipeline.svg"></a>
|
|
38
|
+
<a href="https://sonar.ikus-soft.com/dashboard?id=cherrypy-foundation"><img alt="Quality Gate" src="https://sonar.ikus-soft.com/api/project_badges/measure?project=cherrypy-foundation&metric=alert_status"></a>
|
|
39
|
+
<a href="https://sonar.ikus-soft.com/dashboard?id=cherrypy-foundation"><img alt="Coverage" src="https://sonar.ikus-soft.com/api/project_badges/measure?project=cherrypy-foundation&metric=coverage"></a>
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
This project is a collection of common utilities for creating web applications with CherryPy. It provides integrations with SQLAlchemy, Jinja2, WTForms, and Bootstrap.
|
|
@@ -1,33 +1,29 @@
|
|
|
1
1
|
cherrypy_foundation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
cherrypy_foundation/error_page.py,sha256=
|
|
3
|
-
cherrypy_foundation/flash.py,sha256=
|
|
4
|
-
cherrypy_foundation/form.py,sha256=
|
|
5
|
-
cherrypy_foundation/logging.py,sha256=
|
|
6
|
-
cherrypy_foundation/passwd.py,sha256=
|
|
7
|
-
cherrypy_foundation/
|
|
8
|
-
cherrypy_foundation/
|
|
9
|
-
cherrypy_foundation/
|
|
10
|
-
cherrypy_foundation/components/ColorModes.jinja,sha256=Ai2fy1qHFwEgutvyvvGjKJmffcBdNb7wmY20DJqZ8R4,3528
|
|
2
|
+
cherrypy_foundation/error_page.py,sha256=Mz47u6n4eqQ85LKT9lWglqPPtmizikY9xBsrhGl7_nI,3198
|
|
3
|
+
cherrypy_foundation/flash.py,sha256=fFRbutUX6c1lVHqjehmO9y98dJgmfNCjhd76t2mth2s,1542
|
|
4
|
+
cherrypy_foundation/form.py,sha256=8c9dO0o47sK3CBosTkGXoVRtzNQwY0aw0vNZfTqmhvo,3994
|
|
5
|
+
cherrypy_foundation/logging.py,sha256=YIOK5ZAZLCv52YDdP66yBYpEX1C336JnI3wnrTKl1Lw,3468
|
|
6
|
+
cherrypy_foundation/passwd.py,sha256=ZGdrBNKtLP75l01W6VEd8cIjSQ3guJ_YVPEfbSew7T0,2144
|
|
7
|
+
cherrypy_foundation/url.py,sha256=n12rU2R3VoPbGJ01-iXIMlZL4ohpVhk3vOc-__KkPzE,2814
|
|
8
|
+
cherrypy_foundation/widgets.py,sha256=0B5Y2V6x5Ufl6ExR3tc0Olrzj7N4TAAOtqGq_MUxBG0,1549
|
|
9
|
+
cherrypy_foundation/components/ColorModes.jinja,sha256=8MzkeZsra1wtIdiaQKc7UQUbMfRMUlmM6e9X7V1vfq0,3501
|
|
11
10
|
cherrypy_foundation/components/Datatable.css,sha256=7wSwgdA61vYCdEuQ0bp2o0oSvu5mGLN1c6ovCUSe718,947
|
|
12
|
-
cherrypy_foundation/components/Datatable.jinja,sha256=
|
|
13
|
-
cherrypy_foundation/components/Datatable.js,sha256=
|
|
11
|
+
cherrypy_foundation/components/Datatable.jinja,sha256=K-24vpN5TO8Jk2COvuC5uBaCj3PFLd6ubr28JHFq3KM,3375
|
|
12
|
+
cherrypy_foundation/components/Datatable.js,sha256=jiV78bJPNMTLcjrX03vaYcsEdRbI6ctzSvCo880H8Hw,12072
|
|
14
13
|
cherrypy_foundation/components/Field.css,sha256=CtOkvIbix7ykrOKLJxQJLJsWfEwFqfducJ1BH2vlMvA,244
|
|
15
|
-
cherrypy_foundation/components/Field.jinja,sha256=
|
|
14
|
+
cherrypy_foundation/components/Field.jinja,sha256=R-ZUm88XXOb3zi_hysTuwFUCGGR67A59P4TT5d1Qo_o,3152
|
|
16
15
|
cherrypy_foundation/components/Field.js,sha256=SFixZ62WlLq7SSCEazMAGhSnc9EnQ1wg6PZX4ayO6ZE,2047
|
|
17
|
-
cherrypy_foundation/components/Fields.jinja,sha256=
|
|
18
|
-
cherrypy_foundation/components/Flash.jinja,sha256=COy44drQsXpbZajjJS4w_9NMPYFdMfUNdfhd7SbFdYA,442
|
|
16
|
+
cherrypy_foundation/components/Fields.jinja,sha256=UDu1txwMguvr7dyga9PXepEhFvz9C6ZvchBnhQCWgHI,318
|
|
19
17
|
cherrypy_foundation/components/Icon.jinja,sha256=Z1RGYBg5xlDEoUy3glqb_k_LEjkJHeCxQXqDEvWzEF4,135
|
|
20
|
-
cherrypy_foundation/components/LocaleSelection.jinja,sha256=NHhQGI6CCJl4LWl-eteu_AIg1_qc1MusuA1fKcrjluQ,509
|
|
21
|
-
cherrypy_foundation/components/LocaleSelection.js,sha256=-iTZD5ejg1R9F3tZASTH7dkgd19upke-pzOhsZ9K_LA,670
|
|
22
18
|
cherrypy_foundation/components/SideBySideMultiSelect.css,sha256=_poMY9O8rvDsOh01pQLf9qtg1Gm4eCM2HsM_ekC5zkk,503
|
|
23
19
|
cherrypy_foundation/components/SideBySideMultiSelect.jinja,sha256=sud1WP-6JzuP7ZLRr-JQqvgMRWZRlXvxUJfguFr_klk,478
|
|
24
20
|
cherrypy_foundation/components/SideBySideMultiSelect.js,sha256=5YMz1pgkXeWC_SRRfDbQI3X-c4PuxiTIpbWJt9sY7Rc,197
|
|
25
|
-
cherrypy_foundation/components/Typeahead.css,sha256=
|
|
26
|
-
cherrypy_foundation/components/Typeahead.jinja,sha256=
|
|
21
|
+
cherrypy_foundation/components/Typeahead.css,sha256=8VyPN6FP_l0_mRyES2tjrwr9rEkKT4y0obeBI6nfGLk,1645
|
|
22
|
+
cherrypy_foundation/components/Typeahead.jinja,sha256=g7oiiROxIjwkgwiZtxxFlSIIaWUr2ml2eS0RWm7yUvU,3215
|
|
27
23
|
cherrypy_foundation/components/Typeahead.js,sha256=mnsPRwM_1xtI7ImGn_pu46QdFw_LK_PDHNCRKp_CVxc,236
|
|
28
|
-
cherrypy_foundation/components/__init__.py,sha256=
|
|
24
|
+
cherrypy_foundation/components/__init__.py,sha256=Ck_AY_eTkq4Pyf-jjyOxwfpoKXgtCx90hJpRHPRiA_Q,2012
|
|
29
25
|
cherrypy_foundation/components/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
|
-
cherrypy_foundation/components/tests/test_static.py,sha256=
|
|
26
|
+
cherrypy_foundation/components/tests/test_static.py,sha256=bDtS0CFM5LZxwxbXbUyLkXv7sM5KM-eQtHOWywZu_nc,3814
|
|
31
27
|
cherrypy_foundation/components/vendor/bootstrap-icons/bootstrap-icons.css,sha256=AEMichyFVzMXWbxt2qy7aJsPBxXWiK7IK9BW0tW1zDs,99556
|
|
32
28
|
cherrypy_foundation/components/vendor/bootstrap-icons/bootstrap-icons.min.css,sha256=pdY4ejLKO67E0CM2tbPtq1DJ3VGDVVdqAR6j3ZwdiE4,87008
|
|
33
29
|
cherrypy_foundation/components/vendor/bootstrap-icons/fonts/bootstrap-icons.woff,sha256=9VUTt7WRy4SjuH_w406iTUgx1v7cIuVLkRymS1tUShU,180288
|
|
@@ -83,54 +79,47 @@ cherrypy_foundation/components/vendor/popper/popper.min.js,sha256=whL0tQWoY1Ku1i
|
|
|
83
79
|
cherrypy_foundation/components/vendor/typeahead/jquery.typeahead.min.css,sha256=gBsvk2nlQnvCXdG7JITz1SrnqWQrO6EsUo_r06-KRtU,12464
|
|
84
80
|
cherrypy_foundation/components/vendor/typeahead/jquery.typeahead.min.js,sha256=eFBtgouYdW587kYINWsjkN-UR8GVWAG_fQe1fpJfjOw,47828
|
|
85
81
|
cherrypy_foundation/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
86
|
-
cherrypy_foundation/plugins/db.py,sha256=
|
|
87
|
-
cherrypy_foundation/plugins/ldap.py,sha256=
|
|
88
|
-
cherrypy_foundation/plugins/restapi.py,sha256=
|
|
89
|
-
cherrypy_foundation/plugins/scheduler.py,sha256=
|
|
90
|
-
cherrypy_foundation/plugins/smtp.py,sha256=
|
|
82
|
+
cherrypy_foundation/plugins/db.py,sha256=46S-2kR9BHVYRN9cxWwYfzY2WkpEVBCpx1ubsJolYfA,10108
|
|
83
|
+
cherrypy_foundation/plugins/ldap.py,sha256=N-bJT7daJcLybEigA3P_5iuDr4PFwmLt8YzcMrWafAY,9870
|
|
84
|
+
cherrypy_foundation/plugins/restapi.py,sha256=S5GIxHL0M3Wcs33fyVOb0RfX1FXbp2fqUxJ_ufqBrD4,2843
|
|
85
|
+
cherrypy_foundation/plugins/scheduler.py,sha256=H6ExfmAlTPt2ypK5lBMynNfcUzcWK_n1EP2_K5x2bx8,10400
|
|
86
|
+
cherrypy_foundation/plugins/smtp.py,sha256=yTCUj2XzrJEJ84CIbYcrCUAP6Mg59aZfu6OZDGQyJbQ,7479
|
|
91
87
|
cherrypy_foundation/plugins/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
92
|
-
cherrypy_foundation/plugins/tests/test_db.py,sha256=
|
|
93
|
-
cherrypy_foundation/plugins/tests/test_ldap.py,sha256=
|
|
94
|
-
cherrypy_foundation/plugins/tests/test_scheduler.py,sha256=
|
|
95
|
-
cherrypy_foundation/plugins/tests/
|
|
96
|
-
cherrypy_foundation/
|
|
97
|
-
cherrypy_foundation/tests/
|
|
98
|
-
cherrypy_foundation/tests/
|
|
99
|
-
cherrypy_foundation/tests/
|
|
100
|
-
cherrypy_foundation/tests/test_form.
|
|
101
|
-
cherrypy_foundation/tests/test_logging.py,sha256=Lg1yGwFHTSpGbPvNXBi9risypZziJlAOMi1DeennxRs,2623
|
|
102
|
-
cherrypy_foundation/tests/test_passwd.py,sha256=nGqJZYwRPziifLvf5rm3YifxAvIOFdU_6LkHaUvRk8w,1951
|
|
103
|
-
cherrypy_foundation/tests/test_sessions.py,sha256=_jcCn75hMGr7ETucWZnCqWcI3pw5PCdlzPQuxdE4yZE,2873
|
|
104
|
-
cherrypy_foundation/tests/test_url.py,sha256=sSNwK7KZJcrLtnf_XROYQAPQoYNO5lAsa2BjhFjgmws,6434
|
|
105
|
-
cherrypy_foundation/tests/templates/test_flash.html,sha256=b1S4I9v0n-Y1yoTUh2ZKNysR1NMrqv8ldvqONtmInzw,213
|
|
106
|
-
cherrypy_foundation/tests/templates/test_form.html,sha256=liubTm2q74-3hqQb4weaGJU3sq4vdq868GdVahBafSQ,333
|
|
107
|
-
cherrypy_foundation/tests/templates/test_url.html,sha256=xoyRIkIzzM8Q-M39i80P4j7Wo8Lkzh1rIzRq-40Szak,528
|
|
88
|
+
cherrypy_foundation/plugins/tests/test_db.py,sha256=PELi5ojj8VqcXyPbpaig2Ac4ZqlR_gEPGUYrWJPANWg,3921
|
|
89
|
+
cherrypy_foundation/plugins/tests/test_ldap.py,sha256=7EhFvhxwDCCBoNlAD5XpZxLtKvkrjpQxrtCHMT9wkQ4,14393
|
|
90
|
+
cherrypy_foundation/plugins/tests/test_scheduler.py,sha256=I-ZuQhMvCCvqFDwukwsyz_UkdJJ8JSLTkAanUo24GCE,3564
|
|
91
|
+
cherrypy_foundation/plugins/tests/test_smtp.py,sha256=qs5yezIpSXkBmLmFlqckfPW7NmntHZxQjDSkdQG_dNE,4183
|
|
92
|
+
cherrypy_foundation/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
93
|
+
cherrypy_foundation/tests/test_error_page.py,sha256=8u5p6lv_I4XvfGipjJXNFwW7G1N8AK8IOnc_Th-Ebto,2181
|
|
94
|
+
cherrypy_foundation/tests/test_form.py,sha256=urYi0qC8JqelopdeLBHvtndEv0QJ0hwlv3JkpAvdCYQ,4324
|
|
95
|
+
cherrypy_foundation/tests/test_passwd.py,sha256=gC5O4yhHyU1YRYuDc0pG0T_5zvrG2qrr6P822iyK3Rg,1956
|
|
96
|
+
cherrypy_foundation/tests/templates/test_form.html,sha256=sm-n2cYvih2vbDE4Y8kkERSoulnKAbwoefbzBggMMnA,189
|
|
108
97
|
cherrypy_foundation/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
109
|
-
cherrypy_foundation/tools/auth.py,sha256=
|
|
110
|
-
cherrypy_foundation/tools/auth_mfa.py,sha256=
|
|
111
|
-
cherrypy_foundation/tools/
|
|
112
|
-
cherrypy_foundation/tools/
|
|
113
|
-
cherrypy_foundation/tools/
|
|
114
|
-
cherrypy_foundation/tools/
|
|
115
|
-
cherrypy_foundation/tools/
|
|
98
|
+
cherrypy_foundation/tools/auth.py,sha256=lTSajxCiReMzm-Fl-xhTByi4yFnInEWOoNsmUMnHQhs,9761
|
|
99
|
+
cherrypy_foundation/tools/auth_mfa.py,sha256=VaLvBz9wo6jTx-2mCGqFXPxl-z14f8UMWvd6_xeXd40,9212
|
|
100
|
+
cherrypy_foundation/tools/errors.py,sha256=ELpAj0N9kIxC22QW5xDQJz60zMpCwgm-Twu2WpELM1A,1005
|
|
101
|
+
cherrypy_foundation/tools/i18n.py,sha256=5pcyr7AleaqSj9rCESthvMIbNIORp-8351uJgmi2xog,14172
|
|
102
|
+
cherrypy_foundation/tools/jinja2.py,sha256=nppYnk2ASDsyfNHF9m83W4foiN3MhcwDJvo5baEgnGU,5520
|
|
103
|
+
cherrypy_foundation/tools/ratelimit.py,sha256=pT7vZRmjltNeuiQpdyXOmnpG9BcXjLaj-AXJ0e2x_zw,8300
|
|
104
|
+
cherrypy_foundation/tools/secure_headers.py,sha256=Yh-iA_Js4MUsx5nq4ilbc-iWy90ZC0oMb3TJJD_UwYo,3921
|
|
105
|
+
cherrypy_foundation/tools/sessions_timeout.py,sha256=6iBWJntPMk_Qt94fBSfBISf1IXInSh-1XrxLbKXFV-g,7408
|
|
116
106
|
cherrypy_foundation/tools/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
117
|
-
cherrypy_foundation/tools/tests/test_auth.py,sha256=
|
|
118
|
-
cherrypy_foundation/tools/tests/test_auth_mfa.py,sha256=
|
|
119
|
-
cherrypy_foundation/tools/tests/test_i18n.py,sha256
|
|
120
|
-
cherrypy_foundation/tools/tests/test_jinja2.py,sha256=
|
|
121
|
-
cherrypy_foundation/tools/tests/test_ratelimit.py,sha256=
|
|
122
|
-
cherrypy_foundation/tools/tests/test_secure_headers.py,sha256=Iu3X7u6VJpWOmuNMv1qZFh0oPWdLZAdoJppRyuTV148,7769
|
|
107
|
+
cherrypy_foundation/tools/tests/test_auth.py,sha256=oeM5t38M8DUC9dYn59dcf00jdGY6Ry0jZWhQd_PYQUk,2847
|
|
108
|
+
cherrypy_foundation/tools/tests/test_auth_mfa.py,sha256=911hnBbdg5CKb613uIBrlggoTAyBU9SoL7Sxd-tIKS0,15008
|
|
109
|
+
cherrypy_foundation/tools/tests/test_i18n.py,sha256=-bJuKn8PHHidBWhoFSVr4PdX96m3A50YY4i5osyU7DY,6251
|
|
110
|
+
cherrypy_foundation/tools/tests/test_jinja2.py,sha256=_dkRJpjB0ybDV6YO0uEFFO8LAcWgVu3VBB8_vWthQ48,4296
|
|
111
|
+
cherrypy_foundation/tools/tests/test_ratelimit.py,sha256=rrqybwMbh1GFlF2-Ut57zHPAc1uqX88aqea6VS_6p5E,3449
|
|
123
112
|
cherrypy_foundation/tools/tests/components/Button.jinja,sha256=uSLp1GpEIgZNXK_GWglu0E_a1c3jHpDLI66MRfMqGhE,95
|
|
124
113
|
cherrypy_foundation/tools/tests/locales/messages.pot,sha256=5K9piTRL7H5MxDXFIWJsCccSJRA0HwfCQQU8b8VYo30,40
|
|
125
|
-
cherrypy_foundation/tools/tests/locales/
|
|
126
|
-
cherrypy_foundation/tools/tests/locales/
|
|
114
|
+
cherrypy_foundation/tools/tests/locales/en/LC_MESSAGES/messages.mo,sha256=cdyG2Js1TIU6eenDX1ICH8uP45yvl0OLN0-SMUXTBa4,259
|
|
115
|
+
cherrypy_foundation/tools/tests/locales/en/LC_MESSAGES/messages.po,sha256=JCpiRLLHUSYQhzta8ZYjfB50NmpwPGNCTNwo2Glww14,322
|
|
127
116
|
cherrypy_foundation/tools/tests/locales/fr/LC_MESSAGES/messages.mo,sha256=u3_kl_nqZ3FNaSyKVQKmu4KJzN3xOxxJNVmcdhw37jA,327
|
|
128
117
|
cherrypy_foundation/tools/tests/locales/fr/LC_MESSAGES/messages.po,sha256=6_Sk9Igqm7dtpyyS701p5qc4DvOJE7TRT0ajRZctFAQ,342
|
|
129
|
-
cherrypy_foundation/tools/tests/templates/test_jinja2.html,sha256=
|
|
130
|
-
cherrypy_foundation/tools/tests/templates/
|
|
131
|
-
cherrypy_foundation/tools/tests/templates/
|
|
132
|
-
cherrypy_foundation-1.0.
|
|
133
|
-
cherrypy_foundation-1.0.
|
|
134
|
-
cherrypy_foundation-1.0.
|
|
135
|
-
cherrypy_foundation-1.0.
|
|
136
|
-
cherrypy_foundation-1.0.
|
|
118
|
+
cherrypy_foundation/tools/tests/templates/test_jinja2.html,sha256=v9AHxksbBvzE7sesPqE61HMhsvU4juXt3E0ZQo-zXVQ,190
|
|
119
|
+
cherrypy_foundation/tools/tests/templates/test_jinja2_i18n.html,sha256=98S51dgG7Vb4rvMZNZvomw1D9pBiM4g6pdlxAgvrxXA,373
|
|
120
|
+
cherrypy_foundation/tools/tests/templates/test_jinjax.html,sha256=NT19UaUzm8FRKOIc6H6HNGPDJU6KATnakd8zf3BCeAs,153
|
|
121
|
+
cherrypy_foundation-1.0.0a2.dist-info/licenses/LICENSE.md,sha256=trSLYs5qlaow_bBwsLTRKpmTXsXzFksM_YUCMqrgAJQ,35149
|
|
122
|
+
cherrypy_foundation-1.0.0a2.dist-info/METADATA,sha256=5MZIxynHP0cH_SRXkrU4d0H4BiS-PsRtM01cUtx9fdY,2022
|
|
123
|
+
cherrypy_foundation-1.0.0a2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
124
|
+
cherrypy_foundation-1.0.0a2.dist-info/top_level.txt,sha256=B1vQPTLYhpKJ6W0JkRCWyAf8RPcnwJWdYxixv75-4ew,20
|
|
125
|
+
cherrypy_foundation-1.0.0a2.dist-info/RECORD,,
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{# def messages, floating=False #}
|
|
2
|
-
<div {{ attrs.render(class="flash-messages") }}>
|
|
3
|
-
{% for message, level in messages %}
|
|
4
|
-
<div class="alert alert-{{'danger' if level == 'error' else level }} alert-dismissible fade show"
|
|
5
|
-
role="alert">
|
|
6
|
-
{{ message }}
|
|
7
|
-
<button type="button"
|
|
8
|
-
class="btn-close"
|
|
9
|
-
data-bs-dismiss="alert"
|
|
10
|
-
aria-label="Close"></button>
|
|
11
|
-
</div>
|
|
12
|
-
{% endfor %}
|
|
13
|
-
</div>
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{# def header="Language selection" #}
|
|
2
|
-
<li>
|
|
3
|
-
<h6 class="dropdown-header">{{ header }}</h6>
|
|
4
|
-
</li>
|
|
5
|
-
{% set cur_locale = get_translation().locale %}
|
|
6
|
-
{% for locale in list_available_locales() %}
|
|
7
|
-
<li>
|
|
8
|
-
<button aria-pressed="{{ 'true' if cur_locale == locale else 'false' }}"
|
|
9
|
-
class="dropdown-item btn-locale{{ ' active' if cur_locale == locale else '' }}"
|
|
10
|
-
data-locale="{{ locale.language }}"
|
|
11
|
-
type="button">{{ locale.display_name.capitalize() }}</button>
|
|
12
|
-
</li>
|
|
13
|
-
{% endfor %}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Handle locale selection.
|
|
3
|
-
*/
|
|
4
|
-
document.addEventListener('DOMContentLoaded', function () {
|
|
5
|
-
const LOCALE_COOKIE_NAME = 'locale';
|
|
6
|
-
const ONE_YEAR = 60 * 60 * 24 * 365;
|
|
7
|
-
|
|
8
|
-
function setLocaleCookie(locale) {
|
|
9
|
-
document.cookie = `${LOCALE_COOKIE_NAME}=${locale}; path=/; max-age=${ONE_YEAR}; SameSite=Lax`;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function onLanguageClick(event) {
|
|
13
|
-
const locale = event.target.dataset.locale;
|
|
14
|
-
if (!locale) return;
|
|
15
|
-
|
|
16
|
-
setLocaleCookie(locale);
|
|
17
|
-
|
|
18
|
-
// Reload page so backend can use the new language
|
|
19
|
-
window.location.reload();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
document.querySelectorAll('.btn-locale').forEach(btn => {
|
|
23
|
-
btn.addEventListener('click', onLanguageClick);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
});
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
# Scheduler plugins for 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
|
-
import importlib
|
|
17
|
-
import tempfile
|
|
18
|
-
from threading import Event
|
|
19
|
-
|
|
20
|
-
import cherrypy
|
|
21
|
-
from cherrypy.test import helper
|
|
22
|
-
|
|
23
|
-
from .. import scheduler # noqa
|
|
24
|
-
|
|
25
|
-
done = Event()
|
|
26
|
-
|
|
27
|
-
HAS_SQLALCHEMY = importlib.util.find_spec("sqlalchemy") is not None
|
|
28
|
-
if not HAS_SQLALCHEMY:
|
|
29
|
-
pass
|
|
30
|
-
else:
|
|
31
|
-
from sqlalchemy import Column, Integer, String
|
|
32
|
-
from sqlalchemy.exc import IntegrityError
|
|
33
|
-
|
|
34
|
-
from .. import db # noqa
|
|
35
|
-
|
|
36
|
-
Base = cherrypy.db.get_base()
|
|
37
|
-
|
|
38
|
-
class User2(Base):
|
|
39
|
-
__tablename__ = 'users2'
|
|
40
|
-
id = Column(Integer, primary_key=True)
|
|
41
|
-
username = Column(String)
|
|
42
|
-
|
|
43
|
-
def __repr__(self):
|
|
44
|
-
return f"User2(id={self.id}, username='{self.username}')"
|
|
45
|
-
|
|
46
|
-
class Root:
|
|
47
|
-
|
|
48
|
-
@cherrypy.expose
|
|
49
|
-
def index(self):
|
|
50
|
-
return str(User2.query.all())
|
|
51
|
-
|
|
52
|
-
@cherrypy.expose
|
|
53
|
-
def add(self, username):
|
|
54
|
-
try:
|
|
55
|
-
User2(username=username).add().commit()
|
|
56
|
-
return "OK"
|
|
57
|
-
except IntegrityError as e:
|
|
58
|
-
return str(e)
|
|
59
|
-
|
|
60
|
-
def create_user(*args, **kwargs):
|
|
61
|
-
user = User2(*args, **kwargs).add()
|
|
62
|
-
user.commit()
|
|
63
|
-
done.set()
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
class DbSchedulerPluginTest(helper.CPWebCase):
|
|
67
|
-
interactive = False
|
|
68
|
-
|
|
69
|
-
@classmethod
|
|
70
|
-
def setup_class(cls):
|
|
71
|
-
cls.tempdir = tempfile.TemporaryDirectory(prefix='cherrypy-foundation-', suffix='-db-test')
|
|
72
|
-
super().setup_class()
|
|
73
|
-
|
|
74
|
-
@classmethod
|
|
75
|
-
def teardown_class(cls):
|
|
76
|
-
cls.tempdir.cleanup()
|
|
77
|
-
super().teardown_class()
|
|
78
|
-
|
|
79
|
-
@classmethod
|
|
80
|
-
def setup_server(cls):
|
|
81
|
-
cherrypy.config.update(
|
|
82
|
-
{
|
|
83
|
-
'db.uri': f"sqlite:///{cls.tempdir.name}/data.db",
|
|
84
|
-
}
|
|
85
|
-
)
|
|
86
|
-
cherrypy.tree.mount(Root(), '/')
|
|
87
|
-
|
|
88
|
-
def setUp(self) -> None:
|
|
89
|
-
done.clear()
|
|
90
|
-
cherrypy.db.create_all()
|
|
91
|
-
return super().setUp()
|
|
92
|
-
|
|
93
|
-
def tearDown(self):
|
|
94
|
-
cherrypy.db.drop_all()
|
|
95
|
-
return super().tearDown()
|
|
96
|
-
|
|
97
|
-
def test_add_job_now(self):
|
|
98
|
-
# Given a task
|
|
99
|
-
# When scheduling that task
|
|
100
|
-
scheduled = cherrypy.engine.publish('scheduler:add_job_now', create_user, username='myuser')
|
|
101
|
-
self.assertTrue(scheduled)
|
|
102
|
-
# When waiting for all tasks
|
|
103
|
-
cherrypy.scheduler.wait_for_jobs()
|
|
104
|
-
# Then the task get called
|
|
105
|
-
self.assertTrue(done.is_set())
|
|
106
|
-
# Then database was updated
|
|
107
|
-
User2.query.filter(User2.username == 'myuser').one()
|
cherrypy_foundation/sessions.py
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# Cherrypy-foundation
|
|
2
|
-
# Copyright (C) 2025-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
|
-
|
|
18
|
-
import logging
|
|
19
|
-
import os
|
|
20
|
-
import time
|
|
21
|
-
from contextlib import contextmanager
|
|
22
|
-
|
|
23
|
-
import cherrypy
|
|
24
|
-
import zc.lockfile
|
|
25
|
-
from cherrypy.lib import locking
|
|
26
|
-
from cherrypy.lib.sessions import FileSession as CPFileSession
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class FileSession(CPFileSession):
|
|
30
|
-
"""
|
|
31
|
-
Override implementation of cherrpy file session to improve file locking.
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
def acquire_lock(self, path=None):
|
|
35
|
-
"""Acquire an exclusive lock on the currently-loaded session data."""
|
|
36
|
-
# See Issue https://github.com/cherrypy/cherrypy/issues/2065
|
|
37
|
-
|
|
38
|
-
if path is None:
|
|
39
|
-
path = self._get_file_path()
|
|
40
|
-
path += self.LOCK_SUFFIX
|
|
41
|
-
checker = locking.LockChecker(self.id, self.lock_timeout)
|
|
42
|
-
while not checker.expired():
|
|
43
|
-
try:
|
|
44
|
-
self.lock = zc.lockfile.LockFile(path)
|
|
45
|
-
except zc.lockfile.LockError:
|
|
46
|
-
# Sleep for 1ms only.
|
|
47
|
-
time.sleep(0.001)
|
|
48
|
-
else:
|
|
49
|
-
break
|
|
50
|
-
self.locked = True
|
|
51
|
-
if self.debug:
|
|
52
|
-
cherrypy.log('Lock acquired.', 'TOOLS.SESSIONS')
|
|
53
|
-
|
|
54
|
-
def clean_up(self):
|
|
55
|
-
"""Also clean-up left over lock files."""
|
|
56
|
-
# See Issue https://github.com/cherrypy/cherrypy/issues/1855
|
|
57
|
-
|
|
58
|
-
# Clean-up session files.
|
|
59
|
-
CPFileSession.clean_up(self)
|
|
60
|
-
|
|
61
|
-
# Then clean-up any orphane lock files.
|
|
62
|
-
suffix_len = len(self.LOCK_SUFFIX)
|
|
63
|
-
files = os.listdir(self.storage_path)
|
|
64
|
-
lock_files = [
|
|
65
|
-
fname for fname in files if fname.startswith(self.SESSION_PREFIX) and fname.endswith(self.LOCK_SUFFIX)
|
|
66
|
-
]
|
|
67
|
-
for fname in lock_files:
|
|
68
|
-
session_file = fname[:-suffix_len]
|
|
69
|
-
if session_file not in files:
|
|
70
|
-
filepath = os.path.join(self.storage_path, fname)
|
|
71
|
-
try:
|
|
72
|
-
os.unlink(filepath)
|
|
73
|
-
except Exception as e:
|
|
74
|
-
cherrypy.log(f'Error deleting {filepath}: {e}', 'TOOLS.SESSIONS', severity=logging.WARNING)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
@contextmanager
|
|
78
|
-
def session_lock():
|
|
79
|
-
"""
|
|
80
|
-
Acquire session lock as required. Support re-intrant lock.
|
|
81
|
-
"""
|
|
82
|
-
s = cherrypy.serving.session
|
|
83
|
-
if s.locking == 'explicit' and not s.locked:
|
|
84
|
-
s.acquire_lock()
|
|
85
|
-
try:
|
|
86
|
-
yield s
|
|
87
|
-
finally:
|
|
88
|
-
# When explicit, we want to save the session (with also release the lock.)
|
|
89
|
-
if s.locking == 'explicit':
|
|
90
|
-
s.save()
|
|
91
|
-
cherrypy.serving.request._sessionsaved = True
|
|
92
|
-
else:
|
|
93
|
-
yield s
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<title>test-url</title>
|
|
5
|
-
</head>
|
|
6
|
-
<body>
|
|
7
|
-
Empty: {{ url_for("", **kwargs) }}<br/>
|
|
8
|
-
Dot: {{ url_for(".", **kwargs) }}<br/>
|
|
9
|
-
Dot page: {{ url_for(".", "my-page", **kwargs) }}<br/>
|
|
10
|
-
Slash: {{ url_for("/", **kwargs) }}<br/>
|
|
11
|
-
Page: {{ url_for("my-page", **kwargs) }}<br/>
|
|
12
|
-
Slash page: {{ url_for("/my-page", **kwargs) }}<br/>
|
|
13
|
-
Query: {{ url_for("my-page", foo='1', bar='test with space', **kwargs) }}<br/>
|
|
14
|
-
</body>
|
|
15
|
-
</html>
|
|
@@ -1,61 +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
|
-
|
|
19
|
-
import cherrypy
|
|
20
|
-
from cherrypy.test import helper
|
|
21
|
-
|
|
22
|
-
import cherrypy_foundation.tools.jinja2 # noqa
|
|
23
|
-
from cherrypy_foundation.flash import flash, get_flashed_messages
|
|
24
|
-
|
|
25
|
-
HAS_JINJAX = importlib.util.find_spec("jinjax") is not None
|
|
26
|
-
|
|
27
|
-
env = cherrypy.tools.jinja2.create_env(
|
|
28
|
-
package_name=__package__,
|
|
29
|
-
globals={'get_flashed_messages': get_flashed_messages},
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@cherrypy.tools.sessions(locking='explicit')
|
|
34
|
-
@cherrypy.tools.jinja2(env=env)
|
|
35
|
-
class Root:
|
|
36
|
-
|
|
37
|
-
@cherrypy.expose
|
|
38
|
-
@cherrypy.tools.jinja2(template='test_flash.html')
|
|
39
|
-
def index(self):
|
|
40
|
-
flash('default flash message', level='info')
|
|
41
|
-
return {}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
@skipUnless(HAS_JINJAX, reason='Required jinjax')
|
|
45
|
-
class FormTest(helper.CPWebCase):
|
|
46
|
-
default_lang = None
|
|
47
|
-
interactive = False
|
|
48
|
-
|
|
49
|
-
@classmethod
|
|
50
|
-
def setup_server(cls):
|
|
51
|
-
cherrypy.tree.mount(Root(), '/')
|
|
52
|
-
|
|
53
|
-
def test_get_flash(self):
|
|
54
|
-
# Given a page returning a flash message
|
|
55
|
-
# When querying the page that include this form
|
|
56
|
-
self.getPage("/")
|
|
57
|
-
self.assertStatus(200)
|
|
58
|
-
# Then page display the message.
|
|
59
|
-
self.assertInBody('test-flash')
|
|
60
|
-
self.assertInBody('<div class="alert alert-info alert-dismissible fade show"')
|
|
61
|
-
self.assertInBody('default flash message')
|