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