tallyfy 1.0.16__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 (52) hide show
  1. tallyfy/__init__.py +27 -0
  2. tallyfy/__pycache__/__init__.cpython-310.pyc +0 -0
  3. tallyfy/__pycache__/core.cpython-310.pyc +0 -0
  4. tallyfy/__pycache__/form_fields_management.cpython-310.pyc +0 -0
  5. tallyfy/__pycache__/models.cpython-310.pyc +0 -0
  6. tallyfy/__pycache__/task_management.cpython-310.pyc +0 -0
  7. tallyfy/__pycache__/template_management.cpython-310.pyc +0 -0
  8. tallyfy/__pycache__/user_management.cpython-310.pyc +0 -0
  9. tallyfy/core.py +361 -0
  10. tallyfy/form_fields_management/__init__.py +70 -0
  11. tallyfy/form_fields_management/__pycache__/__init__.cpython-310.pyc +0 -0
  12. tallyfy/form_fields_management/__pycache__/base.cpython-310.pyc +0 -0
  13. tallyfy/form_fields_management/__pycache__/crud_operations.cpython-310.pyc +0 -0
  14. tallyfy/form_fields_management/__pycache__/options_management.cpython-310.pyc +0 -0
  15. tallyfy/form_fields_management/__pycache__/suggestions.cpython-310.pyc +0 -0
  16. tallyfy/form_fields_management/base.py +109 -0
  17. tallyfy/form_fields_management/crud_operations.py +234 -0
  18. tallyfy/form_fields_management/options_management.py +222 -0
  19. tallyfy/form_fields_management/suggestions.py +411 -0
  20. tallyfy/models.py +1464 -0
  21. tallyfy/organization_management/__init__.py +26 -0
  22. tallyfy/organization_management/base.py +76 -0
  23. tallyfy/organization_management/retrieval.py +39 -0
  24. tallyfy/task_management/__init__.py +81 -0
  25. tallyfy/task_management/__pycache__/__init__.cpython-310.pyc +0 -0
  26. tallyfy/task_management/__pycache__/base.cpython-310.pyc +0 -0
  27. tallyfy/task_management/__pycache__/creation.cpython-310.pyc +0 -0
  28. tallyfy/task_management/__pycache__/retrieval.cpython-310.pyc +0 -0
  29. tallyfy/task_management/__pycache__/search.cpython-310.pyc +0 -0
  30. tallyfy/task_management/base.py +125 -0
  31. tallyfy/task_management/creation.py +221 -0
  32. tallyfy/task_management/retrieval.py +252 -0
  33. tallyfy/task_management/search.py +198 -0
  34. tallyfy/template_management/__init__.py +85 -0
  35. tallyfy/template_management/analysis.py +1099 -0
  36. tallyfy/template_management/automation.py +469 -0
  37. tallyfy/template_management/base.py +56 -0
  38. tallyfy/template_management/basic_operations.py +479 -0
  39. tallyfy/template_management/health_assessment.py +793 -0
  40. tallyfy/user_management/__init__.py +70 -0
  41. tallyfy/user_management/__pycache__/__init__.cpython-310.pyc +0 -0
  42. tallyfy/user_management/__pycache__/base.cpython-310.pyc +0 -0
  43. tallyfy/user_management/__pycache__/invitation.cpython-310.pyc +0 -0
  44. tallyfy/user_management/__pycache__/retrieval.cpython-310.pyc +0 -0
  45. tallyfy/user_management/base.py +146 -0
  46. tallyfy/user_management/invitation.py +286 -0
  47. tallyfy/user_management/retrieval.py +381 -0
  48. tallyfy-1.0.16.dist-info/METADATA +742 -0
  49. tallyfy-1.0.16.dist-info/RECORD +52 -0
  50. tallyfy-1.0.16.dist-info/WHEEL +5 -0
  51. tallyfy-1.0.16.dist-info/licenses/LICENSE +21 -0
  52. tallyfy-1.0.16.dist-info/top_level.txt +1 -0
