PageRenderTime 33ms CodeModel.GetById 19ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/core/src/main/java/org/b3log/solo/util/Comments.java

http://github.com/b3log/b3log-solo
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}