simpledomcontrol 0.158.8__tar.gz → 0.159.0__tar.gz
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.
- simpledomcontrol-0.159.0/LICENSE +21 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/PKG-INFO +13 -11
- simpledomcontrol-0.159.0/pyproject.toml +66 -0
- simpledomcontrol-0.159.0/sdc/__main__.py +92 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/apps.py +1 -1
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/consumers.py +110 -49
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/jwt_utils.py +3 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/init_add/sdc_core_manager.py +2 -1
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_cc.py +0 -1
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_db_tools.py +27 -24
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_get_controller_infos.py +1 -1
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_get_model_infos.py +1 -1
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_init.py +1 -1
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_make_model_js.py +3 -2
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_new_model.py +1 -0
- simpledomcontrol-0.159.0/sdc_core/management/commands/sdc_open_api.py +437 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_overwrite_lib_file.py +10 -3
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_shell_execute_script.py +2 -1
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/utils/__init__.py +2 -2
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/rest_api.py +80 -68
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/sdc_extentions/forms.py +4 -2
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/sdc_extentions/models.py +64 -30
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/sdc_extentions/search.py +8 -7
- simpledomcontrol-0.159.0/sdc_core/sdc_extentions/test_utils.py +17 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/sdc_extentions/views.py +40 -6
- simpledomcontrol-0.159.0/sdc_core/signals.py +46 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/Assets/gulpfile.jsx +7 -0
- simpledomcontrol-0.159.0/sdc_core/template_files/Assets/tests/config/pre-test-setup.js +132 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/Assets/tests/config/test-setup.js +10 -6
- simpledomcontrol-0.159.0/sdc_core/template_files/Assets/webpack.config/webpack.default.config.jsx +63 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/asgi.py.txt +1 -1
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/package.json +1 -1
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/settings_extension.py.txt +46 -18
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/bin/sdc_tools/controller/sdc_model_form/sdc_model_form.js +8 -4
- {simpledomcontrol-0.158.8/sdc_tools/Assets/src → simpledomcontrol-0.159.0/sdc_tools/Assets/bin}/sdc_tools/controller/sdc_navigator/sdc_navigator.js +8 -4
- simpledomcontrol-0.159.0/sdc_tools/Assets/bin/sdc_tools/sdc_tools.organizer.js +1 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_model_form/sdc_model_form.js +8 -4
- {simpledomcontrol-0.158.8/sdc_tools/Assets/bin → simpledomcontrol-0.159.0/sdc_tools/Assets/src}/sdc_tools/controller/sdc_navigator/sdc_navigator.js +8 -4
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/tests/sdc_tools.test.js +2 -2
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/templates/widgets/searchable_select.html +2 -1
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/bin/sdc_user/controller/sdc_login/sdc_login.js +6 -5
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/bin/sdc_user/controller/sdc_user/sdc_user.js +10 -7
- simpledomcontrol-0.159.0/sdc_user/Assets/bin/sdc_user/sdc_user.organizer.js +1 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_login/sdc_login.js +6 -5
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_user/sdc_user.js +10 -7
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/tests/sdc_user.test.js +2 -2
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/forms.py +17 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/mails.py +37 -10
- simpledomcontrol-0.159.0/sdc_user/migrations/__init__.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/models.py +43 -4
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/sdc_views.py +54 -12
- simpledomcontrol-0.159.0/sdc_user/templates/sdc_user/sdc/sdc_change_password.html +7 -0
- simpledomcontrol-0.158.8/pyproject.toml +0 -53
- simpledomcontrol-0.158.8/sdc_core/management/commands/sdc_open_api.py +0 -445
- simpledomcontrol-0.158.8/sdc_core/signals.py +0 -39
- simpledomcontrol-0.158.8/sdc_core/template_files/Assets/tests/config/pre-test-setup.js +0 -94
- simpledomcontrol-0.158.8/sdc_core/template_files/Assets/webpack.config/webpack.default.config.jsx +0 -56
- simpledomcontrol-0.158.8/sdc_tools/Assets/bin/sdc_tools/sdc_tools.organizer.js +0 -1
- simpledomcontrol-0.158.8/sdc_user/Assets/bin/sdc_user/sdc_user.organizer.js +0 -1
- simpledomcontrol-0.158.8/sdc_user/templates/sdc_user/sdc/sdc_change_password.html +0 -2
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/README.md +0 -0
- {simpledomcontrol-0.158.8/sdc_core → simpledomcontrol-0.159.0/sdc}/__init__.py +0 -0
- {simpledomcontrol-0.158.8/sdc_core/management → simpledomcontrol-0.159.0/sdc_core}/__init__.py +0 -0
- {simpledomcontrol-0.158.8/sdc_core/management/commands → simpledomcontrol-0.159.0/sdc_core/management}/__init__.py +0 -0
- {simpledomcontrol-0.158.8/sdc_core/sdc_extentions → simpledomcontrol-0.159.0/sdc_core/management/commands}/__init__.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/_private.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/init_add/__init__.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/init_add/add_controller_manager.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/init_add/add_model_manager.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/init_add/options.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/init_add/settings_manager.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/init_add/utils.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_get_controller_url.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_is_installed.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_update_links.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/management/commands/sdc_update_url.py +0 -0
- {simpledomcontrol-0.158.8/sdc_core/templatetags → simpledomcontrol-0.159.0/sdc_core/sdc_extentions}/__init__.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/sdc_extentions/import_manager.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/sdc_extentions/response.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/.devcontainer/Dockerfile +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/.devcontainer/devcontainer.json +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/.devcontainer/on_create.sh +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/.devcontainer/on_startup.sh +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/Assets/babel.config.json +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/Assets/src/index.organizer.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/Assets/src/index.style.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/Assets/static/img/favicon.png +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/Assets/tests/config/post-test-teardown.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/Assets/webpack.config/webpack.bundle.config.jsx +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/Assets/webpack.config/webpack.development.config.jsx +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/Assets/webpack.config/webpack.production.config.jsx +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/controller/template_controller.js.txt +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/controller/template_css.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/controller/template_test.js.txt +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/controller/template_view.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/js_test.js.txt +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/models/detail.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/models/list.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/routing.py.txt +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/sdc_urls.py.txt +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/sdc_views.py.txt +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/templates/base.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/templates/elements/form.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/templates/elements/inline_form.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/templates/index.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/template_files/urls.py.txt +0 -0
- {simpledomcontrol-0.158.8/sdc_tools → simpledomcontrol-0.159.0/sdc_core/templatetags}/__init__.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/templatetags/addclass.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/templatetags/indexfilter.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_core/templatetags/sdc_filter.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/bin/sdc_tools/controller/sdc_alert_messenger/sdc_alert_messenger.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/bin/sdc_tools/controller/sdc_auto_submit/sdc_auto_submit.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/bin/sdc_tools/controller/sdc_detail_view/sdc_detail_view.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/bin/sdc_tools/controller/sdc_dummy/sdc_dummy.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/bin/sdc_tools/controller/sdc_error/sdc_error.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/bin/sdc_tools/controller/sdc_list_view/sdc_list_view.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/bin/sdc_tools/controller/sdc_navigation_client/sdc_navigation_client.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/bin/sdc_tools/controller/sdc_search_select/sdc_search_select.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/bin/sdc_tools/controller/sdc_search_view/sdc_search_view.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/bin/sdc_tools/controller/sdc_update_on_change/sdc_update_on_change.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/bin/sdc_tools/sdc_tools.style.css +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_alert_messenger/sdc_alert_messenger.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_alert_messenger/sdc_alert_messenger.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_auto_submit/sdc_auto_submit.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_detail_view/sdc_detail_view.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_detail_view/sdc_detail_view.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_dummy/sdc_dummy.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_dummy/sdc_dummy.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_error/sdc_error.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_error/sdc_error.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_list_view/sdc_list_view.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_list_view/sdc_list_view.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_model_form/sdc_model_form.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_navigation_client/sdc_navigation_client.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_navigator/sdc_navigator.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_search_select/sdc_search_select.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_search_select/sdc_search_select.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_search_view/sdc_search_view.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_search_view/sdc_search_view.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/controller/sdc_update_on_change/sdc_update_on_change.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/sdc_tools.organizer.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/Assets/src/sdc_tools/sdc_tools.style.scss +0 -0
- {simpledomcontrol-0.158.8/sdc_tools/migrations → simpledomcontrol-0.159.0/sdc_tools}/__init__.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/admin.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/apps.py +0 -0
- {simpledomcontrol-0.158.8/sdc_user → simpledomcontrol-0.159.0/sdc_tools/migrations}/__init__.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/models.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/sdc_urls.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/sdc_views.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/templates/email/base.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/templates/sdc_tools/sdc/dummy_sdc.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/templates/sdc_tools/sdc/sdc_alert_messenger.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/templates/sdc_tools/sdc/sdc_detail_view.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/templates/sdc_tools/sdc/sdc_dummy.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/templates/sdc_tools/sdc/sdc_error.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/templates/sdc_tools/sdc/sdc_list_view.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/templates/sdc_tools/sdc/sdc_model_form.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/templates/sdc_tools/sdc/sdc_navigator.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/templates/sdc_tools/sdc/sdc_search_select.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/templates/sdc_tools/sdc/sdc_search_view.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/tests.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/views.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_tools/widgets.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/bin/sdc_user/controller/register/register.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/bin/sdc_user/controller/sdc_change_password/sdc_change_password.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/bin/sdc_user/controller/sdc_confirm_email/sdc_confirm_email.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/bin/sdc_user/controller/sdc_logout/sdc_logout.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/bin/sdc_user/controller/sdc_password_forgotten/sdc_password_forgotten.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/bin/sdc_user/controller/sdc_reset_password/sdc_reset_password.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/bin/sdc_user/controller/sdc_user_nav_btn/sdc_user_nav_btn.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/bin/sdc_user/sdc_user.style.css +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/register/register.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/register/register.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_change_password/sdc_change_password.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_change_password/sdc_change_password.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_confirm_email/sdc_confirm_email.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_confirm_email/sdc_confirm_email.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_login/sdc_login.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_logout/sdc_logout.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_logout/sdc_logout.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_password_forgotten/sdc_password_forgotten.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_password_forgotten/sdc_password_forgotten.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_reset_password/sdc_reset_password.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_reset_password/sdc_reset_password.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_user/sdc_user.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_user_nav_btn/sdc_user_nav_btn.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/controller/sdc_user_nav_btn/sdc_user_nav_btn.scss +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/sdc_user.organizer.js +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/Assets/src/sdc_user/sdc_user.style.scss +0 -0
- {simpledomcontrol-0.158.8/sdc_user/migrations → simpledomcontrol-0.159.0/sdc_user}/__init__.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/admin.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/apps.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/migrations/0001_initial.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/sdc_urls.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/templates/email/confirm.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/templates/email/reset_password.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/templates/sdc_user/models/SdcUser/SdcUser_details.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/templates/sdc_user/models/SdcUser/SdcUser_list.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/templates/sdc_user/sdc/register.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/templates/sdc_user/sdc/sdc_confirm_email.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/templates/sdc_user/sdc/sdc_login.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/templates/sdc_user/sdc/sdc_logout.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/templates/sdc_user/sdc/sdc_password_forgotten.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/templates/sdc_user/sdc/sdc_reset_password.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/templates/sdc_user/sdc/sdc_user_nav_btn.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/templates/widgets/read_only_password_hash.html +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/tests.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/views.py +0 -0
- {simpledomcontrol-0.158.8 → simpledomcontrol-0.159.0}/sdc_user/widgets.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2026 Martin Starman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SimpleDomControl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.159.0
|
|
4
4
|
Summary: Simple DOM control -> a django MVC framework
|
|
5
|
-
License:
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
6
7
|
Keywords: django,MVC
|
|
7
8
|
Author: Martin Starman
|
|
8
9
|
Author-email: private@martin-starman.com
|
|
9
10
|
Requires-Python: >=3.13,<4.0
|
|
10
|
-
Classifier: Environment :: Web Environment
|
|
11
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
-
Classifier: Operating System :: OS Independent
|
|
13
11
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier:
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
-
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
12
|
+
Classifier: Framework :: Django
|
|
17
13
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
15
|
+
Classifier: Environment :: Web Environment
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Provides-Extra: postgres
|
|
18
18
|
Requires-Dist: attrs (>=25.4.0,<26.0.0)
|
|
19
19
|
Requires-Dist: channels (>=4.3.2,<5.0.0)
|
|
20
20
|
Requires-Dist: channels-redis (>=4.3.0,<5.0.0)
|
|
@@ -22,12 +22,14 @@ Requires-Dist: click (>=8.1.0)
|
|
|
22
22
|
Requires-Dist: daphne (>=4.2.1,<5.0.0)
|
|
23
23
|
Requires-Dist: django (>=6.0.2,<7.0.0)
|
|
24
24
|
Requires-Dist: inquirerpy (>=0.3.4,<0.4.0)
|
|
25
|
-
Requires-Dist:
|
|
26
|
-
Requires-Dist: psycopg2-binary (>=2.9.11,<3.0.0)
|
|
25
|
+
Requires-Dist: psycopg2-binary (>=2.9.11,<3.0.0) ; extra == "postgres"
|
|
27
26
|
Requires-Dist: pyjwt (>=2.11.0,<3.0.0)
|
|
28
27
|
Requires-Dist: pyyaml (>=6.0.3,<7.0.0)
|
|
29
28
|
Requires-Dist: regex (>=2026.1.15,<2027.0.0)
|
|
30
|
-
Project-URL:
|
|
29
|
+
Project-URL: Documentation, https://simpledomcontrol.readthedocs.io/en/latest/
|
|
30
|
+
Project-URL: Homepage, https://github.com/StarmanMartin/SimpleDomControl
|
|
31
|
+
Project-URL: Repository, https://github.com/StarmanMartin/SimpleDomControl
|
|
32
|
+
Project-URL: changelog, https://github.com/StarmanMartin/SimpleDomControl/blob/master/CHANGELOG.md
|
|
31
33
|
Description-Content-Type: text/markdown
|
|
32
34
|
|
|
33
35
|
# Simple Dom Control (SDC)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "SimpleDomControl"
|
|
3
|
+
version = "0.159.0"
|
|
4
|
+
description = "Simple DOM control -> a django MVC framework"
|
|
5
|
+
authors = [{ name = "Martin Starman", email = "private@martin-starman.com" }]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
requires-python = ">=3.13,<4.0"
|
|
10
|
+
keywords = ["django", "MVC"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"Framework :: Django",
|
|
14
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
15
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
16
|
+
"Environment :: Web Environment",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"daphne (>=4.2.1,<5.0.0)",
|
|
21
|
+
"channels (>=4.3.2,<5.0.0)",
|
|
22
|
+
"channels-redis (>=4.3.0,<5.0.0)",
|
|
23
|
+
"django (>=6.0.2,<7.0.0)",
|
|
24
|
+
"attrs (>=25.4.0,<26.0.0)",
|
|
25
|
+
"regex (>=2026.1.15,<2027.0.0)",
|
|
26
|
+
"click (>=8.1.0)",
|
|
27
|
+
"pyjwt (>=2.11.0,<3.0.0)",
|
|
28
|
+
"inquirerpy (>=0.3.4,<0.4.0)",
|
|
29
|
+
"pyyaml (>=6.0.3,<7.0.0)",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
# PostgreSQL driver: pip install "simpledomcontrol[postgres]"
|
|
34
|
+
postgres = ["psycopg2-binary (>=2.9.11,<3.0.0)"]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
homepage = "https://github.com/StarmanMartin/SimpleDomControl"
|
|
38
|
+
repository = "https://github.com/StarmanMartin/SimpleDomControl"
|
|
39
|
+
documentation = "https://simpledomcontrol.readthedocs.io/en/latest/"
|
|
40
|
+
changelog = "https://github.com/StarmanMartin/SimpleDomControl/blob/master/CHANGELOG.md"
|
|
41
|
+
|
|
42
|
+
[project.scripts]
|
|
43
|
+
sdc = "sdc.__main__:cli"
|
|
44
|
+
|
|
45
|
+
[tool.poetry]
|
|
46
|
+
packages = [{include = "sdc_core"}, {include = "sdc_user"}, {include = "sdc_tools"}, {include = "sdc"}]
|
|
47
|
+
|
|
48
|
+
[tool.poetry.group.dev.dependencies]
|
|
49
|
+
pytest = "^9.0.2"
|
|
50
|
+
pillow = "^12.1.0"
|
|
51
|
+
sphinx = "^9.1.0"
|
|
52
|
+
sphinx-toolbox = "^4.1.2"
|
|
53
|
+
sphinx-markdown-builder = "^0.6.9"
|
|
54
|
+
sphinx-rtd-theme = "^3.1.0"
|
|
55
|
+
|
|
56
|
+
[tool.pytest.ini_options]
|
|
57
|
+
pythonpath = [
|
|
58
|
+
"."
|
|
59
|
+
]
|
|
60
|
+
testpaths = [
|
|
61
|
+
"pytests",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[build-system]
|
|
65
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
66
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Command line tool of SDC: ``sdc new --name <project>`` creates a new Django project with SDC.
|
|
3
|
+
|
|
4
|
+
Installed as the console script ``sdc`` (also ``python -m sdc``).
|
|
5
|
+
"""
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
import shutil
|
|
9
|
+
import subprocess
|
|
10
|
+
import sys
|
|
11
|
+
import venv
|
|
12
|
+
from importlib import metadata
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
import click
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _default_package():
|
|
19
|
+
"""The simpledomcontrol version of this installation, so the new project uses the same one."""
|
|
20
|
+
try:
|
|
21
|
+
return f"simpledomcontrol=={metadata.version('SimpleDomControl')}"
|
|
22
|
+
except metadata.PackageNotFoundError:
|
|
23
|
+
return "simpledomcontrol"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _run(cmd, cwd):
|
|
27
|
+
click.echo(f"$ {' '.join(str(c) for c in cmd)}")
|
|
28
|
+
result = subprocess.run(cmd, cwd=cwd)
|
|
29
|
+
if result.returncode != 0:
|
|
30
|
+
raise click.ClickException(f"Command failed with exit code {result.returncode}: {' '.join(map(str, cmd))}")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _venv_python(venv_dir: Path) -> Path:
|
|
34
|
+
if os.name == "nt":
|
|
35
|
+
return venv_dir / "Scripts" / "python.exe"
|
|
36
|
+
return venv_dir / "bin" / "python"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _add_sdc_core(settings_path: Path):
|
|
40
|
+
text = settings_path.read_text()
|
|
41
|
+
if "'sdc_core'" in text or '"sdc_core"' in text:
|
|
42
|
+
return
|
|
43
|
+
new_text, count = re.subn(r"INSTALLED_APPS\s*=\s*\[", "INSTALLED_APPS = [\n 'sdc_core',", text, count=1)
|
|
44
|
+
if count != 1:
|
|
45
|
+
raise click.ClickException(f"INSTALLED_APPS not found in {settings_path}")
|
|
46
|
+
settings_path.write_text(new_text)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@click.group()
|
|
50
|
+
def cli():
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@cli.command(help="Creates a new SDC project in the subdirectory NAME of the current directory.")
|
|
55
|
+
@click.option("--name", prompt="Project name", help="Name of the new project (a valid Python identifier).")
|
|
56
|
+
@click.option("--package", default=None,
|
|
57
|
+
help="pip requirement used to install SDC into the project's virtualenv "
|
|
58
|
+
"(default: the installed version, e.g. simpledomcontrol==0.159.0).")
|
|
59
|
+
@click.option("--skip-npm", is_flag=True, help="Do not run 'npm install'.")
|
|
60
|
+
def new(name, package, skip_npm):
|
|
61
|
+
if not name.isidentifier():
|
|
62
|
+
raise click.BadParameter("The project name must be a valid Python identifier.", param_hint="--name")
|
|
63
|
+
target = Path.cwd() / name
|
|
64
|
+
if target.exists() and any(target.iterdir()):
|
|
65
|
+
raise click.ClickException(f"{target} already exists and is not empty.")
|
|
66
|
+
target.mkdir(parents=True, exist_ok=True)
|
|
67
|
+
|
|
68
|
+
# The virtualenv is created in its final location; moving a virtualenv breaks it.
|
|
69
|
+
venv_dir = target / "venv"
|
|
70
|
+
click.echo(f"Creating virtualenv in {venv_dir}")
|
|
71
|
+
venv.EnvBuilder(with_pip=True).create(venv_dir)
|
|
72
|
+
python = _venv_python(venv_dir)
|
|
73
|
+
|
|
74
|
+
_run([python, "-m", "pip", "install", "--upgrade", "pip"], target)
|
|
75
|
+
_run([python, "-m", "pip", "install", package or _default_package()], target)
|
|
76
|
+
_run([python, "-m", "django", "startproject", name, "."], target)
|
|
77
|
+
_add_sdc_core(target / name / "settings.py")
|
|
78
|
+
_run([python, "manage.py", "sdc_init", "-y"], target)
|
|
79
|
+
|
|
80
|
+
if skip_npm:
|
|
81
|
+
click.echo("Skipped 'npm install'.")
|
|
82
|
+
elif shutil.which("npm"):
|
|
83
|
+
_run(["npm", "install"], target)
|
|
84
|
+
else:
|
|
85
|
+
click.echo("npm was not found; run 'npm install' in the project directory to install the client.")
|
|
86
|
+
|
|
87
|
+
click.echo(f"\nDone. Next steps:\n cd {name}\n source venv/bin/activate\n"
|
|
88
|
+
f" python manage.py migrate\n npm run develop # in a second terminal: python manage.py runserver")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
if __name__ == '__main__':
|
|
92
|
+
cli()
|
|
@@ -8,7 +8,7 @@ class SdcCoreConfig(AppConfig):
|
|
|
8
8
|
def ready(self):
|
|
9
9
|
import sys
|
|
10
10
|
from django.conf import settings
|
|
11
|
-
|
|
11
|
+
import sdc_core.signals # noqa: F401 (registers the signal receivers)
|
|
12
12
|
|
|
13
13
|
if settings.DEBUG and os.path.exists('./Assets'):
|
|
14
14
|
env_vars = {}
|
|
@@ -6,6 +6,7 @@ import traceback
|
|
|
6
6
|
from django.apps import apps
|
|
7
7
|
from django.conf import settings
|
|
8
8
|
from django.core.exceptions import PermissionDenied
|
|
9
|
+
from django.core.serializers.json import DjangoJSONEncoder
|
|
9
10
|
from django.core.files.uploadhandler import TemporaryFileUploadHandler
|
|
10
11
|
|
|
11
12
|
from django.utils.datastructures import MultiValueDict
|
|
@@ -14,11 +15,10 @@ from django.utils.translation import gettext as _f
|
|
|
14
15
|
from django.contrib.auth import get_user_model
|
|
15
16
|
from channels.generic.websocket import WebsocketConsumer, AsyncWebsocketConsumer
|
|
16
17
|
|
|
17
|
-
from asgiref.sync import async_to_sync
|
|
18
|
-
import importlib
|
|
18
|
+
from asgiref.sync import async_to_sync, sync_to_async
|
|
19
19
|
import json
|
|
20
20
|
|
|
21
|
-
from sdc_core.sdc_extentions.models import SdcModel, SDCSerializer, all_models, sanitize_filter_query
|
|
21
|
+
from sdc_core.sdc_extentions.models import SdcModel, SDCSerializer, all_models, sanitize_filter_query, resolve_form
|
|
22
22
|
from sdc_core.sdc_extentions.response import sdc_link_factory, sdc_link_obj_factory
|
|
23
23
|
from sdc_core.sdc_extentions.import_manager import import_function
|
|
24
24
|
from sdc_core.sdc_extentions.search import handle_search_form
|
|
@@ -68,7 +68,7 @@ class MsgManager:
|
|
|
68
68
|
return {'save': {'header': f'{model} saved', 'msg': '{0} was successfully saved'},
|
|
69
69
|
'on_change': {'header': f'{model} was changed', 'msg': '{0} was changed'},
|
|
70
70
|
'create': {'header': f'{model} created', 'msg': '{0} was successfully created'},
|
|
71
|
-
'delete': {'header': f'{model} was deleted', 'msg': '{0} was
|
|
71
|
+
'delete': {'header': f'{model} was deleted', 'msg': '{0} was deleted'}}
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
class SDCConsumer(AsyncWebsocketConsumer):
|
|
@@ -115,7 +115,7 @@ class SDCConsumer(AsyncWebsocketConsumer):
|
|
|
115
115
|
'is_error': True,
|
|
116
116
|
'msg': event.get('msg', ''),
|
|
117
117
|
'header': event.get('header', ''),
|
|
118
|
-
}))
|
|
118
|
+
}, cls=DjangoJSONEncoder))
|
|
119
119
|
|
|
120
120
|
@staticmethod
|
|
121
121
|
def to_camel_case(snake_str):
|
|
@@ -147,19 +147,25 @@ class SDCConsumer(AsyncWebsocketConsumer):
|
|
|
147
147
|
if asyncio.iscoroutinefunction(method):
|
|
148
148
|
return_vals = await method(self, **json_data.get('args', {}))
|
|
149
149
|
else:
|
|
150
|
-
|
|
150
|
+
# Sync methods run in a worker thread, so they may use the Django ORM.
|
|
151
|
+
return_vals = await sync_to_async(method)(self, **json_data.get('args', {}))
|
|
151
152
|
|
|
152
153
|
return_vals_generator = []
|
|
153
154
|
if isinstance(return_vals, types.GeneratorType):
|
|
154
155
|
return_vals_generator = return_vals
|
|
155
156
|
return_vals = next(return_vals, None)
|
|
156
157
|
|
|
158
|
+
# {'is_error': True, 'msg': ..., 'header': ...} rejects the serverCall promise.
|
|
159
|
+
if isinstance(return_vals, dict) and return_vals.get('is_error'):
|
|
160
|
+
await self.state_error(return_vals, json_data['id'])
|
|
161
|
+
return
|
|
162
|
+
|
|
157
163
|
await self.send(text_data=json.dumps({
|
|
158
164
|
'id': json_data['id'],
|
|
159
165
|
'type': 'sdc_recall',
|
|
160
166
|
'data': return_vals,
|
|
161
167
|
'is_error': False
|
|
162
|
-
}))
|
|
168
|
+
}, cls=DjangoJSONEncoder))
|
|
163
169
|
for x in return_vals_generator: pass
|
|
164
170
|
else:
|
|
165
171
|
raise ValueError("event must be sdc_call")
|
|
@@ -190,12 +196,21 @@ class SDCModelConsumer(WebsocketConsumer):
|
|
|
190
196
|
self.model_name = None
|
|
191
197
|
self.model = None
|
|
192
198
|
self.queryset = {}
|
|
193
|
-
|
|
199
|
+
# Filter of the last full load (connect, load, list_view, named_view). Live updates
|
|
200
|
+
# (on_create) are checked against it, independent of later form or detail requests.
|
|
201
|
+
self.live_query = {}
|
|
202
|
+
# Primary keys of the rows the client has received; on_update/on_delete are only
|
|
203
|
+
# forwarded for these.
|
|
204
|
+
self.ids = []
|
|
205
|
+
self.model_id = None
|
|
194
206
|
self._upload_handler = {}
|
|
195
207
|
self._group_names = []
|
|
196
208
|
|
|
197
209
|
def connect(self):
|
|
198
210
|
self.model_name = self.scope['url_route']['kwargs']['model_name']
|
|
211
|
+
# sdc_ws/model/<model_name>/<model_id> restricts the connection to one object.
|
|
212
|
+
model_id = self.scope['url_route']['kwargs'].get('model_id')
|
|
213
|
+
self.model_id = int(model_id) if model_id else None
|
|
199
214
|
self.model = ALL_MODELS.get(self.model_name)
|
|
200
215
|
if self.model is None or not hasattr(self.model, '__is_sdc_model__'):
|
|
201
216
|
raise ValueError(f'{self.model_name} is not a SDC model')
|
|
@@ -204,22 +219,40 @@ class SDCModelConsumer(WebsocketConsumer):
|
|
|
204
219
|
self.accept()
|
|
205
220
|
|
|
206
221
|
def websocket_disconnect(self, close_code):
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
222
|
+
try:
|
|
223
|
+
for group in self._group_names:
|
|
224
|
+
async_to_sync(self.channel_layer.group_discard)(group, self.channel_name)
|
|
225
|
+
on_disconnected = getattr(self.model.SdcMeta, 'on_disconnected', None) if self.model else None
|
|
226
|
+
if callable(on_disconnected):
|
|
227
|
+
on_disconnected(self._load_model('disconnect', self.live_query))
|
|
228
|
+
except Exception:
|
|
229
|
+
logger.exception("Error while closing the SDC model connection")
|
|
230
|
+
finally:
|
|
231
|
+
super().websocket_disconnect(close_code)
|
|
211
232
|
|
|
212
233
|
def on_update(self, data):
|
|
213
234
|
if data['pk'] in self.ids:
|
|
214
235
|
self.send(text_data=json.dumps(data))
|
|
215
236
|
|
|
237
|
+
def on_delete(self, data):
|
|
238
|
+
if data['pk'] in self.ids:
|
|
239
|
+
self.ids.remove(data['pk'])
|
|
240
|
+
self.send(text_data=json.dumps(data))
|
|
241
|
+
|
|
216
242
|
def on_create(self, data):
|
|
217
|
-
|
|
243
|
+
# Forward only rows the user may see and that match the filter of the last full load.
|
|
218
244
|
try:
|
|
219
|
-
self._load_model(
|
|
245
|
+
rows = self._load_model('load', self.live_query)
|
|
246
|
+
if hasattr(rows, 'filter'):
|
|
247
|
+
visible = rows.filter(pk=data['pk']).exists()
|
|
248
|
+
else:
|
|
249
|
+
visible = data['pk'] in self._pks(rows)
|
|
250
|
+
except Exception:
|
|
251
|
+
logger.exception("Error while checking a created %s for live updates", self.model_name)
|
|
252
|
+
visible = False
|
|
253
|
+
if visible:
|
|
254
|
+
self._track_ids([data['pk']])
|
|
220
255
|
self.send(text_data=json.dumps(data))
|
|
221
|
-
except:
|
|
222
|
-
pass
|
|
223
256
|
|
|
224
257
|
def state_error(self, event):
|
|
225
258
|
self.send(text_data=json.dumps({
|
|
@@ -266,12 +299,7 @@ class SDCModelConsumer(WebsocketConsumer):
|
|
|
266
299
|
elif event_type == 'model_delete':
|
|
267
300
|
self._delete_element(json_data)
|
|
268
301
|
elif event_type == 'model_load':
|
|
269
|
-
self.
|
|
270
|
-
'type': json_data['event_type'],
|
|
271
|
-
'event_id': json_data['event_id'],
|
|
272
|
-
'args': self._prepare_loaded_data(),
|
|
273
|
-
'is_error': False
|
|
274
|
-
}))
|
|
302
|
+
self._load(json_data)
|
|
275
303
|
else:
|
|
276
304
|
raise ValueError(
|
|
277
305
|
f"{json_data['event']} must be 'model' and {json_data['event_type']} must be in [load, delete, upload, create, save, detail_view, 'connect', 'edit_form', 'create_form', 'list_view']")
|
|
@@ -287,7 +315,9 @@ class SDCModelConsumer(WebsocketConsumer):
|
|
|
287
315
|
except Exception as e:
|
|
288
316
|
extracted_list = traceback.extract_tb(e.__traceback__)
|
|
289
317
|
e_text = [e.__str__()] + [item for item in traceback.StackSummary.from_list(extracted_list).format()]
|
|
318
|
+
|
|
290
319
|
if settings.DEBUG:
|
|
320
|
+
logger.error(e_text[0])
|
|
291
321
|
traceback.print_tb(e.__traceback__)
|
|
292
322
|
else:
|
|
293
323
|
logger.error(e_text)
|
|
@@ -317,21 +347,63 @@ class SDCModelConsumer(WebsocketConsumer):
|
|
|
317
347
|
self.channel_name
|
|
318
348
|
)
|
|
319
349
|
|
|
320
|
-
def _load_model(self, event_type=None):
|
|
350
|
+
def _load_model(self, event_type=None, query=None):
|
|
351
|
+
"""
|
|
352
|
+
Returns the rows for ``query`` (default: the filter of the current message):
|
|
353
|
+
``get_queryset()`` of the model, filtered with the sanitised query, or the
|
|
354
|
+
result of the model's ``data_load()`` hook if it returns one.
|
|
355
|
+
"""
|
|
321
356
|
if event_type is None:
|
|
322
357
|
event_type = self.scope['event_type']
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
358
|
+
if query is None:
|
|
359
|
+
query = self.queryset
|
|
360
|
+
clean_query = sanitize_filter_query(self.model, query)
|
|
361
|
+
if self.model_id is not None:
|
|
362
|
+
clean_query['pk'] = self.model_id
|
|
363
|
+
queryset = self.model.get_queryset(self.scope['user'], event_type, query)
|
|
364
|
+
|
|
365
|
+
data_load_result = self.model.data_load(self.scope['user'], queryset, clean_query)
|
|
326
366
|
if data_load_result is not None:
|
|
327
367
|
return data_load_result
|
|
328
|
-
|
|
329
|
-
self.ids = list(res.values_list('id', flat=True))
|
|
368
|
+
return queryset.filter(**clean_query)
|
|
330
369
|
|
|
331
|
-
|
|
370
|
+
@staticmethod
|
|
371
|
+
def _pks(rows):
|
|
372
|
+
if hasattr(rows, 'values_list'):
|
|
373
|
+
return list(rows.values_list('pk', flat=True))
|
|
374
|
+
return [row.pk for row in rows]
|
|
375
|
+
|
|
376
|
+
def _track_ids(self, pks, replace=False):
|
|
377
|
+
"""Remembers which rows the client has received (for on_update/on_delete)."""
|
|
378
|
+
if replace:
|
|
379
|
+
self.ids = list(pks)
|
|
380
|
+
else:
|
|
381
|
+
self.ids += [pk for pk in pks if pk not in self.ids]
|
|
382
|
+
|
|
383
|
+
def _full_load(self):
|
|
384
|
+
"""Loads with the current filter and makes it the filter for live updates."""
|
|
385
|
+
self.live_query = dict(self.queryset)
|
|
386
|
+
rows = self._load_model()
|
|
387
|
+
self._track_ids(self._pks(rows), replace=True)
|
|
388
|
+
return rows
|
|
389
|
+
|
|
390
|
+
def _load(self, json_data):
|
|
391
|
+
# queryset.update({item}) loads a single row with {"id": <pk>}: that row is added to
|
|
392
|
+
# the known rows; any other load replaces them and the live filter.
|
|
393
|
+
if set(self.queryset.keys()) in ({'id'}, {'pk'}):
|
|
394
|
+
rows = self._load_model()
|
|
395
|
+
self._track_ids(self._pks(rows))
|
|
396
|
+
else:
|
|
397
|
+
rows = self._full_load()
|
|
398
|
+
self.send(text_data=json.dumps({
|
|
399
|
+
'type': json_data['event_type'],
|
|
400
|
+
'event_id': json_data['event_id'],
|
|
401
|
+
'args': self._prepare_loaded_data(rows),
|
|
402
|
+
'is_error': False
|
|
403
|
+
}))
|
|
332
404
|
|
|
333
405
|
def _init_connection(self, json_data):
|
|
334
|
-
self.
|
|
406
|
+
self._full_load()
|
|
335
407
|
self._add_to_class()
|
|
336
408
|
# self.model_description = {field.name: field.__class__.__name__ for field in self.model._meta.fields}
|
|
337
409
|
self.send(text_data=json.dumps({
|
|
@@ -360,15 +432,7 @@ class SDCModelConsumer(WebsocketConsumer):
|
|
|
360
432
|
return self._load_form(json_data, getattr(self.model.SdcMeta, form_name), instance)
|
|
361
433
|
|
|
362
434
|
def _load_form(self, json_data, form_attr, instance=None):
|
|
363
|
-
|
|
364
|
-
form_attr = form_attr({})
|
|
365
|
-
if form_attr is None:
|
|
366
|
-
raise NotImplementedError()
|
|
367
|
-
elif isinstance(form_attr, str):
|
|
368
|
-
edit_form_path = form_attr.split('.')
|
|
369
|
-
form = getattr(importlib.import_module('.'.join(edit_form_path[0:-1])), edit_form_path[-1])
|
|
370
|
-
else:
|
|
371
|
-
form = form_attr
|
|
435
|
+
form = resolve_form(form_attr)
|
|
372
436
|
|
|
373
437
|
self.send(text_data=json.dumps({
|
|
374
438
|
'type': json_data['event_type'],
|
|
@@ -422,13 +486,7 @@ class SDCModelConsumer(WebsocketConsumer):
|
|
|
422
486
|
def _submit_element(self, json_data, form_attr, instance=None):
|
|
423
487
|
data = json_data['args']['data']
|
|
424
488
|
files = json_data['args'].get('files')
|
|
425
|
-
|
|
426
|
-
raise NotImplementedError()
|
|
427
|
-
elif isinstance(form_attr, str):
|
|
428
|
-
edit_form_path = form_attr.split('.')
|
|
429
|
-
form = getattr(importlib.import_module('.'.join(edit_form_path[0:-1])), edit_form_path[-1])
|
|
430
|
-
else:
|
|
431
|
-
form = form_attr
|
|
489
|
+
form = resolve_form(form_attr)
|
|
432
490
|
uploads = MultiValueDict()
|
|
433
491
|
if files is not None:
|
|
434
492
|
for (key, val) in files.items():
|
|
@@ -442,6 +500,7 @@ class SDCModelConsumer(WebsocketConsumer):
|
|
|
442
500
|
if is_valid:
|
|
443
501
|
form_instance.save()
|
|
444
502
|
new_instance = SDCSerializer().serialize(self._load_model().filter(pk=form_instance.instance.pk))
|
|
503
|
+
self._track_ids([form_instance.instance.pk])
|
|
445
504
|
msg = self.msg_manager.get_msg(form_instance.instance, json_data['event_type'])
|
|
446
505
|
else:
|
|
447
506
|
msg = {'header': 'Upss!',
|
|
@@ -463,7 +522,7 @@ class SDCModelConsumer(WebsocketConsumer):
|
|
|
463
522
|
if self.model.SdcMeta.html_list_template is None:
|
|
464
523
|
raise NotImplementedError()
|
|
465
524
|
filter = self.queryset.pop('__search_values', {})
|
|
466
|
-
loaded_data = self.
|
|
525
|
+
loaded_data = self._full_load()
|
|
467
526
|
self.send(text_data=json.dumps({
|
|
468
527
|
'type': json_data['event_type'],
|
|
469
528
|
'event_id': json_data['event_id'],
|
|
@@ -473,10 +532,11 @@ class SDCModelConsumer(WebsocketConsumer):
|
|
|
473
532
|
}))
|
|
474
533
|
|
|
475
534
|
def _load_named_view(self, json_data):
|
|
476
|
-
loaded_data = self.
|
|
535
|
+
loaded_data = self._full_load()
|
|
477
536
|
view_name = json_data['args']['view_name']
|
|
478
537
|
if not hasattr(self.model.SdcMeta, view_name):
|
|
479
|
-
|
|
538
|
+
text = f'"{view_name}" is not implemented in "{loaded_data.__class__.__name__}.SdcMeta".'
|
|
539
|
+
raise Exception(text)
|
|
480
540
|
self.send(text_data=json.dumps({
|
|
481
541
|
'type': json_data['event_type'],
|
|
482
542
|
'event_id': json_data['event_id'],
|
|
@@ -490,6 +550,7 @@ class SDCModelConsumer(WebsocketConsumer):
|
|
|
490
550
|
raise NotImplementedError()
|
|
491
551
|
instance = self._load_model().get(pk=json_data['args']['pk'])
|
|
492
552
|
instance.scope = self.scope
|
|
553
|
+
self._track_ids([instance.pk])
|
|
493
554
|
self.send(text_data=json.dumps({
|
|
494
555
|
'type': json_data['event_type'],
|
|
495
556
|
'event_id': json_data['event_id'],
|
|
@@ -60,6 +60,9 @@ def verify_jwt(token, type):
|
|
|
60
60
|
|
|
61
61
|
user = User.objects.get(id=payload["user_id"])
|
|
62
62
|
|
|
63
|
+
if not user.is_active:
|
|
64
|
+
raise jwt.InvalidTokenError
|
|
65
|
+
|
|
63
66
|
if type == 'refresh' and abs(payload['iat'] - user.last_login.timestamp()) > 10:
|
|
64
67
|
raise jwt.InvalidTokenError
|
|
65
68
|
|
|
@@ -21,9 +21,10 @@ def add_sdc_to_main_urls(main_urls_path):
|
|
|
21
21
|
new_apps = "%sre_path('sdc_view/sdc_tools/', include('sdc_tools.sdc_urls')),\n" % options.SEP
|
|
22
22
|
new_apps += "%sre_path('sdc_view/sdc_user/', include('sdc_user.sdc_urls')),\n" % options.SEP
|
|
23
23
|
|
|
24
|
+
# The login route must come before sdc_api/<str:model>/, which would match "login" as well.
|
|
25
|
+
new_apps += f"{options.SEP}path('sdc_api/login/', get_api_token),\n"
|
|
24
26
|
new_apps += f"{options.SEP}path('sdc_api/<str:model>/<int:id>/', AdcApi.as_view()),\n"
|
|
25
27
|
new_apps += f"{options.SEP}path('sdc_api/<str:model>/', AdcApi.as_view()),\n"
|
|
26
|
-
new_apps += f"{options.SEP}path('sdc_api/login/', get_api_token),\n"
|
|
27
28
|
|
|
28
29
|
line = re.sub(r'urlpatterns = \[',
|
|
29
30
|
"urlpatterns = [\n%s%s# scd view below\n" % (new_apps, options.SEP), line)
|