binalyze-air-sdk 1.0.1__py3-none-any.whl → 1.0.3__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.
Files changed (142) hide show
  1. binalyze_air/__init__.py +77 -77
  2. binalyze_air/apis/__init__.py +67 -27
  3. binalyze_air/apis/acquisitions.py +107 -0
  4. binalyze_air/apis/api_tokens.py +49 -0
  5. binalyze_air/apis/assets.py +161 -0
  6. binalyze_air/apis/audit_logs.py +26 -0
  7. binalyze_air/apis/{authentication.py → auth.py} +29 -27
  8. binalyze_air/apis/auto_asset_tags.py +79 -75
  9. binalyze_air/apis/backup.py +177 -0
  10. binalyze_air/apis/baseline.py +46 -0
  11. binalyze_air/apis/cases.py +225 -0
  12. binalyze_air/apis/cloud_forensics.py +116 -0
  13. binalyze_air/apis/event_subscription.py +96 -96
  14. binalyze_air/apis/evidence.py +249 -53
  15. binalyze_air/apis/interact.py +153 -36
  16. binalyze_air/apis/investigation_hub.py +234 -0
  17. binalyze_air/apis/license.py +104 -0
  18. binalyze_air/apis/logger.py +83 -0
  19. binalyze_air/apis/multipart_upload.py +201 -0
  20. binalyze_air/apis/notifications.py +115 -0
  21. binalyze_air/apis/organizations.py +267 -0
  22. binalyze_air/apis/params.py +44 -39
  23. binalyze_air/apis/policies.py +186 -0
  24. binalyze_air/apis/preset_filters.py +79 -0
  25. binalyze_air/apis/recent_activities.py +71 -0
  26. binalyze_air/apis/relay_server.py +104 -0
  27. binalyze_air/apis/settings.py +395 -27
  28. binalyze_air/apis/tasks.py +80 -0
  29. binalyze_air/apis/triage.py +197 -0
  30. binalyze_air/apis/user_management.py +183 -74
  31. binalyze_air/apis/webhook_executions.py +50 -0
  32. binalyze_air/apis/webhooks.py +322 -230
  33. binalyze_air/base.py +207 -133
  34. binalyze_air/client.py +217 -1337
  35. binalyze_air/commands/__init__.py +175 -145
  36. binalyze_air/commands/acquisitions.py +661 -387
  37. binalyze_air/commands/api_tokens.py +55 -0
  38. binalyze_air/commands/assets.py +324 -362
  39. binalyze_air/commands/{authentication.py → auth.py} +36 -36
  40. binalyze_air/commands/auto_asset_tags.py +230 -230
  41. binalyze_air/commands/backup.py +47 -0
  42. binalyze_air/commands/baseline.py +32 -396
  43. binalyze_air/commands/cases.py +609 -602
  44. binalyze_air/commands/cloud_forensics.py +88 -0
  45. binalyze_air/commands/event_subscription.py +101 -101
  46. binalyze_air/commands/evidences.py +918 -988
  47. binalyze_air/commands/interact.py +172 -58
  48. binalyze_air/commands/investigation_hub.py +315 -0
  49. binalyze_air/commands/license.py +183 -0
  50. binalyze_air/commands/logger.py +126 -0
  51. binalyze_air/commands/multipart_upload.py +363 -0
  52. binalyze_air/commands/notifications.py +45 -0
  53. binalyze_air/commands/organizations.py +200 -221
  54. binalyze_air/commands/policies.py +175 -203
  55. binalyze_air/commands/preset_filters.py +55 -0
  56. binalyze_air/commands/recent_activities.py +32 -0
  57. binalyze_air/commands/relay_server.py +144 -0
  58. binalyze_air/commands/settings.py +431 -29
  59. binalyze_air/commands/tasks.py +95 -56
  60. binalyze_air/commands/triage.py +224 -360
  61. binalyze_air/commands/user_management.py +351 -126
  62. binalyze_air/commands/webhook_executions.py +77 -0
  63. binalyze_air/config.py +244 -244
  64. binalyze_air/exceptions.py +49 -49
  65. binalyze_air/http_client.py +426 -305
  66. binalyze_air/models/__init__.py +287 -285
  67. binalyze_air/models/acquisitions.py +365 -250
  68. binalyze_air/models/api_tokens.py +73 -0
  69. binalyze_air/models/assets.py +438 -438
  70. binalyze_air/models/audit.py +247 -272
  71. binalyze_air/models/audit_logs.py +14 -0
  72. binalyze_air/models/{authentication.py → auth.py} +69 -69
  73. binalyze_air/models/auto_asset_tags.py +227 -116
  74. binalyze_air/models/backup.py +138 -0
  75. binalyze_air/models/baseline.py +231 -231
  76. binalyze_air/models/cases.py +275 -275
  77. binalyze_air/models/cloud_forensics.py +145 -0
  78. binalyze_air/models/event_subscription.py +170 -171
  79. binalyze_air/models/evidence.py +65 -65
  80. binalyze_air/models/evidences.py +367 -348
  81. binalyze_air/models/interact.py +266 -135
  82. binalyze_air/models/investigation_hub.py +265 -0
  83. binalyze_air/models/license.py +150 -0
  84. binalyze_air/models/logger.py +83 -0
  85. binalyze_air/models/multipart_upload.py +352 -0
  86. binalyze_air/models/notifications.py +138 -0
  87. binalyze_air/models/organizations.py +293 -293
  88. binalyze_air/models/params.py +153 -127
  89. binalyze_air/models/policies.py +260 -249
  90. binalyze_air/models/preset_filters.py +79 -0
  91. binalyze_air/models/recent_activities.py +70 -0
  92. binalyze_air/models/relay_server.py +121 -0
  93. binalyze_air/models/settings.py +538 -84
  94. binalyze_air/models/tasks.py +215 -149
  95. binalyze_air/models/triage.py +141 -142
  96. binalyze_air/models/user_management.py +200 -97
  97. binalyze_air/models/webhook_executions.py +33 -0
  98. binalyze_air/queries/__init__.py +121 -133
  99. binalyze_air/queries/acquisitions.py +155 -155
  100. binalyze_air/queries/api_tokens.py +46 -0
  101. binalyze_air/queries/assets.py +186 -105
  102. binalyze_air/queries/audit.py +400 -416
  103. binalyze_air/queries/{authentication.py → auth.py} +55 -55
  104. binalyze_air/queries/auto_asset_tags.py +59 -59
  105. binalyze_air/queries/backup.py +66 -0
  106. binalyze_air/queries/baseline.py +21 -185
  107. binalyze_air/queries/cases.py +292 -292
  108. binalyze_air/queries/cloud_forensics.py +137 -0
  109. binalyze_air/queries/event_subscription.py +54 -54
  110. binalyze_air/queries/evidence.py +139 -139
  111. binalyze_air/queries/evidences.py +279 -279
  112. binalyze_air/queries/interact.py +140 -28
  113. binalyze_air/queries/investigation_hub.py +329 -0
  114. binalyze_air/queries/license.py +85 -0
  115. binalyze_air/queries/logger.py +58 -0
  116. binalyze_air/queries/multipart_upload.py +180 -0
  117. binalyze_air/queries/notifications.py +71 -0
  118. binalyze_air/queries/organizations.py +222 -222
  119. binalyze_air/queries/params.py +154 -115
  120. binalyze_air/queries/policies.py +149 -149
  121. binalyze_air/queries/preset_filters.py +60 -0
  122. binalyze_air/queries/recent_activities.py +44 -0
  123. binalyze_air/queries/relay_server.py +42 -0
  124. binalyze_air/queries/settings.py +533 -20
  125. binalyze_air/queries/tasks.py +125 -81
  126. binalyze_air/queries/triage.py +230 -230
  127. binalyze_air/queries/user_management.py +193 -83
  128. binalyze_air/queries/webhook_executions.py +39 -0
  129. binalyze_air_sdk-1.0.3.dist-info/METADATA +752 -0
  130. binalyze_air_sdk-1.0.3.dist-info/RECORD +132 -0
  131. {binalyze_air_sdk-1.0.1.dist-info → binalyze_air_sdk-1.0.3.dist-info}/WHEEL +1 -1
  132. binalyze_air/apis/endpoints.py +0 -22
  133. binalyze_air/apis/evidences.py +0 -216
  134. binalyze_air/apis/users.py +0 -68
  135. binalyze_air/commands/users.py +0 -101
  136. binalyze_air/models/endpoints.py +0 -76
  137. binalyze_air/models/users.py +0 -82
  138. binalyze_air/queries/endpoints.py +0 -25
  139. binalyze_air/queries/users.py +0 -69
  140. binalyze_air_sdk-1.0.1.dist-info/METADATA +0 -635
  141. binalyze_air_sdk-1.0.1.dist-info/RECORD +0 -82
  142. {binalyze_air_sdk-1.0.1.dist-info → binalyze_air_sdk-1.0.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,45 @@
1
+ """
2
+ Notifications commands for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import Dict, Any, Union
6
+
7
+ from ..base import Command
8
+ from ..http_client import HTTPClient
9
+
10
+
11
+ class DeleteAllNotificationsCommand(Command[Dict[str, Any]]):
12
+ """Command to delete all notifications for the current user."""
13
+
14
+ def __init__(self, http_client: HTTPClient):
15
+ self.http_client = http_client
16
+
17
+ def execute(self) -> Dict[str, Any]:
18
+ """Execute the delete all notifications command."""
19
+ response = self.http_client.delete("notifications")
20
+ return response
21
+
22
+
23
+ class MarkAllAsReadCommand(Command[Dict[str, Any]]):
24
+ """Command to mark all notifications as read."""
25
+
26
+ def __init__(self, http_client: HTTPClient):
27
+ self.http_client = http_client
28
+
29
+ def execute(self) -> Dict[str, Any]:
30
+ """Execute the mark all as read command."""
31
+ response = self.http_client.put("notifications/mark-as-read/all")
32
+ return response
33
+
34
+
35
+ class MarkAsReadByIdCommand(Command[Dict[str, Any]]):
36
+ """Command to mark a specific notification as read by ID."""
37
+
38
+ def __init__(self, http_client: HTTPClient, notification_id: Union[int, str]):
39
+ self.http_client = http_client
40
+ self.notification_id = notification_id
41
+
42
+ def execute(self) -> Dict[str, Any]:
43
+ """Execute the mark as read by ID command."""
44
+ response = self.http_client.patch(f"notifications/mark-as-read/{self.notification_id}")
45
+ return response
@@ -1,221 +1,200 @@
1
- """
2
- Organization-related commands for the Binalyze AIR SDK.
3
- """
4
-
5
- from typing import Dict, Any, List
6
-
7
- from ..base import Command
8
- from ..models.organizations import (
9
- Organization, OrganizationUser, CreateOrganizationRequest,
10
- UpdateOrganizationRequest, AddUserToOrganizationRequest, OrganizationSettings,
11
- AssignUsersToOrganizationRequest, AddTagsToOrganizationRequest,
12
- DeleteTagsFromOrganizationRequest, UpdateShareableDeploymentSettingsRequest,
13
- UpdateDeploymentTokenRequest, DeploymentTokenUpdateResponse
14
- )
15
- from ..http_client import HTTPClient
16
-
17
-
18
- class CreateOrganizationCommand(Command[Organization]):
19
- """Command to create a new organization."""
20
-
21
- def __init__(self, http_client: HTTPClient, request: CreateOrganizationRequest):
22
- self.http_client = http_client
23
- self.request = request
24
-
25
- def execute(self) -> Organization:
26
- """Execute the command to create an organization."""
27
- data = self.request.model_dump(exclude_none=True, by_alias=True)
28
-
29
- response = self.http_client.post("organizations", json_data=data)
30
-
31
- entity_data = response.get("result", {})
32
-
33
- # Use Pydantic model_validate for automatic field mapping via aliases
34
- return Organization.model_validate(entity_data)
35
-
36
-
37
- class UpdateOrganizationCommand(Command[Organization]):
38
- """Command to update an existing organization."""
39
-
40
- def __init__(self, http_client: HTTPClient, organization_id: str, request: UpdateOrganizationRequest):
41
- self.http_client = http_client
42
- self.organization_id = organization_id
43
- self.request = request
44
-
45
- def execute(self) -> Organization:
46
- """Execute the command to update an organization."""
47
- data = self.request.model_dump(exclude_none=True, by_alias=True)
48
-
49
- response = self.http_client.patch(f"organizations/{self.organization_id}", json_data=data)
50
-
51
- entity_data = response.get("result", {})
52
-
53
- # Use Pydantic model_validate for automatic field mapping via aliases
54
- return Organization.model_validate(entity_data)
55
-
56
-
57
- class DeleteOrganizationCommand(Command[Dict[str, Any]]):
58
- """Command to delete an organization."""
59
-
60
- def __init__(self, http_client: HTTPClient, organization_id: str):
61
- self.http_client = http_client
62
- self.organization_id = organization_id
63
-
64
- def execute(self) -> Dict[str, Any]:
65
- """Execute the command to delete an organization."""
66
- response = self.http_client.delete(f"organizations/{self.organization_id}")
67
- return response
68
-
69
-
70
- class AssignUsersToOrganizationCommand(Command[bool]):
71
- """Command to assign multiple users to an organization using the /assign-users endpoint."""
72
-
73
- def __init__(self, http_client: HTTPClient, organization_id: str, request: AssignUsersToOrganizationRequest):
74
- self.http_client = http_client
75
- self.organization_id = organization_id
76
- self.request = request
77
-
78
- def execute(self) -> bool:
79
- """Execute the command to assign users to organization."""
80
- data = self.request.model_dump(exclude_none=True, by_alias=True)
81
-
82
- response = self.http_client.post(f"organizations/{self.organization_id}/assign-users", json_data=data)
83
-
84
- return response.get("success", False)
85
-
86
-
87
- class RemoveUserFromOrganizationCommand(Command[Dict[str, Any]]):
88
- """Command to remove a user from an organization using the /remove-user/{userId} endpoint."""
89
-
90
- def __init__(self, http_client: HTTPClient, organization_id: str, user_id: str):
91
- self.http_client = http_client
92
- self.organization_id = organization_id
93
- self.user_id = user_id
94
-
95
- def execute(self) -> Dict[str, Any]:
96
- """Execute the command to remove user from organization."""
97
- response = self.http_client.delete(f"organizations/{self.organization_id}/remove-user/{self.user_id}")
98
-
99
- return response
100
-
101
-
102
- class AddTagsToOrganizationCommand(Command[Organization]):
103
- """Command to add tags to an organization."""
104
-
105
- def __init__(self, http_client: HTTPClient, organization_id: str, request: AddTagsToOrganizationRequest):
106
- self.http_client = http_client
107
- self.organization_id = organization_id
108
- self.request = request
109
-
110
- def execute(self) -> Organization:
111
- """Execute the command to add tags to organization."""
112
- data = self.request.model_dump(exclude_none=True, by_alias=True)
113
-
114
- response = self.http_client.patch(f"organizations/{self.organization_id}/tags", json_data=data)
115
-
116
- entity_data = response.get("result", {})
117
-
118
- # Use Pydantic model_validate for automatic field mapping
119
- return Organization.model_validate(entity_data)
120
-
121
-
122
- class DeleteTagsFromOrganizationCommand(Command[Organization]):
123
- """Command to delete tags from an organization."""
124
-
125
- def __init__(self, http_client: HTTPClient, organization_id: str, request: DeleteTagsFromOrganizationRequest):
126
- self.http_client = http_client
127
- self.organization_id = organization_id
128
- self.request = request
129
-
130
- def execute(self) -> Organization:
131
- """Execute the command to delete tags from organization."""
132
- data = self.request.model_dump(exclude_none=True, by_alias=True)
133
-
134
- response = self.http_client.delete(f"organizations/{self.organization_id}/tags", json_data=data)
135
-
136
- entity_data = response.get("result", {})
137
-
138
- # Use Pydantic model_validate for automatic field mapping
139
- return Organization.model_validate(entity_data)
140
-
141
-
142
- class UpdateShareableDeploymentSettingsCommand(Command[bool]):
143
- """Command to update organization shareable deployment settings."""
144
-
145
- def __init__(self, http_client: HTTPClient, organization_id: str, request: UpdateShareableDeploymentSettingsRequest):
146
- self.http_client = http_client
147
- self.organization_id = organization_id
148
- self.request = request
149
-
150
- def execute(self) -> bool:
151
- """Execute the command to update shareable deployment settings."""
152
- data = self.request.model_dump(exclude_none=True, by_alias=True)
153
-
154
- response = self.http_client.post(f"organizations/{self.organization_id}/shareable-deployment", json_data=data)
155
-
156
- return response.get("success", False)
157
-
158
-
159
- class UpdateDeploymentTokenCommand(Command[DeploymentTokenUpdateResponse]):
160
- """Command to update organization deployment token."""
161
-
162
- def __init__(self, http_client: HTTPClient, organization_id: str):
163
- self.http_client = http_client
164
- self.organization_id = organization_id
165
-
166
- def execute(self) -> DeploymentTokenUpdateResponse:
167
- """Execute the command to update deployment token."""
168
- response = self.http_client.post(f"organizations/{self.organization_id}/deployment-token")
169
-
170
- # Use Pydantic model_validate for automatic field mapping
171
- return DeploymentTokenUpdateResponse.model_validate(response)
172
-
173
-
174
- class UpdateOrganizationSettingsCommand(Command[OrganizationSettings]):
175
- """Command to update organization settings."""
176
-
177
- def __init__(self, http_client: HTTPClient, organization_id: str, settings: Dict[str, Any]):
178
- self.http_client = http_client
179
- self.organization_id = organization_id
180
- self.settings = settings
181
-
182
- def execute(self) -> OrganizationSettings:
183
- """Execute the command to update organization settings."""
184
- response = self.http_client.put(f"organizations/{self.organization_id}/settings", json_data=self.settings)
185
-
186
- entity_data = response.get("result", {})
187
-
188
- mapped_data = {
189
- "organization_id": entity_data.get("organizationId"),
190
- "retention_policy": entity_data.get("retentionPolicy", {}),
191
- "security_settings": entity_data.get("securitySettings", {}),
192
- "notification_settings": entity_data.get("notificationSettings", {}),
193
- "api_settings": entity_data.get("apiSettings", {}),
194
- "custom_settings": entity_data.get("customSettings", {}),
195
- }
196
-
197
- # Remove None values
198
- mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
199
-
200
- return OrganizationSettings(**mapped_data)
201
-
202
-
203
- # Legacy command for backward compatibility
204
- class AddUserToOrganizationCommand(Command[OrganizationUser]):
205
- """Legacy command to add a user to an organization (use AssignUsersToOrganizationCommand for new implementations)."""
206
-
207
- def __init__(self, http_client: HTTPClient, organization_id: str, request: AddUserToOrganizationRequest):
208
- self.http_client = http_client
209
- self.organization_id = organization_id
210
- self.request = request
211
-
212
- def execute(self) -> OrganizationUser:
213
- """Execute the command to add user to organization."""
214
- data = self.request.model_dump(exclude_none=True)
215
-
216
- response = self.http_client.post(f"organizations/{self.organization_id}/users", json_data=data)
217
-
218
- entity_data = response.get("result", {})
219
-
220
- # Use Pydantic model_validate for automatic field mapping
221
- return OrganizationUser.model_validate(entity_data)
1
+ """
2
+ Organization-related commands for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import Dict, Any, List
6
+
7
+ from ..base import Command
8
+ from ..models.organizations import (
9
+ Organization, OrganizationUser, CreateOrganizationRequest,
10
+ UpdateOrganizationRequest, AddUserToOrganizationRequest, OrganizationSettings,
11
+ AssignUsersToOrganizationRequest, AddTagsToOrganizationRequest,
12
+ DeleteTagsFromOrganizationRequest, UpdateShareableDeploymentSettingsRequest,
13
+ UpdateDeploymentTokenRequest, DeploymentTokenUpdateResponse
14
+ )
15
+ from ..http_client import HTTPClient
16
+
17
+
18
+ class CreateOrganizationCommand(Command[Organization]):
19
+ """Command to create a new organization."""
20
+
21
+ def __init__(self, http_client: HTTPClient, request: CreateOrganizationRequest):
22
+ self.http_client = http_client
23
+ self.request = request
24
+
25
+ def execute(self) -> Organization:
26
+ """Execute the command to create an organization."""
27
+ data = self.request.model_dump(exclude_none=True, by_alias=True)
28
+
29
+ response = self.http_client.post("organizations", json_data=data)
30
+
31
+ entity_data = response.get("result", {})
32
+
33
+ # Use Pydantic model_validate for automatic field mapping via aliases
34
+ return Organization.model_validate(entity_data)
35
+
36
+
37
+ class UpdateOrganizationCommand(Command[Organization]):
38
+ """Command to update an existing organization."""
39
+
40
+ def __init__(self, http_client: HTTPClient, organization_id: str, request: UpdateOrganizationRequest):
41
+ self.http_client = http_client
42
+ self.organization_id = organization_id
43
+ self.request = request
44
+
45
+ def execute(self) -> Organization:
46
+ """Execute the command to update an organization."""
47
+ data = self.request.model_dump(exclude_none=True, by_alias=True)
48
+
49
+ response = self.http_client.patch(f"organizations/{self.organization_id}", json_data=data)
50
+
51
+ entity_data = response.get("result", {})
52
+
53
+ # Use Pydantic model_validate for automatic field mapping via aliases
54
+ return Organization.model_validate(entity_data)
55
+
56
+
57
+ class DeleteOrganizationCommand(Command[Dict[str, Any]]):
58
+ """Command to delete an organization."""
59
+
60
+ def __init__(self, http_client: HTTPClient, organization_id: str):
61
+ self.http_client = http_client
62
+ self.organization_id = organization_id
63
+
64
+ def execute(self) -> Dict[str, Any]:
65
+ """Execute the command to delete an organization."""
66
+ response = self.http_client.delete(f"organizations/{self.organization_id}")
67
+ return response
68
+
69
+
70
+ class AssignUsersToOrganizationCommand(Command[bool]):
71
+ """Command to assign multiple users to an organization using the /assign-users endpoint."""
72
+
73
+ def __init__(self, http_client: HTTPClient, organization_id: str, request: AssignUsersToOrganizationRequest):
74
+ self.http_client = http_client
75
+ self.organization_id = organization_id
76
+ self.request = request
77
+
78
+ def execute(self) -> bool:
79
+ """Execute the command to assign users to organization."""
80
+ data = self.request.model_dump(exclude_none=True, by_alias=True)
81
+
82
+ response = self.http_client.post(f"organizations/{self.organization_id}/assign-users", json_data=data)
83
+
84
+ return response.get("success", False)
85
+
86
+
87
+ class RemoveUserFromOrganizationCommand(Command[Dict[str, Any]]):
88
+ """Command to remove a user from an organization using the /remove-user/{userId} endpoint."""
89
+
90
+ def __init__(self, http_client: HTTPClient, organization_id: str, user_id: str):
91
+ self.http_client = http_client
92
+ self.organization_id = organization_id
93
+ self.user_id = user_id
94
+
95
+ def execute(self) -> Dict[str, Any]:
96
+ """Execute the command to remove user from organization."""
97
+ response = self.http_client.delete(f"organizations/{self.organization_id}/remove-user/{self.user_id}")
98
+
99
+ return response
100
+
101
+
102
+ class AddTagsToOrganizationCommand(Command[Organization]):
103
+ """Command to add tags to an organization."""
104
+
105
+ def __init__(self, http_client: HTTPClient, organization_id: str, request: AddTagsToOrganizationRequest):
106
+ self.http_client = http_client
107
+ self.organization_id = organization_id
108
+ self.request = request
109
+
110
+ def execute(self) -> Organization:
111
+ """Execute the command to add tags to organization."""
112
+ data = self.request.model_dump(exclude_none=True, by_alias=True)
113
+
114
+ response = self.http_client.patch(f"organizations/{self.organization_id}/tags", json_data=data)
115
+
116
+ entity_data = response.get("result", {})
117
+
118
+ # Use Pydantic model_validate for automatic field mapping
119
+ return Organization.model_validate(entity_data)
120
+
121
+
122
+ class DeleteTagsFromOrganizationCommand(Command[Organization]):
123
+ """Command to delete tags from an organization."""
124
+
125
+ def __init__(self, http_client: HTTPClient, organization_id: str, request: DeleteTagsFromOrganizationRequest):
126
+ self.http_client = http_client
127
+ self.organization_id = organization_id
128
+ self.request = request
129
+
130
+ def execute(self) -> Organization:
131
+ """Execute the command to delete tags from organization."""
132
+ data = self.request.model_dump(exclude_none=True, by_alias=True)
133
+
134
+ response = self.http_client.delete(f"organizations/{self.organization_id}/tags", json_data=data)
135
+
136
+ entity_data = response.get("result", {})
137
+
138
+ # Use Pydantic model_validate for automatic field mapping
139
+ return Organization.model_validate(entity_data)
140
+
141
+
142
+ class UpdateShareableDeploymentSettingsCommand(Command[bool]):
143
+ """Command to update organization shareable deployment settings."""
144
+
145
+ def __init__(self, http_client: HTTPClient, organization_id: str, request: UpdateShareableDeploymentSettingsRequest):
146
+ self.http_client = http_client
147
+ self.organization_id = organization_id
148
+ self.request = request
149
+
150
+ def execute(self) -> bool:
151
+ """Execute the command to update shareable deployment settings."""
152
+ data = self.request.model_dump(exclude_none=True, by_alias=True)
153
+
154
+ response = self.http_client.post(f"organizations/{self.organization_id}/shareable-deployment", json_data=data)
155
+
156
+ return response.get("success", False)
157
+
158
+
159
+ class UpdateDeploymentTokenCommand(Command[DeploymentTokenUpdateResponse]):
160
+ """Command to update organization deployment token."""
161
+
162
+ def __init__(self, http_client: HTTPClient, organization_id: str):
163
+ self.http_client = http_client
164
+ self.organization_id = organization_id
165
+
166
+ def execute(self) -> DeploymentTokenUpdateResponse:
167
+ """Execute the command to update deployment token."""
168
+ response = self.http_client.post(f"organizations/{self.organization_id}/deployment-token")
169
+
170
+ # Use Pydantic model_validate for automatic field mapping
171
+ return DeploymentTokenUpdateResponse.model_validate(response)
172
+
173
+
174
+ class UpdateOrganizationSettingsCommand(Command[OrganizationSettings]):
175
+ """Command to update organization settings."""
176
+
177
+ def __init__(self, http_client: HTTPClient, organization_id: str, settings: Dict[str, Any]):
178
+ self.http_client = http_client
179
+ self.organization_id = organization_id
180
+ self.settings = settings
181
+
182
+ def execute(self) -> OrganizationSettings:
183
+ """Execute the command to update organization settings."""
184
+ response = self.http_client.put(f"organizations/{self.organization_id}/settings", json_data=self.settings)
185
+
186
+ entity_data = response.get("result", {})
187
+
188
+ mapped_data = {
189
+ "organization_id": entity_data.get("organizationId"),
190
+ "retention_policy": entity_data.get("retentionPolicy", {}),
191
+ "security_settings": entity_data.get("securitySettings", {}),
192
+ "notification_settings": entity_data.get("notificationSettings", {}),
193
+ "api_settings": entity_data.get("apiSettings", {}),
194
+ "custom_settings": entity_data.get("customSettings", {}),
195
+ }
196
+
197
+ # Remove None values
198
+ mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
199
+
200
+ return OrganizationSettings(**mapped_data)