Example #1
0
  /**
   * 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);
    }
  }
Example #2
0
  /**
   * 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);
    }
  }
Example #3
0
  @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()));
    }
  }
Example #4
0
  /**
   * 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);
    }
  }
Example #6
0
  /**
   * 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();
  }
Example #8
0
  /**
   * 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);
  }
Example #9
0
  /**
   * 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);
    }
  }
Example #10
0
  /**
   * 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);
  }
Example #14
0
  /**
   * 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": "&lt;p&gt;test&lt;\/p&gt;",
   *         "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());
  }
Example #23
0
  /**
   * 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());
      }
    }
  }