Beispiel #1
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);
    }
  }
  /**
   * Constructs a repository with the specified name.
   *
   * @param name the specified name
   */
  @SuppressWarnings("unchecked")
  public AbstractRepository(final String name) {
    final RuntimeEnv runtimeEnv = Latkes.getRuntimeEnv();

    try {
      Class<Repository> repositoryClass = null;

      switch (runtimeEnv) {
        case BAE:
        case LOCAL:
          final RuntimeDatabase runtimeDatabase = Latkes.getRuntimeDatabase();

          switch (runtimeDatabase) {
            case MYSQL:
              repositoryClass =
                  (Class<Repository>)
                      Class.forName("org.b3log.latke.repository.jdbc.JdbcRepository");
              break;

            case H2:
              repositoryClass =
                  (Class<Repository>)
                      Class.forName("org.b3log.latke.repository.jdbc.JdbcRepository");
              break;

            case NONE:
              repositoryClass =
                  (Class<Repository>) Class.forName("org.b3log.latke.repository.NoneRepository");
              break;

            default:
              throw new RuntimeException(
                  "The runtime database [" + runtimeDatabase + "] is not support NOW!");
          }
          break;

        case GAE:
          repositoryClass =
              (Class<Repository>) Class.forName("org.b3log.latke.repository.gae.GAERepository");
          break;

        default:
          throw new RuntimeException(
              "Latke runs in the hell.... Please set the enviornment correctly");
      }

      final Constructor<Repository> constructor = repositoryClass.getConstructor(String.class);

      repository = constructor.newInstance(name);
    } catch (final Exception e) {
      throw new RuntimeException("Can not initialize repository!", e);
    }

    Repositories.addRepository(repository);
    LOGGER.log(Level.INFO, "Constructed repository[name={0}]", name);
  }
Beispiel #3
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);
    }
  }
  /**
   * {@inheritDoc}
   *
   * <p>Processes page caching.
   */
  @Override
  protected void afterRender(final HTTPRequestContext context) throws Exception {
    final HttpServletRequest request = context.getRequest();
    final String pageContent = (String) request.getAttribute(PageCaches.CACHED_CONTENT);

    if (null == pageContent) {
      return;
    }

    if (Latkes.isPageCacheEnabled()) {
      final String cachedPageKey = (String) request.getAttribute(Keys.PAGE_CACHE_KEY);
      if (Strings.isEmptyOrNull(cachedPageKey)) {
        return;
      }

      LOGGER.log(Level.FINEST, "Caching page[cachedPageKey={0}]", cachedPageKey);

      check(request, pageContent);

      final JSONObject cachedValue = new JSONObject();
      cachedValue.put(PageCaches.CACHED_CONTENT, pageContent);
      cachedValue.put(PageCaches.CACHED_TYPE, request.getAttribute(PageCaches.CACHED_TYPE));
      cachedValue.put(PageCaches.CACHED_OID, request.getAttribute(PageCaches.CACHED_OID));
      cachedValue.put(PageCaches.CACHED_TITLE, request.getAttribute(PageCaches.CACHED_TITLE));
      cachedValue.put(PageCaches.CACHED_LINK, request.getAttribute(PageCaches.CACHED_LINK));
      if (null != request.getAttribute(PageCaches.CACHED_PWD)) {
        cachedValue.put(PageCaches.CACHED_PWD, request.getAttribute(PageCaches.CACHED_PWD));
      }

      PageCaches.put(cachedPageKey, cachedValue, request);
      LOGGER.log(Level.FINEST, "Cached page[cachedPageKey={0}]", cachedPageKey);
    }
  }
  /**
   * Checks whether the specified user-defined permalink is invalid on format.
   *
   * @param permalink the specified user-defined permalink
   * @return {@code true} if invalid, returns {@code false} otherwise
   */
  private static boolean invalidUserDefinedPermalinkFormat(final String permalink) {
    if (Strings.isEmptyOrNull(permalink)) {
      return true;
    }

    if (isReservedLink(permalink)) {
      return true;
    }

    if (Strings.isNumeric(permalink.substring(1))) {
      // See issue 120 (http://code.google.com/p/b3log-solo/issues/detail?id=120#c4) for more
      // details
      return true;
    }

    int slashCnt = 0;

    for (int i = 0; i < permalink.length(); i++) {
      if ('/' == permalink.charAt(i)) {
        slashCnt++;
      }

      if (slashCnt > 1) {
        return true;
      }
    }

    return !Strings.isURL(Latkes.getServer() + permalink);
  }
Beispiel #6
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);
  }
Beispiel #7
0
  /**
   * Gets tag title from the specified URI.
   *
   * @param requestURI the specified request URI
   * @return tag title
   */
  private static String getTagTitle(final String requestURI) {
    final String path = requestURI.substring((Latkes.getContextPath() + "/tags/").length());

    if (path.contains("/")) {
      return path.substring(0, path.indexOf("/"));
    } else {
      return path.substring(0);
    }
  }