@@ -0,0 +1,381 @@
1
+ """
2
+ User and guest retrieval operations
3
+ """
4
+
5
+ from typing import List, Optional
6
+ from .base import UserManagerBase
7
+ from ..models import User, Guest, UsersList, GuestsList, TallyfyError
8
+
9
+
10
+ class UserRetrieval(UserManagerBase):
11
+ """Handles user and guest retrieval operations"""
12
+
13
+ def get_current_user_info(self, org_id: str) -> Optional[User]:
14
+ """
15
+ Get current user with full profile data.
16
+
17
+ Args:
18
+ org_id: Organization ID
19
+
20
+ Returns:
21
+ A User object with full profile data
22
+
23
+ Raises:
24
+ TallyfyError: If the request fails
25
+ """
26
+ self._validate_org_id(org_id)
27
+
28
+ try:
29
+ endpoint = f"organizations/{org_id}/me"
30
+ response_data = self.sdk._make_request('GET', endpoint)
31
+
32
+ user_data = self._extract_data(response_data, default_empty=False)
33
+ if user_data:
34
+ # Handle both single user data and wrapped responses
35
+ if isinstance(user_data, list) and user_data:
36
+ return User.from_dict(user_data[0])
37
+ elif isinstance(user_data, dict):
38
+ return User.from_dict(user_data)
39
+
40
+ self.sdk.logger.warning("Unexpected response format for getting current user")
41
+ return None
42
+
43
+ except TallyfyError:
44
+ raise
45
+ except Exception as e:
46
+ self._handle_api_error(e, "get current user info", org_id=org_id)
47
+
48
+ def get_user(self, org_id: str, user_id: int) -> Optional[User]:
49
+ """
50
+ Get user with full profile data.
51
+
52
+ Args:
53
+ org_id: Organization ID
54
+ user_id: User ID
55
+
56
+ Returns:
57
+ A User object with full profile data
58
+
59
+ Raises:
60
+ TallyfyError: If the request fails
61
+ """
62
+ self._validate_org_id(org_id)
63
+
64
+ try:
65
+ endpoint = f"organizations/{org_id}/users/{user_id}"
66
+ response_data = self.sdk._make_request('GET', endpoint)
67
+
68
+ user_data = self._extract_data(response_data, default_empty=False)
69
+ if user_data:
70
+ # Handle both single user data and wrapped responses
71
+ if isinstance(user_data, list) and user_data:
72
+ return User.from_dict(user_data[0])
73
+ elif isinstance(user_data, dict):
74
+ return User.from_dict(user_data)
75
+
76
+ self.sdk.logger.warning("Unexpected response format for getting current user")
77
+ return None
78
+
79
+ except TallyfyError:
80
+ raise
81
+ except Exception as e:
82
+ self._handle_api_error(e, "get current user info", org_id=org_id)
83
+
84
+ def get_organization_users(self, org_id: str, with_groups: bool = False,
85
+ page: int = 1, per_page: int = 100) -> UsersList:
86
+ """
87
+ Get all organization members with full profile data.
88
+
89
+ Args:
90
+ org_id: Organization ID
91
+ with_groups: Include user groups data
92
+ page: Page number (default: 1)
93
+ per_page: Number of results per page (default: 100)
94
+
95
+ Returns:
96
+ UsersList object containing users and pagination metadata (total count, etc.)
97
+
98
+ Raises:
99
+ TallyfyError: If the request fails
100
+ """
101
+ self._validate_org_id(org_id)
102
+
103
+ try:
104
+ endpoint = f"organizations/{org_id}/users"
105
+ params = self._build_query_params(
106
+ page=page,
107
+ per_page=per_page,
108
+ **({'with': 'groups'} if with_groups else {})
109
+ )
110
+
111
+ response_data = self.sdk._make_request('GET', endpoint, params=params)
112
+
113
+ # Return the structured response with pagination
114
+ return UsersList.from_dict(response_data)
115
+
116
+ except TallyfyError:
117
+ raise
118
+ except Exception as e:
119
+ self._handle_api_error(e, "get organization users", org_id=org_id)
120
+
121
+ def get_organization_users_list(self, org_id: str) -> List[User]:
122
+ """
123
+ Get all organization members with minimal data for listing.
124
+
125
+ Args:
126
+ org_id: Organization ID
127
+
128
+ Returns:
129
+ List of User objects with minimal data
130
+
131
+ Raises:
132
+ TallyfyError: If the request fails
133
+ """
134
+ self._validate_org_id(org_id)
135
+
136
+ try:
137
+ endpoint = f"organizations/{org_id}/users-list"
138
+ response_data = self.sdk._make_request('GET', endpoint)
139
+
140
+ users_data = self._extract_data(response_data)
141
+ if users_data:
142
+ return [User.from_dict(user_data) for user_data in users_data]
143
+ else:
144
+ self.sdk.logger.warning("Unexpected response format for users list")
145
+ return []
146
+
147
+ except TallyfyError:
148
+ raise
149
+ except Exception as e:
150
+ self._handle_api_error(e, "get organization users list", org_id=org_id)
151
+
152
+ def get_organization_guests(self, org_id: str, with_stats: bool = False,
153
+ page: int = 1, per_page: int = 100) -> GuestsList:
154
+ """
155
+ Get all guests in an organization with full profile data.
156
+
157
+ Args:
158
+ org_id: Organization ID
159
+ with_stats: Include guest statistics
160
+ page: Page number (default: 1)
161
+ per_page: Number of results per page (default: 100)
162
+
163
+ Returns:
164
+ GuestsList object containing guests and pagination metadata (total count, etc.)
165
+
166
+ Raises:
167
+ TallyfyError: If the request fails
168
+ """
169
+ self._validate_org_id(org_id)
170
+
171
+ try:
172
+ endpoint = f"organizations/{org_id}/guests"
173
+ params = self._build_query_params(
174
+ page=page,
175
+ per_page=per_page,
176
+ **({'with': 'stats'} if with_stats else {})
177
+ )
178
+
179
+ response_data = self.sdk._make_request('GET', endpoint, params=params)
180
+
181
+ # Return the structured response with pagination
182
+ return GuestsList.from_dict(response_data)
183
+
184
+ except TallyfyError:
185
+ raise
186
+ except Exception as e:
187
+ self._handle_api_error(e, "get organization guests", org_id=org_id)
188
+
189
+ def get_organization_guests_list(self, org_id: str) -> List[Guest]:
190
+ """
191
+ Get organization guests with minimal data.
192
+
193
+ Args:
194
+ org_id: Organization ID
195
+
196
+ Returns:
197
+ List of Guest objects with minimal data
198
+
199
+ Raises:
200
+ TallyfyError: If the request fails
201
+ """
202
+ self._validate_org_id(org_id)
203
+
204
+ try:
205
+ endpoint = f"organizations/{org_id}/guests-list"
206
+ response_data = self.sdk._make_request('GET', endpoint)
207
+
208
+ # Handle different response formats
209
+ guests_data = self._extract_data(response_data)
210
+ if guests_data:
211
+ # Handle both list of guests and single guest responses
212
+ if isinstance(guests_data, list):
213
+ return [Guest.from_dict(guest_data) for guest_data in guests_data]
214
+ else:
215
+ return [Guest.from_dict(guests_data)]
216
+ else:
217
+ self.sdk.logger.warning("Unexpected response format for guests list")
218
+ return []
219
+
220
+ except TallyfyError:
221
+ raise
222
+ except Exception as e:
223
+ self._handle_api_error(e, "get organization guests list", org_id=org_id)
224
+
225
+ def get_all_organization_members(self, org_id: str, include_guests: bool = True,
226
+ with_groups: bool = False, with_stats: bool = False) -> dict:
227
+ """
228
+ Get all organization members and optionally guests in a single call.
229
+
230
+ This is a convenience method that combines users and guests data.
231
+
232
+ Args:
233
+ org_id: Organization ID
234
+ include_guests: Whether to include guests in the results
235
+ with_groups: Include user groups data
236
+ with_stats: Include guest statistics
237
+
238
+ Returns:
239
+ Dictionary with 'users' (UsersList) and optionally 'guests' (GuestsList) keys
240
+
241
+ Raises:
242
+ TallyfyError: If the request fails
243
+ """
244
+ result = {}
245
+
246
+ # Get users
247
+ result['users'] = self.get_organization_users(org_id, with_groups=with_groups)
248
+
249
+ # Get guests if requested
250
+ if include_guests:
251
+ result['guests'] = self.get_organization_guests(org_id, with_stats=with_stats)
252
+
253
+ return result
254
+
255
+ def get_user_by_email(self, org_id: str, email: str) -> Optional[User]:
256
+ """
257
+ Find a user by email address within an organization.
258
+
259
+ Args:
260
+ org_id: Organization ID
261
+ email: Email address to search for
262
+
263
+ Returns:
264
+ User object if found, None otherwise
265
+
266
+ Raises:
267
+ TallyfyError: If the request fails
268
+ """
269
+ self._validate_org_id(org_id)
270
+ self._validate_email(email)
271
+
272
+ # Get all users and search for the email
273
+ users_list = self.get_organization_users(org_id)
274
+
275
+ for user in users_list.data:
276
+ if hasattr(user, 'email') and user.email and user.email.lower() == email.lower():
277
+ return user
278
+
279
+ return None
280
+
281
+ def get_guest_by_email(self, org_id: str, email: str) -> Optional[Guest]:
282
+ """
283
+ Find a guest by email address within an organization.
284
+
285
+ Args:
286
+ org_id: Organization ID
287
+ email: Email address to search for
288
+
289
+ Returns:
290
+ Guest object if found, None otherwise
291
+
292
+ Raises:
293
+ TallyfyError: If the request fails
294
+ """
295
+ self._validate_org_id(org_id)
296
+ self._validate_email(email)
297
+
298
+ # Get all guests and search for the email
299
+ guests_list = self.get_organization_guests(org_id)
300
+
301
+ for guest in guests_list.data:
302
+ if hasattr(guest, 'email') and guest.email and guest.email.lower() == email.lower():
303
+ return guest
304
+
305
+ return None
306
+
307
+ def search_members_by_name(self, org_id: str, name_query: str, include_guests: bool = True) -> dict:
308
+ """
309
+ Search for organization members by name (first name, last name, or full name).
310
+
311
+ Args:
312
+ org_id: Organization ID
313
+ name_query: Name to search for (case-insensitive partial match)
314
+ include_guests: Whether to include guests in the search
315
+
316
+ Returns:
317
+ Dictionary with 'users' and optionally 'guests' keys containing matching members
318
+
319
+ Raises:
320
+ TallyfyError: If the request fails
321
+ """
322
+ self._validate_org_id(org_id)
323
+
324
+ if not name_query or not isinstance(name_query, str):
325
+ raise ValueError("Name query must be a non-empty string")
326
+
327
+ name_query_lower = name_query.lower()
328
+ result = {'users': [], 'guests': []}
329
+
330
+ # Search users
331
+ users_list = self.get_organization_users(org_id)
332
+ for user in users_list.data:
333
+ user_matches = False
334
+
335
+ # Check first name
336
+ if hasattr(user, 'first_name') and user.first_name:
337
+ if name_query_lower in user.first_name.lower():
338
+ user_matches = True
339
+
340
+ # Check last name
341
+ if hasattr(user, 'last_name') and user.last_name:
342
+ if name_query_lower in user.last_name.lower():
343
+ user_matches = True
344
+
345
+ # Check full name
346
+ if hasattr(user, 'first_name') and hasattr(user, 'last_name'):
347
+ if user.first_name and user.last_name:
348
+ full_name = f"{user.first_name} {user.last_name}".lower()
349
+ if name_query_lower in full_name:
350
+ user_matches = True
351
+
352
+ if user_matches:
353
+ result['users'].append(user)
354
+
355
+ # Search guests if requested
356
+ if include_guests:
357
+ guests_list = self.get_organization_guests(org_id)
358
+ for guest in guests_list.data:
359
+ guest_matches = False
360
+
361
+ # Check first name
362
+ if hasattr(guest, 'first_name') and guest.first_name:
363
+ if name_query_lower in guest.first_name.lower():
364
+ guest_matches = True
365
+
366
+ # Check last name
367
+ if hasattr(guest, 'last_name') and guest.last_name:
368
+ if name_query_lower in guest.last_name.lower():
369
+ guest_matches = True
370
+
371
+ # Check full name
372
+ if hasattr(guest, 'first_name') and hasattr(guest, 'last_name'):
373
+ if guest.first_name and guest.last_name:
374
+ full_name = f"{guest.first_name} {guest.last_name}".lower()
375
+ if name_query_lower in full_name:
376
+ guest_matches = True
377
+
378
+ if guest_matches:
379
+ result['guests'].append(guest)
380
+
381
+ return result