001package com.box.sdk;
002
003import static com.box.sdk.http.HttpMethod.DELETE;
004import static com.box.sdk.internal.utils.JsonUtils.addIfNotNull;
005
006import com.eclipsesource.json.Json;
007import com.eclipsesource.json.JsonArray;
008import com.eclipsesource.json.JsonObject;
009import com.eclipsesource.json.JsonValue;
010import java.io.File;
011import java.io.FileInputStream;
012import java.io.FileNotFoundException;
013import java.io.InputStream;
014import java.net.URL;
015import java.util.ArrayList;
016import java.util.Collection;
017import java.util.HashMap;
018import java.util.List;
019import java.util.Map;
020
021/**
022 * Represents a Box user account.
023 *
024 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked
025 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error
026 * handling for errors related to the Box REST API, you should capture this exception explicitly.</p>
027 */
028@BoxResourceType("user")
029public class BoxUser extends BoxCollaborator {
030
031    /**
032     * An array of all possible file fields that can be requested when calling {@link #getInfo(String...)}.
033     */
034    public static final String[] ALL_FIELDS = {"type", "id", "name", "login", "created_at", "modified_at", "role",
035        "language", "timezone", "space_amount", "space_used", "max_upload_size", "tracking_codes",
036        "can_see_managed_users", "is_sync_enabled", "is_external_collab_restricted", "status", "job_title", "phone",
037        "address", "avatar_url", "is_exempt_from_device_limits", "is_exempt_from_login_verification", "enterprise",
038        "my_tags", "hostname", "is_platform_access_only", "external_app_user_id", "notification_email"};
039
040    /**
041     * User URL Template.
042     */
043    public static final URLTemplate USER_URL_TEMPLATE = new URLTemplate("users/%s");
044    /**
045     * Get Me URL Template.
046     */
047    public static final URLTemplate GET_ME_URL = new URLTemplate("users/me");
048    /**
049     * Users URL Template.
050     */
051    public static final URLTemplate USERS_URL_TEMPLATE = new URLTemplate("users");
052    /**
053     * User Memberships URL Template.
054     */
055    public static final URLTemplate USER_MEMBERSHIPS_URL_TEMPLATE = new URLTemplate("users/%s/memberships");
056    /**
057     * E-Mail Alias URL Template.
058     */
059    public static final URLTemplate EMAIL_ALIAS_URL_TEMPLATE = new URLTemplate("users/%s/email_aliases/%s");
060    /**
061     * E-Mail Aliases URL Template.
062     */
063    public static final URLTemplate EMAIL_ALIASES_URL_TEMPLATE = new URLTemplate("users/%s/email_aliases");
064    /**
065     * Move Folder To User Template.
066     */
067    public static final URLTemplate MOVE_FOLDER_TO_USER_TEMPLATE = new URLTemplate("users/%s/folders/%s");
068    /**
069     * User Avatar Template.
070     */
071    public static final URLTemplate USER_AVATAR_TEMPLATE = new URLTemplate("users/%s/avatar");
072
073    /**
074     * Constructs a BoxUser for a user with a given ID.
075     *
076     * @param api the API connection to be used by the user.
077     * @param id  the ID of the user.
078     */
079    public BoxUser(BoxAPIConnection api, String id) {
080        super(api, id);
081    }
082
083    /**
084     * Provisions a new app user in an enterprise using Box Developer Edition.
085     *
086     * @param api  the API connection to be used by the created user.
087     * @param name the name of the user.
088     * @return the created user's info.
089     */
090    public static BoxUser.Info createAppUser(BoxAPIConnection api, String name) {
091        return createAppUser(api, name, new CreateUserParams());
092    }
093
094    /**
095     * Provisions a new app user in an enterprise with additional user information using Box Developer Edition.
096     *
097     * @param api    the API connection to be used by the created user.
098     * @param name   the name of the user.
099     * @param params additional user information.
100     * @return the created user's info.
101     */
102    public static BoxUser.Info createAppUser(BoxAPIConnection api, String name,
103                                             CreateUserParams params) {
104
105        params.setIsPlatformAccessOnly(true);
106        return createEnterpriseUser(api, null, name, params);
107    }
108
109    /**
110     * Provisions a new user in an enterprise.
111     *
112     * @param api   the API connection to be used by the created user.
113     * @param login the email address the user will use to login.
114     * @param name  the name of the user.
115     * @return the created user's info.
116     */
117    public static BoxUser.Info createEnterpriseUser(BoxAPIConnection api, String login, String name) {
118        return createEnterpriseUser(api, login, name, null);
119    }
120
121    /**
122     * Provisions a new user in an enterprise with additional user information.
123     *
124     * @param api    the API connection to be used by the created user.
125     * @param login  the email address the user will use to login.
126     * @param name   the name of the user.
127     * @param params additional user information.
128     * @return the created user's info.
129     */
130    public static BoxUser.Info createEnterpriseUser(BoxAPIConnection api, String login, String name,
131                                                    CreateUserParams params) {
132
133        JsonObject requestJSON = new JsonObject();
134        requestJSON.add("login", login);
135        requestJSON.add("name", name);
136
137        if (params != null) {
138            if (params.getRole() != null) {
139                requestJSON.add("role", params.getRole().toJSONValue());
140            }
141
142            if (params.getStatus() != null) {
143                requestJSON.add("status", params.getStatus().toJSONValue());
144            }
145
146            if (params.getTrackingCodes() != null) {
147                requestJSON.add("tracking_codes", toTrackingCodesJson(params.getTrackingCodes()));
148            }
149
150            addIfNotNull(requestJSON, "language", params.getLanguage());
151            addIfNotNull(requestJSON, "is_sync_enabled", params.getIsSyncEnabled());
152            addIfNotNull(requestJSON, "job_title", params.getJobTitle());
153            addIfNotNull(requestJSON, "phone", params.getPhone());
154            addIfNotNull(requestJSON, "address", params.getAddress());
155            addIfNotNull(requestJSON, "space_amount", params.getSpaceAmount());
156            addIfNotNull(requestJSON, "can_see_managed_users", params.getCanSeeManagedUsers());
157            addIfNotNull(requestJSON, "timezone", params.getTimezone());
158            addIfNotNull(requestJSON, "is_exempt_from_device_limits", params.getIsExemptFromDeviceLimits());
159            addIfNotNull(requestJSON, "is_exempt_from_login_verification", params.getIsExemptFromLoginVerification());
160            addIfNotNull(requestJSON, "is_platform_access_only", params.getIsPlatformAccessOnly());
161            addIfNotNull(requestJSON, "external_app_user_id", params.getExternalAppUserId());
162            addIfNotNull(requestJSON, "is_external_collab_restricted", params.getIsExternalCollabRestricted());
163        }
164
165        URL url = USERS_URL_TEMPLATE.build(api.getBaseURL());
166        BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
167        request.setBody(requestJSON.toString());
168        BoxJSONResponse response = (BoxJSONResponse) request.send();
169        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
170
171        BoxUser createdUser = new BoxUser(api, responseJSON.get("id").asString());
172        return createdUser.new Info(responseJSON);
173    }
174
175    /**
176     * Gets the current user.
177     *
178     * @param api the API connection of the current user.
179     * @return the current user.
180     */
181    public static BoxUser getCurrentUser(BoxAPIConnection api) {
182        URL url = GET_ME_URL.build(api.getBaseURL());
183        BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
184        BoxJSONResponse response = (BoxJSONResponse) request.send();
185        JsonObject jsonObject = Json.parse(response.getJSON()).asObject();
186        return new BoxUser(api, jsonObject.get("id").asString());
187    }
188
189    /**
190     * Returns an iterable containing all the enterprise users.
191     *
192     * @param api the API connection to be used when retrieving the users.
193     * @return an iterable containing all the enterprise users.
194     */
195    public static Iterable<BoxUser.Info> getAllEnterpriseUsers(final BoxAPIConnection api) {
196        return getAllEnterpriseUsers(api, false, null);
197    }
198
199
200    /**
201     * Returns an iterable containing all the enterprise users. Uses marker based pagination.
202     *
203     * @param api       the API connection to be used when retrieving the users.
204     * @param usemarker Boolean that determines whether to use marker based pagination.
205     * @param marker    The marker at which the iterator will begin.
206     * @return an iterable containing all the enterprise users.
207     */
208    public static Iterable<BoxUser.Info> getAllEnterpriseUsers(final BoxAPIConnection api, final boolean usemarker,
209                                                               final String marker) {
210        return getUsersInfoForType(api, null, null, null, usemarker, marker);
211    }
212
213    /**
214     * Returns an iterable containing all the enterprise users that matches the filter and specifies which child fields
215     * to retrieve from the API.
216     *
217     * @param api        the API connection to be used when retrieving the users.
218     * @param filterTerm used to filter the results to only users starting with this string in either the name or the
219     *                   login. Can be null to not filter the results.
220     * @param fields     the fields to retrieve. Leave this out for the standard fields.
221     * @return an iterable containing all the enterprise users that matches the filter.
222     */
223    public static Iterable<BoxUser.Info> getAllEnterpriseUsers(final BoxAPIConnection api, final String filterTerm,
224                                                               final String... fields) {
225        return getUsersInfoForType(api, filterTerm, null, null, false, null, fields);
226    }
227
228    /**
229     * Returns an iterable containing all the enterprise users that matches the filter and specifies which child fields
230     * to retrieve from the API. Uses marker based pagination.
231     *
232     * @param api        the API connection to be used when retrieving the users.
233     * @param filterTerm used to filter the results to only users starting with this string in either the name or the
234     *                   login. Can be null to not filter the results.
235     * @param usemarker  Boolean that determines whether to use marker based pagination.
236     * @param marker     The marker at which the iterator will begin.
237     * @param fields     the fields to retrieve. Leave this out for the standard fields.
238     * @return an iterable containing all the enterprise users that matches the filter.
239     */
240    public static Iterable<BoxUser.Info> getAllEnterpriseUsers(
241        final BoxAPIConnection api,
242        final String filterTerm,
243        final boolean usemarker,
244        final String marker,
245        final String... fields
246    ) {
247        return getUsersInfoForType(api, filterTerm, null, null, usemarker, marker, fields);
248    }
249
250    /**
251     * Gets a limited set of information about an external user. (A user collaborating
252     * on content owned by the enterprise). Note: Only fields the user has permission to
253     * see will be returned with values. Other fields will return a value of null.
254     *
255     * @param api        the API connection to be used when retrieving the users.
256     * @param filterTerm used to filter the results to only users matching the given login.
257     *                   This does exact match only, so if no filter term is passed in, nothing
258     *                   will be returned.
259     * @param fields     the fields to retrieve. Leave this out for the standard fields.
260     * @return an iterable containing external users matching the given email
261     */
262    public static Iterable<BoxUser.Info> getExternalUsers(final BoxAPIConnection api, final String filterTerm,
263                                                          final String... fields) {
264        return getUsersInfoForType(api, filterTerm, "external", null, false, null, fields);
265    }
266
267    /**
268     * Gets a limited set of information about an external user. (A user collaborating
269     * on content owned by the enterprise). Note: Only fields the user has permission to
270     * see will be returned with values. Other fields will return a value of null. Uses marker based pagination.
271     *
272     * @param api        the API connection to be used when retrieving the users.
273     * @param filterTerm used to filter the results to only users matching the given login.
274     *                   This does exact match only, so if no filter term is passed in, nothing
275     *                   will be returned.
276     * @param usemarker  Boolean that determines whether to use marker based pagination.
277     * @param marker     The marker at which the iterator will begin.
278     * @param fields     the fields to retrieve. Leave this out for the standard fields.
279     * @return an iterable containing external users matching the given email
280     */
281    public static Iterable<BoxUser.Info> getExternalUsers(
282        final BoxAPIConnection api,
283        final String filterTerm,
284        final boolean usemarker,
285        final String marker,
286        final String... fields
287    ) {
288        return getUsersInfoForType(api, filterTerm, "external", null, usemarker, marker, fields);
289    }
290
291    /**
292     * Gets any managed users that match the filter term as well as any external users that
293     * match the filter term. For managed users it matches any users names or emails that
294     * start with the term. For external, it only does full match on email. This method
295     * is ideal to use in the case where you have a full email for a user and you don't
296     * know if they're managed or external.
297     *
298     * @param api        the API connection to be used when retrieving the users.
299     * @param filterTerm The filter term to lookup users by (login for external, login or name for managed)
300     * @param fields     the fields to retrieve. Leave this out for the standard fields.
301     * @return an iterable containing users matching the given email
302     */
303    public static Iterable<BoxUser.Info> getAllEnterpriseOrExternalUsers(
304        final BoxAPIConnection api,
305        final String filterTerm,
306        final String... fields
307    ) {
308        return getUsersInfoForType(api, filterTerm, "all", null, false, null, fields);
309    }
310
311    /**
312     * Gets any managed users that match the filter term as well as any external users that
313     * match the filter term. For managed users it matches any users names or emails that
314     * start with the term. For external, it only does full match on email. This method
315     * is ideal to use in the case where you have a full email for a user and you don't
316     * know if they're managed or external. Uses marker based pagination.
317     *
318     * @param api        the API connection to be used when retrieving the users.
319     * @param filterTerm The filter term to lookup users by (login for external, login or name for managed)
320     * @param usemarker  Boolean that determines whether to use marker based pagination.
321     * @param marker     The marker at which the iterator will begin.
322     * @param fields     the fields to retrieve. Leave this out for the standard fields.
323     * @return an iterable containing users matching the given email
324     */
325    public static Iterable<BoxUser.Info> getAllEnterpriseOrExternalUsers(
326        final BoxAPIConnection api,
327        final String filterTerm,
328        final boolean usemarker,
329        final String marker,
330        final String... fields
331    ) {
332        return getUsersInfoForType(api, filterTerm, "all", null, usemarker, marker, fields);
333    }
334
335    /**
336     * Gets any app users that has an exact match with the externalAppUserId term.
337     *
338     * @param api               the API connection to be used when retrieving the users.
339     * @param externalAppUserId the external app user id that has been set for app user
340     * @param fields            the fields to retrieve. Leave this out for the standard fields.
341     * @return an iterable containing users matching the given email
342     */
343    public static Iterable<BoxUser.Info> getAppUsersByExternalAppUserID(
344        final BoxAPIConnection api,
345        final String externalAppUserId,
346        final String... fields
347    ) {
348        return getUsersInfoForType(api, null, null, externalAppUserId, false, null, fields);
349    }
350
351    /**
352     * Gets any app users that has an exact match with the externalAppUserId term using marker based pagination.
353     *
354     * @param api               the API connection to be used when retrieving the users.
355     * @param externalAppUserId the external app user id that has been set for app user
356     * @param usemarker         Boolean that determines whether to use marker based pagination.
357     * @param marker            The marker at which the iterator will begin.
358     * @param fields            the fields to retrieve. Leave this out for the standard fields.
359     * @return an iterable containing users matching the given email
360     */
361    public static Iterable<BoxUser.Info> getAppUsersByExternalAppUserID(
362        final BoxAPIConnection api,
363        final String externalAppUserId,
364        final boolean usemarker,
365        String marker,
366        final String... fields
367    ) {
368        return getUsersInfoForType(api, null, null, externalAppUserId, usemarker, marker, fields);
369    }
370
371    /**
372     * Helper method to abstract out the common logic from the various users methods.
373     *
374     * @param api               the API connection to be used when retrieving the users.
375     * @param filterTerm        The filter term to lookup users by (login for external, login or name for managed)
376     * @param userType          The type of users we want to search with this request.
377     *                          Valid values are 'managed' (enterprise users), 'external' or 'all'
378     * @param externalAppUserId the external app user id that has been set for an app user
379     * @param usemarker         Boolean that determines whether to use marker based pagination.
380     * @param marker            The marker at which the iterator will begin.
381     * @param fields            the fields to retrieve. Leave this out for the standard fields.
382     * @return An iterator over the selected users.
383     */
384    private static Iterable<BoxUser.Info> getUsersInfoForType(
385        final BoxAPIConnection api,
386        final String filterTerm,
387        final String userType,
388        final String externalAppUserId,
389        final boolean usemarker,
390        final String marker,
391        final String... fields
392    ) {
393
394        final QueryStringBuilder builder = new QueryStringBuilder();
395        if (filterTerm != null) {
396            builder.appendParam("filter_term", filterTerm);
397        }
398        if (userType != null) {
399            builder.appendParam("user_type", userType);
400        }
401        if (externalAppUserId != null) {
402            builder.appendParam("external_app_user_id", externalAppUserId);
403        }
404        if (usemarker) {
405            builder.appendParam("usemarker", "true");
406        }
407        if (fields.length > 0) {
408            builder.appendParam("fields", fields);
409        }
410        final URL url = USERS_URL_TEMPLATE.buildWithQuery(api.getBaseURL(), builder.toString());
411
412        if (usemarker) {
413            return new BoxResourceIterable<BoxUser.Info>(api, url, 100, null, marker) {
414                @Override
415                protected BoxUser.Info factory(JsonObject jsonObject) {
416                    BoxUser user = new BoxUser(api, jsonObject.get("id").asString());
417                    return user.new Info(jsonObject);
418                }
419            };
420        } else {
421            return () -> new BoxUserIterator(api, url);
422        }
423    }
424
425    private static JsonArray toTrackingCodesJson(Map<String, String> trackingCodes) {
426        JsonArray trackingCodesJsonArray = new JsonArray();
427        for (String attrKey : trackingCodes.keySet()) {
428            JsonObject trackingCode = new JsonObject();
429            trackingCode.set("type", "tracking_code");
430            trackingCode.set("name", attrKey);
431            trackingCode.set("value", trackingCodes.get(attrKey));
432            trackingCodesJsonArray.add(trackingCode);
433        }
434        return trackingCodesJsonArray;
435    }
436
437    /**
438     * Gets information about this user.
439     *
440     * @param fields the optional fields to retrieve.
441     * @return info about this user.
442     */
443    public BoxUser.Info getInfo(String... fields) {
444        URL url;
445        if (fields.length > 0) {
446            String queryString = new QueryStringBuilder().appendParam("fields", fields).toString();
447            url = USER_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID());
448        } else {
449            url = USER_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
450        }
451        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
452        BoxJSONResponse response = (BoxJSONResponse) request.send();
453        JsonObject jsonObject = Json.parse(response.getJSON()).asObject();
454        return new Info(jsonObject);
455    }
456
457    /**
458     * Gets information about all of the group memberships for this user.
459     * Does not support paging.
460     *
461     * <p>Note: This method is only available to enterprise admins.</p>
462     *
463     * @return a collection of information about the group memberships for this user.
464     */
465    public Collection<BoxGroupMembership.Info> getMemberships() {
466        BoxAPIConnection api = this.getAPI();
467        URL url = USER_MEMBERSHIPS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
468
469        BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
470        BoxJSONResponse response = (BoxJSONResponse) request.send();
471        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
472
473        int entriesCount = responseJSON.get("total_count").asInt();
474        Collection<BoxGroupMembership.Info> memberships = new ArrayList<>(entriesCount);
475        JsonArray entries = responseJSON.get("entries").asArray();
476        for (JsonValue entry : entries) {
477            JsonObject entryObject = entry.asObject();
478            BoxGroupMembership membership = new BoxGroupMembership(api, entryObject.get("id").asString());
479            BoxGroupMembership.Info info = membership.new Info(entryObject);
480            memberships.add(info);
481        }
482
483        return memberships;
484    }
485
486    /**
487     * Gets information about all of the group memberships for this user as iterable with paging support.
488     *
489     * @param fields the fields to retrieve.
490     * @return an iterable with information about the group memberships for this user.
491     */
492    public Iterable<BoxGroupMembership.Info> getAllMemberships(String... fields) {
493        final QueryStringBuilder builder = new QueryStringBuilder();
494        if (fields.length > 0) {
495            builder.appendParam("fields", fields);
496        }
497        return () -> {
498            URL url = USER_MEMBERSHIPS_URL_TEMPLATE.buildWithQuery(
499                BoxUser.this.getAPI().getBaseURL(), builder.toString(), BoxUser.this.getID());
500            return new BoxGroupMembershipIterator(BoxUser.this.getAPI(), url);
501        };
502    }
503
504    /**
505     * Adds a new email alias to this user's account.
506     *
507     * @param email the email address to add as an alias.
508     * @return the newly created email alias.
509     */
510    public EmailAlias addEmailAlias(String email) {
511        return this.addEmailAlias(email, false);
512    }
513
514    /**
515     * Adds a new email alias to this user's account and confirms it without user interaction.
516     * This functionality is only available for enterprise admins.
517     *
518     * @param email       the email address to add as an alias.
519     * @param isConfirmed whether or not the email alias should be automatically confirmed.
520     * @return the newly created email alias.
521     */
522    public EmailAlias addEmailAlias(String email, boolean isConfirmed) {
523        URL url = EMAIL_ALIASES_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
524        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
525
526        JsonObject requestJSON = new JsonObject()
527            .add("email", email);
528
529        if (isConfirmed) {
530            requestJSON.add("is_confirmed", isConfirmed);
531        }
532
533        request.setBody(requestJSON.toString());
534        BoxJSONResponse response = (BoxJSONResponse) request.send();
535        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
536        return new EmailAlias(responseJSON);
537    }
538
539    /**
540     * Deletes an email alias from this user's account.
541     *
542     * <p>The IDs of the user's email aliases can be found by calling {@link #getEmailAliases}.</p>
543     *
544     * @param emailAliasID the ID of the email alias to delete.
545     */
546    public void deleteEmailAlias(String emailAliasID) {
547        URL url = EMAIL_ALIAS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), emailAliasID);
548        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
549        BoxAPIResponse response = request.send();
550        response.disconnect();
551    }
552
553    /**
554     * Gets a collection of all the email aliases for this user.
555     *
556     * <p>Note that the user's primary login email is not included in the collection of email aliases.</p>
557     *
558     * @return a collection of all the email aliases for this user.
559     */
560    public Collection<EmailAlias> getEmailAliases() {
561        URL url = EMAIL_ALIASES_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
562        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
563        BoxJSONResponse response = (BoxJSONResponse) request.send();
564        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
565
566        int totalCount = responseJSON.get("total_count").asInt();
567        Collection<EmailAlias> emailAliases = new ArrayList<>(totalCount);
568        JsonArray entries = responseJSON.get("entries").asArray();
569        for (JsonValue value : entries) {
570            JsonObject emailAliasJSON = value.asObject();
571            emailAliases.add(new EmailAlias(emailAliasJSON));
572        }
573
574        return emailAliases;
575    }
576
577    /**
578     * Deletes a user from an enterprise account.
579     *
580     * @param notifyUser whether or not to send an email notification to the user that their account has been deleted.
581     * @param force      whether or not this user should be deleted even if they still own files.
582     */
583    public void delete(boolean notifyUser, boolean force) {
584        String queryString = new QueryStringBuilder()
585            .appendParam("notify", String.valueOf(notifyUser))
586            .appendParam("force", String.valueOf(force))
587            .toString();
588
589        URL url = USER_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID());
590        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
591        BoxAPIResponse response = request.send();
592        response.disconnect();
593    }
594
595    /**
596     * Updates the information about this user with any info fields that have been modified locally.
597     *
598     * <p>Note: This method is only available to enterprise admins.</p>
599     *
600     * @param info info the updated info.
601     */
602    public void updateInfo(BoxUser.Info info) {
603        URL url = USER_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
604        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
605        request.setBody(info.getPendingChanges());
606        BoxJSONResponse response = (BoxJSONResponse) request.send();
607        JsonObject jsonObject = Json.parse(response.getJSON()).asObject();
608        info.update(jsonObject);
609    }
610
611    /**
612     * @param sourceUserID the user id of the user whose files will be the source for this operation
613     * @return info for the newly created folder
614     * @deprecated As of release 2.22.0, replaced by {@link #transferContent(String)} ()}
615     * <p>
616     * Moves all of the owned content from within one user’s folder into a new folder in another user's account.
617     * You can move folders across users as long as the you have administrative permissions and the 'source'
618     * user owns the folders. Per the documentation at the link below, this will move everything from the root
619     * folder, as this is currently the only mode of operation supported.
620     * <p>
621     * See also <a href="https://developer.box.com/en/reference/put-users-id-folders-id/">https://developer.box.com/en/reference/put-users-id-folders-id/</a>
622     */
623    @Deprecated
624    public BoxFolder.Info moveFolderToUser(String sourceUserID) {
625        // Currently the API only supports moving of the root folder (0), hence the hard coded "0"
626        URL url = MOVE_FOLDER_TO_USER_TEMPLATE.build(this.getAPI().getBaseURL(), sourceUserID, "0");
627        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
628        JsonObject idValue = new JsonObject();
629        idValue.add("id", this.getID());
630        JsonObject ownedBy = new JsonObject();
631        ownedBy.add("owned_by", idValue);
632        request.setBody(ownedBy.toString());
633        BoxJSONResponse response = (BoxJSONResponse) request.send();
634        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
635        BoxFolder movedFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString());
636
637        return movedFolder.new Info(responseJSON);
638    }
639
640    /**
641     * Moves all of the owned content from within one user’s folder into a new folder in another user's account.
642     * You can move folders across users as long as the you have administrative permissions and the 'source'
643     * user owns the folders. Per the documentation at the link below, this will move everything from the root
644     * folder, as this is currently the only mode of operation supported.
645     * <p>
646     * See also <a href="https://developer.box.com/en/reference/put-users-id-folders-id/">https://developer.box.com/en/reference/put-users-id-folders-id/</a>
647     *
648     * @param destinationUserID the user id of the user that you wish to transfer content to.
649     * @return info for the newly created folder.
650     */
651    public BoxFolder.Info transferContent(String destinationUserID) {
652        URL url = MOVE_FOLDER_TO_USER_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), "0");
653        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
654        JsonObject destinationUser = new JsonObject();
655        destinationUser.add("id", destinationUserID);
656        JsonObject ownedBy = new JsonObject();
657        ownedBy.add("owned_by", destinationUser);
658        request.setBody(ownedBy.toString());
659        BoxJSONResponse response = (BoxJSONResponse) request.send();
660        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
661        BoxFolder movedFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString());
662
663        return movedFolder.new Info(responseJSON);
664    }
665
666    /**
667     * Retrieves the avatar of a user as an InputStream.
668     *
669     * @return InputStream representing the user avater.
670     */
671    public InputStream getAvatar() {
672        URL url = USER_AVATAR_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
673        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
674        BoxAPIResponse response = request.send();
675
676        return response.getBody();
677    }
678
679    /**
680     * Upload avatar image to user account. Supported formats are JPG and PNG.
681     * The image size cannot exceed 1024 * 1024 pixels or 1MB.
682     *
683     * @param file File containg avatar image.
684     * @return Avatar creation response.
685     */
686    public AvatarUploadResponse uploadAvatar(File file) {
687        try {
688            return uploadAvatar(new FileInputStream(file), file.getName());
689        } catch (FileNotFoundException e) {
690            throw new RuntimeException(e);
691        }
692    }
693
694    /**
695     * Upload avatar image to user account. Supported formats are JPG and PNG.
696     * The image size cannot exceed 1024 * 1024 pixels or 1MB.
697     *
698     * @param file             {@link File} containg avatar image.
699     * @param progressListener {@link ProgressListener} set if you want to track upload progress
700     * @return Avatar creation response.
701     */
702    public AvatarUploadResponse uploadAvatar(File file, ProgressListener progressListener) {
703        try {
704            return uploadAvatar(new FileInputStream(file), file.getName(), progressListener);
705        } catch (FileNotFoundException e) {
706            throw new RuntimeException(e);
707        }
708    }
709
710    /**
711     * Upload avatar image to user account. Supported formats are JPG and PNG.
712     * The image size cannot exceed 1024 * 1024 pixels or 1MB.
713     *
714     * @param content  {@link InputStream} containing image data
715     * @param fileName file name with extention what will be used to determine content type
716     * @return Avatar creation response.
717     */
718    public AvatarUploadResponse uploadAvatar(InputStream content, String fileName) {
719        return uploadAvatar(content, fileName, null);
720    }
721
722    /**
723     * Upload avatar image to user account. Supported formats are JPG and PNG.
724     * The image size cannot exceed 1024 * 1024 pixels or 1MB.
725     *
726     * @param content          {@link InputStream} containing image data
727     * @param fileName         file name with extention what will be used to determine content type
728     * @param progressListener {@link ProgressListener} set if you want to track upload progress
729     * @return Avatar creation response.
730     */
731    public AvatarUploadResponse uploadAvatar(InputStream content, String fileName, ProgressListener progressListener) {
732        URL url = USER_AVATAR_TEMPLATE.build(getAPI().getBaseURL(), this.getID());
733        BoxImageMultipartRequest request = new BoxImageMultipartRequest(getAPI(), url, "pic");
734        request.setFile(content, fileName);
735
736        BoxAPIResponse response;
737        if (progressListener != null) {
738            response = request.send(progressListener);
739        } else {
740            response = request.send();
741        }
742
743        return parseUploadAvatarResponse(response);
744    }
745
746    /**
747     * Removes avatar from user account.
748     */
749    public void deleteAvatar() {
750        URL url = USER_AVATAR_TEMPLATE.build(getAPI().getBaseURL(), this.getID());
751        BoxAPIRequest request = new BoxAPIRequest(getAPI(), url, DELETE);
752        request.send();
753    }
754
755    private AvatarUploadResponse parseUploadAvatarResponse(BoxAPIResponse response) {
756        JsonObject responseObject = Json.parse(response.bodyToString()).asObject();
757        JsonObject picUrls = responseObject.get("pic_urls").asObject();
758        return new AvatarUploadResponse(
759            picUrls.getString("small", null),
760            picUrls.getString("large", null),
761            picUrls.getString("preview", null)
762        );
763    }
764
765    /**
766     * Enumerates the possible roles that a user can have within an enterprise.
767     */
768    public enum Role {
769        /**
770         * The user is an administrator of their enterprise.
771         */
772        ADMIN("admin"),
773
774        /**
775         * The user is a co-administrator of their enterprise.
776         */
777        COADMIN("coadmin"),
778
779        /**
780         * The user is a regular user within their enterprise.
781         */
782        USER("user");
783
784        private final String jsonValue;
785
786        Role(String jsonValue) {
787            this.jsonValue = jsonValue;
788        }
789
790        static Role fromJSONValue(String jsonValue) {
791            return Role.valueOf(jsonValue.toUpperCase());
792        }
793
794        String toJSONValue() {
795            return this.jsonValue;
796        }
797    }
798
799    /**
800     * Enumerates the possible statuses that a user's account can have.
801     */
802    public enum Status {
803        /**
804         * The user's account is active.
805         */
806        ACTIVE("active"),
807
808        /**
809         * The user's account is inactive.
810         */
811        INACTIVE("inactive"),
812
813        /**
814         * The user's account cannot delete or edit content.
815         */
816        CANNOT_DELETE_EDIT("cannot_delete_edit"),
817
818        /**
819         * The user's account cannot delete, edit, or upload content.
820         */
821        CANNOT_DELETE_EDIT_UPLOAD("cannot_delete_edit_upload");
822
823        private final String jsonValue;
824
825        Status(String jsonValue) {
826            this.jsonValue = jsonValue;
827        }
828
829        static Status fromJSONValue(String jsonValue) {
830            return Status.valueOf(jsonValue.toUpperCase());
831        }
832
833        String toJSONValue() {
834            return this.jsonValue;
835        }
836    }
837
838    /**
839     * Contains information about a BoxUser.
840     */
841    public class Info extends BoxCollaborator.Info {
842        private String login;
843        private Role role;
844        private String language;
845        private String timezone;
846        private long spaceAmount;
847        private long spaceUsed;
848        private long maxUploadSize;
849        private boolean canSeeManagedUsers;
850        private boolean isSyncEnabled;
851        private boolean isExternalCollabRestricted;
852        private Status status;
853        private String jobTitle;
854        private String phone;
855        private String address;
856        private String avatarURL;
857        private BoxNotificationEmail notificationEmail;
858        private boolean isExemptFromDeviceLimits;
859        private boolean isExemptFromLoginVerification;
860        private boolean isPasswordResetRequired;
861        private boolean isPlatformAccessOnly;
862        private String externalAppUserId;
863        private BoxEnterprise enterprise;
864        private List<String> myTags;
865        private String hostname;
866        private Map<String, String> trackingCodes;
867
868        /**
869         * Constructs an empty Info object.
870         */
871        public Info() {
872            super();
873        }
874
875        /**
876         * Constructs an Info object by parsing information from a JSON string.
877         *
878         * @param json the JSON string to parse.
879         */
880        public Info(String json) {
881            super(json);
882        }
883
884        Info(JsonObject jsonObject) {
885            super(jsonObject);
886        }
887
888        @Override
889        public BoxUser getResource() {
890            return BoxUser.this;
891        }
892
893        /**
894         * Gets the email address the user uses to login.
895         *
896         * @return the email address the user uses to login.
897         */
898        public String getLogin() {
899            return this.login;
900        }
901
902        /**
903         * Sets the email address the user uses to login. The new login must be one of the user's already confirmed
904         * email aliases.
905         *
906         * @param login one of the user's confirmed email aliases.
907         */
908        public void setLogin(String login) {
909            this.login = login;
910            this.addPendingChange("login", login);
911        }
912
913        /**
914         * Gets the user's enterprise role.
915         *
916         * @return the user's enterprise role.
917         */
918        public Role getRole() {
919            return this.role;
920        }
921
922        /**
923         * Sets the user's role in their enterprise.
924         *
925         * @param role the user's new role in their enterprise.
926         */
927        public void setRole(Role role) {
928            this.role = role;
929            this.addPendingChange("role", role.name().toLowerCase());
930        }
931
932        /**
933         * Gets the language of the user.
934         *
935         * @return the language of the user.
936         */
937        public String getLanguage() {
938            return this.language;
939        }
940
941        /**
942         * Sets the language of the user.
943         *
944         * @param language the new language of the user.
945         */
946        public void setLanguage(String language) {
947            this.language = language;
948            this.addPendingChange("language", language);
949        }
950
951        /**
952         * Gets the timezone of the user.
953         *
954         * @return the timezone of the user.
955         */
956        public String getTimezone() {
957            return this.timezone;
958        }
959
960        /**
961         * Sets the timezone of the user.
962         *
963         * @param timezone the new timezone of the user.
964         */
965        public void setTimezone(String timezone) {
966            this.timezone = timezone;
967            this.addPendingChange("timezone", timezone);
968        }
969
970        /**
971         * Gets the user's total available space in bytes.
972         *
973         * @return the user's total available space in bytes.
974         */
975        public long getSpaceAmount() {
976            return this.spaceAmount;
977        }
978
979        /**
980         * Sets the user's total available space in bytes.
981         *
982         * @param spaceAmount the new amount of space available to the user in bytes, or -1 for unlimited storage.
983         */
984        public void setSpaceAmount(long spaceAmount) {
985            this.spaceAmount = spaceAmount;
986            this.addPendingChange("space_amount", spaceAmount);
987        }
988
989        /**
990         * Gets the amount of space the user has used in bytes.
991         *
992         * @return the amount of space the user has used in bytes.
993         */
994        public long getSpaceUsed() {
995            return this.spaceUsed;
996        }
997
998        /**
999         * Gets the maximum individual file size in bytes the user can have.
1000         *
1001         * @return the maximum individual file size in bytes the user can have.
1002         */
1003        public long getMaxUploadSize() {
1004            return this.maxUploadSize;
1005        }
1006
1007        /**
1008         * Gets the user's current account status.
1009         *
1010         * @return the user's current account status.
1011         */
1012        public Status getStatus() {
1013            return this.status;
1014        }
1015
1016        /**
1017         * Sets the user's current account status.
1018         *
1019         * @param status the user's new account status.
1020         */
1021        public void setStatus(Status status) {
1022            this.status = status;
1023            this.addPendingChange("status", status.name().toLowerCase());
1024        }
1025
1026        /**
1027         * Gets the job title of the user.
1028         *
1029         * @return the job title of the user.
1030         */
1031        public String getJobTitle() {
1032            return this.jobTitle;
1033        }
1034
1035        /**
1036         * Sets the job title of the user.
1037         *
1038         * @param jobTitle the new job title of the user.
1039         */
1040        public void setJobTitle(String jobTitle) {
1041            this.jobTitle = jobTitle;
1042            this.addPendingChange("job_title", jobTitle);
1043        }
1044
1045        /**
1046         * Gets the phone number of the user.
1047         *
1048         * @return the phone number of the user.
1049         */
1050        public String getPhone() {
1051            return this.phone;
1052        }
1053
1054        /**
1055         * Sets the phone number of the user.
1056         *
1057         * @param phone the new phone number of the user.
1058         */
1059        public void setPhone(String phone) {
1060            this.phone = phone;
1061            this.addPendingChange("phone", phone);
1062        }
1063
1064        /**
1065         * Gets the address of the user.
1066         *
1067         * @return the address of the user.
1068         */
1069        public String getAddress() {
1070            return this.address;
1071        }
1072
1073        /**
1074         * Sets the address of the user.
1075         *
1076         * @param address the new address of the user.
1077         */
1078        public void setAddress(String address) {
1079            this.address = address;
1080            this.addPendingChange("address", address);
1081        }
1082
1083        /**
1084         * Gets the URL of the user's avatar.
1085         *
1086         * @return the URL of the user's avatar.
1087         */
1088        public String getAvatarURL() {
1089            return this.avatarURL;
1090        }
1091
1092        /**
1093         * Gets the user's alternate notification email address to which email notifications are sent.
1094         *
1095         * @return the user's notification email address.
1096         */
1097        public BoxNotificationEmail getNotificationEmail() {
1098            return this.notificationEmail;
1099        }
1100
1101        /**
1102         * Sets the user's notification email address.
1103         *
1104         * @param notificationEmail the user's new notification email address.
1105         */
1106        public void setNotificationEmail(BoxNotificationEmail notificationEmail) {
1107            this.notificationEmail = notificationEmail;
1108        }
1109
1110        /**
1111         * Gets the enterprise that the user belongs to.
1112         *
1113         * @return the enterprise that the user belongs to.
1114         */
1115        public BoxEnterprise getEnterprise() {
1116            return this.enterprise;
1117        }
1118
1119        /**
1120         * Removes the user from their enterprise and converts them to a standalone free user.
1121         */
1122        public void removeEnterprise() {
1123            this.removeChildObject("enterprise");
1124            this.enterprise = null;
1125            this.addChildObject("enterprise", null);
1126        }
1127
1128        /**
1129         * Gets whether or not the user can use Box Sync.
1130         *
1131         * @return true if the user can use Box Sync; otherwise false.
1132         */
1133        public boolean getIsSyncEnabled() {
1134            return this.isSyncEnabled;
1135        }
1136
1137        /**
1138         * Sets whether or not the user can use Box Sync.
1139         *
1140         * @param enabled whether or not the user can use Box Sync.
1141         */
1142        public void setIsSyncEnabled(boolean enabled) {
1143            this.isSyncEnabled = enabled;
1144            this.addPendingChange("is_sync_enabled", enabled);
1145        }
1146
1147        /**
1148         * Gets whether this user is allowed or not to collaborate with users outside their enterprise.
1149         *
1150         * @return true if this user is not allowed to collaborate with users outside their enterprise; otherwise false.
1151         */
1152        public boolean getIsExternalCollabRestricted() {
1153            return this.isExternalCollabRestricted;
1154        }
1155
1156        /**
1157         * Sets whether this user is allowed or not to collaborate with users outside their enterprise.
1158         *
1159         * @param isExternalCollabRestricted whether the user is allowed to collaborate outside their enterprise.
1160         */
1161        public void setIsExternalCollabRestricted(boolean isExternalCollabRestricted) {
1162            this.isExternalCollabRestricted = isExternalCollabRestricted;
1163            this.addPendingChange("is_external_collab_restricted", isExternalCollabRestricted);
1164        }
1165
1166        /**
1167         * Gets whether or not the user can see other enterprise users in their contact list.
1168         *
1169         * @return true if the user can see other enterprise users in their contact list; otherwise false.
1170         */
1171        public boolean getCanSeeManagedUsers() {
1172            return this.canSeeManagedUsers;
1173        }
1174
1175        /**
1176         * Sets whether or not the user can see other enterprise users in their contact list.
1177         *
1178         * @param canSeeManagedUsers whether or not the user can see other enterprise users in their contact list.
1179         */
1180        public void setCanSeeManagedUsers(boolean canSeeManagedUsers) {
1181            this.canSeeManagedUsers = canSeeManagedUsers;
1182            this.addPendingChange("can_see_managed_users", canSeeManagedUsers);
1183        }
1184
1185        /**
1186         * Gets whether or not the user is exempt from enterprise device limits.
1187         *
1188         * @return true if the user is exempt from enterprise device limits; otherwise false.
1189         */
1190        public boolean getIsExemptFromDeviceLimits() {
1191            return this.isExemptFromDeviceLimits;
1192        }
1193
1194        /**
1195         * Sets whether or not the user is exempt from enterprise device limits.
1196         *
1197         * @param isExemptFromDeviceLimits whether or not the user is exempt from enterprise device limits.
1198         */
1199        public void setIsExemptFromDeviceLimits(boolean isExemptFromDeviceLimits) {
1200            this.isExemptFromDeviceLimits = isExemptFromDeviceLimits;
1201            this.addPendingChange("is_exempt_from_device_limits", isExemptFromDeviceLimits);
1202        }
1203
1204        /**
1205         * Gets whether or not the user must use two-factor authentication.
1206         *
1207         * @return true if the user must use two-factor authentication; otherwise false.
1208         */
1209        public boolean getIsExemptFromLoginVerification() {
1210            return this.isExemptFromLoginVerification;
1211        }
1212
1213        /**
1214         * Sets whether or not the user must use two-factor authentication.
1215         *
1216         * @param isExemptFromLoginVerification whether or not the user must use two-factor authentication.
1217         */
1218        public void setIsExemptFromLoginVerification(boolean isExemptFromLoginVerification) {
1219            this.isExemptFromLoginVerification = isExemptFromLoginVerification;
1220            this.addPendingChange("is_exempt_from_login_verification", isExemptFromLoginVerification);
1221        }
1222
1223        /**
1224         * Gets whether or not the user is required to reset password.
1225         *
1226         * @return true if the user is required to reset password; otherwise false.
1227         */
1228        public boolean getIsPasswordResetRequired() {
1229            return this.isPasswordResetRequired;
1230        }
1231
1232        /**
1233         * Sets whether or not the user is required to reset password.
1234         *
1235         * @param isPasswordResetRequired whether or not the user is required to reset password.
1236         */
1237        public void setIsPasswordResetRequired(boolean isPasswordResetRequired) {
1238            this.isPasswordResetRequired = isPasswordResetRequired;
1239            this.addPendingChange("is_password_reset_required", isPasswordResetRequired);
1240        }
1241
1242        /**
1243         * Gets whether or not the user we are creating is an app user with Box Developer Edition.
1244         *
1245         * @return true if the new user is an app user for Box Developer Addition; otherwise false.
1246         */
1247        public boolean getIsPlatformAccessOnly() {
1248            return this.isPlatformAccessOnly;
1249        }
1250
1251        /**
1252         * Gets the external app user id that has been set for the app user.
1253         *
1254         * @return the external app user id.
1255         */
1256        public String getExternalAppUserId() {
1257            return this.externalAppUserId;
1258        }
1259
1260        /**
1261         * Sets the external app user id.
1262         *
1263         * @param externalAppUserId external app user id.
1264         */
1265        public void setExternalAppUserId(String externalAppUserId) {
1266            this.externalAppUserId = externalAppUserId;
1267            this.addPendingChange("external_app_user_id", externalAppUserId);
1268        }
1269
1270        /**
1271         * Gets the tags for all files and folders owned by this user.
1272         *
1273         * @return the tags for all files and folders owned by this user.
1274         */
1275        public List<String> getMyTags() {
1276            return this.myTags;
1277        }
1278
1279        /**
1280         * Gets the root (protocol, subdomain, domain) of any links that need to be generated for this user.
1281         *
1282         * @return the root (protocol, subdomain, domain) of any links that need to be generated for this user.
1283         */
1284        public String getHostname() {
1285            return this.hostname;
1286        }
1287
1288        /**
1289         * Gets the tracking defined for each entity.
1290         *
1291         * @return a Map with tracking codes.
1292         */
1293        public Map<String, String> getTrackingCodes() {
1294            return this.trackingCodes;
1295        }
1296
1297        /**
1298         * Allows admin to set attributes specific for a group of users.
1299         *
1300         * @param trackingCodes a Map representing the user's new tracking codes
1301         */
1302        public void setTrackingCodes(Map<String, String> trackingCodes) {
1303            this.trackingCodes = trackingCodes;
1304            this.addPendingChange("tracking_codes", toTrackingCodesJson(this.trackingCodes));
1305        }
1306
1307        /**
1308         * Allows the admin to append new tracking codes to the previous existing list.
1309         *
1310         * @param name  the name or `key` of the attribute to set.
1311         * @param value the value of the attribute to set.
1312         */
1313        public void appendTrackingCodes(String name, String value) {
1314            this.getTrackingCodes().put(name, value);
1315            this.addPendingChange("tracking_codes", toTrackingCodesJson(this.trackingCodes));
1316        }
1317
1318        @Override
1319        protected void parseJSONMember(JsonObject.Member member) {
1320            super.parseJSONMember(member);
1321
1322            JsonValue value = member.getValue();
1323            String memberName = member.getName();
1324            try {
1325                if (memberName.equals("login")) {
1326                    this.login = value.asString();
1327                } else if (memberName.equals("role")) {
1328                    this.role = Role.fromJSONValue(value.asString());
1329                } else if (memberName.equals("language")) {
1330                    this.language = value.asString();
1331                } else if (memberName.equals("timezone")) {
1332                    this.timezone = value.asString();
1333                } else if (memberName.equals("space_amount")) {
1334                    this.spaceAmount = Double.valueOf(value.toString()).longValue();
1335                } else if (memberName.equals("space_used")) {
1336                    this.spaceUsed = Double.valueOf(value.toString()).longValue();
1337                } else if (memberName.equals("max_upload_size")) {
1338                    this.maxUploadSize = Double.valueOf(value.toString()).longValue();
1339                } else if (memberName.equals("status")) {
1340                    this.status = Status.fromJSONValue(value.asString());
1341                } else if (memberName.equals("job_title")) {
1342                    this.jobTitle = value.asString();
1343                } else if (memberName.equals("phone")) {
1344                    this.phone = value.asString();
1345                } else if (memberName.equals("address")) {
1346                    this.address = value.asString();
1347                } else if (memberName.equals("avatar_url")) {
1348                    this.avatarURL = value.asString();
1349                } else if (memberName.equals("notification_email")) {
1350                    if (value.isObject()) {
1351                        this.notificationEmail = new BoxNotificationEmail(value.asObject());
1352                    } else {
1353                        this.notificationEmail = null;
1354                    }
1355                } else if (memberName.equals("can_see_managed_users")) {
1356                    this.canSeeManagedUsers = value.asBoolean();
1357                } else if (memberName.equals("is_sync_enabled")) {
1358                    this.isSyncEnabled = value.asBoolean();
1359                } else if (memberName.equals("is_external_collab_restricted")) {
1360                    this.isExternalCollabRestricted = value.asBoolean();
1361                } else if (memberName.equals("is_exempt_from_device_limits")) {
1362                    this.isExemptFromDeviceLimits = value.asBoolean();
1363                } else if (memberName.equals("is_exempt_from_login_verification")) {
1364                    this.isExemptFromLoginVerification = value.asBoolean();
1365                } else if (memberName.equals("is_password_reset_required")) {
1366                    this.isPasswordResetRequired = value.asBoolean();
1367                } else if (memberName.equals("is_platform_access_only")) {
1368                    this.isPlatformAccessOnly = value.asBoolean();
1369                } else if (memberName.equals("external_app_user_id")) {
1370                    this.externalAppUserId = value.asString();
1371                } else if (memberName.equals("enterprise")) {
1372                    JsonObject jsonObject = value.asObject();
1373                    if (this.enterprise == null) {
1374                        this.enterprise = new BoxEnterprise(jsonObject);
1375                    } else {
1376                        this.enterprise.update(jsonObject);
1377                    }
1378                } else if (memberName.equals("my_tags")) {
1379                    this.myTags = this.parseMyTags(value.asArray());
1380                } else if (memberName.equals("hostname")) {
1381                    this.hostname = value.asString();
1382                } else if (memberName.equals("tracking_codes")) {
1383                    this.trackingCodes = this.parseTrackingCodes(value.asArray());
1384                }
1385            } catch (Exception e) {
1386                throw new BoxDeserializationException(memberName, value.toString(), e);
1387            }
1388
1389        }
1390
1391        private List<String> parseMyTags(JsonArray jsonArray) {
1392            List<String> myTags = new ArrayList<>(jsonArray.size());
1393            for (JsonValue value : jsonArray) {
1394                myTags.add(value.asString());
1395            }
1396
1397            return myTags;
1398        }
1399
1400        private Map<String, String> parseTrackingCodes(JsonArray jsonArray) {
1401            Map<String, String> result = new HashMap<>();
1402            if (jsonArray == null) {
1403                return null;
1404            }
1405            List<JsonValue> valuesList = jsonArray.values();
1406            for (JsonValue jsonValue : valuesList) {
1407                JsonObject object = jsonValue.asObject();
1408                result.put(object.get("name").asString(), object.get("value").asString());
1409            }
1410            return result;
1411        }
1412    }
1413}