Beispiel #8
0
  /**
   * Sends the password resetting URL with a random token.
   *
   * @param userEmail the given email
   * @param jsonObject return code and message object
   * @throws JSONException the JSONException
   * @throws ServiceException the ServiceException
   * @throws IOException the IOException
   * @throws RepositoryException the RepositoryException
   */
  private void sendResetUrl(final String userEmail, final JSONObject jsonObject)
      throws JSONException, ServiceException, IOException, RepositoryException {
    final JSONObject preference = preferenceQueryService.getPreference();
    final String token = new Randoms().nextStringWithMD5();
    final String adminEmail = preference.getString(Preference.ADMIN_EMAIL);
    final String mailSubject = langPropsService.get("resetPwdMailSubject");
    final String mailBody =
        langPropsService.get("resetPwdMailBody")
            + " "
            + Latkes.getServePath()
            + "/forgot?token="
            + token
            + "&login="******"passwordReset");
    option.put(Option.OPTION_VALUE, System.currentTimeMillis());

    final Transaction transaction = optionRepository.beginTransaction();

    optionRepository.add(option);
    transaction.commit();

    message.setFrom(adminEmail);
    message.addRecipient(userEmail);
    message.setSubject(mailSubject);
    message.setHtmlBody(mailBody);

    mailService.send(message);

    jsonObject.put("succeed", true);
    jsonObject.put("to", Latkes.getServePath() + "/login?from=forgot");
    jsonObject.put(Keys.MSG, langPropsService.get("resetPwdSuccessSend"));

    LOGGER.log(
        Level.DEBUG,
        "Sent a mail[mailSubject={0}, mailBody=[{1}] to [{2}]",
        new Object[] {mailSubject, mailBody, userEmail});
  }
Beispiel #9
0
  /**
   * Gets the request page number from the specified request URI and tag title.
   *
   * @param requestURI the specified request URI
   * @param tagTitle the specified tag title
   * @return page number, returns {@code -1} if the specified request URI can not convert to an
   *     number
   */
  private static int getCurrentPageNum(final String requestURI, final String tagTitle) {
    if (Strings.isEmptyOrNull(tagTitle)) {
      return -1;
    }

    final String pageNumString =
        requestURI.substring((Latkes.getContextPath() + "/tags/" + tagTitle + "/").length());

    return Requests.getCurrentPageNum(pageNumString);
  }
Beispiel #10
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);
  }
  /**
   * Markdowns.
   *
   * <p>Renders the response with a json object, for example,
   *
   * <pre>
   * {
   *     "html": ""
   * }
   * </pre>
   *
   * @param request the specified http servlet request
   * @param response the specified http servlet response
   * @param context the specified http request context
   * @throws Exception exception
   */
  @RequestProcessing(value = "/markdown", method = HTTPRequestMethod.POST)
  @Before(adviceClass = StopwatchStartAdvice.class)
  @After(adviceClass = StopwatchEndAdvice.class)
  public void markdown2HTML(
      final HttpServletRequest request,
      final HttpServletResponse response,
      final HTTPRequestContext context)
      throws Exception {
    final JSONRenderer renderer = new JSONRenderer();
    context.setRenderer(renderer);
    final JSONObject result = new JSONObject();
    renderer.setJSONObject(result);

    result.put(Keys.STATUS_CODE, true);

    String markdownText = request.getParameter("markdownText");
    if (Strings.isEmptyOrNull(markdownText)) {
      result.put("html", "");

      return;
    }

    final JSONObject currentUser = userQueryService.getCurrentUser(request);
    if (null == currentUser) {
      response.sendError(HttpServletResponse.SC_FORBIDDEN);

      return;
    }

    final Set<String> userNames = userQueryService.getUserNames(markdownText);
    for (final String userName : userNames) {
      markdownText =
          markdownText.replace(
              '@' + userName,
              "@<a href='"
                  + Latkes.getServePath()
                  + "/member/"
                  + userName
                  + "'>"
                  + userName
                  + "</a>");
    }
    markdownText = shortLinkQueryService.linkArticle(markdownText);
    markdownText = shortLinkQueryService.linkTag(markdownText);
    markdownText = Emotions.convert(markdownText);
    markdownText = Markdowns.toHTML(markdownText);
    markdownText = Markdowns.clean(markdownText, "");

    result.put("html", markdownText);
  }
  // XXX: [Performance Issue] genCommentContentUserName
  private void genCommentContentUserName(final JSONObject comment) {
    String commentContent = comment.optString(Comment.COMMENT_CONTENT);
    try {
      final Set<String> userNames = userQueryService.getUserNames(commentContent);
      for (final String userName : userNames) {
        commentContent =
            commentContent.replace(
                '@' + userName,
                "@<a href='"
                    + Latkes.getServePath()
                    + "/member/"
                    + userName
                    + "'>"
                    + userName
                    + "</a>");
      }
    } catch (final ServiceException e) {
      LOGGER.log(Level.ERROR, "Generates @username home URL for comment content failed", e);
    }

    comment.put(Comment.COMMENT_CONTENT, commentContent);
  }
  static {
    LOGGER.info("Constructing URL Fetch Service....");

    final RuntimeEnv runtimeEnv = Latkes.getRuntimeEnv();

    try {
      Class<URLFetchService> serviceClass;

      switch (runtimeEnv) {
        case BAE:
          // serviceClass = (Class<URLFetchService>)
          // Class.forName("org.b3log.latke.urlfetch.bae.BAEURLFetchService");
          serviceClass =
              (Class<URLFetchService>)
                  Class.forName("org.b3log.latke.urlfetch.local.LocalURLFetchService");
          URL_FETCH_SERVICE = serviceClass.newInstance();
          break;
        case LOCAL:
          serviceClass =
              (Class<URLFetchService>)
                  Class.forName("org.b3log.latke.urlfetch.local.LocalURLFetchService");
          URL_FETCH_SERVICE = serviceClass.newInstance();
          break;
        case GAE:
          serviceClass =
              (Class<URLFetchService>)
                  Class.forName("org.b3log.latke.urlfetch.gae.GAEURLFetchService");
          URL_FETCH_SERVICE = serviceClass.newInstance();
          break;
        default:
          throw new RuntimeException(
              "Latke runs in the hell.... Please set the enviornment correctly");
      }
    } catch (final Exception e) {
      throw new RuntimeException("Can not initialize URL Fetch Service!", e);
    }

    LOGGER.info("Constructed URL Fetch Service");
  }
