@@ -93,8 +93,14 @@ a Python dictionary of its attributes.
93
93
94
94
# # Get a List of Users
95
95
96
+ The following code enumerates the first 5 users, printing the email of each.
97
+ This will only have fetched the first page of results. Then, after the loop,
98
+ the `all_results` call will force the fetch of all remaining pages so the
99
+ list of all results can be constructed. ()Once the `all_results` call has been made,
100
+ you cannot enumerate again without first calling `reload`.)
101
+
96
102
` ` ` python
97
- users = QueryUsers(conn)
103
+ users = umapi_client. QueryUsers(conn)
98
104
# print first 5 users
99
105
for i, user in enumerate(users):
100
106
if i == 5: break
@@ -109,7 +115,7 @@ This list of groups will contain both user groups and product license
109
115
configuration groups.
110
116
111
117
` ` ` python
112
- groups = QueryGroups(conn)
118
+ groups = umapi_client. QueryGroups(conn)
113
119
# print all the group details
114
120
for group in groups:
115
121
print(group)
@@ -122,5 +128,160 @@ for group in groups:
122
128
123
129
# Performing Operations on Users
124
130
125
- _...under construction..._
131
+ User operations in the UMAPI are performed in three steps :
132
+
133
+ 1. You specify the user to be operated on.
134
+ 2. You specify the operations to be performed on the user.
135
+ 3. You submit the user and operations to the UMAPI server.
136
+
137
+ The combined specification of the user identity and the operations to be performed
138
+ is called an _action_ in the UMAPI documentation, while the individual operations are called
139
+ _commands_. If you read the documentation carefully, you will see that there
140
+ are limits to how many actions can be submitted to the UMAPI
141
+ service in a single call, how many commands there can be in a single action, and
142
+ how many calls can be submitted in a given period of time. However,
143
+ the `umapi_client` implementation has been design to insulate
144
+ your application from these limits
145
+ by
146
+ packing as many commands as allowed into each action,
147
+ batching up as many actions as possible into a call,
148
+ and spacing calls out when required to by the server. Thus, from an
149
+ application perspective, you can simply follow the three steps above for each
150
+ user and not worry about the mechanics of server communication limits.
151
+
152
+ # # Step 1: Specify the User
153
+
154
+ To operate on a user, you first create a `UserAction` object that
155
+ specifies the user's identity type, domain, and unique ID in the domain.
156
+
157
+ In most cases,
158
+ the user's email ID will be his unique ID and will itself contain his domain,
159
+ as in these examples :
160
+
161
+ ` ` ` python
162
+ from umapi_client import IdentityTypes
163
+ user1 = UserAction(id_type=IdentityTypes.adobeID, email="[email protected] ")
164
+ user2 = UserAction(id_type=IdentityTypes.enterpriseID, email="[email protected] ")
165
+ ` ` `
166
+
167
+ But when Federated ID is being used, and a non-email username is being
168
+ used to identify users across the SAML connection, both the username
169
+ and the domain must be specified separately, as in these examples :
170
+
171
+ ` ` ` python
172
+ user3 = UserAction(id_type=IdentityTypes.federatedID,
173
+ username="user347", domain="division.conglomerate.com")
174
+ user4 = UserAction(id_type=IdentityTypes.federatedID,
175
+ username="user348", domain="division.conglomerate.com",
176
+
177
+ ` ` `
178
+
179
+ Note that, as in the last example, it's OK to specify the email when
180
+ creating a user object even if the email is not the unique ID or
181
+ doesn't use the same domain. If
182
+ you later perform an operations on a user which requires the email
183
+ (such as user creation on the Adobe side), the email will be remembered
184
+ and supplied from the UserAction object.
185
+
186
+ # # Step 2: Specify the Operations
187
+
188
+ Once you have a `UserAction` object for a user, you can specify
189
+ operations (called _commands_) to perform on that user. For
190
+ example, to create a new user on the Adobe side, for the users
191
+ that were specified in the last section, we could do :
192
+
193
+ ` ` ` python
194
+ user1.create()
195
+ user2.create(first_name="Geoffrey", last_name="Giraffe")
196
+ user3.create(email="[email protected] ", country="US")
197
+ user4.create(first_name="John", last_name="User", country="US")
198
+ ` ` `
199
+
200
+ When creating users, the email address is mandatory if not already specified
201
+ when creating the user action. First and last name and country can be optionally
202
+ specified ()except for Adobe ID users),
203
+ and country _must_ be specified for Federated ID users.
204
+
205
+ If a user has already been created, but you want to update attributes,
206
+ you can use the `update` rather than the `create` command :
207
+
208
+ ` ` ` python
209
+ user2.update(first_name="Jeff", country="AU")
210
+ user4.update(username="user0347")
211
+ ` ` `
212
+
213
+ You can also specify to create if necessary, but update if already created :
214
+
215
+ ` ` ` python
216
+ from umapi_client import IfAlreadyExistsOptions
217
+ user4.create(first_name="John", last_name="User", country="US",
218
+ on_conflict=IfAlreadyExistsOptions.updateIfAlreadyExists)
219
+ ` ` `
220
+
221
+ There are many other operations you can perform, such as adding and removing
222
+ users from user groups and product configuration groups. Because each
223
+ operation specifier returns the user, it's easy to chain the together :
224
+
225
+ ` ` ` python
226
+ user2.add_group(groups=["Photoshop", "Illustrator"]).remove_group(groups=["CC All Apps"])
227
+ ` ` `
228
+
229
+ The details of all the possible commands are specified in the code,
230
+ and more user documentation will be forthcoming. In general, commands
231
+ are performed in the order they are specified, except for certain special
232
+ commands such as ```create``` which are always performed first regardless
233
+ of when they were specified.
234
+
235
+ # # Step 3: Submit to the UMAPI server
236
+
237
+ Once you have specified all the desired operations on a given `UserAction`,
238
+ you can submit it to the server as follows (recall that `conn` is an authorized
239
+ connection to the UMAPI server, as created above) :
240
+
241
+ ` ` ` python
242
+ result = conn.execute_single(user1)
243
+ result = conn.execute_multiple([user2, user3, user4])
244
+ ` ` `
245
+
246
+ By default, `execute_single` queues the action for sending to the server
247
+ when a "full batch" (of 10) actions has been accumulated, but
248
+ ` execute_multiple` forces a batch to be sent (including any
249
+ previously queued actions as well as the specified ones). You can
250
+ override these defaults with the `immediate` argument, as in :
251
+
252
+ ` ` ` python
253
+ result = conn.execute_single(user1, immediate=True)
254
+ result = conn.execute_multiple([user2, user3, user4], immediate=False)
255
+ ` ` `
256
+
257
+ The result of either execute operation is a tuple of three numbers
258
+ ` (queued, sent, succeeded)` which tell you how many actions were
259
+ queued, how many were sent, and how many of those sent succeeded
260
+ without errors. So, for example, in the following code :
261
+
262
+ ` ` ` python
263
+ queued, _, _ = conn.execute_single(user1)
264
+ _, sent, succeeded = conn.execute_multiple(user2, user3, user4)
265
+ ` ` `
266
+
267
+ we would likely see `queued = 1`, `sent = 4`, and `succeeded = 4`.
268
+
269
+ If, for some reason, the succeeded number is not equal to the sent
270
+ number for any call, it means that not all of the actions were
271
+ executed successfully on the server-side : one or more of the commands
272
+ failed to execute. In such cases, the server will have sent back
273
+ error information which the `umapi_client` implementation records
274
+ against the commands that failed, you can call the `execution_errors`
275
+ method on the user actions to get a list of the failed commands
276
+ and the server error information. For example, if only three
277
+ of the four actions sent had succeeded, then we could execute
278
+ this code :
279
+
280
+ ` ` ` python
281
+ actions = (user1, user2, user3, user4)
282
+ errors = [info for action in actions for info in action.execution_errors()]
283
+ ` ` `
126
284
285
+ Each entry in errors would then be a dictionary giving
286
+ the command that failed, the target user it failed on,
287
+ and server information about the reason for the failure.
0 commit comments