/** * Logins. * * <p>Renders the response with a json object, for example, * * <pre> * { * "isLoggedIn": boolean, * "msg": "" // optional, exists if isLoggedIn equals to false * } * </pre> * * @param context the specified context */ @RequestProcessing(value = "/login", method = HTTPRequestMethod.POST) public void login(final HTTPRequestContext context) { final HttpServletRequest request = context.getRequest(); final JSONRenderer renderer = new JSONRenderer(); context.setRenderer(renderer); final JSONObject jsonObject = new JSONObject(); renderer.setJSONObject(jsonObject); try { jsonObject.put(Common.IS_LOGGED_IN, false); final String loginFailLabel = langPropsService.get("loginFailLabel"); jsonObject.put(Keys.MSG, loginFailLabel); final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, context.getResponse()); final String userEmail = requestJSONObject.getString(User.USER_EMAIL); final String userPwd = requestJSONObject.getString(User.USER_PASSWORD); if (Strings.isEmptyOrNull(userEmail) || Strings.isEmptyOrNull(userPwd)) { return; } LOGGER.log(Level.INFO, "Login[email={0}]", userEmail); final JSONObject user = userQueryService.getUserByEmail(userEmail); if (null == user) { LOGGER.log(Level.WARN, "Not found user[email={0}]", userEmail); return; } if (MD5.hash(userPwd).equals(user.getString(User.USER_PASSWORD))) { Sessions.login(request, context.getResponse(), user); LOGGER.log(Level.INFO, "Logged in[email={0}]", userEmail); jsonObject.put(Common.IS_LOGGED_IN, true); if (Role.VISITOR_ROLE.equals(user.optString(User.USER_ROLE))) { jsonObject.put("to", Latkes.getServePath()); } else { jsonObject.put("to", Latkes.getServePath() + Common.ADMIN_INDEX_URI); } jsonObject.remove(Keys.MSG); return; } LOGGER.log(Level.WARN, "Wrong password[{0}]", userPwd); } catch (final Exception e) { LOGGER.log(Level.ERROR, e.getMessage(), e); } }
/** * Constructs a repository with the specified name. * * @param name the specified name */ @SuppressWarnings("unchecked") public AbstractRepository(final String name) { final RuntimeEnv runtimeEnv = Latkes.getRuntimeEnv(); try { Class<Repository> repositoryClass = null; switch (runtimeEnv) { case BAE: case LOCAL: final RuntimeDatabase runtimeDatabase = Latkes.getRuntimeDatabase(); switch (runtimeDatabase) { case MYSQL: repositoryClass = (Class<Repository>) Class.forName("org.b3log.latke.repository.jdbc.JdbcRepository"); break; case H2: repositoryClass = (Class<Repository>) Class.forName("org.b3log.latke.repository.jdbc.JdbcRepository"); break; case NONE: repositoryClass = (Class<Repository>) Class.forName("org.b3log.latke.repository.NoneRepository"); break; default: throw new RuntimeException( "The runtime database [" + runtimeDatabase + "] is not support NOW!"); } break; case GAE: repositoryClass = (Class<Repository>) Class.forName("org.b3log.latke.repository.gae.GAERepository"); break; default: throw new RuntimeException( "Latke runs in the hell.... Please set the enviornment correctly"); } final Constructor<Repository> constructor = repositoryClass.getConstructor(String.class); repository = constructor.newInstance(name); } catch (final Exception e) { throw new RuntimeException("Can not initialize repository!", e); } Repositories.addRepository(repository); LOGGER.log(Level.INFO, "Constructed repository[name={0}]", name); }
/** * Resets forgotten password. * * <p>Renders the response with a json object, for example, * * <pre> * { * "isLoggedIn": boolean, * "msg": "" // optional, exists if isLoggedIn equals to false * } * </pre> * * @param context the specified context */ @RequestProcessing(value = "/reset", method = HTTPRequestMethod.POST) public void reset(final HTTPRequestContext context) { final HttpServletRequest request = context.getRequest(); final JSONRenderer renderer = new JSONRenderer(); context.setRenderer(renderer); final JSONObject jsonObject = new JSONObject(); renderer.setJSONObject(jsonObject); try { final JSONObject requestJSONObject; requestJSONObject = Requests.parseRequestJSONObject(request, context.getResponse()); final String userEmail = requestJSONObject.getString(User.USER_EMAIL); final String newPwd = requestJSONObject.getString("newPwd"); final JSONObject user = userQueryService.getUserByEmail(userEmail); user.put(User.USER_PASSWORD, newPwd); userMgmtService.updateUser(user); LOGGER.log(Level.DEBUG, "[{0}]'s password updated successfully.", new Object[] {userEmail}); jsonObject.put("succeed", true); jsonObject.put("to", Latkes.getServePath() + "/login?from=reset"); jsonObject.put(Keys.MSG, langPropsService.get("resetPwdSuccessMsg")); } catch (final Exception e) { LOGGER.log(Level.ERROR, e.getMessage(), e); } }
/** * {@inheritDoc} * * <p>Processes page caching. */ @Override protected void afterRender(final HTTPRequestContext context) throws Exception { final HttpServletRequest request = context.getRequest(); final String pageContent = (String) request.getAttribute(PageCaches.CACHED_CONTENT); if (null == pageContent) { return; } if (Latkes.isPageCacheEnabled()) { final String cachedPageKey = (String) request.getAttribute(Keys.PAGE_CACHE_KEY); if (Strings.isEmptyOrNull(cachedPageKey)) { return; } LOGGER.log(Level.FINEST, "Caching page[cachedPageKey={0}]", cachedPageKey); check(request, pageContent); final JSONObject cachedValue = new JSONObject(); cachedValue.put(PageCaches.CACHED_CONTENT, pageContent); cachedValue.put(PageCaches.CACHED_TYPE, request.getAttribute(PageCaches.CACHED_TYPE)); cachedValue.put(PageCaches.CACHED_OID, request.getAttribute(PageCaches.CACHED_OID)); cachedValue.put(PageCaches.CACHED_TITLE, request.getAttribute(PageCaches.CACHED_TITLE)); cachedValue.put(PageCaches.CACHED_LINK, request.getAttribute(PageCaches.CACHED_LINK)); if (null != request.getAttribute(PageCaches.CACHED_PWD)) { cachedValue.put(PageCaches.CACHED_PWD, request.getAttribute(PageCaches.CACHED_PWD)); } PageCaches.put(cachedPageKey, cachedValue, request); LOGGER.log(Level.FINEST, "Cached page[cachedPageKey={0}]", cachedPageKey); } }
/** * Checks whether the specified user-defined permalink is invalid on format. * * @param permalink the specified user-defined permalink * @return {@code true} if invalid, returns {@code false} otherwise */ private static boolean invalidUserDefinedPermalinkFormat(final String permalink) { if (Strings.isEmptyOrNull(permalink)) { return true; } if (isReservedLink(permalink)) { return true; } if (Strings.isNumeric(permalink.substring(1))) { // See issue 120 (http://code.google.com/p/b3log-solo/issues/detail?id=120#c4) for more // details return true; } int slashCnt = 0; for (int i = 0; i < permalink.length(); i++) { if ('/' == permalink.charAt(i)) { slashCnt++; } if (slashCnt > 1) { return true; } } return !Strings.isURL(Latkes.getServer() + permalink); }
/** * Render a page template with the destination URL. * * @param context the context * @param pageTemplate the page template * @param destinationURL the destination URL * @param request for reset password page * @throws JSONException the JSONException * @throws ServiceException the ServiceException */ private void renderPage( final HTTPRequestContext context, final String pageTemplate, final String destinationURL, final HttpServletRequest request) throws JSONException, ServiceException { final AbstractFreeMarkerRenderer renderer = new ConsoleRenderer(); renderer.setTemplateName(pageTemplate); context.setRenderer(renderer); final Map<String, Object> dataModel = renderer.getDataModel(); final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale()); final JSONObject preference = preferenceQueryService.getPreference(); dataModel.putAll(langs); dataModel.put(Common.GOTO, destinationURL); dataModel.put(Common.YEAR, String.valueOf(Calendar.getInstance().get(Calendar.YEAR))); dataModel.put(Common.VERSION, SoloServletListener.VERSION); dataModel.put(Common.STATIC_RESOURCE_VERSION, Latkes.getStaticResourceVersion()); dataModel.put(Preference.BLOG_TITLE, preference.getString(Preference.BLOG_TITLE)); final String token = request.getParameter("token"); final String email = request.getParameter("login"); final JSONObject tokenObj = optionQueryService.getOptionById(token); if (tokenObj == null) { dataModel.put("inputType", "email"); } else { // TODO verify the expired time in the tokenObj dataModel.put("inputType", "password"); dataModel.put("userEmailHidden", email); } final String from = request.getParameter("from"); if ("forgot".equals(from)) { dataModel.put("resetMsg", langPropsService.get("resetPwdSuccessSend")); } else if ("reset".equals(from)) { dataModel.put("resetMsg", langPropsService.get("resetPwdSuccessMsg")); } else { dataModel.put("resetMsg", ""); } Keys.fillRuntime(dataModel); filler.fillMinified(dataModel); }
/** * Gets tag title from the specified URI. * * @param requestURI the specified request URI * @return tag title */ private static String getTagTitle(final String requestURI) { final String path = requestURI.substring((Latkes.getContextPath() + "/tags/").length()); if (path.contains("/")) { return path.substring(0, path.indexOf("/")); } else { return path.substring(0); } }
/** * Sends the password resetting URL with a random token. * * @param userEmail the given email * @param jsonObject return code and message object * @throws JSONException the JSONException * @throws ServiceException the ServiceException * @throws IOException the IOException * @throws RepositoryException the RepositoryException */ private void sendResetUrl(final String userEmail, final JSONObject jsonObject) throws JSONException, ServiceException, IOException, RepositoryException { final JSONObject preference = preferenceQueryService.getPreference(); final String token = new Randoms().nextStringWithMD5(); final String adminEmail = preference.getString(Preference.ADMIN_EMAIL); final String mailSubject = langPropsService.get("resetPwdMailSubject"); final String mailBody = langPropsService.get("resetPwdMailBody") + " " + Latkes.getServePath() + "/forgot?token=" + token + "&login="******"passwordReset"); option.put(Option.OPTION_VALUE, System.currentTimeMillis()); final Transaction transaction = optionRepository.beginTransaction(); optionRepository.add(option); transaction.commit(); message.setFrom(adminEmail); message.addRecipient(userEmail); message.setSubject(mailSubject); message.setHtmlBody(mailBody); mailService.send(message); jsonObject.put("succeed", true); jsonObject.put("to", Latkes.getServePath() + "/login?from=forgot"); jsonObject.put(Keys.MSG, langPropsService.get("resetPwdSuccessSend")); LOGGER.log( Level.DEBUG, "Sent a mail[mailSubject={0}, mailBody=[{1}] to [{2}]", new Object[] {mailSubject, mailBody, userEmail}); }
/** * Gets the request page number from the specified request URI and tag title. * * @param requestURI the specified request URI * @param tagTitle the specified tag title * @return page number, returns {@code -1} if the specified request URI can not convert to an * number */ private static int getCurrentPageNum(final String requestURI, final String tagTitle) { if (Strings.isEmptyOrNull(tagTitle)) { return -1; } final String pageNumString = requestURI.substring((Latkes.getContextPath() + "/tags/" + tagTitle + "/").length()); return Requests.getCurrentPageNum(pageNumString); }
/** * Shows forgotten password page. * * @param context the specified context * @throws Exception exception */ @RequestProcessing(value = "/forgot", method = HTTPRequestMethod.GET) public void showForgot(final HTTPRequestContext context) throws Exception { final HttpServletRequest request = context.getRequest(); String destinationURL = request.getParameter(Common.GOTO); if (Strings.isEmptyOrNull(destinationURL)) { destinationURL = Latkes.getServePath() + Common.ADMIN_INDEX_URI; } renderPage(context, "reset-pwd.ftl", destinationURL, request); }
/** * Markdowns. * * <p>Renders the response with a json object, for example, * * <pre> * { * "html": "" * } * </pre> * * @param request the specified http servlet request * @param response the specified http servlet response * @param context the specified http request context * @throws Exception exception */ @RequestProcessing(value = "/markdown", method = HTTPRequestMethod.POST) @Before(adviceClass = StopwatchStartAdvice.class) @After(adviceClass = StopwatchEndAdvice.class) public void markdown2HTML( final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context) throws Exception { final JSONRenderer renderer = new JSONRenderer(); context.setRenderer(renderer); final JSONObject result = new JSONObject(); renderer.setJSONObject(result); result.put(Keys.STATUS_CODE, true); String markdownText = request.getParameter("markdownText"); if (Strings.isEmptyOrNull(markdownText)) { result.put("html", ""); return; } final JSONObject currentUser = userQueryService.getCurrentUser(request); if (null == currentUser) { response.sendError(HttpServletResponse.SC_FORBIDDEN); return; } final Set<String> userNames = userQueryService.getUserNames(markdownText); for (final String userName : userNames) { markdownText = markdownText.replace( '@' + userName, "@<a href='" + Latkes.getServePath() + "/member/" + userName + "'>" + userName + "</a>"); } markdownText = shortLinkQueryService.linkArticle(markdownText); markdownText = shortLinkQueryService.linkTag(markdownText); markdownText = Emotions.convert(markdownText); markdownText = Markdowns.toHTML(markdownText); markdownText = Markdowns.clean(markdownText, ""); result.put("html", markdownText); }
// XXX: [Performance Issue] genCommentContentUserName private void genCommentContentUserName(final JSONObject comment) { String commentContent = comment.optString(Comment.COMMENT_CONTENT); try { final Set<String> userNames = userQueryService.getUserNames(commentContent); for (final String userName : userNames) { commentContent = commentContent.replace( '@' + userName, "@<a href='" + Latkes.getServePath() + "/member/" + userName + "'>" + userName + "</a>"); } } catch (final ServiceException e) { LOGGER.log(Level.ERROR, "Generates @username home URL for comment content failed", e); } comment.put(Comment.COMMENT_CONTENT, commentContent); }
static { LOGGER.info("Constructing URL Fetch Service...."); final RuntimeEnv runtimeEnv = Latkes.getRuntimeEnv(); try { Class<URLFetchService> serviceClass; switch (runtimeEnv) { case BAE: // serviceClass = (Class<URLFetchService>) // Class.forName("org.b3log.latke.urlfetch.bae.BAEURLFetchService"); serviceClass = (Class<URLFetchService>) Class.forName("org.b3log.latke.urlfetch.local.LocalURLFetchService"); URL_FETCH_SERVICE = serviceClass.newInstance(); break; case LOCAL: serviceClass = (Class<URLFetchService>) Class.forName("org.b3log.latke.urlfetch.local.LocalURLFetchService"); URL_FETCH_SERVICE = serviceClass.newInstance(); break; case GAE: serviceClass = (Class<URLFetchService>) Class.forName("org.b3log.latke.urlfetch.gae.GAEURLFetchService"); URL_FETCH_SERVICE = serviceClass.newInstance(); break; default: throw new RuntimeException( "Latke runs in the hell.... Please set the enviornment correctly"); } } catch (final Exception e) { throw new RuntimeException("Can not initialize URL Fetch Service!", e); } LOGGER.info("Constructed URL Fetch Service"); }
/** * Shows login page. * * @param context the specified context * @throws Exception exception */ @RequestProcessing(value = "/login", method = HTTPRequestMethod.GET) public void showLogin(final HTTPRequestContext context) throws Exception { final HttpServletRequest request = context.getRequest(); String destinationURL = request.getParameter(Common.GOTO); if (Strings.isEmptyOrNull(destinationURL)) { destinationURL = Latkes.getServePath() + Common.ADMIN_INDEX_URI; } final HttpServletResponse response = context.getResponse(); userMgmtService.tryLogInWithCookie(request, response); if (null != userService.getCurrentUser(request)) { // User has already logged in response.sendRedirect(destinationURL); return; } renderPage(context, "login.ftl", destinationURL, request); }
static { Latkes.initRuntimeEnv(); }
/** * Gets article preview content. * * <p>Renders the response with a json object, for example, * * <pre> * { * "html": "" * } * </pre> * * @param request the specified http servlet request * @param response the specified http servlet response * @param context the specified http request context * @param articleId the specified article id * @throws Exception exception */ @RequestProcessing(value = "/article/{articleId}/preview", method = HTTPRequestMethod.GET) @Before(adviceClass = StopwatchStartAdvice.class) @After(adviceClass = StopwatchEndAdvice.class) public void getArticlePreviewContent( final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context, final String articleId) throws Exception { final JSONRenderer renderer = new JSONRenderer(); context.setRenderer(renderer); final JSONObject result = Results.trueResult(); renderer.setJSONObject(result); result.put("html", ""); final JSONObject article = articleQueryService.getArticle(articleId); if (null == article) { result.put(Keys.STATUS_CODE, false); return; } final int length = Integer.valueOf("150"); String content = article.optString(Article.ARTICLE_CONTENT); final String authorId = article.optString(Article.ARTICLE_AUTHOR_ID); final JSONObject author = userQueryService.getUser(authorId); if (null != author && UserExt.USER_STATUS_C_INVALID == author.optInt(UserExt.USER_STATUS) || Article.ARTICLE_STATUS_C_INVALID == article.optInt(Article.ARTICLE_STATUS)) { result.put("html", langPropsService.get("articleContentBlockLabel")); return; } final Set<String> userNames = userQueryService.getUserNames(content); final JSONObject currentUser = userQueryService.getCurrentUser(request); final String currentUserName = null == currentUser ? "" : currentUser.optString(User.USER_NAME); final String authorName = author.optString(User.USER_NAME); if (Article.ARTICLE_TYPE_C_DISCUSSION == article.optInt(Article.ARTICLE_TYPE) && !authorName.equals(currentUserName)) { boolean invited = false; for (final String userName : userNames) { if (userName.equals(currentUserName)) { invited = true; break; } } if (!invited) { String blockContent = langPropsService.get("articleDiscussionLabel"); blockContent = blockContent.replace( "{user}", "<a href='" + Latkes.getServePath() + "/member/" + authorName + "'>" + authorName + "</a>"); result.put("html", blockContent); return; } } content = Emotions.convert(content); content = Markdowns.toHTML(content); content = Jsoup.clean(content, Whitelist.none()); if (content.length() >= length) { content = StringUtils.substring(content, 0, length) + " ...."; } result.put("html", content); }
@Override public void action(final Event<JSONObject> event) throws EventException { final JSONObject data = event.getData(); LOGGER.log( Level.DEBUG, "Processing an event[type={0}, data={1}] in listener[className={2}]", new Object[] {event.getType(), data, ArticleSender.class.getName()}); try { final JSONObject originalArticle = data.getJSONObject(Article.ARTICLE); if (!originalArticle.getBoolean(Article.ARTICLE_IS_PUBLISHED)) { LOGGER.log( Level.DEBUG, "Ignores post article[title={0}] to Rhythm", originalArticle.getString(Article.ARTICLE_TITLE)); return; } final LatkeBeanManager beanManager = Lifecycle.getBeanManager(); final PreferenceQueryService preferenceQueryService = beanManager.getReference(PreferenceQueryService.class); final JSONObject preference = preferenceQueryService.getPreference(); if (null == preference) { throw new EventException("Not found preference"); } if (!Strings.isEmptyOrNull(originalArticle.optString(Article.ARTICLE_VIEW_PWD))) { return; } if (Latkes.getServePath().contains("localhost")) { LOGGER.log( Level.INFO, "Solo runs on local server, so should not send this article[id={0}, title={1}] to Rhythm", new Object[] { originalArticle.getString(Keys.OBJECT_ID), originalArticle.getString(Article.ARTICLE_TITLE) }); return; } final HTTPRequest httpRequest = new HTTPRequest(); httpRequest.setURL(ADD_ARTICLE_URL); httpRequest.setRequestMethod(HTTPRequestMethod.POST); final JSONObject requestJSONObject = new JSONObject(); final JSONObject article = new JSONObject(); article.put(Keys.OBJECT_ID, originalArticle.getString(Keys.OBJECT_ID)); article.put(Article.ARTICLE_TITLE, originalArticle.getString(Article.ARTICLE_TITLE)); article.put(Article.ARTICLE_PERMALINK, originalArticle.getString(Article.ARTICLE_PERMALINK)); article.put(Article.ARTICLE_TAGS_REF, originalArticle.getString(Article.ARTICLE_TAGS_REF)); article.put( Article.ARTICLE_AUTHOR_EMAIL, originalArticle.getString(Article.ARTICLE_AUTHOR_EMAIL)); article.put(Article.ARTICLE_CONTENT, originalArticle.getString(Article.ARTICLE_CONTENT)); article.put( Article.ARTICLE_CREATE_DATE, ((Date) originalArticle.get(Article.ARTICLE_CREATE_DATE)).getTime()); article.put(Common.POST_TO_COMMUNITY, originalArticle.getBoolean(Common.POST_TO_COMMUNITY)); // Removes this property avoid to persist originalArticle.remove(Common.POST_TO_COMMUNITY); requestJSONObject.put(Article.ARTICLE, article); requestJSONObject.put(Common.BLOG_VERSION, SoloServletListener.VERSION); requestJSONObject.put(Common.BLOG, "B3log Solo"); requestJSONObject.put(Option.ID_C_BLOG_TITLE, preference.getString(Option.ID_C_BLOG_TITLE)); requestJSONObject.put("blogHost", Latkes.getServePath()); requestJSONObject.put("userB3Key", preference.optString(Option.ID_C_KEY_OF_SOLO)); requestJSONObject.put("clientAdminEmail", preference.optString(Option.ID_C_ADMIN_EMAIL)); requestJSONObject.put("clientRuntimeEnv", Latkes.getRuntimeEnv().name()); httpRequest.setPayload(requestJSONObject.toString().getBytes("UTF-8")); urlFetchService.fetchAsync(httpRequest); } catch (final Exception e) { LOGGER.log(Level.ERROR, "Sends an article to Rhythm error: {0}", e.getMessage()); } LOGGER.log(Level.DEBUG, "Sent an article to Rhythm"); }
/** * Try to write response from cache. * * @param request the specified request * @param response the specified response * @param chain filter chain * @throws IOException io exception * @throws ServletException servlet exception */ @Override public void doFilter( final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { final long startTimeMillis = System.currentTimeMillis(); request.setAttribute(Keys.HttpRequest.START_TIME_MILLIS, startTimeMillis); final HttpServletRequest httpServletRequest = (HttpServletRequest) request; final String requestURI = httpServletRequest.getRequestURI(); LOGGER.log(Level.FINER, "Request URI[{0}]", requestURI); if (StaticResources.isStatic(httpServletRequest)) { final String path = httpServletRequest.getServletPath() + httpServletRequest.getPathInfo(); LOGGER.log(Level.FINEST, "Requests a static resource, forwards to servlet[path={0}]", path); request.getRequestDispatcher(path).forward(request, response); return; } if (!Latkes.isPageCacheEnabled()) { LOGGER.log(Level.FINEST, "Page cache is disabled"); chain.doFilter(request, response); return; } final String skinDirName = (String) httpServletRequest.getAttribute(Keys.TEMAPLTE_DIR_NAME); if ("mobile".equals(skinDirName)) { // Mobile request, bypasses page caching chain.doFilter(request, response); return; } String pageCacheKey; final String queryString = httpServletRequest.getQueryString(); pageCacheKey = (String) request.getAttribute(Keys.PAGE_CACHE_KEY); if (Strings.isEmptyOrNull(pageCacheKey)) { pageCacheKey = PageCaches.getPageCacheKey(requestURI, queryString); request.setAttribute(Keys.PAGE_CACHE_KEY, pageCacheKey); } final JSONObject cachedPageContentObject = PageCaches.get(pageCacheKey, httpServletRequest, (HttpServletResponse) response); if (null == cachedPageContentObject) { LOGGER.log(Level.FINER, "Page cache miss for request URI[{0}]", requestURI); chain.doFilter(request, response); return; } final String cachedType = cachedPageContentObject.optString(PageCaches.CACHED_TYPE); try { // If cached an article that has view password, dispatches the password form if (langPropsService.get(PageTypes.ARTICLE.getLangeLabel()).equals(cachedType) && cachedPageContentObject.has(PageCaches.CACHED_PWD)) { JSONObject article = new JSONObject(); final String articleId = cachedPageContentObject.optString(PageCaches.CACHED_OID); article.put(Keys.OBJECT_ID, articleId); article.put( Article.ARTICLE_VIEW_PWD, cachedPageContentObject.optString(PageCaches.CACHED_PWD)); if (articles.needViewPwd(httpServletRequest, article)) { article = articleRepository.get(articleId); // Loads the article entity final HttpServletResponse httpServletResponse = (HttpServletResponse) response; try { httpServletResponse.sendRedirect( Latkes.getServePath() + "/console/article-pwd" + articles.buildArticleViewPwdFormParameters(article)); return; } catch (final Exception e) { httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); return; } } } } catch (final Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); chain.doFilter(request, response); } try { LOGGER.log( Level.FINEST, "Writes resposne for page[pageCacheKey={0}] from cache", pageCacheKey); response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); final PrintWriter writer = response.getWriter(); String cachedPageContent = cachedPageContentObject.getString(PageCaches.CACHED_CONTENT); final String topBarHTML = TopBars.getTopBarHTML((HttpServletRequest) request, (HttpServletResponse) response); cachedPageContent = cachedPageContent.replace(Common.TOP_BAR_REPLACEMENT_FLAG, topBarHTML); final String cachedTitle = cachedPageContentObject.getString(PageCaches.CACHED_TITLE); LOGGER.log( Level.FINEST, "Cached value[key={0}, type={1}, title={2}]", new Object[] {pageCacheKey, cachedType, cachedTitle}); statistics.incBlogViewCount((HttpServletRequest) request, (HttpServletResponse) response); final long endimeMillis = System.currentTimeMillis(); final String dateString = DateFormatUtils.format(endimeMillis, "yyyy/MM/dd HH:mm:ss"); final String msg = String.format( "<!-- Cached by B3log Solo(%1$d ms), %2$s -->", endimeMillis - startTimeMillis, dateString); LOGGER.finer(msg); cachedPageContent += Strings.LINE_SEPARATOR + msg; writer.write(cachedPageContent); writer.flush(); writer.close(); } catch (final JSONException e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); chain.doFilter(request, response); } catch (final RepositoryException e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); chain.doFilter(request, response); } catch (final ServiceException e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); chain.doFilter(request, response); } }
@Override public void action(final Event<JSONObject> event) throws EventException { final JSONObject data = event.getData(); LOGGER.log( Level.DEBUG, "Processing an event[type={0}, data={1}] in listener[className={2}]", new Object[] {event.getType(), data, CommentNotifier.class.getName()}); try { final JSONObject originalArticle = data.getJSONObject(Article.ARTICLE); final JSONObject originalComment = data.getJSONObject(Comment.COMMENT); final String commentContent = originalComment.optString(Comment.COMMENT_CONTENT); final JSONObject commenter = userQueryService.getUser(originalComment.optString(Comment.COMMENT_AUTHOR_ID)); final String commenterName = commenter.optString(User.USER_NAME); // 0. Data channel (WebSocket) final JSONObject chData = new JSONObject(); chData.put(Article.ARTICLE_T_ID, originalArticle.optString(Keys.OBJECT_ID)); chData.put(Comment.COMMENT_T_ID, originalComment.optString(Keys.OBJECT_ID)); chData.put(Comment.COMMENT_T_AUTHOR_NAME, commenterName); final String userEmail = commenter.optString(User.USER_EMAIL); chData.put( Comment.COMMENT_T_AUTHOR_THUMBNAIL_URL, avatarQueryService.getAvatarURL(userEmail)); chData.put(Common.THUMBNAIL_UPDATE_TIME, commenter.optLong(UserExt.USER_UPDATE_TIME)); chData.put( Comment.COMMENT_CREATE_TIME, DateFormatUtils.format( new Date(originalComment.optLong(Comment.COMMENT_CREATE_TIME)), "yyyy-MM-dd HH:mm")); String cc = shortLinkQueryService.linkArticle(commentContent); cc = shortLinkQueryService.linkTag(cc); cc = Emotions.convert(cc); cc = Markdowns.toHTML(cc); cc = Markdowns.clean(cc, ""); try { final Set<String> userNames = userQueryService.getUserNames(commentContent); for (final String userName : userNames) { cc = cc.replace( '@' + userName, "@<a href='" + Latkes.getServePath() + "/member/" + userName + "'>" + userName + "</a>"); } } catch (final ServiceException e) { LOGGER.log(Level.ERROR, "Generates @username home URL for comment content failed", e); } chData.put(Comment.COMMENT_CONTENT, cc); ArticleChannel.notifyComment(chData); // + Article Heat final JSONObject articleHeat = new JSONObject(); articleHeat.put(Article.ARTICLE_T_ID, originalArticle.optString(Keys.OBJECT_ID)); articleHeat.put(Common.OPERATION, "+"); ArticleListChannel.notifyHeat(articleHeat); final boolean isDiscussion = originalArticle.optInt(Article.ARTICLE_TYPE) == Article.ARTICLE_TYPE_C_DISCUSSION; // Timeline if (!isDiscussion) { final String articleTitle = StringUtils.substring( Jsoup.parse(originalArticle.optString(Article.ARTICLE_TITLE)).text(), 0, 28); final String articlePermalink = Latkes.getServePath() + originalArticle.optString(Article.ARTICLE_PERMALINK); final JSONObject timeline = new JSONObject(); timeline.put(Common.TYPE, Comment.COMMENT); String content = langPropsService.get("timelineCommentLabel"); content = content .replace( "{user}", "<a target='_blank' rel='nofollow' href='" + Latkes.getServePath() + "/member/" + commenterName + "'>" + commenterName + "</a>") .replace( "{article}", "<a target='_blank' rel='nofollow' href='" + articlePermalink + "'>" + articleTitle + "</a>") .replace("{comment}", StringUtils.substring(Jsoup.parse(cc).text(), 0, 28)); timeline.put(Common.CONTENT, content); timelineMgmtService.addTimeline(timeline); } // 1. 'Commented' Notification final String articleAuthorId = originalArticle.optString(Article.ARTICLE_AUTHOR_ID); final Set<String> atUserNames = userQueryService.getUserNames(commentContent); final boolean commenterIsArticleAuthor = articleAuthorId.equals(originalComment.optString(Comment.COMMENT_AUTHOR_ID)); if (commenterIsArticleAuthor && atUserNames.isEmpty()) { return; } atUserNames.remove(commenterName); // Do not notify commenter itself if (!commenterIsArticleAuthor) { final JSONObject requestJSONObject = new JSONObject(); requestJSONObject.put(Notification.NOTIFICATION_USER_ID, articleAuthorId); requestJSONObject.put( Notification.NOTIFICATION_DATA_ID, originalComment.optString(Keys.OBJECT_ID)); notificationMgmtService.addCommentedNotification(requestJSONObject); } final String articleContent = originalArticle.optString(Article.ARTICLE_CONTENT); final Set<String> articleContentAtUserNames = userQueryService.getUserNames(articleContent); // 2. 'At' Notification for (final String userName : atUserNames) { if (isDiscussion && !articleContentAtUserNames.contains(userName)) { continue; } final JSONObject user = userQueryService.getUserByName(userName); if (null == user) { LOGGER.log(Level.WARN, "Not found user by name [{0}]", userName); continue; } if (user.optString(Keys.OBJECT_ID).equals(articleAuthorId)) { continue; // Has added in step 1 } final JSONObject requestJSONObject = new JSONObject(); requestJSONObject.put(Notification.NOTIFICATION_USER_ID, user.optString(Keys.OBJECT_ID)); requestJSONObject.put( Notification.NOTIFICATION_DATA_ID, originalComment.optString(Keys.OBJECT_ID)); notificationMgmtService.addAtNotification(requestJSONObject); } } catch (final Exception e) { LOGGER.log(Level.ERROR, "Sends the comment notification failed", e); } }
@Override public void action(final Event<JSONObject> event) throws EventException { final JSONObject data = event.getData(); LOGGER.log( Level.DEBUG, "Processing an event[type={0}, data={1}] in listener[className={2}]", new Object[] {event.getType(), data, ArticleNotifier.class.getName()}); try { final JSONObject originalArticle = data.getJSONObject(Article.ARTICLE); final String articleId = originalArticle.optString(Keys.OBJECT_ID); final String articleAuthorId = originalArticle.optString(Article.ARTICLE_AUTHOR_ID); final JSONObject articleAuthor = userQueryService.getUser(articleAuthorId); final String articleAuthorName = articleAuthor.optString(User.USER_NAME); final String articleContent = originalArticle.optString(Article.ARTICLE_CONTENT); final Set<String> atUserNames = userQueryService.getUserNames(articleContent); atUserNames.remove(articleAuthorName); // Do not notify the author itself final Set<String> atedUserIds = new HashSet<String>(); // 'At' Notification for (final String userName : atUserNames) { final JSONObject user = userQueryService.getUserByName(userName); if (null == user) { LOGGER.log(Level.WARN, "Not found user by name [{0}]", userName); continue; } final JSONObject requestJSONObject = new JSONObject(); final String atedUserId = user.optString(Keys.OBJECT_ID); requestJSONObject.put(Notification.NOTIFICATION_USER_ID, atedUserId); requestJSONObject.put(Notification.NOTIFICATION_DATA_ID, articleId); notificationMgmtService.addAtNotification(requestJSONObject); atedUserIds.add(atedUserId); } // 'FollowingUser' Notification final JSONObject followerUsersResult = followQueryService.getFollowerUsers(articleAuthorId, 1, Integer.MAX_VALUE); @SuppressWarnings("unchecked") final List<JSONObject> followerUsers = (List) followerUsersResult.opt(Keys.RESULTS); for (final JSONObject followerUser : followerUsers) { final JSONObject requestJSONObject = new JSONObject(); final String followerUserId = followerUser.optString(Keys.OBJECT_ID); if (atedUserIds.contains(followerUserId)) { continue; } requestJSONObject.put(Notification.NOTIFICATION_USER_ID, followerUserId); requestJSONObject.put(Notification.NOTIFICATION_DATA_ID, articleId); notificationMgmtService.addFollowingUserNotification(requestJSONObject); } // Timeline final String articleTitle = StringUtils.substring( Jsoup.parse(originalArticle.optString(Article.ARTICLE_TITLE)).text(), 0, 28); final String articlePermalink = Latkes.getServePath() + originalArticle.optString(Article.ARTICLE_PERMALINK); final JSONObject timeline = new JSONObject(); timeline.put(Common.TYPE, Article.ARTICLE); String content = langPropsService.get("timelineArticleLabel"); content = content .replace( "{user}", "<a target='_blank' rel='nofollow' href='" + Latkes.getServePath() + "/member/" + articleAuthorName + "'>" + articleAuthorName + "</a>") .replace( "{article}", "<a target='_blank' rel='nofollow' href='" + articlePermalink + "'>" + articleTitle + "</a>"); timeline.put(Common.CONTENT, content); timelineMgmtService.addTimeline(timeline); // 'Broadcast' Notification if (Article.ARTICLE_TYPE_C_CITY_BROADCAST == originalArticle.optInt(Article.ARTICLE_TYPE)) { final String city = originalArticle.optString(Article.ARTICLE_CITY); if (StringUtils.isNotBlank(city)) { final JSONObject requestJSONObject = new JSONObject(); requestJSONObject.put(Pagination.PAGINATION_CURRENT_PAGE_NUM, 1); requestJSONObject.put(Pagination.PAGINATION_PAGE_SIZE, Integer.MAX_VALUE); requestJSONObject.put(Pagination.PAGINATION_WINDOW_SIZE, Integer.MAX_VALUE); final long latestLoginTime = DateUtils.addDays(new Date(), -15).getTime(); requestJSONObject.put(UserExt.USER_LATEST_LOGIN_TIME, latestLoginTime); requestJSONObject.put(UserExt.USER_CITY, city); final JSONObject result = userQueryService.getUsersByCity(requestJSONObject); final JSONArray users = result.optJSONArray(User.USERS); for (int i = 0; i < users.length(); i++) { final String userId = users.optJSONObject(i).optString(Keys.OBJECT_ID); if (userId.equals(articleAuthorId)) { continue; } final JSONObject notification = new JSONObject(); notification.put(Notification.NOTIFICATION_USER_ID, userId); notification.put(Notification.NOTIFICATION_DATA_ID, articleId); notificationMgmtService.addBroadcastNotification(notification); } LOGGER.info("City broadcast [" + users.length() + "]"); } } } catch (final Exception e) { LOGGER.log(Level.ERROR, "Sends the article notification failed", e); } }
/** * Gets the user comments with the specified user id, page number and page size. * * @param userId the specified user id * @param currentPageNum the specified page number * @param pageSize the specified page size * @param viewer the specified viewer, may be {@code null} * @return user comments, return an empty list if not found * @throws ServiceException service exception */ public List<JSONObject> getUserComments( final String userId, final int currentPageNum, final int pageSize, final JSONObject viewer) throws ServiceException { final Query query = new Query() .addSort(Comment.COMMENT_CREATE_TIME, SortDirection.DESCENDING) .setCurrentPageNum(currentPageNum) .setPageSize(pageSize) .setFilter(new PropertyFilter(Comment.COMMENT_AUTHOR_ID, FilterOperator.EQUAL, userId)); try { final JSONObject result = commentRepository.get(query); final List<JSONObject> ret = CollectionUtils.<JSONObject>jsonArrayToList(result.optJSONArray(Keys.RESULTS)); for (final JSONObject comment : ret) { comment.put( Comment.COMMENT_CREATE_TIME, new Date(comment.optLong(Comment.COMMENT_CREATE_TIME))); final String articleId = comment.optString(Comment.COMMENT_ON_ARTICLE_ID); final JSONObject article = articleRepository.get(articleId); comment.put( Comment.COMMENT_T_ARTICLE_TITLE, Article.ARTICLE_STATUS_C_INVALID == article.optInt(Article.ARTICLE_STATUS) ? langPropsService.get("articleTitleBlockLabel") : Emotions.convert(article.optString(Article.ARTICLE_TITLE))); comment.put(Comment.COMMENT_T_ARTICLE_TYPE, article.optInt(Article.ARTICLE_TYPE)); comment.put( Comment.COMMENT_T_ARTICLE_PERMALINK, article.optString(Article.ARTICLE_PERMALINK)); final JSONObject commenter = userRepository.get(userId); comment.put(Comment.COMMENT_T_COMMENTER, commenter); final String articleAuthorId = article.optString(Article.ARTICLE_AUTHOR_ID); final JSONObject articleAuthor = userRepository.get(articleAuthorId); final String articleAuthorName = articleAuthor.optString(User.USER_NAME); final String articleAuthorURL = "/member/" + articleAuthor.optString(User.USER_NAME); comment.put(Comment.COMMENT_T_ARTICLE_AUTHOR_NAME, articleAuthorName); comment.put(Comment.COMMENT_T_ARTICLE_AUTHOR_URL, articleAuthorURL); final String articleAuthorEmail = articleAuthor.optString(User.USER_EMAIL); final String articleAuthorThumbnailURL = avatarQueryService.getAvatarURL(articleAuthorEmail); comment.put(Comment.COMMENT_T_ARTICLE_AUTHOR_THUMBNAIL_URL, articleAuthorThumbnailURL); if (Article.ARTICLE_TYPE_C_DISCUSSION == article.optInt(Article.ARTICLE_TYPE)) { final String msgContent = langPropsService .get("articleDiscussionLabel") .replace( "{user}", "<a href='" + Latkes.getServePath() + "/member/" + articleAuthorName + "'>" + articleAuthorName + "</a>"); if (null == viewer) { comment.put(Comment.COMMENT_CONTENT, msgContent); } else { final String commenterName = commenter.optString(User.USER_NAME); final String viewerUserName = viewer.optString(User.USER_NAME); final String viewerRole = viewer.optString(User.USER_ROLE); if (!commenterName.equals(viewerUserName) && !Role.ADMIN_ROLE.equals(viewerRole)) { final String articleContent = article.optString(Article.ARTICLE_CONTENT); final Set<String> userNames = userQueryService.getUserNames(articleContent); boolean invited = false; for (final String userName : userNames) { if (userName.equals(viewerUserName)) { invited = true; break; } } if (!invited) { comment.put(Comment.COMMENT_CONTENT, msgContent); } } } } processCommentContent(comment); } return ret; } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets user comments failed", e); throw new ServiceException(e); } }