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