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 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 @Override 226 public BoxComment getResource() { 227 return BoxComment.this; 228 } 229 230 @Override 231 protected void parseJSONMember(JsonObject.Member member) { 232 super.parseJSONMember(member); 233 234 try { 235 String memberName = member.getName(); 236 JsonValue value = member.getValue(); 237 if (memberName.equals("is_reply_comment")) { 238 this.isReplyComment = value.asBoolean(); 239 240 } else if (memberName.equals("message")) { 241 this.message = value.asString(); 242 243 } else if (memberName.equals("tagged_message")) { 244 this.taggedMessage = value.asString(); 245 246 } else if (memberName.equals("created_by")) { 247 JsonObject userJSON = value.asObject(); 248 if (this.createdBy == null) { 249 String userID = userJSON.get("id").asString(); 250 BoxUser user = new BoxUser(getAPI(), userID); 251 this.createdBy = user.new Info(userJSON); 252 } else { 253 this.createdBy.update(userJSON); 254 } 255 256 } else if (memberName.equals("created_at")) { 257 this.createdAt = BoxDateFormat.parse(value.asString()); 258 259 } else if (memberName.equals("item")) { 260 this.parseItem(value); 261 262 } else if (memberName.equals("modified_by")) { 263 JsonObject userJSON = value.asObject(); 264 if (this.modifiedBy == null) { 265 String userID = userJSON.get("id").asString(); 266 BoxUser user = new BoxUser(getAPI(), userID); 267 this.modifiedBy = user.new Info(userJSON); 268 } else { 269 this.modifiedBy.update(userJSON); 270 } 271 } 272 } catch (ParseException e) { 273 assert false : "A ParseException indicates a bug in the SDK."; 274 } 275 } 276 277 private void parseItem(JsonValue value) { 278 JsonObject itemJSON = value.asObject(); 279 String itemType = itemJSON.get("type").asString(); 280 if (itemType.equals("file")) { 281 this.updateItemAsFile(itemJSON); 282 } else if (itemType.equals("comment")) { 283 this.updateItemAsComment(itemJSON); 284 } 285 } 286 287 private void updateItemAsFile(JsonObject itemJSON) { 288 String itemID = itemJSON.get("id").asString(); 289 if (this.item != null && this.item instanceof BoxFile.Info && this.item.getID().equals(itemID)) { 290 this.item.update(itemJSON); 291 } else { 292 BoxFile file = new BoxFile(getAPI(), itemID); 293 this.item = file.new Info(itemJSON); 294 } 295 } 296 297 private void updateItemAsComment(JsonObject itemJSON) { 298 String itemType = itemJSON.get("type").asString(); 299 String itemID = itemJSON.get("id").asString(); 300 if (this.item != null && this.item instanceof BoxComment.Info && this.item.getID().equals(itemID)) { 301 this.item.update(itemJSON); 302 } else { 303 BoxComment comment = new BoxComment(getAPI(), itemID); 304 this.item = comment.new Info(itemJSON); 305 } 306 } 307 } 308}