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        performUserDelete(queryString);
590    }
591
592    /**
593     * Deletes a user from an enterprise account. Uses API default values to determine if request should
594     * be forced and if user should be notified.
595     */
596    public void delete() {
597        performUserDelete("");
598    }
599
600    private void performUserDelete(String queryString) {
601        URL url = USER_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID());
602        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
603        BoxAPIResponse response = request.send();
604        response.disconnect();
605    }
606
607    /**
608     * Updates the information about this user with any info fields that have been modified locally.
609     *
610     * <p>Note: This method is only available to enterprise admins.</p>
611     *
612     * @param info info the updated info.
613     */
614    public void updateInfo(BoxUser.Info info) {
615        URL url = USER_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
616        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
617        request.setBody(info.getPendingChanges());
618        BoxJSONResponse response = (BoxJSONResponse) request.send();
619        JsonObject jsonObject = Json.parse(response.getJSON()).asObject();
620        info.update(jsonObject);
621    }
622
623    /**
624     * @param sourceUserID the user id of the user whose files will be the source for this operation
625     * @return info for the newly created folder
626     * @deprecated As of release 2.22.0, replaced by {@link #transferContent(String)} ()}
627     * <p>
628     * Moves all of the owned content from within one user’s folder into a new folder in another user's account.
629     * You can move folders across users as long as the you have administrative permissions and the 'source'
630     * user owns the folders. Per the documentation at the link below, this will move everything from the root
631     * folder, as this is currently the only mode of operation supported.
632     * <p>
633     * 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>
634     */
635    @Deprecated
636    public BoxFolder.Info moveFolderToUser(String sourceUserID) {
637        // Currently the API only supports moving of the root folder (0), hence the hard coded "0"
638        URL url = MOVE_FOLDER_TO_USER_TEMPLATE.build(this.getAPI().getBaseURL(), sourceUserID, "0");
639        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
640        JsonObject idValue = new JsonObject();
641        idValue.add("id", this.getID());
642        JsonObject ownedBy = new JsonObject();
643        ownedBy.add("owned_by", idValue);
644        request.setBody(ownedBy.toString());
645        BoxJSONResponse response = (BoxJSONResponse) request.send();
646        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
647        BoxFolder movedFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString());
648
649        return movedFolder.new Info(responseJSON);
650    }
651
652    /**
653     * Moves all of the owned content from within one user’s folder into a new folder in another user's account.
654     * You can move folders across users as long as the you have administrative permissions and the 'source'
655     * user owns the folders. Per the documentation at the link below, this will move everything from the root
656     * folder, as this is currently the only mode of operation supported.
657     * <p>
658     * 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>
659     *
660     * @param destinationUserID the user id of the user that you wish to transfer content to.
661     * @return info for the newly created folder.
662     */
663    public BoxFolder.Info transferContent(String destinationUserID) {
664        URL url = MOVE_FOLDER_TO_USER_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), "0");
665        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
666        JsonObject destinationUser = new JsonObject();
667        destinationUser.add("id", destinationUserID);
668        JsonObject ownedBy = new JsonObject();
669        ownedBy.add("owned_by", destinationUser);
670        request.setBody(ownedBy.toString());
671        BoxJSONResponse response = (BoxJSONResponse) request.send();
672        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
673        BoxFolder movedFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString());
674
675        return movedFolder.new Info(responseJSON);
676    }
677
678    /**
679     * Retrieves the avatar of a user as an InputStream.
680     *
681     * @return InputStream representing the user avater.
682     */
683    public InputStream getAvatar() {
684        URL url = USER_AVATAR_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
685        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
686        BoxAPIResponse response = request.send();
687
688        return response.getBody();
689    }
690
691    /**
692     * Upload avatar image to user account. Supported formats are JPG and PNG.
693     * The image size cannot exceed 1024 * 1024 pixels or 1MB.
694     *
695     * @param file File containg avatar image.
696     * @return Avatar creation response.
697     */
698    public AvatarUploadResponse uploadAvatar(File file) {
699        try {
700            return uploadAvatar(new FileInputStream(file), file.getName());
701        } catch (FileNotFoundException e) {
702            throw new RuntimeException(e);
703        }
704    }
705
706    /**
707     * Upload avatar image to user account. Supported formats are JPG and PNG.
708     * The image size cannot exceed 1024 * 1024 pixels or 1MB.
709     *
710     * @param file             {@link File} containg avatar image.
711     * @param progressListener {@link ProgressListener} set if you want to track upload progress
712     * @return Avatar creation response.
713     */
714    public AvatarUploadResponse uploadAvatar(File file, ProgressListener progressListener) {
715        try {
716            return uploadAvatar(new FileInputStream(file), file.getName(), progressListener);
717        } catch (FileNotFoundException e) {
718            throw new RuntimeException(e);
719        }
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     * @return Avatar creation response.
729     */
730    public AvatarUploadResponse uploadAvatar(InputStream content, String fileName) {
731        return uploadAvatar(content, fileName, null);
732    }
733
734    /**
735     * Upload avatar image to user account. Supported formats are JPG and PNG.
736     * The image size cannot exceed 1024 * 1024 pixels or 1MB.
737     *
738     * @param content          {@link InputStream} containing image data
739     * @param fileName         file name with extention what will be used to determine content type
740     * @param progressListener {@link ProgressListener} set if you want to track upload progress
741     * @return Avatar creation response.
742     */
743    public AvatarUploadResponse uploadAvatar(InputStream content, String fileName, ProgressListener progressListener) {
744        URL url = USER_AVATAR_TEMPLATE.build(getAPI().getBaseURL(), this.getID());
745        BoxImageMultipartRequest request = new BoxImageMultipartRequest(getAPI(), url, "pic");
746        request.setFile(content, fileName);
747
748        BoxAPIResponse response;
749        if (progressListener != null) {
750            response = request.send(progressListener);
751        } else {
752            response = request.send();
753        }
754
755        return parseUploadAvatarResponse(response);
756    }
757
758    /**
759     * Removes avatar from user account.
760     */
761    public void deleteAvatar() {
762        URL url = USER_AVATAR_TEMPLATE.build(getAPI().getBaseURL(), this.getID());
763        BoxAPIRequest request = new BoxAPIRequest(getAPI(), url, DELETE);
764        request.send();
765    }
766
767    private AvatarUploadResponse parseUploadAvatarResponse(BoxAPIResponse response) {
768        JsonObject responseObject = Json.parse(response.bodyToString()).asObject();
769        JsonObject picUrls = responseObject.get("pic_urls").asObject();
770        return new AvatarUploadResponse(
771            picUrls.getString("small", null),
772            picUrls.getString("large", null),
773            picUrls.getString("preview", null)
774        );
775    }
776
777    /**
778     * Enumerates the possible roles that a user can have within an enterprise.
779     */
780    public enum Role {
781        /**
782         * The user is an administrator of their enterprise.
783         */
784        ADMIN("admin"),
785
786        /**
787         * The user is a co-administrator of their enterprise.
788         */
789        COADMIN("coadmin"),
790
791        /**
792         * The user is a regular user within their enterprise.
793         */
794        USER("user");
795
796        private final String jsonValue;
797
798        Role(String jsonValue) {
799            this.jsonValue = jsonValue;
800        }
801
802        static Role fromJSONValue(String jsonValue) {
803            return Role.valueOf(jsonValue.toUpperCase());
804        }
805
806        String toJSONValue() {
807            return this.jsonValue;
808        }
809    }
810
811    /**
812     * Enumerates the possible statuses that a user's account can have.
813     */
814    public enum Status {
815        /**
816         * The user's account is active.
817         */
818        ACTIVE("active"),
819
820        /**
821         * The user's account is inactive.
822         */
823        INACTIVE("inactive"),
824
825        /**
826         * The user's account cannot delete or edit content.
827         */
828        CANNOT_DELETE_EDIT("cannot_delete_edit"),
829
830        /**
831         * The user's account cannot delete, edit, or upload content.
832         */
833        CANNOT_DELETE_EDIT_UPLOAD("cannot_delete_edit_upload");
834
835        private final String jsonValue;
836
837        Status(String jsonValue) {
838            this.jsonValue = jsonValue;
839        }
840
841        static Status fromJSONValue(String jsonValue) {
842            return Status.valueOf(jsonValue.toUpperCase());
843        }
844
845        String toJSONValue() {
846            return this.jsonValue;
847        }
848    }
849
850    /**
851     * Contains information about a BoxUser.
852     */
853    public class Info extends BoxCollaborator.Info {
854        private String login;
855        private Role role;
856        private String language;
857        private String timezone;
858        private long spaceAmount;
859        private long spaceUsed;
860        private long maxUploadSize;
861        private boolean canSeeManagedUsers;
862        private boolean isSyncEnabled;
863        private boolean isExternalCollabRestricted;
864        private Status status;
865        private String jobTitle;
866        private String phone;
867        private String address;
868        private String avatarURL;
869        private BoxNotificationEmail notificationEmail;
870        private boolean isExemptFromDeviceLimits;
871        private boolean isExemptFromLoginVerification;
872        private boolean isPasswordResetRequired;
873        private boolean isPlatformAccessOnly;
874        private String externalAppUserId;
875        private BoxEnterprise enterprise;
876        private List<String> myTags;
877        private String hostname;
878        private Map<String, String> trackingCodes;
879
880        /**
881         * Constructs an empty Info object.
882         */
883        public Info() {
884            super();
885        }
886
887        /**
888         * Constructs an Info object by parsing information from a JSON string.
889         *
890         * @param json the JSON string to parse.
891         */
892        public Info(String json) {
893            super(json);
894        }
895
896        Info(JsonObject jsonObject) {
897            super(jsonObject);
898        }
899
900        @Override
901        public BoxUser getResource() {
902            return BoxUser.this;
903        }
904
905        /**
906         * Gets the email address the user uses to login.
907         *
908         * @return the email address the user uses to login.
909         */
910        public String getLogin() {
911            return this.login;
912        }
913
914        /**
915         * Sets the email address the user uses to login. The new login must be one of the user's already confirmed
916         * email aliases.
917         *
918         * @param login one of the user's confirmed email aliases.
919         */
920        public void setLogin(String login) {
921            this.login = login;
922            this.addPendingChange("login", login);
923        }
924
925        /**
926         * Gets the user's enterprise role.
927         *
928         * @return the user's enterprise role.
929         */
930        public Role getRole() {
931            return this.role;
932        }
933
934        /**
935         * Sets the user's role in their enterprise.
936         *
937         * @param role the user's new role in their enterprise.
938         */
939        public void setRole(Role role) {
940            this.role = role;
941            this.addPendingChange("role", role.name().toLowerCase());
942        }
943
944        /**
945         * Gets the language of the user.
946         *
947         * @return the language of the user.
948         */
949        public String getLanguage() {
950            return this.language;
951        }
952
953        /**
954         * Sets the language of the user.
955         *
956         * @param language the new language of the user.
957         */
958        public void setLanguage(String language) {
959            this.language = language;
960            this.addPendingChange("language", language);
961        }
962
963        /**
964         * Gets the timezone of the user.
965         *
966         * @return the timezone of the user.
967         */
968        public String getTimezone() {
969            return this.timezone;
970        }
971
972        /**
973         * Sets the timezone of the user.
974         *
975         * @param timezone the new timezone of the user.
976         */
977        public void setTimezone(String timezone) {
978            this.timezone = timezone;
979            this.addPendingChange("timezone", timezone);
980        }
981
982        /**
983         * Gets the user's total available space in bytes.
984         *
985         * @return the user's total available space in bytes.
986         */
987        public long getSpaceAmount() {
988            return this.spaceAmount;
989        }
990
991        /**
992         * Sets the user's total available space in bytes.
993         *
994         * @param spaceAmount the new amount of space available to the user in bytes, or -1 for unlimited storage.
995         */
996        public void setSpaceAmount(long spaceAmount) {
997            this.spaceAmount = spaceAmount;
998            this.addPendingChange("space_amount", spaceAmount);
999        }
1000
1001        /**
1002         * Gets the amount of space the user has used in bytes.
1003         *
1004         * @return the amount of space the user has used in bytes.
1005         */
1006        public long getSpaceUsed() {
1007            return this.spaceUsed;
1008        }
1009
1010        /**
1011         * Gets the maximum individual file size in bytes the user can have.
1012         *
1013         * @return the maximum individual file size in bytes the user can have.
1014         */
1015        public long getMaxUploadSize() {
1016            return this.maxUploadSize;
1017        }
1018
1019        /**
1020         * Gets the user's current account status.
1021         *
1022         * @return the user's current account status.
1023         */
1024        public Status getStatus() {
1025            return this.status;
1026        }
1027
1028        /**
1029         * Sets the user's current account status.
1030         *
1031         * @param status the user's new account status.
1032         */
1033        public void setStatus(Status status) {
1034            this.status = status;
1035            this.addPendingChange("status", status.name().toLowerCase());
1036        }
1037
1038        /**
1039         * Gets the job title of the user.
1040         *
1041         * @return the job title of the user.
1042         */
1043        public String getJobTitle() {
1044            return this.jobTitle;
1045        }
1046
1047        /**
1048         * Sets the job title of the user.
1049         *
1050         * @param jobTitle the new job title of the user.
1051         */
1052        public void setJobTitle(String jobTitle) {
1053            this.jobTitle = jobTitle;
1054            this.addPendingChange("job_title", jobTitle);
1055        }
1056
1057        /**
1058         * Gets the phone number of the user.
1059         *
1060         * @return the phone number of the user.
1061         */
1062        public String getPhone() {
1063            return this.phone;
1064        }
1065
1066        /**
1067         * Sets the phone number of the user.
1068         *
1069         * @param phone the new phone number of the user.
1070         */
1071        public void setPhone(String phone) {
1072            this.phone = phone;
1073            this.addPendingChange("phone", phone);
1074        }
1075
1076        /**
1077         * Gets the address of the user.
1078         *
1079         * @return the address of the user.
1080         */
1081        public String getAddress() {
1082            return this.address;
1083        }
1084
1085        /**
1086         * Sets the address of the user.
1087         *
1088         * @param address the new address of the user.
1089         */
1090        public void setAddress(String address) {
1091            this.address = address;
1092            this.addPendingChange("address", address);
1093        }
1094
1095        /**
1096         * Gets the URL of the user's avatar.
1097         *
1098         * @return the URL of the user's avatar.
1099         */
1100        public String getAvatarURL() {
1101            return this.avatarURL;
1102        }
1103
1104        /**
1105         * Gets the user's alternate notification email address to which email notifications are sent.
1106         *
1107         * @return the user's notification email address.
1108         */
1109        public BoxNotificationEmail getNotificationEmail() {
1110            return this.notificationEmail;
1111        }
1112
1113        /**
1114         * Sets the user's notification email address.
1115         *
1116         * @param notificationEmail the user's new notification email address.
1117         */
1118        public void setNotificationEmail(BoxNotificationEmail notificationEmail) {
1119            this.notificationEmail = notificationEmail;
1120        }
1121
1122        /**
1123         * Gets the enterprise that the user belongs to.
1124         *
1125         * @return the enterprise that the user belongs to.
1126         */
1127        public BoxEnterprise getEnterprise() {
1128            return this.enterprise;
1129        }
1130
1131        /**
1132         * Removes the user from their enterprise and converts them to a standalone free user.
1133         */
1134        public void removeEnterprise() {
1135            this.removeChildObject("enterprise");
1136            this.enterprise = null;
1137            this.addChildObject("enterprise", null);
1138        }
1139
1140        /**
1141         * Gets whether or not the user can use Box Sync.
1142         *
1143         * @return true if the user can use Box Sync; otherwise false.
1144         */
1145        public boolean getIsSyncEnabled() {
1146            return this.isSyncEnabled;
1147        }
1148
1149        /**
1150         * Sets whether or not the user can use Box Sync.
1151         *
1152         * @param enabled whether or not the user can use Box Sync.
1153         */
1154        public void setIsSyncEnabled(boolean enabled) {
1155            this.isSyncEnabled = enabled;
1156            this.addPendingChange("is_sync_enabled", enabled);
1157        }
1158
1159        /**
1160         * Gets whether this user is allowed or not to collaborate with users outside their enterprise.
1161         *
1162         * @return true if this user is not allowed to collaborate with users outside their enterprise; otherwise false.
1163         */
1164        public boolean getIsExternalCollabRestricted() {
1165            return this.isExternalCollabRestricted;
1166        }
1167
1168        /**
1169         * Sets whether this user is allowed or not to collaborate with users outside their enterprise.
1170         *
1171         * @param isExternalCollabRestricted whether the user is allowed to collaborate outside their enterprise.
1172         */
1173        public void setIsExternalCollabRestricted(boolean isExternalCollabRestricted) {
1174            this.isExternalCollabRestricted = isExternalCollabRestricted;
1175            this.addPendingChange("is_external_collab_restricted", isExternalCollabRestricted);
1176        }
1177
1178        /**
1179         * Gets whether or not the user can see other enterprise users in their contact list.
1180         *
1181         * @return true if the user can see other enterprise users in their contact list; otherwise false.
1182         */
1183        public boolean getCanSeeManagedUsers() {
1184            return this.canSeeManagedUsers;
1185        }
1186
1187        /**
1188         * Sets whether or not the user can see other enterprise users in their contact list.
1189         *
1190         * @param canSeeManagedUsers whether or not the user can see other enterprise users in their contact list.
1191         */
1192        public void setCanSeeManagedUsers(boolean canSeeManagedUsers) {
1193            this.canSeeManagedUsers = canSeeManagedUsers;
1194            this.addPendingChange("can_see_managed_users", canSeeManagedUsers);
1195        }
1196
1197        /**
1198         * Gets whether or not the user is exempt from enterprise device limits.
1199         *
1200         * @return true if the user is exempt from enterprise device limits; otherwise false.
1201         */
1202        public boolean getIsExemptFromDeviceLimits() {
1203            return this.isExemptFromDeviceLimits;
1204        }
1205
1206        /**
1207         * Sets whether or not the user is exempt from enterprise device limits.
1208         *
1209         * @param isExemptFromDeviceLimits whether or not the user is exempt from enterprise device limits.
1210         */
1211        public void setIsExemptFromDeviceLimits(boolean isExemptFromDeviceLimits) {
1212            this.isExemptFromDeviceLimits = isExemptFromDeviceLimits;
1213            this.addPendingChange("is_exempt_from_device_limits", isExemptFromDeviceLimits);
1214        }
1215
1216        /**
1217         * Gets whether or not the user must use two-factor authentication.
1218         *
1219         * @return true if the user must use two-factor authentication; otherwise false.
1220         */
1221        public boolean getIsExemptFromLoginVerification() {
1222            return this.isExemptFromLoginVerification;
1223        }
1224
1225        /**
1226         * Sets whether or not the user must use two-factor authentication.
1227         *
1228         * @param isExemptFromLoginVerification whether or not the user must use two-factor authentication.
1229         */
1230        public void setIsExemptFromLoginVerification(boolean isExemptFromLoginVerification) {
1231            this.isExemptFromLoginVerification = isExemptFromLoginVerification;
1232            this.addPendingChange("is_exempt_from_login_verification", isExemptFromLoginVerification);
1233        }
1234
1235        /**
1236         * Gets whether or not the user is required to reset password.
1237         *
1238         * @return true if the user is required to reset password; otherwise false.
1239         */
1240        public boolean getIsPasswordResetRequired() {
1241            return this.isPasswordResetRequired;
1242        }
1243
1244        /**
1245         * Sets whether or not the user is required to reset password.
1246         *
1247         * @param isPasswordResetRequired whether or not the user is required to reset password.
1248         */
1249        public void setIsPasswordResetRequired(boolean isPasswordResetRequired) {
1250            this.isPasswordResetRequired = isPasswordResetRequired;
1251            this.addPendingChange("is_password_reset_required", isPasswordResetRequired);
1252        }
1253
1254        /**
1255         * Gets whether or not the user we are creating is an app user with Box Developer Edition.
1256         *
1257         * @return true if the new user is an app user for Box Developer Addition; otherwise false.
1258         */
1259        public boolean getIsPlatformAccessOnly() {
1260            return this.isPlatformAccessOnly;
1261        }
1262
1263        /**
1264         * Gets the external app user id that has been set for the app user.
1265         *
1266         * @return the external app user id.
1267         */
1268        public String getExternalAppUserId() {
1269            return this.externalAppUserId;
1270        }
1271
1272        /**
1273         * Sets the external app user id.
1274         *
1275         * @param externalAppUserId external app user id.
1276         */
1277        public void setExternalAppUserId(String externalAppUserId) {
1278            this.externalAppUserId = externalAppUserId;
1279            this.addPendingChange("external_app_user_id", externalAppUserId);
1280        }
1281
1282        /**
1283         * Gets the tags for all files and folders owned by this user.
1284         *
1285         * @return the tags for all files and folders owned by this user.
1286         */
1287        public List<String> getMyTags() {
1288            return this.myTags;
1289        }
1290
1291        /**
1292         * Gets the root (protocol, subdomain, domain) of any links that need to be generated for this user.
1293         *
1294         * @return the root (protocol, subdomain, domain) of any links that need to be generated for this user.
1295         */
1296        public String getHostname() {
1297            return this.hostname;
1298        }
1299
1300        /**
1301         * Gets the tracking defined for each entity.
1302         *
1303         * @return a Map with tracking codes.
1304         */
1305        public Map<String, String> getTrackingCodes() {
1306            return this.trackingCodes;
1307        }
1308
1309        /**
1310         * Allows admin to set attributes specific for a group of users.
1311         *
1312         * @param trackingCodes a Map representing the user's new tracking codes
1313         */
1314        public void setTrackingCodes(Map<String, String> trackingCodes) {
1315            this.trackingCodes = trackingCodes;
1316            this.addPendingChange("tracking_codes", toTrackingCodesJson(this.trackingCodes));
1317        }
1318
1319        /**
1320         * Allows the admin to append new tracking codes to the previous existing list.
1321         *
1322         * @param name  the name or `key` of the attribute to set.
1323         * @param value the value of the attribute to set.
1324         */
1325        public void appendTrackingCodes(String name, String value) {
1326            this.getTrackingCodes().put(name, value);
1327            this.addPendingChange("tracking_codes", toTrackingCodesJson(this.trackingCodes));
1328        }
1329
1330        @SuppressWarnings("checkstyle:MissingSwitchDefault")
1331        @Override
1332        protected void parseJSONMember(JsonObject.Member member) {
1333            super.parseJSONMember(member);
1334
1335            JsonValue value = member.getValue();
1336            String memberName = member.getName();
1337            try {
1338                switch (memberName) {
1339                    case "login":
1340                        this.login = value.asString();
1341                        break;
1342                    case "role":
1343                        this.role = Role.fromJSONValue(value.asString());
1344                        break;
1345                    case "language":
1346                        this.language = value.asString();
1347                        break;
1348                    case "timezone":
1349                        this.timezone = value.asString();
1350                        break;
1351                    case "space_amount":
1352                        this.spaceAmount = Double.valueOf(value.toString()).longValue();
1353                        break;
1354                    case "space_used":
1355                        this.spaceUsed = Double.valueOf(value.toString()).longValue();
1356                        break;
1357                    case "max_upload_size":
1358                        this.maxUploadSize = Double.valueOf(value.toString()).longValue();
1359                        break;
1360                    case "status":
1361                        this.status = Status.fromJSONValue(value.asString());
1362                        break;
1363                    case "job_title":
1364                        this.jobTitle = value.asString();
1365                        break;
1366                    case "phone":
1367                        this.phone = value.asString();
1368                        break;
1369                    case "address":
1370                        this.address = value.asString();
1371                        break;
1372                    case "avatar_url":
1373                        this.avatarURL = value.asString();
1374                        break;
1375                    case "notification_email":
1376                        if (value.isObject()) {
1377                            this.notificationEmail = new BoxNotificationEmail(value.asObject());
1378                        } else {
1379                            this.notificationEmail = null;
1380                        }
1381                        break;
1382                    case "can_see_managed_users":
1383                        this.canSeeManagedUsers = value.asBoolean();
1384                        break;
1385                    case "is_sync_enabled":
1386                        this.isSyncEnabled = value.asBoolean();
1387                        break;
1388                    case "is_external_collab_restricted":
1389                        this.isExternalCollabRestricted = value.asBoolean();
1390                        break;
1391                    case "is_exempt_from_device_limits":
1392                        this.isExemptFromDeviceLimits = value.asBoolean();
1393                        break;
1394                    case "is_exempt_from_login_verification":
1395                        this.isExemptFromLoginVerification = value.asBoolean();
1396                        break;
1397                    case "is_password_reset_required":
1398                        this.isPasswordResetRequired = value.asBoolean();
1399                        break;
1400                    case "is_platform_access_only":
1401                        this.isPlatformAccessOnly = value.asBoolean();
1402                        break;
1403                    case "external_app_user_id":
1404                        this.externalAppUserId = value.asString();
1405                        break;
1406                    case "enterprise":
1407                        JsonObject jsonObject = value.asObject();
1408                        if (this.enterprise == null) {
1409                            this.enterprise = new BoxEnterprise(jsonObject);
1410                        } else {
1411                            this.enterprise.update(jsonObject);
1412                        }
1413                        break;
1414                    case "my_tags":
1415                        this.myTags = this.parseMyTags(value.asArray());
1416                        break;
1417                    case "hostname":
1418                        this.hostname = value.asString();
1419                        break;
1420                    case "tracking_codes":
1421                        this.trackingCodes = this.parseTrackingCodes(value.asArray());
1422                        break;
1423                }
1424            } catch (Exception e) {
1425                throw new BoxDeserializationException(memberName, value.toString(), e);
1426            }
1427
1428        }
1429
1430        private List<String> parseMyTags(JsonArray jsonArray) {
1431            List<String> myTags = new ArrayList<>(jsonArray.size());
1432            for (JsonValue value : jsonArray) {
1433                myTags.add(value.asString());
1434            }
1435
1436            return myTags;
1437        }
1438
1439        private Map<String, String> parseTrackingCodes(JsonArray jsonArray) {
1440            Map<String, String> result = new HashMap<>();
1441            if (jsonArray == null) {
1442                return null;
1443            }
1444            List<JsonValue> valuesList = jsonArray.values();
1445            for (JsonValue jsonValue : valuesList) {
1446                JsonObject object = jsonValue.asObject();
1447                result.put(object.get("name").asString(), object.get("value").asString());
1448            }
1449            return result;
1450        }
1451    }
1452}