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