Beispiel #14
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);
  }
 static {
   Latkes.initRuntimeEnv();
 }
  /**
   * Gets article preview content.
   *
   * <p>Renders the response with a json object, for example,
   *
   * <pre>
   * {
   *     "html": ""
   * }
   * </pre>
   *
   * @param request the specified http servlet request
   * @param response the specified http servlet response
   * @param context the specified http request context
   * @param articleId the specified article id
   * @throws Exception exception
   */
  @RequestProcessing(value = "/article/{articleId}/preview", method = HTTPRequestMethod.GET)
  @Before(adviceClass = StopwatchStartAdvice.class)
  @After(adviceClass = StopwatchEndAdvice.class)
  public void getArticlePreviewContent(
      final HttpServletRequest request,
      final HttpServletResponse response,
      final HTTPRequestContext context,
      final String articleId)
      throws Exception {
    final JSONRenderer renderer = new JSONRenderer();
    context.setRenderer(renderer);
    final JSONObject result = Results.trueResult();
    renderer.setJSONObject(result);

    result.put("html", "");

    final JSONObject article = articleQueryService.getArticle(articleId);
    if (null == article) {
      result.put(Keys.STATUS_CODE, false);

      return;
    }

    final int length = Integer.valueOf("150");
    String content = article.optString(Article.ARTICLE_CONTENT);
    final String authorId = article.optString(Article.ARTICLE_AUTHOR_ID);
    final JSONObject author = userQueryService.getUser(authorId);

    if (null != author && UserExt.USER_STATUS_C_INVALID == author.optInt(UserExt.USER_STATUS)
        || Article.ARTICLE_STATUS_C_INVALID == article.optInt(Article.ARTICLE_STATUS)) {
      result.put("html", langPropsService.get("articleContentBlockLabel"));

      return;
    }

    final Set<String> userNames = userQueryService.getUserNames(content);
    final JSONObject currentUser = userQueryService.getCurrentUser(request);
    final String currentUserName = null == currentUser ? "" : currentUser.optString(User.USER_NAME);
    final String authorName = author.optString(User.USER_NAME);
    if (Article.ARTICLE_TYPE_C_DISCUSSION == article.optInt(Article.ARTICLE_TYPE)
        && !authorName.equals(currentUserName)) {
      boolean invited = false;
      for (final String userName : userNames) {
        if (userName.equals(currentUserName)) {
          invited = true;

          break;
        }
      }

      if (!invited) {
        String blockContent = langPropsService.get("articleDiscussionLabel");
        blockContent =
            blockContent.replace(
                "{user}",
                "<a href='"
                    + Latkes.getServePath()
                    + "/member/"
                    + authorName
                    + "'>"
                    + authorName
                    + "</a>");

        result.put("html", blockContent);

        return;
      }
    }

    content = Emotions.convert(content);
    content = Markdowns.toHTML(content);

    content = Jsoup.clean(content, Whitelist.none());
    if (content.length() >= length) {
      content = StringUtils.substring(content, 0, length) + " ....";
    }

    result.put("html", content);
  }
