/** * 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); } }
/** * 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); } }
@Override public void doAdvice(final HTTPRequestContext context, final Object ret) { final AbstractHTTPResponseRenderer renderer = context.getRenderer(); if (null != renderer) { final Map<String, Object> dataModel = renderer.getRenderDataModel(); dataModel.put(Common.CSRF_TOKEN, Sessions.getCSRFToken(context.getRequest())); } }
/** * Logout. * * @param context the specified context * @throws IOException io exception */ @RequestProcessing(value = "/logout", method = HTTPRequestMethod.GET) public void logout(final HTTPRequestContext context) throws IOException { final HttpServletRequest httpServletRequest = context.getRequest(); Sessions.logout(httpServletRequest, context.getResponse()); String destinationURL = httpServletRequest.getParameter(Common.GOTO); if (Strings.isEmptyOrNull(destinationURL)) { destinationURL = "/"; } context.getResponse().sendRedirect(destinationURL); }
/** * {@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); } }
/** * Mobile logins user. * * @param context the specified context * @param request the specified request * @param response the specified response * @throws ServletException servlet exception * @throws IOException io exception * @throws JSONException JSONException */ @RequestProcessing(value = "/oauth/token", method = HTTPRequestMethod.POST) public void mobileLogin( final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException, JSONException { final String error = "invalid grant"; final String errorDescription = "The provided authorization grant is invalid, expired, revoked, does not match"; final JSONRenderer renderer = new JSONRenderer(); context.setRenderer(renderer); final JSONObject ret = new JSONObject(); renderer.setJSONObject(ret); final String username = request.getParameter("username"); final String password = request.getParameter("password"); try { JSONObject user = userQueryService.getUserByName(username); if (null == user) { user = userQueryService.getUserByEmail(username); } if (null == user || null == password) { ret.put("error", error); ret.put("error_description", errorDescription); return; } if (UserExt.USER_STATUS_C_INVALID == user.optInt(UserExt.USER_STATUS) || UserExt.USER_STATUS_C_INVALID_LOGIN == user.optInt(UserExt.USER_STATUS)) { userMgmtService.updateOnlineStatus(user.optString(Keys.OBJECT_ID), "", false); ret.put("error", error); ret.put("error_description", errorDescription); return; } final String userPassword = user.optString(User.USER_PASSWORD); if (userPassword.equals(MD5.hash(password))) { final String ip = Requests.getRemoteAddr(request); userMgmtService.updateOnlineStatus(user.optString(Keys.OBJECT_ID), ip, true); ret.put( "access_token", "{\"userPassword\":\"" + user.optString(User.USER_PASSWORD) + "\",\"userEmail\":\"" + user.optString(User.USER_EMAIL) + "\"}"); ret.put("token_type", "bearer"); ret.put("scope", "user"); ret.put("created_at", new Date().getTime()); } } catch (final ServiceException e) { ret.put("error", error); ret.put("error_description", errorDescription); } }
@Override public void handle(final HTTPRequestContext context, final HttpControl httpControl) throws Exception { final HttpServletRequest request = context.getRequest(); final long startTimeMillis = System.currentTimeMillis(); request.setAttribute(Keys.HttpRequest.START_TIME_MILLIS, startTimeMillis); httpControl.nextHandler(); }
/** * 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); }
/** * 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 = "/forgot", method = HTTPRequestMethod.POST) public void forgot(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("succeed", false); jsonObject.put(Keys.MSG, langPropsService.get("resetPwdSuccessMsg")); final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, context.getResponse()); final String userEmail = requestJSONObject.getString(User.USER_EMAIL); if (Strings.isEmptyOrNull(userEmail)) { LOGGER.log(Level.WARN, "Why user's email is empty"); 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); jsonObject.put(Keys.MSG, langPropsService.get("userEmailNotFoundMsg")); return; } sendResetUrl(userEmail, jsonObject); } catch (final Exception e) { LOGGER.log(Level.ERROR, e.getMessage(), e); } }
/** * 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); }
/** * 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); }
/** * Shows update article. * * @param context the specified context * @param request the specified request * @param response the specified response * @throws Exception exception */ @RequestProcessing(value = "/update", method = HTTPRequestMethod.GET) @Before(adviceClass = {StopwatchStartAdvice.class, LoginCheck.class}) @After(adviceClass = {CSRFToken.class, StopwatchEndAdvice.class}) public void showUpdateArticle( final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response) throws Exception { final String articleId = request.getParameter("id"); if (Strings.isEmptyOrNull(articleId)) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } final JSONObject article = articleQueryService.getArticleById(articleId); if (null == article) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } final JSONObject currentUser = Sessions.currentUser(request); if (null == currentUser || !currentUser .optString(Keys.OBJECT_ID) .equals(article.optString(Article.ARTICLE_AUTHOR_ID))) { response.sendError(HttpServletResponse.SC_FORBIDDEN); return; } final AbstractFreeMarkerRenderer renderer = new SkinRenderer(); context.setRenderer(renderer); renderer.setTemplateName("/home/post.ftl"); final Map<String, Object> dataModel = renderer.getDataModel(); dataModel.put(Article.ARTICLE, article); filler.fillHeaderAndFooter(request, response, dataModel); // Qiniu file upload authenticate final Auth auth = Auth.create(Symphonys.get("qiniu.accessKey"), Symphonys.get("qiniu.secretKey")); final String uploadToken = auth.uploadToken(Symphonys.get("qiniu.bucket")); dataModel.put("qiniuUploadToken", uploadToken); dataModel.put("qiniuDomain", Symphonys.get("qiniu.domain")); }
/** * Shows pre-add article. * * @param context the specified context * @param request the specified request * @param response the specified response * @throws Exception exception */ @RequestProcessing(value = "/pre-post", method = HTTPRequestMethod.GET) @Before(adviceClass = {StopwatchStartAdvice.class, LoginCheck.class}) @After(adviceClass = {CSRFToken.class, StopwatchEndAdvice.class}) public void showPreAddArticle( final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response) throws Exception { final AbstractFreeMarkerRenderer renderer = new SkinRenderer(); context.setRenderer(renderer); renderer.setTemplateName("/home/pre-post.ftl"); final Map<String, Object> dataModel = renderer.getDataModel(); filler.fillHeaderAndFooter(request, response, dataModel); }
/** * 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); }
/** * Article rewards. * * @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 = "/article/reward", method = HTTPRequestMethod.POST) @Before(adviceClass = StopwatchStartAdvice.class) @After(adviceClass = StopwatchEndAdvice.class) public void reward( final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context) throws Exception { final JSONObject currentUser = userQueryService.getCurrentUser(request); if (null == currentUser) { response.sendError(HttpServletResponse.SC_FORBIDDEN); return; } final String articleId = request.getParameter(Article.ARTICLE_T_ID); if (Strings.isEmptyOrNull(articleId)) { response.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } final JSONRenderer renderer = new JSONRenderer(); context.setRenderer(renderer); final JSONObject result = Results.falseResult(); renderer.setJSONObject(result); try { articleMgmtService.reward(articleId, currentUser.optString(Keys.OBJECT_ID)); } catch (final ServiceException e) { result.put(Keys.MSG, langPropsService.get("transferFailLabel")); return; } final JSONObject article = articleQueryService.getArticle(articleId); if (null == article) { return; } result.put(Keys.STATUS_CODE, true); articleQueryService.processArticleContent(article, request); result.put(Article.ARTICLE_REWARD_CONTENT, article.optString(Article.ARTICLE_REWARD_CONTENT)); }
/** * Updates an article remotely. * * <p>This interface will be called by Rhythm, so here is no article data validation, just only * validate the B3 key. * * <p>The request json object, for example, * * <pre> * { * "article": { * "articleAuthorEmail": "*****@*****.**", * "articleContent": "<p>test<\/p>", * "articleCreateDate": 1350635469922, * "articlePermalink": "/articles/2012/10/19/1350635469866.html", * "articleTags": "test", * "articleTitle": "test", * "clientArticleId": "1350635469866", * "oId": "1350635469866" * }, * "clientAdminEmail": "*****@*****.**", * "clientHost": "http://localhost:11099", * "clientName": "B3log Solo", * "clientTitle": "简约设计の艺术", * "clientRuntimeEnv": "LOCAL", * "clientVersion": "0.5.0", * "symphonyKey": "....", * "userB3Key": "Your key" * } * </pre> * * @param context the specified context * @param request the specified request * @param response the specified response * @throws Exception exception */ @RequestProcessing(value = "/rhythm/article", method = HTTPRequestMethod.PUT) @Before(adviceClass = StopwatchStartAdvice.class) @After(adviceClass = StopwatchEndAdvice.class) public void updateArticleFromRhythm( final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response) throws Exception { final JSONRenderer renderer = new JSONRenderer(); context.setRenderer(renderer); final JSONObject ret = Results.falseResult(); renderer.setJSONObject(ret); final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, response); final String userB3Key = requestJSONObject.getString(UserExt.USER_B3_KEY); final String symphonyKey = requestJSONObject.getString(Common.SYMPHONY_KEY); final String clientAdminEmail = requestJSONObject.getString(Client.CLIENT_ADMIN_EMAIL); final String clientName = requestJSONObject.getString(Client.CLIENT_NAME); final String clientTitle = requestJSONObject.getString(Client.CLIENT_T_TITLE); final String clientVersion = requestJSONObject.getString(Client.CLIENT_VERSION); final String clientHost = requestJSONObject.getString(Client.CLIENT_HOST); final String clientRuntimeEnv = requestJSONObject.getString(Client.CLIENT_RUNTIME_ENV); final String maybeIP = StringUtils.substringBetween(clientHost, "://", ":"); if (Networks.isIPv4(maybeIP)) { LOGGER.log( Level.WARN, "Sync update article error, caused by the client host [{0}] is invalid", clientHost); return; } final JSONObject user = userQueryService.getUserByEmail(clientAdminEmail); if (null == user) { LOGGER.log( Level.WARN, "The user[email={0}, host={1}] not found in community", clientAdminEmail, clientHost); return; } final String userName = user.optString(User.USER_NAME); if (!Symphonys.get("keyOfSymphony").equals(symphonyKey) || !user.optString(UserExt.USER_B3_KEY).equals(userB3Key)) { LOGGER.log( Level.WARN, "B3 key not match, ignored update article [name={0}, host={1}]", userName, clientHost); return; } if (UserExt.USER_STATUS_C_VALID != user.optInt(UserExt.USER_STATUS)) { LOGGER.log( Level.WARN, "The user[name={0}, host={1}] has been forbidden", userName, clientHost); return; } final JSONObject originalArticle = requestJSONObject.getJSONObject(Article.ARTICLE); final String articleTitle = originalArticle.optString(Article.ARTICLE_TITLE); String articleTags = articleMgmtService.formatArticleTags(originalArticle.optString(Article.ARTICLE_TAGS)); String articleContent = originalArticle.optString(Article.ARTICLE_CONTENT); final String permalink = originalArticle.optString(Article.ARTICLE_PERMALINK); articleContent += "<p class='fn-clear'><span class='fn-right'><span class='ft-small'>该文章同步自</span> " + "<i style='margin-right:5px;'><a target='_blank' href='" + clientHost + permalink + "'>" + clientTitle + "</a></i></span></p>"; final String authorId = user.optString(Keys.OBJECT_ID); final String clientArticleId = originalArticle.optString(Keys.OBJECT_ID); final JSONObject oldArticle = articleQueryService.getArticleByClientArticleId(authorId, clientArticleId); if (null == oldArticle) { LOGGER.log( Level.WARN, "Not found article [clientHost={0}, clientArticleId={1}] to update", clientHost, clientArticleId); return; } final JSONObject article = new JSONObject(); article.put(Keys.OBJECT_ID, oldArticle.optString(Keys.OBJECT_ID)); article.put(Article.ARTICLE_TITLE, articleTitle); article.put(Article.ARTICLE_CONTENT, articleContent); article.put(Article.ARTICLE_EDITOR_TYPE, 0); article.put(Article.ARTICLE_SYNC_TO_CLIENT, false); article.put(Article.ARTICLE_CLIENT_ARTICLE_ID, clientArticleId); article.put(Article.ARTICLE_AUTHOR_ID, authorId); article.put(Article.ARTICLE_AUTHOR_EMAIL, clientAdminEmail.toLowerCase().trim()); article.put(Article.ARTICLE_T_IS_BROADCAST, false); if (!Role.ADMIN_ROLE.equals(user.optString(User.USER_ROLE))) { articleTags = articleMgmtService.filterReservedTags(articleTags); } try { if (Strings.isEmptyOrNull(articleTags)) { throw new ServiceException(langPropsService.get("articleTagReservedLabel")); } article.put(Article.ARTICLE_TAGS, articleTags); articleMgmtService.updateArticle(article); ret.put(Keys.STATUS_CODE, true); } catch (final ServiceException e) { final String msg = langPropsService.get("updateFailLabel") + " - " + e.getMessage(); LOGGER.log(Level.ERROR, msg, e); ret.put(Keys.MSG, msg); } // Updates client record JSONObject client = clientQueryService.getClientByAdminEmail(clientAdminEmail); if (null == client) { client = new JSONObject(); client.put(Client.CLIENT_ADMIN_EMAIL, clientAdminEmail); client.put(Client.CLIENT_HOST, clientHost); client.put(Client.CLIENT_NAME, clientName); client.put(Client.CLIENT_RUNTIME_ENV, clientRuntimeEnv); client.put(Client.CLIENT_VERSION, clientVersion); client.put(Client.CLIENT_LATEST_ADD_COMMENT_TIME, 0L); client.put(Client.CLIENT_LATEST_ADD_ARTICLE_TIME, System.currentTimeMillis()); clientMgmtService.addClient(client); } else { client.put(Client.CLIENT_ADMIN_EMAIL, clientAdminEmail); client.put(Client.CLIENT_HOST, clientHost); client.put(Client.CLIENT_NAME, clientName); client.put(Client.CLIENT_RUNTIME_ENV, clientRuntimeEnv); client.put(Client.CLIENT_VERSION, clientVersion); client.put(Client.CLIENT_LATEST_ADD_ARTICLE_TIME, System.currentTimeMillis()); clientMgmtService.updateClient(client); } }
/** * Updates an article locally. * * <p>The request json object (an article): * * <pre> * { * "articleTitle": "", * "articleTags": "", // Tags spliting by ',' * "articleContent": "", * "articleCommentable": boolean, * "articleType": int, * "articleRewardContent": "", * "articleRewardPoint": int * } * </pre> * * @param context the specified context * @param request the specified request * @param response the specified response * @param id the specified article id * @throws Exception exception */ @RequestProcessing(value = "/article/{id}", method = HTTPRequestMethod.PUT) @Before( adviceClass = { StopwatchStartAdvice.class, LoginCheck.class, CSRFCheck.class, ArticleUpdateValidation.class }) @After(adviceClass = StopwatchEndAdvice.class) public void updateArticle( final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response, final String id) throws Exception { if (Strings.isEmptyOrNull(id)) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } final JSONObject oldArticle = articleQueryService.getArticleById(id); if (null == oldArticle) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } final JSONRenderer renderer = new JSONRenderer(); context.setRenderer(renderer); final JSONObject ret = Results.falseResult(); renderer.setJSONObject(ret); final JSONObject requestJSONObject = (JSONObject) request.getAttribute(Keys.REQUEST); final String articleTitle = requestJSONObject.optString(Article.ARTICLE_TITLE); String articleTags = requestJSONObject.optString(Article.ARTICLE_TAGS); final String articleContent = requestJSONObject.optString(Article.ARTICLE_CONTENT); // final boolean articleCommentable = requestJSONObject.optBoolean(Article.ARTICLE_COMMENTABLE); final boolean articleCommentable = true; final int articleType = requestJSONObject.optInt(Article.ARTICLE_TYPE, Article.ARTICLE_TYPE_C_NORMAL); final String articleRewardContent = requestJSONObject.optString(Article.ARTICLE_REWARD_CONTENT); final int articleRewardPoint = requestJSONObject.optInt(Article.ARTICLE_REWARD_POINT); final JSONObject article = new JSONObject(); article.put(Keys.OBJECT_ID, id); article.put(Article.ARTICLE_TITLE, articleTitle); article.put(Article.ARTICLE_CONTENT, articleContent); article.put(Article.ARTICLE_EDITOR_TYPE, 0); article.put(Article.ARTICLE_COMMENTABLE, articleCommentable); article.put(Article.ARTICLE_TYPE, articleType); article.put(Article.ARTICLE_REWARD_CONTENT, articleRewardContent); article.put(Article.ARTICLE_REWARD_POINT, articleRewardPoint); final JSONObject currentUser = (JSONObject) request.getAttribute(User.USER); if (null == currentUser || !currentUser .optString(Keys.OBJECT_ID) .equals(oldArticle.optString(Article.ARTICLE_AUTHOR_ID))) { response.sendError(HttpServletResponse.SC_FORBIDDEN); return; } article.put(Article.ARTICLE_AUTHOR_ID, currentUser.optString(Keys.OBJECT_ID)); final String authorEmail = currentUser.optString(User.USER_EMAIL); article.put(Article.ARTICLE_AUTHOR_EMAIL, authorEmail); if (!Role.ADMIN_ROLE.equals(currentUser.optString(User.USER_ROLE))) { articleTags = articleMgmtService.filterReservedTags(articleTags); } try { if (Strings.isEmptyOrNull(articleTags)) { throw new ServiceException(langPropsService.get("articleTagReservedLabel")); } article.put(Article.ARTICLE_TAGS, articleTags); articleMgmtService.updateArticle(article); ret.put(Keys.STATUS_CODE, true); } catch (final ServiceException e) { final String msg = e.getMessage(); LOGGER.log( Level.ERROR, "Adds article[title=" + articleTitle + "] failed: {0}", e.getMessage()); ret.put(Keys.MSG, msg); } }
@Override public void doAdvice(final HTTPRequestContext context, final Map<String, Object> args) throws RequestProcessAdviceException { final String requestURI = context.getRequest().getRequestURI(); Stopwatchs.start("Request URI [" + requestURI + ']'); }
/** * Shows article with the specified article id. * * @param context the specified context * @param request the specified request * @param response the specified response * @param articleId the specified article id * @throws Exception exception */ @RequestProcessing(value = "/article/{articleId}", method = HTTPRequestMethod.GET) @Before(adviceClass = StopwatchStartAdvice.class) @After(adviceClass = {CSRFToken.class, StopwatchEndAdvice.class}) public void showArticle( final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response, final String articleId) throws Exception { final AbstractFreeMarkerRenderer renderer = new SkinRenderer(); context.setRenderer(renderer); renderer.setTemplateName("/article.ftl"); final Map<String, Object> dataModel = renderer.getDataModel(); final JSONObject article = articleQueryService.getArticleById(articleId); if (null == article) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } final HttpSession session = request.getSession(false); if (null != session) { session.setAttribute(Article.ARTICLE_T_ID, articleId); } filler.fillHeaderAndFooter(request, response, dataModel); final String authorEmail = article.optString(Article.ARTICLE_AUTHOR_EMAIL); final JSONObject author = userQueryService.getUserByEmail(authorEmail); article.put(Article.ARTICLE_T_AUTHOR_NAME, author.optString(User.USER_NAME)); article.put(Article.ARTICLE_T_AUTHOR_URL, author.optString(User.USER_URL)); article.put(Article.ARTICLE_T_AUTHOR_INTRO, author.optString(UserExt.USER_INTRO)); dataModel.put(Article.ARTICLE, article); article.put(Common.IS_MY_ARTICLE, false); article.put(Article.ARTICLE_T_AUTHOR, author); article.put(Common.REWARDED, false); articleQueryService.processArticleContent(article, request); final boolean isLoggedIn = (Boolean) dataModel.get(Common.IS_LOGGED_IN); JSONObject currentUser; String currentUserId = null; if (isLoggedIn) { currentUser = (JSONObject) dataModel.get(Common.CURRENT_USER); currentUserId = currentUser.optString(Keys.OBJECT_ID); article.put( Common.IS_MY_ARTICLE, currentUserId.equals(article.optString(Article.ARTICLE_AUTHOR_ID))); final boolean isFollowing = followQueryService.isFollowing(currentUserId, articleId); dataModel.put(Common.IS_FOLLOWING, isFollowing); final int vote = voteQueryService.isVoted(currentUserId, articleId); dataModel.put(Vote.VOTE, vote); if (currentUserId.equals(author.optString(Keys.OBJECT_ID))) { article.put(Common.REWARDED, true); } else { article.put( Common.REWARDED, rewardQueryService.isRewarded(currentUserId, articleId, Reward.TYPE_C_ARTICLE)); } } if (!(Boolean) request.getAttribute(Keys.HttpRequest.IS_SEARCH_ENGINE_BOT)) { articleMgmtService.incArticleViewCount(articleId); } filler.fillRelevantArticles(dataModel, article); filler.fillRandomArticles(dataModel); filler.fillHotArticles(dataModel); // Qiniu file upload authenticate final Auth auth = Auth.create(Symphonys.get("qiniu.accessKey"), Symphonys.get("qiniu.secretKey")); final String uploadToken = auth.uploadToken(Symphonys.get("qiniu.bucket")); dataModel.put("qiniuUploadToken", uploadToken); dataModel.put("qiniuDomain", Symphonys.get("qiniu.domain")); dataModel.put(Common.DISCUSSION_VIEWABLE, article.optBoolean(Common.DISCUSSION_VIEWABLE)); if (!article.optBoolean(Common.DISCUSSION_VIEWABLE)) { article.put(Article.ARTICLE_T_COMMENTS, (Object) Collections.emptyList()); return; } String pageNumStr = request.getParameter("p"); if (Strings.isEmptyOrNull(pageNumStr) || !Strings.isNumeric(pageNumStr)) { pageNumStr = "1"; } final int pageNum = Integer.valueOf(pageNumStr); final int pageSize = Symphonys.getInt("articleCommentsPageSize"); final int windowSize = Symphonys.getInt("articleCommentsWindowSize"); final List<JSONObject> articleComments = commentQueryService.getArticleComments(articleId, pageNum, pageSize); article.put(Article.ARTICLE_T_COMMENTS, (Object) articleComments); // Fill reward(thank) for (final JSONObject comment : articleComments) { String thankTemplate = langPropsService.get("thankConfirmLabel"); thankTemplate = thankTemplate .replace("{point}", String.valueOf(Symphonys.getInt("pointThankComment"))) .replace( "{user}", comment.optJSONObject(Comment.COMMENT_T_COMMENTER).optString(User.USER_NAME)); comment.put(Comment.COMMENT_T_THANK_LABEL, thankTemplate); final String commentId = comment.optString(Keys.OBJECT_ID); if (isLoggedIn) { comment.put( Common.REWARDED, rewardQueryService.isRewarded(currentUserId, commentId, Reward.TYPE_C_COMMENT)); } comment.put( Common.REWARED_COUNT, rewardQueryService.rewardedCount(commentId, Reward.TYPE_C_COMMENT)); } final int commentCnt = article.getInt(Article.ARTICLE_COMMENT_CNT); final int pageCount = (int) Math.ceil((double) commentCnt / (double) pageSize); final List<Integer> pageNums = Paginator.paginate(pageNum, pageSize, pageCount, windowSize); if (!pageNums.isEmpty()) { dataModel.put(Pagination.PAGINATION_FIRST_PAGE_NUM, pageNums.get(0)); dataModel.put(Pagination.PAGINATION_LAST_PAGE_NUM, pageNums.get(pageNums.size() - 1)); } dataModel.put(Pagination.PAGINATION_CURRENT_PAGE_NUM, pageNum); dataModel.put(Pagination.PAGINATION_PAGE_COUNT, pageCount); dataModel.put(Pagination.PAGINATION_PAGE_NUMS, pageNums); dataModel.put(Common.ARTICLE_COMMENTS_PAGE_SIZE, pageSize); }
/** * Shows add article. * * @param context the specified context * @param request the specified request * @param response the specified response * @throws Exception exception */ @RequestProcessing(value = "/post", method = HTTPRequestMethod.GET) @Before(adviceClass = {StopwatchStartAdvice.class, LoginCheck.class}) @After(adviceClass = {CSRFToken.class, StopwatchEndAdvice.class}) public void showAddArticle( final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response) throws Exception { final AbstractFreeMarkerRenderer renderer = new SkinRenderer(); context.setRenderer(renderer); renderer.setTemplateName("/home/post.ftl"); final Map<String, Object> dataModel = renderer.getDataModel(); // Qiniu file upload authenticate final Auth auth = Auth.create(Symphonys.get("qiniu.accessKey"), Symphonys.get("qiniu.secretKey")); final String uploadToken = auth.uploadToken(Symphonys.get("qiniu.bucket")); dataModel.put("qiniuUploadToken", uploadToken); dataModel.put("qiniuDomain", Symphonys.get("qiniu.domain")); String tags = request.getParameter(Tag.TAGS); if (StringUtils.isBlank(tags)) { tags = ""; dataModel.put(Tag.TAGS, tags); } else { tags = articleMgmtService.formatArticleTags(tags); final String[] tagTitles = tags.split(","); final StringBuilder tagBuilder = new StringBuilder(); for (final String title : tagTitles) { final String tagTitle = title.trim(); if (Strings.isEmptyOrNull(tagTitle)) { continue; } if (!Tag.TAG_TITLE_PATTERN.matcher(tagTitle).matches()) { continue; } if (Strings.isEmptyOrNull(tagTitle) || tagTitle.length() > Tag.MAX_TAG_TITLE_LENGTH || tagTitle.length() < 1) { continue; } final JSONObject currentUser = (JSONObject) request.getAttribute(User.USER); if (!Role.ADMIN_ROLE.equals(currentUser.optString(User.USER_ROLE)) && ArrayUtils.contains(Symphonys.RESERVED_TAGS, tagTitle)) { continue; } tagBuilder.append(tagTitle).append(","); } if (tagBuilder.length() > 0) { tagBuilder.deleteCharAt(tagBuilder.length() - 1); } dataModel.put(Tag.TAGS, tagBuilder.toString()); } final String type = request.getParameter(Common.TYPE); if (StringUtils.isBlank(type)) { dataModel.put(Article.ARTICLE_TYPE, Article.ARTICLE_TYPE_C_NORMAL); } else { int articleType = Article.ARTICLE_TYPE_C_NORMAL; try { articleType = Integer.valueOf(type); } catch (final Exception e) { LOGGER.log(Level.WARN, "Gets article type error [" + type + "]", e); } if (Article.isInvalidArticleType(articleType)) { articleType = Article.ARTICLE_TYPE_C_NORMAL; } dataModel.put(Article.ARTICLE_TYPE, articleType); } filler.fillHeaderAndFooter(request, response, dataModel); }
/** * 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 doAdvice(final HTTPRequestContext context, final Map<String, Object> args) throws RequestProcessAdviceException { final HttpServletRequest request = context.getRequest(); JSONObject requestJSONObject; try { requestJSONObject = Requests.parseRequestJSONObject(request, context.getResponse()); request.setAttribute(Keys.REQUEST, requestJSONObject); } catch (final Exception e) { throw new RequestProcessAdviceException(new JSONObject().put(Keys.MSG, e.getMessage())); } final String userURL = requestJSONObject.optString(User.USER_URL); if (!Strings.isEmptyOrNull(userURL) && invalidUserURL(userURL)) { throw new RequestProcessAdviceException( new JSONObject() .put( Keys.MSG, "URL" + langPropsService.get("colonLabel") + langPropsService.get("invalidUserURLLabel"))); } final String userQQ = requestJSONObject.optString(UserExt.USER_QQ); if (!Strings.isEmptyOrNull(userQQ) && (!Strings.isNumeric(userQQ) || userQQ.length() > MAX_USER_QQ_LENGTH)) { throw new RequestProcessAdviceException( new JSONObject().put(Keys.MSG, langPropsService.get("invalidUserQQLabel"))); } final String userIntro = requestJSONObject.optString(UserExt.USER_INTRO); if (!Strings.isEmptyOrNull(userIntro) && userIntro.length() > MAX_USER_INTRO_LENGTH) { throw new RequestProcessAdviceException( new JSONObject().put(Keys.MSG, langPropsService.get("invalidUserIntroLabel"))); } final String tagErrMsg = langPropsService.get("selfTagLabel") + langPropsService.get("colonLabel") + langPropsService.get("tagsErrorLabel"); String userTags = requestJSONObject.optString(UserExt.USER_TAGS); if (Strings.isEmptyOrNull(userTags)) { throw new RequestProcessAdviceException(new JSONObject().put(Keys.MSG, tagErrMsg)); } final LatkeBeanManager beanManager = Lifecycle.getBeanManager(); final UserMgmtService userMgmtService = beanManager.getReference(UserMgmtService.class); userTags = userMgmtService.formatUserTags(userTags); String[] tagTitles = userTags.split(","); if (null == tagTitles || 0 == tagTitles.length) { throw new RequestProcessAdviceException(new JSONObject().put(Keys.MSG, tagErrMsg)); } tagTitles = new LinkedHashSet<String>(Arrays.asList(tagTitles)).toArray(new String[0]); final StringBuilder tagBuilder = new StringBuilder(); for (int i = 0; i < tagTitles.length; i++) { final String tagTitle = tagTitles[i].trim(); if (Strings.isEmptyOrNull(tagTitle)) { throw new RequestProcessAdviceException(new JSONObject().put(Keys.MSG, tagErrMsg)); } if (!Tag.TAG_TITLE_PATTERN.matcher(tagTitle).matches()) { throw new RequestProcessAdviceException(new JSONObject().put(Keys.MSG, tagErrMsg)); } if (Strings.isEmptyOrNull(tagTitle) || tagTitle.length() > Tag.MAX_TAG_TITLE_LENGTH || tagTitle.length() < 1) { throw new RequestProcessAdviceException(new JSONObject().put(Keys.MSG, tagErrMsg)); } final JSONObject currentUser = (JSONObject) request.getAttribute(User.USER); if (!Role.ADMIN_ROLE.equals(currentUser.optString(User.USER_ROLE)) && ArrayUtils.contains(Symphonys.RESERVED_TAGS, tagTitle)) { throw new RequestProcessAdviceException( new JSONObject() .put( Keys.MSG, langPropsService.get("selfTagLabel") + langPropsService.get("colonLabel") + langPropsService.get("articleTagReservedLabel") + " [" + tagTitle + "]")); } tagBuilder.append(tagTitle).append(","); } if (tagBuilder.length() > 0) { tagBuilder.deleteCharAt(tagBuilder.length() - 1); } requestJSONObject.put(UserExt.USER_TAGS, tagBuilder.toString()); }
/** * Shows articles related with a tag with the specified context. * * @param context the specified context * @throws IOException io exception */ @RequestProcessing(value = "/tags/**", method = HTTPRequestMethod.GET) public void showTagArticles(final HTTPRequestContext context) throws IOException { final AbstractFreeMarkerRenderer renderer = new FreeMarkerRenderer(); context.setRenderer(renderer); renderer.setTemplateName("tag-articles.ftl"); final Map<String, Object> dataModel = renderer.getDataModel(); final HttpServletRequest request = context.getRequest(); final HttpServletResponse response = context.getResponse(); try { String requestURI = request.getRequestURI(); if (!requestURI.endsWith("/")) { requestURI += "/"; } String tagTitle = getTagTitle(requestURI); final int currentPageNum = getCurrentPageNum(requestURI, tagTitle); if (-1 == currentPageNum) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } LOGGER.log( Level.DEBUG, "Tag[title={0}, currentPageNum={1}]", new Object[] {tagTitle, currentPageNum}); tagTitle = URLDecoder.decode(tagTitle, "UTF-8"); final JSONObject result = tagQueryService.getTagByTitle(tagTitle); if (null == result) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } final JSONObject tag = result.getJSONObject(Tag.TAG); final String tagId = tag.getString(Keys.OBJECT_ID); final JSONObject preference = preferenceQueryService.getPreference(); Skins.fillLangs( preference.optString(Option.ID_C_LOCALE_STRING), (String) request.getAttribute(Keys.TEMAPLTE_DIR_NAME), dataModel); final int pageSize = preference.getInt(Option.ID_C_ARTICLE_LIST_DISPLAY_COUNT); final int windowSize = preference.getInt(Option.ID_C_ARTICLE_LIST_PAGINATION_WINDOW_SIZE); final List<JSONObject> articles = articleQueryService.getArticlesByTag(tagId, currentPageNum, pageSize); if (articles.isEmpty()) { try { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } catch (final IOException ex) { LOGGER.error(ex.getMessage()); } } final boolean hasMultipleUsers = userQueryService.hasMultipleUsers(); if (hasMultipleUsers) { filler.setArticlesExProperties(request, articles, preference); } else { // All articles composed by the same author final JSONObject author = articleQueryService.getAuthor(articles.get(0)); filler.setArticlesExProperties(request, articles, author, preference); } final int tagArticleCount = tag.getInt(Tag.TAG_PUBLISHED_REFERENCE_COUNT); final int pageCount = (int) Math.ceil((double) tagArticleCount / (double) pageSize); LOGGER.log( Level.TRACE, "Paginate tag-articles[currentPageNum={0}, pageSize={1}, pageCount={2}, windowSize={3}]", new Object[] {currentPageNum, pageSize, pageCount, windowSize}); final List<Integer> pageNums = Paginator.paginate(currentPageNum, pageSize, pageCount, windowSize); LOGGER.log(Level.TRACE, "tag-articles[pageNums={0}]", pageNums); Collections.sort(articles, Comparators.ARTICLE_CREATE_DATE_COMPARATOR); fillPagination(dataModel, pageCount, currentPageNum, articles, pageNums); dataModel.put(Common.PATH, "/tags/" + URLEncoder.encode(tagTitle, "UTF-8")); dataModel.put(Keys.OBJECT_ID, tagId); dataModel.put(Tag.TAG, tag); filler.fillSide(request, dataModel, preference); filler.fillBlogHeader(request, response, dataModel, preference); filler.fillBlogFooter(request, dataModel, preference); statisticMgmtService.incBlogViewCount(request, response); } catch (final ServiceException e) { LOGGER.log(Level.ERROR, e.getMessage(), e); try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (final IOException ex) { LOGGER.error(ex.getMessage()); } } catch (final JSONException e) { LOGGER.log(Level.ERROR, e.getMessage(), e); try { response.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (final IOException ex) { LOGGER.error(ex.getMessage()); } } }