GeneralManager 0.87.5__tar.gz → 0.87.6__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.
- {generalmanager-0.87.5/src/GeneralManager.egg-info → generalmanager-0.87.6}/PKG-INFO +1 -1
- {generalmanager-0.87.5 → generalmanager-0.87.6}/pyproject.toml +1 -1
- {generalmanager-0.87.5 → generalmanager-0.87.6/src/GeneralManager.egg-info}/PKG-INFO +1 -1
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/GeneralManager.egg-info/SOURCES.txt +3 -0
- generalmanager-0.87.6/src/general_manager/api/graphql_query_permissions.py +619 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_resolvers.py +319 -92
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_search.py +430 -75
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/apps.py +4 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/bucket/calculation_bucket.py +322 -15
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/bucket/database_bucket.py +144 -1
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/run_context.py +15 -1
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/signals.py +82 -15
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/base_interface.py +18 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm/support.py +26 -0
- generalmanager-0.87.6/src/general_manager/interface/capabilities/orm_utils/collection_probes.py +181 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +37 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/manager/general_manager.py +4 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/manager/input.py +12 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/manager/meta.py +70 -25
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/permission/manager_based_permission.py +190 -11
- generalmanager-0.87.6/src/general_manager/search/authorization.py +109 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/backend.py +17 -2
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/backends/meilisearch.py +313 -6
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/config.py +30 -3
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/indexer.py +2 -0
- generalmanager-0.87.6/src/general_manager/search/projection.py +317 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/reconciliation.py +29 -4
- generalmanager-0.87.5/src/general_manager/api/graphql_query_permissions.py +0 -168
- {generalmanager-0.87.5 → generalmanager-0.87.6}/LICENSE +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/README.md +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/setup.cfg +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/api.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/bucket.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/cache.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/dataframes.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/factory.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/general_manager.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/interface.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/manager.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/measurement.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/permission.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/rule.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/search.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/_types/utils.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_as_of.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_errors.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_filter_contract.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_groups.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_identifiers.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_mutations.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_ordering.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_output.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_prefetch.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_relations.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_subscriptions.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_type.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_units.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_value_contract.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_view.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_warmup.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_warmup_registry.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/mutation.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/mutation_controls.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/notification_batching.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/property.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/registry.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/remote_api.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/remote_invalidation.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/api/remote_invalidation_client.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/as_of.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/bootstrap.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/bucket/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/bucket/_materialized_bucket.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/bucket/_ordering.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/bucket/base_bucket.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/bucket/excel_bucket.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/bucket/group_bucket.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/bucket/indexing.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/bucket/projection.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/bucket/request_bucket.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/_dependency_graph.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/batch_refresh.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/cache_decorator.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/cache_tracker.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/data_change_context.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/dependency_cache.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/dependency_index.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/dependency_matching.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/dependency_publish.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/dependency_shards.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/model_dependency_collector.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/run_context_lru.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/cache/transaction_barrier.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/audit.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/audit_identity.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/bootstrap.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/checks.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/consumer.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/context.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/errors.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/__main__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/baseline.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/datasets/basic_queries.yaml +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/datasets/demo_readiness.yaml +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/datasets/edge_cases.yaml +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/datasets/follow_ups.yaml +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/datasets/large_schema.yaml +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/datasets/multi_hop.yaml +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/datasets/planned_orchestration.yaml +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/diagnostics.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/execution.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/fingerprints.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/fixtures.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/judges/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/judges/contract.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/judges/result_set.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/outcomes.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/readiness.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/runner.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/evals/traces.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/graphql_contract.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/grounding.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/models.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/mutation_inputs.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/action_contract.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/binding_diagnostics.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/budget.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/calculation_scope.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/calculations.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/catalog.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/category_binding.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/choice_context.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/clarification.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/config.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/contract.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/conversion.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/cross_query.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/deferred_calculations.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/deferred_schema.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/events.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/evidence.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/evidence_selection.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/group_actions.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/models.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/planner.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/planner_context.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/provider_calls.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/resolver.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/scheduler.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/schema_projection.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/selector_clarification.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/selector_question.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/synthesis.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/planned/validation.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/providers/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/providers/_shared.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/providers/anthropic.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/providers/base.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/providers/google.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/providers/ollama.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/providers/openai.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/rate_limits.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/routing.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/schema_index.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/schema_inspection.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/settings.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/signals.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/system_prompt.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/tool_metadata.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/tools.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/turns.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/chat/views.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/conf.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/dataframes/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/dataframes/measurements.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/factory/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/factory/auto_factory.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/factory/factories.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/factory/factory_methods.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/bundles/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/bundles/calculation.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/bundles/database.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/bundles/excel.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/bundles/remote_manager.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/bundles/request.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/base.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/builtin.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/calculation/input_resolution.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/configuration.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/core/observability.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/core/utils.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/excel/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/exceptions.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/factory.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm/bulk.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm/create_many.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm/history.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm/history_query.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/orm_utils/update_state.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/registry.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/excel.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/excel_store.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/excel_workbook.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/infrastructure/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/interfaces/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/interfaces/calculation.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/interfaces/database.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/interfaces/excel.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/interfaces/existing_model.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/interfaces/read_only.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/interfaces/request.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/manifests/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/manifests/capability_builder.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/manifests/capability_models.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/orm_interface.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/requests.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/unit_contract.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/utils/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/utils/errors.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/utils/history.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/interface/utils/models.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/logging.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/management/commands/chat_cleanup.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/management/commands/cleanup_upload_intents.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/management/commands/graphql_warmup.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/management/commands/search_index.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/management/commands/search_reconcile.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/management/commands/shell.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/management/commands/sync_read_only.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/manager/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/manager/bulk_create.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/manager/group_manager.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/measurement/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/measurement/measurement.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/measurement/measurement_field.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/metrics/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/metrics/graphql.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0001_initial.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0004_search_index_state.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0007_upload_intent.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0008_upload_finalization_versions.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0009_upload_cleanup_state.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0011_search_index_state_dirty_generation.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/0012_chat_context_watermarks.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/migrations/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/models.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/permission/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/permission/audit.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/permission/base_permission.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/permission/graphql_capabilities.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/permission/mutation_permission.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/permission/permission_checks.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/permission/permission_data_manager.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/permission/utils.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/public_api_registry.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/py.typed +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/rule/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/rule/handler.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/rule/rule.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/async_tasks.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/backend_registry.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/backends/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/backends/dev.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/backends/opensearch.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/backends/typesense.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/checks.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/identity.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/invalidation.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/m2m_invalidation.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/models.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/registry.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/tasks.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/search/utils.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/seeding/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/seeding/manager_landscape.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/adapters.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/checks.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/config.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/errors.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/finalization.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/graphql.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/graphql_types.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/metrics.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/models.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/public.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/s3.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/services.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/tokens.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/types.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/urls.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/uploads/views.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/_args_to_kwargs.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/_cache_key_encoder.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/_make_cache_key.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/_none_to_zero.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/executable_contract.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/filter_parser.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/format_string.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/json_encoder.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/path_mapping.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/public_api.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/testing.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/utils/type_checks.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/actions.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/backend_registry.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/backends/__init__.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/backends/celery.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/backends/local.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/backends/n8n.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/config.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/engine.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/event_registry.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/events.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/models.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/signal_bridge.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/tasks.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/src/general_manager/workflow/telemetry.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/tests/test_settings.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/tests/test_urls.py +0 -0
- {generalmanager-0.87.5 → generalmanager-0.87.6}/tests/testing_asgi.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GeneralManager
|
|
3
|
-
Version: 0.87.
|
|
3
|
+
Version: 0.87.6
|
|
4
4
|
Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
|
|
5
5
|
Author-email: Tim Kleindick <tkleindick@yahoo.de>
|
|
6
6
|
License: MIT License
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "GeneralManager"
|
|
7
|
-
version = "0.87.
|
|
7
|
+
version = "0.87.6"
|
|
8
8
|
description = "Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "Tim Kleindick", email = "tkleindick@yahoo.de" }]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GeneralManager
|
|
3
|
-
Version: 0.87.
|
|
3
|
+
Version: 0.87.6
|
|
4
4
|
Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
|
|
5
5
|
Author-email: Tim Kleindick <tkleindick@yahoo.de>
|
|
6
6
|
License: MIT License
|
|
@@ -221,6 +221,7 @@ src/general_manager/interface/capabilities/orm/lifecycle.py
|
|
|
221
221
|
src/general_manager/interface/capabilities/orm/mutations.py
|
|
222
222
|
src/general_manager/interface/capabilities/orm/support.py
|
|
223
223
|
src/general_manager/interface/capabilities/orm_utils/__init__.py
|
|
224
|
+
src/general_manager/interface/capabilities/orm_utils/collection_probes.py
|
|
224
225
|
src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py
|
|
225
226
|
src/general_manager/interface/capabilities/orm_utils/field_descriptors.py
|
|
226
227
|
src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py
|
|
@@ -301,6 +302,7 @@ src/general_manager/rule/handler.py
|
|
|
301
302
|
src/general_manager/rule/rule.py
|
|
302
303
|
src/general_manager/search/__init__.py
|
|
303
304
|
src/general_manager/search/async_tasks.py
|
|
305
|
+
src/general_manager/search/authorization.py
|
|
304
306
|
src/general_manager/search/backend.py
|
|
305
307
|
src/general_manager/search/backend_registry.py
|
|
306
308
|
src/general_manager/search/checks.py
|
|
@@ -310,6 +312,7 @@ src/general_manager/search/indexer.py
|
|
|
310
312
|
src/general_manager/search/invalidation.py
|
|
311
313
|
src/general_manager/search/m2m_invalidation.py
|
|
312
314
|
src/general_manager/search/models.py
|
|
315
|
+
src/general_manager/search/projection.py
|
|
313
316
|
src/general_manager/search/reconciliation.py
|
|
314
317
|
src/general_manager/search/registry.py
|
|
315
318
|
src/general_manager/search/tasks.py
|
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
"""Authorize query operands before they influence membership or ordering."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from inspect import getattr_static
|
|
8
|
+
from typing import TYPE_CHECKING, cast
|
|
9
|
+
|
|
10
|
+
from graphql import GraphQLError
|
|
11
|
+
|
|
12
|
+
from general_manager.bucket.base_bucket import Bucket
|
|
13
|
+
from general_manager.bucket.request_bucket import RequestBucket
|
|
14
|
+
from general_manager.manager.general_manager import GeneralManager
|
|
15
|
+
from general_manager.manager.meta import GeneralManagerMeta
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from graphene import ResolveInfo
|
|
19
|
+
from general_manager.interface.base_interface import (
|
|
20
|
+
AttributeTypedDict,
|
|
21
|
+
InterfaceBase,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class QueryFieldPermissionError(GraphQLError):
|
|
26
|
+
"""A requested operand is not authorized on the candidate scope."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, field: str) -> None:
|
|
29
|
+
super().__init__(f"Permission denied to use query field '{field}'.")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
_LIMIT_ERROR = "Query field authorization candidate limit exceeded."
|
|
33
|
+
_AMBIGUOUS_ERROR = "Cannot authorize ambiguous query relation."
|
|
34
|
+
_RELATION_ERROR = "Permission denied to traverse query relation."
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class QueryRelationPermissionError(GraphQLError):
|
|
38
|
+
"""A search candidate contains a related row the actor cannot read."""
|
|
39
|
+
|
|
40
|
+
def __init__(self) -> None:
|
|
41
|
+
super().__init__(_RELATION_ERROR)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
INCOMPLETE_ERROR = "Query field authorization requires a complete candidate set."
|
|
45
|
+
CUSTOM_PROJECTION_ERROR = (
|
|
46
|
+
"Cannot authorize fields of a custom search document projection."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Bound field/path decisions; bucket materialization and row checks precede this.
|
|
50
|
+
MAX_QUERY_PERMISSION_CANDIDATES = 1000
|
|
51
|
+
_LOOKUPS = {
|
|
52
|
+
"exact",
|
|
53
|
+
"iexact",
|
|
54
|
+
"in",
|
|
55
|
+
"isnull",
|
|
56
|
+
"lt",
|
|
57
|
+
"lte",
|
|
58
|
+
"gt",
|
|
59
|
+
"gte",
|
|
60
|
+
"contains",
|
|
61
|
+
"icontains",
|
|
62
|
+
"startswith",
|
|
63
|
+
"istartswith",
|
|
64
|
+
"endswith",
|
|
65
|
+
"iendswith",
|
|
66
|
+
"range",
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass(slots=True)
|
|
71
|
+
class _NativePathNode:
|
|
72
|
+
"""One shared native source prefix, without storing permission decisions."""
|
|
73
|
+
|
|
74
|
+
children: dict[str, _NativePathNode] = field(default_factory=dict)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@dataclass(slots=True)
|
|
78
|
+
class QueryFieldAuthorizationBudget:
|
|
79
|
+
"""Share only accounting across authorization calls in one operation."""
|
|
80
|
+
|
|
81
|
+
decisions: int = 0
|
|
82
|
+
|
|
83
|
+
def charge(self) -> None:
|
|
84
|
+
"""Reject work exceeding the operation's field/path decision limit."""
|
|
85
|
+
self.decisions += 1
|
|
86
|
+
if self.decisions > MAX_QUERY_PERMISSION_CANDIDATES:
|
|
87
|
+
raise GraphQLError(_LIMIT_ERROR)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _operand_field_names(
|
|
91
|
+
manager: type[GeneralManager],
|
|
92
|
+
field_name: str,
|
|
93
|
+
attributes: dict[str, AttributeTypedDict],
|
|
94
|
+
*,
|
|
95
|
+
native_paths: bool,
|
|
96
|
+
) -> tuple[list[str], set[str], set[str]]:
|
|
97
|
+
"""Resolve the existing field/relationship spellings for one operand."""
|
|
98
|
+
from general_manager.api.graphql_relations import (
|
|
99
|
+
get_graphql_manager_registry,
|
|
100
|
+
resolve_general_manager_type,
|
|
101
|
+
)
|
|
102
|
+
from general_manager.api.graphql_resolvers import relation_id_alias_field
|
|
103
|
+
|
|
104
|
+
aliases = (
|
|
105
|
+
[]
|
|
106
|
+
if native_paths
|
|
107
|
+
else [
|
|
108
|
+
name
|
|
109
|
+
for name, metadata in attributes.items()
|
|
110
|
+
if metadata.get("filter_lookup", name) == field_name
|
|
111
|
+
]
|
|
112
|
+
)
|
|
113
|
+
names = set(aliases or [field_name])
|
|
114
|
+
native_relations: set[str] = set()
|
|
115
|
+
for name in tuple(names):
|
|
116
|
+
relation = relation_id_alias_field(manager, name, native_source=native_paths)
|
|
117
|
+
if not native_paths and relation is None and name.endswith("_id"):
|
|
118
|
+
alias = name.removesuffix("_id")
|
|
119
|
+
metadata: dict[str, object] = dict(attributes.get(alias, {}))
|
|
120
|
+
if (
|
|
121
|
+
resolve_general_manager_type(
|
|
122
|
+
metadata.get("type"), get_graphql_manager_registry()
|
|
123
|
+
)
|
|
124
|
+
is not None
|
|
125
|
+
):
|
|
126
|
+
relation = alias
|
|
127
|
+
if relation is not None:
|
|
128
|
+
names.add(relation)
|
|
129
|
+
if native_paths:
|
|
130
|
+
native_relations.add(relation)
|
|
131
|
+
return aliases, names, native_relations
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _unchanged_metadata_methods(
|
|
135
|
+
owner: object, bindings: Iterable[tuple[str, object, object]]
|
|
136
|
+
) -> bool:
|
|
137
|
+
"""Check the actual metadata owners, including instance and code overrides."""
|
|
138
|
+
from general_manager.utils.executable_contract import executable_matches
|
|
139
|
+
|
|
140
|
+
for name, original, signature in bindings:
|
|
141
|
+
if getattr_static(owner, name, None) is not original:
|
|
142
|
+
return False
|
|
143
|
+
executable = (
|
|
144
|
+
original.__func__ if isinstance(original, classmethod) else original
|
|
145
|
+
)
|
|
146
|
+
if not executable_matches(executable, signature):
|
|
147
|
+
return False
|
|
148
|
+
return True
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@dataclass(frozen=True, slots=True)
|
|
152
|
+
class _FlatQueryField:
|
|
153
|
+
"""Structure only: runtime decisions still run in the original order."""
|
|
154
|
+
|
|
155
|
+
names: tuple[str, ...]
|
|
156
|
+
additional: bool
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@dataclass(slots=True)
|
|
160
|
+
class _NativeQueryStructure:
|
|
161
|
+
"""One call's stable standard ORM schema and declarative policy structure."""
|
|
162
|
+
|
|
163
|
+
manager: type[GeneralManager]
|
|
164
|
+
interface: type[InterfaceBase]
|
|
165
|
+
permission: object
|
|
166
|
+
attributes: dict[str, AttributeTypedDict]
|
|
167
|
+
properties: frozenset[str]
|
|
168
|
+
fields: dict[tuple[str, ...], _FlatQueryField | None] = field(default_factory=dict)
|
|
169
|
+
additional: dict[str, bool | None] = field(default_factory=dict)
|
|
170
|
+
|
|
171
|
+
def flat_field(self, parts: tuple[str, ...]) -> _FlatQueryField | None:
|
|
172
|
+
"""Prepare only a visited, known flat operand; keep general paths dynamic."""
|
|
173
|
+
if parts in self.fields:
|
|
174
|
+
return self.fields[parts]
|
|
175
|
+
from general_manager.api.graphql_relations import (
|
|
176
|
+
get_graphql_manager_registry,
|
|
177
|
+
resolve_general_manager_type,
|
|
178
|
+
)
|
|
179
|
+
from general_manager.permission.manager_based_permission import (
|
|
180
|
+
additional_local_read_permission,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
self.fields[parts] = None
|
|
184
|
+
field_name, *rest = parts
|
|
185
|
+
if len(rest) > 1 or (rest and rest[0] not in _LOOKUPS):
|
|
186
|
+
return None
|
|
187
|
+
aliases, names, _ = _operand_field_names(
|
|
188
|
+
self.manager, field_name, self.attributes, native_paths=False
|
|
189
|
+
)
|
|
190
|
+
if (
|
|
191
|
+
len(aliases) > 1
|
|
192
|
+
or not names.intersection(self.attributes)
|
|
193
|
+
or names.intersection(self.properties)
|
|
194
|
+
):
|
|
195
|
+
return None
|
|
196
|
+
metadata: dict[str, object] = dict(
|
|
197
|
+
self.attributes.get(aliases[0] if aliases else field_name, {})
|
|
198
|
+
)
|
|
199
|
+
annotation = metadata.get("type")
|
|
200
|
+
identity_alias = field_name.endswith("_id") and len(names) > 1
|
|
201
|
+
if not identity_alias and (
|
|
202
|
+
type(annotation) is not type
|
|
203
|
+
or (
|
|
204
|
+
(
|
|
205
|
+
back_reference := getattr_static(
|
|
206
|
+
annotation, "_general_manager_class", None
|
|
207
|
+
)
|
|
208
|
+
)
|
|
209
|
+
is not None
|
|
210
|
+
and type(back_reference) is not GeneralManagerMeta
|
|
211
|
+
)
|
|
212
|
+
or resolve_general_manager_type(annotation, get_graphql_manager_registry())
|
|
213
|
+
is not None
|
|
214
|
+
or metadata.get("relation_kind") in {"direct", "collection"}
|
|
215
|
+
):
|
|
216
|
+
return None
|
|
217
|
+
# Rule definitions, including their lists/dicts, are stable for this
|
|
218
|
+
# call. No actor/object result or Permission instance is retained.
|
|
219
|
+
for name in names:
|
|
220
|
+
if name not in self.additional:
|
|
221
|
+
self.additional[name] = additional_local_read_permission(
|
|
222
|
+
self.permission, name
|
|
223
|
+
)
|
|
224
|
+
if self.additional[name] is None:
|
|
225
|
+
return None
|
|
226
|
+
prepared = _FlatQueryField(
|
|
227
|
+
tuple(names), any(self.additional[name] for name in names)
|
|
228
|
+
)
|
|
229
|
+
self.fields[parts] = prepared
|
|
230
|
+
return prepared
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _prepare_native_query_structure(
|
|
234
|
+
manager: type[GeneralManager],
|
|
235
|
+
) -> _NativeQueryStructure | None:
|
|
236
|
+
"""Attest canonical metadata providers without evaluating a permission."""
|
|
237
|
+
from general_manager.interface.base_interface import _NATIVE_QUERY_METADATA_METHODS
|
|
238
|
+
from general_manager.interface.capabilities.orm import support as orm_support
|
|
239
|
+
from general_manager.interface.capabilities.orm_utils.field_descriptors import (
|
|
240
|
+
FieldDescriptor,
|
|
241
|
+
)
|
|
242
|
+
from general_manager.interface.manifests.capability_models import (
|
|
243
|
+
CapabilitySelection,
|
|
244
|
+
)
|
|
245
|
+
from general_manager.interface.orm_interface import OrmInterfaceBase
|
|
246
|
+
from general_manager.permission.manager_based_permission import (
|
|
247
|
+
_can_prepare_local_read_definitions,
|
|
248
|
+
)
|
|
249
|
+
from general_manager.utils.executable_contract import executable_matches
|
|
250
|
+
|
|
251
|
+
interface = getattr_static(manager, "Interface", None)
|
|
252
|
+
permission = getattr_static(manager, "Permission", None)
|
|
253
|
+
if (
|
|
254
|
+
type(interface) is not type(OrmInterfaceBase)
|
|
255
|
+
or not issubclass(interface, OrmInterfaceBase)
|
|
256
|
+
or not _unchanged_metadata_methods(interface, _NATIVE_QUERY_METADATA_METHODS)
|
|
257
|
+
or getattr_static(permission, "__based_on__", None) is not None
|
|
258
|
+
or not _can_prepare_local_read_definitions(permission)
|
|
259
|
+
):
|
|
260
|
+
return None
|
|
261
|
+
# Canonical wrappers may still read custom descriptors or mappings. Those
|
|
262
|
+
# are dynamic providers and must retain their original per-visit behavior.
|
|
263
|
+
if (
|
|
264
|
+
type(getattr_static(interface, "_capability_handlers", None)) is not dict
|
|
265
|
+
or type(getattr_static(interface, "_capability_selection", None))
|
|
266
|
+
is not CapabilitySelection
|
|
267
|
+
or getattr_static(interface, "_configured_capabilities_applied", None)
|
|
268
|
+
is not True
|
|
269
|
+
or getattr_static(interface, "_parent_class", None) is not manager
|
|
270
|
+
):
|
|
271
|
+
return None
|
|
272
|
+
descriptors = getattr_static(interface, "_field_descriptors", None)
|
|
273
|
+
if type(descriptors) is not dict:
|
|
274
|
+
return None
|
|
275
|
+
if any(
|
|
276
|
+
type(name) is not str
|
|
277
|
+
or type(descriptor) is not FieldDescriptor
|
|
278
|
+
or type(descriptor.metadata) is not dict
|
|
279
|
+
for name, descriptor in descriptors.items()
|
|
280
|
+
):
|
|
281
|
+
return None
|
|
282
|
+
resolver, signature = orm_support._NATIVE_QUERY_SUPPORT_RESOLVER
|
|
283
|
+
if orm_support.get_support_capability is not resolver or not executable_matches(
|
|
284
|
+
resolver, signature
|
|
285
|
+
):
|
|
286
|
+
return None
|
|
287
|
+
for handler, capability in (
|
|
288
|
+
(interface.get_capability_handler("read"), orm_support.OrmReadCapability),
|
|
289
|
+
(
|
|
290
|
+
interface.get_capability_handler("orm_support"),
|
|
291
|
+
orm_support.OrmPersistenceSupportCapability,
|
|
292
|
+
),
|
|
293
|
+
):
|
|
294
|
+
if (
|
|
295
|
+
type(handler) is not capability
|
|
296
|
+
or getattr_static(type(handler), "__getattribute__", None)
|
|
297
|
+
is not object.__getattribute__
|
|
298
|
+
or not _unchanged_metadata_methods(
|
|
299
|
+
handler, orm_support._NATIVE_QUERY_METADATA_METHODS[capability]
|
|
300
|
+
)
|
|
301
|
+
):
|
|
302
|
+
return None
|
|
303
|
+
return _NativeQueryStructure(
|
|
304
|
+
manager,
|
|
305
|
+
interface,
|
|
306
|
+
permission,
|
|
307
|
+
interface.get_attribute_types(),
|
|
308
|
+
frozenset(interface.get_graph_ql_properties()),
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
class _NativeQueryStructures:
|
|
313
|
+
"""Lazily prepare a call's ordinary manager classes; never cache decisions."""
|
|
314
|
+
|
|
315
|
+
def __init__(self) -> None:
|
|
316
|
+
self.managers: dict[type[GeneralManager], _NativeQueryStructure | None] = {}
|
|
317
|
+
|
|
318
|
+
def flat_field(
|
|
319
|
+
self, instance: GeneralManager, parts: tuple[str, ...]
|
|
320
|
+
) -> _FlatQueryField | None:
|
|
321
|
+
"""Return a reusable flat-field plan only for unchanged native manager contracts."""
|
|
322
|
+
manager = type(instance)
|
|
323
|
+
if type(manager) is not GeneralManagerMeta:
|
|
324
|
+
return None
|
|
325
|
+
if manager not in self.managers:
|
|
326
|
+
from general_manager.interface.orm_interface import OrmInterfaceBase
|
|
327
|
+
from general_manager.manager.general_manager import (
|
|
328
|
+
_COMMON_MANAGER_EXECUTABLES,
|
|
329
|
+
_COMMON_MANAGER_GETATTR,
|
|
330
|
+
_COMMON_MANAGER_IDENTIFICATION,
|
|
331
|
+
)
|
|
332
|
+
from general_manager.permission.manager_based_permission import (
|
|
333
|
+
AdditiveManagerPermission,
|
|
334
|
+
)
|
|
335
|
+
from general_manager.utils.executable_contract import executable_matches
|
|
336
|
+
|
|
337
|
+
identification, identification_signature = _COMMON_MANAGER_IDENTIFICATION
|
|
338
|
+
if (
|
|
339
|
+
getattr_static(manager, "__getattribute__")
|
|
340
|
+
is not object.__getattribute__
|
|
341
|
+
or getattr_static(manager, "__getattr__") is not _COMMON_MANAGER_GETATTR
|
|
342
|
+
or getattr_static(manager, "identification") is not identification
|
|
343
|
+
or not executable_matches(identification.fget, identification_signature)
|
|
344
|
+
or not executable_matches(
|
|
345
|
+
_COMMON_MANAGER_GETATTR, _COMMON_MANAGER_EXECUTABLES[2][1]
|
|
346
|
+
)
|
|
347
|
+
):
|
|
348
|
+
self.managers[manager] = None
|
|
349
|
+
return None
|
|
350
|
+
interface = getattr_static(manager, "Interface", None)
|
|
351
|
+
permission = getattr_static(manager, "Permission", None)
|
|
352
|
+
if (
|
|
353
|
+
type(interface) is not type(OrmInterfaceBase)
|
|
354
|
+
or getattr_static(type(interface), "__get__", None) is not None
|
|
355
|
+
or (
|
|
356
|
+
permission is not None
|
|
357
|
+
and (
|
|
358
|
+
type(permission) is not type(AdditiveManagerPermission)
|
|
359
|
+
or getattr_static(type(permission), "__get__", None) is not None
|
|
360
|
+
)
|
|
361
|
+
)
|
|
362
|
+
):
|
|
363
|
+
self.managers[manager] = None
|
|
364
|
+
return None
|
|
365
|
+
if (
|
|
366
|
+
instance.Interface is not interface
|
|
367
|
+
or getattr(instance, "Permission", None) is not permission
|
|
368
|
+
):
|
|
369
|
+
return None
|
|
370
|
+
self.managers[manager] = _prepare_native_query_structure(manager)
|
|
371
|
+
structure = self.managers[manager]
|
|
372
|
+
if (
|
|
373
|
+
structure is None
|
|
374
|
+
or instance.Interface is not structure.interface
|
|
375
|
+
or getattr(instance, "Permission", None) is not structure.permission
|
|
376
|
+
):
|
|
377
|
+
return None
|
|
378
|
+
return structure.flat_field(parts)
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def authorize_query_fields(
|
|
382
|
+
candidates: Iterable[GeneralManager],
|
|
383
|
+
info: ResolveInfo,
|
|
384
|
+
paths: Iterable[str],
|
|
385
|
+
*,
|
|
386
|
+
native_paths: bool = False,
|
|
387
|
+
budget_additional_permissions_only: bool = False,
|
|
388
|
+
budget: QueryFieldAuthorizationBudget | None = None,
|
|
389
|
+
prepare_native_structure: bool = False,
|
|
390
|
+
) -> None:
|
|
391
|
+
"""Check all operands against every row-visible candidate, never just hits.
|
|
392
|
+
|
|
393
|
+
Related rows require their own row permission as well as field permission.
|
|
394
|
+
Failure leaves the original candidate set unchanged and rejects the query.
|
|
395
|
+
``native_paths`` checks exact projection sources without backend aliases or
|
|
396
|
+
lookup operators. Callers validate those paths statically before iteration.
|
|
397
|
+
Their shared prefixes are walked once for each candidate/member occurrence;
|
|
398
|
+
all child fields and related-row gates remain required. No decision is
|
|
399
|
+
reused between candidates, unrelated source branches or authorization calls.
|
|
400
|
+
Native list resolvers may budget only additional or unknown field policies.
|
|
401
|
+
That mode still executes every runtime field and related-row check; it
|
|
402
|
+
changes accounting, never the authorization decision or candidate scope.
|
|
403
|
+
Native database lists may prepare canonical flat ORM operand structure once
|
|
404
|
+
per call. This assumes schema and declarative rule definitions stay fixed
|
|
405
|
+
during the call; every runtime permission check remains. Custom providers
|
|
406
|
+
and complex paths retain the general traversal. A new call prepares afresh.
|
|
407
|
+
"""
|
|
408
|
+
from general_manager.api.graphql_relations import (
|
|
409
|
+
resolve_general_manager_type,
|
|
410
|
+
get_graphql_manager_registry,
|
|
411
|
+
)
|
|
412
|
+
from general_manager.api.graphql_resolvers import (
|
|
413
|
+
can_read_instance,
|
|
414
|
+
check_read_permission,
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
normalized = set()
|
|
418
|
+
for path in paths:
|
|
419
|
+
parts = path.split("__")
|
|
420
|
+
if parts:
|
|
421
|
+
normalized.add(tuple(parts))
|
|
422
|
+
if not normalized:
|
|
423
|
+
return
|
|
424
|
+
normalized_paths = sorted(normalized)
|
|
425
|
+
native_root = _NativePathNode()
|
|
426
|
+
if native_paths:
|
|
427
|
+
for native_parts in normalized_paths:
|
|
428
|
+
node = native_root
|
|
429
|
+
for part in native_parts:
|
|
430
|
+
node = node.children.setdefault(part, _NativePathNode())
|
|
431
|
+
budget = budget or QueryFieldAuthorizationBudget()
|
|
432
|
+
structures = (
|
|
433
|
+
_NativeQueryStructures()
|
|
434
|
+
if prepare_native_structure
|
|
435
|
+
and budget_additional_permissions_only
|
|
436
|
+
and not native_paths
|
|
437
|
+
else None
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
def needs_additional_budget(instance: GeneralManager, names: set[str]) -> bool:
|
|
441
|
+
"""Inspect the current policy, including subtype and instance overrides."""
|
|
442
|
+
from inspect import getattr_static
|
|
443
|
+
|
|
444
|
+
from general_manager.permission.base_permission import BasePermission
|
|
445
|
+
from general_manager.permission.manager_based_permission import (
|
|
446
|
+
additional_local_read_permission,
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
permission = getattr(instance, "Permission", None)
|
|
450
|
+
if permission is None:
|
|
451
|
+
return False
|
|
452
|
+
if not isinstance(permission, type) or not issubclass(
|
|
453
|
+
permission, BasePermission
|
|
454
|
+
):
|
|
455
|
+
return True
|
|
456
|
+
# A delegated object's runtime type and nullable fallback can tighten
|
|
457
|
+
# the local rule. Keep that proof outside this accounting shortcut.
|
|
458
|
+
if getattr_static(permission, "__based_on__", None) is not None:
|
|
459
|
+
return True
|
|
460
|
+
return any(
|
|
461
|
+
additional_local_read_permission(permission, name) is not False
|
|
462
|
+
for name in names
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
def check(
|
|
466
|
+
instance: GeneralManager,
|
|
467
|
+
parts: tuple[str, ...],
|
|
468
|
+
native_node: _NativePathNode | None = None,
|
|
469
|
+
) -> None:
|
|
470
|
+
"""Authorize one exact operand path, charging each visited field decision."""
|
|
471
|
+
prepared = structures.flat_field(instance, parts) if structures else None
|
|
472
|
+
if prepared is not None:
|
|
473
|
+
if prepared.additional:
|
|
474
|
+
budget.charge()
|
|
475
|
+
# Identification is per object. Preserve its validation/errors at
|
|
476
|
+
# the original point even though the field is already known.
|
|
477
|
+
set(instance.identification)
|
|
478
|
+
if any(
|
|
479
|
+
not check_read_permission(instance, info, name)
|
|
480
|
+
for name in prepared.names
|
|
481
|
+
):
|
|
482
|
+
raise QueryFieldPermissionError(parts[0])
|
|
483
|
+
return
|
|
484
|
+
if not budget_additional_permissions_only:
|
|
485
|
+
budget.charge()
|
|
486
|
+
field, *rest = parts
|
|
487
|
+
attributes = instance.Interface.get_attribute_types()
|
|
488
|
+
# Backend collection lookup names can differ from public manager names.
|
|
489
|
+
aliases, names, native_relations = _operand_field_names(
|
|
490
|
+
type(instance), field, attributes, native_paths=native_paths
|
|
491
|
+
)
|
|
492
|
+
if budget_additional_permissions_only and needs_additional_budget(
|
|
493
|
+
instance, names
|
|
494
|
+
):
|
|
495
|
+
budget.charge()
|
|
496
|
+
known_fields = set(attributes) | set(instance.identification)
|
|
497
|
+
known_fields.update(instance.Interface.get_graph_ql_properties())
|
|
498
|
+
known_fields.update(instance.Interface.get_attributes())
|
|
499
|
+
known_fields.update(instance.Interface.input_fields)
|
|
500
|
+
if not names.intersection(known_fields):
|
|
501
|
+
raise QueryFieldPermissionError(field)
|
|
502
|
+
if any(not check_read_permission(instance, info, name) for name in names):
|
|
503
|
+
raise QueryFieldPermissionError(field)
|
|
504
|
+
for relation in sorted(native_relations):
|
|
505
|
+
# An ORM attname is a scalar spelling of a related field. Give it
|
|
506
|
+
# the same target row/leaf gates as an explicit relation path.
|
|
507
|
+
value = getattr(instance, relation)
|
|
508
|
+
if value is None:
|
|
509
|
+
continue
|
|
510
|
+
related_type = resolve_general_manager_type(
|
|
511
|
+
attributes[relation].get("type"), get_graphql_manager_registry()
|
|
512
|
+
)
|
|
513
|
+
if (
|
|
514
|
+
not isinstance(value, GeneralManager)
|
|
515
|
+
or related_type is None
|
|
516
|
+
or not isinstance(value, related_type)
|
|
517
|
+
):
|
|
518
|
+
raise GraphQLError(_RELATION_ERROR)
|
|
519
|
+
if not can_read_instance(value, info):
|
|
520
|
+
raise QueryRelationPermissionError()
|
|
521
|
+
from django.db import models
|
|
522
|
+
from general_manager.interface.orm_interface import OrmInterfaceBase
|
|
523
|
+
|
|
524
|
+
orm_interface = cast(
|
|
525
|
+
type[OrmInterfaceBase[models.Model]], instance.Interface
|
|
526
|
+
)
|
|
527
|
+
foreign_key = orm_interface._model._meta.get_field(relation)
|
|
528
|
+
target_field = getattr(foreign_key, "target_field", None)
|
|
529
|
+
if not isinstance(target_field, models.Field):
|
|
530
|
+
raise GraphQLError(_RELATION_ERROR)
|
|
531
|
+
target_names = {target_field.name}
|
|
532
|
+
if target_field.primary_key:
|
|
533
|
+
target_names.add("id")
|
|
534
|
+
for target_name in sorted(target_names):
|
|
535
|
+
check(value, (target_name,))
|
|
536
|
+
if not rest and not (native_node and native_node.children):
|
|
537
|
+
return
|
|
538
|
+
if len(aliases) > 1:
|
|
539
|
+
raise GraphQLError(_AMBIGUOUS_ERROR)
|
|
540
|
+
field_metadata: dict[str, object] = dict(
|
|
541
|
+
attributes.get(aliases[0] if aliases else field, {})
|
|
542
|
+
)
|
|
543
|
+
if native_paths:
|
|
544
|
+
from general_manager.search.projection import source_field_annotation
|
|
545
|
+
|
|
546
|
+
_, annotation = source_field_annotation(type(instance), field)
|
|
547
|
+
field_metadata["type"] = annotation
|
|
548
|
+
if (
|
|
549
|
+
not native_paths
|
|
550
|
+
and len(rest) == 1
|
|
551
|
+
and rest[0] in _LOOKUPS
|
|
552
|
+
and (
|
|
553
|
+
(field.endswith("_id") and len(names) > 1)
|
|
554
|
+
or (
|
|
555
|
+
field_metadata.get("type") is not None
|
|
556
|
+
and resolve_general_manager_type(
|
|
557
|
+
field_metadata.get("type"), get_graphql_manager_registry()
|
|
558
|
+
)
|
|
559
|
+
is None
|
|
560
|
+
and field_metadata.get("relation_kind")
|
|
561
|
+
not in {"direct", "collection"}
|
|
562
|
+
)
|
|
563
|
+
)
|
|
564
|
+
):
|
|
565
|
+
return
|
|
566
|
+
related_type = resolve_general_manager_type(
|
|
567
|
+
field_metadata.get("type"), get_graphql_manager_registry()
|
|
568
|
+
)
|
|
569
|
+
if (
|
|
570
|
+
not native_paths
|
|
571
|
+
and len(rest) == 1
|
|
572
|
+
and rest[0] in _LOOKUPS
|
|
573
|
+
and related_type is not None
|
|
574
|
+
):
|
|
575
|
+
related_fields = set(related_type.Interface.get_attribute_types())
|
|
576
|
+
related_fields.update(related_type.Interface.get_attributes())
|
|
577
|
+
related_fields.update(related_type.Interface.get_graph_ql_properties())
|
|
578
|
+
if rest[0] not in related_fields:
|
|
579
|
+
return
|
|
580
|
+
value = getattr(instance, aliases[0] if aliases else field)
|
|
581
|
+
if value is None:
|
|
582
|
+
return
|
|
583
|
+
related = value if isinstance(value, (Bucket, list, tuple, set)) else [value]
|
|
584
|
+
for member in related:
|
|
585
|
+
if not isinstance(member, GeneralManager):
|
|
586
|
+
# A lookup is an operator only after resolving its preceding
|
|
587
|
+
# scalar field. A relation's field named "contains" is a field.
|
|
588
|
+
if not native_paths and len(rest) == 1 and rest[0] in _LOOKUPS:
|
|
589
|
+
continue
|
|
590
|
+
raise GraphQLError(_RELATION_ERROR)
|
|
591
|
+
if (
|
|
592
|
+
native_paths
|
|
593
|
+
and related_type is not None
|
|
594
|
+
and not isinstance(member, related_type)
|
|
595
|
+
):
|
|
596
|
+
raise GraphQLError(_RELATION_ERROR)
|
|
597
|
+
if not can_read_instance(member, info):
|
|
598
|
+
raise QueryRelationPermissionError()
|
|
599
|
+
if native_node is None:
|
|
600
|
+
check(member, tuple(rest))
|
|
601
|
+
else:
|
|
602
|
+
for child_field, child in sorted(native_node.children.items()):
|
|
603
|
+
check(member, (child_field,), child)
|
|
604
|
+
if (
|
|
605
|
+
native_paths
|
|
606
|
+
and isinstance(related, RequestBucket)
|
|
607
|
+
and not related.response_is_complete
|
|
608
|
+
):
|
|
609
|
+
raise GraphQLError(INCOMPLETE_ERROR)
|
|
610
|
+
|
|
611
|
+
for candidate in candidates:
|
|
612
|
+
if native_paths:
|
|
613
|
+
for native_field, native_node in sorted(native_root.children.items()):
|
|
614
|
+
check(candidate, (native_field,), native_node)
|
|
615
|
+
else:
|
|
616
|
+
for normalized_parts in normalized_paths:
|
|
617
|
+
check(candidate, normalized_parts)
|
|
618
|
+
if isinstance(candidates, RequestBucket) and not candidates.response_is_complete:
|
|
619
|
+
raise GraphQLError(INCOMPLETE_ERROR)
|