Beispiel #17
0
  @Override
  public void action(final Event<JSONObject> event) throws EventException {
    final JSONObject data = event.getData();

    LOGGER.log(
        Level.DEBUG,
        "Processing an event[type={0}, data={1}] in listener[className={2}]",
        new Object[] {event.getType(), data, ArticleSender.class.getName()});
    try {
      final JSONObject originalArticle = data.getJSONObject(Article.ARTICLE);

      if (!originalArticle.getBoolean(Article.ARTICLE_IS_PUBLISHED)) {
        LOGGER.log(
            Level.DEBUG,
            "Ignores post article[title={0}] to Rhythm",
            originalArticle.getString(Article.ARTICLE_TITLE));

        return;
      }

      final LatkeBeanManager beanManager = Lifecycle.getBeanManager();
      final PreferenceQueryService preferenceQueryService =
          beanManager.getReference(PreferenceQueryService.class);

      final JSONObject preference = preferenceQueryService.getPreference();

      if (null == preference) {
        throw new EventException("Not found preference");
      }

      if (!Strings.isEmptyOrNull(originalArticle.optString(Article.ARTICLE_VIEW_PWD))) {
        return;
      }

      if (Latkes.getServePath().contains("localhost")) {
        LOGGER.log(
            Level.INFO,
            "Solo runs on local server, so should not send this article[id={0}, title={1}] to Rhythm",
            new Object[] {
              originalArticle.getString(Keys.OBJECT_ID),
              originalArticle.getString(Article.ARTICLE_TITLE)
            });
        return;
      }

      final HTTPRequest httpRequest = new HTTPRequest();

      httpRequest.setURL(ADD_ARTICLE_URL);
      httpRequest.setRequestMethod(HTTPRequestMethod.POST);
      final JSONObject requestJSONObject = new JSONObject();
      final JSONObject article = new JSONObject();

      article.put(Keys.OBJECT_ID, originalArticle.getString(Keys.OBJECT_ID));
      article.put(Article.ARTICLE_TITLE, originalArticle.getString(Article.ARTICLE_TITLE));
      article.put(Article.ARTICLE_PERMALINK, originalArticle.getString(Article.ARTICLE_PERMALINK));
      article.put(Article.ARTICLE_TAGS_REF, originalArticle.getString(Article.ARTICLE_TAGS_REF));
      article.put(
          Article.ARTICLE_AUTHOR_EMAIL, originalArticle.getString(Article.ARTICLE_AUTHOR_EMAIL));
      article.put(Article.ARTICLE_CONTENT, originalArticle.getString(Article.ARTICLE_CONTENT));
      article.put(
          Article.ARTICLE_CREATE_DATE,
          ((Date) originalArticle.get(Article.ARTICLE_CREATE_DATE)).getTime());
      article.put(Common.POST_TO_COMMUNITY, originalArticle.getBoolean(Common.POST_TO_COMMUNITY));

      // Removes this property avoid to persist
      originalArticle.remove(Common.POST_TO_COMMUNITY);

      requestJSONObject.put(Article.ARTICLE, article);
      requestJSONObject.put(Common.BLOG_VERSION, SoloServletListener.VERSION);
      requestJSONObject.put(Common.BLOG, "B3log Solo");
      requestJSONObject.put(Option.ID_C_BLOG_TITLE, preference.getString(Option.ID_C_BLOG_TITLE));
      requestJSONObject.put("blogHost", Latkes.getServePath());
      requestJSONObject.put("userB3Key", preference.optString(Option.ID_C_KEY_OF_SOLO));
      requestJSONObject.put("clientAdminEmail", preference.optString(Option.ID_C_ADMIN_EMAIL));
      requestJSONObject.put("clientRuntimeEnv", Latkes.getRuntimeEnv().name());

      httpRequest.setPayload(requestJSONObject.toString().getBytes("UTF-8"));

      urlFetchService.fetchAsync(httpRequest);
    } catch (final Exception e) {
      LOGGER.log(Level.ERROR, "Sends an article to Rhythm error: {0}", e.getMessage());
    }

    LOGGER.log(Level.DEBUG, "Sent an article to Rhythm");
  }
