/core/src/main/java/org/b3log/solo/util/Comments.java
Java | 346 lines | 183 code | 38 blank | 125 comment | 28 complexity | 224e09858433082644404f5d5227b43d MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1
1/* 2 * Copyright (c) 2009, 2010, 2011, 2012, B3log Team 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package org.b3log.solo.util; 17 18import java.io.IOException; 19import java.net.URL; 20import java.util.logging.Level; 21import java.util.logging.Logger; 22import org.b3log.latke.Keys; 23import org.b3log.latke.mail.MailService; 24import org.b3log.latke.mail.MailService.Message; 25import org.b3log.latke.mail.MailServiceFactory; 26import org.b3log.latke.service.LangPropsService; 27import org.b3log.latke.util.Strings; 28import org.b3log.solo.SoloServletListener; 29import org.b3log.solo.model.*; 30import org.b3log.solo.repository.ArticleRepository; 31import org.b3log.solo.repository.PageRepository; 32import org.b3log.solo.repository.impl.ArticleRepositoryImpl; 33import org.b3log.solo.repository.impl.PageRepositoryImpl; 34import org.b3log.solo.service.PreferenceQueryService; 35import org.json.JSONException; 36import org.json.JSONObject; 37 38/** 39 * Comment utilities. 40 * 41 * @author <a href="mailto:DL88250@gmail.com">Liang Ding</a> 42 * @version 1.0.0.9, Mar 28, 2012 43 * @since 0.3.1 44 */ 45public final class Comments { 46 47 /** 48 * Logger. 49 */ 50 private static final Logger LOGGER = Logger.getLogger(Comments.class.getName()); 51 /** 52 * Language service. 53 */ 54 private static LangPropsService langPropsService = LangPropsService.getInstance(); 55 /** 56 * Preference query service. 57 */ 58 private static PreferenceQueryService preferenceQueryService = PreferenceQueryService.getInstance(); 59 /** 60 * Article repository. 61 */ 62 private static ArticleRepository articleRepository = ArticleRepositoryImpl.getInstance(); 63 /** 64 * Page repository. 65 */ 66 private static PageRepository pageRepository = PageRepositoryImpl.getInstance(); 67 /** 68 * Mail service. 69 */ 70 private static final MailService MAIL_SVC = MailServiceFactory.getMailService(); 71 /** 72 * Minimum length of comment name. 73 */ 74 private static final int MIN_COMMENT_NAME_LENGTH = 2; 75 /** 76 * Maximum length of comment name. 77 */ 78 private static final int MAX_COMMENT_NAME_LENGTH = 20; 79 /** 80 * Minimum length of comment content. 81 */ 82 private static final int MIN_COMMENT_CONTENT_LENGTH = 2; 83 /** 84 * Maximum length of comment content. 85 */ 86 private static final int MAX_COMMENT_CONTENT_LENGTH = 500; 87 /** 88 * Comment mail HTML body. 89 */ 90 public static final String COMMENT_MAIL_HTML_BODY = 91 "<p>{articleOrPage} [<a href=\"" + "{articleOrPageURL}\">" 92 + "{title}</a>]" + " received a new comment:</p>" 93 + "{commenter}: <span><a href=\"http://{commentSharpURL}\">" 94 + "{commentContent}</a></span>"; 95 96 /** 97 * Gets comment sharp URL with the specified page and comment id. 98 * 99 * @param page the specified page 100 * @param commentId the specified comment id 101 * @return comment sharp URL 102 * @throws JSONException json exception 103 */ 104 public static String getCommentSharpURLForPage(final JSONObject page, final String commentId) throws JSONException { 105 return page.getString(Page.PAGE_PERMALINK) + "#" + commentId; 106 } 107 108 /** 109 * Gets comment sharp URL with the specified article and comment id. 110 * 111 * @param article the specified article 112 * @param commentId the specified comment id 113 * @return comment sharp URL 114 * @throws JSONException json exception 115 */ 116 public static String getCommentSharpURLForArticle(final JSONObject article, final String commentId) throws JSONException { 117 final String articleLink = article.getString(Article.ARTICLE_PERMALINK); 118 119 return articleLink + "#" + commentId; 120 } 121 122 /** 123 * Checks the specified comment adding request. 124 * 125 * @param requestJSONObject the specified comment adding request, for example, 126 * <pre> 127 * { 128 * "type": "", // "article"/"page" 129 * "oId": "", 130 * "commentName": "", 131 * "commentEmail": "", 132 * "commentURL": "", 133 * "commentContent": "", 134 * } 135 * </pre> 136 * @return check result, for example, 137 * <pre> 138 * { 139 * "sc": boolean, 140 * "msg": "" // Exists if "sc" equals to false 141 * } 142 * </pre> 143 */ 144 public static JSONObject checkAddCommentRequest(final JSONObject requestJSONObject) { 145 final JSONObject ret = new JSONObject(); 146 147 try { 148 ret.put(Keys.STATUS_CODE, false); 149 final JSONObject preference = preferenceQueryService.getPreference(); 150 if (null == preference || !preference.optBoolean(Preference.COMMENTABLE)) { 151 ret.put(Keys.MSG, langPropsService.get("notAllowCommentLabel")); 152 153 return ret; 154 } 155 156 final String id = requestJSONObject.optString(Keys.OBJECT_ID); 157 final String type = requestJSONObject.optString(Common.TYPE); 158 if (Article.ARTICLE.equals(type)) { 159 final JSONObject article = articleRepository.get(id); 160 if (null == article || !article.optBoolean(Article.ARTICLE_COMMENTABLE)) { 161 ret.put(Keys.MSG, langPropsService.get("notAllowCommentLabel")); 162 163 return ret; 164 } 165 } else { 166 final JSONObject page = pageRepository.get(id); 167 if (null == page || !page.optBoolean(Page.PAGE_COMMENTABLE)) { 168 ret.put(Keys.MSG, langPropsService.get("notAllowCommentLabel")); 169 170 return ret; 171 } 172 } 173 174 final String commentName = requestJSONObject.getString(Comment.COMMENT_NAME); 175 if (MAX_COMMENT_NAME_LENGTH < commentName.length() || MIN_COMMENT_NAME_LENGTH > commentName.length()) { 176 LOGGER.log(Level.WARNING, "Comment name is too long[{0}]", commentName); 177 ret.put(Keys.MSG, langPropsService.get("nameTooLongLabel")); 178 179 return ret; 180 } 181 182 final String commentEmail = requestJSONObject.getString(Comment.COMMENT_EMAIL).trim().toLowerCase(); 183 if (!Strings.isEmail(commentEmail)) { 184 LOGGER.log(Level.WARNING, "Comment email is invalid[{0}]", commentEmail); 185 ret.put(Keys.MSG, langPropsService.get("mailInvalidLabel")); 186 187 return ret; 188 } 189 190 final String commentURL = requestJSONObject.optString(Comment.COMMENT_URL); 191 try { 192 new URL(commentURL); 193 194 if (commentURL.contains("<") || commentURL.contains(">")) { 195 throw new IllegalArgumentException(); 196 } 197 } catch (final Exception e) { 198 LOGGER.log(Level.WARNING, "Comment URL is invalid[{0}]", commentURL); 199 ret.put(Keys.MSG, langPropsService.get("urlInvalidLabel")); 200 201 return ret; 202 } 203 204 final String commentContent = requestJSONObject.optString(Comment.COMMENT_CONTENT). 205 replaceAll("\\n", SoloServletListener.ENTER_ESC); 206 if (MAX_COMMENT_CONTENT_LENGTH < commentContent.length() || MIN_COMMENT_CONTENT_LENGTH > commentContent.length()) { 207 LOGGER.log(Level.WARNING, "Comment conent length is invalid[{0}]", commentContent.length()); 208 ret.put(Keys.MSG, langPropsService.get("commentContentCannotEmptyLabel")); 209 210 return ret; 211 } 212 213 ret.put(Keys.STATUS_CODE, true); 214 215 return ret; 216 } catch (final Exception e) { 217 LOGGER.log(Level.WARNING, "Checks add comment request[" + requestJSONObject.toString() + "] failed", e); 218 219 ret.put(Keys.STATUS_CODE, false); 220 ret.put(Keys.MSG, langPropsService.get("addFailLabel")); 221 222 return ret; 223 } 224 } 225 226 /** 227 * Sends a notification mail to administrator for notifying the specified 228 * article or page received the specified comment and original comment. 229 * 230 * @param articleOrPage the specified article or page 231 * @param comment the specified comment 232 * @param originalComment original comment, if not exists, set it as 233 * {@code null} 234 * @param preference the specified preference 235 * @throws IOException io exception 236 * @throws JSONException json exception 237 */ 238 public static void sendNotificationMail(final JSONObject articleOrPage, 239 final JSONObject comment, 240 final JSONObject originalComment, 241 final JSONObject preference) 242 throws IOException, JSONException { 243 final String commentEmail = comment.getString(Comment.COMMENT_EMAIL); 244 final String commentId = comment.getString(Keys.OBJECT_ID); 245 final String commentContent = comment.getString(Comment.COMMENT_CONTENT). 246 replaceAll(SoloServletListener.ENTER_ESC, "<br/>"); 247 248 final String adminEmail = preference.getString(Preference.ADMIN_EMAIL); 249 if (adminEmail.equalsIgnoreCase(commentEmail)) { 250 LOGGER.log(Level.FINER, "Do not send comment notification mail to admin itself[{0}]", adminEmail); 251 return; 252 } 253 254 if (null != originalComment && comment.has(Comment.COMMENT_ORIGINAL_COMMENT_ID)) { 255 final String originalEmail = originalComment.getString(Comment.COMMENT_EMAIL); 256 if (originalEmail.equalsIgnoreCase(adminEmail)) { 257 LOGGER.log(Level.FINER, "Do not send comment notification mail to admin while the specified comment[{0}] is an reply", 258 commentId); 259 return; 260 } 261 } 262 263 final String blogTitle = preference.getString(Preference.BLOG_TITLE); 264 final String blogHost = preference.getString(Preference.BLOG_HOST); 265 boolean isArticle = true; 266 String title = articleOrPage.optString(Article.ARTICLE_TITLE); 267 if (Strings.isEmptyOrNull(title)) { 268 title = articleOrPage.getString(Page.PAGE_TITLE); 269 isArticle = false; 270 } 271 272 final String commentSharpURL = comment.getString(Comment.COMMENT_SHARP_URL); 273 final Message message = new Message(); 274 message.setFrom(adminEmail); 275 message.addRecipient(adminEmail); 276 String mailSubject = null; 277 String articleOrPageURL = null; 278 String mailBody = null; 279 if (isArticle) { 280 mailSubject = blogTitle + ": New comment on article [" + title + "]"; 281 articleOrPageURL = "http://" + blogHost + articleOrPage.getString(Article.ARTICLE_PERMALINK); 282 mailBody = COMMENT_MAIL_HTML_BODY.replace("{articleOrPage}", "Article"); 283 } else { 284 mailSubject = blogTitle + ": New comment on page [" + title + "]"; 285 articleOrPageURL = "http://" + blogHost + articleOrPage.getString(Page.PAGE_PERMALINK); 286 mailBody = COMMENT_MAIL_HTML_BODY.replace("{articleOrPage}", "Page"); 287 } 288 289 message.setSubject(mailSubject); 290 final String commentName = comment.getString(Comment.COMMENT_NAME); 291 final String commentURL = comment.getString(Comment.COMMENT_URL); 292 String commenter = null; 293 if (!"http://".equals(commentURL)) { 294 commenter = "<a target=\"_blank\" " + "href=\"" + commentURL + "\">" + commentName + "</a>"; 295 } else { 296 commenter = commentName; 297 } 298 299 mailBody = mailBody.replace("{articleOrPageURL}", articleOrPageURL). 300 replace("{title}", title). 301 replace("{commentContent}", commentContent). 302 replace("{commentSharpURL}", blogHost + commentSharpURL). 303 replace("{commenter}", commenter); 304 message.setHtmlBody(mailBody); 305 306 LOGGER.log(Level.FINER, 307 "Sending a mail[mailSubject={0}, mailBody=[{1}] to admin[email={2}]", 308 new Object[]{mailSubject, mailBody, adminEmail}); 309 MAIL_SVC.send(message); 310 } 311 312 /** 313 * Gets the {@link Comments} singleton. 314 * 315 * @return the singleton 316 */ 317 public static Comments getInstance() { 318 return SingletonHolder.SINGLETON; 319 } 320 321 /** 322 * Private default constructor. 323 */ 324 private Comments() { 325 } 326 327 /** 328 * Singleton holder. 329 * 330 * @author <a href="mailto:DL88250@gmail.com">Liang Ding</a> 331 * @version 1.0.0.0, Jan 12, 2011 332 */ 333 private static final class SingletonHolder { 334 335 /** 336 * Singleton. 337 */ 338 private static final Comments SINGLETON = new Comments(); 339 340 /** 341 * Private default constructor. 342 */ 343 private SingletonHolder() { 344 } 345 } 346}