smartsheet-python-sdk 3.5.5__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 (195) hide show
  1. smartsheet/__init__.py +37 -0
  2. smartsheet/attachments.py +565 -0
  3. smartsheet/cells.py +164 -0
  4. smartsheet/contacts.py +78 -0
  5. smartsheet/discussions.py +411 -0
  6. smartsheet/events.py +79 -0
  7. smartsheet/exceptions.py +130 -0
  8. smartsheet/favorites.py +116 -0
  9. smartsheet/folders.py +438 -0
  10. smartsheet/groups.py +186 -0
  11. smartsheet/home.py +180 -0
  12. smartsheet/images.py +61 -0
  13. smartsheet/models/__init__.py +126 -0
  14. smartsheet/models/access_token.py +95 -0
  15. smartsheet/models/account.py +77 -0
  16. smartsheet/models/alternate_email.py +88 -0
  17. smartsheet/models/asset_share.py +165 -0
  18. smartsheet/models/asset_shares_paginated_result.py +84 -0
  19. smartsheet/models/attachment.py +181 -0
  20. smartsheet/models/auto_number_format.py +81 -0
  21. smartsheet/models/automation_action.py +162 -0
  22. smartsheet/models/automation_rule.py +164 -0
  23. smartsheet/models/boolean_object_value.py +38 -0
  24. smartsheet/models/bulk_item_failure.py +77 -0
  25. smartsheet/models/bulk_item_result.py +111 -0
  26. smartsheet/models/cell.py +193 -0
  27. smartsheet/models/cell_data_item.py +152 -0
  28. smartsheet/models/cell_history.py +67 -0
  29. smartsheet/models/cell_link.py +91 -0
  30. smartsheet/models/cell_link_widget_content.py +101 -0
  31. smartsheet/models/chart_widget_content.py +124 -0
  32. smartsheet/models/column.py +253 -0
  33. smartsheet/models/comment.py +126 -0
  34. smartsheet/models/contact.py +88 -0
  35. smartsheet/models/contact_object_value.py +59 -0
  36. smartsheet/models/container_destination.py +74 -0
  37. smartsheet/models/copy_or_move_row_destination.py +54 -0
  38. smartsheet/models/copy_or_move_row_directive.py +64 -0
  39. smartsheet/models/copy_or_move_row_result.py +67 -0
  40. smartsheet/models/criteria.py +82 -0
  41. smartsheet/models/cross_sheet_reference.py +134 -0
  42. smartsheet/models/currency.py +64 -0
  43. smartsheet/models/date_object_value.py +56 -0
  44. smartsheet/models/datetime_object_value.py +56 -0
  45. smartsheet/models/discussion.py +183 -0
  46. smartsheet/models/downloaded_file.py +106 -0
  47. smartsheet/models/duration.py +112 -0
  48. smartsheet/models/email.py +82 -0
  49. smartsheet/models/enums/__init__.py +56 -0
  50. smartsheet/models/enums/access_level.py +26 -0
  51. smartsheet/models/enums/asset_type.py +10 -0
  52. smartsheet/models/enums/attachment_parent_type.py +23 -0
  53. smartsheet/models/enums/attachment_sub_type.py +26 -0
  54. smartsheet/models/enums/attachment_type.py +29 -0
  55. smartsheet/models/enums/automation_action_frequency.py +24 -0
  56. smartsheet/models/enums/automation_action_type.py +23 -0
  57. smartsheet/models/enums/automation_rule_disabled_reason.py +27 -0
  58. smartsheet/models/enums/cell_link_status.py +28 -0
  59. smartsheet/models/enums/column_type.py +31 -0
  60. smartsheet/models/enums/criteria_target.py +21 -0
  61. smartsheet/models/enums/cross_sheet_reference_status.py +28 -0
  62. smartsheet/models/enums/currency_code.py +43 -0
  63. smartsheet/models/enums/day_descriptors.py +30 -0
  64. smartsheet/models/enums/day_ordinal.py +25 -0
  65. smartsheet/models/enums/event_action.py +76 -0
  66. smartsheet/models/enums/event_obejct_type.py +34 -0
  67. smartsheet/models/enums/event_source.py +27 -0
  68. smartsheet/models/enums/global_template.py +23 -0
  69. smartsheet/models/enums/operator.py +62 -0
  70. smartsheet/models/enums/paper_type.py +29 -0
  71. smartsheet/models/enums/predecessor_type.py +24 -0
  72. smartsheet/models/enums/publish_accessible_by.py +22 -0
  73. smartsheet/models/enums/schedule_type.py +25 -0
  74. smartsheet/models/enums/seat_type.py +17 -0
  75. smartsheet/models/enums/share_scope.py +22 -0
  76. smartsheet/models/enums/share_type.py +22 -0
  77. smartsheet/models/enums/sheet_email_format.py +23 -0
  78. smartsheet/models/enums/sheet_filter_operator.py +22 -0
  79. smartsheet/models/enums/sheet_filter_type.py +23 -0
  80. smartsheet/models/enums/sort_direction.py +22 -0
  81. smartsheet/models/enums/symbol.py +45 -0
  82. smartsheet/models/enums/system_column_type.py +25 -0
  83. smartsheet/models/enums/update_request_status.py +23 -0
  84. smartsheet/models/enums/user_status.py +23 -0
  85. smartsheet/models/enums/widget_type.py +32 -0
  86. smartsheet/models/error.py +74 -0
  87. smartsheet/models/error_result.py +117 -0
  88. smartsheet/models/event.py +153 -0
  89. smartsheet/models/event_result.py +86 -0
  90. smartsheet/models/explicit_null.py +24 -0
  91. smartsheet/models/favorite.py +81 -0
  92. smartsheet/models/folder.py +177 -0
  93. smartsheet/models/font_family.py +63 -0
  94. smartsheet/models/format_details.py +55 -0
  95. smartsheet/models/format_tables.py +191 -0
  96. smartsheet/models/group.py +134 -0
  97. smartsheet/models/group_member.py +104 -0
  98. smartsheet/models/home.py +110 -0
  99. smartsheet/models/hyperlink.py +81 -0
  100. smartsheet/models/image.py +101 -0
  101. smartsheet/models/image_url.py +91 -0
  102. smartsheet/models/image_url_map.py +68 -0
  103. smartsheet/models/image_widget_content.py +117 -0
  104. smartsheet/models/index_result.py +118 -0
  105. smartsheet/models/json_object.py +59 -0
  106. smartsheet/models/multi_contact_object_value.py +49 -0
  107. smartsheet/models/multi_picklist_object_value.py +48 -0
  108. smartsheet/models/multi_row_email.py +60 -0
  109. smartsheet/models/number_object_value.py +38 -0
  110. smartsheet/models/o_auth_error.py +86 -0
  111. smartsheet/models/object_value.py +130 -0
  112. smartsheet/models/paginated_children_result.py +80 -0
  113. smartsheet/models/predecessor.py +102 -0
  114. smartsheet/models/predecessor_list.py +49 -0
  115. smartsheet/models/primitive_object_value.py +59 -0
  116. smartsheet/models/profile_image.py +72 -0
  117. smartsheet/models/project_settings.py +89 -0
  118. smartsheet/models/recipient.py +63 -0
  119. smartsheet/models/report.py +90 -0
  120. smartsheet/models/report_cell.py +59 -0
  121. smartsheet/models/report_column.py +67 -0
  122. smartsheet/models/report_publish.py +95 -0
  123. smartsheet/models/report_row.py +68 -0
  124. smartsheet/models/report_widget_content.py +78 -0
  125. smartsheet/models/result.py +105 -0
  126. smartsheet/models/row.py +336 -0
  127. smartsheet/models/row_email.py +83 -0
  128. smartsheet/models/row_mapping.py +77 -0
  129. smartsheet/models/schedule.py +140 -0
  130. smartsheet/models/scope.py +70 -0
  131. smartsheet/models/search_result.py +67 -0
  132. smartsheet/models/search_result_item.py +150 -0
  133. smartsheet/models/selection_range.py +86 -0
  134. smartsheet/models/sent_update_request.py +172 -0
  135. smartsheet/models/server_info.py +67 -0
  136. smartsheet/models/share.py +183 -0
  137. smartsheet/models/sheet.py +462 -0
  138. smartsheet/models/sheet_email.py +81 -0
  139. smartsheet/models/sheet_filter.py +106 -0
  140. smartsheet/models/sheet_filter_details.py +76 -0
  141. smartsheet/models/sheet_publish.py +184 -0
  142. smartsheet/models/sheet_summary.py +59 -0
  143. smartsheet/models/sheet_user_permissions.py +58 -0
  144. smartsheet/models/sheet_user_settings.py +72 -0
  145. smartsheet/models/shortcut_data_item.py +102 -0
  146. smartsheet/models/shortcut_widget_content.py +61 -0
  147. smartsheet/models/sight.py +175 -0
  148. smartsheet/models/sight_publish.py +77 -0
  149. smartsheet/models/sort_criterion.py +64 -0
  150. smartsheet/models/sort_specifier.py +55 -0
  151. smartsheet/models/source.py +83 -0
  152. smartsheet/models/string_object_value.py +38 -0
  153. smartsheet/models/summary_field.py +256 -0
  154. smartsheet/models/template.py +171 -0
  155. smartsheet/models/title_rich_text_widget_content.py +68 -0
  156. smartsheet/models/token_paginated_result.py +79 -0
  157. smartsheet/models/update_request.py +110 -0
  158. smartsheet/models/user.py +58 -0
  159. smartsheet/models/user_model.py +280 -0
  160. smartsheet/models/user_plan.py +77 -0
  161. smartsheet/models/user_profile.py +89 -0
  162. smartsheet/models/version.py +57 -0
  163. smartsheet/models/web_content_widget_content.py +60 -0
  164. smartsheet/models/webhook.py +219 -0
  165. smartsheet/models/webhook_secret.py +58 -0
  166. smartsheet/models/webhook_stats.py +76 -0
  167. smartsheet/models/webhook_subscope.py +50 -0
  168. smartsheet/models/widget.py +211 -0
  169. smartsheet/models/widget_content.py +52 -0
  170. smartsheet/models/widget_hyperlink.py +74 -0
  171. smartsheet/models/workspace.py +185 -0
  172. smartsheet/object_value.py +72 -0
  173. smartsheet/passthrough.py +127 -0
  174. smartsheet/reports.py +382 -0
  175. smartsheet/search.py +100 -0
  176. smartsheet/server.py +48 -0
  177. smartsheet/session.py +70 -0
  178. smartsheet/sharing.py +163 -0
  179. smartsheet/sheets.py +2062 -0
  180. smartsheet/sights.py +370 -0
  181. smartsheet/smartsheet.py +684 -0
  182. smartsheet/templates.py +87 -0
  183. smartsheet/token.py +128 -0
  184. smartsheet/types.py +323 -0
  185. smartsheet/users.py +490 -0
  186. smartsheet/util.py +199 -0
  187. smartsheet/version.py +34 -0
  188. smartsheet/webhooks.py +161 -0
  189. smartsheet/workspaces.py +647 -0
  190. smartsheet_python_sdk-3.5.5.dist-info/METADATA +120 -0
  191. smartsheet_python_sdk-3.5.5.dist-info/RECORD +195 -0
  192. smartsheet_python_sdk-3.5.5.dist-info/WHEEL +5 -0
  193. smartsheet_python_sdk-3.5.5.dist-info/licenses/LICENSE.md +201 -0
  194. smartsheet_python_sdk-3.5.5.dist-info/licenses/NOTICE +10 -0
  195. smartsheet_python_sdk-3.5.5.dist-info/top_level.txt +1 -0