Beispiel #18
0
  /**
   * Try to write response from cache.
   *
   * @param request the specified request
   * @param response the specified response
   * @param chain filter chain
   * @throws IOException io exception
   * @throws ServletException servlet exception
   */
  @Override
  public void doFilter(
      final ServletRequest request, final ServletResponse response, final FilterChain chain)
      throws IOException, ServletException {
    final long startTimeMillis = System.currentTimeMillis();
    request.setAttribute(Keys.HttpRequest.START_TIME_MILLIS, startTimeMillis);

    final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    final String requestURI = httpServletRequest.getRequestURI();
    LOGGER.log(Level.FINER, "Request URI[{0}]", requestURI);

    if (StaticResources.isStatic(httpServletRequest)) {
      final String path = httpServletRequest.getServletPath() + httpServletRequest.getPathInfo();
      LOGGER.log(Level.FINEST, "Requests a static resource, forwards to servlet[path={0}]", path);
      request.getRequestDispatcher(path).forward(request, response);

      return;
    }

    if (!Latkes.isPageCacheEnabled()) {
      LOGGER.log(Level.FINEST, "Page cache is disabled");
      chain.doFilter(request, response);

      return;
    }

    final String skinDirName = (String) httpServletRequest.getAttribute(Keys.TEMAPLTE_DIR_NAME);
    if ("mobile".equals(skinDirName)) {
      // Mobile request, bypasses page caching
      chain.doFilter(request, response);

      return;
    }

    String pageCacheKey;
    final String queryString = httpServletRequest.getQueryString();
    pageCacheKey = (String) request.getAttribute(Keys.PAGE_CACHE_KEY);
    if (Strings.isEmptyOrNull(pageCacheKey)) {
      pageCacheKey = PageCaches.getPageCacheKey(requestURI, queryString);
      request.setAttribute(Keys.PAGE_CACHE_KEY, pageCacheKey);
    }

    final JSONObject cachedPageContentObject =
        PageCaches.get(pageCacheKey, httpServletRequest, (HttpServletResponse) response);

    if (null == cachedPageContentObject) {
      LOGGER.log(Level.FINER, "Page cache miss for request URI[{0}]", requestURI);
      chain.doFilter(request, response);

      return;
    }

    final String cachedType = cachedPageContentObject.optString(PageCaches.CACHED_TYPE);

    try {
      // If cached an article that has view password, dispatches the password form
      if (langPropsService.get(PageTypes.ARTICLE.getLangeLabel()).equals(cachedType)
          && cachedPageContentObject.has(PageCaches.CACHED_PWD)) {
        JSONObject article = new JSONObject();

        final String articleId = cachedPageContentObject.optString(PageCaches.CACHED_OID);

        article.put(Keys.OBJECT_ID, articleId);
        article.put(
            Article.ARTICLE_VIEW_PWD, cachedPageContentObject.optString(PageCaches.CACHED_PWD));

        if (articles.needViewPwd(httpServletRequest, article)) {
          article = articleRepository.get(articleId); // Loads the article entity

          final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
          try {
            httpServletResponse.sendRedirect(
                Latkes.getServePath()
                    + "/console/article-pwd"
                    + articles.buildArticleViewPwdFormParameters(article));
            return;
          } catch (final Exception e) {
            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
          }
        }
      }
    } catch (final Exception e) {
      LOGGER.log(Level.SEVERE, e.getMessage(), e);
      chain.doFilter(request, response);
    }

    try {
      LOGGER.log(
          Level.FINEST, "Writes resposne for page[pageCacheKey={0}] from cache", pageCacheKey);
      response.setContentType("text/html");
      response.setCharacterEncoding("UTF-8");
      final PrintWriter writer = response.getWriter();
      String cachedPageContent = cachedPageContentObject.getString(PageCaches.CACHED_CONTENT);
      final String topBarHTML =
          TopBars.getTopBarHTML((HttpServletRequest) request, (HttpServletResponse) response);
      cachedPageContent = cachedPageContent.replace(Common.TOP_BAR_REPLACEMENT_FLAG, topBarHTML);

      final String cachedTitle = cachedPageContentObject.getString(PageCaches.CACHED_TITLE);
      LOGGER.log(
          Level.FINEST,
          "Cached value[key={0}, type={1}, title={2}]",
          new Object[] {pageCacheKey, cachedType, cachedTitle});

      statistics.incBlogViewCount((HttpServletRequest) request, (HttpServletResponse) response);

      final long endimeMillis = System.currentTimeMillis();
      final String dateString = DateFormatUtils.format(endimeMillis, "yyyy/MM/dd HH:mm:ss");
      final String msg =
          String.format(
              "<!-- Cached by B3log Solo(%1$d ms), %2$s -->",
              endimeMillis - startTimeMillis, dateString);
      LOGGER.finer(msg);
      cachedPageContent += Strings.LINE_SEPARATOR + msg;
      writer.write(cachedPageContent);
      writer.flush();
      writer.close();
    } catch (final JSONException e) {
      LOGGER.log(Level.SEVERE, e.getMessage(), e);
      chain.doFilter(request, response);
    } catch (final RepositoryException e) {
      LOGGER.log(Level.SEVERE, e.getMessage(), e);
      chain.doFilter(request, response);
    } catch (final ServiceException e) {
      LOGGER.log(Level.SEVERE, e.getMessage(), e);
      chain.doFilter(request, response);
    }
  }
