001package com.box.sdk; 002 003import java.net.URL; 004import java.text.ParseException; 005import java.util.Date; 006import java.util.regex.Pattern; 007 008import com.eclipsesource.json.JsonObject; 009import com.eclipsesource.json.JsonValue; 010 011/** 012 * Represents a comment on a file. Comments can be added directly to a file or they can be created as replies to other 013 * comments. 014 * 015 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked 016 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error 017 * handling for errors related to the Box REST API, you should capture this exception explicitly.</p> 018 */ 019@BoxResourceType("comment") 020public class BoxComment extends BoxResource { 021 022 /** 023 * Add Comment URL Template. 024 */ 025 public static final URLTemplate ADD_COMMENT_URL_TEMPLATE = new URLTemplate("comments"); 026 /** 027 * Comment URL Template. 028 */ 029 public static final URLTemplate COMMENT_URL_TEMPLATE = new URLTemplate("comments/%s"); 030 031 private static final Pattern MENTION_REGEX = Pattern.compile("@\\[.+:.+\\]"); 032 033 /** 034 * Constructs a BoxComment for a comment with a given ID. 035 * @param api the API connection to be used with the comment. 036 * @param id the ID of the comment. 037 */ 038 public BoxComment(BoxAPIConnection api, String id) { 039 super(api, id); 040 } 041 042 /** 043 * Determines if a comment message contains an @mention. 044 * @param message the comment message. 045 * @return true if the message contains an @mention; otherwise false. 046 */ 047 static boolean messageContainsMention(String message) { 048 return MENTION_REGEX.matcher(message).find(); 049 } 050 051 /** 052 * Gets information about this comment. 053 * @return info about this comment. 054 */ 055 public Info getInfo() { 056 URL url = COMMENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 057 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 058 BoxJSONResponse response = (BoxJSONResponse) request.send(); 059 JsonObject jsonResponse = JsonObject.readFrom(response.getJSON()); 060 061 return new Info(jsonResponse); 062 } 063 064 /** 065 * Changes the message of this comment. 066 * @param newMessage the new message for this comment. 067 * @return updated info about this comment. 068 */ 069 public Info changeMessage(String newMessage) { 070 Info newInfo = new Info(); 071 newInfo.setMessage(newMessage); 072 073 URL url = COMMENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 074 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 075 request.setBody(newInfo.getPendingChanges()); 076 BoxJSONResponse response = (BoxJSONResponse) request.send(); 077 JsonObject jsonResponse = JsonObject.readFrom(response.getJSON()); 078 079 return new Info(jsonResponse); 080 } 081 082 /** 083 * Replies to this comment with another message. 084 * @param message the message for the reply. 085 * @return info about the newly created reply comment. 086 */ 087 public BoxComment.Info reply(String message) { 088 JsonObject itemJSON = new JsonObject(); 089 itemJSON.add("type", "comment"); 090 itemJSON.add("id", this.getID()); 091 092 JsonObject requestJSON = new JsonObject(); 093 requestJSON.add("item", itemJSON); 094 if (BoxComment.messageContainsMention(message)) { 095 requestJSON.add("tagged_message", message); 096 } else { 097 requestJSON.add("message", message); 098 } 099 100 URL url = ADD_COMMENT_URL_TEMPLATE.build(this.getAPI().getBaseURL()); 101 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 102 request.setBody(requestJSON.toString()); 103 BoxJSONResponse response = (BoxJSONResponse) request.send(); 104 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 105 106 BoxComment addedComment = new BoxComment(this.getAPI(), responseJSON.get("id").asString()); 107 return addedComment.new Info(responseJSON); 108 } 109 110 /** 111 * Deletes this comment. 112 */ 113 public void delete() { 114 URL url = COMMENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 115 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE"); 116 BoxAPIResponse response = request.send(); 117 response.disconnect(); 118 } 119 120 /** 121 * Contains information about a BoxComment. 122 */ 123 public class Info extends BoxResource.Info { 124 private boolean isReplyComment; 125 private String message; 126 private String taggedMessage; 127 private BoxUser.Info createdBy; 128 private Date createdAt; 129 private BoxResource.Info item; 130 private BoxUser.Info modifiedBy; 131 private Date modifiedAt; 132 133 /** 134 * Constructs an empty Info object. 135 */ 136 public Info() { 137 super(); 138 } 139 140 /** 141 * Constructs an Info object by parsing information from a JSON string. 142 * @param json the JSON string to parse. 143 */ 144 public Info(String json) { 145 super(json); 146 } 147 148 /** 149 * Constructs an Info object using an already parsed JSON object. 150 * @param jsonObject the parsed JSON object. 151 */ 152 Info(JsonObject jsonObject) { 153 super(jsonObject); 154 } 155 156 /** 157 * Gets whether or not the comment is a reply to another comment. 158 * @return true if this comment is a reply to another comment; otherwise false. 159 */ 160 public boolean getIsReplyComment() { 161 return this.isReplyComment; 162 } 163 164 /** 165 * Gets the comment's message. 166 * @return the comment's message. 167 */ 168 public String getMessage() { 169 if (this.taggedMessage != null) { 170 return this.taggedMessage; 171 } 172 173 return this.message; 174 } 175 176 /** 177 * Sets the comment's message. The message can contain @mentions by using the string @[userid:username] anywhere 178 * within the message, where userid and username are the ID and username of the person being mentioned. 179 * @param message the comment's new message. 180 */ 181 public void setMessage(String message) { 182 if (messageContainsMention(message)) { 183 this.taggedMessage = message; 184 this.addPendingChange("tagged_message", message); 185 this.removePendingChange("message"); 186 } else { 187 this.message = message; 188 this.addPendingChange("message", message); 189 this.removePendingChange("tagged_message"); 190 } 191 } 192 193 /** 194 * Gets info about the user who created the comment. 195 * @return info about the user who created the comment. 196 */ 197 public BoxUser.Info getCreatedBy() { 198 return this.createdBy; 199 } 200 201 /** 202 * Gets the time the comment was created. 203 * @return the time the comment was created. 204 */ 205 public Date getCreatedAt() { 206 return this.createdAt; 207 } 208 209 /** 210 * Gets info about the item this comment is attached to. If the comment is a reply, then the item will be 211 * another BoxComment. Otherwise, the item will be a {@link BoxFile}. 212 * @return the item this comment is attached to. 213 */ 214 public BoxResource.Info getItem() { 215 return this.item; 216 } 217 218 /** 219 * Gets info about the user who last modified the comment. 220 * @return info about the user who last modified the comment. 221 */ 222 public BoxUser.Info getModifiedBy() { 223 return this.modifiedBy; 224 } 225 226 /** 227 * Gets the time the comment was last modified. 228 * @return the time the comment was last modified. 229 */ 230 public Date getModifiedAt() { 231 return this.modifiedAt; 232 } 233 234 @Override 235 public BoxComment getResource() { 236 return BoxComment.this; 237 } 238 239 @Override 240 protected void parseJSONMember(JsonObject.Member member) { 241 super.parseJSONMember(member); 242 243 try { 244 String memberName = member.getName(); 245 JsonValue value = member.getValue(); 246 if (memberName.equals("is_reply_comment")) { 247 this.isReplyComment = value.asBoolean(); 248 249 } else if (memberName.equals("message")) { 250 this.message = value.asString(); 251 252 } else if (memberName.equals("tagged_message")) { 253 this.taggedMessage = value.asString(); 254 255 } else if (memberName.equals("created_by")) { 256 JsonObject userJSON = value.asObject(); 257 if (this.createdBy == null) { 258 String userID = userJSON.get("id").asString(); 259 BoxUser user = new BoxUser(getAPI(), userID); 260 this.createdBy = user.new Info(userJSON); 261 } else { 262 this.createdBy.update(userJSON); 263 } 264 265 } else if (memberName.equals("created_at")) { 266 this.createdAt = BoxDateFormat.parse(value.asString()); 267 268 } else if (memberName.equals("item")) { 269 this.parseItem(value); 270 271 } else if (memberName.equals("modified_by")) { 272 JsonObject userJSON = value.asObject(); 273 if (this.modifiedBy == null) { 274 String userID = userJSON.get("id").asString(); 275 BoxUser user = new BoxUser(getAPI(), userID); 276 this.modifiedBy = user.new Info(userJSON); 277 } else { 278 this.modifiedBy.update(userJSON); 279 } 280 } else if (memberName.equals("modified_at")) { 281 this.modifiedAt = BoxDateFormat.parse(value.asString()); 282 } 283 } catch (ParseException e) { 284 assert false : "A ParseException indicates a bug in the SDK."; 285 } 286 } 287 288 private void parseItem(JsonValue value) { 289 JsonObject itemJSON = value.asObject(); 290 String itemType = itemJSON.get("type").asString(); 291 if (itemType.equals("file")) { 292 this.updateItemAsFile(itemJSON); 293 } else if (itemType.equals("comment")) { 294 this.updateItemAsComment(itemJSON); 295 } 296 } 297 298 private void updateItemAsFile(JsonObject itemJSON) { 299 String itemID = itemJSON.get("id").asString(); 300 if (this.item != null && this.item instanceof BoxFile.Info && this.item.getID().equals(itemID)) { 301 this.item.update(itemJSON); 302 } else { 303 BoxFile file = new BoxFile(getAPI(), itemID); 304 this.item = file.new Info(itemJSON); 305 } 306 } 307 308 private void updateItemAsComment(JsonObject itemJSON) { 309 String itemType = itemJSON.get("type").asString(); 310 String itemID = itemJSON.get("id").asString(); 311 if (this.item != null && this.item instanceof BoxComment.Info && this.item.getID().equals(itemID)) { 312 this.item.update(itemJSON); 313 } else { 314 BoxComment comment = new BoxComment(getAPI(), itemID); 315 this.item = comment.new Info(itemJSON); 316 } 317 } 318 } 319}