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