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