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