howler-api 3.2.0.dev595__tar.gz → 3.2.0.dev599__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.
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/PKG-INFO +2 -2
- howler_api-3.2.0.dev599/howler/actions/add_to_bundle.py +159 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/actions/demote.py +2 -2
- howler_api-3.2.0.dev599/howler/actions/remove_from_bundle.py +133 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/actions/transition.py +5 -3
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/__init__.py +1 -2
- howler_api-3.2.0.dev595/howler/services/docs_service.py → howler_api-3.2.0.dev599/howler/api/v1/__init__.py +45 -37
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/action.py +2 -1
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/analytic.py +102 -17
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/hit.py +215 -11
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/tool.py +18 -1
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/user.py +1 -1
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/app.py +0 -10
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/loader.py +5 -4
- howler_api-3.2.0.dev599/howler/cronjobs/rules.py +274 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/collection.py +9 -8
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/howler_store.py +14 -29
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/store.py +1 -4
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/types.py +6 -1
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/helper/discover.py +7 -11
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/helper/hit.py +4 -4
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/helper/search.py +2 -12
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/base.py +12 -40
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/helper.py +5 -115
- howler_api-3.2.0.dev595/howler/odm/models/record.py → howler_api-3.2.0.dev599/howler/odm/models/hit.py +21 -1
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/howler_data.py +31 -3
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/random_data.py +45 -347
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/__init__.py +2 -3
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/queues/comms.py +1 -2
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/config_service.py +3 -3
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/hit_service.py +168 -90
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/pyproject.toml +3 -3
- howler_api-3.2.0.dev595/howler/api/v1/__init__.py +0 -44
- howler_api-3.2.0.dev595/howler/api/v2/__init__.py +0 -44
- howler_api-3.2.0.dev595/howler/api/v2/case.py +0 -286
- howler_api-3.2.0.dev595/howler/api/v2/ingest.py +0 -327
- howler_api-3.2.0.dev595/howler/api/v2/search.py +0 -341
- howler_api-3.2.0.dev595/howler/odm/constants.py +0 -20
- howler_api-3.2.0.dev595/howler/odm/models/case.py +0 -179
- howler_api-3.2.0.dev595/howler/odm/models/hit.py +0 -29
- howler_api-3.2.0.dev595/howler/odm/models/observable.py +0 -129
- howler_api-3.2.0.dev595/howler/services/case_service.py +0 -558
- howler_api-3.2.0.dev595/howler/services/observable_service.py +0 -128
- howler_api-3.2.0.dev595/howler/services/search_service.py +0 -225
- howler_api-3.2.0.dev595/howler/utils/compat.py +0 -21
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/README.md +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/actions/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/actions/add_label.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/actions/change_field.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/actions/example_plugin.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/actions/prioritization.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/actions/promote.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/actions/remove_label.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/base.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/socket.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/auth.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/clue.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/configs.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/dossier.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/help.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/notebook.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/overview.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/search.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/template.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/utils/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/utils/etag.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/api/v1/view.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/README.md +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/classification.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/classification.yml +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/exceptions.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/logging/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/logging/audit.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/logging/format.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/net.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/net_static.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/random_user.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/common/swagger.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/config.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/cronjobs/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/cronjobs/retention.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/cronjobs/view_cleanup.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/README.md +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/bulk.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/constants.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/exceptions.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/migrations/fix_process.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/operations.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/schemas.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/support/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/support/build.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/datastore/support/schemas.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/error.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/external/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/external/generate_mitre.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/external/generate_sigma_rules.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/external/generate_tlds.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/external/reindex_data.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/external/wipe_databases.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/gunicorn_config.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/healthz.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/helper/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/helper/azure.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/helper/oauth.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/helper/workflow.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/helper/ws.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/README.md +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/charter.txt +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/howler_enum.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/action.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/analytic.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/assemblyline.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/aws.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/azure.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/cbs.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/clue.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/config.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/dossier.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/agent.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/autonomous_system.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/client.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/cloud.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/code_signature.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/container.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/dns.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/egress.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/elf.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/email.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/error.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/event.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/faas.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/file.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/geo.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/group.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/hash.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/host.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/http.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/ingress.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/interface.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/network.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/observer.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/organization.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/os.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/pe.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/process.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/registry.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/related.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/rule.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/server.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/threat.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/tls.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/url.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/user.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/user_agent.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/ecs/vulnerability.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/gcp.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/lead.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/localized_label.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/overview.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/pivot.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/template.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/user.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/models/view.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/odm/randomizer.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/patched.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/plugins/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/plugins/config.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/README.md +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/counters.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/events.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/hash.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/lock.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/queues/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/queues/multi.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/queues/named.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/queues/priority.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/set.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/remote/datatypes/user_quota_tracker.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/security/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/security/socket.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/security/utils.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/action_service.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/analytic_service.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/auth_service.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/dossier_service.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/event_service.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/jwt_service.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/lucene_service.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/notebook_service.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/overview_service.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/template_service.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/services/user_service.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/utils/__init__.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/utils/annotations.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/utils/chunk.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/utils/dict_utils.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/utils/isotime.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/utils/list_utils.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/utils/lucene.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/utils/path.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/utils/socket_utils.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/utils/str_utils.py +0 -0
- {howler_api-3.2.0.dev595 → howler_api-3.2.0.dev599}/howler/utils/uid.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: howler-api
|
|
3
|
-
Version: 3.2.0.
|
|
3
|
+
Version: 3.2.0.dev599
|
|
4
4
|
Summary: Howler - API server
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
|
|
@@ -29,7 +29,7 @@ Requires-Dist: elasticsearch (==8.19.3)
|
|
|
29
29
|
Requires-Dist: flasgger (>=0.9.7.1,<0.10.0.0)
|
|
30
30
|
Requires-Dist: flask (==3.1.3)
|
|
31
31
|
Requires-Dist: flask-caching (==2.3.1)
|
|
32
|
-
Requires-Dist: gevent (
|
|
32
|
+
Requires-Dist: gevent (==23.9.1)
|
|
33
33
|
Requires-Dist: gunicorn (==23.0.0)
|
|
34
34
|
Requires-Dist: luqum (>=1.0.0,<2.0.0)
|
|
35
35
|
Requires-Dist: mergedeep (>=1.3.4,<2.0.0)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from howler.common.loader import datastore
|
|
4
|
+
from howler.datastore.operations import OdmHelper
|
|
5
|
+
from howler.odm.models.action import VALID_TRIGGERS
|
|
6
|
+
from howler.odm.models.hit import Hit
|
|
7
|
+
from howler.services import hit_service
|
|
8
|
+
from howler.utils.str_utils import sanitize_lucene_query
|
|
9
|
+
|
|
10
|
+
hit_helper = OdmHelper(Hit)
|
|
11
|
+
|
|
12
|
+
OPERATION_ID = "add_to_bundle"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def execute(query: str, bundle_id: Optional[str] = None, **kwargs):
|
|
16
|
+
"""Add a set of hits matching the query to the specified bundle.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
query (str): The query containing the matching hits
|
|
20
|
+
bundle_id (str): The `howler.id` of the bundle to add the hits to.
|
|
21
|
+
"""
|
|
22
|
+
report = []
|
|
23
|
+
|
|
24
|
+
if not bundle_id:
|
|
25
|
+
return [
|
|
26
|
+
{
|
|
27
|
+
"query": query,
|
|
28
|
+
"outcome": "error",
|
|
29
|
+
"title": "Invalid Bundle ID",
|
|
30
|
+
"message": "Bundle ID cannot be empty.",
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
bundle_hit = hit_service.get_hit(bundle_id, as_odm=True)
|
|
36
|
+
if not bundle_hit or not bundle_hit.howler.is_bundle:
|
|
37
|
+
report.append(
|
|
38
|
+
{
|
|
39
|
+
"query": query,
|
|
40
|
+
"outcome": "error",
|
|
41
|
+
"title": "Invalid Bundle",
|
|
42
|
+
"message": f"Either a hit with ID {bundle_id} does not exist, or it is not a bundle.",
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
return report
|
|
46
|
+
|
|
47
|
+
ds = datastore()
|
|
48
|
+
|
|
49
|
+
skipped_hits_bundles = ds.hit.search(
|
|
50
|
+
f"({query}) AND howler.is_bundle:true",
|
|
51
|
+
fl="howler.id",
|
|
52
|
+
)["items"]
|
|
53
|
+
|
|
54
|
+
if len(skipped_hits_bundles) > 0:
|
|
55
|
+
report.append(
|
|
56
|
+
{
|
|
57
|
+
"query": f"({query}) AND howler.is_bundle:true",
|
|
58
|
+
"outcome": "skipped",
|
|
59
|
+
"title": "Skipped Bundles",
|
|
60
|
+
"message": "Bundles cannot be added to a bundle.",
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
skipped_hits_already_added = ds.hit.search(
|
|
65
|
+
f"({query}) AND (howler.bundles:{sanitize_lucene_query(bundle_id)})",
|
|
66
|
+
fl="howler.id",
|
|
67
|
+
)["items"]
|
|
68
|
+
|
|
69
|
+
if len(skipped_hits_already_added) > 0:
|
|
70
|
+
report.append(
|
|
71
|
+
{
|
|
72
|
+
"query": f"({query}) AND (howler.bundles:{sanitize_lucene_query(bundle_id)})",
|
|
73
|
+
"outcome": "skipped",
|
|
74
|
+
"title": "Skipped Hits",
|
|
75
|
+
"message": "These hits have already been added to the specified bundle.",
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
safe_query = f"({query}) AND (-howler.bundles:({sanitize_lucene_query(bundle_id)}) AND howler.is_bundle:false)"
|
|
80
|
+
matching_hits = ds.hit.search(safe_query)["items"]
|
|
81
|
+
if len(matching_hits) < 1:
|
|
82
|
+
report.append(
|
|
83
|
+
{
|
|
84
|
+
"query": safe_query,
|
|
85
|
+
"outcome": "skipped",
|
|
86
|
+
"title": "No Matching Hits",
|
|
87
|
+
"message": "There were no hits matching this query.",
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
return report
|
|
91
|
+
|
|
92
|
+
ds.hit.update_by_query(
|
|
93
|
+
safe_query,
|
|
94
|
+
[hit_helper.list_add("howler.bundles", sanitize_lucene_query(bundle_id), if_missing=True)],
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
operations = [
|
|
98
|
+
hit_helper.list_add(
|
|
99
|
+
"howler.hits",
|
|
100
|
+
hit["howler"]["id"],
|
|
101
|
+
if_missing=True,
|
|
102
|
+
)
|
|
103
|
+
for hit in matching_hits
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
operations.append(hit_helper.update("howler.bundle_size", len(operations)))
|
|
107
|
+
hit_service.update_hit(
|
|
108
|
+
bundle_id,
|
|
109
|
+
operations,
|
|
110
|
+
)
|
|
111
|
+
bundle_hit = hit_service.get_hit(bundle_id, as_odm=True)
|
|
112
|
+
report.append(
|
|
113
|
+
{
|
|
114
|
+
"query": safe_query.replace("-howler.bundles", "howler.bundles"),
|
|
115
|
+
"outcome": "success",
|
|
116
|
+
"title": "Executed Successfully",
|
|
117
|
+
"message": "The specified bundle has had all matching hits added.",
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
except Exception as e:
|
|
121
|
+
report.append(
|
|
122
|
+
{
|
|
123
|
+
"query": query,
|
|
124
|
+
"outcome": "error",
|
|
125
|
+
"title": "Failed to Execute",
|
|
126
|
+
"message": f"Unknown exception occurred: {str(e)}",
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
return report
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def specification():
|
|
134
|
+
"""Specify various properties of the action, such as title, descriptions, permissions and input steps."""
|
|
135
|
+
return {
|
|
136
|
+
"id": OPERATION_ID,
|
|
137
|
+
"title": "Add to Bundle",
|
|
138
|
+
"priority": 6,
|
|
139
|
+
"i18nKey": f"operations.{OPERATION_ID}",
|
|
140
|
+
"description": {
|
|
141
|
+
"short": "Add a set of hits to a bundle",
|
|
142
|
+
"long": execute.__doc__,
|
|
143
|
+
},
|
|
144
|
+
"roles": ["automation_basic"],
|
|
145
|
+
"steps": [
|
|
146
|
+
{
|
|
147
|
+
"args": {"bundle_id": []},
|
|
148
|
+
"options": {},
|
|
149
|
+
"validation": {
|
|
150
|
+
"warn": {"query": "howler.bundles:($bundle_id) OR howler.is_bundle:true"},
|
|
151
|
+
"error": {
|
|
152
|
+
"query": "howler.id:$bundle_id AND howler.is_bundle:false",
|
|
153
|
+
"message": "The bundle id given must be a bundle.",
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
"triggers": VALID_TRIGGERS,
|
|
159
|
+
}
|
|
@@ -9,7 +9,7 @@ from howler.odm.models.howler_data import (
|
|
|
9
9
|
Assessment,
|
|
10
10
|
AssessmentEscalationMap,
|
|
11
11
|
Escalation,
|
|
12
|
-
|
|
12
|
+
HitStatus,
|
|
13
13
|
)
|
|
14
14
|
from howler.odm.models.user import User
|
|
15
15
|
from howler.utils.str_utils import sanitize_lucene_query
|
|
@@ -96,7 +96,7 @@ def execute(
|
|
|
96
96
|
"howler.assignment",
|
|
97
97
|
user.get("uname", "automation") if user else "automation",
|
|
98
98
|
),
|
|
99
|
-
odm_helper.update("howler.status",
|
|
99
|
+
odm_helper.update("howler.status", HitStatus.RESOLVED),
|
|
100
100
|
],
|
|
101
101
|
)
|
|
102
102
|
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from howler.common.exceptions import HowlerException
|
|
4
|
+
from howler.common.loader import datastore
|
|
5
|
+
from howler.datastore.operations import OdmHelper
|
|
6
|
+
from howler.odm.models.action import VALID_TRIGGERS
|
|
7
|
+
from howler.odm.models.hit import Hit
|
|
8
|
+
from howler.services import hit_service
|
|
9
|
+
from howler.utils.str_utils import sanitize_lucene_query
|
|
10
|
+
|
|
11
|
+
hit_helper = OdmHelper(Hit)
|
|
12
|
+
|
|
13
|
+
OPERATION_ID = "remove_from_bundle"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def execute(query: str, bundle_id: Optional[str] = None, **kwargs):
|
|
17
|
+
"""Remove a set of hits matching the query from the specified bundle.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
query (str): The query containing the matching hits
|
|
21
|
+
bundle_id (str): The `howler.id` of the bundle to remove the hits from.
|
|
22
|
+
"""
|
|
23
|
+
report = []
|
|
24
|
+
|
|
25
|
+
if not bundle_id:
|
|
26
|
+
return [
|
|
27
|
+
{
|
|
28
|
+
"query": query,
|
|
29
|
+
"outcome": "error",
|
|
30
|
+
"title": "Invalid Bundle ID",
|
|
31
|
+
"message": "Bundle ID cannot be empty.",
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
bundle_hit = hit_service.get_hit(bundle_id, as_odm=True)
|
|
37
|
+
if not bundle_hit or not bundle_hit.howler.is_bundle:
|
|
38
|
+
report.append(
|
|
39
|
+
{
|
|
40
|
+
"query": query,
|
|
41
|
+
"outcome": "error",
|
|
42
|
+
"title": "Invalid Bundle",
|
|
43
|
+
"message": f"Either a hit with ID {bundle_id} does not exist, or it is not a bundle.",
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
return report
|
|
47
|
+
|
|
48
|
+
ds = datastore()
|
|
49
|
+
|
|
50
|
+
skipped_hits = ds.hit.search(
|
|
51
|
+
f"({query}) AND -howler.bundles:{sanitize_lucene_query(bundle_id)}",
|
|
52
|
+
fl="howler.id",
|
|
53
|
+
)["items"]
|
|
54
|
+
|
|
55
|
+
if len(skipped_hits) > 0:
|
|
56
|
+
report.append(
|
|
57
|
+
{
|
|
58
|
+
"query": f"howler.id:({' OR '.join(h.howler.id for h in skipped_hits)})",
|
|
59
|
+
"outcome": "skipped",
|
|
60
|
+
"title": "Skipped Hit not in Bundle",
|
|
61
|
+
"message": "These hits already are not in the bundle.",
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
safe_query = f"{query} AND (howler.bundles:{bundle_id})"
|
|
66
|
+
|
|
67
|
+
matching_hits = ds.hit.search(safe_query)["items"]
|
|
68
|
+
if len(matching_hits) < 1:
|
|
69
|
+
report.append(
|
|
70
|
+
{
|
|
71
|
+
"query": safe_query,
|
|
72
|
+
"outcome": "skipped",
|
|
73
|
+
"title": "No Matching Hits",
|
|
74
|
+
"message": "There were no hits matching this query.",
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
return report
|
|
78
|
+
|
|
79
|
+
ds.hit.update_by_query(
|
|
80
|
+
safe_query,
|
|
81
|
+
[hit_helper.list_remove("howler.bundles", bundle_id)],
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
hit_service.update_hit(
|
|
85
|
+
bundle_id,
|
|
86
|
+
[hit_helper.list_remove("howler.hits", h["howler"]["id"]) for h in ds.hit.search(safe_query)["items"]],
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
if len(ds.hit.get(bundle_id).howler.hits) < 1:
|
|
90
|
+
hit_service.update_hit(bundle_id, [hit_helper.update("howler.is_bundle", False)])
|
|
91
|
+
|
|
92
|
+
report.append(
|
|
93
|
+
{
|
|
94
|
+
"query": query,
|
|
95
|
+
"outcome": "success",
|
|
96
|
+
"title": "Executed Successfully",
|
|
97
|
+
"message": f"Matching hits removed from bundle with id {bundle_id}",
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
except HowlerException as e:
|
|
101
|
+
report.append(
|
|
102
|
+
{
|
|
103
|
+
"query": query,
|
|
104
|
+
"outcome": "error",
|
|
105
|
+
"title": "Failed to Execute",
|
|
106
|
+
"message": f"Unknown exception occurred: {str(e)}",
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
return report
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def specification():
|
|
114
|
+
"""Specify various properties of the action, such as title, descriptions, permissions and input steps."""
|
|
115
|
+
return {
|
|
116
|
+
"id": OPERATION_ID,
|
|
117
|
+
"title": "Remove from Bundle",
|
|
118
|
+
"priority": 5,
|
|
119
|
+
"i18nKey": f"operations.{OPERATION_ID}",
|
|
120
|
+
"description": {
|
|
121
|
+
"short": "Remove a set of hits from a bundle",
|
|
122
|
+
"long": execute.__doc__,
|
|
123
|
+
},
|
|
124
|
+
"roles": ["automation_basic"],
|
|
125
|
+
"steps": [
|
|
126
|
+
{
|
|
127
|
+
"args": {"bundle_id": []},
|
|
128
|
+
"options": {},
|
|
129
|
+
"validation": {"error": {"query": "-howler.bundles:$bundle_id"}},
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
"triggers": VALID_TRIGGERS,
|
|
133
|
+
}
|
|
@@ -8,8 +8,8 @@ from howler.helper.workflow import Workflow, WorkflowException
|
|
|
8
8
|
from howler.odm.models.action import VALID_TRIGGERS
|
|
9
9
|
from howler.odm.models.howler_data import (
|
|
10
10
|
Assessment,
|
|
11
|
+
HitStatus,
|
|
11
12
|
HitStatusTransition,
|
|
12
|
-
Status,
|
|
13
13
|
Vote,
|
|
14
14
|
)
|
|
15
15
|
from howler.odm.models.user import User
|
|
@@ -180,13 +180,15 @@ def specification():
|
|
|
180
180
|
"steps": [
|
|
181
181
|
{
|
|
182
182
|
"args": {"status": []},
|
|
183
|
-
"options": {"status":
|
|
183
|
+
"options": {"status": HitStatus.list()},
|
|
184
184
|
"validation": {"error": {"query": "-howler.status:$status"}},
|
|
185
185
|
},
|
|
186
186
|
{
|
|
187
187
|
"args": {"transition": []},
|
|
188
188
|
"options": {
|
|
189
|
-
"transition": {
|
|
189
|
+
"transition": {
|
|
190
|
+
f"status:{status}": hit_service.get_transitions(status) for status in HitStatus.list()
|
|
191
|
+
},
|
|
190
192
|
},
|
|
191
193
|
},
|
|
192
194
|
{
|
|
@@ -24,8 +24,7 @@ logger = get_logger(__file__)
|
|
|
24
24
|
|
|
25
25
|
def make_subapi_blueprint(name, api_version=1):
|
|
26
26
|
"""Create a flask Blueprint for a subapi in a standard way."""
|
|
27
|
-
|
|
28
|
-
return Blueprint(full_name, full_name, url_prefix="/".join([API_PREFIX, f"v{api_version}", name]))
|
|
27
|
+
return Blueprint(name, name, url_prefix="/".join([API_PREFIX, f"v{api_version}", name]))
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
def _make_api_response(
|
|
@@ -1,39 +1,47 @@
|
|
|
1
1
|
from textwrap import dedent
|
|
2
2
|
|
|
3
|
-
from flask import current_app, request
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
3
|
+
from flask import Blueprint, current_app, request
|
|
4
|
+
|
|
5
|
+
from howler.api import ok
|
|
6
|
+
from howler.security import api_login
|
|
7
|
+
|
|
8
|
+
API_PREFIX = "/api/v1"
|
|
9
|
+
apiv1 = Blueprint("apiv1", __name__, url_prefix=API_PREFIX)
|
|
10
|
+
apiv1._doc = "Api Documentation Version 1" # type: ignore[attr-defined] # type: ignore
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@apiv1.route("/")
|
|
14
|
+
@api_login(audit=False, required_priv=["R", "W"], required_type=["user", "admin"])
|
|
15
|
+
def get_api_documentation(**kwargs):
|
|
16
|
+
"""Full API doc.
|
|
17
|
+
|
|
18
|
+
Loop through all registered API paths and display their documentation.
|
|
19
|
+
Returns a list of API definition.
|
|
20
|
+
|
|
21
|
+
Variables:
|
|
22
|
+
None
|
|
23
|
+
|
|
24
|
+
Arguments:
|
|
25
|
+
None
|
|
26
|
+
|
|
27
|
+
Result Example:
|
|
28
|
+
[
|
|
29
|
+
{
|
|
30
|
+
'name': "Api Doc", # Name of the api
|
|
31
|
+
'path': "/api/path/<variable>/", # API path
|
|
32
|
+
'ui_only': false, # Is UI only API
|
|
33
|
+
'methods': ["GET", "POST"], # Allowed HTTP methods
|
|
34
|
+
'description': "API doc.", # API documentation
|
|
35
|
+
'id': "api_doc", # Unique ID for the API
|
|
36
|
+
'function': "apiv1.api_doc", # Function called in the code
|
|
37
|
+
'protected': False, # Does the API require login?
|
|
38
|
+
'required_type': ['user'], # Type of users allowed to use API
|
|
39
|
+
'complete' : True # Is the API stable?
|
|
40
|
+
},
|
|
41
|
+
]
|
|
36
42
|
"""
|
|
43
|
+
user_types = kwargs["user"]["type"]
|
|
44
|
+
|
|
37
45
|
api_blueprints = {}
|
|
38
46
|
api_list = []
|
|
39
47
|
for rule in current_app.url_map.iter_rules():
|
|
@@ -50,7 +58,7 @@ def build_route_docs(version: str, user_types: list[str]):
|
|
|
50
58
|
[x.capitalize() for x in rule.endpoint[rule.endpoint.rindex(".") + 1 :].split("_")]
|
|
51
59
|
)
|
|
52
60
|
blueprint = rule.endpoint[: rule.endpoint.rindex(".")]
|
|
53
|
-
if blueprint ==
|
|
61
|
+
if blueprint == "apiv1":
|
|
54
62
|
blueprint = "documentation"
|
|
55
63
|
|
|
56
64
|
if blueprint not in api_blueprints:
|
|
@@ -66,7 +74,7 @@ def build_route_docs(version: str, user_types: list[str]):
|
|
|
66
74
|
else:
|
|
67
75
|
description = "[INCOMPLETE]\n\nTHIS API HAS NOT BEEN DOCUMENTED YET!"
|
|
68
76
|
|
|
69
|
-
api_id = rule.endpoint.replace(
|
|
77
|
+
api_id = rule.endpoint.replace("apiv1.", "").replace(".", "_")
|
|
70
78
|
|
|
71
79
|
api_list.append(
|
|
72
80
|
{
|
|
@@ -74,7 +82,7 @@ def build_route_docs(version: str, user_types: list[str]):
|
|
|
74
82
|
"required_type": sorted(required_type),
|
|
75
83
|
"name": func_title,
|
|
76
84
|
"id": api_id,
|
|
77
|
-
"function": f"api.
|
|
85
|
+
"function": f"api.v1.{rule.endpoint}",
|
|
78
86
|
"path": rule.rule,
|
|
79
87
|
"ui_only": rule.rule.startswith("%sui/" % request.path),
|
|
80
88
|
"methods": sorted(methods),
|
|
@@ -86,4 +94,4 @@ def build_route_docs(version: str, user_types: list[str]):
|
|
|
86
94
|
|
|
87
95
|
break
|
|
88
96
|
|
|
89
|
-
return {"apis": api_list, "blueprints": api_blueprints}
|
|
97
|
+
return ok({"apis": api_list, "blueprints": api_blueprints})
|
|
@@ -231,7 +231,8 @@ def execute_action(id: str, **kwargs) -> Response:
|
|
|
231
231
|
if not isinstance(execute_req, dict):
|
|
232
232
|
return bad_request(err="Incorrect data structure!")
|
|
233
233
|
|
|
234
|
-
action = datastore().action.get(id)
|
|
234
|
+
action: Action = datastore().action.get(id)
|
|
235
|
+
|
|
235
236
|
if not action:
|
|
236
237
|
return not_found(err="The specified action does not exist")
|
|
237
238
|
|