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