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