Beispiel #19
0
  @Override
  public void action(final Event<JSONObject> event) throws EventException {
    final JSONObject data = event.getData();
    LOGGER.log(
        Level.DEBUG,
        "Processing an event[type={0}, data={1}] in listener[className={2}]",
        new Object[] {event.getType(), data, CommentNotifier.class.getName()});

    try {
      final JSONObject originalArticle = data.getJSONObject(Article.ARTICLE);
      final JSONObject originalComment = data.getJSONObject(Comment.COMMENT);
      final String commentContent = originalComment.optString(Comment.COMMENT_CONTENT);
      final JSONObject commenter =
          userQueryService.getUser(originalComment.optString(Comment.COMMENT_AUTHOR_ID));
      final String commenterName = commenter.optString(User.USER_NAME);

      // 0. Data channel (WebSocket)
      final JSONObject chData = new JSONObject();
      chData.put(Article.ARTICLE_T_ID, originalArticle.optString(Keys.OBJECT_ID));
      chData.put(Comment.COMMENT_T_ID, originalComment.optString(Keys.OBJECT_ID));
      chData.put(Comment.COMMENT_T_AUTHOR_NAME, commenterName);

      final String userEmail = commenter.optString(User.USER_EMAIL);
      chData.put(
          Comment.COMMENT_T_AUTHOR_THUMBNAIL_URL, avatarQueryService.getAvatarURL(userEmail));
      chData.put(Common.THUMBNAIL_UPDATE_TIME, commenter.optLong(UserExt.USER_UPDATE_TIME));

      chData.put(
          Comment.COMMENT_CREATE_TIME,
          DateFormatUtils.format(
              new Date(originalComment.optLong(Comment.COMMENT_CREATE_TIME)), "yyyy-MM-dd HH:mm"));
      String cc = shortLinkQueryService.linkArticle(commentContent);
      cc = shortLinkQueryService.linkTag(cc);
      cc = Emotions.convert(cc);
      cc = Markdowns.toHTML(cc);
      cc = Markdowns.clean(cc, "");
      try {
        final Set<String> userNames = userQueryService.getUserNames(commentContent);
        for (final String userName : userNames) {
          cc =
              cc.replace(
                  '@' + userName,
                  "@<a href='"
                      + Latkes.getServePath()
                      + "/member/"
                      + userName
                      + "'>"
                      + userName
                      + "</a>");
        }
      } catch (final ServiceException e) {
        LOGGER.log(Level.ERROR, "Generates @username home URL for comment content failed", e);
      }
      chData.put(Comment.COMMENT_CONTENT, cc);

      ArticleChannel.notifyComment(chData);

      // + Article Heat
      final JSONObject articleHeat = new JSONObject();
      articleHeat.put(Article.ARTICLE_T_ID, originalArticle.optString(Keys.OBJECT_ID));
      articleHeat.put(Common.OPERATION, "+");
      ArticleListChannel.notifyHeat(articleHeat);

      final boolean isDiscussion =
          originalArticle.optInt(Article.ARTICLE_TYPE) == Article.ARTICLE_TYPE_C_DISCUSSION;

      // Timeline
      if (!isDiscussion) {
        final String articleTitle =
            StringUtils.substring(
                Jsoup.parse(originalArticle.optString(Article.ARTICLE_TITLE)).text(), 0, 28);
        final String articlePermalink =
            Latkes.getServePath() + originalArticle.optString(Article.ARTICLE_PERMALINK);

        final JSONObject timeline = new JSONObject();
        timeline.put(Common.TYPE, Comment.COMMENT);
        String content = langPropsService.get("timelineCommentLabel");
        content =
            content
                .replace(
                    "{user}",
                    "<a target='_blank' rel='nofollow' href='"
                        + Latkes.getServePath()
                        + "/member/"
                        + commenterName
                        + "'>"
                        + commenterName
                        + "</a>")
                .replace(
                    "{article}",
                    "<a target='_blank' rel='nofollow' href='"
                        + articlePermalink
                        + "'>"
                        + articleTitle
                        + "</a>")
                .replace("{comment}", StringUtils.substring(Jsoup.parse(cc).text(), 0, 28));
        timeline.put(Common.CONTENT, content);

        timelineMgmtService.addTimeline(timeline);
      }

      // 1. 'Commented' Notification
      final String articleAuthorId = originalArticle.optString(Article.ARTICLE_AUTHOR_ID);
      final Set<String> atUserNames = userQueryService.getUserNames(commentContent);
      final boolean commenterIsArticleAuthor =
          articleAuthorId.equals(originalComment.optString(Comment.COMMENT_AUTHOR_ID));
      if (commenterIsArticleAuthor && atUserNames.isEmpty()) {
        return;
      }

      atUserNames.remove(commenterName); // Do not notify commenter itself

      if (!commenterIsArticleAuthor) {
        final JSONObject requestJSONObject = new JSONObject();
        requestJSONObject.put(Notification.NOTIFICATION_USER_ID, articleAuthorId);
        requestJSONObject.put(
            Notification.NOTIFICATION_DATA_ID, originalComment.optString(Keys.OBJECT_ID));

        notificationMgmtService.addCommentedNotification(requestJSONObject);
      }

      final String articleContent = originalArticle.optString(Article.ARTICLE_CONTENT);
      final Set<String> articleContentAtUserNames = userQueryService.getUserNames(articleContent);

      // 2. 'At' Notification
      for (final String userName : atUserNames) {
        if (isDiscussion && !articleContentAtUserNames.contains(userName)) {
          continue;
        }

        final JSONObject user = userQueryService.getUserByName(userName);

        if (null == user) {
          LOGGER.log(Level.WARN, "Not found user by name [{0}]", userName);

          continue;
        }

        if (user.optString(Keys.OBJECT_ID).equals(articleAuthorId)) {
          continue; // Has added in step 1
        }

        final JSONObject requestJSONObject = new JSONObject();
        requestJSONObject.put(Notification.NOTIFICATION_USER_ID, user.optString(Keys.OBJECT_ID));
        requestJSONObject.put(
            Notification.NOTIFICATION_DATA_ID, originalComment.optString(Keys.OBJECT_ID));

        notificationMgmtService.addAtNotification(requestJSONObject);
      }
    } catch (final Exception e) {
      LOGGER.log(Level.ERROR, "Sends the comment notification failed", e);
    }
  }
