content: /*
   * Solo - A small and beautiful blogging system written in Java.
   * Copyright (c) 2010-present, b3log.org
   *
   * Solo is licensed under Mulan PSL v2.
   * You can use this software according to the terms and conditions of the Mulan PSL v2.
   * You may obtain a copy of Mulan PSL v2 at:
   *         http://license.coscl.org.cn/MulanPSL2
   * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
   * See the Mulan PSL v2 for more details.
   */
  package org.b3log.solo.processor;
  
  import org.apache.commons.io.IOUtils;
  import org.apache.commons.lang3.StringUtils;
  import org.apache.logging.log4j.Level;
  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.Logger;
  import org.b3log.latke.Keys;
  import org.b3log.latke.Latkes;
  import org.b3log.latke.http.RequestContext;
  import org.b3log.latke.http.renderer.JsonRenderer;
  import org.b3log.latke.ioc.Inject;
  import org.b3log.latke.ioc.Singleton;
  import org.b3log.latke.model.Pagination;
  import org.b3log.latke.model.User;
  import org.b3log.solo.Server;
  import org.b3log.solo.model.Article;
  import org.b3log.solo.model.Option;
  import org.b3log.solo.service.*;
  import org.json.JSONArray;
  import org.json.JSONObject;
  
  import java.io.InputStream;
  import java.nio.charset.StandardCharsets;
  import java.util.List;
  
  /**
   * Blog processor.
   *
   * @author <a href="http://88250.b3log.org">Liang Ding</a>
   * @version 2.0.0.1, Apr 15, 2020
   * @since 0.4.6
   */
  @Singleton
  public class BlogProcessor {
  
      /**
       * Logger.
       */
      private static final Logger LOGGER = LogManager.getLogger(BlogProcessor.class);
  
      /**
       * Article query service.
       */
      @Inject
      private ArticleQueryService articleQueryService;
  
      /**
       * Tag query service.
       */
      @Inject
      private TagQueryService tagQueryService;
  
      /**
       * Statistic query service.
       */
      @Inject
      private StatisticQueryService statisticQueryService;
  
      /**
       * User query service.
       */
      @Inject
      private UserQueryService userQueryService;
  
      /**
       * Option query service.
       */
      @Inject
      private OptionQueryService optionQueryService;
  
      /**
       * PWA manifest JSON template.
       */
      private static String PWA_MANIFESTO_JSON;
  
      static {
          try (final InputStream tplStream = BlogProcessor.class.getResourceAsStream("/manifest.json.tpl")) {
              PWA_MANIFESTO_JSON = IOUtils.toString(tplStream, StandardCharsets.UTF_8);
          } catch (final Exception e) {
              LOGGER.log(Level.ERROR, "Loads PWA manifest.json template failed", e);
          }
      }
  
      /**
       * Gets PWA manifest.json.
       *
       * @param context the specified context
       */
      public void getPWAManifestJSON(final RequestContext context) {
          final JsonRenderer renderer = new JsonRenderer();
          renderer.setPretty(true);
          context.setRenderer(renderer);
          final JSONObject preference = optionQueryService.getPreference();
          if (null == preference) {
              return;
          }
          final String name = preference.optString(Option.ID_C_BLOG_TITLE);
          PWA_MANIFESTO_JSON = StringUtils.replace(PWA_MANIFESTO_JSON, "${name}", name);
          final String description = preference.optString(Option.ID_C_BLOG_SUBTITLE);
          PWA_MANIFESTO_JSON = StringUtils.replace(PWA_MANIFESTO_JSON, "${description}", description);
          final JSONObject jsonObject = new JSONObject(PWA_MANIFESTO_JSON);
          PWA_MANIFESTO_JSON = StringUtils.replace(PWA_MANIFESTO_JSON, "${shortName}", name);
          renderer.setJSONObject(jsonObject);
      }
  
      /**
       * Gets blog information.
       * <ul>
       * <li>Time of the recent updated article</li>
       * <li>Article count</li>
       * <li>Comment count</li>
       * <li>Tag count</li>
       * <li>Serve path</li>
       * <li>Static serve path</li>
       * <li>Solo version</li>
       * <li>Runtime mode</li>
       * <li>Runtime database</li>
       * <li>Locale</li>
       * <li>Admin username</li>
       * <li>Skin</li>
       * <li>Mobile skin</li>
       * </ul>
       *
       * @param context the specified context
       */
      public void getBlogInfo(final RequestContext context) {
          final JsonRenderer renderer = new JsonRenderer();
          context.setRenderer(renderer);
          final JSONObject jsonObject = new JSONObject();
          renderer.setJSONObject(jsonObject);
  
          jsonObject.put("recentArticleTime", articleQueryService.getRecentArticleTime());
          final JSONObject statistic = statisticQueryService.getStatistic();
          jsonObject.put("articleCount", statistic.getLong(Option.ID_T_STATISTIC_PUBLISHED_ARTICLE_COUNT));
          jsonObject.put("tagCount", tagQueryService.getTagCount());
          jsonObject.put("servePath", Latkes.getServePath());
          jsonObject.put("staticServePath", Latkes.getStaticServePath());
          String version = Server.VERSION;
          final String gitCommit = System.getenv("git_commit");
          if (StringUtils.isNotBlank(gitCommit)) {
              version += ", commit " + gitCommit;
          }
          jsonObject.put("version", version);
          jsonObject.put("runtimeMode", Latkes.getRuntimeMode());
          jsonObject.put("runtimeDatabase", Latkes.getRuntimeDatabase());
          jsonObject.put("locale", Latkes.getLocale());
          final String userName = userQueryService.getAdmin().optString(User.USER_NAME);
          jsonObject.put("userName", userName);
          jsonObject.put("skin", optionQueryService.getOptionById(Option.ID_C_SKIN_DIR_NAME).optString(Option.OPTION_VALUE));
          jsonObject.put("mobileSkin", optionQueryService.getOptionById(Option.ID_C_MOBILE_SKIN_DIR_NAME).optString(Option.OPTION_VALUE));
      }
  
      /**
       * Gets tags of all articles.
       * <p>
       * <pre>
       * {
       *     "data": [
       *         ["tag1", "tag2", ....], // tags of one article
       *         ["tagX", "tagY", ....], // tags of another article
       *         ....
       *     ]
       * }
       * </pre>
       * </p>
       *
       * @param context the specified context
       */
      public void getArticlesTags(final RequestContext context) {
          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);
          requestJSONObject.put(Article.ARTICLE_STATUS, Article.ARTICLE_STATUS_C_PUBLISHED);
  
          final JSONArray excludes = new JSONArray();
  
          excludes.put(Article.ARTICLE_CONTENT);
          excludes.put(Article.ARTICLE_UPDATED);
          excludes.put(Article.ARTICLE_CREATED);
          excludes.put(Article.ARTICLE_AUTHOR_ID);
          excludes.put(Article.ARTICLE_RANDOM_DOUBLE);
  
          requestJSONObject.put(Keys.EXCLUDES, excludes);
  
          final JSONObject result = articleQueryService.getArticles(requestJSONObject);
          final List<JSONObject> articles = (List<JSONObject>) result.opt(Article.ARTICLES);
  
          final JsonRenderer renderer = new JsonRenderer();
          context.setRenderer(renderer);
          final JSONObject ret = new JSONObject();
          renderer.setJSONObject(ret);
  
          final JSONArray data = new JSONArray();
          ret.put("data", data);
  
          for (final JSONObject article : articles) {
              final String tagString = article.optString(Article.ARTICLE_TAGS_REF);
  
              final JSONArray tagArray = new JSONArray();
              data.put(tagArray);
  
              final String[] tags = tagString.split(",");
  
              for (final String tag : tags) {
                  final String trim = tag.trim();
                  if (StringUtils.isNotBlank(trim)) {
                      tagArray.put(tag);
                  }
              }
          }
      }
  }
  