smartsheet/users.py ADDED
@@ -0,0 +1,490 @@
1
+ # pylint: disable=C0111,R0902,R0913
2
+ # Smartsheet Python SDK.
3
+ #
4
+ # Copyright 2018 Smartsheet.com, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License"): you may
7
+ # not use this file except in compliance with the License. You may obtain
8
+ # a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ # License for the specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ from __future__ import absolute_import
19
+
20
+ import logging
21
+ from datetime import datetime
22
+
23
+ from . import fresh_operation
24
+ from .models.enums.seat_type import SeatType
25
+
26
+
27
+ class Users:
28
+
29
+ """Class for handling Users operations."""
30
+
31
+ def __init__(self, smartsheet_obj):
32
+ """Init Users with base Smartsheet object."""
33
+ self._base = smartsheet_obj
34
+ self._log = logging.getLogger(__name__)
35
+
36
+ def add_alternate_email(self, user_id, list_of_alternate_emails):
37
+ """Add one or more alternate email addresses for the specified User
38
+
39
+ Args:
40
+ user_id (int): User ID
41
+ list_of_alternate_emails (list[AlternateEmail]):
42
+ An array of one or more AlternateEmail objects.
43
+
44
+ Returns:
45
+ Result
46
+ """
47
+ _op = fresh_operation("add_alternate_email")
48
+ _op["method"] = "POST"
49
+ _op["path"] = "/users/" + str(user_id) + "/alternateemails"
50
+ _op["json"] = list_of_alternate_emails
51
+
52
+ expected = ["Result", "AlternateEmail"]
53
+
54
+ prepped_request = self._base.prepare_request(_op)
55
+ response = self._base.request(prepped_request, expected, _op)
56
+
57
+ return response
58
+
59
+ def promote_alternate_email(self, user_id, alt_id):
60
+ """Promote an email address to primary
61
+
62
+ Args:
63
+ user_id (int): User ID
64
+ alt_id(int): AlternateEmail ID to be promoted
65
+
66
+ Returns:
67
+ Result
68
+ """
69
+ _op = fresh_operation("promote_alternate_email")
70
+ _op["method"] = "POST"
71
+ _op["path"] = (
72
+ "/users/"
73
+ + str(user_id)
74
+ + "/alternateemails/"
75
+ + str(alt_id)
76
+ + "/makeprimary"
77
+ )
78
+
79
+ expected = ["Result", "AlternateEmail"]
80
+
81
+ prepped_request = self._base.prepare_request(_op)
82
+ response = self._base.request(prepped_request, expected, _op)
83
+
84
+ return response
85
+
86
+ def add_user(self, user_obj, send_email=None):
87
+ """Add a User to the organization.
88
+
89
+ Args:
90
+ user_obj (User): User object with the following attributes:
91
+
92
+ email (required)
93
+
94
+ admin (required)
95
+
96
+ licensedSheetCreator (required)
97
+
98
+ firstName (optional)
99
+
100
+ lastName (optional)
101
+
102
+ resourceViewer (optional)
103
+
104
+ send_email (bool): Either true or false to indicate
105
+ whether or not to notify the user by email. Default is false.
106
+
107
+ Returns:
108
+ Result
109
+ """
110
+ _op = fresh_operation("add_user")
111
+ _op["method"] = "POST"
112
+ _op["path"] = "/users"
113
+ _op["json"] = user_obj
114
+ _op["query_params"]["sendEmail"] = send_email
115
+
116
+ expected = ["Result", "User"]
117
+
118
+ prepped_request = self._base.prepare_request(_op)
119
+ response = self._base.request(prepped_request, expected, _op)
120
+
121
+ return response
122
+
123
+ def delete_alternate_email(self, user_id, alternate_email_id):
124
+ """Deletes the specified alternate email address for the specified User.
125
+
126
+ Args:
127
+ user_id (int): User ID
128
+ alternate_email_id (int): Alternate Email ID
129
+
130
+ Returns:
131
+ Result
132
+ """
133
+ _op = fresh_operation("delete_alternate_email")
134
+ _op["method"] = "DELETE"
135
+ _op["path"] = (
136
+ "/users/" + str(user_id) + "/alternateemails/" + str(alternate_email_id)
137
+ )
138
+
139
+ expected = ["Result", None]
140
+ prepped_request = self._base.prepare_request(_op)
141
+ response = self._base.request(prepped_request, expected, _op)
142
+
143
+ return response
144
+
145
+ def get_alternate_email(self, user_id, alternate_email_id):
146
+ """Get the specified Alternate Email
147
+
148
+ Args:
149
+ user_id (int): User ID
150
+ alternate_email_id (int): Alternate Email ID
151
+
152
+ Returns:
153
+ AlternateEmail
154
+ """
155
+ _op = fresh_operation("get_alternate_email")
156
+ _op["method"] = "GET"
157
+ _op["path"] = (
158
+ "/users/" + str(user_id) + "/alternateemails/" + str(alternate_email_id)
159
+ )
160
+
161
+ expected = "AlternateEmail"
162
+ prepped_request = self._base.prepare_request(_op)
163
+ response = self._base.request(prepped_request, expected, _op)
164
+
165
+ return response
166
+
167
+ def get_current_user(self, include=None):
168
+ """Get the currently authenticated User.
169
+ Returns:
170
+ UserProfile
171
+ """
172
+ _op = fresh_operation("get_current_user")
173
+ _op["method"] = "GET"
174
+ _op["path"] = "/users/me"
175
+ _op["query_params"]["include"] = include
176
+
177
+ expected = "UserProfile"
178
+ prepped_request = self._base.prepare_request(_op)
179
+ response = self._base.request(prepped_request, expected, _op)
180
+
181
+ return response
182
+
183
+ def get_user(self, user_id):
184
+ """Get the specified User.
185
+
186
+ Args:
187
+ user_id (int): User ID
188
+
189
+ Returns:
190
+ UserProfile
191
+ """
192
+ _op = fresh_operation("get_user")
193
+ _op["method"] = "GET"
194
+ _op["path"] = "/users/" + str(user_id)
195
+
196
+ expected = "UserProfile"
197
+ prepped_request = self._base.prepare_request(_op)
198
+ response = self._base.request(prepped_request, expected, _op)
199
+
200
+ return response
201
+
202
+ def list_alternate_emails(self, user_id):
203
+ """Get a list of the Alternate Emails for the specified User.
204
+
205
+ Args:
206
+ user_id (int): User ID
207
+
208
+ Returns:
209
+ IndexResult
210
+ """
211
+ _op = fresh_operation("list_alternate_emails")
212
+ _op["method"] = "GET"
213
+ _op["path"] = "/users/" + str(user_id) + "/alternateemails"
214
+
215
+ expected = ["IndexResult", "AlternateEmail"]
216
+
217
+ prepped_request = self._base.prepare_request(_op)
218
+ response = self._base.request(prepped_request, expected, _op)
219
+
220
+ return response
221
+
222
+ def list_org_sheets(
223
+ self, page_size=None, page=None, include_all=None, modified_since=None
224
+ ):
225
+ """Get a list of all Sheets owned by an organization.
226
+
227
+ Get the list of all Sheets owned by the members of the
228
+ account (organization).
229
+
230
+ Args:
231
+ page_size (int): The maximum number of items to
232
+ return per page.
233
+ page (int): Which page to return.
234
+ include_all (bool): If true, include all results
235
+ (i.e. do not paginate).
236
+ modified_since(datetime): list organization sheets modified since datetime
237
+
238
+ Returns:
239
+ IndexResult
240
+ """
241
+ _op = fresh_operation("list_org_sheets")
242
+ _op["method"] = "GET"
243
+ _op["path"] = "/users/sheets"
244
+ _op["query_params"]["pageSize"] = page_size
245
+ _op["query_params"]["page"] = page
246
+ _op["query_params"]["includeAll"] = include_all
247
+ if isinstance(modified_since, datetime):
248
+ _op["query_params"]["modifiedSince"] = modified_since.isoformat()
249
+
250
+ expected = ["IndexResult", "Sheet"]
251
+
252
+ prepped_request = self._base.prepare_request(_op)
253
+ response = self._base.request(prepped_request, expected, _op)
254
+
255
+ return response
256
+
257
+ def list_users(
258
+ self, email=None, page_size=None, page=None, include_all=None, include=None,
259
+ plan_id=None, seat_type=None
260
+ ):
261
+ """Get the list of Users in the organization.
262
+
263
+ Args:
264
+ email (list[str]): Comma separated list of email
265
+ addresses on which to filter the results.
266
+ page_size (int): The maximum number of items to
267
+ return per page.
268
+ page (int): Which page to return.
269
+ include_all (bool): If true, include all results
270
+ (i.e. do not paginate).
271
+ include(list[str]): optional include parameter, only current
272
+ accepted value is 'lastLogin'
273
+ plan_id(int): optional plan_id parameter, returns users
274
+ in the selected plan.
275
+ seat_type(SeatType): optional seat_type parameter, filters users
276
+ by their seat type.
277
+
278
+ Returns:
279
+ IndexResult
280
+ """
281
+ _op = fresh_operation("list_users")
282
+ _op["method"] = "GET"
283
+ _op["path"] = "/users"
284
+ _op["query_params"]["email"] = email
285
+ _op["query_params"]["include"] = include
286
+ _op["query_params"]["pageSize"] = page_size
287
+ _op["query_params"]["page"] = page
288
+ _op["query_params"]["includeAll"] = include_all
289
+ _op["query_params"]["planId"] = plan_id
290
+ _op["query_params"]["seatType"] = seat_type
291
+
292
+ expected = ["IndexResult", "User"]
293
+
294
+ prepped_request = self._base.prepare_request(_op)
295
+ response = self._base.request(prepped_request, expected, _op)
296
+
297
+ return response
298
+
299
+ def remove_user(
300
+ self,
301
+ user_id,
302
+ transfer_to=None,
303
+ transfer_sheets=False,
304
+ remove_from_sharing=False,
305
+ ):
306
+ """Remove a user from an organization.
307
+
308
+ Remove a User from an organization. User is transitioned to
309
+ a free collaborator with read-only access to owned sheets, unless
310
+ those are optionally transferred to another User.
311
+
312
+ Args:
313
+ user_id (int): User ID
314
+ transfer_to (int): The ID of the User to
315
+ transfer ownership to. If the User being removed owns
316
+ groups, this value is required. Any groups owned by the User
317
+ being removed will be transferred to the specified User. If
318
+ the User owns sheets, _and_ **transferSheets** is `true`,
319
+ the removed User's sheets will be transferred to the
320
+ specified User.
321
+ transfer_sheets (bool): If `true` and
322
+ **transferTo** is specified, the removed User's sheets will
323
+ be transferred. Otherwise, sheets will not be transferred.
324
+ Defaults to `false`.
325
+ remove_from_sharing (bool): Set to `true` to
326
+ remove the user from sharing for all sheets/workspaces in
327
+ the organization. If not specified, User will not be removed
328
+ from sharing.
329
+
330
+ Returns:
331
+ Result
332
+ """
333
+ _op = fresh_operation("remove_user")
334
+ _op["method"] = "DELETE"
335
+ _op["path"] = "/users/" + str(user_id)
336
+ _op["query_params"]["transferTo"] = transfer_to
337
+ _op["query_params"]["transferSheets"] = transfer_sheets
338
+ _op["query_params"]["removeFromSharing"] = remove_from_sharing
339
+
340
+ expected = ["Result", None]
341
+ prepped_request = self._base.prepare_request(_op)
342
+ response = self._base.request(prepped_request, expected, _op)
343
+
344
+ return response
345
+
346
+ def update_user(self, user_id, user_obj):
347
+ """Update the specified User.
348
+
349
+ Args:
350
+ user_id (int): User ID
351
+ user_obj (User): User object with the following
352
+ attributes:
353
+
354
+ Returns:
355
+ Result
356
+ """
357
+ _op = fresh_operation("update_user")
358
+ _op["method"] = "PUT"
359
+ _op["path"] = "/users/" + str(user_id)
360
+ _op["json"] = user_obj
361
+
362
+ expected = ["Result", "User"]
363
+
364
+ prepped_request = self._base.prepare_request(_op)
365
+ response = self._base.request(prepped_request, expected, _op)
366
+
367
+ return response
368
+
369
+ def upgrade_user(self, user_id, plan_id, seat_type):
370
+ """Upgrades a user for a plan.
371
+
372
+ Args:
373
+ user_id (int): User ID
374
+ plan_id (int): Plan ID
375
+ seat_type (UpgradeSeatType): Seat type to upgrade to
376
+
377
+ Returns:
378
+ dict: Result
379
+ """
380
+ _op = fresh_operation("upgrade_user")
381
+ _op["method"] = "POST"
382
+ _op["path"] = f"/users/{user_id}/plans/{plan_id}/upgrade"
383
+ _op["json"] = {"seatType": seat_type}
384
+
385
+ expected = ["Result", None]
386
+
387
+ prepped_request = self._base.prepare_request(_op)
388
+ response = self._base.request(prepped_request, expected, _op)
389
+
390
+ return response
391
+
392
+ def downgrade_user(self, user_id, plan_id, seat_type):
393
+ """Downgrades a user for a plan.
394
+
395
+ Args:
396
+ user_id (int): User ID
397
+ plan_id (int): Plan ID
398
+ seat_type (DowngradeSeatType): Seat type to downgrade to
399
+
400
+ Returns:
401
+ dict: Result
402
+ """
403
+ _op = fresh_operation("downgrade_user")
404
+ _op["method"] = "POST"
405
+ _op["path"] = f"/users/{user_id}/plans/{plan_id}/downgrade"
406
+ _op["json"] = {"seatType": seat_type}
407
+
408
+ expected = ["Result", None]
409
+
410
+ prepped_request = self._base.prepare_request(_op)
411
+ response = self._base.request(prepped_request, expected, _op)
412
+
413
+ return response
414
+
415
+ def list_user_plans(self, user_id, last_key=None, max_items=None):
416
+ """List user's plans.
417
+ Args:
418
+ user_id (int): User ID
419
+ Returns:
420
+ TokenPaginatedResult
421
+ """
422
+ _op = fresh_operation("list_user_plans")
423
+ _op["method"] = "GET"
424
+ _op["path"] = f"/users/{user_id}/plans"
425
+ _op["query_params"]["lastKey"] = last_key
426
+ _op["query_params"]["maxItems"] = max_items
427
+
428
+ expected = ["TokenPaginatedResult", "UserPlan"]
429
+
430
+ prepped_request = self._base.prepare_request(_op)
431
+ response = self._base.request(prepped_request, expected, _op)
432
+
433
+ return response
434
+
435
+ def remove_user_from_plan(self, user_id, plan_id):
436
+ """Remove user from plan.
437
+ Args:
438
+ user_id (int): User ID
439
+ plan_id (int): Plan ID
440
+ Returns:
441
+ Result
442
+ """
443
+ _op = fresh_operation("remove_user_from_plan")
444
+ _op["method"] = "DELETE"
445
+ _op["path"] = f"/users/{user_id}/plans/{plan_id}"
446
+
447
+ expected = ["Result", None]
448
+
449
+ prepped_request = self._base.prepare_request(_op)
450
+ response = self._base.request(prepped_request, expected, _op)
451
+
452
+ return response
453
+
454
+ def add_profile_image(self, user_id, file, file_type):
455
+ """Uploads a profile image for the specified user.
456
+
457
+ Args:
458
+ user_id (int): user ID
459
+ file (string): path to image file.
460
+ file_type (string): content type of image file
461
+
462
+ Returns:
463
+ Result
464
+ """
465
+ if not all(val is not None for val in ["user_id", "file", "file_type"]):
466
+ raise ValueError(
467
+ ("One or more required values are missing from call to " + __name__)
468
+ )
469
+
470
+ return self._attach_profile_image(user_id, file, file_type)
471
+
472
+ def _attach_profile_image(self, user_id, file, file_type):
473
+ """Internal function used to load image"""
474
+
475
+ _data = open(file, "rb").read()
476
+ _op = fresh_operation("attach_profile_image")
477
+ _op["method"] = "POST"
478
+ _op["path"] = "/users/" + str(user_id) + "/profileimage"
479
+ _op["headers"] = {
480
+ "content-type": file_type,
481
+ "content-disposition": 'attachment; filename="' + file + '"',
482
+ }
483
+ _op["form_data"] = _data
484
+
485
+ expected = ["Result", "User"]
486
+
487
+ prepped_request = self._base.prepare_request(_op)
488
+ response = self._base.request(prepped_request, expected, _op)
489
+
490
+ return response
smartsheet/util.py ADDED
@@ -0,0 +1,199 @@
1
+ # pylint: disable=R0912
2
+ # Smartsheet Python SDK.
3
+ #
4
+ # Copyright 2018 Smartsheet.com, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License"): you may
7
+ # not use this file except in compliance with the License. You may obtain
8
+ # a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ # License for the specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ from __future__ import absolute_import
19
+
20
+ import functools
21
+ import inspect
22
+ import logging
23
+ import re
24
+ import warnings
25
+ from datetime import date, datetime
26
+
27
+ import six
28
+
29
+ from .types import EnumeratedValue, TypedList
30
+
31
+ _log = logging.getLogger(__name__)
32
+ _primitive_types = (six.string_types, six.integer_types, float, bool)
33
+ _list_types = (TypedList, list)
34
+
35
+
36
+ def _camel_to_underscore(name):
37
+ camel_pat = re.compile(r"([A-Z])")
38
+ return camel_pat.sub(lambda x: "_" + x.group(1).lower(), name)
39
+
40
+
41
+ def _underscore_to_camel(name):
42
+ under_pat = re.compile(r"_([a-z])")
43
+ return under_pat.sub(lambda x: x.group(1).upper(), name)
44
+
45
+
46
+ def prep(prop, op_id=None, method=None):
47
+ """Serialize a value for JSON transformation."""
48
+ if isinstance(prop, (datetime, date)):
49
+ retval = prop.isoformat()
50
+
51
+ elif hasattr(prop, "to_list"):
52
+ # Export TypedList recursively
53
+ proplist = prop.to_list()
54
+ retval = [prep(x) for x in proplist]
55
+
56
+ elif hasattr(prop, "to_dict"):
57
+ retval = prop.to_dict(op_id, method)
58
+
59
+ elif isinstance(prop, list):
60
+ retval = [
61
+ (x.to_dict(op_id, method) if hasattr(x, "to_dict") else x) for x in prop
62
+ ]
63
+
64
+ else:
65
+ retval = prop
66
+
67
+ return retval
68
+
69
+
70
+ def get_child_properties(obj):
71
+ retval = []
72
+ prop_list = inspect.getmembers(obj.__class__, inspect.isdatadescriptor)
73
+ for prop in prop_list:
74
+ if isinstance(prop[1], property):
75
+ prop_name = prop[0]
76
+ camel_case = _underscore_to_camel(prop_name)
77
+ camel_case = camel_case.rstrip(
78
+ "_"
79
+ ) # trim trailing '_' from props with names eq. to built-ins
80
+ retval.append((prop_name, camel_case))
81
+
82
+ return retval
83
+
84
+
85
+ def serialize(obj):
86
+
87
+ retval = None
88
+
89
+ if hasattr(obj, "serialize"):
90
+ retval = obj.serialize()
91
+
92
+ elif isinstance(obj, datetime):
93
+ retval = obj.isoformat() + "Z"
94
+
95
+ elif isinstance(obj, date):
96
+ retval = obj.isoformat()
97
+
98
+ elif isinstance(obj, _primitive_types):
99
+ retval = obj
100
+
101
+ elif hasattr(obj, "is_explicit_null"):
102
+ retval = obj
103
+
104
+ elif isinstance(obj, EnumeratedValue):
105
+ if obj.value is not None:
106
+ retval = obj.value.name
107
+
108
+ elif isinstance(obj, _list_types):
109
+ if len(obj):
110
+ retval = []
111
+ for item in obj:
112
+ serialized = serialize(item)
113
+ if not hasattr(serialized, "is_explicit_null"):
114
+ retval.append(serialized)
115
+
116
+ elif isinstance(obj, dict):
117
+ retval = {}
118
+ for key, value in obj.items():
119
+ if value is None:
120
+ retval[key] = None
121
+ else:
122
+ serialized_value = serialize(value)
123
+ if not hasattr(serialized_value, "is_explicit_null"):
124
+ retval[key] = serialized_value
125
+
126
+ else:
127
+ retval = {}
128
+ prop_list = get_child_properties(obj)
129
+ for prop in prop_list:
130
+ prop_name = prop[0]
131
+ camel_case = prop[1]
132
+ prop_value = getattr(obj, prop_name)
133
+ if prop_value is not None:
134
+ serialized = serialize(prop_value)
135
+ if hasattr(
136
+ serialized, "is_explicit_null"
137
+ ): # object forcing serialization of a null
138
+ retval[camel_case] = None
139
+ elif serialized is not None:
140
+ retval[camel_case] = serialized
141
+
142
+ return retval
143
+
144
+
145
+ def deserialize(obj, props):
146
+ if isinstance(props, dict):
147
+ for key, value in props.items():
148
+ key_ = _camel_to_underscore(key)
149
+ if hasattr(obj, key_):
150
+ setattr(obj, key_, value)
151
+
152
+ else:
153
+ _log.debug(
154
+ "object '%s' is missing property '%s'", obj.__class__.__name__, key_
155
+ )
156
+
157
+
158
+ def dump_message_headers(request):
159
+ bytearr = bytearray()
160
+ headers = request.headers.copy()
161
+ for name, value in headers.items():
162
+ bytearr.extend(format_header(name, value))
163
+ return bytearr.decode("utf-8")
164
+
165
+
166
+ def coerce_to_bytes(data):
167
+ if not isinstance(data, bytes) and hasattr(data, "encode"):
168
+ data = data.encode("utf-8")
169
+ return data
170
+
171
+
172
+ def format_header(name, value):
173
+ return coerce_to_bytes(name) + b": " + coerce_to_bytes(value) + b"\r\n"
174
+
175
+
176
+ def is_multipart(request):
177
+ headers = dump_message_headers(request)
178
+ if "Content-Type: multipart/form-data" in headers:
179
+ return True
180
+ return False
181
+
182
+
183
+ def deprecated(func):
184
+ """This is a decorator which can be used to mark functions
185
+ as deprecated. It will result in a warning being emitted
186
+ when the function is used."""
187
+
188
+ @functools.wraps(func)
189
+ def new_func(*args, **kwargs):
190
+ warnings.simplefilter("always", DeprecationWarning) # turn off filter
191
+ warnings.warn(
192
+ f"Call to deprecated function {func.__name__}.",
193
+ category=DeprecationWarning,
194
+ stacklevel=2,
195
+ )
196
+ warnings.simplefilter("default", DeprecationWarning) # reset filter
197
+ return func(*args, **kwargs)
198
+
199
+ return new_func