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