001package com.box.sdk;
002
003import java.net.URL;
004import java.util.ArrayList;
005import java.util.Date;
006import java.util.Iterator;
007import java.util.List;
008
009import com.eclipsesource.json.JsonArray;
010import com.eclipsesource.json.JsonObject;
011import com.eclipsesource.json.JsonValue;
012
013/**
014 * Represents a task on Box. Tasks can have a due date and can be assigned to a specific user.
015 */
016@BoxResourceType("task")
017public class BoxTask extends BoxResource {
018
019    /**
020     * Task URL Template.
021     */
022    public static final URLTemplate TASK_URL_TEMPLATE = new URLTemplate("tasks/%s");
023    /**
024     * Get Assignments URL Template.
025     */
026    public static final URLTemplate GET_ASSIGNMENTS_URL_TEMPLATE = new URLTemplate("tasks/%s/assignments");
027    /**
028     * Add Task Assignment URL Template.
029     */
030    public static final URLTemplate ADD_TASK_ASSIGNMENT_URL_TEMPLATE = new URLTemplate("task_assignments");
031
032    /**
033     * Constructs a BoxTask for a task with a given ID.
034     * @param  api the API connection to be used by the task.
035     * @param  id  the ID of the task.
036     */
037    public BoxTask(BoxAPIConnection api, String id) {
038        super(api, id);
039    }
040
041    /**
042     * Deletes this task.
043     */
044    public void delete() {
045        URL url = TASK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
046        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
047        BoxAPIResponse response = request.send();
048        response.disconnect();
049    }
050
051    /**
052     * Adds a new assignment to this task.
053     * @param assignTo the user to assign the assignment to.
054     * @return information about the newly added task assignment.
055     */
056    public BoxTaskAssignment.Info addAssignment(BoxUser assignTo) {
057        JsonObject taskJSON = new JsonObject();
058        taskJSON.add("type", "task");
059        taskJSON.add("id", this.getID());
060
061        JsonObject assignToJSON = new JsonObject();
062        assignToJSON.add("id", assignTo.getID());
063
064        JsonObject requestJSON = new JsonObject();
065        requestJSON.add("task", taskJSON);
066        requestJSON.add("assign_to", assignToJSON);
067
068        URL url = ADD_TASK_ASSIGNMENT_URL_TEMPLATE.build(this.getAPI().getBaseURL());
069        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
070        request.setBody(requestJSON.toString());
071        BoxJSONResponse response = (BoxJSONResponse) request.send();
072        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
073
074        BoxTaskAssignment addedAssignment = new BoxTaskAssignment(this.getAPI(), responseJSON.get("id").asString());
075        return addedAssignment.new Info(responseJSON);
076    }
077
078    /**
079     * Adds a new assignment to this task using user's login as identifier.
080     * @param assignToLogin the login of user to assign the task to.
081     * @return information about the newly added task assignment.
082     */
083    public BoxTaskAssignment.Info addAssignmentByLogin(String assignToLogin) {
084        JsonObject taskJSON = new JsonObject();
085        taskJSON.add("type", "task");
086        taskJSON.add("id", this.getID());
087
088        JsonObject assignToJSON = new JsonObject();
089        assignToJSON.add("login", assignToLogin);
090
091        JsonObject requestJSON = new JsonObject();
092        requestJSON.add("task", taskJSON);
093        requestJSON.add("assign_to", assignToJSON);
094
095        URL url = ADD_TASK_ASSIGNMENT_URL_TEMPLATE.build(this.getAPI().getBaseURL());
096        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
097        request.setBody(requestJSON.toString());
098        BoxJSONResponse response = (BoxJSONResponse) request.send();
099        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
100
101        BoxTaskAssignment addedAssignment = new BoxTaskAssignment(this.getAPI(), responseJSON.get("id").asString());
102        return addedAssignment.new Info(responseJSON);
103    }
104
105    /**
106     * Gets any assignments for this task.
107     * @return a list of assignments for this task.
108     */
109    public List<BoxTaskAssignment.Info> getAssignments() {
110        URL url = GET_ASSIGNMENTS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
111        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
112        BoxJSONResponse response = (BoxJSONResponse) request.send();
113        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
114
115        int totalCount = responseJSON.get("total_count").asInt();
116        List<BoxTaskAssignment.Info> assignments = new ArrayList<BoxTaskAssignment.Info>(totalCount);
117        JsonArray entries = responseJSON.get("entries").asArray();
118        for (JsonValue value : entries) {
119            JsonObject assignmentJSON = value.asObject();
120            BoxTaskAssignment assignment = new BoxTaskAssignment(this.getAPI(), assignmentJSON.get("id").asString());
121            BoxTaskAssignment.Info info = assignment.new Info(assignmentJSON);
122            assignments.add(info);
123        }
124
125        return assignments;
126    }
127
128    /**
129     * Gets an iterable of all the assignments of this task.
130     * @param fields the fields to retrieve.
131     * @return     an iterable containing info about all the assignments.
132     */
133    public Iterable<BoxTaskAssignment.Info> getAllAssignments(String ... fields) {
134        final QueryStringBuilder builder = new QueryStringBuilder();
135        if (fields.length > 0) {
136            builder.appendParam("fields", fields);
137        }
138        return new Iterable<BoxTaskAssignment.Info>() {
139            public Iterator<BoxTaskAssignment.Info> iterator() {
140                URL url = GET_ASSIGNMENTS_URL_TEMPLATE.buildWithQuery(
141                        BoxTask.this.getAPI().getBaseURL(), builder.toString(), BoxTask.this.getID());
142                return new BoxTaskAssignmentIterator(BoxTask.this.getAPI(), url);
143            }
144        };
145    }
146
147    /**
148     * Gets information about this task.
149     * @return info about this task.
150     */
151    public Info getInfo() {
152        URL url = TASK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
153        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
154        BoxJSONResponse response = (BoxJSONResponse) request.send();
155        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
156        return new Info(responseJSON);
157    }
158
159    /**
160     * Gets information about this task.
161     * @param fields the fields to retrieve.
162     * @return info about this task.
163     */
164    public Info getInfo(String... fields) {
165        QueryStringBuilder builder = new QueryStringBuilder();
166        if (fields.length > 0) {
167            builder.appendParam("fields", fields);
168        }
169        URL url = TASK_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), builder.toString(), this.getID());
170        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
171        BoxJSONResponse response = (BoxJSONResponse) request.send();
172        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
173        return new Info(responseJSON);
174    }
175
176    /**
177     * Updates the information about this task with any info fields that have been modified locally.
178     *
179     * <p>The only fields that will be updated are the ones that have been modified locally. For example, the following
180     * code won't update any information (or even send a network request) since none of the info's fields were
181     * changed:</p>
182     *
183     * <pre>BoxTask task = new BoxTask(api, id);
184     *BoxTask.Info info = task.getInfo();
185     *task.updateInfo(info);</pre>
186     *
187     * @param info the updated info.
188     */
189    public void updateInfo(BoxTask.Info info) {
190        URL url = TASK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
191        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
192        request.setBody(info.getPendingChanges());
193        BoxJSONResponse response = (BoxJSONResponse) request.send();
194        JsonObject jsonObject = JsonObject.readFrom(response.getJSON());
195        info.update(jsonObject);
196    }
197
198    /**
199     * Contains information about a BoxTask.
200     */
201    public class Info extends BoxResource.Info {
202        private BoxFile.Info item;
203        private Date dueAt;
204        private String action;
205        private String completionRule;
206        private String message;
207        private List<BoxTaskAssignment.Info> taskAssignments;
208        private boolean completed;
209        private BoxUser.Info createdBy;
210        private Date createdAt;
211
212        /**
213         * Constructs an empty Info object.
214         */
215        public Info() {
216            super();
217        }
218
219        /**
220         * Constructs an Info object by parsing information from a JSON string.
221         * @param  json the JSON string to parse.
222         */
223        public Info(String json) {
224            super(json);
225        }
226
227        /**
228         * Constructs an Info object using an already parsed JSON object.
229         * @param  jsonObject the parsed JSON object.
230         */
231        Info(JsonObject jsonObject) {
232            super(jsonObject);
233        }
234
235        @Override
236        public BoxTask getResource() {
237            return BoxTask.this;
238        }
239
240        /**
241         * Gets the file associated with this task.
242         * @return the file associated with this task.
243         */
244        public BoxFile.Info getItem() {
245            return this.item;
246        }
247
248        /**
249         * Gets the date at which this task is due.
250         * @return the date at which this task is due.
251         */
252        public Date getDueAt() {
253            return this.dueAt;
254        }
255
256        /**
257         * Sets the task's due date.
258         * @param dueAt the task's due date.
259         */
260        public void setDueAt(Date dueAt) {
261            this.dueAt = dueAt;
262            this.addPendingChange("due_at", BoxDateFormat.format(dueAt));
263        }
264
265        /**
266         * @deprecated
267         * Please use getTaskType()
268         *
269         * Gets the action the task assignee will be prompted to do.
270         * @return the action the task assignee will be prompted to do.
271         */
272        @Deprecated
273        public Action getAction() {
274            return Action.REVIEW;
275        }
276
277        /**
278         * Gets the action the task assignee will be prompted to do.
279         * @return the action the task assignee will be prompted to do.
280         */
281        public String getTaskType() {
282            return this.action;
283        }
284
285        /**
286         * Returns the completion rule for the task.
287         * @return the task completion rule.
288         */
289        public String getCompletionRule() {
290            return this.completionRule;
291        }
292
293        /**
294         * Sets the task's completion rule.
295         * @param completionRule the new completion rule.
296         */
297        public void setCompletionRule(CompletionRule completionRule) {
298            this.completionRule = completionRule.toJSONString();
299            this.addPendingChange("completion_rule", completionRule.toJSONString());
300        }
301
302        /**
303         * Gets the message that will be included with this task.
304         * @return the message that will be included with this task.
305         */
306        public String getMessage() {
307            return this.message;
308        }
309
310        /**
311         * Sets the task's message.
312         * @param message the task's new message.
313         */
314        public void setMessage(String message) {
315            this.message = message;
316            this.addPendingChange("message", message);
317        }
318
319        /**
320         * Gets the collection of task assignments associated with this task.
321         * @return the collection of task assignments associated with this task.
322         */
323        public List<BoxTaskAssignment.Info> getTaskAssignments() {
324            return this.taskAssignments;
325        }
326
327        /**
328         * Gets whether or not this task has been completed.
329         * @return whether or not this task has been completed.
330         */
331        public boolean isCompleted() {
332            return this.completed;
333        }
334
335        /**
336         * Gets the user who created this task.
337         * @return the user who created this task.
338         */
339        public BoxUser.Info getCreatedBy() {
340            return this.createdBy;
341        }
342
343        /**
344         * Gets when this task was created.
345         * @return when this task was created.
346         */
347        public Date getCreatedAt() {
348            return this.createdAt;
349        }
350
351        @Override
352        void parseJSONMember(JsonObject.Member member) {
353            super.parseJSONMember(member);
354
355            String memberName = member.getName();
356            JsonValue value = member.getValue();
357            try {
358                if (memberName.equals("item")) {
359                    JsonObject itemJSON = value.asObject();
360                    String itemID = itemJSON.get("id").asString();
361                    BoxFile file = new BoxFile(getAPI(), itemID);
362                    this.item = file.new Info(itemJSON);
363                } else if (memberName.equals("due_at")) {
364                    this.dueAt = BoxDateFormat.parse(value.asString());
365                } else if (memberName.equals("action")) {
366                    this.action = value.asString();
367                } else if (memberName.equals("completion_rule")) {
368                    this.completionRule = value.asString();
369                } else if (memberName.equals("message")) {
370                    this.message = value.asString();
371                } else if (memberName.equals("task_assignment_collection")) {
372                    this.taskAssignments = this.parseTaskAssignmentCollection(value.asObject());
373                } else if (memberName.equals("is_completed")) {
374                    this.completed = value.asBoolean();
375                } else if (memberName.equals("created_by")) {
376                    JsonObject userJSON = value.asObject();
377                    String userID = userJSON.get("id").asString();
378                    BoxUser user = new BoxUser(getAPI(), userID);
379                    this.createdBy = user.new Info(userJSON);
380                } else if (memberName.equals("created_at")) {
381                    this.createdAt = BoxDateFormat.parse(value.asString());
382                }
383
384            } catch (Exception e) {
385                throw new BoxDeserializationException(memberName, value.toString(), e);
386            }
387        }
388
389        private List<BoxTaskAssignment.Info> parseTaskAssignmentCollection(JsonObject jsonObject) {
390            int count = jsonObject.get("total_count").asInt();
391            List<BoxTaskAssignment.Info> taskAssignmentCollection = new ArrayList<BoxTaskAssignment.Info>(count);
392            JsonArray entries = jsonObject.get("entries").asArray();
393            for (JsonValue value : entries) {
394                JsonObject entry = value.asObject();
395                String id = entry.get("id").asString();
396                BoxTaskAssignment assignment = new BoxTaskAssignment(getAPI(), id);
397                taskAssignmentCollection.add(assignment.new Info(entry));
398            }
399
400            return taskAssignmentCollection;
401        }
402    }
403
404    /**
405     * Enumerates the possible actions that a task can have.
406     */
407    public enum Action {
408        /**
409         * The task must be reviewed.
410         */
411        REVIEW ("review"),
412
413        /**
414         * The task must be completed.
415         */
416        COMPLETE ("complete");
417
418        private final String jsonValue;
419
420        private Action(String jsonValue) {
421            this.jsonValue = jsonValue;
422        }
423
424        static Action fromJSONString(String jsonValue) {
425            if (jsonValue.equals("review")) {
426                return REVIEW;
427            } else if (jsonValue.equals("complete")) {
428                return COMPLETE;
429            } else {
430                throw new IllegalArgumentException("The provided JSON value isn't a valid Action.");
431            }
432        }
433
434        String toJSONString() {
435            return this.jsonValue;
436        }
437    }
438
439    /**
440     * Enumerates the possible completion rules for a task.
441     */
442    public enum CompletionRule {
443
444        /**
445         * The task must be completed by all assignees.
446         */
447        ALL_ASSIGNEES ("all_assignees"),
448
449        /**
450         * The task must be completed by at least one assignee.
451         */
452        ANY_ASSIGNEE ("any_assignee");
453
454        private final String jsonValue;
455
456        private CompletionRule(String jsonValue) {
457            this.jsonValue = jsonValue;
458        }
459
460        String toJSONString() {
461            return this.jsonValue;
462        }
463    }
464}