001package com.box.sdk;
002
003import java.io.InputStream;
004import java.net.URL;
005import java.util.ArrayList;
006import java.util.Collection;
007import java.util.Date;
008import java.util.EnumSet;
009import java.util.Iterator;
010
011import com.eclipsesource.json.JsonArray;
012import com.eclipsesource.json.JsonObject;
013import com.eclipsesource.json.JsonValue;
014
015/**
016 * Represents a folder on Box. This class can be used to iterate through a folder's contents, collaborate a folder with
017 * another user or group, and perform other common folder operations (move, copy, delete, etc.).
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 */
023public class BoxFolder extends BoxItem implements Iterable<BoxItem.Info> {
024    /**
025     * An array of all possible folder fields that can be requested when calling {@link #getInfo()}.
026     */
027    public static final String[] ALL_FIELDS = {"type", "id", "sequence_id", "etag", "name", "created_at", "modified_at",
028        "description", "size", "path_collection", "created_by", "modified_by", "trashed_at", "purged_at",
029        "content_created_at", "content_modified_at", "owned_by", "shared_link", "folder_upload_email", "parent",
030        "item_status", "item_collection", "sync_state", "has_collaborations", "permissions", "tags",
031        "can_non_owners_invite"};
032
033    private static final URLTemplate CREATE_FOLDER_URL = new URLTemplate("folders");
034    private static final URLTemplate COPY_FOLDER_URL = new URLTemplate("folders/%s/copy");
035    private static final URLTemplate DELETE_FOLDER_URL = new URLTemplate("folders/%s?recursive=%b");
036    private static final URLTemplate FOLDER_INFO_URL_TEMPLATE = new URLTemplate("folders/%s");
037    private static final URLTemplate UPLOAD_FILE_URL = new URLTemplate("files/content");
038    private static final URLTemplate ADD_COLLABORATION_URL = new URLTemplate("collaborations");
039    private static final URLTemplate GET_COLLABORATIONS_URL = new URLTemplate("folders/%s/collaborations");
040    private static final URLTemplate GET_ITEMS_URL = new URLTemplate("folders/%s/items/");
041    private static final URLTemplate SEARCH_URL_TEMPLATE = new URLTemplate("search");
042
043    /**
044     * Constructs a BoxFolder for a folder with a given ID.
045     * @param  api the API connection to be used by the folder.
046     * @param  id  the ID of the folder.
047     */
048    public BoxFolder(BoxAPIConnection api, String id) {
049        super(api, id);
050    }
051
052    /**
053     * Gets the current user's root folder.
054     * @param  api the API connection to be used by the folder.
055     * @return     the user's root folder.
056     */
057    public static BoxFolder getRootFolder(BoxAPIConnection api) {
058        return new BoxFolder(api, "0");
059    }
060
061    /**
062     * Adds a collaborator to this folder.
063     * @param  collaborator the collaborator to add.
064     * @param  role         the role of the collaborator.
065     * @return              info about the new collaboration.
066     */
067    public BoxCollaboration.Info collaborate(BoxCollaborator collaborator, BoxCollaboration.Role role) {
068        JsonObject accessibleByField = new JsonObject();
069        accessibleByField.add("id", collaborator.getID());
070
071        if (collaborator instanceof BoxUser) {
072            accessibleByField.add("type", "user");
073        } else {
074            throw new IllegalArgumentException("The given collaborator is of an unknown type.");
075        }
076
077        return this.collaborate(accessibleByField, role);
078    }
079
080    /**
081     * Adds a collaborator to this folder. An email will be sent to the collaborator if they don't already have a Box
082     * account.
083     * @param  email the email address of the collaborator to add.
084     * @param  role  the role of the collaborator.
085     * @return       info about the new collaboration.
086     */
087    public BoxCollaboration.Info collaborate(String email, BoxCollaboration.Role role) {
088        JsonObject accessibleByField = new JsonObject();
089        accessibleByField.add("login", email);
090        accessibleByField.add("type", "user");
091
092        return this.collaborate(accessibleByField, role);
093    }
094
095    private BoxCollaboration.Info collaborate(JsonObject accessibleByField, BoxCollaboration.Role role) {
096        BoxAPIConnection api = this.getAPI();
097        URL url = ADD_COLLABORATION_URL.build(api.getBaseURL());
098
099        JsonObject itemField = new JsonObject();
100        itemField.add("id", this.getID());
101        itemField.add("type", "folder");
102
103        JsonObject requestJSON = new JsonObject();
104        requestJSON.add("item", itemField);
105        requestJSON.add("accessible_by", accessibleByField);
106        requestJSON.add("role", role.toJSONString());
107
108        BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
109        request.setBody(requestJSON.toString());
110        BoxJSONResponse response = (BoxJSONResponse) request.send();
111        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
112
113        BoxCollaboration newCollaboration = new BoxCollaboration(api, responseJSON.get("id").asString());
114        BoxCollaboration.Info info = newCollaboration.new Info(responseJSON);
115        return info;
116    }
117
118    @Override
119    public BoxSharedLink createSharedLink(BoxSharedLink.Access access, Date unshareDate,
120        BoxSharedLink.Permissions permissions) {
121
122        BoxSharedLink sharedLink = new BoxSharedLink(access, unshareDate, permissions);
123        Info info = new Info();
124        info.setSharedLink(sharedLink);
125
126        this.updateInfo(info);
127        return info.getSharedLink();
128    }
129
130    /**
131     * Gets information about all of the collaborations for this folder.
132     * @return a collection of information about the collaborations for this folder.
133     */
134    public Collection<BoxCollaboration.Info> getCollaborations() {
135        BoxAPIConnection api = this.getAPI();
136        URL url = GET_COLLABORATIONS_URL.build(api.getBaseURL(), this.getID());
137
138        BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
139        BoxJSONResponse response = (BoxJSONResponse) request.send();
140        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
141
142        int entriesCount = responseJSON.get("total_count").asInt();
143        Collection<BoxCollaboration.Info> collaborations = new ArrayList<BoxCollaboration.Info>(entriesCount);
144        JsonArray entries = responseJSON.get("entries").asArray();
145        for (JsonValue entry : entries) {
146            JsonObject entryObject = entry.asObject();
147            BoxCollaboration collaboration = new BoxCollaboration(api, entryObject.get("id").asString());
148            BoxCollaboration.Info info = collaboration.new Info(entryObject);
149            collaborations.add(info);
150        }
151
152        return collaborations;
153    }
154
155    @Override
156    public BoxFolder.Info getInfo() {
157        URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
158        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
159        BoxJSONResponse response = (BoxJSONResponse) request.send();
160        return new Info(response.getJSON());
161    }
162
163    @Override
164    public BoxFolder.Info getInfo(String... fields) {
165        String queryString = new QueryStringBuilder().appendParam("fields", fields).toString();
166        URL url = FOLDER_INFO_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID());
167
168        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
169        BoxJSONResponse response = (BoxJSONResponse) request.send();
170        return new Info(response.getJSON());
171    }
172
173    /**
174     * Updates the information about this folder with any info fields that have been modified locally.
175     * @param info the updated info.
176     */
177    public void updateInfo(BoxFolder.Info info) {
178        URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
179        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
180        request.setBody(info.getPendingChanges());
181        BoxJSONResponse response = (BoxJSONResponse) request.send();
182        JsonObject jsonObject = JsonObject.readFrom(response.getJSON());
183        info.update(jsonObject);
184    }
185
186    @Override
187    public BoxFolder.Info copy(BoxFolder destination) {
188        return this.copy(destination, null);
189    }
190
191    @Override
192    public BoxFolder.Info copy(BoxFolder destination, String newName) {
193        URL url = COPY_FOLDER_URL.build(this.getAPI().getBaseURL(), this.getID());
194        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
195
196        JsonObject parent = new JsonObject();
197        parent.add("id", destination.getID());
198
199        JsonObject copyInfo = new JsonObject();
200        copyInfo.add("parent", parent);
201        if (newName != null) {
202            copyInfo.add("name", newName);
203        }
204
205        request.setBody(copyInfo.toString());
206        BoxJSONResponse response = (BoxJSONResponse) request.send();
207        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
208        BoxFolder copiedFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString());
209        return copiedFolder.new Info(responseJSON);
210    }
211
212    /**
213     * Creates a new child folder inside this folder.
214     * @param  name the new folder's name.
215     * @return      the created folder's info.
216     */
217    public BoxFolder.Info createFolder(String name) {
218        JsonObject parent = new JsonObject();
219        parent.add("id", this.getID());
220
221        JsonObject newFolder = new JsonObject();
222        newFolder.add("name", name);
223        newFolder.add("parent", parent);
224
225        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), CREATE_FOLDER_URL.build(this.getAPI().getBaseURL()),
226            "POST");
227        request.setBody(newFolder.toString());
228        BoxJSONResponse response = (BoxJSONResponse) request.send();
229        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
230
231        BoxFolder createdFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString());
232        return createdFolder.new Info(responseJSON);
233    }
234
235    /**
236     * Deletes this folder, optionally recursively deleting all of its contents.
237     * @param recursive true to recursively delete this folder's contents; otherwise false.
238     */
239    public void delete(boolean recursive) {
240        URL url = DELETE_FOLDER_URL.build(this.getAPI().getBaseURL(), this.getID(), recursive);
241        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
242        BoxAPIResponse response = request.send();
243        response.disconnect();
244    }
245
246    @Override
247    public BoxItem.Info move(BoxFolder destination) {
248        return this.move(destination, null);
249    }
250
251    @Override
252    public BoxItem.Info move(BoxFolder destination, String newName) {
253        URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
254        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
255
256        JsonObject parent = new JsonObject();
257        parent.add("id", destination.getID());
258
259        JsonObject updateInfo = new JsonObject();
260        updateInfo.add("parent", parent);
261        if (newName != null) {
262            updateInfo.add("name", newName);
263        }
264
265        request.setBody(updateInfo.toString());
266        BoxJSONResponse response = (BoxJSONResponse) request.send();
267        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
268        BoxFolder movedFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString());
269        return movedFolder.new Info(responseJSON);
270    }
271
272    /**
273     * Renames this folder.
274     * @param newName the new name of the folder.
275     */
276    public void rename(String newName) {
277        URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
278        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
279
280        JsonObject updateInfo = new JsonObject();
281        updateInfo.add("name", newName);
282
283        request.setBody(updateInfo.toString());
284        BoxAPIResponse response = request.send();
285        response.disconnect();
286    }
287
288    /**
289     * Uploads a new file to this folder.
290     * @param  fileContent a stream containing the contents of the file to upload.
291     * @param  name        the name to give the uploaded file.
292     * @return             the uploaded file's info.
293     */
294    public BoxFile.Info uploadFile(InputStream fileContent, String name) {
295        FileUploadParams uploadInfo = new FileUploadParams()
296            .setContent(fileContent)
297            .setName(name);
298        return this.uploadFile(uploadInfo);
299    }
300
301    /**
302     * Uploads a new file to this folder while reporting the progress to a ProgressListener.
303     * @param  fileContent a stream containing the contents of the file to upload.
304     * @param  name        the name to give the uploaded file.
305     * @param  fileSize    the size of the file used for determining the progress of the upload.
306     * @param  listener    a listener for monitoring the upload's progress.
307     * @return             the uploaded file's info.
308     */
309    public BoxFile.Info uploadFile(InputStream fileContent, String name, long fileSize, ProgressListener listener) {
310        FileUploadParams uploadInfo = new FileUploadParams()
311            .setContent(fileContent)
312            .setName(name)
313            .setSize(fileSize)
314            .setProgressListener(listener);
315        return this.uploadFile(uploadInfo);
316    }
317
318    /**
319     * Uploads a new file to this folder with custom upload parameters.
320     * @param  uploadParams the custom upload parameters.
321     * @return              the uploaded file's info.
322     */
323    public BoxFile.Info uploadFile(FileUploadParams uploadParams) {
324        URL uploadURL = UPLOAD_FILE_URL.build(this.getAPI().getBaseUploadURL());
325        BoxMultipartRequest request = new BoxMultipartRequest(getAPI(), uploadURL);
326        request.putField("parent_id", getID());
327
328        if (uploadParams.getSize() > 0) {
329            request.setFile(uploadParams.getContent(), uploadParams.getName(), uploadParams.getSize());
330        } else {
331            request.setFile(uploadParams.getContent(), uploadParams.getName());
332        }
333
334        if (uploadParams.getCreated() != null) {
335            request.putField("content_created_at", uploadParams.getCreated());
336        }
337
338        if (uploadParams.getModified() != null) {
339            request.putField("content_modified_at", uploadParams.getModified());
340        }
341
342        BoxJSONResponse response;
343        if (uploadParams.getProgressListener() == null) {
344            response = (BoxJSONResponse) request.send();
345        } else {
346            response = (BoxJSONResponse) request.send(uploadParams.getProgressListener());
347        }
348        JsonObject collection = JsonObject.readFrom(response.getJSON());
349        JsonArray entries = collection.get("entries").asArray();
350        JsonObject fileInfoJSON = entries.get(0).asObject();
351        String uploadedFileID = fileInfoJSON.get("id").asString();
352
353        BoxFile uploadedFile = new BoxFile(getAPI(), uploadedFileID);
354        return uploadedFile.new Info(fileInfoJSON);
355    }
356
357    /**
358     * Returns an iterable containing the items in this folder. Iterating over the iterable returned by this method is
359     * equivalent to iterating over this BoxFolder directly.
360     * @return an iterable containing the items in this folder.
361     */
362    public Iterable<BoxItem.Info> getChildren() {
363        return this;
364    }
365
366    /**
367     * Returns an iterable containing the items in this folder and specifies which child fields to retrieve from the
368     * API.
369     * @param  fields the fields to retrieve.
370     * @return        an iterable containing the items in this folder.
371     */
372    public Iterable<BoxItem.Info> getChildren(final String... fields) {
373        return new Iterable<BoxItem.Info>() {
374            @Override
375            public Iterator<BoxItem.Info> iterator() {
376                String queryString = new QueryStringBuilder().appendParam("fields", fields).toString();
377                URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), queryString, getID());
378                return new BoxItemIterator(getAPI(), url);
379            }
380        };
381    }
382
383    /**
384     * Retrieves a specific range of child items in this folder.
385     * @param  offset the index of the first child item to retrieve.
386     * @param  limit  the maximum number of children to retrieve after the offset.
387     * @param  fields the fields to retrieve.
388     * @return        a partial collection containing the specified range of child items.
389     */
390    public PartialCollection<BoxItem.Info> getChildrenRange(long offset, long limit, String... fields) {
391        QueryStringBuilder builder = new QueryStringBuilder()
392            .appendParam("limit", limit)
393            .appendParam("offset", offset);
394
395        if (fields.length > 0) {
396            builder.appendParam("fields", fields).toString();
397        }
398
399        URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), builder.toString(), getID());
400        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
401        BoxJSONResponse response = (BoxJSONResponse) request.send();
402        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
403
404        String totalCountString = responseJSON.get("total_count").toString();
405        long fullSize = Double.valueOf(totalCountString).longValue();
406        PartialCollection<BoxItem.Info> children = new PartialCollection<BoxItem.Info>(offset, limit, fullSize);
407        JsonArray jsonArray = responseJSON.get("entries").asArray();
408        for (JsonValue value : jsonArray) {
409            JsonObject jsonObject = value.asObject();
410            BoxItem.Info parsedItemInfo = (BoxItem.Info) BoxResource.parseInfo(this.getAPI(), jsonObject);
411            if (parsedItemInfo != null) {
412                children.add(parsedItemInfo);
413            }
414        }
415        return children;
416    }
417
418    /**
419     * Returns an iterator over the items in this folder.
420     * @return an iterator over the items in this folder.
421     */
422    @Override
423    public Iterator<BoxItem.Info> iterator() {
424        URL url = GET_ITEMS_URL.build(this.getAPI().getBaseURL(), BoxFolder.this.getID());
425        return new BoxItemIterator(BoxFolder.this.getAPI(), url);
426    }
427
428    /**
429     * Searches this folder and all descendant folders using a given query.
430     * @param  query the search query.
431     * @return an Iterable containing the search results.
432     */
433    public Iterable<BoxItem.Info> search(final String query) {
434        return new Iterable<BoxItem.Info>() {
435            @Override
436            public Iterator<BoxItem.Info> iterator() {
437                QueryStringBuilder builder = new QueryStringBuilder();
438                builder.appendParam("query", query);
439                builder.appendParam("ancestor_folder_ids", getID());
440
441                URL url = SEARCH_URL_TEMPLATE.buildWithQuery(getAPI().getBaseURL(), builder.toString());
442                return new BoxItemIterator(getAPI(), url);
443            }
444        };
445    }
446
447    /**
448     * Contains information about a BoxFolder.
449     */
450    public class Info extends BoxItem.Info {
451        private BoxUploadEmail uploadEmail;
452        private boolean hasCollaborations;
453        private SyncState syncState;
454        private EnumSet<Permission> permissions;
455        private boolean canNonOwnersInvite;
456
457        /**
458         * Constructs an empty Info object.
459         */
460        public Info() {
461            super();
462        }
463
464        /**
465         * Constructs an Info object by parsing information from a JSON string.
466         * @param  json the JSON string to parse.
467         */
468        public Info(String json) {
469            super(json);
470        }
471
472        /**
473         * Constructs an Info object using an already parsed JSON object.
474         * @param  jsonObject the parsed JSON object.
475         */
476        Info(JsonObject jsonObject) {
477            super(jsonObject);
478        }
479
480        /**
481         * Gets the upload email for the folder.
482         * @return the upload email for the folder.
483         */
484        public BoxUploadEmail getUploadEmail() {
485            return this.uploadEmail;
486        }
487
488        /**
489         * Sets the upload email for the folder.
490         * @param uploadEmail the upload email for the folder.
491         */
492        public void setUploadEmail(BoxUploadEmail uploadEmail) {
493            if (this.uploadEmail == uploadEmail) {
494                return;
495            }
496
497            this.removeChildObject("folder_upload_email");
498            this.uploadEmail = uploadEmail;
499
500            if (uploadEmail == null) {
501                this.addPendingChange("folder_upload_email", null);
502            } else {
503                this.addChildObject("folder_upload_email", uploadEmail);
504            }
505        }
506
507        /**
508         * Gets whether or not the folder has any collaborations.
509         * @return true if the folder has collaborations; otherwise false.
510         */
511        public boolean getHasCollaborations() {
512            return this.hasCollaborations;
513        }
514
515        /**
516         * Gets the sync state of the folder.
517         * @return the sync state of the folder.
518         */
519        public SyncState getSyncState() {
520            return this.syncState;
521        }
522
523        /**
524         * Sets the sync state of the folder.
525         * @param syncState the sync state of the folder.
526         */
527        public void setSyncState(SyncState syncState) {
528            this.syncState = syncState;
529            this.addPendingChange("sync_state", syncState.toJSONValue());
530        }
531
532        /**
533         * Gets the permissions that the current user has on the folder.
534         * @return the permissions that the current user has on the folder.
535         */
536        public EnumSet<Permission> getPermissions() {
537            return this.permissions;
538        }
539
540        /**
541         * Gets whether or not the non-owners can invite collaborators to the folder.
542         * @return [description]
543         */
544        public boolean getCanNonOwnersInvite() {
545            return this.canNonOwnersInvite;
546        }
547
548        @Override
549        public BoxFolder getResource() {
550            return BoxFolder.this;
551        }
552
553        @Override
554        protected void parseJSONMember(JsonObject.Member member) {
555            super.parseJSONMember(member);
556
557            String memberName = member.getName();
558            JsonValue value = member.getValue();
559            if (memberName.equals("folder_upload_email")) {
560                if (this.uploadEmail == null) {
561                    this.uploadEmail = new BoxUploadEmail(value.asObject());
562                } else {
563                    this.uploadEmail.update(value.asObject());
564                }
565
566            } else if (memberName.equals("has_collaborations")) {
567                this.hasCollaborations = value.asBoolean();
568
569            } else if (memberName.equals("sync_state")) {
570                this.syncState = SyncState.fromJSONValue(value.asString());
571
572            } else if (memberName.equals("permissions")) {
573                this.permissions = this.parsePermissions(value.asObject());
574
575            } else if (memberName.equals("can_non_owners_invite")) {
576                this.canNonOwnersInvite = value.asBoolean();
577            }
578        }
579
580        private EnumSet<Permission> parsePermissions(JsonObject jsonObject) {
581            EnumSet<Permission> permissions = EnumSet.noneOf(Permission.class);
582            for (JsonObject.Member member : jsonObject) {
583                JsonValue value = member.getValue();
584                if (value.isNull() || !value.asBoolean()) {
585                    continue;
586                }
587
588                String memberName = member.getName();
589                if (memberName.equals("can_download")) {
590                    permissions.add(Permission.CAN_DOWNLOAD);
591                } else if (memberName.equals("can_upload")) {
592                    permissions.add(Permission.CAN_UPLOAD);
593                } else if (memberName.equals("can_rename")) {
594                    permissions.add(Permission.CAN_RENAME);
595                } else if (memberName.equals("can_delete")) {
596                    permissions.add(Permission.CAN_DELETE);
597                } else if (memberName.equals("can_share")) {
598                    permissions.add(Permission.CAN_SHARE);
599                } else if (memberName.equals("can_invite_collaborator")) {
600                    permissions.add(Permission.CAN_INVITE_COLLABORATOR);
601                } else if (memberName.equals("can_set_share_access")) {
602                    permissions.add(Permission.CAN_SET_SHARE_ACCESS);
603                }
604            }
605
606            return permissions;
607        }
608    }
609
610    /**
611     * Enumerates the possible sync states that a folder can have.
612     */
613    public enum SyncState {
614        /**
615         * The folder is synced.
616         */
617        SYNCED ("synced"),
618
619        /**
620         * The folder is not synced.
621         */
622        NOT_SYNCED ("not_synced"),
623
624        /**
625         * The folder is partially synced.
626         */
627        PARTIALLY_SYNCED ("partially_synced");
628
629        private final String jsonValue;
630
631        private SyncState(String jsonValue) {
632            this.jsonValue = jsonValue;
633        }
634
635        static SyncState fromJSONValue(String jsonValue) {
636            return SyncState.valueOf(jsonValue.toUpperCase());
637        }
638
639        String toJSONValue() {
640            return this.jsonValue;
641        }
642    }
643
644    /**
645     * Enumerates the possible permissions that a user can have on a folder.
646     */
647    public enum Permission {
648        /**
649         * The user can download the folder.
650         */
651        CAN_DOWNLOAD ("can_download"),
652
653        /**
654         * The user can upload to the folder.
655         */
656        CAN_UPLOAD ("can_upload"),
657
658        /**
659         * The user can rename the folder.
660         */
661        CAN_RENAME ("can_rename"),
662
663        /**
664         * The user can delete the folder.
665         */
666        CAN_DELETE ("can_delete"),
667
668        /**
669         * The user can share the folder.
670         */
671        CAN_SHARE ("can_share"),
672
673        /**
674         * The user can invite collaborators to the folder.
675         */
676        CAN_INVITE_COLLABORATOR ("can_invite_collaborator"),
677
678        /**
679         * The user can set the access level for shared links to the folder.
680         */
681        CAN_SET_SHARE_ACCESS ("can_set_share_access");
682
683        private final String jsonValue;
684
685        private Permission(String jsonValue) {
686            this.jsonValue = jsonValue;
687        }
688
689        static Permission fromJSONValue(String jsonValue) {
690            return Permission.valueOf(jsonValue.toUpperCase());
691        }
692
693        String toJSONValue() {
694            return this.jsonValue;
695        }
696    }
697}