cherrypy-foundation 1.0.0__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.
Files changed (136) hide show
  1. cherrypy_foundation/__init__.py +0 -0
  2. cherrypy_foundation/components/ColorModes.jinja +70 -0
  3. cherrypy_foundation/components/Datatable.css +47 -0
  4. cherrypy_foundation/components/Datatable.jinja +63 -0
  5. cherrypy_foundation/components/Datatable.js +358 -0
  6. cherrypy_foundation/components/Field.css +10 -0
  7. cherrypy_foundation/components/Field.jinja +66 -0
  8. cherrypy_foundation/components/Field.js +56 -0
  9. cherrypy_foundation/components/Fields.jinja +4 -0
  10. cherrypy_foundation/components/Flash.jinja +13 -0
  11. cherrypy_foundation/components/Icon.jinja +3 -0
  12. cherrypy_foundation/components/LocaleSelection.jinja +13 -0
  13. cherrypy_foundation/components/LocaleSelection.js +26 -0
  14. cherrypy_foundation/components/SideBySideMultiSelect.css +25 -0
  15. cherrypy_foundation/components/SideBySideMultiSelect.jinja +9 -0
  16. cherrypy_foundation/components/SideBySideMultiSelect.js +9 -0
  17. cherrypy_foundation/components/Typeahead.css +55 -0
  18. cherrypy_foundation/components/Typeahead.jinja +106 -0
  19. cherrypy_foundation/components/Typeahead.js +8 -0
  20. cherrypy_foundation/components/__init__.py +51 -0
  21. cherrypy_foundation/components/tests/__init__.py +0 -0
  22. cherrypy_foundation/components/tests/test_static.py +90 -0
  23. cherrypy_foundation/components/vendor/bootstrap-icons/bootstrap-icons.css +2106 -0
  24. cherrypy_foundation/components/vendor/bootstrap-icons/bootstrap-icons.min.css +5 -0
  25. cherrypy_foundation/components/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
  26. cherrypy_foundation/components/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
  27. cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.css +9262 -0
  28. cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.css.map +95 -0
  29. cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.min.css +6 -0
  30. cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.min.css.map +7 -0
  31. cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.js +4846 -0
  32. cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.js.map +1 -0
  33. cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.min.js +7 -0
  34. cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.min.js.map +7 -0
  35. cherrypy_foundation/components/vendor/bootstrap5/js/color-modes.js +80 -0
  36. cherrypy_foundation/components/vendor/datatables/css/dataTables.dataTables.css +849 -0
  37. cherrypy_foundation/components/vendor/datatables/css/dataTables.dataTables.min.css +1 -0
  38. cherrypy_foundation/components/vendor/datatables/images/sort_asc.png +0 -0
  39. cherrypy_foundation/components/vendor/datatables/images/sort_asc_disabled.png +0 -0
  40. cherrypy_foundation/components/vendor/datatables/images/sort_both.png +0 -0
  41. cherrypy_foundation/components/vendor/datatables/images/sort_desc.png +0 -0
  42. cherrypy_foundation/components/vendor/datatables/images/sort_desc_disabled.png +0 -0
  43. cherrypy_foundation/components/vendor/datatables/js/dataTables.js +14073 -0
  44. cherrypy_foundation/components/vendor/datatables/js/dataTables.min.js +4 -0
  45. cherrypy_foundation/components/vendor/datatables-extensions/Buttons/css/buttons.dataTables.css +556 -0
  46. cherrypy_foundation/components/vendor/datatables-extensions/Buttons/css/buttons.dataTables.min.css +1 -0
  47. cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/buttons.html5.js +1700 -0
  48. cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/buttons.html5.min.js +8 -0
  49. cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/dataTables.buttons.js +2944 -0
  50. cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/dataTables.buttons.min.js +4 -0
  51. cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/css/fixedHeader.dataTables.css +13 -0
  52. cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/css/fixedHeader.dataTables.min.css +1 -0
  53. cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/js/dataTables.fixedHeader.js +1202 -0
  54. cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/js/dataTables.fixedHeader.min.js +4 -0
  55. cherrypy_foundation/components/vendor/datatables-extensions/JSZip/jszip.js +11577 -0
  56. cherrypy_foundation/components/vendor/datatables-extensions/JSZip/jszip.min.js +13 -0
  57. cherrypy_foundation/components/vendor/datatables-extensions/Responsive/css/responsive.dataTables.css +194 -0
  58. cherrypy_foundation/components/vendor/datatables-extensions/Responsive/css/responsive.dataTables.min.css +1 -0
  59. cherrypy_foundation/components/vendor/datatables-extensions/Responsive/js/dataTables.responsive.js +1861 -0
  60. cherrypy_foundation/components/vendor/datatables-extensions/Responsive/js/dataTables.responsive.min.js +4 -0
  61. cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/pdfmake.js +75023 -0
  62. cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/pdfmake.min.js +3 -0
  63. cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/vfs_fonts.js +6 -0
  64. cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/css/rowGroup.dataTables.css +53 -0
  65. cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/css/rowGroup.dataTables.min.css +1 -0
  66. cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/js/dataTables.rowGroup.js +485 -0
  67. cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/js/dataTables.rowGroup.min.js +4 -0
  68. cherrypy_foundation/components/vendor/jquery/jquery.min.js +2 -0
  69. cherrypy_foundation/components/vendor/multi/LICENSE +7 -0
  70. cherrypy_foundation/components/vendor/multi/README.md +109 -0
  71. cherrypy_foundation/components/vendor/multi/multi.css +95 -0
  72. cherrypy_foundation/components/vendor/multi/multi.js +328 -0
  73. cherrypy_foundation/components/vendor/popper/popper.js +1825 -0
  74. cherrypy_foundation/components/vendor/popper/popper.min.js +6 -0
  75. cherrypy_foundation/components/vendor/typeahead/jquery.typeahead.min.css +1 -0
  76. cherrypy_foundation/components/vendor/typeahead/jquery.typeahead.min.js +10 -0
  77. cherrypy_foundation/error_page.py +94 -0
  78. cherrypy_foundation/flash.py +50 -0
  79. cherrypy_foundation/form.py +119 -0
  80. cherrypy_foundation/logging.py +103 -0
  81. cherrypy_foundation/passwd.py +65 -0
  82. cherrypy_foundation/plugins/__init__.py +0 -0
  83. cherrypy_foundation/plugins/db.py +286 -0
  84. cherrypy_foundation/plugins/ldap.py +257 -0
  85. cherrypy_foundation/plugins/restapi.py +74 -0
  86. cherrypy_foundation/plugins/scheduler.py +287 -0
  87. cherrypy_foundation/plugins/smtp.py +223 -0
  88. cherrypy_foundation/plugins/tests/__init__.py +0 -0
  89. cherrypy_foundation/plugins/tests/test_db.py +118 -0
  90. cherrypy_foundation/plugins/tests/test_ldap.py +451 -0
  91. cherrypy_foundation/plugins/tests/test_scheduler.py +100 -0
  92. cherrypy_foundation/plugins/tests/test_scheduler_db.py +107 -0
  93. cherrypy_foundation/plugins/tests/test_smtp.py +140 -0
  94. cherrypy_foundation/sessions.py +93 -0
  95. cherrypy_foundation/tests/__init__.py +72 -0
  96. cherrypy_foundation/tests/templates/test_flash.html +9 -0
  97. cherrypy_foundation/tests/templates/test_form.html +16 -0
  98. cherrypy_foundation/tests/templates/test_url.html +15 -0
  99. cherrypy_foundation/tests/test_error_page.py +78 -0
  100. cherrypy_foundation/tests/test_flash.py +61 -0
  101. cherrypy_foundation/tests/test_form.py +148 -0
  102. cherrypy_foundation/tests/test_logging.py +78 -0
  103. cherrypy_foundation/tests/test_passwd.py +51 -0
  104. cherrypy_foundation/tests/test_sessions.py +89 -0
  105. cherrypy_foundation/tests/test_url.py +161 -0
  106. cherrypy_foundation/tools/__init__.py +0 -0
  107. cherrypy_foundation/tools/auth.py +263 -0
  108. cherrypy_foundation/tools/auth_mfa.py +249 -0
  109. cherrypy_foundation/tools/i18n.py +529 -0
  110. cherrypy_foundation/tools/jinja2.py +158 -0
  111. cherrypy_foundation/tools/ratelimit.py +265 -0
  112. cherrypy_foundation/tools/secure_headers.py +119 -0
  113. cherrypy_foundation/tools/sessions_timeout.py +167 -0
  114. cherrypy_foundation/tools/tests/__init__.py +0 -0
  115. cherrypy_foundation/tools/tests/components/Button.jinja +2 -0
  116. cherrypy_foundation/tools/tests/locales/de/LC_MESSAGES/messages.mo +0 -0
  117. cherrypy_foundation/tools/tests/locales/de/LC_MESSAGES/messages.po +15 -0
  118. cherrypy_foundation/tools/tests/locales/fr/LC_MESSAGES/messages.mo +0 -0
  119. cherrypy_foundation/tools/tests/locales/fr/LC_MESSAGES/messages.po +15 -0
  120. cherrypy_foundation/tools/tests/locales/messages.pot +2 -0
  121. cherrypy_foundation/tools/tests/templates/test_jinja2.html +11 -0
  122. cherrypy_foundation/tools/tests/templates/test_jinjax.html +9 -0
  123. cherrypy_foundation/tools/tests/templates/test_jinjax_i18n.html +22 -0
  124. cherrypy_foundation/tools/tests/test_auth.py +110 -0
  125. cherrypy_foundation/tools/tests/test_auth_mfa.py +369 -0
  126. cherrypy_foundation/tools/tests/test_i18n.py +247 -0
  127. cherrypy_foundation/tools/tests/test_jinja2.py +153 -0
  128. cherrypy_foundation/tools/tests/test_ratelimit.py +109 -0
  129. cherrypy_foundation/tools/tests/test_secure_headers.py +200 -0
  130. cherrypy_foundation/url.py +66 -0
  131. cherrypy_foundation/widgets.py +48 -0
  132. cherrypy_foundation-1.0.0.dist-info/METADATA +71 -0
  133. cherrypy_foundation-1.0.0.dist-info/RECORD +136 -0
  134. cherrypy_foundation-1.0.0.dist-info/WHEEL +5 -0
  135. cherrypy_foundation-1.0.0.dist-info/licenses/LICENSE.md +674 -0
  136. cherrypy_foundation-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,13 @@
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>
@@ -0,0 +1,3 @@
1
+ {# def value #}
2
+ {#css vendor/bootstrap-icons/bootstrap-icons.css #}
3
+ <i {{ attrs.render(class="bi " + value) }} aria-hidden="true"></i>
@@ -0,0 +1,13 @@
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 %}
@@ -0,0 +1,26 @@
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
+ });
@@ -0,0 +1,25 @@
1
+ /* Make Multi-wrapper similar to other bootstrap */
2
+ .multi-wrapper {
3
+ border: 1px solid #ced4da;
4
+ border-radius: 0.375rem;
5
+ background: #ffffff;
6
+ }
7
+
8
+ .multi-wrapper .search-input,
9
+ .multi-wrapper .non-selected-wrapper,
10
+ .multi-wrapper .selected-wrapper {
11
+ background: none;
12
+ padding: 0.375rem 0.75rem;
13
+ overflow-y: auto;
14
+ }
15
+
16
+ .multi-wrapper .header {
17
+ padding: 1px;
18
+ }
19
+
20
+ .multi-wrapper .item {
21
+ padding: 1px;
22
+ white-space: nowrap;
23
+ text-overflow: ellipsis;
24
+ overflow: hidden;
25
+ }
@@ -0,0 +1,9 @@
1
+ {# def field #}
2
+ {# css vendor/multi/multi.css #}
3
+ {# js vendor/multi/multi.js #}
4
+ <select {{ attrs.render(name=field.name, class="multi", multiple=True, data_non_selected_header=_("Available") , data_selected_header=_("Selected"), data_search_placeholder=_("Filter...")) }}>
5
+ {% for choice in field.iter_choices() %}
6
+ {% set val, label, selected = choice[0:3] %}
7
+ <option {% if selected %}selected{% endif %} value="{{ val }}">{{ label }}</option>
8
+ {% endfor %}
9
+ </select>
@@ -0,0 +1,9 @@
1
+ /**
2
+ * DualList Widget configure with class="multi"
3
+ */
4
+ jQuery(function () {
5
+ $('select.multi').each(function (_idx) {
6
+ const cfg = $(this).data();
7
+ $(this).multi(cfg);
8
+ });
9
+ });
@@ -0,0 +1,55 @@
1
+ /* Limit the height of the typeahead list */
2
+ .typeahead__list {
3
+ max-height: 24em;
4
+ overflow: auto;
5
+ }
6
+
7
+ /* Fix location of spinning wheel */
8
+ .typeahead__container.loading .typeahead__query::after,
9
+ .typeahead__container.loading .typeahead__query::before {
10
+ top: 0.5rem;
11
+ }
12
+
13
+ /* Fix lense position */
14
+ .typeahead__button button {
15
+ height: 100%;
16
+ }
17
+
18
+ /* Fix color for DarkMode */
19
+ .typeahead__container button,
20
+ .typeahead__container button.disabled,
21
+ .typeahead__container button[disabled],
22
+ .typeahead__container input.disabled,
23
+ .typeahead__container input[disabled],
24
+ .typeahead__container.hint .typeahead__field [contenteditable],
25
+ .typeahead__container.hint .typeahead__field input,
26
+ .typeahead__container.hint .typeahead__field textarea
27
+ .typeahead__dropdown,
28
+ .typeahead__field .typeahead__hint,
29
+ .typeahead__field [contenteditable],
30
+ .typeahead__field input,
31
+ .typeahead__field textarea,
32
+ .typeahead__list {
33
+ background-color: var(--bs-body-bg);
34
+ }
35
+
36
+ .typeahead__dropdown .typeahead__dropdown-item>a,
37
+ .typeahead__list .typeahead__item>a,
38
+ .typeahead__list.empty>li {
39
+ color: var(--bs-body-color);
40
+ }
41
+
42
+ .typeahead__dropdown .typeahead__dropdown-item>a>strong,
43
+ .typeahead__list .typeahead__item>a>strong {
44
+ color: var(--bs-emphasis-color);
45
+ }
46
+
47
+ .typeahead__dropdown .typeahead__dropdown-item:not([disabled]).active>a,
48
+ .typeahead__dropdown .typeahead__dropdown-item:not([disabled])>a:focus,
49
+ .typeahead__dropdown .typeahead__dropdown-item:not([disabled])>a:hover,
50
+ .typeahead__list .typeahead__item:not([disabled]).active>a,
51
+ .typeahead__list .typeahead__item:not([disabled])>a:focus,
52
+ .typeahead__list .typeahead__item:not([disabled])>a:hover {
53
+ background-color: var(--bs-tertiary-bg);
54
+ color: var(--bs-body-color);
55
+ }
@@ -0,0 +1,106 @@
1
+ {#def
2
+ accent=False,
3
+ async_result=False,
4
+ autofocus=False,
5
+ backdrop=False,
6
+ backdrop_on_focus=False,
7
+ blur_on_tab=True,
8
+ cache=False,
9
+ cancel_button=True,
10
+ compression=False,
11
+ correlative_template=False,
12
+ debug=False,
13
+ delay=300,
14
+ display=[],
15
+ dropdown_filter=False,
16
+ dynamic=False,
17
+ dynamic_filter=None,
18
+ empty_template=None,
19
+ filter=True,
20
+ generate_on_load=None,
21
+ group=False,
22
+ group_order=None,
23
+ group_template=None,
24
+ highlight=True,
25
+ hint=True,
26
+ href=None,
27
+ loading_animation=True,
28
+ matcher=None,
29
+ max_item=8,
30
+ max_item_per_group=None,
31
+ max_length=None,
32
+ min_length=2,
33
+ multiselect=None,
34
+ must_select_item=False,
35
+ name="search",
36
+ offset=False,
37
+ order=None,
38
+ placeholder=None,
39
+ result_container=None,
40
+ search_on_focus=False,
41
+ source={},
42
+ submit_button=True,
43
+ template=None,
44
+ template_value=None,
45
+ ttl=3600000,
46
+ #}
47
+ {#css vendor/typeahead/jquery.typeahead.min.css #}
48
+ {#js vendor/jquery/jquery.min.js, vendor/typeahead/jquery.typeahead.min.js #}
49
+ <div class="typeahead__container">
50
+ <div class="typeahead__field">
51
+ <div class="typeahead__query">
52
+ <input {{ attrs.render(autocomplete="off",
53
+ autofocus=autofocus | tojson,
54
+ class="js-typeahead",
55
+ data_accent=accent | tojson,
56
+ data_async_result=async_result | tojson,
57
+ data_backdrop=backdrop | tojson,
58
+ data_backdrop_on_focus=backdrop_on_focus | tojson,
59
+ data_blur_on_tab=blur_on_tab | tojson,
60
+ data_cache=cache | tojson,
61
+ data_cancel_button=cancel_button | tojson,
62
+ data_compression=compression | tojson,
63
+ data_correlative_template=correlative_template | tojson,
64
+ data_debug=debug | tojson,
65
+ data_delay=delay,
66
+ data_display=display | tojson,
67
+ data_dropdown_filter=dropdown_filter | tojson,
68
+ data_dynamic=dynamic | tojson,
69
+ data_dynamic_filter=dynamic_filter | tojson,
70
+ data_empty_template=empty_template | tojson,
71
+ data_filter=filter | tojson,
72
+ data_generate_on_load=generate_on_load | tojson,
73
+ data_group=group | tojson,
74
+ data_group_order=group_order | tojson,
75
+ data_group_template=group_template | tojson,
76
+ data_highlight=highlight | tojson,
77
+ data_hint=hint | tojson,
78
+ data_href=href,
79
+ loading_animation=loading_animation | tojson,
80
+ data_max_item=max_item,
81
+ data_max_item_per_group=max_item_per_group,
82
+ data_max_length=max_length,
83
+ data_min_length=min_length,
84
+ data_multiselect=multiselect | tojson,
85
+ data_must_select_item=must_select_item | tojson,
86
+ data_offset=offset | tojson,
87
+ data_order=None,
88
+ data_result_container=result_container,
89
+ data_search_on_focus=search_on_focus | tojson,
90
+ data_source=source | tojson,
91
+ data_template=template,
92
+ data_template_value=template_value,
93
+ data_ttl=ttl,
94
+ name=name,
95
+ placeholder=placeholder or _('Search...') ,
96
+ ) }}>
97
+ </div>
98
+ <div class="typeahead__button">
99
+ {% if submit_button %}
100
+ <button type="submit">
101
+ <i class="fbi bi-search" aria-hidden="true"></i>
102
+ </button>
103
+ {% endif %}
104
+ </div>
105
+ </div>
106
+ </div>
@@ -0,0 +1,8 @@
1
+ /* Initialize Typeahead */
2
+ jQuery(function() {
3
+ $('.js-typeahead').each(function(_idx) {
4
+ const cfg = $(this).data();
5
+ const typeahead = $(this).typeahead(cfg);
6
+ $(this).data('typeahead', typeahead);
7
+ });
8
+ });
@@ -0,0 +1,51 @@
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.resources
17
+
18
+ import cherrypy
19
+
20
+ RE_STATIC_MATCH = r"(\.js|\.css|\.png|\.woff|\.woff2|\.map)$"
21
+
22
+
23
+ @cherrypy.config(
24
+ **{
25
+ 'tools.auth.on': False,
26
+ 'tools.auth_mfa.on': False,
27
+ 'tools.i18n.on': False,
28
+ 'tools.ratelimit.on': False,
29
+ 'tools.secure_headers.on': False,
30
+ 'tools.sessions.on': False,
31
+ }
32
+ )
33
+ class StaticMiddleware:
34
+
35
+ @cherrypy.expose
36
+ @cherrypy.tools.staticdir(match=RE_STATIC_MATCH, dir=str(importlib.resources.files(__package__)))
37
+ def default(self, *args, **kwargs):
38
+ """This entry point is used to serve content of /static/components/ folder and JinjaX static ressources"""
39
+ # Make use of JinjaX catalog
40
+ env = cherrypy.request.config.get('tools.jinja2.env')
41
+ if env is None or 'catalog' not in env.globals:
42
+ raise cherrypy.HTTPError(400)
43
+
44
+ # JinjaX resources could be locaed in multiple path.
45
+ section = cherrypy.serving.request.toolmaps['tools']['staticdir']['section']
46
+ jinjax_catalog = env.globals['catalog']
47
+ for path in jinjax_catalog.paths:
48
+ handled = cherrypy.lib.static.staticdir(section=section, match=RE_STATIC_MATCH, dir=path)
49
+ if handled:
50
+ return cherrypy.serving.response.body
51
+ raise cherrypy.HTTPError(400)
File without changes
@@ -0,0 +1,90 @@
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 importlib.resources
18
+
19
+ import cherrypy
20
+ from cherrypy.test import helper
21
+ from parameterized import parameterized
22
+
23
+ from .. import StaticMiddleware
24
+
25
+
26
+ class Static:
27
+
28
+ components = StaticMiddleware()
29
+
30
+
31
+ class Root:
32
+
33
+ static = Static()
34
+
35
+ @cherrypy.expose
36
+ def index(self):
37
+ return "OK"
38
+
39
+
40
+ class StaticMiddlewareTest(helper.CPWebCase):
41
+ default_lang = None
42
+ interactive = False
43
+
44
+ @classmethod
45
+ def setup_server(cls):
46
+ cherrypy.config.update(
47
+ {
48
+ 'tools.i18n.default': cls.default_lang,
49
+ 'tools.i18n.mo_dir': importlib.resources.files(__package__) / 'locales',
50
+ 'tools.i18n.domain': 'messages',
51
+ }
52
+ )
53
+ cherrypy.tree.mount(Root(), '/')
54
+
55
+ @parameterized.expand(
56
+ [
57
+ '/static/components/Datatable.css',
58
+ '/static/components/Datatable.js',
59
+ '/static/components/Field.css',
60
+ '/static/components/Field.js',
61
+ '/static/components/SideBySideMultiSelect.css',
62
+ '/static/components/SideBySideMultiSelect.js',
63
+ '/static/components/Typeahead.css',
64
+ '/static/components/Typeahead.js',
65
+ '/static/components/vendor/bootstrap5/css/bootstrap.min.css',
66
+ '/static/components/vendor/bootstrap5/js/bootstrap.min.js',
67
+ '/static/components/vendor/datatables-extensions/Buttons/css/buttons.dataTables.min.css',
68
+ '/static/components/vendor/datatables-extensions/Buttons/js/buttons.html5.min.js',
69
+ '/static/components/vendor/datatables-extensions/Buttons/js/dataTables.buttons.min.js',
70
+ '/static/components/vendor/datatables-extensions/FixedHeader/css/fixedHeader.dataTables.css',
71
+ '/static/components/vendor/datatables-extensions/FixedHeader/js/dataTables.fixedHeader.min.js',
72
+ '/static/components/vendor/datatables-extensions/JSZip/jszip.min.js',
73
+ '/static/components/vendor/datatables-extensions/pdfmake/build/pdfmake.min.js',
74
+ '/static/components/vendor/datatables-extensions/pdfmake/build/vfs_fonts.js',
75
+ '/static/components/vendor/datatables-extensions/Responsive/css/responsive.dataTables.min.css',
76
+ '/static/components/vendor/datatables-extensions/Responsive/js/dataTables.responsive.min.js',
77
+ '/static/components/vendor/datatables-extensions/rowgroup/css/rowGroup.dataTables.min.css',
78
+ '/static/components/vendor/datatables-extensions/rowgroup/js/dataTables.rowGroup.js',
79
+ '/static/components/vendor/datatables/css/dataTables.dataTables.css',
80
+ '/static/components/vendor/datatables/js/dataTables.min.js',
81
+ '/static/components/vendor/jquery/jquery.min.js',
82
+ '/static/components/vendor/popper/popper.min.js',
83
+ '/static/components/vendor/typeahead/jquery.typeahead.min.css',
84
+ '/static/components/vendor/typeahead/jquery.typeahead.min.js',
85
+ '/static/components/vendor/typeahead/jquery.typeahead.min.js',
86
+ ]
87
+ )
88
+ def test_static(self, url):
89
+ self.getPage(url)
90
+ self.assertStatus(200)