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