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.
- cherrypy_foundation/__init__.py +0 -0
- cherrypy_foundation/components/ColorModes.jinja +70 -0
- cherrypy_foundation/components/Datatable.css +47 -0
- cherrypy_foundation/components/Datatable.jinja +63 -0
- cherrypy_foundation/components/Datatable.js +358 -0
- cherrypy_foundation/components/Field.css +10 -0
- cherrypy_foundation/components/Field.jinja +66 -0
- cherrypy_foundation/components/Field.js +56 -0
- cherrypy_foundation/components/Fields.jinja +4 -0
- cherrypy_foundation/components/Flash.jinja +13 -0
- cherrypy_foundation/components/Icon.jinja +3 -0
- cherrypy_foundation/components/LocaleSelection.jinja +13 -0
- cherrypy_foundation/components/LocaleSelection.js +26 -0
- cherrypy_foundation/components/SideBySideMultiSelect.css +25 -0
- cherrypy_foundation/components/SideBySideMultiSelect.jinja +9 -0
- cherrypy_foundation/components/SideBySideMultiSelect.js +9 -0
- cherrypy_foundation/components/Typeahead.css +55 -0
- cherrypy_foundation/components/Typeahead.jinja +106 -0
- cherrypy_foundation/components/Typeahead.js +8 -0
- cherrypy_foundation/components/__init__.py +51 -0
- cherrypy_foundation/components/tests/__init__.py +0 -0
- cherrypy_foundation/components/tests/test_static.py +90 -0
- cherrypy_foundation/components/vendor/bootstrap-icons/bootstrap-icons.css +2106 -0
- cherrypy_foundation/components/vendor/bootstrap-icons/bootstrap-icons.min.css +5 -0
- cherrypy_foundation/components/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
- cherrypy_foundation/components/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
- cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.css +9262 -0
- cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.css.map +95 -0
- cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.min.css +6 -0
- cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.min.css.map +7 -0
- cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.js +4846 -0
- cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.js.map +1 -0
- cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.min.js +7 -0
- cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.min.js.map +7 -0
- cherrypy_foundation/components/vendor/bootstrap5/js/color-modes.js +80 -0
- cherrypy_foundation/components/vendor/datatables/css/dataTables.dataTables.css +849 -0
- cherrypy_foundation/components/vendor/datatables/css/dataTables.dataTables.min.css +1 -0
- cherrypy_foundation/components/vendor/datatables/images/sort_asc.png +0 -0
- cherrypy_foundation/components/vendor/datatables/images/sort_asc_disabled.png +0 -0
- cherrypy_foundation/components/vendor/datatables/images/sort_both.png +0 -0
- cherrypy_foundation/components/vendor/datatables/images/sort_desc.png +0 -0
- cherrypy_foundation/components/vendor/datatables/images/sort_desc_disabled.png +0 -0
- cherrypy_foundation/components/vendor/datatables/js/dataTables.js +14073 -0
- cherrypy_foundation/components/vendor/datatables/js/dataTables.min.js +4 -0
- cherrypy_foundation/components/vendor/datatables-extensions/Buttons/css/buttons.dataTables.css +556 -0
- cherrypy_foundation/components/vendor/datatables-extensions/Buttons/css/buttons.dataTables.min.css +1 -0
- cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/buttons.html5.js +1700 -0
- cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/buttons.html5.min.js +8 -0
- cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/dataTables.buttons.js +2944 -0
- cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/dataTables.buttons.min.js +4 -0
- cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/css/fixedHeader.dataTables.css +13 -0
- cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/css/fixedHeader.dataTables.min.css +1 -0
- cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/js/dataTables.fixedHeader.js +1202 -0
- cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/js/dataTables.fixedHeader.min.js +4 -0
- cherrypy_foundation/components/vendor/datatables-extensions/JSZip/jszip.js +11577 -0
- cherrypy_foundation/components/vendor/datatables-extensions/JSZip/jszip.min.js +13 -0
- cherrypy_foundation/components/vendor/datatables-extensions/Responsive/css/responsive.dataTables.css +194 -0
- cherrypy_foundation/components/vendor/datatables-extensions/Responsive/css/responsive.dataTables.min.css +1 -0
- cherrypy_foundation/components/vendor/datatables-extensions/Responsive/js/dataTables.responsive.js +1861 -0
- cherrypy_foundation/components/vendor/datatables-extensions/Responsive/js/dataTables.responsive.min.js +4 -0
- cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/pdfmake.js +75023 -0
- cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/pdfmake.min.js +3 -0
- cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/vfs_fonts.js +6 -0
- cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/css/rowGroup.dataTables.css +53 -0
- cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/css/rowGroup.dataTables.min.css +1 -0
- cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/js/dataTables.rowGroup.js +485 -0
- cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/js/dataTables.rowGroup.min.js +4 -0
- cherrypy_foundation/components/vendor/jquery/jquery.min.js +2 -0
- cherrypy_foundation/components/vendor/multi/LICENSE +7 -0
- cherrypy_foundation/components/vendor/multi/README.md +109 -0
- cherrypy_foundation/components/vendor/multi/multi.css +95 -0
- cherrypy_foundation/components/vendor/multi/multi.js +328 -0
- cherrypy_foundation/components/vendor/popper/popper.js +1825 -0
- cherrypy_foundation/components/vendor/popper/popper.min.js +6 -0
- cherrypy_foundation/components/vendor/typeahead/jquery.typeahead.min.css +1 -0
- cherrypy_foundation/components/vendor/typeahead/jquery.typeahead.min.js +10 -0
- cherrypy_foundation/error_page.py +94 -0
- cherrypy_foundation/flash.py +50 -0
- cherrypy_foundation/form.py +119 -0
- cherrypy_foundation/logging.py +103 -0
- cherrypy_foundation/passwd.py +65 -0
- cherrypy_foundation/plugins/__init__.py +0 -0
- cherrypy_foundation/plugins/db.py +286 -0
- cherrypy_foundation/plugins/ldap.py +257 -0
- cherrypy_foundation/plugins/restapi.py +74 -0
- cherrypy_foundation/plugins/scheduler.py +287 -0
- cherrypy_foundation/plugins/smtp.py +223 -0
- cherrypy_foundation/plugins/tests/__init__.py +0 -0
- cherrypy_foundation/plugins/tests/test_db.py +118 -0
- cherrypy_foundation/plugins/tests/test_ldap.py +451 -0
- cherrypy_foundation/plugins/tests/test_scheduler.py +100 -0
- cherrypy_foundation/plugins/tests/test_scheduler_db.py +107 -0
- cherrypy_foundation/plugins/tests/test_smtp.py +140 -0
- cherrypy_foundation/sessions.py +93 -0
- cherrypy_foundation/tests/__init__.py +72 -0
- cherrypy_foundation/tests/templates/test_flash.html +9 -0
- cherrypy_foundation/tests/templates/test_form.html +16 -0
- cherrypy_foundation/tests/templates/test_url.html +15 -0
- cherrypy_foundation/tests/test_error_page.py +78 -0
- cherrypy_foundation/tests/test_flash.py +61 -0
- cherrypy_foundation/tests/test_form.py +148 -0
- cherrypy_foundation/tests/test_logging.py +78 -0
- cherrypy_foundation/tests/test_passwd.py +51 -0
- cherrypy_foundation/tests/test_sessions.py +89 -0
- cherrypy_foundation/tests/test_url.py +161 -0
- cherrypy_foundation/tools/__init__.py +0 -0
- cherrypy_foundation/tools/auth.py +263 -0
- cherrypy_foundation/tools/auth_mfa.py +249 -0
- cherrypy_foundation/tools/i18n.py +529 -0
- cherrypy_foundation/tools/jinja2.py +158 -0
- cherrypy_foundation/tools/ratelimit.py +265 -0
- cherrypy_foundation/tools/secure_headers.py +119 -0
- cherrypy_foundation/tools/sessions_timeout.py +167 -0
- cherrypy_foundation/tools/tests/__init__.py +0 -0
- cherrypy_foundation/tools/tests/components/Button.jinja +2 -0
- cherrypy_foundation/tools/tests/locales/de/LC_MESSAGES/messages.mo +0 -0
- cherrypy_foundation/tools/tests/locales/de/LC_MESSAGES/messages.po +15 -0
- cherrypy_foundation/tools/tests/locales/fr/LC_MESSAGES/messages.mo +0 -0
- cherrypy_foundation/tools/tests/locales/fr/LC_MESSAGES/messages.po +15 -0
- cherrypy_foundation/tools/tests/locales/messages.pot +2 -0
- cherrypy_foundation/tools/tests/templates/test_jinja2.html +11 -0
- cherrypy_foundation/tools/tests/templates/test_jinjax.html +9 -0
- cherrypy_foundation/tools/tests/templates/test_jinjax_i18n.html +22 -0
- cherrypy_foundation/tools/tests/test_auth.py +110 -0
- cherrypy_foundation/tools/tests/test_auth_mfa.py +369 -0
- cherrypy_foundation/tools/tests/test_i18n.py +247 -0
- cherrypy_foundation/tools/tests/test_jinja2.py +153 -0
- cherrypy_foundation/tools/tests/test_ratelimit.py +109 -0
- cherrypy_foundation/tools/tests/test_secure_headers.py +200 -0
- cherrypy_foundation/url.py +66 -0
- cherrypy_foundation/widgets.py +48 -0
- cherrypy_foundation-1.0.0.dist-info/METADATA +71 -0
- cherrypy_foundation-1.0.0.dist-info/RECORD +136 -0
- cherrypy_foundation-1.0.0.dist-info/WHEEL +5 -0
- cherrypy_foundation-1.0.0.dist-info/licenses/LICENSE.md +674 -0
- 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,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,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,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)
|