001package com.box.sdk;
002
003import java.net.URL;
004import java.text.ParseException;
005import java.util.ArrayList;
006import java.util.Date;
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 */
016public class BoxTask extends BoxResource {
017
018    private static final URLTemplate TASK_URL_TEMPLATE = new URLTemplate("tasks/%s");
019    private static final URLTemplate GET_ASSIGNMENTS_URL_TEMPLATE = new URLTemplate("tasks/%s/assignments");
020    private static final URLTemplate ADD_TASK_ASSIGNMENT_URL_TEMPLATE = new URLTemplate("task_assignments");
021
022    /**
023     * Constructs a BoxTask for a task with a given ID.
024     * @param  api the API connection to be used by the task.
025     * @param  id  the ID of the task.
026     */
027    public BoxTask(BoxAPIConnection api, String id) {
028        super(api, id);
029    }
030
031    /**
032     * Deletes this task.
033     */
034    public void delete() {
035        URL url = TASK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
036        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
037        BoxAPIResponse response = request.send();
038        response.disconnect();
039    }
040
041    /**
042     * Adds a new assignment to this task.
043     * @param assignTo the user to assign the assignment to.
044     * @return information about the newly added task assignment.
045     */
046    public BoxTaskAssignment.Info addAssignment(BoxUser assignTo) {
047        JsonObject taskJSON = new JsonObject();
048        taskJSON.add("type", "task");
049        taskJSON.add("id", this.getID());
050
051        JsonObject assignToJSON = new JsonObject();
052        assignToJSON.add("id", assignTo.getID());
053
054        JsonObject requestJSON = new JsonObject();
055        requestJSON.add("task", taskJSON);
056        requestJSON.add("assign_to", assignToJSON);
057
058        URL url = ADD_TASK_ASSIGNMENT_URL_TEMPLATE.build(this.getAPI().getBaseURL());
059        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
060        request.setBody(requestJSON.toString());
061        BoxJSONResponse response = (BoxJSONResponse) request.send();
062        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
063
064        BoxTaskAssignment addedAssignment = new BoxTaskAssignment(this.getAPI(), responseJSON.get("id").asString());
065        return addedAssignment.new Info(responseJSON);
066    }
067
068    /**
069     * Gets any assignments for this task.
070     * @return a list of assignments for this task.
071     */
072    public List<BoxTaskAssignment.Info> getAssignments() {
073        URL url = GET_ASSIGNMENTS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
074        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
075        BoxJSONResponse response = (BoxJSONResponse) request.send();
076        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
077
078        int totalCount = responseJSON.get("total_count").asInt();
079        List<BoxTaskAssignment.Info> assignments = new ArrayList<BoxTaskAssignment.Info>(totalCount);
080        JsonArray entries = responseJSON.get("entries").asArray();
081        for (JsonValue value : entries) {
082            JsonObject assignmentJSON = value.asObject();
083            BoxTaskAssignment assignment = new BoxTaskAssignment(this.getAPI(), assignmentJSON.get("id").asString());
084            BoxTaskAssignment.Info info = assignment.new Info(assignmentJSON);
085            assignments.add(info);
086        }
087
088        return assignments;
089    }
090
091    /**
092     * Gets information about this task.
093     * @return info about this task.
094     */
095    public Info getInfo() {
096        URL url = TASK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
097        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
098        BoxJSONResponse response = (BoxJSONResponse) request.send();
099        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
100        return new Info(responseJSON);
101    }
102
103    /**
104     * Updates the information about this task with any info fields that have been modified locally.
105     *
106     * <p>The only fields that will be updated are the ones that have been modified locally. For example, the following
107     * code won't update any information (or even send a network request) since none of the info's fields were
108     * changed:</p>
109     *
110     * <pre>BoxTask task = new BoxTask(api, id);
111     *BoxTask.Info info = task.getInfo();
112     *task.updateInfo(info);</pre>
113     *
114     * @param info the updated info.
115     */
116    public void updateInfo(BoxTask.Info info) {
117        URL url = TASK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
118        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
119        request.setBody(info.getPendingChanges());
120        BoxJSONResponse response = (BoxJSONResponse) request.send();
121        JsonObject jsonObject = JsonObject.readFrom(response.getJSON());
122        info.update(jsonObject);
123    }
124
125    /**
126     * Contains information about a BoxTask.
127     */
128    public class Info extends BoxResource.Info {
129        private BoxFile.Info item;
130        private Date dueAt;
131        private Action action;
132        private String message;
133        private List<BoxTaskAssignment.Info> taskAssignments;
134        private boolean completed;
135        private BoxUser.Info createdBy;
136        private Date createdAt;
137
138        /**
139         * Constructs an empty Info object.
140         */
141        public Info() {
142            super();
143        }
144
145        /**
146         * Constructs an Info object by parsing information from a JSON string.
147         * @param  json the JSON string to parse.
148         */
149        public Info(String json) {
150            super(json);
151        }
152
153        /**
154         * Constructs an Info object using an already parsed JSON object.
155         * @param  jsonObject the parsed JSON object.
156         */
157        Info(JsonObject jsonObject) {
158            super(jsonObject);
159        }
160
161        @Override
162        public BoxResource getResource() {
163            return BoxTask.this;
164        }
165
166        /**
167         * Gets the file associated with this task.
168         * @return the file associated with this task.
169         */
170        public BoxFile.Info getItem() {
171            return this.item;
172        }
173
174        /**
175         * Gets the date at which this task is due.
176         * @return the date at which this task is due.
177         */
178        public Date getDueAt() {
179            return this.dueAt;
180        }
181
182        /**
183         * Gets the action the task assignee will be prompted to do.
184         * @return the action the task assignee will be prompted to do.
185         */
186        public Action getAction() {
187            return this.action;
188        }
189
190        /**
191         * Gets the message that will be included with this task.
192         * @return the message that will be included with this task.
193         */
194        public String getMessage() {
195            return this.message;
196        }
197
198        /**
199         * Gets the collection of task assignments associated with this task.
200         * @return the collection of task assignments associated with this task.
201         */
202        public List<BoxTaskAssignment.Info> getTaskAssignments() {
203            return this.taskAssignments;
204        }
205
206        /**
207         * Gets whether or not this task has been completed.
208         * @return whether or not this task has been completed.
209         */
210        public boolean isCompleted() {
211            return this.completed;
212        }
213
214        /**
215         * Gets the user who created this task.
216         * @return the user who created this task.
217         */
218        public BoxUser.Info getCreatedBy() {
219            return this.createdBy;
220        }
221
222        /**
223         * Gets when this task was created.
224         * @return when this task was created.
225         */
226        public Date getCreatedAt() {
227            return this.createdAt;
228        }
229
230        @Override
231        void parseJSONMember(JsonObject.Member member) {
232            super.parseJSONMember(member);
233
234            String memberName = member.getName();
235            JsonValue value = member.getValue();
236            try {
237                if (memberName.equals("item")) {
238                    JsonObject itemJSON = value.asObject();
239                    String itemID = itemJSON.get("id").asString();
240                    BoxFile file = new BoxFile(getAPI(), itemID);
241                    this.item = file.new Info(itemJSON);
242                } else if (memberName.equals("due_at")) {
243                    this.dueAt = BoxDateFormat.parse(value.asString());
244                } else if (memberName.equals("action")) {
245                    this.action = Action.fromJSONString(value.asString());
246                } else if (memberName.equals("message")) {
247                    this.message = value.asString();
248                } else if (memberName.equals("task_assignment_collection")) {
249                    this.taskAssignments = this.parseTaskAssignmentCollection(value.asObject());
250                } else if (memberName.equals("is_completed")) {
251                    this.completed = value.asBoolean();
252                } else if (memberName.equals("created_by")) {
253                    JsonObject userJSON = value.asObject();
254                    String userID = userJSON.get("id").asString();
255                    BoxUser user = new BoxUser(getAPI(), userID);
256                    this.createdBy = user.new Info(userJSON);
257                } else if (memberName.equals("created_at")) {
258                    this.createdAt = BoxDateFormat.parse(value.asString());
259                }
260
261            } catch (ParseException e) {
262                assert false : "A ParseException indicates a bug in the SDK.";
263            }
264        }
265
266        private List<BoxTaskAssignment.Info> parseTaskAssignmentCollection(JsonObject jsonObject) {
267            int count = jsonObject.get("total_count").asInt();
268            List<BoxTaskAssignment.Info> taskAssignmentCollection = new ArrayList<BoxTaskAssignment.Info>(count);
269            JsonArray entries = jsonObject.get("entries").asArray();
270            for (JsonValue value : entries) {
271                JsonObject entry = value.asObject();
272                String id = entry.get("id").asString();
273                BoxTaskAssignment assignment = new BoxTaskAssignment(getAPI(), id);
274                taskAssignmentCollection.add(assignment.new Info(entry));
275            }
276
277            return taskAssignmentCollection;
278        }
279    }
280
281    /**
282     * Enumerates the possible actions that a task can have.
283     */
284    public enum Action {
285        /**
286         * The task must be reviewed.
287         */
288        REVIEW ("review");
289
290        private final String jsonValue;
291
292        private Action(String jsonValue) {
293            this.jsonValue = jsonValue;
294        }
295
296        static Action fromJSONString(String jsonValue) {
297            if (jsonValue.equals("review")) {
298                return REVIEW;
299            } else {
300                throw new IllegalArgumentException("The provided JSON value isn't a valid Action.");
301            }
302        }
303
304        String toJSONString() {
305            return this.jsonValue;
306        }
307    }
308}