001package com.box.sdk;
002
003import java.io.IOException;
004import java.io.InputStream;
005import java.io.OutputStream;
006import java.net.URL;
007import java.util.ArrayList;
008import java.util.Collection;
009import java.util.Date;
010import java.util.EnumSet;
011import java.util.List;
012
013import com.eclipsesource.json.JsonArray;
014import com.eclipsesource.json.JsonObject;
015import com.eclipsesource.json.JsonValue;
016
017/**
018 * Represents an individual file on Box. This class can be used to download a file's contents, upload new versions, and
019 * perform other common file operations (move, copy, delete, etc.).
020 *
021 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked
022 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error
023 * handling for errors related to the Box REST API, you should capture this exception explicitly.</p>
024 */
025public class BoxFile extends BoxItem {
026    /**
027     * An array of all possible file fields that can be requested when calling {@link #getInfo()}.
028     */
029    public static final String[] ALL_FIELDS = {"type", "id", "sequence_id", "etag", "sha1", "name", "description",
030        "size", "path_collection", "created_at", "modified_at", "trashed_at", "purged_at", "content_created_at",
031        "content_modified_at", "created_by", "modified_by", "owned_by", "shared_link", "parent", "item_status",
032        "version_number", "comment_count", "permissions", "tags", "lock", "extension", "is_package", "file_version"};
033
034    private static final URLTemplate FILE_URL_TEMPLATE = new URLTemplate("files/%s");
035    private static final URLTemplate CONTENT_URL_TEMPLATE = new URLTemplate("files/%s/content");
036    private static final URLTemplate VERSIONS_URL_TEMPLATE = new URLTemplate("files/%s/versions");
037    private static final URLTemplate COPY_URL_TEMPLATE = new URLTemplate("files/%s/copy");
038    private static final URLTemplate ADD_COMMENT_URL_TEMPLATE = new URLTemplate("comments");
039    private static final URLTemplate GET_COMMENTS_URL_TEMPLATE = new URLTemplate("files/%s/comments");
040    private static final URLTemplate METADATA_URL_TEMPLATE = new URLTemplate("files/%s/metadata/%s");
041    private static final String DEFAULT_METADATA_TYPE = "properties";
042    private static final int BUFFER_SIZE = 8192;
043
044    /**
045     * Constructs a BoxFile for a file with a given ID.
046     * @param  api the API connection to be used by the file.
047     * @param  id  the ID of the file.
048     */
049    public BoxFile(BoxAPIConnection api, String id) {
050        super(api, id);
051    }
052
053    @Override
054    public BoxSharedLink createSharedLink(BoxSharedLink.Access access, Date unshareDate,
055        BoxSharedLink.Permissions permissions) {
056
057        BoxSharedLink sharedLink = new BoxSharedLink(access, unshareDate, permissions);
058        Info info = new Info();
059        info.setSharedLink(sharedLink);
060
061        this.updateInfo(info);
062        return info.getSharedLink();
063    }
064
065    /**
066     * Adds a comment to this file. The message can contain @mentions by using the string @[userid:username] anywhere
067     * within the message, where userid and username are the ID and username of the person being mentioned.
068     * @see    <a href="https://developers.box.com/docs/#comments-add-a-comment-to-an-item">the tagged_message field
069     *         for including @mentions.</a>
070     * @param  message the comment's message.
071     * @return information about the newly added comment.
072     */
073    public BoxComment.Info addComment(String message) {
074        JsonObject itemJSON = new JsonObject();
075        itemJSON.add("type", "file");
076        itemJSON.add("id", this.getID());
077
078        JsonObject requestJSON = new JsonObject();
079        requestJSON.add("item", itemJSON);
080        if (BoxComment.messageContainsMention(message)) {
081            requestJSON.add("tagged_message", message);
082        } else {
083            requestJSON.add("message", message);
084        }
085
086        URL url = ADD_COMMENT_URL_TEMPLATE.build(this.getAPI().getBaseURL());
087        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
088        request.setBody(requestJSON.toString());
089        BoxJSONResponse response = (BoxJSONResponse) request.send();
090        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
091
092        BoxComment addedComment = new BoxComment(this.getAPI(), responseJSON.get("id").asString());
093        return addedComment.new Info(responseJSON);
094    }
095
096    /**
097     * Downloads the contents of this file to a given OutputStream.
098     * @param output the stream to where the file will be written.
099     */
100    public void download(OutputStream output) {
101        this.download(output, null);
102    }
103
104    /**
105     * Downloads the contents of this file to a given OutputStream while reporting the progress to a ProgressListener.
106     * @param output   the stream to where the file will be written.
107     * @param listener a listener for monitoring the download's progress.
108     */
109    public void download(OutputStream output, ProgressListener listener) {
110        URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
111        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
112        BoxAPIResponse response = request.send();
113        InputStream input = response.getBody(listener);
114
115        byte[] buffer = new byte[BUFFER_SIZE];
116        try {
117            int n = input.read(buffer);
118            while (n != -1) {
119                output.write(buffer, 0, n);
120                n = input.read(buffer);
121            }
122        } catch (IOException e) {
123            throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e);
124        } finally {
125            response.disconnect();
126        }
127    }
128
129    /**
130     * Downloads a part of this file's contents, starting at specified byte offset.
131     * @param output the stream to where the file will be written.
132     * @param offset the byte offset at which to start the download.
133     */
134    public void downloadRange(OutputStream output, long offset) {
135        this.downloadRange(output, offset, -1);
136    }
137
138    /**
139     * Downloads a part of this file's contents, starting at rangeStart and stopping at rangeEnd.
140     * @param output     the stream to where the file will be written.
141     * @param rangeStart the byte offset at which to start the download.
142     * @param rangeEnd   the byte offset at which to stop the download.
143     */
144    public void downloadRange(OutputStream output, long rangeStart, long rangeEnd) {
145        this.downloadRange(output, rangeStart, rangeEnd, null);
146    }
147
148    /**
149     * Downloads a part of this file's contents, starting at rangeStart and stopping at rangeEnd, while reporting the
150     * progress to a ProgressListener.
151     * @param output     the stream to where the file will be written.
152     * @param rangeStart the byte offset at which to start the download.
153     * @param rangeEnd   the byte offset at which to stop the download.
154     * @param listener   a listener for monitoring the download's progress.
155     */
156    public void downloadRange(OutputStream output, long rangeStart, long rangeEnd, ProgressListener listener) {
157        URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
158        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
159        if (rangeEnd > 0) {
160            request.addHeader("Range", String.format("bytes=%s-%s", Long.toString(rangeStart),
161                Long.toString(rangeEnd)));
162        } else {
163            request.addHeader("Range", String.format("bytes=%s-", Long.toString(rangeStart)));
164        }
165
166        BoxAPIResponse response = request.send();
167        InputStream input = response.getBody(listener);
168
169        byte[] buffer = new byte[BUFFER_SIZE];
170        try {
171            int n = input.read(buffer);
172            while (n != -1) {
173                output.write(buffer, 0, n);
174                n = input.read(buffer);
175            }
176        } catch (IOException e) {
177            throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e);
178        } finally {
179            response.disconnect();
180        }
181    }
182
183    @Override
184    public BoxFile.Info copy(BoxFolder destination) {
185        return this.copy(destination, null);
186    }
187
188    @Override
189    public BoxFile.Info copy(BoxFolder destination, String newName) {
190        URL url = COPY_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
191
192        JsonObject parent = new JsonObject();
193        parent.add("id", destination.getID());
194
195        JsonObject copyInfo = new JsonObject();
196        copyInfo.add("parent", parent);
197        if (newName != null) {
198            copyInfo.add("name", newName);
199        }
200
201        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
202        request.setBody(copyInfo.toString());
203        BoxJSONResponse response = (BoxJSONResponse) request.send();
204        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
205        BoxFile copiedFile = new BoxFile(this.getAPI(), responseJSON.get("id").asString());
206        return copiedFile.new Info(responseJSON);
207    }
208
209    /**
210     * Deletes this file by moving it to the trash.
211     */
212    public void delete() {
213        URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
214        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
215        BoxAPIResponse response = request.send();
216        response.disconnect();
217    }
218
219    @Override
220    public BoxItem.Info move(BoxFolder destination) {
221        return this.move(destination, null);
222    }
223
224    @Override
225    public BoxItem.Info move(BoxFolder destination, String newName) {
226        URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
227        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
228
229        JsonObject parent = new JsonObject();
230        parent.add("id", destination.getID());
231
232        JsonObject updateInfo = new JsonObject();
233        updateInfo.add("parent", parent);
234        if (newName != null) {
235            updateInfo.add("name", newName);
236        }
237
238        request.setBody(updateInfo.toString());
239        BoxJSONResponse response = (BoxJSONResponse) request.send();
240        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
241        BoxFile movedFile = new BoxFile(this.getAPI(), responseJSON.get("id").asString());
242        return movedFile.new Info(responseJSON);
243    }
244
245    /**
246     * Renames this file.
247     * @param newName the new name of the file.
248     */
249    public void rename(String newName) {
250        URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
251        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
252
253        JsonObject updateInfo = new JsonObject();
254        updateInfo.add("name", newName);
255
256        request.setBody(updateInfo.toString());
257        BoxAPIResponse response = request.send();
258        response.disconnect();
259    }
260
261    @Override
262    public BoxFile.Info getInfo() {
263        URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
264        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
265        BoxJSONResponse response = (BoxJSONResponse) request.send();
266        return new Info(response.getJSON());
267    }
268
269    @Override
270    public BoxFile.Info getInfo(String... fields) {
271        String queryString = new QueryStringBuilder().appendParam("fields", fields).toString();
272        URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID());
273
274        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
275        BoxJSONResponse response = (BoxJSONResponse) request.send();
276        return new Info(response.getJSON());
277    }
278
279    /**
280     * Updates the information about this file with any info fields that have been modified locally.
281     *
282     * <p>The only fields that will be updated are the ones that have been modified locally. For example, the following
283     * code won't update any information (or even send a network request) since none of the info's fields were
284     * changed:</p>
285     *
286     * <pre>BoxFile file = new File(api, id);
287     *BoxFile.Info info = file.getInfo();
288     *file.updateInfo(info);</pre>
289     *
290     * @param info the updated info.
291     */
292    public void updateInfo(BoxFile.Info info) {
293        URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
294        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
295        request.setBody(info.getPendingChanges());
296        BoxJSONResponse response = (BoxJSONResponse) request.send();
297        JsonObject jsonObject = JsonObject.readFrom(response.getJSON());
298        info.update(jsonObject);
299    }
300
301    /**
302     * Gets any previous versions of this file. Note that only users with premium accounts will be able to retrieve
303     * previous versions of their files.
304     * @return a list of previous file versions.
305     */
306    public Collection<BoxFileVersion> getVersions() {
307        URL url = VERSIONS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
308        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
309        BoxJSONResponse response = (BoxJSONResponse) request.send();
310
311        JsonObject jsonObject = JsonObject.readFrom(response.getJSON());
312        JsonArray entries = jsonObject.get("entries").asArray();
313        Collection<BoxFileVersion> versions = new ArrayList<BoxFileVersion>();
314        for (JsonValue entry : entries) {
315            versions.add(new BoxFileVersion(this.getAPI(), entry.asObject(), this.getID()));
316        }
317
318        return versions;
319    }
320
321    /**
322     * Checks if the file can be successfully uploaded by using the preflight check.
323     * @param  name        the name to give the uploaded file or null to use existing name.
324     * @param  fileSize    the size of the file used for account capacity calculations.
325     * @param  parentID    the ID of the parent folder that the new version is being uploaded to.
326     */
327    public void canUploadVersion(String name, long fileSize, String parentID) {
328        URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
329        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "OPTIONS");
330
331        JsonObject parent = new JsonObject();
332        parent.add("id", parentID);
333
334        JsonObject preflightInfo = new JsonObject();
335        preflightInfo.add("parent", parent);
336        if (name != null) {
337            preflightInfo.add("name", name);
338        }
339
340        preflightInfo.add("size", fileSize);
341
342        request.setBody(preflightInfo.toString());
343        BoxAPIResponse response = request.send();
344        response.disconnect();
345    }
346
347    /**
348     * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts
349     * will be able to view and recover previous versions of the file.
350     * @param fileContent a stream containing the new file contents.
351     */
352    public void uploadVersion(InputStream fileContent) {
353        this.uploadVersion(fileContent, null);
354    }
355
356    /**
357     * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts
358     * will be able to view and recover previous versions of the file.
359     * @param fileContent a stream containing the new file contents.
360     * @param modified    the date that the new version was modified.
361     */
362    public void uploadVersion(InputStream fileContent, Date modified) {
363        this.uploadVersion(fileContent, modified, 0, null);
364    }
365
366    /**
367     * Uploads a new version of this file, replacing the current version, while reporting the progress to a
368     * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions
369     * of the file.
370     * @param fileContent a stream containing the new file contents.
371     * @param modified    the date that the new version was modified.
372     * @param fileSize    the size of the file used for determining the progress of the upload.
373     * @param listener    a listener for monitoring the upload's progress.
374     */
375    public void uploadVersion(InputStream fileContent, Date modified, long fileSize, ProgressListener listener) {
376        URL uploadURL = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID());
377        BoxMultipartRequest request = new BoxMultipartRequest(getAPI(), uploadURL);
378        if (fileSize > 0) {
379            request.setFile(fileContent, "", fileSize);
380        } else {
381            request.setFile(fileContent, "");
382        }
383
384        if (modified != null) {
385            request.putField("content_modified_at", modified);
386        }
387
388        BoxAPIResponse response;
389        if (listener == null) {
390            response = request.send();
391        } else {
392            response = request.send(listener);
393        }
394        response.disconnect();
395    }
396
397    /**
398     * Gets a list of any comments on this file.
399     * @return a list of comments on this file.
400     */
401    public List<BoxComment.Info> getComments() {
402        URL url = GET_COMMENTS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
403        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
404        BoxJSONResponse response = (BoxJSONResponse) request.send();
405        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
406
407        int totalCount = responseJSON.get("total_count").asInt();
408        List<BoxComment.Info> comments = new ArrayList<BoxComment.Info>(totalCount);
409        JsonArray entries = responseJSON.get("entries").asArray();
410        for (JsonValue value : entries) {
411            JsonObject commentJSON = value.asObject();
412            BoxComment comment = new BoxComment(this.getAPI(), commentJSON.get("id").asString());
413            BoxComment.Info info = comment.new Info(commentJSON);
414            comments.add(info);
415        }
416
417        return comments;
418    }
419
420    /**
421     * Creates metadata on this file.
422     * @param metadata The new metadata values.
423     * @return the metadata returned from the server.
424     */
425    public Metadata createMetadata(Metadata metadata) {
426        return this.createMetadata(DEFAULT_METADATA_TYPE, metadata);
427    }
428
429    /**
430     * Creates the metadata of specified type.
431     * @param typeName the metadata type name.
432     * @param metadata the new metadata values.
433     * @return the metadata returned from the server.
434     */
435    public Metadata createMetadata(String typeName, Metadata metadata) {
436        URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), typeName);
437        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "POST");
438        request.addHeader("Content-Type", "application/json");
439        request.setBody(metadata.toString());
440        BoxJSONResponse response = (BoxJSONResponse) request.send();
441        return new Metadata(JsonObject.readFrom(response.getJSON()));
442    }
443
444    /**
445     * Gets the file properties metadata.
446     * @return the metadata returned from the server.
447     */
448    public Metadata getMetadata() {
449        return this.getMetadata(DEFAULT_METADATA_TYPE);
450    }
451
452    /**
453     * Gets the file metadata of specified type.
454     * @param typeName the metadata type name.
455     * @return the metadata returned from the server.
456     */
457    public Metadata getMetadata(String typeName) {
458        URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), typeName);
459        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
460        BoxJSONResponse response = (BoxJSONResponse) request.send();
461        return new Metadata(JsonObject.readFrom(response.getJSON()));
462    }
463
464    /**
465     * Updates the file metadata.
466     * @param metadata the new metadata values.
467     * @return the metadata returned from the server.
468     */
469    public Metadata updateMetadata(Metadata metadata) {
470        URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), metadata.getTypeName());
471        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "PUT");
472        request.addHeader("Content-Type", "application/json-patch+json");
473        request.setBody(metadata.getPatch());
474        BoxJSONResponse response = (BoxJSONResponse) request.send();
475        return new Metadata(JsonObject.readFrom(response.getJSON()));
476    }
477
478    /**
479     * Deletes the file properties metadata.
480     */
481    public void deleteMetadata() {
482        this.deleteMetadata(DEFAULT_METADATA_TYPE);
483    }
484
485    /**
486     * Deletes the file metadata of specified type.
487     * @param typeName the metadata type name.
488     */
489    public void deleteMetadata(String typeName) {
490        URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), typeName);
491        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
492        request.send();
493    }
494
495    /**
496     * Contains information about a BoxFile.
497     */
498    public class Info extends BoxItem.Info {
499        private String sha1;
500        private String versionNumber;
501        private long commentCount;
502        private EnumSet<Permission> permissions;
503        private String extension;
504        private boolean isPackage;
505        private BoxFileVersion version;
506
507        /**
508         * Constructs an empty Info object.
509         */
510        public Info() {
511            super();
512        }
513
514        /**
515         * Constructs an Info object by parsing information from a JSON string.
516         * @param  json the JSON string to parse.
517         */
518        public Info(String json) {
519            super(json);
520        }
521
522        /**
523         * Constructs an Info object using an already parsed JSON object.
524         * @param  jsonObject the parsed JSON object.
525         */
526        Info(JsonObject jsonObject) {
527            super(jsonObject);
528        }
529
530        @Override
531        public BoxFile getResource() {
532            return BoxFile.this;
533        }
534
535        /**
536         * Gets the SHA1 hash of the file.
537         * @return the SHA1 hash of the file.
538         */
539        public String getSha1() {
540            return this.sha1;
541        }
542
543        /**
544         * Gets the current version number of the file.
545         * @return the current version number of the file.
546         */
547        public String getVersionNumber() {
548            return this.versionNumber;
549        }
550
551        /**
552         * Gets the number of comments on the file.
553         * @return the number of comments on the file.
554         */
555        public long getCommentCount() {
556            return this.commentCount;
557        }
558
559        /**
560         * Gets the permissions that the current user has on the file.
561         * @return the permissions that the current user has on the file.
562         */
563        public EnumSet<Permission> getPermissions() {
564            return this.permissions;
565        }
566
567        /**
568         * Gets the extension suffix of the file, excluding the dot.
569         * @return the extension of the file.
570         */
571        public String getExtension() {
572            return this.extension;
573        }
574
575        /**
576         * Gets whether or not the file is an OSX package.
577         * @return true if the file is an OSX package; otherwise false.
578         */
579        public boolean getIsPackage() {
580            return this.isPackage;
581        }
582
583        /**
584         * Gets the current version details of the file.
585         * @return the current version details of the file.
586         */
587        public BoxFileVersion getVersion() {
588            return this.version;
589        }
590
591        @Override
592        protected void parseJSONMember(JsonObject.Member member) {
593            super.parseJSONMember(member);
594
595            String memberName = member.getName();
596            JsonValue value = member.getValue();
597            if (memberName.equals("sha1")) {
598                this.sha1 = value.asString();
599            } else if (memberName.equals("version_number")) {
600                this.versionNumber = value.asString();
601            } else if (memberName.equals("comment_count")) {
602                this.commentCount = value.asLong();
603            } else if (memberName.equals("permissions")) {
604                this.permissions = this.parsePermissions(value.asObject());
605            } else if (memberName.equals("extension")) {
606                this.extension = value.asString();
607            } else if (memberName.equals("is_package")) {
608                this.isPackage = value.asBoolean();
609            } else if (memberName.equals("file_version")) {
610                this.version = this.parseFileVersion(value.asObject());
611            }
612        }
613
614        private EnumSet<Permission> parsePermissions(JsonObject jsonObject) {
615            EnumSet<Permission> permissions = EnumSet.noneOf(Permission.class);
616            for (JsonObject.Member member : jsonObject) {
617                JsonValue value = member.getValue();
618                if (value.isNull() || !value.asBoolean()) {
619                    continue;
620                }
621
622                String memberName = member.getName();
623                if (memberName.equals("can_download")) {
624                    permissions.add(Permission.CAN_DOWNLOAD);
625                } else if (memberName.equals("can_upload")) {
626                    permissions.add(Permission.CAN_UPLOAD);
627                } else if (memberName.equals("can_rename")) {
628                    permissions.add(Permission.CAN_RENAME);
629                } else if (memberName.equals("can_delete")) {
630                    permissions.add(Permission.CAN_DELETE);
631                } else if (memberName.equals("can_share")) {
632                    permissions.add(Permission.CAN_SHARE);
633                } else if (memberName.equals("can_set_share_access")) {
634                    permissions.add(Permission.CAN_SET_SHARE_ACCESS);
635                } else if (memberName.equals("can_preview")) {
636                    permissions.add(Permission.CAN_PREVIEW);
637                } else if (memberName.equals("can_comment")) {
638                    permissions.add(Permission.CAN_COMMENT);
639                }
640            }
641
642            return permissions;
643        }
644
645        private BoxFileVersion parseFileVersion(JsonObject jsonObject) {
646            return new BoxFileVersion(BoxFile.this.getAPI(), jsonObject, BoxFile.this.getID());
647        }
648    }
649
650    /**
651     * Enumerates the possible permissions that a user can have on a file.
652     */
653    public enum Permission {
654        /**
655         * The user can download the file.
656         */
657        CAN_DOWNLOAD ("can_download"),
658
659        /**
660         * The user can upload new versions of the file.
661         */
662        CAN_UPLOAD ("can_upload"),
663
664        /**
665         * The user can rename the file.
666         */
667        CAN_RENAME ("can_rename"),
668
669        /**
670         * The user can delete the file.
671         */
672        CAN_DELETE ("can_delete"),
673
674        /**
675         * The user can share the file.
676         */
677        CAN_SHARE ("can_share"),
678
679        /**
680         * The user can set the access level for shared links to the file.
681         */
682        CAN_SET_SHARE_ACCESS ("can_set_share_access"),
683
684        /**
685         * The user can preview the file.
686         */
687        CAN_PREVIEW ("can_preview"),
688
689        /**
690         * The user can comment on the file.
691         */
692        CAN_COMMENT ("can_comment");
693
694        private final String jsonValue;
695
696        private Permission(String jsonValue) {
697            this.jsonValue = jsonValue;
698        }
699
700        static Permission fromJSONValue(String jsonValue) {
701            return Permission.valueOf(jsonValue.toUpperCase());
702        }
703
704        String toJSONValue() {
705            return this.jsonValue;
706        }
707    }
708}