001package com.box.sdk;
002
003import java.net.URL;
004import java.text.ParseException;
005import java.util.ArrayList;
006import java.util.Collection;
007import java.util.Date;
008
009import com.eclipsesource.json.JsonArray;
010import com.eclipsesource.json.JsonObject;
011import com.eclipsesource.json.JsonValue;
012
013/**
014 * Represents a collaboration between a user and another user or group. Collaborations are Box's equivalent of access
015 * control lists. They can be used to set and apply permissions for users or groups to folders.
016 */
017public class BoxCollaboration extends BoxResource {
018    private static final URLTemplate COLLABORATIONS_URL_TEMPLATE = new URLTemplate("collaborations");
019    private static final URLTemplate PENDING_COLLABORATIONS_URL = new URLTemplate("collaborations?status=pending");
020    private static final URLTemplate COLLABORATION_URL_TEMPLATE = new URLTemplate("collaborations/%s");
021
022    /**
023     * Constructs a BoxCollaboration for a collaboration with a given ID.
024     * @param  api the API connection to be used by the collaboration.
025     * @param  id  the ID of the collaboration.
026     */
027    public BoxCollaboration(BoxAPIConnection api, String id) {
028        super(api, id);
029    }
030
031    /**
032     * Gets all pending collaboration invites for the current user.
033     * @param  api the API connection to use.
034     * @return     a collection of pending collaboration infos.
035     */
036    public static Collection<Info> getPendingCollaborations(BoxAPIConnection api) {
037        URL url = PENDING_COLLABORATIONS_URL.build(api.getBaseURL());
038
039        BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
040        BoxJSONResponse response = (BoxJSONResponse) request.send();
041        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
042
043        int entriesCount = responseJSON.get("total_count").asInt();
044        Collection<BoxCollaboration.Info> collaborations = new ArrayList<BoxCollaboration.Info>(entriesCount);
045        JsonArray entries = responseJSON.get("entries").asArray();
046        for (JsonValue entry : entries) {
047            JsonObject entryObject = entry.asObject();
048            BoxCollaboration collaboration = new BoxCollaboration(api, entryObject.get("id").asString());
049            BoxCollaboration.Info info = collaboration.new Info(entryObject);
050            collaborations.add(info);
051        }
052
053        return collaborations;
054    }
055
056    /**
057     * Gets information about this collaboration.
058     * @return info about this collaboration.
059     */
060    public Info getInfo() {
061        BoxAPIConnection api = this.getAPI();
062        URL url = COLLABORATIONS_URL_TEMPLATE.build(api.getBaseURL());
063
064        BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
065        BoxJSONResponse response = (BoxJSONResponse) request.send();
066        JsonObject jsonObject = JsonObject.readFrom(response.getJSON());
067        return new Info(jsonObject);
068    }
069
070    /**
071     * Updates the information about this collaboration with any info fields that have been modified locally.
072     * @param info the updated info.
073     */
074    public void updateInfo(Info info) {
075        BoxAPIConnection api = this.getAPI();
076        URL url = COLLABORATION_URL_TEMPLATE.build(api.getBaseURL(), this.getID());
077
078        BoxJSONRequest request = new BoxJSONRequest(api, url, "PUT");
079        request.setBody(info.getPendingChanges());
080        BoxJSONResponse response = (BoxJSONResponse) request.send();
081        JsonObject jsonObject = JsonObject.readFrom(response.getJSON());
082        info.update(jsonObject);
083    }
084
085    /**
086     * Deletes this collaboration.
087     */
088    public void delete() {
089        BoxAPIConnection api = this.getAPI();
090        URL url = COLLABORATION_URL_TEMPLATE.build(api.getBaseURL(), this.getID());
091
092        BoxAPIRequest request = new BoxAPIRequest(api, url, "DELETE");
093        BoxAPIResponse response = request.send();
094        response.disconnect();
095    }
096
097    /**
098     * Contains information about a BoxCollaboration.
099     */
100    public class Info extends BoxResource.Info {
101        private BoxUser.Info createdBy;
102        private Date createdAt;
103        private Date modifiedAt;
104        private Date expiresAt;
105        private Status status;
106        private BoxCollaborator.Info accessibleBy;
107        private Role role;
108        private Date acknowledgedAt;
109        private BoxFolder.Info item;
110
111        /**
112         * Constructs an empty Info object.
113         */
114        public Info() {
115            super();
116        }
117
118        /**
119         * Constructs an Info object by parsing information from a JSON string.
120         * @param  json the JSON string to parse.
121         */
122        public Info(String json) {
123            super(json);
124        }
125
126        Info(JsonObject jsonObject) {
127            super(jsonObject);
128        }
129
130        /**
131         * Gets the user who created the collaboration.
132         * @return the user who created the collaboration.
133         */
134        public BoxUser.Info getCreatedBy() {
135            return this.createdBy;
136        }
137
138        /**
139         * Gets the time the collaboration was created.
140         * @return the time the collaboration was created.
141         */
142        public Date getCreatedAt() {
143            return this.createdAt;
144        }
145
146        /**
147         * Gets the time the collaboration was last modified.
148         * @return the time the collaboration was last modified.
149         */
150        public Date getModifiedAt() {
151            return this.modifiedAt;
152        }
153
154        /**
155         * Gets the time the collaboration will expire.
156         * @return the time the collaboration will expire.
157         */
158        public Date getExpiresAt() {
159            return this.expiresAt;
160        }
161
162        /**
163         * Gets the status of the collaboration.
164         * @return the status of the collaboration.
165         */
166        public Status getStatus() {
167            return this.status;
168        }
169
170        /**
171         * Sets the status of the collaboration in order to accept or reject the collaboration if it's pending.
172         * @param status the new status of the collaboration.
173         */
174        public void setStatus(Status status) {
175            this.status = status;
176            this.addPendingChange("status", status.name().toLowerCase());
177        }
178
179        /**
180         * Gets the collaborator who this collaboration applies to.
181         * @return the collaborator who this collaboration applies to.
182         */
183        public BoxCollaborator.Info getAccessibleBy() {
184            return this.accessibleBy;
185        }
186
187        /**
188         * Gets the level of access the collaborator has.
189         * @return the level of access the collaborator has.
190         */
191        public Role getRole() {
192            return this.role;
193        }
194
195        /**
196         * Sets the level of access the collaborator has.
197         * @param role the new level of access to give the collaborator.
198         */
199        public void setRole(Role role) {
200            this.role = role;
201            this.addPendingChange("role", role.toJSONString());
202        }
203
204        /**
205         * Gets the time the collaboration's status was changed.
206         * @return the time the collaboration's status was changed.
207         */
208        public Date getAcknowledgedAt() {
209            return this.acknowledgedAt;
210        }
211
212        /**
213         * Gets the folder the collaboration is related to.
214         * @return the folder the collaboration is related to.
215         */
216        public BoxFolder.Info getItem() {
217            return this.item;
218        }
219
220        @Override
221        public BoxCollaboration getResource() {
222            return BoxCollaboration.this;
223        }
224
225        @Override
226        protected void parseJSONMember(JsonObject.Member member) {
227            super.parseJSONMember(member);
228
229            String memberName = member.getName();
230            JsonValue value = member.getValue();
231            try {
232                switch (memberName) {
233                    case "created_by":
234                        JsonObject userJSON = value.asObject();
235                        if (this.createdBy == null) {
236                            String userID = userJSON.get("id").asString();
237                            BoxUser user = new BoxUser(getAPI(), userID);
238                            this.createdBy = user.new Info(userJSON);
239                        } else {
240                            this.createdBy.update(userJSON);
241                        }
242                        break;
243                    case "created_at":
244                        this.createdAt = BoxDateFormat.parse(value.asString());
245                        break;
246                    case "modified_at":
247                        this.modifiedAt = BoxDateFormat.parse(value.asString());
248                        break;
249                    case "expires_at":
250                        this.expiresAt = BoxDateFormat.parse(value.asString());
251                        break;
252                    case "status":
253                        String statusString = value.asString().toUpperCase();
254                        this.status = Status.valueOf(statusString);
255                        break;
256                    case "accessible_by":
257                        userJSON = value.asObject();
258                        if (this.accessibleBy == null) {
259                            String userID = userJSON.get("id").asString();
260                            BoxUser user = new BoxUser(getAPI(), userID);
261                            BoxUser.Info userInfo = user.new Info(userJSON);
262                            this.accessibleBy = userInfo;
263                        } else {
264                            this.accessibleBy.update(userJSON);
265                        }
266                        break;
267                    case "role":
268                        this.role = Role.fromJSONString(value.asString());
269                        break;
270                    case "acknowledged_at":
271                        this.acknowledgedAt = BoxDateFormat.parse(value.asString());
272                        break;
273                    case "item":
274                        JsonObject folderJSON = value.asObject();
275                        if (this.item == null) {
276                            String folderID = folderJSON.get("id").asString();
277                            BoxFolder folder = new BoxFolder(getAPI(), folderID);
278                            this.item = folder.new Info(folderJSON);
279                        } else {
280                            this.item.update(folderJSON);
281                        }
282                        break;
283                    default:
284                        break;
285                }
286            } catch (ParseException e) {
287                assert false : "A ParseException indicates a bug in the SDK.";
288            }
289        }
290    }
291
292    /**
293     * Enumerates the possible statuses that a collaboration can have.
294     */
295    public enum Status {
296        /**
297         * The collaboration has been accepted.
298         */
299        ACCEPTED,
300
301        /**
302         * The collaboration is waiting to be accepted or rejected.
303         */
304        PENDING,
305
306        /**
307         * The collaboration has been rejected.
308         */
309        REJECTED;
310    }
311
312    /**
313     * Enumerates the possible access levels that a collaborator can have.
314     */
315    public enum Role {
316        /**
317         * An Editor has full read/write access to a folder. Once invited to a folder, they will be able to view,
318         * download, upload, edit, delete, copy, move, rename, generate shared links, make comments, assign tasks,
319         * create tags, and invite/remove collaborators. They will not be able to delete or move root level folders.
320         */
321        EDITOR ("editor"),
322
323        /**
324         * The viewer role has full read access to a folder. Once invited to a folder, they will be able to preview,
325         * download, make comments, and generate shared links.  They will not be able to add tags, invite new
326         * collaborators, upload, edit, or delete items in the folder.
327         */
328        VIEWER ("viewer"),
329
330        /**
331         * The previewer role has limited read access to a folder. They will only be able to preview the items in the
332         * folder using the integrated content viewer. They will not be able to share, upload, edit, or delete any
333         * content. This role is only available to enterprise accounts.
334         */
335        PREVIEWER ("previewer"),
336
337        /**
338         * The uploader has limited write access to a folder. They will only be able to upload and see the names of the
339         * items in a folder. They will not able to download or view any content. This role is only available to
340         * enterprise accounts.
341         */
342        UPLOADER ("uploader"),
343
344        /**
345         * The previewer-uploader role is a combination of previewer and uploader. A user with this access level will be
346         * able to preview files using the integrated content viewer as well as upload items into the folder. They will
347         * not be able to download, edit, or share, items in the folder. This role is only available to enterprise
348         * accounts.
349         */
350        PREVIEWER_UPLOADER ("previewer uploader"),
351
352        /**
353         * The viewer-uploader role is a combination of viewer and uploader. A viewer-uploader has full read access to a
354         * folder and limited write access. They are able to preview, download, add comments, generate shared links, and
355         * upload content to the folder. They will not be able to add tags, invite new collaborators, edit, or delete
356         * items in the folder. This role is only available to enterprise accounts.
357         */
358        VIEWER_UPLOADER ("viewer uploader"),
359
360        /**
361         * The co-owner role has all of the functional read/write access that an editor does. This permission level has
362         * the added ability of being able to manage users in the folder. A co-owner can add new collaborators, change
363         * access levels of existing collaborators, and remove collaborators. However, they will not be able to
364         * manipulate the owner of the folder or transfer ownership to another user. This role is only available to
365         * enterprise accounts.
366         */
367        CO_OWNER ("co-owner"),
368
369        /**
370         * The owner role has all of the functional capabilities of a co-owner. However, they will be able to manipulate
371         * the owner of the folder or transfer ownership to another user. This role is only available to enterprise
372         * accounts.
373         */
374        OWNER ("owner");
375
376        private final String jsonValue;
377
378        private Role(String jsonValue) {
379            this.jsonValue = jsonValue;
380        }
381
382        static Role fromJSONString(String jsonValue) {
383            switch (jsonValue) {
384                case "editor":
385                    return EDITOR;
386                case "viewer":
387                    return VIEWER;
388                case "previewer":
389                    return PREVIEWER;
390                case "uploader":
391                    return UPLOADER;
392                case "previewer uploader":
393                    return PREVIEWER_UPLOADER;
394                case "viewer uploader":
395                    return VIEWER_UPLOADER;
396                case "co-owner":
397                    return CO_OWNER;
398                case "owner":
399                    return OWNER;
400                default:
401                    throw new IllegalArgumentException("The provided JSON value isn't a valid Role.");
402            }
403        }
404
405        String toJSONString() {
406            return this.jsonValue;
407        }
408    }
409}