Beispiel #20
0
  @Override
  public void action(final Event<JSONObject> event) throws EventException {
    final JSONObject data = event.getData();
    LOGGER.log(
        Level.DEBUG,
        "Processing an event[type={0}, data={1}] in listener[className={2}]",
        new Object[] {event.getType(), data, ArticleNotifier.class.getName()});

    try {
      final JSONObject originalArticle = data.getJSONObject(Article.ARTICLE);
      final String articleId = originalArticle.optString(Keys.OBJECT_ID);

      final String articleAuthorId = originalArticle.optString(Article.ARTICLE_AUTHOR_ID);
      final JSONObject articleAuthor = userQueryService.getUser(articleAuthorId);
      final String articleAuthorName = articleAuthor.optString(User.USER_NAME);

      final String articleContent = originalArticle.optString(Article.ARTICLE_CONTENT);
      final Set<String> atUserNames = userQueryService.getUserNames(articleContent);
      atUserNames.remove(articleAuthorName); // Do not notify the author itself

      final Set<String> atedUserIds = new HashSet<String>();

      // 'At' Notification
      for (final String userName : atUserNames) {
        final JSONObject user = userQueryService.getUserByName(userName);

        if (null == user) {
          LOGGER.log(Level.WARN, "Not found user by name [{0}]", userName);

          continue;
        }

        final JSONObject requestJSONObject = new JSONObject();
        final String atedUserId = user.optString(Keys.OBJECT_ID);
        requestJSONObject.put(Notification.NOTIFICATION_USER_ID, atedUserId);
        requestJSONObject.put(Notification.NOTIFICATION_DATA_ID, articleId);

        notificationMgmtService.addAtNotification(requestJSONObject);

        atedUserIds.add(atedUserId);
      }

      // 'FollowingUser' Notification
      final JSONObject followerUsersResult =
          followQueryService.getFollowerUsers(articleAuthorId, 1, Integer.MAX_VALUE);
      @SuppressWarnings("unchecked")
      final List<JSONObject> followerUsers = (List) followerUsersResult.opt(Keys.RESULTS);
      for (final JSONObject followerUser : followerUsers) {
        final JSONObject requestJSONObject = new JSONObject();
        final String followerUserId = followerUser.optString(Keys.OBJECT_ID);

        if (atedUserIds.contains(followerUserId)) {
          continue;
        }

        requestJSONObject.put(Notification.NOTIFICATION_USER_ID, followerUserId);
        requestJSONObject.put(Notification.NOTIFICATION_DATA_ID, articleId);

        notificationMgmtService.addFollowingUserNotification(requestJSONObject);
      }

      // Timeline
      final String articleTitle =
          StringUtils.substring(
              Jsoup.parse(originalArticle.optString(Article.ARTICLE_TITLE)).text(), 0, 28);
      final String articlePermalink =
          Latkes.getServePath() + originalArticle.optString(Article.ARTICLE_PERMALINK);

      final JSONObject timeline = new JSONObject();
      timeline.put(Common.TYPE, Article.ARTICLE);
      String content = langPropsService.get("timelineArticleLabel");
      content =
          content
              .replace(
                  "{user}",
                  "<a target='_blank' rel='nofollow' href='"
                      + Latkes.getServePath()
                      + "/member/"
                      + articleAuthorName
                      + "'>"
                      + articleAuthorName
                      + "</a>")
              .replace(
                  "{article}",
                  "<a target='_blank' rel='nofollow' href='"
                      + articlePermalink
                      + "'>"
                      + articleTitle
                      + "</a>");
      timeline.put(Common.CONTENT, content);

      timelineMgmtService.addTimeline(timeline);

      // 'Broadcast' Notification
      if (Article.ARTICLE_TYPE_C_CITY_BROADCAST == originalArticle.optInt(Article.ARTICLE_TYPE)) {
        final String city = originalArticle.optString(Article.ARTICLE_CITY);

        if (StringUtils.isNotBlank(city)) {
          final JSONObject requestJSONObject = new JSONObject();
          requestJSONObject.put(Pagination.PAGINATION_CURRENT_PAGE_NUM, 1);
          requestJSONObject.put(Pagination.PAGINATION_PAGE_SIZE, Integer.MAX_VALUE);
          requestJSONObject.put(Pagination.PAGINATION_WINDOW_SIZE, Integer.MAX_VALUE);

          final long latestLoginTime = DateUtils.addDays(new Date(), -15).getTime();
          requestJSONObject.put(UserExt.USER_LATEST_LOGIN_TIME, latestLoginTime);
          requestJSONObject.put(UserExt.USER_CITY, city);

          final JSONObject result = userQueryService.getUsersByCity(requestJSONObject);
          final JSONArray users = result.optJSONArray(User.USERS);

          for (int i = 0; i < users.length(); i++) {
            final String userId = users.optJSONObject(i).optString(Keys.OBJECT_ID);

            if (userId.equals(articleAuthorId)) {
              continue;
            }

            final JSONObject notification = new JSONObject();
            notification.put(Notification.NOTIFICATION_USER_ID, userId);
            notification.put(Notification.NOTIFICATION_DATA_ID, articleId);

            notificationMgmtService.addBroadcastNotification(notification);
          }

          LOGGER.info("City broadcast [" + users.length() + "]");
        }
      }
    } catch (final Exception e) {
      LOGGER.log(Level.ERROR, "Sends the article notification failed", e);
    }
  }
  /**
   * Gets the user comments with the specified user id, page number and page size.
   *
   * @param userId the specified user id
   * @param currentPageNum the specified page number
   * @param pageSize the specified page size
   * @param viewer the specified viewer, may be {@code null}
   * @return user comments, return an empty list if not found
   * @throws ServiceException service exception
   */
  public List<JSONObject> getUserComments(
      final String userId, final int currentPageNum, final int pageSize, final JSONObject viewer)
      throws ServiceException {
    final Query query =
        new Query()
            .addSort(Comment.COMMENT_CREATE_TIME, SortDirection.DESCENDING)
            .setCurrentPageNum(currentPageNum)
            .setPageSize(pageSize)
            .setFilter(new PropertyFilter(Comment.COMMENT_AUTHOR_ID, FilterOperator.EQUAL, userId));
    try {
      final JSONObject result = commentRepository.get(query);
      final List<JSONObject> ret =
          CollectionUtils.<JSONObject>jsonArrayToList(result.optJSONArray(Keys.RESULTS));

      for (final JSONObject comment : ret) {
        comment.put(
            Comment.COMMENT_CREATE_TIME, new Date(comment.optLong(Comment.COMMENT_CREATE_TIME)));

        final String articleId = comment.optString(Comment.COMMENT_ON_ARTICLE_ID);
        final JSONObject article = articleRepository.get(articleId);

        comment.put(
            Comment.COMMENT_T_ARTICLE_TITLE,
            Article.ARTICLE_STATUS_C_INVALID == article.optInt(Article.ARTICLE_STATUS)
                ? langPropsService.get("articleTitleBlockLabel")
                : Emotions.convert(article.optString(Article.ARTICLE_TITLE)));
        comment.put(Comment.COMMENT_T_ARTICLE_TYPE, article.optInt(Article.ARTICLE_TYPE));
        comment.put(
            Comment.COMMENT_T_ARTICLE_PERMALINK, article.optString(Article.ARTICLE_PERMALINK));

        final JSONObject commenter = userRepository.get(userId);
        comment.put(Comment.COMMENT_T_COMMENTER, commenter);

        final String articleAuthorId = article.optString(Article.ARTICLE_AUTHOR_ID);
        final JSONObject articleAuthor = userRepository.get(articleAuthorId);
        final String articleAuthorName = articleAuthor.optString(User.USER_NAME);
        final String articleAuthorURL = "/member/" + articleAuthor.optString(User.USER_NAME);
        comment.put(Comment.COMMENT_T_ARTICLE_AUTHOR_NAME, articleAuthorName);
        comment.put(Comment.COMMENT_T_ARTICLE_AUTHOR_URL, articleAuthorURL);
        final String articleAuthorEmail = articleAuthor.optString(User.USER_EMAIL);
        final String articleAuthorThumbnailURL =
            avatarQueryService.getAvatarURL(articleAuthorEmail);
        comment.put(Comment.COMMENT_T_ARTICLE_AUTHOR_THUMBNAIL_URL, articleAuthorThumbnailURL);

        if (Article.ARTICLE_TYPE_C_DISCUSSION == article.optInt(Article.ARTICLE_TYPE)) {
          final String msgContent =
              langPropsService
                  .get("articleDiscussionLabel")
                  .replace(
                      "{user}",
                      "<a href='"
                          + Latkes.getServePath()
                          + "/member/"
                          + articleAuthorName
                          + "'>"
                          + articleAuthorName
                          + "</a>");

          if (null == viewer) {
            comment.put(Comment.COMMENT_CONTENT, msgContent);
          } else {
            final String commenterName = commenter.optString(User.USER_NAME);
            final String viewerUserName = viewer.optString(User.USER_NAME);
            final String viewerRole = viewer.optString(User.USER_ROLE);

            if (!commenterName.equals(viewerUserName) && !Role.ADMIN_ROLE.equals(viewerRole)) {
              final String articleContent = article.optString(Article.ARTICLE_CONTENT);
              final Set<String> userNames = userQueryService.getUserNames(articleContent);

              boolean invited = false;
              for (final String userName : userNames) {
                if (userName.equals(viewerUserName)) {
                  invited = true;

                  break;
                }
              }

              if (!invited) {
                comment.put(Comment.COMMENT_CONTENT, msgContent);
              }
            }
          }
        }

        processCommentContent(comment);
      }

      return ret;
    } catch (final RepositoryException e) {
      LOGGER.log(Level.ERROR, "Gets user comments failed", e);
      throw new ServiceException(e);
    }
  }