binalyze-air-sdk 1.0.2__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.2.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.2.dist-info/METADATA +0 -706
  141. binalyze_air_sdk-1.0.2.dist-info/RECORD +0 -82
  142. {binalyze_air_sdk-1.0.2.dist-info → binalyze_air_sdk-1.0.3.dist-info}/top_level.txt +0 -0
@@ -1,223 +1,223 @@
1
- """
2
- Organization-related queries for the Binalyze AIR SDK.
3
- """
4
-
5
- from typing import List, Optional
6
-
7
- from ..base import Query
8
- from ..models.organizations import (
9
- Organization, OrganizationUser, OrganizationRole, OrganizationLicense,
10
- OrganizationSettings, OrganizationFilter, OrganizationsPaginatedResponse,
11
- FilterOption, OrganizationUsersPaginatedResponse, CheckOrganizationNameExistsResponse,
12
- ShareableDeploymentInfoResponse
13
- )
14
- from ..http_client import HTTPClient
15
-
16
-
17
- class ListOrganizationsQuery(Query[OrganizationsPaginatedResponse]):
18
- """Query to list organizations with optional filtering."""
19
-
20
- def __init__(self, http_client: HTTPClient, page: int = 1, page_size: int = 10,
21
- sort_by: str = "name", order: str = "asc", filter_params: Optional[OrganizationFilter] = None):
22
- self.http_client = http_client
23
- self.page = page
24
- self.page_size = page_size
25
- self.sort_by = sort_by
26
- self.order = order
27
- self.filter_params = filter_params or OrganizationFilter()
28
-
29
- def execute(self) -> OrganizationsPaginatedResponse:
30
- """Execute the query to list organizations with complete parameter support."""
31
- # Build query parameters
32
- params = {
33
- "pageNumber": self.page,
34
- "pageSize": self.page_size,
35
- "sortBy": self.sort_by,
36
- "sortType": self.order.upper(), # ASC or DESC
37
- }
38
-
39
- # Add filter parameters using proper API structure
40
- filter_params = self.filter_params.to_params()
41
- params.update(filter_params)
42
-
43
- response = self.http_client.get("organizations", params=params)
44
-
45
- result = response.get("result", {})
46
-
47
- # Use Pydantic model_validate for automatic field mapping
48
- return OrganizationsPaginatedResponse.model_validate(result)
49
-
50
-
51
- class GetOrganizationQuery(Query[Organization]):
52
- """Query to get a specific organization by ID."""
53
-
54
- def __init__(self, http_client: HTTPClient, organization_id: str):
55
- self.http_client = http_client
56
- self.organization_id = organization_id
57
-
58
- def execute(self) -> Organization:
59
- """Execute the query to get organization details."""
60
- response = self.http_client.get(f"organizations/{self.organization_id}")
61
-
62
- entity_data = response.get("result", {})
63
-
64
- # Use Pydantic model_validate for automatic field mapping via aliases
65
- return Organization.model_validate(entity_data)
66
-
67
-
68
- class GetOrganizationUsersQuery(Query[OrganizationUsersPaginatedResponse]):
69
- """Query to get users for a specific organization with complete field mapping."""
70
-
71
- def __init__(self, http_client: HTTPClient, organization_id: str, page: int = 1, page_size: int = 10):
72
- self.http_client = http_client
73
- self.organization_id = organization_id
74
- self.page = page
75
- self.page_size = page_size
76
-
77
- def execute(self) -> OrganizationUsersPaginatedResponse:
78
- """Execute the query to get organization users with complete field mapping."""
79
- # Add pagination parameters
80
- params = {
81
- "pageNumber": self.page,
82
- "pageSize": self.page_size
83
- }
84
-
85
- response = self.http_client.get(f"organizations/{self.organization_id}/users", params=params)
86
-
87
- result = response.get("result", {})
88
-
89
- # Use Pydantic model_validate for automatic field mapping
90
- return OrganizationUsersPaginatedResponse.model_validate(result)
91
-
92
-
93
- class CheckOrganizationNameExistsQuery(Query[CheckOrganizationNameExistsResponse]):
94
- """Query to check if an organization name exists."""
95
-
96
- def __init__(self, http_client: HTTPClient, name: str):
97
- self.http_client = http_client
98
- self.name = name
99
-
100
- def execute(self) -> CheckOrganizationNameExistsResponse:
101
- """Execute the query to check organization name availability."""
102
- params = {"name": self.name}
103
-
104
- response = self.http_client.get("organizations/check", params=params)
105
-
106
- # Use Pydantic model_validate for automatic field mapping
107
- return CheckOrganizationNameExistsResponse.model_validate(response)
108
-
109
-
110
- class GetShareableDeploymentInfoQuery(Query[ShareableDeploymentInfoResponse]):
111
- """Query to get shareable deployment information by token."""
112
-
113
- def __init__(self, http_client: HTTPClient, token: str):
114
- self.http_client = http_client
115
- self.token = token
116
-
117
- def execute(self) -> ShareableDeploymentInfoResponse:
118
- """Execute the query to get shareable deployment information."""
119
- params = {"token": self.token}
120
-
121
- response = self.http_client.get("organizations/shareable-deployment", params=params)
122
-
123
- # Use Pydantic model_validate for automatic field mapping
124
- return ShareableDeploymentInfoResponse.model_validate(response)
125
-
126
-
127
- class GetOrganizationRolesQuery(Query[List[OrganizationRole]]):
128
- """Query to get roles for a specific organization."""
129
-
130
- def __init__(self, http_client: HTTPClient, organization_id: str):
131
- self.http_client = http_client
132
- self.organization_id = organization_id
133
-
134
- def execute(self) -> List[OrganizationRole]:
135
- """Execute the query to get organization roles."""
136
- response = self.http_client.get(f"organizations/{self.organization_id}/roles")
137
-
138
- entities = response.get("result", {}).get("entities", [])
139
-
140
- roles = []
141
- for entity_data in entities:
142
- mapped_data = {
143
- "id": entity_data.get("_id"),
144
- "name": entity_data.get("name"),
145
- "description": entity_data.get("description"),
146
- "organization_id": entity_data.get("organizationId"),
147
- "permissions": entity_data.get("permissions", []),
148
- "created_at": entity_data.get("createdAt"),
149
- "updated_at": entity_data.get("updatedAt"),
150
- "created_by": entity_data.get("createdBy"),
151
- "is_system": entity_data.get("isSystem", False),
152
- "user_count": entity_data.get("userCount", 0),
153
- }
154
-
155
- # Remove None values
156
- mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
157
-
158
- roles.append(OrganizationRole(**mapped_data))
159
-
160
- return roles
161
-
162
-
163
- class GetOrganizationLicensesQuery(Query[List[OrganizationLicense]]):
164
- """Query to get licenses for a specific organization."""
165
-
166
- def __init__(self, http_client: HTTPClient, organization_id: str):
167
- self.http_client = http_client
168
- self.organization_id = organization_id
169
-
170
- def execute(self) -> List[OrganizationLicense]:
171
- """Execute the query to get organization licenses."""
172
- response = self.http_client.get(f"organizations/{self.organization_id}/licenses")
173
-
174
- entities = response.get("result", {}).get("entities", [])
175
-
176
- licenses = []
177
- for entity_data in entities:
178
- mapped_data = {
179
- "id": entity_data.get("_id"),
180
- "organization_id": entity_data.get("organizationId"),
181
- "license_type": entity_data.get("licenseType"),
182
- "total_licenses": entity_data.get("totalLicenses", 0),
183
- "used_licenses": entity_data.get("usedLicenses", 0),
184
- "valid_from": entity_data.get("validFrom"),
185
- "valid_until": entity_data.get("validUntil"),
186
- "features": entity_data.get("features", []),
187
- "is_active": entity_data.get("isActive", True),
188
- }
189
-
190
- # Remove None values
191
- mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
192
-
193
- licenses.append(OrganizationLicense(**mapped_data))
194
-
195
- return licenses
196
-
197
-
198
- class GetOrganizationSettingsQuery(Query[OrganizationSettings]):
199
- """Query to get settings for a specific organization."""
200
-
201
- def __init__(self, http_client: HTTPClient, organization_id: str):
202
- self.http_client = http_client
203
- self.organization_id = organization_id
204
-
205
- def execute(self) -> OrganizationSettings:
206
- """Execute the query to get organization settings."""
207
- response = self.http_client.get(f"organizations/{self.organization_id}/settings")
208
-
209
- entity_data = response.get("result", {})
210
-
211
- mapped_data = {
212
- "organization_id": entity_data.get("organizationId"),
213
- "retention_policy": entity_data.get("retentionPolicy", {}),
214
- "security_settings": entity_data.get("securitySettings", {}),
215
- "notification_settings": entity_data.get("notificationSettings", {}),
216
- "api_settings": entity_data.get("apiSettings", {}),
217
- "custom_settings": entity_data.get("customSettings", {}),
218
- }
219
-
220
- # Remove None values
221
- mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
222
-
1
+ """
2
+ Organization-related queries for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import List, Optional
6
+
7
+ from ..base import Query
8
+ from ..models.organizations import (
9
+ Organization, OrganizationUser, OrganizationRole, OrganizationLicense,
10
+ OrganizationSettings, OrganizationFilter, OrganizationsPaginatedResponse,
11
+ FilterOption, OrganizationUsersPaginatedResponse, CheckOrganizationNameExistsResponse,
12
+ ShareableDeploymentInfoResponse
13
+ )
14
+ from ..http_client import HTTPClient
15
+
16
+
17
+ class ListOrganizationsQuery(Query[OrganizationsPaginatedResponse]):
18
+ """Query to list organizations with optional filtering."""
19
+
20
+ def __init__(self, http_client: HTTPClient, page: int = 1, page_size: int = 10,
21
+ sort_by: str = "name", order: str = "asc", filter_params: Optional[OrganizationFilter] = None):
22
+ self.http_client = http_client
23
+ self.page = page
24
+ self.page_size = page_size
25
+ self.sort_by = sort_by
26
+ self.order = order
27
+ self.filter_params = filter_params or OrganizationFilter()
28
+
29
+ def execute(self) -> OrganizationsPaginatedResponse:
30
+ """Execute the query to list organizations with complete parameter support."""
31
+ # Build query parameters
32
+ params = {
33
+ "pageNumber": self.page,
34
+ "pageSize": self.page_size,
35
+ "sortBy": self.sort_by,
36
+ "sortType": self.order.upper(), # ASC or DESC
37
+ }
38
+
39
+ # Add filter parameters using proper API structure
40
+ filter_params = self.filter_params.to_params()
41
+ params.update(filter_params)
42
+
43
+ response = self.http_client.get("organizations", params=params)
44
+
45
+ result = response.get("result", {})
46
+
47
+ # Use Pydantic model_validate for automatic field mapping
48
+ return OrganizationsPaginatedResponse.model_validate(result)
49
+
50
+
51
+ class GetOrganizationQuery(Query[Organization]):
52
+ """Query to get a specific organization by ID."""
53
+
54
+ def __init__(self, http_client: HTTPClient, organization_id: str):
55
+ self.http_client = http_client
56
+ self.organization_id = organization_id
57
+
58
+ def execute(self) -> Organization:
59
+ """Execute the query to get organization details."""
60
+ response = self.http_client.get(f"organizations/{self.organization_id}")
61
+
62
+ entity_data = response.get("result", {})
63
+
64
+ # Use Pydantic model_validate for automatic field mapping via aliases
65
+ return Organization.model_validate(entity_data)
66
+
67
+
68
+ class GetOrganizationUsersQuery(Query[OrganizationUsersPaginatedResponse]):
69
+ """Query to get users for a specific organization with complete field mapping."""
70
+
71
+ def __init__(self, http_client: HTTPClient, organization_id: str, page: int = 1, page_size: int = 10):
72
+ self.http_client = http_client
73
+ self.organization_id = organization_id
74
+ self.page = page
75
+ self.page_size = page_size
76
+
77
+ def execute(self) -> OrganizationUsersPaginatedResponse:
78
+ """Execute the query to get organization users with complete field mapping."""
79
+ # Add pagination parameters
80
+ params = {
81
+ "pageNumber": self.page,
82
+ "pageSize": self.page_size
83
+ }
84
+
85
+ response = self.http_client.get(f"organizations/{self.organization_id}/users", params=params)
86
+
87
+ result = response.get("result", {})
88
+
89
+ # Use Pydantic model_validate for automatic field mapping
90
+ return OrganizationUsersPaginatedResponse.model_validate(result)
91
+
92
+
93
+ class CheckOrganizationNameExistsQuery(Query[CheckOrganizationNameExistsResponse]):
94
+ """Query to check if an organization name exists."""
95
+
96
+ def __init__(self, http_client: HTTPClient, name: str):
97
+ self.http_client = http_client
98
+ self.name = name
99
+
100
+ def execute(self) -> CheckOrganizationNameExistsResponse:
101
+ """Execute the query to check organization name availability."""
102
+ params = {"name": self.name}
103
+
104
+ response = self.http_client.get("organizations/check", params=params)
105
+
106
+ # Use Pydantic model_validate for automatic field mapping
107
+ return CheckOrganizationNameExistsResponse.model_validate(response)
108
+
109
+
110
+ class GetShareableDeploymentInfoQuery(Query[ShareableDeploymentInfoResponse]):
111
+ """Query to get shareable deployment information by token."""
112
+
113
+ def __init__(self, http_client: HTTPClient, token: str):
114
+ self.http_client = http_client
115
+ self.token = token
116
+
117
+ def execute(self) -> ShareableDeploymentInfoResponse:
118
+ """Execute the query to get shareable deployment information."""
119
+ params = {"token": self.token}
120
+
121
+ response = self.http_client.get("organizations/shareable-deployment", params=params)
122
+
123
+ # Use Pydantic model_validate for automatic field mapping
124
+ return ShareableDeploymentInfoResponse.model_validate(response)
125
+
126
+
127
+ class GetOrganizationRolesQuery(Query[List[OrganizationRole]]):
128
+ """Query to get roles for a specific organization."""
129
+
130
+ def __init__(self, http_client: HTTPClient, organization_id: str):
131
+ self.http_client = http_client
132
+ self.organization_id = organization_id
133
+
134
+ def execute(self) -> List[OrganizationRole]:
135
+ """Execute the query to get organization roles."""
136
+ response = self.http_client.get(f"organizations/{self.organization_id}/roles")
137
+
138
+ entities = response.get("result", {}).get("entities", [])
139
+
140
+ roles = []
141
+ for entity_data in entities:
142
+ mapped_data = {
143
+ "id": entity_data.get("_id"),
144
+ "name": entity_data.get("name"),
145
+ "description": entity_data.get("description"),
146
+ "organization_id": entity_data.get("organizationId"),
147
+ "permissions": entity_data.get("permissions", []),
148
+ "created_at": entity_data.get("createdAt"),
149
+ "updated_at": entity_data.get("updatedAt"),
150
+ "created_by": entity_data.get("createdBy"),
151
+ "is_system": entity_data.get("isSystem", False),
152
+ "user_count": entity_data.get("userCount", 0),
153
+ }
154
+
155
+ # Remove None values
156
+ mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
157
+
158
+ roles.append(OrganizationRole(**mapped_data))
159
+
160
+ return roles
161
+
162
+
163
+ class GetOrganizationLicensesQuery(Query[List[OrganizationLicense]]):
164
+ """Query to get licenses for a specific organization."""
165
+
166
+ def __init__(self, http_client: HTTPClient, organization_id: str):
167
+ self.http_client = http_client
168
+ self.organization_id = organization_id
169
+
170
+ def execute(self) -> List[OrganizationLicense]:
171
+ """Execute the query to get organization licenses."""
172
+ response = self.http_client.get(f"organizations/{self.organization_id}/licenses")
173
+
174
+ entities = response.get("result", {}).get("entities", [])
175
+
176
+ licenses = []
177
+ for entity_data in entities:
178
+ mapped_data = {
179
+ "id": entity_data.get("_id"),
180
+ "organization_id": entity_data.get("organizationId"),
181
+ "license_type": entity_data.get("licenseType"),
182
+ "total_licenses": entity_data.get("totalLicenses", 0),
183
+ "used_licenses": entity_data.get("usedLicenses", 0),
184
+ "valid_from": entity_data.get("validFrom"),
185
+ "valid_until": entity_data.get("validUntil"),
186
+ "features": entity_data.get("features", []),
187
+ "is_active": entity_data.get("isActive", True),
188
+ }
189
+
190
+ # Remove None values
191
+ mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
192
+
193
+ licenses.append(OrganizationLicense(**mapped_data))
194
+
195
+ return licenses
196
+
197
+
198
+ class GetOrganizationSettingsQuery(Query[OrganizationSettings]):
199
+ """Query to get settings for a specific organization."""
200
+
201
+ def __init__(self, http_client: HTTPClient, organization_id: str):
202
+ self.http_client = http_client
203
+ self.organization_id = organization_id
204
+
205
+ def execute(self) -> OrganizationSettings:
206
+ """Execute the query to get organization settings."""
207
+ response = self.http_client.get(f"organizations/{self.organization_id}/settings")
208
+
209
+ entity_data = response.get("result", {})
210
+
211
+ mapped_data = {
212
+ "organization_id": entity_data.get("organizationId"),
213
+ "retention_policy": entity_data.get("retentionPolicy", {}),
214
+ "security_settings": entity_data.get("securitySettings", {}),
215
+ "notification_settings": entity_data.get("notificationSettings", {}),
216
+ "api_settings": entity_data.get("apiSettings", {}),
217
+ "custom_settings": entity_data.get("customSettings", {}),
218
+ }
219
+
220
+ # Remove None values
221
+ mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
222
+
223
223
  return OrganizationSettings(**mapped_data)