infrahub-server 1.6.3__py3-none-any.whl → 1.7.0__py3-none-any.whl
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.
- infrahub/actions/tasks.py +4 -2
- infrahub/api/exceptions.py +2 -2
- infrahub/api/schema.py +3 -1
- infrahub/artifacts/tasks.py +1 -0
- infrahub/auth.py +2 -2
- infrahub/cli/db.py +54 -28
- infrahub/computed_attribute/gather.py +3 -4
- infrahub/computed_attribute/tasks.py +23 -6
- infrahub/config.py +8 -0
- infrahub/constants/enums.py +12 -0
- infrahub/core/account.py +4 -4
- infrahub/core/attribute.py +106 -108
- infrahub/core/branch/models.py +44 -71
- infrahub/core/branch/tasks.py +5 -3
- infrahub/core/changelog/diff.py +1 -20
- infrahub/core/changelog/models.py +0 -7
- infrahub/core/constants/__init__.py +17 -0
- infrahub/core/constants/database.py +0 -1
- infrahub/core/constants/schema.py +0 -1
- infrahub/core/convert_object_type/repository_conversion.py +3 -4
- infrahub/core/diff/branch_differ.py +1 -1
- infrahub/core/diff/conflict_transferer.py +1 -1
- infrahub/core/diff/data_check_synchronizer.py +4 -3
- infrahub/core/diff/enricher/cardinality_one.py +2 -2
- infrahub/core/diff/enricher/hierarchy.py +1 -1
- infrahub/core/diff/enricher/labels.py +1 -1
- infrahub/core/diff/merger/merger.py +28 -2
- infrahub/core/diff/merger/serializer.py +3 -10
- infrahub/core/diff/model/diff.py +1 -1
- infrahub/core/diff/query/merge.py +376 -135
- infrahub/core/diff/repository/repository.py +3 -1
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/graph/constraints.py +3 -3
- infrahub/core/graph/schema.py +2 -12
- infrahub/core/ipam/reconciler.py +8 -6
- infrahub/core/ipam/utilization.py +8 -15
- infrahub/core/manager.py +133 -152
- infrahub/core/merge.py +1 -1
- infrahub/core/metadata/__init__.py +0 -0
- infrahub/core/metadata/interface.py +37 -0
- infrahub/core/metadata/model.py +31 -0
- infrahub/core/metadata/query/__init__.py +0 -0
- infrahub/core/metadata/query/node_metadata.py +301 -0
- infrahub/core/migrations/graph/__init__.py +4 -0
- infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -12
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -12
- infrahub/core/migrations/graph/m017_add_core_profile.py +5 -2
- infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -1
- infrahub/core/migrations/graph/m019_restore_rels_to_time.py +0 -10
- infrahub/core/migrations/graph/m020_duplicate_edges.py +0 -8
- infrahub/core/migrations/graph/m025_uniqueness_nulls.py +2 -1
- infrahub/core/migrations/graph/m026_0000_prefix_fix.py +2 -1
- infrahub/core/migrations/graph/m029_duplicates_cleanup.py +0 -1
- infrahub/core/migrations/graph/m031_check_number_attributes.py +2 -2
- infrahub/core/migrations/graph/m038_redo_0000_prefix_fix.py +2 -1
- infrahub/core/migrations/graph/m041_deleted_dup_edges.py +1 -1
- infrahub/core/migrations/graph/m049_remove_is_visible_relationship.py +53 -0
- infrahub/core/migrations/graph/m050_backfill_vertex_metadata.py +168 -0
- infrahub/core/migrations/query/__init__.py +2 -2
- infrahub/core/migrations/query/attribute_add.py +17 -6
- infrahub/core/migrations/query/attribute_remove.py +19 -5
- infrahub/core/migrations/query/attribute_rename.py +21 -5
- infrahub/core/migrations/query/node_duplicate.py +19 -4
- infrahub/core/migrations/query/schema_attribute_update.py +1 -1
- infrahub/core/migrations/schema/attribute_kind_update.py +21 -2
- infrahub/core/migrations/schema/attribute_name_update.py +1 -1
- infrahub/core/migrations/schema/attribute_supports_profile.py +5 -3
- infrahub/core/migrations/schema/models.py +3 -0
- infrahub/core/migrations/schema/node_attribute_add.py +5 -2
- infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
- infrahub/core/migrations/schema/node_kind_update.py +1 -1
- infrahub/core/migrations/schema/node_remove.py +24 -2
- infrahub/core/migrations/schema/tasks.py +4 -1
- infrahub/core/migrations/shared.py +13 -6
- infrahub/core/models.py +6 -6
- infrahub/core/node/__init__.py +157 -58
- infrahub/core/node/base.py +9 -5
- infrahub/core/node/create.py +7 -3
- infrahub/core/node/delete_validator.py +1 -1
- infrahub/core/node/standard.py +100 -14
- infrahub/core/order.py +30 -0
- infrahub/core/property.py +0 -1
- infrahub/core/protocols.py +1 -0
- infrahub/core/protocols_base.py +10 -2
- infrahub/core/query/__init__.py +5 -3
- infrahub/core/query/attribute.py +164 -49
- infrahub/core/query/branch.py +58 -70
- infrahub/core/query/delete.py +1 -1
- infrahub/core/query/diff.py +7 -7
- infrahub/core/query/ipam.py +104 -43
- infrahub/core/query/node.py +1072 -281
- infrahub/core/query/relationship.py +531 -325
- infrahub/core/query/resource_manager.py +107 -18
- infrahub/core/query/standard_node.py +25 -5
- infrahub/core/query/utils.py +2 -4
- infrahub/core/relationship/constraints/count.py +1 -1
- infrahub/core/relationship/constraints/peer_kind.py +1 -1
- infrahub/core/relationship/constraints/peer_parent.py +1 -1
- infrahub/core/relationship/constraints/peer_relatives.py +1 -1
- infrahub/core/relationship/constraints/profiles_kind.py +1 -1
- infrahub/core/relationship/constraints/profiles_removal.py +168 -0
- infrahub/core/relationship/model.py +293 -139
- infrahub/core/schema/attribute_schema.py +2 -2
- infrahub/core/schema/basenode_schema.py +3 -0
- infrahub/core/schema/definitions/core/__init__.py +8 -2
- infrahub/core/schema/definitions/core/account.py +10 -10
- infrahub/core/schema/definitions/core/artifact.py +14 -8
- infrahub/core/schema/definitions/core/check.py +10 -4
- infrahub/core/schema/definitions/core/generator.py +26 -6
- infrahub/core/schema/definitions/core/graphql_query.py +1 -1
- infrahub/core/schema/definitions/core/group.py +9 -2
- infrahub/core/schema/definitions/core/ipam.py +80 -10
- infrahub/core/schema/definitions/core/menu.py +41 -7
- infrahub/core/schema/definitions/core/permission.py +16 -2
- infrahub/core/schema/definitions/core/profile.py +16 -2
- infrahub/core/schema/definitions/core/propose_change.py +24 -4
- infrahub/core/schema/definitions/core/propose_change_comment.py +23 -11
- infrahub/core/schema/definitions/core/propose_change_validator.py +50 -21
- infrahub/core/schema/definitions/core/repository.py +10 -0
- infrahub/core/schema/definitions/core/resource_pool.py +8 -1
- infrahub/core/schema/definitions/core/template.py +19 -2
- infrahub/core/schema/definitions/core/transform.py +11 -5
- infrahub/core/schema/definitions/core/webhook.py +27 -9
- infrahub/core/schema/manager.py +63 -43
- infrahub/core/schema/relationship_schema.py +6 -2
- infrahub/core/schema/schema_branch.py +48 -10
- infrahub/core/task/task.py +4 -2
- infrahub/core/utils.py +3 -25
- infrahub/core/validators/aggregated_checker.py +1 -1
- infrahub/core/validators/attribute/choices.py +1 -1
- infrahub/core/validators/attribute/enum.py +1 -1
- infrahub/core/validators/attribute/kind.py +1 -1
- infrahub/core/validators/attribute/length.py +1 -1
- infrahub/core/validators/attribute/min_max.py +1 -1
- infrahub/core/validators/attribute/number_pool.py +1 -1
- infrahub/core/validators/attribute/optional.py +1 -1
- infrahub/core/validators/attribute/regex.py +1 -1
- infrahub/core/validators/determiner.py +3 -3
- infrahub/core/validators/node/attribute.py +1 -1
- infrahub/core/validators/node/relationship.py +1 -1
- infrahub/core/validators/relationship/peer.py +1 -1
- infrahub/database/__init__.py +4 -4
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +2 -0
- infrahub/dependencies/builder/constraint/relationship_manager/profiles_removal.py +8 -0
- infrahub/dependencies/registry.py +2 -0
- infrahub/display_labels/tasks.py +12 -3
- infrahub/git/integrator.py +18 -18
- infrahub/git/tasks.py +1 -1
- infrahub/git/utils.py +1 -1
- infrahub/graphql/constants.py +3 -0
- infrahub/graphql/context.py +1 -1
- infrahub/graphql/field_extractor.py +1 -1
- infrahub/graphql/initialization.py +11 -0
- infrahub/graphql/loaders/account.py +134 -0
- infrahub/graphql/loaders/node.py +5 -12
- infrahub/graphql/loaders/peers.py +5 -7
- infrahub/graphql/manager.py +175 -21
- infrahub/graphql/metadata.py +91 -0
- infrahub/graphql/mutations/account.py +6 -6
- infrahub/graphql/mutations/attribute.py +0 -2
- infrahub/graphql/mutations/branch.py +9 -5
- infrahub/graphql/mutations/computed_attribute.py +1 -1
- infrahub/graphql/mutations/display_label.py +1 -1
- infrahub/graphql/mutations/hfid.py +1 -1
- infrahub/graphql/mutations/ipam.py +4 -6
- infrahub/graphql/mutations/main.py +9 -4
- infrahub/graphql/mutations/profile.py +16 -22
- infrahub/graphql/mutations/proposed_change.py +4 -4
- infrahub/graphql/mutations/relationship.py +40 -10
- infrahub/graphql/mutations/repository.py +14 -12
- infrahub/graphql/mutations/schema.py +2 -2
- infrahub/graphql/order.py +14 -0
- infrahub/graphql/queries/branch.py +62 -6
- infrahub/graphql/queries/resource_manager.py +25 -24
- infrahub/graphql/resolvers/account_metadata.py +84 -0
- infrahub/graphql/resolvers/ipam.py +6 -8
- infrahub/graphql/resolvers/many_relationship.py +77 -35
- infrahub/graphql/resolvers/resolver.py +59 -14
- infrahub/graphql/resolvers/single_relationship.py +87 -23
- infrahub/graphql/subscription/graphql_query.py +2 -0
- infrahub/graphql/types/__init__.py +0 -1
- infrahub/graphql/types/attribute.py +10 -5
- infrahub/graphql/types/branch.py +40 -53
- infrahub/graphql/types/enums.py +3 -0
- infrahub/graphql/types/metadata.py +28 -0
- infrahub/graphql/types/node.py +22 -2
- infrahub/graphql/types/relationship.py +10 -2
- infrahub/graphql/types/standard_node.py +12 -7
- infrahub/hfid/tasks.py +12 -3
- infrahub/lock.py +7 -0
- infrahub/menu/repository.py +1 -1
- infrahub/patch/queries/base.py +1 -1
- infrahub/pools/number.py +1 -8
- infrahub/profiles/gather.py +56 -0
- infrahub/profiles/mandatory_fields_checker.py +116 -0
- infrahub/profiles/models.py +66 -0
- infrahub/profiles/node_applier.py +154 -13
- infrahub/profiles/queries/get_profile_data.py +143 -31
- infrahub/profiles/tasks.py +79 -27
- infrahub/profiles/triggers.py +22 -0
- infrahub/proposed_change/action_checker.py +1 -1
- infrahub/proposed_change/tasks.py +4 -1
- infrahub/services/__init__.py +1 -1
- infrahub/services/adapters/cache/nats.py +1 -1
- infrahub/services/adapters/cache/redis.py +7 -0
- infrahub/tasks/artifact.py +1 -0
- infrahub/transformations/tasks.py +2 -2
- infrahub/trigger/catalogue.py +2 -0
- infrahub/trigger/models.py +1 -0
- infrahub/trigger/setup.py +3 -3
- infrahub/trigger/tasks.py +3 -0
- infrahub/validators/tasks.py +1 -0
- infrahub/webhook/gather.py +1 -1
- infrahub/webhook/models.py +1 -1
- infrahub/webhook/tasks.py +23 -7
- infrahub/workers/dependencies.py +9 -3
- infrahub/workers/infrahub_async.py +13 -4
- infrahub/workflows/catalogue.py +19 -0
- infrahub_sdk/analyzer.py +2 -2
- infrahub_sdk/branch.py +12 -39
- infrahub_sdk/checks.py +4 -4
- infrahub_sdk/client.py +36 -0
- infrahub_sdk/ctl/cli_commands.py +2 -1
- infrahub_sdk/ctl/graphql.py +15 -4
- infrahub_sdk/ctl/utils.py +2 -2
- infrahub_sdk/enums.py +6 -0
- infrahub_sdk/graphql/renderers.py +21 -0
- infrahub_sdk/graphql/utils.py +85 -0
- infrahub_sdk/node/attribute.py +12 -2
- infrahub_sdk/node/constants.py +12 -0
- infrahub_sdk/node/metadata.py +69 -0
- infrahub_sdk/node/node.py +65 -14
- infrahub_sdk/node/property.py +3 -0
- infrahub_sdk/node/related_node.py +37 -5
- infrahub_sdk/node/relationship.py +18 -1
- infrahub_sdk/operation.py +2 -2
- infrahub_sdk/schema/repository.py +1 -2
- infrahub_sdk/transforms.py +2 -2
- infrahub_sdk/types.py +18 -2
- {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/METADATA +17 -16
- {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/RECORD +249 -228
- infrahub_testcontainers/container.py +3 -3
- infrahub_testcontainers/docker-compose-cluster.test.yml +7 -7
- infrahub_testcontainers/docker-compose.test.yml +13 -5
- infrahub_testcontainers/models.py +3 -3
- infrahub_testcontainers/performance_test.py +1 -1
- infrahub/graphql/models.py +0 -6
- {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/entry_points.txt +0 -0
- {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/licenses/LICENSE.txt +0 -0
infrahub/core/node/__init__.py
CHANGED
|
@@ -14,6 +14,7 @@ from infrahub.core.constants import (
|
|
|
14
14
|
GLOBAL_BRANCH_NAME,
|
|
15
15
|
OBJECT_TEMPLATE_NAME_ATTR,
|
|
16
16
|
OBJECT_TEMPLATE_RELATIONSHIP_NAME,
|
|
17
|
+
SYSTEM_USER_ID,
|
|
17
18
|
BranchSupportType,
|
|
18
19
|
ComputedAttributeKind,
|
|
19
20
|
InfrahubKind,
|
|
@@ -22,8 +23,10 @@ from infrahub.core.constants import (
|
|
|
22
23
|
RelationshipKind,
|
|
23
24
|
)
|
|
24
25
|
from infrahub.core.constants.schema import SchemaElementPathType
|
|
26
|
+
from infrahub.core.metadata.interface import MetadataInterface
|
|
27
|
+
from infrahub.core.metadata.model import MetadataInfo
|
|
25
28
|
from infrahub.core.protocols import CoreNumberPool, CoreObjectTemplate
|
|
26
|
-
from infrahub.core.query.node import NodeCheckIDQuery, NodeCreateAllQuery, NodeDeleteQuery,
|
|
29
|
+
from infrahub.core.query.node import NodeCheckIDQuery, NodeCreateAllQuery, NodeDeleteQuery, NodeUpdateMetadataQuery
|
|
27
30
|
from infrahub.core.schema import (
|
|
28
31
|
AttributeSchema,
|
|
29
32
|
GenericSchema,
|
|
@@ -37,15 +40,14 @@ from infrahub.core.schema.attribute_parameters import NumberPoolParameters
|
|
|
37
40
|
from infrahub.core.timestamp import Timestamp
|
|
38
41
|
from infrahub.exceptions import InitializationError, NodeNotFoundError, PoolExhaustedError, ValidationError
|
|
39
42
|
from infrahub.pools.models import NumberPoolLockDefinition
|
|
43
|
+
from infrahub.profiles.mandatory_fields_checker import ProfilesMandatoryFieldGetter
|
|
40
44
|
from infrahub.types import ATTRIBUTE_TYPES
|
|
41
45
|
|
|
42
46
|
from ...graphql.constants import KIND_GRAPHQL_FIELD_NAME
|
|
43
|
-
from ...graphql.models import OrderModel
|
|
44
47
|
from ...log import get_logger
|
|
45
48
|
from ..attribute import BaseAttribute
|
|
46
49
|
from ..query.relationship import RelationshipDeleteAllQuery
|
|
47
50
|
from ..relationship import RelationshipManager
|
|
48
|
-
from ..utils import update_relationships_to
|
|
49
51
|
from .base import BaseNode, BaseNodeMeta, BaseNodeOptions
|
|
50
52
|
from .node_property_attribute import DisplayLabel, HumanFriendlyIdentifier
|
|
51
53
|
|
|
@@ -69,7 +71,7 @@ SchemaProtocol = TypeVar("SchemaProtocol")
|
|
|
69
71
|
log = get_logger()
|
|
70
72
|
|
|
71
73
|
|
|
72
|
-
class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
74
|
+
class Node(BaseNode, MetadataInterface, metaclass=BaseNodeMeta):
|
|
73
75
|
@classmethod
|
|
74
76
|
def __init_subclass_with_meta__(
|
|
75
77
|
cls, _meta: BaseNodeOptions | None = None, default_filter: None = None, **options: dict[str, Any]
|
|
@@ -80,13 +82,14 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
80
82
|
_meta.default_filter = default_filter
|
|
81
83
|
super().__init_subclass_with_meta__(_meta=_meta, **options)
|
|
82
84
|
|
|
83
|
-
def __init__(self, schema: NodeSchema | ProfileSchema | TemplateSchema, branch: Branch, at: Timestamp):
|
|
85
|
+
def __init__(self, schema: NodeSchema | ProfileSchema | TemplateSchema, branch: Branch, at: Timestamp) -> None:
|
|
86
|
+
super().__init__()
|
|
84
87
|
self._schema: NodeSchema | ProfileSchema | TemplateSchema = schema
|
|
85
88
|
self._branch: Branch = branch
|
|
86
89
|
self._at: Timestamp = at
|
|
87
90
|
self._existing: bool = False
|
|
91
|
+
self._metadata = MetadataInfo()
|
|
88
92
|
|
|
89
|
-
self._updated_at: Timestamp | None = None
|
|
90
93
|
self.id: str = None
|
|
91
94
|
self.db_id: str = None
|
|
92
95
|
|
|
@@ -94,6 +97,8 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
94
97
|
self._owner: Node | None = None
|
|
95
98
|
self._is_protected: bool = None
|
|
96
99
|
self._computed_jinja2_attributes: list[str] = []
|
|
100
|
+
self._profile_provided_attrs: set[str] = set()
|
|
101
|
+
self._profile_provided_rels: set[str] = set()
|
|
97
102
|
|
|
98
103
|
self._display_label: DisplayLabel | None = None
|
|
99
104
|
self._human_friendly_id: HumanFriendlyIdentifier | None = None
|
|
@@ -103,6 +108,30 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
103
108
|
self._relationships: list[str] = []
|
|
104
109
|
self._node_changelog: NodeChangelog | None = None
|
|
105
110
|
|
|
111
|
+
def _set_created_at(self, value: Timestamp | None) -> None:
|
|
112
|
+
self._metadata.created_at = value
|
|
113
|
+
|
|
114
|
+
def _set_created_by(self, value: str | None) -> None:
|
|
115
|
+
self._metadata.created_by = value
|
|
116
|
+
|
|
117
|
+
def _set_updated_at(self, value: Timestamp | None) -> None:
|
|
118
|
+
self._metadata.updated_at = value
|
|
119
|
+
|
|
120
|
+
def _set_updated_by(self, value: str | None) -> None:
|
|
121
|
+
self._metadata.updated_by = value
|
|
122
|
+
|
|
123
|
+
def _get_created_at(self) -> Timestamp | None:
|
|
124
|
+
return self._metadata.created_at
|
|
125
|
+
|
|
126
|
+
def _get_created_by(self) -> str | None:
|
|
127
|
+
return self._metadata.created_by
|
|
128
|
+
|
|
129
|
+
def _get_updated_at(self) -> Timestamp | None:
|
|
130
|
+
return self._metadata.updated_at
|
|
131
|
+
|
|
132
|
+
def _get_updated_by(self) -> str | None:
|
|
133
|
+
return self._metadata.updated_by
|
|
134
|
+
|
|
106
135
|
def get_schema(self) -> NonGenericSchemaTypes:
|
|
107
136
|
return self._schema
|
|
108
137
|
|
|
@@ -120,9 +149,6 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
120
149
|
|
|
121
150
|
raise InitializationError("The node has not been saved yet and doesn't have an id")
|
|
122
151
|
|
|
123
|
-
def get_updated_at(self) -> Timestamp | None:
|
|
124
|
-
return self._updated_at
|
|
125
|
-
|
|
126
152
|
def get_attribute(self, name: str) -> BaseAttribute:
|
|
127
153
|
attribute = getattr(self, name)
|
|
128
154
|
if not isinstance(attribute, BaseAttribute):
|
|
@@ -135,6 +161,12 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
135
161
|
raise ValueError(f"{name} is not a relationship of {self.get_kind()}")
|
|
136
162
|
return relationship
|
|
137
163
|
|
|
164
|
+
def get_relationship_by_identifier(self, identifier: str) -> RelationshipManager:
|
|
165
|
+
for rel_schema in self._schema.relationships:
|
|
166
|
+
if rel_schema.identifier == identifier:
|
|
167
|
+
return self.get_relationship(rel_schema.name)
|
|
168
|
+
raise ValueError(f"Unable to find the relationship with the identifier {identifier} for {self.get_kind()}")
|
|
169
|
+
|
|
138
170
|
def uses_profiles(self) -> bool:
|
|
139
171
|
for attr_name in self.get_schema().attribute_names:
|
|
140
172
|
try:
|
|
@@ -490,6 +522,25 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
490
522
|
elif relationship_peers := await relationship.get_peers(db=db):
|
|
491
523
|
fields[relationship_name] = [{"id": peer_id} for peer_id in relationship_peers]
|
|
492
524
|
|
|
525
|
+
async def _get_profile_provided_mandatory_fields(
|
|
526
|
+
self, db: InfrahubDatabase, fields: dict[str, Any]
|
|
527
|
+
) -> tuple[set[str], set[str]]:
|
|
528
|
+
if not isinstance(self._schema, NodeSchema) or "profiles" not in fields:
|
|
529
|
+
return set(), set()
|
|
530
|
+
|
|
531
|
+
mandatory_attrs_to_check = [a for a in self._schema.mandatory_attribute_names if a not in fields.keys()]
|
|
532
|
+
mandatory_rels_to_check = [r for r in self._schema.mandatory_relationship_names if r not in fields.keys()]
|
|
533
|
+
if not mandatory_attrs_to_check and not mandatory_rels_to_check:
|
|
534
|
+
return set(), set()
|
|
535
|
+
|
|
536
|
+
profiles_mandatory_field_getter = ProfilesMandatoryFieldGetter(db=db, branch=self._branch)
|
|
537
|
+
return await profiles_mandatory_field_getter.get_mandatory_fields_from_profiles(
|
|
538
|
+
schema=self._schema,
|
|
539
|
+
profiles_data=fields.get("profiles"),
|
|
540
|
+
mandatory_attr_names=mandatory_attrs_to_check,
|
|
541
|
+
mandatory_rel_names=mandatory_rels_to_check,
|
|
542
|
+
)
|
|
543
|
+
|
|
493
544
|
async def _process_fields(self, fields: dict, db: InfrahubDatabase, process_pools: bool = True) -> None:
|
|
494
545
|
errors = []
|
|
495
546
|
|
|
@@ -511,10 +562,14 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
511
562
|
# Backfill fields with the ones from the template if there's one
|
|
512
563
|
await self.handle_object_template(fields=fields, db=db, errors=errors)
|
|
513
564
|
|
|
514
|
-
# If the object is new, we need to ensure that all mandatory attributes and relationships have been provided
|
|
515
565
|
if not self._existing:
|
|
566
|
+
(
|
|
567
|
+
self._profile_provided_attrs,
|
|
568
|
+
self._profile_provided_rels,
|
|
569
|
+
) = await self._get_profile_provided_mandatory_fields(db=db, fields=fields)
|
|
570
|
+
|
|
516
571
|
for mandatory_attr in self._schema.mandatory_attribute_names:
|
|
517
|
-
if mandatory_attr not in fields.keys():
|
|
572
|
+
if mandatory_attr not in fields.keys() and mandatory_attr not in self._profile_provided_attrs:
|
|
518
573
|
if self._schema.is_node_schema:
|
|
519
574
|
mandatory_attribute = self._schema.get_attribute(name=mandatory_attr)
|
|
520
575
|
if (
|
|
@@ -532,7 +587,7 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
532
587
|
)
|
|
533
588
|
|
|
534
589
|
for mandatory_rel in self._schema.mandatory_relationship_names:
|
|
535
|
-
if mandatory_rel not in fields.keys():
|
|
590
|
+
if mandatory_rel not in fields.keys() and mandatory_rel not in self._profile_provided_rels:
|
|
536
591
|
errors.append(
|
|
537
592
|
ValidationError({mandatory_rel: f"{mandatory_rel} is mandatory for {self.get_kind()}"})
|
|
538
593
|
)
|
|
@@ -610,6 +665,9 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
610
665
|
attribute: BaseAttribute = getattr(self, attr_schema.name)
|
|
611
666
|
await self.handle_pool(db=db, attribute=attribute, errors=errors, allocate_resources=process_pools)
|
|
612
667
|
|
|
668
|
+
if attr_schema.name in self._profile_provided_attrs:
|
|
669
|
+
continue
|
|
670
|
+
|
|
613
671
|
if process_pools or attribute.from_pool is None:
|
|
614
672
|
attribute.validate(value=attribute.value, name=attribute.name, schema=attribute.schema)
|
|
615
673
|
except ValidationError as exc:
|
|
@@ -729,6 +787,12 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
729
787
|
source=self._source,
|
|
730
788
|
owner=self._owner,
|
|
731
789
|
)
|
|
790
|
+
if isinstance(data, dict):
|
|
791
|
+
attr._set_created_at(data.pop("created_at", None))
|
|
792
|
+
attr._set_created_by(data.pop("created_by", None))
|
|
793
|
+
attr._set_updated_at(data.pop("updated_at", None))
|
|
794
|
+
attr._set_updated_by(data.pop("updated_by", None))
|
|
795
|
+
|
|
732
796
|
return attr
|
|
733
797
|
|
|
734
798
|
async def process_label(self, db: InfrahubDatabase | None = None) -> None: # noqa: ARG002
|
|
@@ -789,19 +853,12 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
789
853
|
db: InfrahubDatabase,
|
|
790
854
|
id: str | None = None,
|
|
791
855
|
db_id: str | None = None,
|
|
792
|
-
updated_at: Timestamp | str | None = None,
|
|
793
856
|
**kwargs: Any,
|
|
794
857
|
) -> Self:
|
|
795
858
|
self.id = id
|
|
796
859
|
self.db_id = db_id
|
|
797
860
|
self._existing = True
|
|
798
861
|
|
|
799
|
-
if updated_at:
|
|
800
|
-
kwargs["updated_at"] = (
|
|
801
|
-
updated_at # FIXME: Allow users to use "updated_at" named attributes until we have proper metadata handling
|
|
802
|
-
)
|
|
803
|
-
self._updated_at = Timestamp(updated_at)
|
|
804
|
-
|
|
805
862
|
if not self._schema.is_schema_node:
|
|
806
863
|
if hfid := kwargs.pop("human_friendly_id", None):
|
|
807
864
|
self._human_friendly_id = HumanFriendlyIdentifier(
|
|
@@ -815,19 +872,22 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
815
872
|
await self._process_fields(db=db, fields=kwargs)
|
|
816
873
|
return self
|
|
817
874
|
|
|
818
|
-
async def _create(self, db: InfrahubDatabase, at: Timestamp | None = None) -> NodeChangelog:
|
|
875
|
+
async def _create(self, db: InfrahubDatabase, user_id: str, at: Timestamp | None = None) -> NodeChangelog:
|
|
819
876
|
create_at = Timestamp(at)
|
|
877
|
+
self._set_created_at(create_at)
|
|
878
|
+
self._set_created_by(user_id)
|
|
879
|
+
self._set_updated_at(create_at)
|
|
880
|
+
self._set_updated_by(user_id)
|
|
820
881
|
|
|
821
882
|
if not self._schema.is_schema_node:
|
|
822
883
|
await self.add_human_friendly_id(db=db)
|
|
823
884
|
await self.add_display_label(db=db)
|
|
824
885
|
|
|
825
|
-
query = await NodeCreateAllQuery.init(db=db, node=self, at=create_at)
|
|
886
|
+
query = await NodeCreateAllQuery.init(db=db, node=self, at=create_at, user_id=user_id)
|
|
826
887
|
await query.execute(db=db)
|
|
827
888
|
|
|
828
889
|
_, self.db_id = query.get_self_ids()
|
|
829
890
|
self._at = create_at
|
|
830
|
-
self._updated_at = create_at
|
|
831
891
|
self._existing = True
|
|
832
892
|
|
|
833
893
|
new_ids = query.get_ids()
|
|
@@ -845,6 +905,10 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
845
905
|
attr: BaseAttribute = getattr(self, name)
|
|
846
906
|
attr.id, attr.db_id = new_ids[name]
|
|
847
907
|
attr.at = create_at
|
|
908
|
+
attr._set_created_at(create_at)
|
|
909
|
+
attr._set_created_by(user_id)
|
|
910
|
+
attr._set_updated_at(create_at)
|
|
911
|
+
attr._set_updated_by(user_id)
|
|
848
912
|
node_changelog.create_attribute(attribute=attr)
|
|
849
913
|
|
|
850
914
|
# Go over the list of relationships and assign the new IDs one by one
|
|
@@ -859,7 +923,7 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
859
923
|
return node_changelog
|
|
860
924
|
|
|
861
925
|
async def _update(
|
|
862
|
-
self, db: InfrahubDatabase, at: Timestamp | None = None, fields: list[str] | None = None
|
|
926
|
+
self, db: InfrahubDatabase, user_id: str, at: Timestamp | None = None, fields: list[str] | None = None
|
|
863
927
|
) -> NodeChangelog:
|
|
864
928
|
"""Update the node in the database if needed."""
|
|
865
929
|
|
|
@@ -869,8 +933,8 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
869
933
|
# Go over the list of Attribute and update them one by one
|
|
870
934
|
for name in self._attributes:
|
|
871
935
|
if (fields and name in fields) or not fields:
|
|
872
|
-
attr
|
|
873
|
-
updated_attribute = await attr.save(
|
|
936
|
+
attr = self.get_attribute(name=name)
|
|
937
|
+
updated_attribute = await attr.save(db=db, user_id=user_id, at=update_at)
|
|
874
938
|
if updated_attribute:
|
|
875
939
|
node_changelog.add_attribute(attribute=updated_attribute)
|
|
876
940
|
|
|
@@ -879,15 +943,15 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
879
943
|
for name in self._relationships:
|
|
880
944
|
if (fields and name in fields) or not fields:
|
|
881
945
|
processed_relationships.append(name)
|
|
882
|
-
rel
|
|
883
|
-
updated_relationship = await rel.save(
|
|
946
|
+
rel = self.get_relationship(name=name)
|
|
947
|
+
updated_relationship = await rel.save(db=db, user_id=user_id, at=update_at)
|
|
884
948
|
node_changelog.add_relationship(relationship_changelog=updated_relationship)
|
|
885
949
|
|
|
886
950
|
if len(processed_relationships) != len(self._relationships):
|
|
887
951
|
# Analyze if the node has a parent and add it to the changelog if missing
|
|
888
952
|
if parent_relationship := self._get_parent_relationship_name():
|
|
889
953
|
if parent_relationship not in processed_relationships:
|
|
890
|
-
rel
|
|
954
|
+
rel = self.get_relationship(name=parent_relationship)
|
|
891
955
|
if parent := await rel.get_parent(db=db):
|
|
892
956
|
node_changelog.add_parent_from_relationship(parent=parent)
|
|
893
957
|
|
|
@@ -915,20 +979,40 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
915
979
|
node_changelog.add_attribute(attribute=updated_attribute)
|
|
916
980
|
|
|
917
981
|
node_changelog.display_label = await self.get_display_label(db=db)
|
|
982
|
+
|
|
983
|
+
if node_changelog.has_changes:
|
|
984
|
+
self._set_updated_at(update_at)
|
|
985
|
+
self._set_updated_by(user_id)
|
|
986
|
+
update_branch = self.get_branch_based_on_support_type()
|
|
987
|
+
if update_branch.is_default or update_branch.is_global:
|
|
988
|
+
await self._save_metadata(db=db, branch=update_branch)
|
|
918
989
|
return node_changelog
|
|
919
990
|
|
|
920
|
-
async def save(
|
|
991
|
+
async def save(
|
|
992
|
+
self,
|
|
993
|
+
db: InfrahubDatabase,
|
|
994
|
+
user_id: str = SYSTEM_USER_ID,
|
|
995
|
+
at: Timestamp | None = None,
|
|
996
|
+
fields: list[str] | None = None,
|
|
997
|
+
) -> Self:
|
|
921
998
|
"""Create or Update the Node in the database."""
|
|
922
999
|
save_at = Timestamp(at)
|
|
923
1000
|
|
|
924
1001
|
if self._existing:
|
|
925
|
-
self._node_changelog = await self._update(
|
|
1002
|
+
self._node_changelog = await self._update(db=db, user_id=user_id, at=save_at, fields=fields)
|
|
926
1003
|
else:
|
|
927
|
-
self._node_changelog = await self._create(
|
|
1004
|
+
self._node_changelog = await self._create(db=db, user_id=user_id, at=save_at)
|
|
928
1005
|
|
|
929
1006
|
return self
|
|
930
1007
|
|
|
931
|
-
async def
|
|
1008
|
+
async def _save_metadata(self, db: InfrahubDatabase, branch: Branch) -> None:
|
|
1009
|
+
if user_id := self._get_updated_by():
|
|
1010
|
+
update_metadata_query = await NodeUpdateMetadataQuery.init(
|
|
1011
|
+
db=db, branch=branch, node_id=self.get_id(), user_id=user_id, at=self._get_updated_at()
|
|
1012
|
+
)
|
|
1013
|
+
await update_metadata_query.execute(db=db)
|
|
1014
|
+
|
|
1015
|
+
async def delete(self, db: InfrahubDatabase, user_id: str = SYSTEM_USER_ID, at: Timestamp | None = None) -> None:
|
|
932
1016
|
"""Delete the Node in the database."""
|
|
933
1017
|
|
|
934
1018
|
delete_at = Timestamp(at)
|
|
@@ -939,25 +1023,32 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
939
1023
|
# Go over the list of Attribute and update them one by one
|
|
940
1024
|
for name in self._attributes:
|
|
941
1025
|
attr: BaseAttribute = getattr(self, name)
|
|
942
|
-
if deleted_attribute := await attr.delete(at=delete_at,
|
|
1026
|
+
if deleted_attribute := await attr.delete(db=db, at=delete_at, user_id=user_id):
|
|
943
1027
|
node_changelog.add_attribute(attribute=deleted_attribute)
|
|
944
1028
|
|
|
945
1029
|
if self._human_friendly_id:
|
|
946
1030
|
if deleted_attribute := await self._human_friendly_id.get_node_attribute(node=self, at=delete_at).delete(
|
|
947
|
-
|
|
1031
|
+
db=db,
|
|
1032
|
+
user_id=user_id,
|
|
1033
|
+
at=delete_at,
|
|
948
1034
|
):
|
|
949
1035
|
node_changelog.add_attribute(attribute=deleted_attribute)
|
|
950
1036
|
|
|
951
1037
|
if self._display_label:
|
|
952
1038
|
if deleted_attribute := await self._display_label.get_node_attribute(node=self, at=delete_at).delete(
|
|
953
|
-
at=delete_at,
|
|
1039
|
+
db=db, at=delete_at, user_id=user_id
|
|
954
1040
|
):
|
|
955
1041
|
node_changelog.add_attribute(attribute=deleted_attribute)
|
|
956
1042
|
|
|
957
1043
|
branch = self.get_branch_based_on_support_type()
|
|
958
1044
|
|
|
959
1045
|
delete_query = await RelationshipDeleteAllQuery.init(
|
|
960
|
-
db=db,
|
|
1046
|
+
db=db,
|
|
1047
|
+
node_id=self.get_id(),
|
|
1048
|
+
branch=branch,
|
|
1049
|
+
user_id=user_id,
|
|
1050
|
+
at=delete_at,
|
|
1051
|
+
branch_agnostic=branch.name == GLOBAL_BRANCH_NAME,
|
|
961
1052
|
)
|
|
962
1053
|
await delete_query.execute(db=db)
|
|
963
1054
|
|
|
@@ -965,22 +1056,7 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
965
1056
|
for relationship_changelog in deleted_relationships_changelogs:
|
|
966
1057
|
node_changelog.add_relationship(relationship_changelog=relationship_changelog)
|
|
967
1058
|
|
|
968
|
-
|
|
969
|
-
query = await NodeGetListQuery.init(
|
|
970
|
-
db=db,
|
|
971
|
-
schema=self._schema,
|
|
972
|
-
filters={"id": self.id},
|
|
973
|
-
branch=self._branch,
|
|
974
|
-
at=delete_at,
|
|
975
|
-
order=OrderModel(disable=True),
|
|
976
|
-
)
|
|
977
|
-
await query.execute(db=db)
|
|
978
|
-
result = query.get_result()
|
|
979
|
-
|
|
980
|
-
if result and result.get("rb.branch") == branch.name:
|
|
981
|
-
await update_relationships_to([result.get("rb_id")], to=delete_at, db=db)
|
|
982
|
-
|
|
983
|
-
query = await NodeDeleteQuery.init(db=db, node=self, at=delete_at)
|
|
1059
|
+
query = await NodeDeleteQuery.init(db=db, node=self, at=delete_at, user_id=user_id)
|
|
984
1060
|
await query.execute(db=db)
|
|
985
1061
|
|
|
986
1062
|
self._node_changelog = node_changelog
|
|
@@ -1007,10 +1083,11 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
1007
1083
|
|
|
1008
1084
|
FIELD_NAME_TO_EXCLUDE = ["id"] + self._schema.relationship_names
|
|
1009
1085
|
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1086
|
+
field_names = (
|
|
1087
|
+
[field_name for field_name in fields.keys() if field_name not in FIELD_NAME_TO_EXCLUDE]
|
|
1088
|
+
if fields and isinstance(fields, dict)
|
|
1089
|
+
else self._schema.attribute_names + ["__typename", "display_label"]
|
|
1090
|
+
)
|
|
1014
1091
|
|
|
1015
1092
|
for field_name in field_names:
|
|
1016
1093
|
if field_name == "__typename":
|
|
@@ -1027,8 +1104,8 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
1027
1104
|
continue
|
|
1028
1105
|
|
|
1029
1106
|
if field_name == "_updated_at":
|
|
1030
|
-
if self.
|
|
1031
|
-
response[field_name] = await
|
|
1107
|
+
if updated_at := self._get_updated_at():
|
|
1108
|
+
response[field_name] = await updated_at.to_graphql()
|
|
1032
1109
|
else:
|
|
1033
1110
|
response[field_name] = None
|
|
1034
1111
|
continue
|
|
@@ -1079,6 +1156,28 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
|
|
|
1079
1156
|
|
|
1080
1157
|
return response
|
|
1081
1158
|
|
|
1159
|
+
async def _build_meta_response(self, field_name: str, fields: dict) -> dict:
|
|
1160
|
+
data = {}
|
|
1161
|
+
for meta_field in fields.get(field_name, {}).keys():
|
|
1162
|
+
if meta_field == "created_at":
|
|
1163
|
+
created_at = self._get_created_at()
|
|
1164
|
+
data["created_at"] = created_at.to_datetime() if created_at else None
|
|
1165
|
+
|
|
1166
|
+
if meta_field == "created_by":
|
|
1167
|
+
data["created_by"] = (
|
|
1168
|
+
{"id": self._get_created_by(), "__kind__": "CoreAccount"} if self._get_created_by() else None
|
|
1169
|
+
)
|
|
1170
|
+
|
|
1171
|
+
if meta_field == "updated_by":
|
|
1172
|
+
data["updated_by"] = (
|
|
1173
|
+
{"id": self._get_updated_by(), "__kind__": "CoreAccount"} if self._get_updated_by() else None
|
|
1174
|
+
)
|
|
1175
|
+
|
|
1176
|
+
if meta_field == "updated_at":
|
|
1177
|
+
updated_at = self._get_updated_at()
|
|
1178
|
+
data["updated_at"] = updated_at.to_datetime() if updated_at else None
|
|
1179
|
+
return data
|
|
1180
|
+
|
|
1082
1181
|
async def from_graphql(self, data: dict, db: InfrahubDatabase, process_pools: bool = True) -> bool:
|
|
1083
1182
|
"""Update object from a GraphQL payload."""
|
|
1084
1183
|
|
infrahub/core/node/base.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
3
5
|
from ..utils import SubclassWithMeta, SubclassWithMeta_Meta
|
|
4
6
|
|
|
5
7
|
|
|
@@ -9,19 +11,19 @@ class BaseOptions:
|
|
|
9
11
|
|
|
10
12
|
_frozen: bool = False
|
|
11
13
|
|
|
12
|
-
def __init__(self, class_type):
|
|
14
|
+
def __init__(self, class_type: type) -> None:
|
|
13
15
|
self.class_type = class_type
|
|
14
16
|
|
|
15
17
|
def freeze(self) -> None:
|
|
16
18
|
self._frozen = True
|
|
17
19
|
|
|
18
|
-
def __setattr__(self, name, value):
|
|
20
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
19
21
|
if not self._frozen:
|
|
20
22
|
super().__setattr__(name, value)
|
|
21
23
|
else:
|
|
22
24
|
raise Exception(f"Can't modify frozen Options {self}")
|
|
23
25
|
|
|
24
|
-
def __repr__(self):
|
|
26
|
+
def __repr__(self) -> str:
|
|
25
27
|
return f"<{self.__class__.__name__} name={repr(self.name)}>"
|
|
26
28
|
|
|
27
29
|
|
|
@@ -34,7 +36,9 @@ class BaseNode(SubclassWithMeta):
|
|
|
34
36
|
# return type(class_name, (cls,), {"Meta": options})
|
|
35
37
|
|
|
36
38
|
@classmethod
|
|
37
|
-
def __init_subclass_with_meta__(
|
|
39
|
+
def __init_subclass_with_meta__(
|
|
40
|
+
cls, name: str | None = None, description: str | None = None, _meta: BaseOptions | None = None, **_kwargs: Any
|
|
41
|
+
) -> None:
|
|
38
42
|
assert "_meta" not in cls.__dict__, "Can't assign meta directly"
|
|
39
43
|
if not _meta:
|
|
40
44
|
return
|
|
@@ -52,7 +56,7 @@ class BaseNodeOptions(BaseOptions):
|
|
|
52
56
|
|
|
53
57
|
|
|
54
58
|
class ObjectNodeMeta(BaseNodeMeta):
|
|
55
|
-
def __new__(mcs, name_, bases, namespace, **options):
|
|
59
|
+
def __new__(mcs, name_: str, bases: tuple[type, ...], namespace: dict[str, Any], **options: Any) -> type:
|
|
56
60
|
# Note: it's safe to pass options as keyword arguments as they are still type-checked by NodeOptions.
|
|
57
61
|
|
|
58
62
|
# We create this type, to then overload it with the dataclass attrs
|
infrahub/core/node/create.py
CHANGED
|
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Any, Mapping
|
|
|
4
4
|
|
|
5
5
|
from infrahub import lock
|
|
6
6
|
from infrahub.core import registry
|
|
7
|
-
from infrahub.core.constants import RelationshipCardinality, RelationshipKind
|
|
7
|
+
from infrahub.core.constants import SYSTEM_USER_ID, RelationshipCardinality, RelationshipKind
|
|
8
8
|
from infrahub.core.constraint.node.runner import NodeConstraintRunner
|
|
9
9
|
from infrahub.core.node import Node
|
|
10
10
|
from infrahub.core.node.lock_utils import get_lock_names_on_object_mutation
|
|
@@ -180,11 +180,12 @@ async def _do_create_node(
|
|
|
180
180
|
fields_to_validate: list[str],
|
|
181
181
|
data: dict[str, Any],
|
|
182
182
|
at: Timestamp | None = None,
|
|
183
|
+
user_id: str = SYSTEM_USER_ID,
|
|
183
184
|
) -> Node:
|
|
184
185
|
obj = await node_class.init(db=db, schema=schema, branch=branch)
|
|
185
186
|
await obj.new(db=db, **data)
|
|
186
187
|
await node_constraint_runner.check(node=obj, field_filters=fields_to_validate)
|
|
187
|
-
await obj.save(db=db, at=at)
|
|
188
|
+
await obj.save(db=db, at=at, user_id=user_id)
|
|
188
189
|
|
|
189
190
|
object_template = await obj.get_object_template(db=db)
|
|
190
191
|
if object_template:
|
|
@@ -205,6 +206,7 @@ async def create_node(
|
|
|
205
206
|
branch: Branch,
|
|
206
207
|
schema: MainSchemaTypes,
|
|
207
208
|
at: Timestamp | None = None,
|
|
209
|
+
user_id: str = SYSTEM_USER_ID,
|
|
208
210
|
) -> Node:
|
|
209
211
|
"""Create a node in the database if constraint checks succeed."""
|
|
210
212
|
|
|
@@ -237,6 +239,7 @@ async def create_node(
|
|
|
237
239
|
fields_to_validate=fields_to_validate,
|
|
238
240
|
data=data,
|
|
239
241
|
at=at,
|
|
242
|
+
user_id=user_id,
|
|
240
243
|
)
|
|
241
244
|
else:
|
|
242
245
|
async with db.start_transaction() as dbt:
|
|
@@ -253,11 +256,12 @@ async def create_node(
|
|
|
253
256
|
fields_to_validate=fields_to_validate,
|
|
254
257
|
data=data,
|
|
255
258
|
at=at,
|
|
259
|
+
user_id=user_id,
|
|
256
260
|
)
|
|
257
261
|
|
|
258
262
|
if await get_profile_ids(db=db, obj=obj):
|
|
259
263
|
node_profiles_applier = NodeProfilesApplier(db=db, branch=branch)
|
|
260
264
|
await node_profiles_applier.apply_profiles(node=obj)
|
|
261
|
-
await obj.save(db=db)
|
|
265
|
+
await obj.save(db=db, user_id=user_id)
|
|
262
266
|
|
|
263
267
|
return obj
|
|
@@ -117,7 +117,7 @@ class NodeDeleteIndex:
|
|
|
117
117
|
|
|
118
118
|
|
|
119
119
|
class NodeDeleteValidator:
|
|
120
|
-
def __init__(self, db: InfrahubDatabase, branch: Branch):
|
|
120
|
+
def __init__(self, db: InfrahubDatabase, branch: Branch) -> None:
|
|
121
121
|
self.db = db
|
|
122
122
|
self.branch = branch
|
|
123
123
|
schema_branch = registry.schema.get_schema_branch(name=self.branch.name)
|