GeneralManager 0.87.0__tar.gz → 0.87.1__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.0/src/GeneralManager.egg-info → generalmanager-0.87.1}/PKG-INFO +1 -1
- {generalmanager-0.87.0 → generalmanager-0.87.1}/pyproject.toml +1 -1
- {generalmanager-0.87.0 → generalmanager-0.87.1/src/GeneralManager.egg-info}/PKG-INFO +1 -1
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/GeneralManager.egg-info/SOURCES.txt +1 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql.py +29 -4
- generalmanager-0.87.1/src/general_manager/api/graphql_query_permissions.py +168 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_resolvers.py +180 -45
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_search.py +134 -24
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_subscription_consumer.py +63 -3
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/tools.py +10 -11
- {generalmanager-0.87.0 → generalmanager-0.87.1}/LICENSE +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/README.md +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/setup.cfg +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/api.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/bucket.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/cache.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/dataframes.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/factory.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/general_manager.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/interface.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/manager.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/measurement.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/permission.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/rule.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/search.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/_types/utils.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_as_of.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_errors.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_filter_contract.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_groups.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_identifiers.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_mutations.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_ordering.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_output.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_prefetch.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_relations.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_subscriptions.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_type.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_units.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_value_contract.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_view.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_warmup.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_warmup_registry.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/mutation.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/mutation_controls.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/notification_batching.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/property.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/registry.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/remote_api.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/remote_invalidation.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/remote_invalidation_client.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/apps.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/as_of.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/bootstrap.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/bucket/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/bucket/_materialized_bucket.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/bucket/_ordering.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/bucket/base_bucket.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/bucket/calculation_bucket.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/bucket/database_bucket.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/bucket/excel_bucket.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/bucket/group_bucket.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/bucket/indexing.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/bucket/projection.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/bucket/request_bucket.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/_dependency_graph.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/batch_refresh.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/cache_decorator.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/cache_tracker.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/data_change_context.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/dependency_cache.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/dependency_index.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/dependency_matching.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/dependency_publish.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/dependency_shards.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/model_dependency_collector.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/run_context.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/run_context_lru.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/signals.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/cache/transaction_barrier.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/audit.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/audit_identity.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/bootstrap.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/checks.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/consumer.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/context.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/errors.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/__main__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/baseline.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/datasets/basic_queries.yaml +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/datasets/demo_readiness.yaml +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/datasets/edge_cases.yaml +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/datasets/follow_ups.yaml +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/datasets/large_schema.yaml +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/datasets/multi_hop.yaml +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/datasets/planned_orchestration.yaml +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/diagnostics.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/execution.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/fingerprints.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/fixtures.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/judges/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/judges/contract.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/judges/result_set.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/outcomes.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/readiness.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/runner.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/evals/traces.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/graphql_contract.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/grounding.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/models.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/mutation_inputs.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/action_contract.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/binding_diagnostics.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/budget.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/calculation_scope.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/calculations.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/catalog.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/category_binding.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/choice_context.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/clarification.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/config.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/contract.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/conversion.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/cross_query.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/deferred_calculations.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/deferred_schema.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/events.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/evidence.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/evidence_selection.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/group_actions.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/models.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/planner.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/planner_context.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/provider_calls.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/resolver.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/scheduler.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/schema_projection.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/selector_clarification.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/selector_question.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/synthesis.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/planned/validation.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/providers/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/providers/_shared.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/providers/anthropic.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/providers/base.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/providers/google.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/providers/ollama.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/providers/openai.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/rate_limits.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/routing.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/schema_index.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/schema_inspection.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/settings.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/signals.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/system_prompt.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/tool_metadata.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/turns.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/chat/views.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/conf.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/dataframes/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/dataframes/measurements.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/factory/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/factory/auto_factory.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/factory/factories.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/factory/factory_methods.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/base_interface.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/bundles/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/bundles/calculation.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/bundles/database.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/bundles/excel.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/bundles/remote_manager.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/bundles/request.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/base.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/builtin.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/calculation/input_resolution.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/configuration.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/core/observability.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/core/utils.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/excel/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/exceptions.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/factory.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm/bulk.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm/create_many.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm/history.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm/support.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/orm_utils/update_state.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/registry.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/excel.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/excel_store.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/excel_workbook.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/infrastructure/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/interfaces/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/interfaces/calculation.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/interfaces/database.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/interfaces/excel.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/interfaces/existing_model.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/interfaces/read_only.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/interfaces/request.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/manifests/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/manifests/capability_builder.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/manifests/capability_models.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/orm_interface.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/requests.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/unit_contract.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/utils/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/utils/errors.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/utils/history.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/interface/utils/models.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/logging.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/management/commands/chat_cleanup.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/management/commands/cleanup_upload_intents.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/management/commands/graphql_warmup.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/management/commands/search_index.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/management/commands/search_reconcile.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/management/commands/shell.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/management/commands/sync_read_only.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/manager/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/manager/bulk_create.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/manager/general_manager.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/manager/group_manager.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/manager/input.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/manager/meta.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/measurement/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/measurement/measurement.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/measurement/measurement_field.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/metrics/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/metrics/graphql.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0001_initial.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0004_search_index_state.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0007_upload_intent.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0008_upload_finalization_versions.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0009_upload_cleanup_state.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0011_search_index_state_dirty_generation.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/0012_chat_context_watermarks.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/migrations/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/models.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/permission/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/permission/audit.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/permission/base_permission.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/permission/graphql_capabilities.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/permission/manager_based_permission.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/permission/mutation_permission.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/permission/permission_checks.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/permission/permission_data_manager.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/permission/utils.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/public_api_registry.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/py.typed +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/rule/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/rule/handler.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/rule/rule.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/async_tasks.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/backend.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/backend_registry.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/backends/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/backends/dev.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/backends/meilisearch.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/backends/opensearch.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/backends/typesense.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/checks.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/config.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/identity.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/indexer.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/invalidation.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/m2m_invalidation.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/models.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/reconciliation.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/registry.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/tasks.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/search/utils.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/seeding/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/seeding/manager_landscape.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/adapters.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/checks.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/config.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/errors.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/finalization.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/graphql.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/graphql_types.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/metrics.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/models.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/public.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/s3.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/services.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/tokens.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/types.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/urls.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/uploads/views.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/_args_to_kwargs.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/_cache_key_encoder.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/_make_cache_key.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/_none_to_zero.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/executable_contract.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/filter_parser.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/format_string.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/json_encoder.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/path_mapping.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/public_api.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/testing.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/utils/type_checks.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/actions.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/backend_registry.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/backends/__init__.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/backends/celery.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/backends/local.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/backends/n8n.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/config.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/engine.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/event_registry.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/events.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/models.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/signal_bridge.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/tasks.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/workflow/telemetry.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/tests/test_settings.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/tests/test_urls.py +0 -0
- {generalmanager-0.87.0 → generalmanager-0.87.1}/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.1
|
|
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.1"
|
|
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.1
|
|
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
|
|
@@ -40,6 +40,7 @@ src/general_manager/api/graphql_mutations.py
|
|
|
40
40
|
src/general_manager/api/graphql_ordering.py
|
|
41
41
|
src/general_manager/api/graphql_output.py
|
|
42
42
|
src/general_manager/api/graphql_prefetch.py
|
|
43
|
+
src/general_manager/api/graphql_query_permissions.py
|
|
43
44
|
src/general_manager/api/graphql_relations.py
|
|
44
45
|
src/general_manager/api/graphql_resolvers.py
|
|
45
46
|
src/general_manager/api/graphql_search.py
|
|
@@ -36,6 +36,9 @@ import graphene
|
|
|
36
36
|
from asgiref.sync import async_to_sync
|
|
37
37
|
from channels.layers import BaseChannelLayer
|
|
38
38
|
from django.core.exceptions import ObjectDoesNotExist
|
|
39
|
+
|
|
40
|
+
from general_manager.interface.requests import RequestNotFoundError
|
|
41
|
+
from general_manager.manager.meta import AttributeEvaluationError
|
|
39
42
|
from django.db import DEFAULT_DB_ALIAS, models, transaction
|
|
40
43
|
from django.utils.module_loading import import_string
|
|
41
44
|
|
|
@@ -120,6 +123,7 @@ from general_manager.api.graphql_resolvers import (
|
|
|
120
123
|
check_read_permission as _check_read_permission_fn,
|
|
121
124
|
check_read_permission_for_user as _check_read_permission_for_user_fn,
|
|
122
125
|
can_read_instance_for_user as _can_read_instance_for_user_fn,
|
|
126
|
+
can_read_class_for_user as _can_read_class_for_user_fn,
|
|
123
127
|
create_measurement_resolver as _create_measurement_resolver_fn,
|
|
124
128
|
create_normal_resolver as _create_normal_resolver_fn,
|
|
125
129
|
create_list_resolver as _create_list_resolver_fn,
|
|
@@ -2260,17 +2264,32 @@ class GraphQL:
|
|
|
2260
2264
|
|
|
2261
2265
|
def resolver(
|
|
2262
2266
|
self: GeneralManager, info: GraphQLResolveInfo, **identification: object
|
|
2263
|
-
) -> GeneralManager:
|
|
2267
|
+
) -> GeneralManager | None:
|
|
2264
2268
|
"""
|
|
2265
|
-
Instantiate and
|
|
2269
|
+
Instantiate and authorize a manager before exposing its existence.
|
|
2266
2270
|
|
|
2267
2271
|
Parameters:
|
|
2268
2272
|
identification (dict): Mapping of identification argument names to values passed to the manager constructor.
|
|
2269
2273
|
|
|
2270
2274
|
Returns:
|
|
2271
|
-
GeneralManager: The manager
|
|
2275
|
+
GeneralManager | None: The readable manager, or None for missing
|
|
2276
|
+
or unreadable targets.
|
|
2272
2277
|
"""
|
|
2273
|
-
|
|
2278
|
+
try:
|
|
2279
|
+
instance = generalManagerClass(**identification)
|
|
2280
|
+
except (ObjectDoesNotExist, RequestNotFoundError):
|
|
2281
|
+
# Missing and unreadable targets share the same public response.
|
|
2282
|
+
return None
|
|
2283
|
+
try:
|
|
2284
|
+
readable = _can_read_instance_for_user_fn(instance, info.context.user)
|
|
2285
|
+
except RequestNotFoundError:
|
|
2286
|
+
return None
|
|
2287
|
+
except AttributeEvaluationError as error:
|
|
2288
|
+
# Request-backed fields hydrate lazily during the row gate.
|
|
2289
|
+
if isinstance(error.__cause__, RequestNotFoundError):
|
|
2290
|
+
return None
|
|
2291
|
+
raise
|
|
2292
|
+
return instance if readable else None
|
|
2274
2293
|
|
|
2275
2294
|
cls._query_fields[item_field_name] = item_field
|
|
2276
2295
|
cls._query_fields[f"resolve_{item_field_name}"] = resolver
|
|
@@ -2658,6 +2677,12 @@ class GraphQL:
|
|
|
2658
2677
|
continue
|
|
2659
2678
|
identification = message.get("identification")
|
|
2660
2679
|
if action == "refresh" and identification is None:
|
|
2680
|
+
if not await asyncio.to_thread(
|
|
2681
|
+
_can_read_class_for_user_fn,
|
|
2682
|
+
generalManagerClass,
|
|
2683
|
+
subscription_user,
|
|
2684
|
+
):
|
|
2685
|
+
continue
|
|
2661
2686
|
clear_capability_context(info)
|
|
2662
2687
|
yield SubscriptionEvent(item=None, action=action)
|
|
2663
2688
|
continue
|
|
@@ -0,0 +1,168 @@
|
|
|
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 typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from graphql import GraphQLError
|
|
9
|
+
|
|
10
|
+
from general_manager.bucket.base_bucket import Bucket
|
|
11
|
+
from general_manager.bucket.request_bucket import RequestBucket
|
|
12
|
+
from general_manager.manager.general_manager import GeneralManager
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from graphene import ResolveInfo
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class QueryFieldPermissionError(GraphQLError):
|
|
19
|
+
"""A requested operand is not authorized on the candidate scope."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, field: str) -> None:
|
|
22
|
+
super().__init__(f"Permission denied to use query field '{field}'.")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
_LIMIT_ERROR = "Query field authorization candidate limit exceeded."
|
|
26
|
+
_AMBIGUOUS_ERROR = "Cannot authorize ambiguous query relation."
|
|
27
|
+
_RELATION_ERROR = "Permission denied to traverse query relation."
|
|
28
|
+
INCOMPLETE_ERROR = "Query field authorization requires a complete candidate set."
|
|
29
|
+
CUSTOM_PROJECTION_ERROR = (
|
|
30
|
+
"Cannot authorize fields of a custom search document projection."
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Bound field/path decisions; bucket materialization and row checks precede this.
|
|
34
|
+
MAX_QUERY_PERMISSION_CANDIDATES = 1000
|
|
35
|
+
_LOOKUPS = {
|
|
36
|
+
"exact",
|
|
37
|
+
"iexact",
|
|
38
|
+
"in",
|
|
39
|
+
"isnull",
|
|
40
|
+
"lt",
|
|
41
|
+
"lte",
|
|
42
|
+
"gt",
|
|
43
|
+
"gte",
|
|
44
|
+
"contains",
|
|
45
|
+
"icontains",
|
|
46
|
+
"startswith",
|
|
47
|
+
"istartswith",
|
|
48
|
+
"endswith",
|
|
49
|
+
"iendswith",
|
|
50
|
+
"range",
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def authorize_query_fields(
|
|
55
|
+
candidates: Iterable[GeneralManager], info: ResolveInfo, paths: Iterable[str]
|
|
56
|
+
) -> None:
|
|
57
|
+
"""Check all operands against every row-visible candidate, never just hits.
|
|
58
|
+
|
|
59
|
+
Related rows require their own row permission as well as field permission.
|
|
60
|
+
Failure leaves the original candidate set unchanged and rejects the query.
|
|
61
|
+
"""
|
|
62
|
+
from general_manager.api.graphql_relations import (
|
|
63
|
+
resolve_general_manager_type,
|
|
64
|
+
get_graphql_manager_registry,
|
|
65
|
+
)
|
|
66
|
+
from general_manager.api.graphql_resolvers import (
|
|
67
|
+
can_read_instance,
|
|
68
|
+
check_read_permission,
|
|
69
|
+
relation_id_alias_field,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
normalized = set()
|
|
73
|
+
for path in paths:
|
|
74
|
+
parts = path.split("__")
|
|
75
|
+
if parts:
|
|
76
|
+
normalized.add(tuple(parts))
|
|
77
|
+
if not normalized:
|
|
78
|
+
return
|
|
79
|
+
decisions = 0
|
|
80
|
+
|
|
81
|
+
def check(instance: GeneralManager, parts: tuple[str, ...]) -> None:
|
|
82
|
+
nonlocal decisions
|
|
83
|
+
decisions += 1
|
|
84
|
+
if decisions > MAX_QUERY_PERMISSION_CANDIDATES:
|
|
85
|
+
raise GraphQLError(_LIMIT_ERROR)
|
|
86
|
+
field, *rest = parts
|
|
87
|
+
attributes = instance.Interface.get_attribute_types()
|
|
88
|
+
# Backend collection lookup names can differ from public manager names.
|
|
89
|
+
aliases = [
|
|
90
|
+
name
|
|
91
|
+
for name, metadata in attributes.items()
|
|
92
|
+
if metadata.get("filter_lookup", name) == field
|
|
93
|
+
]
|
|
94
|
+
names = set(aliases or [field])
|
|
95
|
+
for name in tuple(names):
|
|
96
|
+
relation = relation_id_alias_field(type(instance), name)
|
|
97
|
+
if relation is None and name.endswith("_id"):
|
|
98
|
+
alias = name.removesuffix("_id")
|
|
99
|
+
metadata: dict[str, object] = dict(attributes.get(alias, {}))
|
|
100
|
+
if (
|
|
101
|
+
resolve_general_manager_type(
|
|
102
|
+
metadata.get("type"), get_graphql_manager_registry()
|
|
103
|
+
)
|
|
104
|
+
is not None
|
|
105
|
+
):
|
|
106
|
+
relation = alias
|
|
107
|
+
if relation is not None:
|
|
108
|
+
names.add(relation)
|
|
109
|
+
known_fields = set(attributes) | set(instance.identification)
|
|
110
|
+
known_fields.update(instance.Interface.get_graph_ql_properties())
|
|
111
|
+
known_fields.update(instance.Interface.get_attributes())
|
|
112
|
+
if not names.intersection(known_fields):
|
|
113
|
+
raise QueryFieldPermissionError(field)
|
|
114
|
+
if any(not check_read_permission(instance, info, name) for name in names):
|
|
115
|
+
raise QueryFieldPermissionError(field)
|
|
116
|
+
if not rest:
|
|
117
|
+
return
|
|
118
|
+
if len(aliases) > 1:
|
|
119
|
+
raise GraphQLError(_AMBIGUOUS_ERROR)
|
|
120
|
+
field_metadata: dict[str, object] = dict(
|
|
121
|
+
attributes.get(aliases[0] if aliases else field, {})
|
|
122
|
+
)
|
|
123
|
+
if (
|
|
124
|
+
len(rest) == 1
|
|
125
|
+
and rest[0] in _LOOKUPS
|
|
126
|
+
and (
|
|
127
|
+
(field.endswith("_id") and len(names) > 1)
|
|
128
|
+
or (
|
|
129
|
+
field_metadata.get("type") is not None
|
|
130
|
+
and resolve_general_manager_type(
|
|
131
|
+
field_metadata.get("type"), get_graphql_manager_registry()
|
|
132
|
+
)
|
|
133
|
+
is None
|
|
134
|
+
and field_metadata.get("relation_kind")
|
|
135
|
+
not in {"direct", "collection"}
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
):
|
|
139
|
+
return
|
|
140
|
+
related_type = resolve_general_manager_type(
|
|
141
|
+
field_metadata.get("type"), get_graphql_manager_registry()
|
|
142
|
+
)
|
|
143
|
+
if len(rest) == 1 and rest[0] in _LOOKUPS and related_type is not None:
|
|
144
|
+
related_fields = set(related_type.Interface.get_attribute_types())
|
|
145
|
+
related_fields.update(related_type.Interface.get_attributes())
|
|
146
|
+
related_fields.update(related_type.Interface.get_graph_ql_properties())
|
|
147
|
+
if rest[0] not in related_fields:
|
|
148
|
+
return
|
|
149
|
+
value = getattr(instance, aliases[0] if aliases else field)
|
|
150
|
+
if value is None:
|
|
151
|
+
return
|
|
152
|
+
related = value if isinstance(value, (Bucket, list, tuple, set)) else [value]
|
|
153
|
+
for member in related:
|
|
154
|
+
if not isinstance(member, GeneralManager):
|
|
155
|
+
# A lookup is an operator only after resolving its preceding
|
|
156
|
+
# scalar field. A relation's field named "contains" is a field.
|
|
157
|
+
if len(rest) == 1 and rest[0] in _LOOKUPS:
|
|
158
|
+
continue
|
|
159
|
+
raise GraphQLError(_RELATION_ERROR)
|
|
160
|
+
if not can_read_instance(member, info):
|
|
161
|
+
raise GraphQLError(_RELATION_ERROR)
|
|
162
|
+
check(member, tuple(rest))
|
|
163
|
+
|
|
164
|
+
for candidate in candidates:
|
|
165
|
+
for normalized_parts in sorted(normalized):
|
|
166
|
+
check(candidate, normalized_parts)
|
|
167
|
+
if isinstance(candidates, RequestBucket) and not candidates.response_is_complete:
|
|
168
|
+
raise GraphQLError(INCOMPLETE_ERROR)
|
{generalmanager-0.87.0 → generalmanager-0.87.1}/src/general_manager/api/graphql_resolvers.py
RENAMED
|
@@ -36,6 +36,7 @@ from graphql import GraphQLError, OperationType
|
|
|
36
36
|
from graphql.language.ast import FieldNode, FragmentSpreadNode, InlineFragmentNode
|
|
37
37
|
|
|
38
38
|
from general_manager.logging import get_logger
|
|
39
|
+
from general_manager.conf import get_setting
|
|
39
40
|
from general_manager.bucket.base_bucket import Bucket
|
|
40
41
|
from general_manager.bucket._materialized_bucket import MaterializedBucket
|
|
41
42
|
from general_manager.bucket.group_bucket import GroupBucket
|
|
@@ -822,6 +823,38 @@ class InvalidPaginationValueError(ValueError):
|
|
|
822
823
|
super().__init__(f"{field_name} must be a positive integer")
|
|
823
824
|
|
|
824
825
|
|
|
826
|
+
class PaginationLimitExceededError(ValueError):
|
|
827
|
+
"""Raised when an explicit page exceeds the server maximum."""
|
|
828
|
+
|
|
829
|
+
def __init__(self, maximum: int) -> None:
|
|
830
|
+
super().__init__(f"pageSize must not exceed {maximum}")
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
class InvalidPaginationConfigurationError(ValueError):
|
|
834
|
+
"""Raised when configured pagination cannot provide finite valid pages."""
|
|
835
|
+
|
|
836
|
+
def __init__(self, setting: str) -> None:
|
|
837
|
+
super().__init__(
|
|
838
|
+
f"{setting} must be a positive integer, with default <= maximum"
|
|
839
|
+
)
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
def _pagination_sizes() -> tuple[int, int]:
|
|
843
|
+
default = get_setting("GRAPHQL_DEFAULT_PAGE_SIZE", 10)
|
|
844
|
+
maximum = get_setting("GRAPHQL_MAX_PAGE_SIZE", 100)
|
|
845
|
+
for name, value in (
|
|
846
|
+
("GRAPHQL_DEFAULT_PAGE_SIZE", default),
|
|
847
|
+
("GRAPHQL_MAX_PAGE_SIZE", maximum),
|
|
848
|
+
):
|
|
849
|
+
if not isinstance(value, int) or isinstance(value, bool) or value <= 0:
|
|
850
|
+
raise InvalidPaginationConfigurationError(name)
|
|
851
|
+
default = cast(int, default)
|
|
852
|
+
maximum = cast(int, maximum)
|
|
853
|
+
if default > maximum:
|
|
854
|
+
raise InvalidPaginationConfigurationError("GRAPHQL_DEFAULT_PAGE_SIZE")
|
|
855
|
+
return default, maximum
|
|
856
|
+
|
|
857
|
+
|
|
825
858
|
@dataclass(frozen=True, slots=True)
|
|
826
859
|
class EffectivePagination:
|
|
827
860
|
"""Normalized public pagination arguments and their observable defaults."""
|
|
@@ -849,19 +882,19 @@ def normalize_pagination(
|
|
|
849
882
|
page: int | None,
|
|
850
883
|
page_size: int | None,
|
|
851
884
|
) -> EffectivePagination:
|
|
852
|
-
"""
|
|
853
|
-
|
|
885
|
+
"""Resolve finite server defaults and reject oversized explicit pages."""
|
|
886
|
+
default, maximum = _pagination_sizes()
|
|
854
887
|
for field_name, value in (("page", page), ("pageSize", page_size)):
|
|
855
888
|
if value is not None and (
|
|
856
889
|
not isinstance(value, int) or isinstance(value, bool) or value <= 0
|
|
857
890
|
):
|
|
858
891
|
raise InvalidPaginationValueError(field_name)
|
|
859
|
-
if not
|
|
860
|
-
|
|
892
|
+
if page_size is not None and page_size > maximum:
|
|
893
|
+
raise PaginationLimitExceededError(maximum)
|
|
861
894
|
return EffectivePagination(
|
|
862
895
|
requested=True,
|
|
863
896
|
page=1 if page is None else page,
|
|
864
|
-
page_size=
|
|
897
|
+
page_size=default if page_size is None else page_size,
|
|
865
898
|
)
|
|
866
899
|
|
|
867
900
|
|
|
@@ -922,6 +955,9 @@ def _forward_remote_request_controls(
|
|
|
922
955
|
terms = order_by_to_sort_terms(order_by)
|
|
923
956
|
except GraphQLOrderingInputError as exc:
|
|
924
957
|
raise GraphQLError(str(exc)) from exc
|
|
958
|
+
if not isinstance(queryset, RequestBucket) or queryset.request_plan is None:
|
|
959
|
+
# Concrete snapshots must be paginated locally, never filtered by controls.
|
|
960
|
+
return queryset, False
|
|
925
961
|
controls: dict[str, object] = {}
|
|
926
962
|
if pagination.requested:
|
|
927
963
|
controls["page"] = pagination.page
|
|
@@ -943,8 +979,8 @@ def apply_pagination(
|
|
|
943
979
|
"""
|
|
944
980
|
Return a paginated slice of *queryset*.
|
|
945
981
|
|
|
946
|
-
|
|
947
|
-
|
|
982
|
+
Omitted controls use page 1 and the configured finite default size (10).
|
|
983
|
+
Explicit sizes above the configured maximum (100) are rejected.
|
|
948
984
|
Zero, negative, boolean, and non-integer controls raise ``ValueError``
|
|
949
985
|
before slicing.
|
|
950
986
|
Already-empty grouped buckets are returned unchanged when pagination is
|
|
@@ -1268,6 +1304,34 @@ def _is_supported_grouped_annotation(
|
|
|
1268
1304
|
)
|
|
1269
1305
|
|
|
1270
1306
|
|
|
1307
|
+
def can_read_class_for_user(
|
|
1308
|
+
manager_class: type[GeneralManager],
|
|
1309
|
+
user: object,
|
|
1310
|
+
) -> bool:
|
|
1311
|
+
"""Authorize an identity-less notification through the class read gate.
|
|
1312
|
+
|
|
1313
|
+
Construct fresh permissions for every event so revocations take effect.
|
|
1314
|
+
Callers in async code must offload this potentially database-backed check.
|
|
1315
|
+
"""
|
|
1316
|
+
from django.contrib.auth import get_user_model
|
|
1317
|
+
|
|
1318
|
+
user_model = get_user_model()
|
|
1319
|
+
if isinstance(user, user_model):
|
|
1320
|
+
if user.pk is None:
|
|
1321
|
+
return False
|
|
1322
|
+
user = (
|
|
1323
|
+
user_model._default_manager.using(user._state.db).filter(pk=user.pk).first()
|
|
1324
|
+
)
|
|
1325
|
+
if user is None or not getattr(user, "is_active", True):
|
|
1326
|
+
return False
|
|
1327
|
+
permission_class: type[BasePermission] | None = getattr(
|
|
1328
|
+
manager_class, "Permission", None
|
|
1329
|
+
)
|
|
1330
|
+
if permission_class is not None:
|
|
1331
|
+
return permission_class(manager_class, user).check_operation_permission("read")
|
|
1332
|
+
return True
|
|
1333
|
+
|
|
1334
|
+
|
|
1271
1335
|
def can_read_instance_for_user(
|
|
1272
1336
|
instance: GeneralManager,
|
|
1273
1337
|
user: object,
|
|
@@ -1560,9 +1624,8 @@ def create_list_resolver(
|
|
|
1560
1624
|
``pageInfo`` contains ``total_count``, ``page_size``,
|
|
1561
1625
|
``current_page``, and ``total_pages`` using the Python-side field names;
|
|
1562
1626
|
Graphene exposes them as camelCase in the GraphQL schema. ``current_page``
|
|
1563
|
-
reports effective pagination values:
|
|
1564
|
-
the
|
|
1565
|
-
lists remain unpaginated with ``page_size=None``. ``total_pages`` is
|
|
1627
|
+
reports effective pagination values: omitted controls default to page 1
|
|
1628
|
+
and the server-configured finite page size (10 by default). ``total_pages`` is
|
|
1566
1629
|
zero for an exact empty result and ``None`` when the source total is
|
|
1567
1630
|
incomplete. Invalid pagination values raise
|
|
1568
1631
|
``InvalidPaginationValueError`` before slicing.
|
|
@@ -1579,6 +1642,7 @@ def create_list_resolver(
|
|
|
1579
1642
|
group_by: list[str] | None = None,
|
|
1580
1643
|
include_inactive: bool = False,
|
|
1581
1644
|
) -> ListResolverPayload:
|
|
1645
|
+
effective_pagination = normalize_pagination(page, page_size)
|
|
1582
1646
|
_ensure_as_of_compatible(self)
|
|
1583
1647
|
base_queryset = base_getter(self, include_inactive)
|
|
1584
1648
|
if base_queryset is None:
|
|
@@ -1606,7 +1670,12 @@ def create_list_resolver(
|
|
|
1606
1670
|
exclude,
|
|
1607
1671
|
filter_normalizer=bound_filter_normalizer,
|
|
1608
1672
|
)
|
|
1609
|
-
|
|
1673
|
+
from general_manager.api.graphql_query_permissions import authorize_query_fields
|
|
1674
|
+
|
|
1675
|
+
operand_paths = (
|
|
1676
|
+
set(plan.filters) | set(plan.excludes) | set(plan.normalized_excludes)
|
|
1677
|
+
)
|
|
1678
|
+
operand_paths.update(term.field for term in order_by_to_sort_terms(order_by))
|
|
1610
1679
|
from general_manager.interface import CalculationInterface
|
|
1611
1680
|
|
|
1612
1681
|
interface = getattr(manager_class, "Interface", None)
|
|
@@ -1614,30 +1683,105 @@ def create_list_resolver(
|
|
|
1614
1683
|
remote_ordering_forwarded = False
|
|
1615
1684
|
request_provenance: RequestPaginationProvenance | None = None
|
|
1616
1685
|
authorization_result: ReadAuthorizationResult[GeneralManager]
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1686
|
+
complete_disjunction: ReadAuthorizationPreparation[GeneralManager] | None = None
|
|
1687
|
+
if is_request_source and not operand_paths:
|
|
1688
|
+
request_permission_plan = get_read_permission_filter(manager_class, info)
|
|
1689
|
+
if (
|
|
1690
|
+
request_permission_plan.decision != "deny_all"
|
|
1691
|
+
and len(request_permission_plan.filters) > 1
|
|
1692
|
+
):
|
|
1693
|
+
# Check completeness before RequestBucket union loses provenance.
|
|
1694
|
+
# No client predicates are evaluated on this local union.
|
|
1695
|
+
combined = MaterializedBucket(manager_class, [])
|
|
1696
|
+
for permission_filter in request_permission_plan.filters:
|
|
1697
|
+
branch = base_queryset.filter(
|
|
1698
|
+
**permission_filter.get("filter", {})
|
|
1699
|
+
).exclude(**permission_filter.get("exclude", {}))
|
|
1700
|
+
if (
|
|
1701
|
+
isinstance(branch, RequestBucket)
|
|
1702
|
+
and not branch.response_is_complete
|
|
1703
|
+
):
|
|
1704
|
+
operation = _requested_request_global_operation(
|
|
1705
|
+
effective_pagination, group_by, order_by
|
|
1706
|
+
)
|
|
1707
|
+
raise _request_global_operation_error(operation or "pagination")
|
|
1708
|
+
combined = combined | MaterializedBucket(manager_class, branch)
|
|
1709
|
+
shape = get_backend_shape(manager_class)
|
|
1710
|
+
complete_disjunction = ReadAuthorizationPreparation(
|
|
1711
|
+
queryset=combined,
|
|
1712
|
+
permission_plan=request_permission_plan,
|
|
1713
|
+
backend_shape=shape,
|
|
1714
|
+
instance_check_reasons=resolve_instance_check_reasons(
|
|
1715
|
+
request_permission_plan, backend_shape=shape
|
|
1716
|
+
),
|
|
1717
|
+
)
|
|
1718
|
+
if operand_paths and is_request_source:
|
|
1719
|
+
operand_preparation = prepare_read_authorization(
|
|
1720
|
+
base_queryset, manager_class, info
|
|
1626
1721
|
)
|
|
1722
|
+
# Inspect the permission-filtered source before a final instance
|
|
1723
|
+
# gate can materialize it and discard upstream provenance. Never
|
|
1724
|
+
# touch the original source when the plan denies all rows.
|
|
1627
1725
|
if (
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1726
|
+
operand_preparation.permission_plan.decision != "deny_all"
|
|
1727
|
+
and isinstance(operand_preparation.queryset, RequestBucket)
|
|
1728
|
+
and not operand_preparation.queryset.response_is_complete
|
|
1631
1729
|
):
|
|
1632
|
-
|
|
1730
|
+
from general_manager.api.graphql_query_permissions import (
|
|
1731
|
+
INCOMPLETE_ERROR,
|
|
1732
|
+
)
|
|
1733
|
+
|
|
1734
|
+
raise GraphQLError(INCOMPLETE_ERROR)
|
|
1735
|
+
operand_candidates = finalize_read_authorization(
|
|
1736
|
+
operand_preparation, manager_class, info, source="query_fields"
|
|
1737
|
+
).queryset
|
|
1738
|
+
authorize_query_fields(operand_candidates, info, operand_paths)
|
|
1739
|
+
if isinstance(interface, type) and issubclass(interface, CalculationInterface):
|
|
1633
1740
|
authorization_result = apply_read_authorization(
|
|
1634
|
-
|
|
1635
|
-
manager_class,
|
|
1636
|
-
info,
|
|
1637
|
-
source="list",
|
|
1741
|
+
base_queryset, manager_class, info, source="list"
|
|
1638
1742
|
)
|
|
1639
1743
|
qs = authorization_result.queryset
|
|
1744
|
+
authorize_query_fields(qs, info, operand_paths)
|
|
1745
|
+
# Freeze row authorization before constructor-input filters can
|
|
1746
|
+
# replace the calculation bucket's permission constraints.
|
|
1747
|
+
if operand_paths:
|
|
1748
|
+
qs = qs.with_instances(qs)
|
|
1749
|
+
input_plan, deferred_plan = partition_calculation_query_plan(
|
|
1750
|
+
manager_class, plan
|
|
1751
|
+
)
|
|
1752
|
+
|
|
1753
|
+
def canonical_inputs(mapping: GraphQLFilterMapping) -> GraphQLFilterMapping:
|
|
1754
|
+
normalized = {}
|
|
1755
|
+
for lookup, value in mapping.items():
|
|
1756
|
+
root, separator, suffix = lookup.partition("__")
|
|
1757
|
+
alias = (
|
|
1758
|
+
interface.input_fields.get(root.removesuffix("_id"))
|
|
1759
|
+
if root.endswith("_id")
|
|
1760
|
+
else None
|
|
1761
|
+
)
|
|
1762
|
+
if alias is not None and safe_issubclass(
|
|
1763
|
+
alias.type, GeneralManager
|
|
1764
|
+
):
|
|
1765
|
+
lookup = (
|
|
1766
|
+
root.removesuffix("_id")
|
|
1767
|
+
+ "__id"
|
|
1768
|
+
+ (separator + suffix if separator else "")
|
|
1769
|
+
)
|
|
1770
|
+
normalized[lookup] = value
|
|
1771
|
+
return normalized
|
|
1772
|
+
|
|
1773
|
+
input_plan = QueryParameterPlan(
|
|
1774
|
+
canonical_inputs(input_plan.filters),
|
|
1775
|
+
canonical_inputs(input_plan.excludes),
|
|
1776
|
+
canonical_inputs(input_plan.normalized_excludes),
|
|
1777
|
+
)
|
|
1778
|
+
qs = apply_query_parameter_plan(qs, input_plan, None)
|
|
1640
1779
|
qs = apply_query_parameter_plan(qs, deferred_plan, None)
|
|
1780
|
+
elif complete_disjunction is not None:
|
|
1781
|
+
authorization_result = finalize_read_authorization(
|
|
1782
|
+
complete_disjunction, manager_class, info, source="list"
|
|
1783
|
+
)
|
|
1784
|
+
qs = authorization_result.queryset
|
|
1641
1785
|
elif is_request_source:
|
|
1642
1786
|
permission_plan = get_read_permission_filter(manager_class, info)
|
|
1643
1787
|
if permission_plan.decision == "deny_all":
|
|
@@ -1692,12 +1836,6 @@ def create_list_resolver(
|
|
|
1692
1836
|
)
|
|
1693
1837
|
assert request_provenance is not None
|
|
1694
1838
|
if request_provenance.is_partial:
|
|
1695
|
-
if effective_pagination.requested and (
|
|
1696
|
-
request_provenance.page != effective_pagination.page
|
|
1697
|
-
or request_provenance.page_size
|
|
1698
|
-
!= effective_pagination.page_size
|
|
1699
|
-
):
|
|
1700
|
-
raise _request_global_operation_error("pagination")
|
|
1701
1839
|
if group_by is not None:
|
|
1702
1840
|
raise _request_global_operation_error("grouping")
|
|
1703
1841
|
if order_by is not None and not remote_ordering_forwarded:
|
|
@@ -1707,6 +1845,12 @@ def create_list_resolver(
|
|
|
1707
1845
|
raise GraphQLError(str(exc)) from exc
|
|
1708
1846
|
if has_ordering:
|
|
1709
1847
|
raise _request_global_operation_error("ordering")
|
|
1848
|
+
if effective_pagination.requested and (
|
|
1849
|
+
request_provenance.page != effective_pagination.page
|
|
1850
|
+
or request_provenance.page_size
|
|
1851
|
+
!= effective_pagination.page_size
|
|
1852
|
+
):
|
|
1853
|
+
raise _request_global_operation_error("pagination")
|
|
1710
1854
|
authorization_result = finalize_read_authorization(
|
|
1711
1855
|
authorization_preparation,
|
|
1712
1856
|
manager_class,
|
|
@@ -1732,6 +1876,7 @@ def create_list_resolver(
|
|
|
1732
1876
|
source="list",
|
|
1733
1877
|
)
|
|
1734
1878
|
qs = authorization_result.queryset
|
|
1879
|
+
authorize_query_fields(qs, info, operand_paths)
|
|
1735
1880
|
qs = apply_query_parameter_plan(qs, plan, None)
|
|
1736
1881
|
if grouping_validator is not None:
|
|
1737
1882
|
grouping_validator(qs, group_by, order_by, info)
|
|
@@ -1751,16 +1896,6 @@ def create_list_resolver(
|
|
|
1751
1896
|
total_count = request_provenance.total_count
|
|
1752
1897
|
|
|
1753
1898
|
metadata_pagination = effective_pagination
|
|
1754
|
-
if (
|
|
1755
|
-
not effective_pagination.requested
|
|
1756
|
-
and request_provenance is not None
|
|
1757
|
-
and request_provenance.page is not None
|
|
1758
|
-
):
|
|
1759
|
-
metadata_pagination = EffectivePagination(
|
|
1760
|
-
requested=True,
|
|
1761
|
-
page=request_provenance.page,
|
|
1762
|
-
page_size=request_provenance.page_size,
|
|
1763
|
-
)
|
|
1764
1899
|
|
|
1765
1900
|
upstream_page_matches = (
|
|
1766
1901
|
request_provenance is not None
|
|
@@ -1770,7 +1905,7 @@ def create_list_resolver(
|
|
|
1770
1905
|
and group_by is None
|
|
1771
1906
|
)
|
|
1772
1907
|
qs_paginated = (
|
|
1773
|
-
qs_sorted
|
|
1908
|
+
qs_sorted[: cast(int, metadata_pagination.page_size)]
|
|
1774
1909
|
if upstream_page_matches
|
|
1775
1910
|
else apply_pagination(
|
|
1776
1911
|
qs_sorted,
|