tallyfy 1.0.4__py3-none-any.whl → 1.0.6__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.
Potentially problematic release.
This version of tallyfy might be problematic. Click here for more details.
- tallyfy/__init__.py +8 -4
- tallyfy/core.py +11 -8
- tallyfy/form_fields_management/__init__.py +70 -0
- tallyfy/form_fields_management/base.py +109 -0
- tallyfy/form_fields_management/crud_operations.py +234 -0
- tallyfy/form_fields_management/options_management.py +222 -0
- tallyfy/form_fields_management/suggestions.py +411 -0
- tallyfy/models.py +3 -1
- tallyfy/task_management/__init__.py +81 -0
- tallyfy/task_management/base.py +125 -0
- tallyfy/task_management/creation.py +221 -0
- tallyfy/task_management/retrieval.py +211 -0
- tallyfy/task_management/search.py +196 -0
- tallyfy/template_management/__init__.py +85 -0
- tallyfy/template_management/analysis.py +1093 -0
- tallyfy/template_management/automation.py +469 -0
- tallyfy/template_management/base.py +56 -0
- tallyfy/template_management/basic_operations.py +477 -0
- tallyfy/template_management/health_assessment.py +763 -0
- tallyfy/user_management/__init__.py +69 -0
- tallyfy/user_management/base.py +146 -0
- tallyfy/user_management/invitation.py +286 -0
- tallyfy/user_management/retrieval.py +339 -0
- {tallyfy-1.0.4.dist-info → tallyfy-1.0.6.dist-info}/METADATA +120 -56
- tallyfy-1.0.6.dist-info/RECORD +28 -0
- tallyfy/BUILD.md +0 -5
- tallyfy/form_fields_management.py +0 -582
- tallyfy/task_management.py +0 -356
- tallyfy/template_management.py +0 -2607
- tallyfy/user_management.py +0 -235
- tallyfy-1.0.4.dist-info/RECORD +0 -13
- {tallyfy-1.0.4.dist-info → tallyfy-1.0.6.dist-info}/WHEEL +0 -0
- {tallyfy-1.0.4.dist-info → tallyfy-1.0.6.dist-info}/licenses/LICENSE +0 -0
- {tallyfy-1.0.4.dist-info → tallyfy-1.0.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,339 @@
|
|
|
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, 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_organization_users(self, org_id: str, with_groups: bool = False) -> List[User]:
|
|
49
|
+
"""
|
|
50
|
+
Get all organization members with full profile data.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
org_id: Organization ID
|
|
54
|
+
with_groups: Include user groups data
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
List of User objects 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"
|
|
66
|
+
params = self._build_query_params(**{'with': 'groups'} if with_groups else {})
|
|
67
|
+
|
|
68
|
+
response_data = self.sdk._make_request('GET', endpoint, params=params)
|
|
69
|
+
|
|
70
|
+
users_data = self._extract_data(response_data)
|
|
71
|
+
if users_data:
|
|
72
|
+
return [User.from_dict(user_data) for user_data in users_data]
|
|
73
|
+
else:
|
|
74
|
+
self.sdk.logger.warning("Unexpected response format for users")
|
|
75
|
+
return []
|
|
76
|
+
|
|
77
|
+
except TallyfyError:
|
|
78
|
+
raise
|
|
79
|
+
except Exception as e:
|
|
80
|
+
self._handle_api_error(e, "get organization users", org_id=org_id)
|
|
81
|
+
|
|
82
|
+
def get_organization_users_list(self, org_id: str) -> List[User]:
|
|
83
|
+
"""
|
|
84
|
+
Get all organization members with minimal data for listing.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
org_id: Organization ID
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
List of User objects with minimal data
|
|
91
|
+
|
|
92
|
+
Raises:
|
|
93
|
+
TallyfyError: If the request fails
|
|
94
|
+
"""
|
|
95
|
+
self._validate_org_id(org_id)
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
endpoint = f"organizations/{org_id}/users-list"
|
|
99
|
+
response_data = self.sdk._make_request('GET', endpoint)
|
|
100
|
+
|
|
101
|
+
users_data = self._extract_data(response_data)
|
|
102
|
+
if users_data:
|
|
103
|
+
return [User.from_dict(user_data) for user_data in users_data]
|
|
104
|
+
else:
|
|
105
|
+
self.sdk.logger.warning("Unexpected response format for users list")
|
|
106
|
+
return []
|
|
107
|
+
|
|
108
|
+
except TallyfyError:
|
|
109
|
+
raise
|
|
110
|
+
except Exception as e:
|
|
111
|
+
self._handle_api_error(e, "get organization users list", org_id=org_id)
|
|
112
|
+
|
|
113
|
+
def get_organization_guests(self, org_id: str, with_stats: bool = False) -> List[Guest]:
|
|
114
|
+
"""
|
|
115
|
+
Get all guests in an organization with full profile data.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
org_id: Organization ID
|
|
119
|
+
with_stats: Include guest statistics
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
List of Guest objects with full profile data
|
|
123
|
+
|
|
124
|
+
Raises:
|
|
125
|
+
TallyfyError: If the request fails
|
|
126
|
+
"""
|
|
127
|
+
self._validate_org_id(org_id)
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
endpoint = f"organizations/{org_id}/guests"
|
|
131
|
+
params = self._build_query_params(**{'with': 'stats'} if with_stats else {})
|
|
132
|
+
|
|
133
|
+
response_data = self.sdk._make_request('GET', endpoint, params=params)
|
|
134
|
+
|
|
135
|
+
guests_data = self._extract_data(response_data)
|
|
136
|
+
if guests_data:
|
|
137
|
+
return [Guest.from_dict(guest_data) for guest_data in guests_data]
|
|
138
|
+
else:
|
|
139
|
+
self.sdk.logger.warning("Unexpected response format for guests")
|
|
140
|
+
return []
|
|
141
|
+
|
|
142
|
+
except TallyfyError:
|
|
143
|
+
raise
|
|
144
|
+
except Exception as e:
|
|
145
|
+
self._handle_api_error(e, "get organization guests", org_id=org_id)
|
|
146
|
+
|
|
147
|
+
def get_organization_guests_list(self, org_id: str) -> List[Guest]:
|
|
148
|
+
"""
|
|
149
|
+
Get organization guests with minimal data.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
org_id: Organization ID
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
List of Guest objects with minimal data
|
|
156
|
+
|
|
157
|
+
Raises:
|
|
158
|
+
TallyfyError: If the request fails
|
|
159
|
+
"""
|
|
160
|
+
self._validate_org_id(org_id)
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
endpoint = f"organizations/{org_id}/guests-list"
|
|
164
|
+
response_data = self.sdk._make_request('GET', endpoint)
|
|
165
|
+
|
|
166
|
+
# Handle different response formats
|
|
167
|
+
guests_data = self._extract_data(response_data)
|
|
168
|
+
if guests_data:
|
|
169
|
+
# Handle both list of guests and single guest responses
|
|
170
|
+
if isinstance(guests_data, list):
|
|
171
|
+
return [Guest.from_dict(guest_data) for guest_data in guests_data]
|
|
172
|
+
else:
|
|
173
|
+
return [Guest.from_dict(guests_data)]
|
|
174
|
+
else:
|
|
175
|
+
self.sdk.logger.warning("Unexpected response format for guests list")
|
|
176
|
+
return []
|
|
177
|
+
|
|
178
|
+
except TallyfyError:
|
|
179
|
+
raise
|
|
180
|
+
except Exception as e:
|
|
181
|
+
self._handle_api_error(e, "get organization guests list", org_id=org_id)
|
|
182
|
+
|
|
183
|
+
def get_all_organization_members(self, org_id: str, include_guests: bool = True,
|
|
184
|
+
with_groups: bool = False, with_stats: bool = False) -> dict:
|
|
185
|
+
"""
|
|
186
|
+
Get all organization members and optionally guests in a single call.
|
|
187
|
+
|
|
188
|
+
This is a convenience method that combines users and guests data.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
org_id: Organization ID
|
|
192
|
+
include_guests: Whether to include guests in the results
|
|
193
|
+
with_groups: Include user groups data
|
|
194
|
+
with_stats: Include guest statistics
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Dictionary with 'users' and optionally 'guests' keys
|
|
198
|
+
|
|
199
|
+
Raises:
|
|
200
|
+
TallyfyError: If the request fails
|
|
201
|
+
"""
|
|
202
|
+
result = {}
|
|
203
|
+
|
|
204
|
+
# Get users
|
|
205
|
+
result['users'] = self.get_organization_users(org_id, with_groups=with_groups)
|
|
206
|
+
|
|
207
|
+
# Get guests if requested
|
|
208
|
+
if include_guests:
|
|
209
|
+
result['guests'] = self.get_organization_guests(org_id, with_stats=with_stats)
|
|
210
|
+
|
|
211
|
+
return result
|
|
212
|
+
|
|
213
|
+
def get_user_by_email(self, org_id: str, email: str) -> Optional[User]:
|
|
214
|
+
"""
|
|
215
|
+
Find a user by email address within an organization.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
org_id: Organization ID
|
|
219
|
+
email: Email address to search for
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
User object if found, None otherwise
|
|
223
|
+
|
|
224
|
+
Raises:
|
|
225
|
+
TallyfyError: If the request fails
|
|
226
|
+
"""
|
|
227
|
+
self._validate_org_id(org_id)
|
|
228
|
+
self._validate_email(email)
|
|
229
|
+
|
|
230
|
+
# Get all users and search for the email
|
|
231
|
+
users = self.get_organization_users(org_id)
|
|
232
|
+
|
|
233
|
+
for user in users:
|
|
234
|
+
if hasattr(user, 'email') and user.email and user.email.lower() == email.lower():
|
|
235
|
+
return user
|
|
236
|
+
|
|
237
|
+
return None
|
|
238
|
+
|
|
239
|
+
def get_guest_by_email(self, org_id: str, email: str) -> Optional[Guest]:
|
|
240
|
+
"""
|
|
241
|
+
Find a guest by email address within an organization.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
org_id: Organization ID
|
|
245
|
+
email: Email address to search for
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
Guest object if found, None otherwise
|
|
249
|
+
|
|
250
|
+
Raises:
|
|
251
|
+
TallyfyError: If the request fails
|
|
252
|
+
"""
|
|
253
|
+
self._validate_org_id(org_id)
|
|
254
|
+
self._validate_email(email)
|
|
255
|
+
|
|
256
|
+
# Get all guests and search for the email
|
|
257
|
+
guests = self.get_organization_guests(org_id)
|
|
258
|
+
|
|
259
|
+
for guest in guests:
|
|
260
|
+
if hasattr(guest, 'email') and guest.email and guest.email.lower() == email.lower():
|
|
261
|
+
return guest
|
|
262
|
+
|
|
263
|
+
return None
|
|
264
|
+
|
|
265
|
+
def search_members_by_name(self, org_id: str, name_query: str, include_guests: bool = True) -> dict:
|
|
266
|
+
"""
|
|
267
|
+
Search for organization members by name (first name, last name, or full name).
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
org_id: Organization ID
|
|
271
|
+
name_query: Name to search for (case-insensitive partial match)
|
|
272
|
+
include_guests: Whether to include guests in the search
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
Dictionary with 'users' and optionally 'guests' keys containing matching members
|
|
276
|
+
|
|
277
|
+
Raises:
|
|
278
|
+
TallyfyError: If the request fails
|
|
279
|
+
"""
|
|
280
|
+
self._validate_org_id(org_id)
|
|
281
|
+
|
|
282
|
+
if not name_query or not isinstance(name_query, str):
|
|
283
|
+
raise ValueError("Name query must be a non-empty string")
|
|
284
|
+
|
|
285
|
+
name_query_lower = name_query.lower()
|
|
286
|
+
result = {'users': [], 'guests': []}
|
|
287
|
+
|
|
288
|
+
# Search users
|
|
289
|
+
users = self.get_organization_users(org_id)
|
|
290
|
+
for user in users:
|
|
291
|
+
user_matches = False
|
|
292
|
+
|
|
293
|
+
# Check first name
|
|
294
|
+
if hasattr(user, 'first_name') and user.first_name:
|
|
295
|
+
if name_query_lower in user.first_name.lower():
|
|
296
|
+
user_matches = True
|
|
297
|
+
|
|
298
|
+
# Check last name
|
|
299
|
+
if hasattr(user, 'last_name') and user.last_name:
|
|
300
|
+
if name_query_lower in user.last_name.lower():
|
|
301
|
+
user_matches = True
|
|
302
|
+
|
|
303
|
+
# Check full name
|
|
304
|
+
if hasattr(user, 'first_name') and hasattr(user, 'last_name'):
|
|
305
|
+
if user.first_name and user.last_name:
|
|
306
|
+
full_name = f"{user.first_name} {user.last_name}".lower()
|
|
307
|
+
if name_query_lower in full_name:
|
|
308
|
+
user_matches = True
|
|
309
|
+
|
|
310
|
+
if user_matches:
|
|
311
|
+
result['users'].append(user)
|
|
312
|
+
|
|
313
|
+
# Search guests if requested
|
|
314
|
+
if include_guests:
|
|
315
|
+
guests = self.get_organization_guests(org_id)
|
|
316
|
+
for guest in guests:
|
|
317
|
+
guest_matches = False
|
|
318
|
+
|
|
319
|
+
# Check first name
|
|
320
|
+
if hasattr(guest, 'first_name') and guest.first_name:
|
|
321
|
+
if name_query_lower in guest.first_name.lower():
|
|
322
|
+
guest_matches = True
|
|
323
|
+
|
|
324
|
+
# Check last name
|
|
325
|
+
if hasattr(guest, 'last_name') and guest.last_name:
|
|
326
|
+
if name_query_lower in guest.last_name.lower():
|
|
327
|
+
guest_matches = True
|
|
328
|
+
|
|
329
|
+
# Check full name
|
|
330
|
+
if hasattr(guest, 'first_name') and hasattr(guest, 'last_name'):
|
|
331
|
+
if guest.first_name and guest.last_name:
|
|
332
|
+
full_name = f"{guest.first_name} {guest.last_name}".lower()
|
|
333
|
+
if name_query_lower in full_name:
|
|
334
|
+
guest_matches = True
|
|
335
|
+
|
|
336
|
+
if guest_matches:
|
|
337
|
+
result['guests'].append(guest)
|
|
338
|
+
|
|
339
|
+
return result
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tallyfy
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.6
|
|
4
4
|
Summary: A comprehensive Python SDK for interacting with the Tallyfy API
|
|
5
5
|
Home-page: https://github.com/tallyfy/tallyfy-sdk
|
|
6
6
|
Author: Tallyfy
|
|
@@ -31,6 +31,7 @@ Description-Content-Type: text/markdown
|
|
|
31
31
|
License-File: LICENSE
|
|
32
32
|
Requires-Dist: requests>=2.25.0
|
|
33
33
|
Requires-Dist: typing-extensions>=4.0.0; python_version < "3.8"
|
|
34
|
+
Requires-Dist: email-validator==2.2.0
|
|
34
35
|
Provides-Extra: dev
|
|
35
36
|
Requires-Dist: pytest>=6.0.0; extra == "dev"
|
|
36
37
|
Requires-Dist: pytest-cov>=2.10.0; extra == "dev"
|
|
@@ -62,7 +63,7 @@ A comprehensive Python SDK for interacting with the Tallyfy API. This SDK provid
|
|
|
62
63
|
## Installation
|
|
63
64
|
|
|
64
65
|
```bash
|
|
65
|
-
pip install
|
|
66
|
+
pip install tallyfy
|
|
66
67
|
```
|
|
67
68
|
|
|
68
69
|
**Dependencies:**
|
|
@@ -101,12 +102,11 @@ The Tallyfy SDK follows a modular architecture with specialized management class
|
|
|
101
102
|
- **`TallyfySDK`** - Main SDK class that orchestrates all operations with backward compatibility methods
|
|
102
103
|
- **`BaseSDK`** - Base class with HTTP request handling, retry logic, and connection pooling
|
|
103
104
|
- **Management Modules:**
|
|
104
|
-
- `
|
|
105
|
-
- `
|
|
106
|
-
- `
|
|
107
|
-
- `
|
|
108
|
-
- **
|
|
109
|
-
- `DateExtractor` - Natural language date parsing and task extraction
|
|
105
|
+
- `UserManager` - User and guest operations with modular retrieval and invitation components
|
|
106
|
+
- `TaskManager` - Task and process operations with search and creation capabilities
|
|
107
|
+
- `TemplateManager` - Template/checklist operations with automation analysis and health assessment
|
|
108
|
+
- `FormFieldManager` - Form field operations with AI-powered suggestions and dropdown management
|
|
109
|
+
- **Error Handling:**
|
|
110
110
|
- `TallyfyError` - Custom exception handling with status codes and response data
|
|
111
111
|
|
|
112
112
|
### File Structure
|
|
@@ -116,10 +116,30 @@ tallyfy/
|
|
|
116
116
|
├── __init__.py # SDK exports and version
|
|
117
117
|
├── core.py # BaseSDK and TallyfySDK classes
|
|
118
118
|
├── models.py # Data models and types
|
|
119
|
-
├── user_management
|
|
120
|
-
├──
|
|
121
|
-
├──
|
|
122
|
-
├──
|
|
119
|
+
├── user_management/ # User and guest management (modular)
|
|
120
|
+
│ ├── __init__.py # UserManager with unified interface
|
|
121
|
+
│ ├── base.py # Common validation and error handling
|
|
122
|
+
│ ├── retrieval.py # User and guest retrieval operations
|
|
123
|
+
│ └── invitation.py # User invitation operations
|
|
124
|
+
├── task_management/ # Task and process management (modular)
|
|
125
|
+
│ ├── __init__.py # TaskManager with unified interface
|
|
126
|
+
│ ├── base.py # Common task operations base
|
|
127
|
+
│ ├── retrieval.py # Task and process retrieval
|
|
128
|
+
│ ├── search.py # Search functionality
|
|
129
|
+
│ └── creation.py # Task creation operations
|
|
130
|
+
├── template_management/ # Template management (modular)
|
|
131
|
+
│ ├── __init__.py # TemplateManager with unified interface
|
|
132
|
+
│ ├── base.py # Common template operations
|
|
133
|
+
│ ├── basic_operations.py # Template retrieval and CRUD operations
|
|
134
|
+
│ ├── automation.py # Automation rule management
|
|
135
|
+
│ ├── analysis.py # Template analysis and health checks
|
|
136
|
+
│ └── health_assessment.py # Template health assessment functionality
|
|
137
|
+
├── form_fields_management/ # Form field management (modular)
|
|
138
|
+
│ ├── __init__.py # FormFieldManager with unified interface
|
|
139
|
+
│ ├── base.py # Common form field operations
|
|
140
|
+
│ ├── crud_operations.py # CRUD operations for form fields
|
|
141
|
+
│ ├── options_management.py # Dropdown options management
|
|
142
|
+
│ └── suggestions.py # AI-powered field suggestions
|
|
123
143
|
└── README.md # This documentation
|
|
124
144
|
```
|
|
125
145
|
|
|
@@ -133,16 +153,19 @@ tallyfy/
|
|
|
133
153
|
- Comprehensive error handling with detailed error information
|
|
134
154
|
|
|
135
155
|
### 👥 User Management
|
|
156
|
+
- **Modular architecture** with specialized retrieval and invitation components
|
|
136
157
|
- Get organization members with full profile data (country, timezone, job details)
|
|
137
158
|
- Get minimal user lists for performance-critical operations
|
|
138
159
|
- Manage guests and external users with guest-specific features
|
|
139
|
-
-
|
|
140
|
-
-
|
|
160
|
+
- **Enhanced search capabilities** - Find users by email or name with fuzzy matching
|
|
161
|
+
- **Batch invitation support** - Invite multiple users with default roles and messages
|
|
162
|
+
- **Advanced invitation features** - Custom messages, role validation, and resend functionality
|
|
163
|
+
- Support for user groups and permissions with flexible query parameters
|
|
164
|
+
- **Convenience methods** - Get all members (users + guests) in a single call
|
|
141
165
|
|
|
142
166
|
### ✅ Task Management
|
|
143
167
|
- Get tasks for specific users or processes with filtering
|
|
144
168
|
- Create standalone tasks with rich assignment options
|
|
145
|
-
- **Natural language task creation** with automatic date/time extraction
|
|
146
169
|
- Search processes by name with fuzzy matching
|
|
147
170
|
- Advanced filtering for organization runs (status, owners, tags, etc.)
|
|
148
171
|
- Universal search across processes, templates, and tasks
|
|
@@ -175,16 +198,8 @@ tallyfy/
|
|
|
175
198
|
- Exact and fuzzy matching with relevance scoring
|
|
176
199
|
- Pagination support with configurable page sizes
|
|
177
200
|
- Rich search results with metadata and context
|
|
178
|
-
- **Natural language date extraction** from search queries
|
|
179
201
|
- Process and template name-based search with suggestions
|
|
180
202
|
|
|
181
|
-
### 🤖 Natural Language Processing
|
|
182
|
-
- **Task creation from natural language** with automatic parsing
|
|
183
|
-
- **Date extraction** supporting various formats ("next Monday at 12PM", "tomorrow morning")
|
|
184
|
-
- **User/guest resolution** from names and emails
|
|
185
|
-
- **Smart task parsing** extracting titles, descriptions, and deadlines
|
|
186
|
-
- **Fuzzy matching** for user names and process titles
|
|
187
|
-
|
|
188
203
|
## API Reference
|
|
189
204
|
|
|
190
205
|
### SDK Initialization
|
|
@@ -201,20 +216,88 @@ TallyfySDK(
|
|
|
201
216
|
### User Management
|
|
202
217
|
|
|
203
218
|
```python
|
|
204
|
-
# Get all organization users
|
|
219
|
+
# Get all organization users with optional group data
|
|
205
220
|
users = sdk.users.get_organization_users(org_id, with_groups=False)
|
|
206
221
|
|
|
207
|
-
# Get minimal user list
|
|
222
|
+
# Get minimal user list for performance
|
|
208
223
|
users_list = sdk.users.get_organization_users_list(org_id)
|
|
209
224
|
|
|
210
|
-
# Get organization guests
|
|
225
|
+
# Get organization guests with optional statistics
|
|
211
226
|
guests = sdk.users.get_organization_guests(org_id, with_stats=False)
|
|
212
227
|
|
|
213
|
-
#
|
|
228
|
+
# Get current user info
|
|
229
|
+
current_user = sdk.users.get_current_user_info(org_id)
|
|
230
|
+
|
|
231
|
+
# Enhanced search capabilities
|
|
232
|
+
user = sdk.users.get_user_by_email(org_id, "john@company.com")
|
|
233
|
+
guest = sdk.users.get_guest_by_email(org_id, "contractor@company.com")
|
|
234
|
+
|
|
235
|
+
# Search members by name (fuzzy matching)
|
|
236
|
+
search_results = sdk.users.search_members_by_name(org_id, "John Smith", include_guests=True)
|
|
237
|
+
matching_users = search_results['users']
|
|
238
|
+
matching_guests = search_results['guests']
|
|
239
|
+
|
|
240
|
+
# Get all members in one call
|
|
241
|
+
all_members = sdk.users.get_all_organization_members(
|
|
242
|
+
org_id, include_guests=True, with_groups=True, with_stats=True
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
# Invite single user to organization
|
|
214
246
|
user = sdk.users.invite_user_to_organization(
|
|
215
|
-
org_id, email,
|
|
216
|
-
|
|
247
|
+
org_id, email="new.hire@company.com",
|
|
248
|
+
first_name="John", last_name="Doe",
|
|
249
|
+
role="standard",
|
|
250
|
+
message="Welcome! Please complete your onboarding process."
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
# Batch invite multiple users
|
|
254
|
+
invitations = [
|
|
255
|
+
{
|
|
256
|
+
"email": "user1@company.com",
|
|
257
|
+
"first_name": "Jane",
|
|
258
|
+
"last_name": "Smith",
|
|
259
|
+
"role": "standard"
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"email": "user2@company.com",
|
|
263
|
+
"first_name": "Bob",
|
|
264
|
+
"last_name": "Johnson",
|
|
265
|
+
"message": "Welcome to the engineering team!"
|
|
266
|
+
}
|
|
267
|
+
]
|
|
268
|
+
results = sdk.users.invite_multiple_users(
|
|
269
|
+
org_id, invitations,
|
|
270
|
+
default_role="light",
|
|
271
|
+
default_message="Welcome to our organization!"
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
# Resend invitation
|
|
275
|
+
success = sdk.users.resend_invitation(
|
|
276
|
+
org_id, email="pending@company.com",
|
|
277
|
+
message="Reminder: Please accept your invitation to join our organization."
|
|
217
278
|
)
|
|
279
|
+
|
|
280
|
+
# Generate custom invitation message
|
|
281
|
+
message = sdk.users.get_invitation_template_message(
|
|
282
|
+
org_name="ACME Corp",
|
|
283
|
+
custom_text="We're excited to have you join our innovative team!"
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
# Validate invitation data before sending
|
|
287
|
+
invitation_data = {
|
|
288
|
+
"email": "new@company.com",
|
|
289
|
+
"first_name": "Alice",
|
|
290
|
+
"last_name": "Wilson",
|
|
291
|
+
"role": "admin"
|
|
292
|
+
}
|
|
293
|
+
validated_data = sdk.users.validate_invitation_data(invitation_data)
|
|
294
|
+
|
|
295
|
+
# Access modular components directly (advanced usage)
|
|
296
|
+
# Retrieval operations
|
|
297
|
+
users_with_groups = sdk.users.retrieval.get_organization_users(org_id, with_groups=True)
|
|
298
|
+
|
|
299
|
+
# Invitation operations
|
|
300
|
+
batch_results = sdk.users.invitation.invite_multiple_users(org_id, invitations)
|
|
218
301
|
```
|
|
219
302
|
|
|
220
303
|
### Task Management
|
|
@@ -244,14 +327,6 @@ task = sdk.tasks.create_task(
|
|
|
244
327
|
description="Please review the attached document"
|
|
245
328
|
)
|
|
246
329
|
|
|
247
|
-
# Create task from natural language (via MCP Server)
|
|
248
|
-
task_result = create_task_from_text(
|
|
249
|
-
org_id,
|
|
250
|
-
"Create a task called Review Document with description Review the quarterly report the deadline is next Monday at 12PM",
|
|
251
|
-
user_emails=["john@company.com"],
|
|
252
|
-
max_assignable=2
|
|
253
|
-
)
|
|
254
|
-
|
|
255
330
|
# Search processes, templates, or tasks
|
|
256
331
|
results = sdk.tasks.search(org_id, "onboarding", search_type="process")
|
|
257
332
|
|
|
@@ -306,14 +381,13 @@ suggestions = sdk.templates.suggest_automation_consolidation(org_id, template_id
|
|
|
306
381
|
# Assess overall template health
|
|
307
382
|
health_report = sdk.templates.assess_template_health(org_id, template_id)
|
|
308
383
|
|
|
309
|
-
#
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
"
|
|
313
|
-
"
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
kickoff_field = sdk.templates.add_kickoff_field(org_id, template_id, kickoff_data)
|
|
384
|
+
# Template metadata management
|
|
385
|
+
updated = sdk.templates.update_template_metadata(
|
|
386
|
+
org_id, template_id,
|
|
387
|
+
title="Updated Template Title",
|
|
388
|
+
guidance="New guidance text",
|
|
389
|
+
is_featured=True
|
|
390
|
+
)
|
|
317
391
|
|
|
318
392
|
# Add assignees to step
|
|
319
393
|
assignees = {"users": [123, 456], "groups": ["managers"], "guests": ["contractor@company.com"]}
|
|
@@ -640,13 +714,6 @@ enhance_template_with_smart_fields(org_id, "your_template_id")
|
|
|
640
714
|
|
|
641
715
|
## Contributing
|
|
642
716
|
|
|
643
|
-
### Development Setup
|
|
644
|
-
|
|
645
|
-
1. Clone the repository
|
|
646
|
-
2. Install dependencies: `pip install -r requirements.txt`
|
|
647
|
-
3. Set up environment variables in `.env`
|
|
648
|
-
4. Run tests: `python -m pytest tests/`
|
|
649
|
-
|
|
650
717
|
### Code Style
|
|
651
718
|
|
|
652
719
|
- Follow PEP 8 style guidelines
|
|
@@ -662,9 +729,6 @@ enhance_template_with_smart_fields(org_id, "your_template_id")
|
|
|
662
729
|
4. Include error handling and logging
|
|
663
730
|
5. Update this README with usage examples
|
|
664
731
|
|
|
665
|
-
## License
|
|
666
|
-
|
|
667
|
-
This SDK is part of the Tallyfy MCP project. See the main project repository for license information.
|
|
668
732
|
|
|
669
733
|
## Support
|
|
670
734
|
|
|
@@ -674,5 +738,5 @@ For bugs, feature requests, or questions:
|
|
|
674
738
|
2. Contact us at: support@tallyfy.com
|
|
675
739
|
---
|
|
676
740
|
|
|
677
|
-
**Version:** 1.0.
|
|
741
|
+
**Version:** 1.0.6
|
|
678
742
|
**Last Updated:** 2025
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
tallyfy/__init__.py,sha256=vE4XedttVizpD6kJHpTkg686xmokJwQ4rZ749yUCKEA,638
|
|
2
|
+
tallyfy/core.py,sha256=ZEQQIIUDajH8t4RVPxtqu9VR2mFurDBH_o5Hzl0YUUA,16590
|
|
3
|
+
tallyfy/models.py,sha256=6TcrkaLtbp7zz1ZCW6W3Gk5k9Jyp305I1QpLRgO1uw8,38136
|
|
4
|
+
tallyfy/form_fields_management/__init__.py,sha256=epEFynMhcKUKJhY58ZtZ_fCkreBMtg9HbbEQouvK8FM,2567
|
|
5
|
+
tallyfy/form_fields_management/base.py,sha256=6YH5wGTlG1EDEuEFxROz4CPadNHOVX1UZY1zLlfTqbg,3215
|
|
6
|
+
tallyfy/form_fields_management/crud_operations.py,sha256=3XCJunGwMo8z4we8fva8zRryKajBcQMt9Jgg_Y_QM5Q,8877
|
|
7
|
+
tallyfy/form_fields_management/options_management.py,sha256=cZWGBkR3770NEDQYDj9I1ug5lhGQ4tH482sZW6qkapk,8640
|
|
8
|
+
tallyfy/form_fields_management/suggestions.py,sha256=4XaYG7SHAXjjxnVLDGtd0FGOxPrBzPnp4fTjd-Iuj34,16866
|
|
9
|
+
tallyfy/task_management/__init__.py,sha256=5pknQarjvQZtv3Sa2GXxlMqSZ9skCIE6DsJwaGBQWU4,2963
|
|
10
|
+
tallyfy/task_management/base.py,sha256=lHYvdFQh0YlFYawDnApZVU37UWnPkePFcYqFK1QLS1c,4027
|
|
11
|
+
tallyfy/task_management/creation.py,sha256=reaiAFWH7GIlNLTzGwqgJX5iXbHUROXh5oFgEXv-bX4,9012
|
|
12
|
+
tallyfy/task_management/retrieval.py,sha256=fWsED0K_DnDunQl-Y2B7uIjtqz47LdP4oLhrXAUNKYA,7926
|
|
13
|
+
tallyfy/task_management/search.py,sha256=2bFMIsnjq-sE8inj0EP_bK_Ituuq-59bcq9cYedDEmw,7404
|
|
14
|
+
tallyfy/template_management/__init__.py,sha256=9ID-EHNIyucko5TBWagVSp3FKi9ADjNfRMWyT7rPSAo,3674
|
|
15
|
+
tallyfy/template_management/analysis.py,sha256=9rCAw5B8k5919_PUCUAaJe-hJ8n1yCB27rSZWCbYGlg,51547
|
|
16
|
+
tallyfy/template_management/automation.py,sha256=jJnVBdLKUkuS7NsxKmQQ-MGoS0vb9xiX-EOqVNoNcQQ,19809
|
|
17
|
+
tallyfy/template_management/base.py,sha256=wP18jd5T06QwCV2rw4FhSDQCEKlAMwbSg5ffd8vSDVw,2031
|
|
18
|
+
tallyfy/template_management/basic_operations.py,sha256=RzZSvGJ8Q0fcF_c6Vk_PrFhp0rGJ_UUMd3YfxgY5AwE,18888
|
|
19
|
+
tallyfy/template_management/health_assessment.py,sha256=ApyLE3j_XnmtmGsRjWvjPp2faQIcmToi9PvZ0hrVk4o,32085
|
|
20
|
+
tallyfy/user_management/__init__.py,sha256=LTyxJ7i4JrsUMf8QMdtrLdwbgtv8_mmMi8eUmo5Yre8,2658
|
|
21
|
+
tallyfy/user_management/base.py,sha256=jD5jOAu3y0K7fumSH65t9zFRDLriOV-YYPZSuJzYuTE,4681
|
|
22
|
+
tallyfy/user_management/invitation.py,sha256=Ss1Gtii-sS02GuY-XUPYi7dHwAKWMkaG_tRFVOfS_2Q,11395
|
|
23
|
+
tallyfy/user_management/retrieval.py,sha256=M5xFlY2IPIR2b5TUbF0YF2Cm12Mdnu5ZU1iahBFI1vA,11696
|
|
24
|
+
tallyfy-1.0.6.dist-info/licenses/LICENSE,sha256=8HUsrXnc3l2sZxhPV9Z1gYinq76Q2Ym7ahYJy57QlLc,1063
|
|
25
|
+
tallyfy-1.0.6.dist-info/METADATA,sha256=ayLEgfiP9ESfd0MH2HAfYGhVgo3guelApM2QabEAQQo,26359
|
|
26
|
+
tallyfy-1.0.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
27
|
+
tallyfy-1.0.6.dist-info/top_level.txt,sha256=yIycWbR61EZJD0MYRPwUQjOS2XZw5B5jCWx1IP73KcM,8
|
|
28
|
+
tallyfy-1.0.6.dist-info/RECORD,,
|