arthexis 0.1.20__tar.gz → 0.1.21__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.
Potentially problematic release.
This version of arthexis might be problematic. Click here for more details.
- {arthexis-0.1.20 → arthexis-0.1.21}/PKG-INFO +3 -4
- {arthexis-0.1.20 → arthexis-0.1.21}/arthexis.egg-info/PKG-INFO +3 -4
- {arthexis-0.1.20 → arthexis-0.1.21}/arthexis.egg-info/SOURCES.txt +2 -10
- {arthexis-0.1.20 → arthexis-0.1.21}/arthexis.egg-info/requires.txt +2 -3
- {arthexis-0.1.20 → arthexis-0.1.21}/config/asgi.py +1 -15
- {arthexis-0.1.20 → arthexis-0.1.21}/config/settings.py +0 -26
- {arthexis-0.1.20 → arthexis-0.1.21}/config/urls.py +0 -1
- {arthexis-0.1.20 → arthexis-0.1.21}/core/admin.py +1 -233
- {arthexis-0.1.20 → arthexis-0.1.21}/core/apps.py +0 -6
- {arthexis-0.1.20 → arthexis-0.1.21}/core/environment.py +29 -10
- {arthexis-0.1.20 → arthexis-0.1.21}/core/models.py +8 -77
- {arthexis-0.1.20 → arthexis-0.1.21}/core/tests.py +1 -7
- {arthexis-0.1.20 → arthexis-0.1.21}/core/views.py +0 -96
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/admin.py +29 -6
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/tests.py +49 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/views.py +60 -1
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/admin.py +48 -6
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/models.py +48 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/tests.py +83 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/views.py +85 -3
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/context_processors.py +0 -12
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/tests.py +0 -41
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/urls.py +0 -1
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/views.py +0 -5
- {arthexis-0.1.20 → arthexis-0.1.21}/pyproject.toml +2 -2
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_email_profiles.py +0 -3
- arthexis-0.1.21/tests/test_environment_network_setup_form.py +39 -0
- arthexis-0.1.21/tests/test_fixture_presence.py +53 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_install_script.py +20 -11
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_network_setup_interactive.py +10 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_profile_inline_deletion.py +2 -44
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_release_progress.py +17 -112
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_release_progress_pre_release_integration.py +10 -33
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_rfid_admin_scan_csrf.py +4 -0
- arthexis-0.1.21/tests/test_settings_mcp_port.py +35 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_switch_role_script.py +0 -17
- arthexis-0.1.21/tests/test_uninstall_script.py +9 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_user_data_admin.py +1 -5
- arthexis-0.1.20/core/workgroup_urls.py +0 -17
- arthexis-0.1.20/core/workgroup_views.py +0 -94
- arthexis-0.1.20/tests/test_assistant_data_api.py +0 -32
- arthexis-0.1.20/tests/test_assistant_profile_admin.py +0 -168
- arthexis-0.1.20/tests/test_assistant_profile_api.py +0 -49
- arthexis-0.1.20/tests/test_fixture_presence.py +0 -21
- arthexis-0.1.20/tests/test_mcp_asgi.py +0 -55
- arthexis-0.1.20/tests/test_mcp_auto_start.py +0 -170
- arthexis-0.1.20/tests/test_mcp_process.py +0 -43
- arthexis-0.1.20/tests/test_mcp_sigil_server.py +0 -182
- arthexis-0.1.20/tests/test_mcp_sigil_server_command.py +0 -42
- arthexis-0.1.20/tests/test_uninstall_script.py +0 -20
- {arthexis-0.1.20 → arthexis-0.1.21}/LICENSE +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/README.md +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/arthexis.egg-info/dependency_links.txt +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/arthexis.egg-info/top_level.txt +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/config/__init__.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/config/active_app.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/config/auth_app.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/config/celery.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/config/context_processors.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/config/horologia_app.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/config/loadenv.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/config/logging.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/config/middleware.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/config/offline.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/config/settings_helpers.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/config/wsgi.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/__init__.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/admin_history.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/admindocs.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/auto_upgrade.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/backends.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/changelog.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/entity.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/fields.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/form_fields.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/github_helper.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/github_issues.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/github_repos.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/lcd_screen.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/liveupdate.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/log_paths.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/mailer.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/middleware.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/notifications.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/public_wifi.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/reference_utils.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/release.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/rfid_import_export.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/sigil_builder.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/sigil_context.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/sigil_resolver.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/system.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/tasks.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/temp_passwords.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/test_system_info.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/tests_liveupdate.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/urls.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/user_data.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/core/widgets.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/__init__.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/apps.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/backends.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/dns.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/feature_checks.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/lcd.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/models.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/reports.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/rfid_sync.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/signals.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/tasks.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/urls.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/nodes/utils.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/__init__.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/apps.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/consumers.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/evcs.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/evcs_discovery.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/reference_utils.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/routing.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/simulator.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/status_display.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/store.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/tasks.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/test_export_import.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/test_rfid.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/transactions_io.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/ocpp/urls.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/__init__.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/admin.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/apps.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/checks.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/defaults.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/forms.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/middleware.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/models.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/module_defaults.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/site_config.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/tasks.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/pages/utils.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/setup.cfg +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_acronym_capitalization.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_admin_client_report.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_admin_doc_commands.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_admin_doc_model_groups.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_admin_history.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_admin_index_actions.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_admin_model_graph.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_admin_object_history.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_admin_profile_link.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_admin_system_stop.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_allowed_hosts_hostname.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_api_login_required.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_auto_upgrade_scheduler.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_awg_admin.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_benchmark_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_build_pypi_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_celery_no_debug.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_changelog_builder.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_check_admin_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_check_migrations_script.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_check_pypi_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_clean_release_logs_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_client_report_form.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_client_report_generation.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_client_report_schedule.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_csrf_failure.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_csrf_origin_subnet.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_dist_cleanup.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_email_collector.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_email_inbox.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_email_inbox_admin.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_email_inbox_search_action.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_email_outbox_admin.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_email_transaction.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_env_refresh_clean.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_env_refresh_pip.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_env_refresh_unlink.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_experience_admin_group.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_footer_no_references.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_footer_presence.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_footer_render.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_git_checks.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_github_issue_reporting.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_invitation_login_view.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_language_switch.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_lcd_check_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_lcd_smbus2.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_localhost_admin_backend.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_log_paths.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_login_view_no_site.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_manage_debug_flag.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_manuals.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_message_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_migrations.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_model_verbose_name_capitalization.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_node_info_view.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_notifications_fallback.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_notify_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_ocpp_session_lock.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_odoo_product.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_odoo_profile.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_odoo_profile_admin.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_odoo_quote_report.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_offline.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_package_admin_next_release.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_power_admin_group.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_pypi_check.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_pypi_token.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_readme_editor.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_readme_language.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_reference_qr_code.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_reference_transaction_uuid.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_register_site_apps_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_release_build.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_release_build_flow.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_release_checklist.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_release_logs.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_release_manager_admin.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_release_packages.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_release_push.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_release_tasks.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_render_nginx_sites.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_request_invite.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_rfid_admin_print_labels.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_rfid_admin_reference_clear.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_rfid_always_on.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_rfid_backend.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_rfid_background_reader.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_rfid_client_report.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_rfid_watch_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_role_marker_filtering.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_seed_data.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_send_invite_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_settings_helpers.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_shell_scripts.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_show_leads_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_sigil_builder.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_sigil_resolution.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_sites_utils.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_social_profile.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_staff_login_net_message.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_staff_required_decorator.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_suite_gateway.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_system_changelog_report.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_temp_passwords.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_totp_admin.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_totp_backend.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_update_fixtures_command.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_upgrade_report.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_urls_autodiscover.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_version_endpoint.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_version_file.py +0 -0
- {arthexis-0.1.20 → arthexis-0.1.21}/tests/test_vscode_manage.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arthexis
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.21
|
|
4
4
|
Summary: Power & Energy Infrastructure
|
|
5
5
|
Author-email: "Rafael J. Guillén-Osorio" <tecnologia@gelectriic.com>
|
|
6
6
|
License-Expression: GPL-3.0-only
|
|
@@ -59,7 +59,6 @@ Requires-Dist: kombu==5.5.4
|
|
|
59
59
|
Requires-Dist: libipld==3.1.1
|
|
60
60
|
Requires-Dist: Markdown==3.8.2
|
|
61
61
|
Requires-Dist: mdx_truly_sane_lists==1.3
|
|
62
|
-
Requires-Dist: mcp==1.18.0
|
|
63
62
|
Requires-Dist: mfrc522==0.0.7; sys_platform == "linux"
|
|
64
63
|
Requires-Dist: outcome==1.3.0.post0
|
|
65
64
|
Requires-Dist: packaging==25.0
|
|
@@ -67,7 +66,7 @@ Requires-Dist: pillow==11.3.0
|
|
|
67
66
|
Requires-Dist: prompt_toolkit==3.0.51
|
|
68
67
|
Requires-Dist: psutil==7.1.1
|
|
69
68
|
Requires-Dist: psycopg==3.2.9
|
|
70
|
-
Requires-Dist: psycopg-binary==3.2.
|
|
69
|
+
Requires-Dist: psycopg-binary==3.2.12
|
|
71
70
|
Requires-Dist: pyasn1==0.6.1
|
|
72
71
|
Requires-Dist: pyasn1_modules==0.4.2
|
|
73
72
|
Requires-Dist: pycparser==2.22
|
|
@@ -111,7 +110,7 @@ Requires-Dist: websockets==13.1
|
|
|
111
110
|
Requires-Dist: whitenoise==6.11.0
|
|
112
111
|
Requires-Dist: plyer==2.1.0; sys_platform == "win32"
|
|
113
112
|
Requires-Dist: wsproto==1.2.0
|
|
114
|
-
Requires-Dist: zope.interface==
|
|
113
|
+
Requires-Dist: zope.interface==8.0.1
|
|
115
114
|
Dynamic: license-file
|
|
116
115
|
|
|
117
116
|
# Arthexis Constellation
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arthexis
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.21
|
|
4
4
|
Summary: Power & Energy Infrastructure
|
|
5
5
|
Author-email: "Rafael J. Guillén-Osorio" <tecnologia@gelectriic.com>
|
|
6
6
|
License-Expression: GPL-3.0-only
|
|
@@ -59,7 +59,6 @@ Requires-Dist: kombu==5.5.4
|
|
|
59
59
|
Requires-Dist: libipld==3.1.1
|
|
60
60
|
Requires-Dist: Markdown==3.8.2
|
|
61
61
|
Requires-Dist: mdx_truly_sane_lists==1.3
|
|
62
|
-
Requires-Dist: mcp==1.18.0
|
|
63
62
|
Requires-Dist: mfrc522==0.0.7; sys_platform == "linux"
|
|
64
63
|
Requires-Dist: outcome==1.3.0.post0
|
|
65
64
|
Requires-Dist: packaging==25.0
|
|
@@ -67,7 +66,7 @@ Requires-Dist: pillow==11.3.0
|
|
|
67
66
|
Requires-Dist: prompt_toolkit==3.0.51
|
|
68
67
|
Requires-Dist: psutil==7.1.1
|
|
69
68
|
Requires-Dist: psycopg==3.2.9
|
|
70
|
-
Requires-Dist: psycopg-binary==3.2.
|
|
69
|
+
Requires-Dist: psycopg-binary==3.2.12
|
|
71
70
|
Requires-Dist: pyasn1==0.6.1
|
|
72
71
|
Requires-Dist: pyasn1_modules==0.4.2
|
|
73
72
|
Requires-Dist: pycparser==2.22
|
|
@@ -111,7 +110,7 @@ Requires-Dist: websockets==13.1
|
|
|
111
110
|
Requires-Dist: whitenoise==6.11.0
|
|
112
111
|
Requires-Dist: plyer==2.1.0; sys_platform == "win32"
|
|
113
112
|
Requires-Dist: wsproto==1.2.0
|
|
114
|
-
Requires-Dist: zope.interface==
|
|
113
|
+
Requires-Dist: zope.interface==8.0.1
|
|
115
114
|
Dynamic: license-file
|
|
116
115
|
|
|
117
116
|
# Arthexis Constellation
|
|
@@ -60,8 +60,6 @@ core/urls.py
|
|
|
60
60
|
core/user_data.py
|
|
61
61
|
core/views.py
|
|
62
62
|
core/widgets.py
|
|
63
|
-
core/workgroup_urls.py
|
|
64
|
-
core/workgroup_views.py
|
|
65
63
|
nodes/__init__.py
|
|
66
64
|
nodes/admin.py
|
|
67
65
|
nodes/apps.py
|
|
@@ -125,9 +123,6 @@ tests/test_admin_profile_link.py
|
|
|
125
123
|
tests/test_admin_system_stop.py
|
|
126
124
|
tests/test_allowed_hosts_hostname.py
|
|
127
125
|
tests/test_api_login_required.py
|
|
128
|
-
tests/test_assistant_data_api.py
|
|
129
|
-
tests/test_assistant_profile_admin.py
|
|
130
|
-
tests/test_assistant_profile_api.py
|
|
131
126
|
tests/test_auto_upgrade_scheduler.py
|
|
132
127
|
tests/test_awg_admin.py
|
|
133
128
|
tests/test_benchmark_command.py
|
|
@@ -154,6 +149,7 @@ tests/test_email_transaction.py
|
|
|
154
149
|
tests/test_env_refresh_clean.py
|
|
155
150
|
tests/test_env_refresh_pip.py
|
|
156
151
|
tests/test_env_refresh_unlink.py
|
|
152
|
+
tests/test_environment_network_setup_form.py
|
|
157
153
|
tests/test_experience_admin_group.py
|
|
158
154
|
tests/test_fixture_presence.py
|
|
159
155
|
tests/test_footer_no_references.py
|
|
@@ -171,11 +167,6 @@ tests/test_log_paths.py
|
|
|
171
167
|
tests/test_login_view_no_site.py
|
|
172
168
|
tests/test_manage_debug_flag.py
|
|
173
169
|
tests/test_manuals.py
|
|
174
|
-
tests/test_mcp_asgi.py
|
|
175
|
-
tests/test_mcp_auto_start.py
|
|
176
|
-
tests/test_mcp_process.py
|
|
177
|
-
tests/test_mcp_sigil_server.py
|
|
178
|
-
tests/test_mcp_sigil_server_command.py
|
|
179
170
|
tests/test_message_command.py
|
|
180
171
|
tests/test_migrations.py
|
|
181
172
|
tests/test_model_verbose_name_capitalization.py
|
|
@@ -223,6 +214,7 @@ tests/test_role_marker_filtering.py
|
|
|
223
214
|
tests/test_seed_data.py
|
|
224
215
|
tests/test_send_invite_command.py
|
|
225
216
|
tests/test_settings_helpers.py
|
|
217
|
+
tests/test_settings_mcp_port.py
|
|
226
218
|
tests/test_shell_scripts.py
|
|
227
219
|
tests/test_show_leads_command.py
|
|
228
220
|
tests/test_sigil_builder.py
|
|
@@ -45,14 +45,13 @@ kombu==5.5.4
|
|
|
45
45
|
libipld==3.1.1
|
|
46
46
|
Markdown==3.8.2
|
|
47
47
|
mdx_truly_sane_lists==1.3
|
|
48
|
-
mcp==1.18.0
|
|
49
48
|
outcome==1.3.0.post0
|
|
50
49
|
packaging==25.0
|
|
51
50
|
pillow==11.3.0
|
|
52
51
|
prompt_toolkit==3.0.51
|
|
53
52
|
psutil==7.1.1
|
|
54
53
|
psycopg==3.2.9
|
|
55
|
-
psycopg-binary==3.2.
|
|
54
|
+
psycopg-binary==3.2.12
|
|
56
55
|
pyasn1==0.6.1
|
|
57
56
|
pyasn1_modules==0.4.2
|
|
58
57
|
pycparser==2.22
|
|
@@ -95,7 +94,7 @@ websocket-client==1.8.0
|
|
|
95
94
|
websockets==13.1
|
|
96
95
|
whitenoise==6.11.0
|
|
97
96
|
wsproto==1.2.0
|
|
98
|
-
zope.interface==
|
|
97
|
+
zope.interface==8.0.1
|
|
99
98
|
|
|
100
99
|
[:sys_platform == "linux"]
|
|
101
100
|
gpiozero==2.0.1
|
|
@@ -9,35 +9,21 @@ https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/
|
|
|
9
9
|
|
|
10
10
|
import os
|
|
11
11
|
from config.loadenv import loadenv
|
|
12
|
-
from typing import Any, Awaitable, Callable, Dict, MutableMapping
|
|
13
12
|
from channels.auth import AuthMiddlewareStack
|
|
14
13
|
from channels.routing import ProtocolTypeRouter, URLRouter
|
|
15
14
|
from django.core.asgi import get_asgi_application
|
|
16
15
|
import ocpp.routing
|
|
17
16
|
|
|
18
|
-
from core.mcp.asgi import application as mcp_application
|
|
19
|
-
from core.mcp.asgi import is_mcp_scope
|
|
20
|
-
|
|
21
17
|
loadenv()
|
|
22
18
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
|
23
19
|
|
|
24
20
|
django_asgi_app = get_asgi_application()
|
|
25
21
|
|
|
26
|
-
Scope = MutableMapping[str, Any]
|
|
27
|
-
Receive = Callable[[], Awaitable[Dict[str, Any]]]
|
|
28
|
-
Send = Callable[[Dict[str, Any]], Awaitable[None]]
|
|
29
|
-
|
|
30
22
|
websocket_patterns = ocpp.routing.websocket_urlpatterns
|
|
31
23
|
|
|
32
|
-
async def http_application(scope: Scope, receive: Receive, send: Send) -> None:
|
|
33
|
-
if is_mcp_scope(scope):
|
|
34
|
-
await mcp_application(scope, receive, send)
|
|
35
|
-
else:
|
|
36
|
-
await django_asgi_app(scope, receive, send)
|
|
37
|
-
|
|
38
24
|
application = ProtocolTypeRouter(
|
|
39
25
|
{
|
|
40
|
-
"http":
|
|
26
|
+
"http": django_asgi_app,
|
|
41
27
|
"websocket": AuthMiddlewareStack(URLRouter(websocket_patterns)),
|
|
42
28
|
}
|
|
43
29
|
)
|
|
@@ -444,32 +444,6 @@ ASGI_APPLICATION = "config.asgi.application"
|
|
|
444
444
|
CHANNEL_LAYERS = {"default": {"BACKEND": "channels.layers.InMemoryChannelLayer"}}
|
|
445
445
|
|
|
446
446
|
|
|
447
|
-
# MCP sigil resolver configuration
|
|
448
|
-
def _env_int(name: str, default: int) -> int:
|
|
449
|
-
try:
|
|
450
|
-
return int(os.environ.get(name, default))
|
|
451
|
-
except (TypeError, ValueError): # pragma: no cover - defensive
|
|
452
|
-
return default
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
def _split_env_list(name: str) -> list[str]:
|
|
456
|
-
raw = os.environ.get(name)
|
|
457
|
-
if not raw:
|
|
458
|
-
return []
|
|
459
|
-
return [item.strip() for item in raw.split(",") if item.strip()]
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
MCP_SIGIL_SERVER = {
|
|
463
|
-
"host": os.environ.get("MCP_SIGIL_HOST", "127.0.0.1"),
|
|
464
|
-
"port": _env_int("MCP_SIGIL_PORT", 8800),
|
|
465
|
-
"api_keys": _split_env_list("MCP_SIGIL_API_KEYS"),
|
|
466
|
-
"required_scopes": ["sigils:read"],
|
|
467
|
-
"issuer_url": os.environ.get("MCP_SIGIL_ISSUER_URL"),
|
|
468
|
-
"resource_server_url": os.environ.get("MCP_SIGIL_RESOURCE_URL"),
|
|
469
|
-
"mount_path": os.environ.get("MCP_SIGIL_MOUNT_PATH", "/mcp"),
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
|
|
473
447
|
# Custom user model
|
|
474
448
|
AUTH_USER_MODEL = "core.User"
|
|
475
449
|
|
|
@@ -91,9 +91,7 @@ from .models import (
|
|
|
91
91
|
SecurityGroup,
|
|
92
92
|
InviteLead,
|
|
93
93
|
PublicWifiAccess,
|
|
94
|
-
AssistantProfile,
|
|
95
94
|
Todo,
|
|
96
|
-
hash_key,
|
|
97
95
|
)
|
|
98
96
|
from .user_data import (
|
|
99
97
|
EntityModelAdmin,
|
|
@@ -110,8 +108,6 @@ from .rfid_import_export import (
|
|
|
110
108
|
parse_accounts,
|
|
111
109
|
serialize_accounts,
|
|
112
110
|
)
|
|
113
|
-
from .mcp import process as mcp_process
|
|
114
|
-
from .mcp.server import resolve_base_urls
|
|
115
111
|
from . import release as release_utils
|
|
116
112
|
|
|
117
113
|
logger = logging.getLogger(__name__)
|
|
@@ -1304,46 +1300,6 @@ class ReleaseManagerInlineForm(ProfileFormMixin, forms.ModelForm):
|
|
|
1304
1300
|
}
|
|
1305
1301
|
|
|
1306
1302
|
|
|
1307
|
-
class AssistantProfileInlineForm(ProfileFormMixin, forms.ModelForm):
|
|
1308
|
-
user_key = forms.CharField(
|
|
1309
|
-
required=False,
|
|
1310
|
-
widget=forms.PasswordInput(render_value=True),
|
|
1311
|
-
help_text="Provide a plain key to create or rotate credentials.",
|
|
1312
|
-
)
|
|
1313
|
-
profile_fields = ("assistant_name", "user_key", "scopes", "is_active")
|
|
1314
|
-
|
|
1315
|
-
class Meta:
|
|
1316
|
-
model = AssistantProfile
|
|
1317
|
-
fields = ("assistant_name", "scopes", "is_active")
|
|
1318
|
-
|
|
1319
|
-
def __init__(self, *args, **kwargs):
|
|
1320
|
-
super().__init__(*args, **kwargs)
|
|
1321
|
-
if not self.instance.pk and "is_active" in self.fields:
|
|
1322
|
-
self.fields["is_active"].initial = False
|
|
1323
|
-
|
|
1324
|
-
def clean(self):
|
|
1325
|
-
cleaned = super().clean()
|
|
1326
|
-
if cleaned.get("DELETE"):
|
|
1327
|
-
return cleaned
|
|
1328
|
-
if not self.instance.pk and not cleaned.get("user_key"):
|
|
1329
|
-
if cleaned.get("scopes") or cleaned.get("is_active"):
|
|
1330
|
-
raise forms.ValidationError(
|
|
1331
|
-
"Provide a user key to create an assistant profile."
|
|
1332
|
-
)
|
|
1333
|
-
return cleaned
|
|
1334
|
-
|
|
1335
|
-
def save(self, commit=True):
|
|
1336
|
-
instance = super().save(commit=False)
|
|
1337
|
-
user_key = self.cleaned_data.get("user_key")
|
|
1338
|
-
if user_key:
|
|
1339
|
-
instance.user_key_hash = hash_key(user_key)
|
|
1340
|
-
instance.last_used_at = None
|
|
1341
|
-
if commit:
|
|
1342
|
-
instance.save()
|
|
1343
|
-
self.save_m2m()
|
|
1344
|
-
return instance
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
1303
|
PROFILE_INLINE_CONFIG = {
|
|
1348
1304
|
OdooProfile: {
|
|
1349
1305
|
"form": OdooProfileInlineForm,
|
|
@@ -1474,12 +1430,6 @@ PROFILE_INLINE_CONFIG = {
|
|
|
1474
1430
|
"secondary_pypi_url",
|
|
1475
1431
|
),
|
|
1476
1432
|
},
|
|
1477
|
-
AssistantProfile: {
|
|
1478
|
-
"form": AssistantProfileInlineForm,
|
|
1479
|
-
"fields": ("assistant_name", "user_key", "scopes", "is_active"),
|
|
1480
|
-
"readonly_fields": ("user_key_hash", "created_at", "last_used_at"),
|
|
1481
|
-
"template": "admin/edit_inline/profile_stacked.html",
|
|
1482
|
-
},
|
|
1483
1433
|
}
|
|
1484
1434
|
|
|
1485
1435
|
|
|
@@ -1526,7 +1476,6 @@ PROFILE_MODELS = (
|
|
|
1526
1476
|
EmailOutbox,
|
|
1527
1477
|
SocialProfile,
|
|
1528
1478
|
ReleaseManager,
|
|
1529
|
-
AssistantProfile,
|
|
1530
1479
|
)
|
|
1531
1480
|
USER_PROFILE_INLINES = [
|
|
1532
1481
|
_build_profile_inline(model, "user") for model in PROFILE_MODELS
|
|
@@ -2013,188 +1962,6 @@ class EmailInboxAdmin(ProfileAdminMixin, SaveBeforeChangeAction, EntityModelAdmi
|
|
|
2013
1962
|
return TemplateResponse(request, "admin/core/emailinbox/search.html", context)
|
|
2014
1963
|
|
|
2015
1964
|
|
|
2016
|
-
@admin.register(AssistantProfile)
|
|
2017
|
-
class AssistantProfileAdmin(
|
|
2018
|
-
ProfileAdminMixin, SaveBeforeChangeAction, EntityModelAdmin
|
|
2019
|
-
):
|
|
2020
|
-
list_display = ("assistant_name", "owner", "created_at", "last_used_at", "is_active")
|
|
2021
|
-
readonly_fields = ("user_key_hash", "created_at", "last_used_at")
|
|
2022
|
-
|
|
2023
|
-
change_form_template = "admin/workgroupassistantprofile_change_form.html"
|
|
2024
|
-
change_list_template = "admin/assistantprofile_change_list.html"
|
|
2025
|
-
change_actions = ["my_profile_action"]
|
|
2026
|
-
changelist_actions = ["my_profile"]
|
|
2027
|
-
fieldsets = (
|
|
2028
|
-
("Owner", {"fields": ("user", "group")}),
|
|
2029
|
-
("Credentials", {"fields": ("user_key_hash",)}),
|
|
2030
|
-
(
|
|
2031
|
-
"Configuration",
|
|
2032
|
-
{
|
|
2033
|
-
"fields": (
|
|
2034
|
-
"assistant_name",
|
|
2035
|
-
"scopes",
|
|
2036
|
-
"is_active",
|
|
2037
|
-
"created_at",
|
|
2038
|
-
"last_used_at",
|
|
2039
|
-
)
|
|
2040
|
-
},
|
|
2041
|
-
),
|
|
2042
|
-
)
|
|
2043
|
-
|
|
2044
|
-
def owner(self, obj):
|
|
2045
|
-
return obj.owner_display()
|
|
2046
|
-
|
|
2047
|
-
owner.short_description = "Owner"
|
|
2048
|
-
|
|
2049
|
-
def get_urls(self):
|
|
2050
|
-
urls = super().get_urls()
|
|
2051
|
-
opts = self.model._meta
|
|
2052
|
-
app_label = opts.app_label
|
|
2053
|
-
model_name = opts.model_name
|
|
2054
|
-
custom = [
|
|
2055
|
-
path(
|
|
2056
|
-
"<path:object_id>/generate-key/",
|
|
2057
|
-
self.admin_site.admin_view(self.generate_key),
|
|
2058
|
-
name=f"{app_label}_{model_name}_generate_key",
|
|
2059
|
-
),
|
|
2060
|
-
path(
|
|
2061
|
-
"server/start/",
|
|
2062
|
-
self.admin_site.admin_view(self.start_server),
|
|
2063
|
-
name=f"{app_label}_{model_name}_start_server",
|
|
2064
|
-
),
|
|
2065
|
-
path(
|
|
2066
|
-
"server/stop/",
|
|
2067
|
-
self.admin_site.admin_view(self.stop_server),
|
|
2068
|
-
name=f"{app_label}_{model_name}_stop_server",
|
|
2069
|
-
),
|
|
2070
|
-
path(
|
|
2071
|
-
"server/status/",
|
|
2072
|
-
self.admin_site.admin_view(self.server_status),
|
|
2073
|
-
name=f"{app_label}_{model_name}_status",
|
|
2074
|
-
),
|
|
2075
|
-
]
|
|
2076
|
-
return custom + urls
|
|
2077
|
-
|
|
2078
|
-
def changelist_view(self, request, extra_context=None):
|
|
2079
|
-
extra_context = extra_context or {}
|
|
2080
|
-
status = mcp_process.get_status()
|
|
2081
|
-
opts = self.model._meta
|
|
2082
|
-
app_label = opts.app_label
|
|
2083
|
-
model_name = opts.model_name
|
|
2084
|
-
extra_context.update(
|
|
2085
|
-
{
|
|
2086
|
-
"mcp_status": status,
|
|
2087
|
-
"mcp_server_actions": {
|
|
2088
|
-
"start": reverse(f"admin:{app_label}_{model_name}_start_server"),
|
|
2089
|
-
"stop": reverse(f"admin:{app_label}_{model_name}_stop_server"),
|
|
2090
|
-
"status": reverse(f"admin:{app_label}_{model_name}_status"),
|
|
2091
|
-
},
|
|
2092
|
-
}
|
|
2093
|
-
)
|
|
2094
|
-
return super().changelist_view(request, extra_context=extra_context)
|
|
2095
|
-
|
|
2096
|
-
def _redirect_to_changelist(self):
|
|
2097
|
-
opts = self.model._meta
|
|
2098
|
-
return HttpResponseRedirect(
|
|
2099
|
-
reverse(f"admin:{opts.app_label}_{opts.model_name}_changelist")
|
|
2100
|
-
)
|
|
2101
|
-
|
|
2102
|
-
def generate_key(self, request, object_id, *args, **kwargs):
|
|
2103
|
-
profile = self.get_object(request, object_id)
|
|
2104
|
-
if profile is None:
|
|
2105
|
-
return HttpResponseRedirect("../")
|
|
2106
|
-
if profile.user is None:
|
|
2107
|
-
self.message_user(
|
|
2108
|
-
request,
|
|
2109
|
-
"Assign a user before generating a key.",
|
|
2110
|
-
level=messages.ERROR,
|
|
2111
|
-
)
|
|
2112
|
-
return HttpResponseRedirect("../")
|
|
2113
|
-
profile, key = AssistantProfile.issue_key(profile.user)
|
|
2114
|
-
context = {
|
|
2115
|
-
**self.admin_site.each_context(request),
|
|
2116
|
-
"opts": self.model._meta,
|
|
2117
|
-
"original": profile,
|
|
2118
|
-
"user_key": key,
|
|
2119
|
-
}
|
|
2120
|
-
return TemplateResponse(request, "admin/assistantprofile_key.html", context)
|
|
2121
|
-
|
|
2122
|
-
def render_change_form(
|
|
2123
|
-
self, request, context, add=False, change=False, form_url="", obj=None
|
|
2124
|
-
):
|
|
2125
|
-
response = super().render_change_form(
|
|
2126
|
-
request, context, add=add, change=change, form_url=form_url, obj=obj
|
|
2127
|
-
)
|
|
2128
|
-
config = dict(getattr(settings, "MCP_SIGIL_SERVER", {}))
|
|
2129
|
-
host = config.get("host") or "127.0.0.1"
|
|
2130
|
-
port = config.get("port", 8800)
|
|
2131
|
-
base_url, issuer_url = resolve_base_urls(config)
|
|
2132
|
-
mount_path = config.get("mount_path") or "/"
|
|
2133
|
-
display_base_url = base_url or f"http://{host}:{port}"
|
|
2134
|
-
display_issuer_url = issuer_url or display_base_url
|
|
2135
|
-
chat_endpoint = f"{display_base_url.rstrip('/')}/api/chat/"
|
|
2136
|
-
if isinstance(response, dict):
|
|
2137
|
-
response.setdefault("mcp_server_host", host)
|
|
2138
|
-
response.setdefault("mcp_server_port", port)
|
|
2139
|
-
response.setdefault("mcp_server_base_url", display_base_url)
|
|
2140
|
-
response.setdefault("mcp_server_issuer_url", display_issuer_url)
|
|
2141
|
-
response.setdefault("mcp_server_mount_path", mount_path)
|
|
2142
|
-
response.setdefault("mcp_server_chat_endpoint", chat_endpoint)
|
|
2143
|
-
else:
|
|
2144
|
-
context_data = getattr(response, "context_data", None)
|
|
2145
|
-
if context_data is not None:
|
|
2146
|
-
context_data.setdefault("mcp_server_host", host)
|
|
2147
|
-
context_data.setdefault("mcp_server_port", port)
|
|
2148
|
-
context_data.setdefault("mcp_server_base_url", display_base_url)
|
|
2149
|
-
context_data.setdefault("mcp_server_issuer_url", display_issuer_url)
|
|
2150
|
-
context_data.setdefault("mcp_server_mount_path", mount_path)
|
|
2151
|
-
context_data.setdefault("mcp_server_chat_endpoint", chat_endpoint)
|
|
2152
|
-
return response
|
|
2153
|
-
|
|
2154
|
-
def start_server(self, request):
|
|
2155
|
-
try:
|
|
2156
|
-
pid = mcp_process.start_server()
|
|
2157
|
-
except mcp_process.ServerAlreadyRunningError as exc:
|
|
2158
|
-
self.message_user(request, str(exc), level=messages.WARNING)
|
|
2159
|
-
except mcp_process.ServerStartError as exc:
|
|
2160
|
-
self.message_user(request, str(exc), level=messages.ERROR)
|
|
2161
|
-
else:
|
|
2162
|
-
self.message_user(
|
|
2163
|
-
request,
|
|
2164
|
-
f"Started MCP server (PID {pid}).",
|
|
2165
|
-
level=messages.SUCCESS,
|
|
2166
|
-
)
|
|
2167
|
-
return self._redirect_to_changelist()
|
|
2168
|
-
|
|
2169
|
-
def stop_server(self, request):
|
|
2170
|
-
try:
|
|
2171
|
-
pid = mcp_process.stop_server()
|
|
2172
|
-
except mcp_process.ServerNotRunningError as exc:
|
|
2173
|
-
self.message_user(request, str(exc), level=messages.WARNING)
|
|
2174
|
-
except mcp_process.ServerStopError as exc:
|
|
2175
|
-
self.message_user(request, str(exc), level=messages.ERROR)
|
|
2176
|
-
else:
|
|
2177
|
-
self.message_user(
|
|
2178
|
-
request,
|
|
2179
|
-
f"Stopped MCP server (PID {pid}).",
|
|
2180
|
-
level=messages.SUCCESS,
|
|
2181
|
-
)
|
|
2182
|
-
return self._redirect_to_changelist()
|
|
2183
|
-
|
|
2184
|
-
def server_status(self, request):
|
|
2185
|
-
status = mcp_process.get_status()
|
|
2186
|
-
if status["running"]:
|
|
2187
|
-
msg = f"MCP server is running (PID {status['pid']})."
|
|
2188
|
-
level = messages.INFO
|
|
2189
|
-
else:
|
|
2190
|
-
msg = "MCP server is not running."
|
|
2191
|
-
level = messages.WARNING
|
|
2192
|
-
if status.get("last_error"):
|
|
2193
|
-
msg = f"{msg} {status['last_error']}"
|
|
2194
|
-
self.message_user(request, msg, level=level)
|
|
2195
|
-
return self._redirect_to_changelist()
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
1965
|
class EnergyCreditInline(admin.TabularInline):
|
|
2199
1966
|
model = EnergyCredit
|
|
2200
1967
|
fields = ("amount_kw", "created_by", "created_on")
|
|
@@ -3690,6 +3457,7 @@ class RFIDAdmin(EntityModelAdmin, ImportExportModelAdmin):
|
|
|
3690
3457
|
"toggle_url": toggle_url,
|
|
3691
3458
|
"toggle_label": toggle_label,
|
|
3692
3459
|
"public_view_url": public_view_url,
|
|
3460
|
+
"deep_read_url": reverse("rfid-scan-deep"),
|
|
3693
3461
|
}
|
|
3694
3462
|
)
|
|
3695
3463
|
context["title"] = _("Scan RFIDs")
|
|
@@ -348,9 +348,3 @@ class CoreConfig(AppConfig):
|
|
|
348
348
|
weak=False,
|
|
349
349
|
)
|
|
350
350
|
|
|
351
|
-
try:
|
|
352
|
-
from .mcp.auto_start import schedule_auto_start
|
|
353
|
-
|
|
354
|
-
schedule_auto_start(check_profiles_immediately=False)
|
|
355
|
-
except Exception: # pragma: no cover - defensive
|
|
356
|
-
logger.exception("Failed to schedule MCP auto-start")
|
|
@@ -71,7 +71,7 @@ class NetworkSetupForm(forms.Form):
|
|
|
71
71
|
ethernet_subnet = forms.CharField(
|
|
72
72
|
label=_("Ethernet subnet"),
|
|
73
73
|
required=False,
|
|
74
|
-
help_text=_("Provide
|
|
74
|
+
help_text=_("Provide Z, Z/P (prefix 16 or 24), X.Y.Z, or X.Y.Z/P to supply --subnet."),
|
|
75
75
|
)
|
|
76
76
|
update_ap_password_only = forms.BooleanField(
|
|
77
77
|
label=_("Update access point password only"),
|
|
@@ -84,16 +84,35 @@ class NetworkSetupForm(forms.Form):
|
|
|
84
84
|
if not value:
|
|
85
85
|
return ""
|
|
86
86
|
raw = value.strip()
|
|
87
|
-
match = re.fullmatch(
|
|
87
|
+
match = re.fullmatch(
|
|
88
|
+
r"(?P<first>\d{1,3})(?:\.(?P<second>\d{1,3})\.(?P<third>\d{1,3}))?(?:/(?P<prefix>\d{1,2}))?",
|
|
89
|
+
raw,
|
|
90
|
+
)
|
|
88
91
|
if not match:
|
|
89
92
|
raise forms.ValidationError(
|
|
90
|
-
_("Enter a subnet in the form
|
|
91
|
-
)
|
|
92
|
-
subnet = int(match.group("subnet"))
|
|
93
|
-
if subnet < 0 or subnet > 254:
|
|
94
|
-
raise forms.ValidationError(
|
|
95
|
-
_("Subnet value must be between 0 and 254."),
|
|
93
|
+
_("Enter a subnet in the form Z, Z/P, X.Y.Z, or X.Y.Z/P with prefix 16 or 24."),
|
|
96
94
|
)
|
|
95
|
+
first_octet = int(match.group("first"))
|
|
96
|
+
second = match.group("second")
|
|
97
|
+
third = match.group("third")
|
|
98
|
+
if second is not None and third is not None:
|
|
99
|
+
octets = [first_octet, int(second), int(third)]
|
|
100
|
+
for octet in octets:
|
|
101
|
+
if octet < 0 or octet > 255:
|
|
102
|
+
raise forms.ValidationError(
|
|
103
|
+
_("Subnet octets must be between 0 and 255."),
|
|
104
|
+
)
|
|
105
|
+
if octets[2] > 254:
|
|
106
|
+
raise forms.ValidationError(
|
|
107
|
+
_("The third subnet octet must be between 0 and 254."),
|
|
108
|
+
)
|
|
109
|
+
subnet_value = ".".join(str(octet) for octet in octets)
|
|
110
|
+
else:
|
|
111
|
+
if first_octet < 0 or first_octet > 254:
|
|
112
|
+
raise forms.ValidationError(
|
|
113
|
+
_("Subnet value must be between 0 and 254."),
|
|
114
|
+
)
|
|
115
|
+
subnet_value = str(first_octet)
|
|
97
116
|
prefix_value = match.group("prefix")
|
|
98
117
|
if prefix_value:
|
|
99
118
|
prefix = int(prefix_value)
|
|
@@ -101,8 +120,8 @@ class NetworkSetupForm(forms.Form):
|
|
|
101
120
|
raise forms.ValidationError(
|
|
102
121
|
_("Subnet prefix must be 16 or 24."),
|
|
103
122
|
)
|
|
104
|
-
return f"{
|
|
105
|
-
return
|
|
123
|
+
return f"{subnet_value}/{prefix}"
|
|
124
|
+
return subnet_value
|
|
106
125
|
|
|
107
126
|
def clean(self) -> dict:
|
|
108
127
|
cleaned_data = super().clean()
|