View Javadoc
1   /*
2    * Copyright 2012-2025 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.helper;
17  
18  import java.io.IOException;
19  
20  import org.apache.commons.text.StringEscapeUtils;
21  import org.apache.logging.log4j.LogManager;
22  import org.apache.logging.log4j.Logger;
23  import org.codelibs.core.lang.StringUtil;
24  import org.codelibs.core.stream.StreamUtil;
25  import org.codelibs.curl.Curl;
26  import org.codelibs.curl.CurlResponse;
27  import org.codelibs.fess.mylasta.direction.FessConfig;
28  import org.codelibs.fess.util.ComponentUtil;
29  import org.dbflute.mail.CardView;
30  import org.dbflute.mail.send.supplement.SMailPostingDiscloser;
31  
32  /**
33   * Helper class for sending notifications to various platforms.
34   */
35  public class NotificationHelper {
36  
37      /**
38       * Default constructor.
39       */
40      public NotificationHelper() {
41          // Default constructor
42      }
43  
44      private static final Logger logger = LogManager.getLogger(NotificationHelper.class);
45  
46      /** Line feed character for message formatting. */
47      protected static final char LF = '\n';
48  
49      /**
50       * Sends notifications to configured platforms.
51       *
52       * @param cardView the card view for the notification
53       * @param discloser the mail posting discloser
54       */
55      public void send(final CardView cardView, final SMailPostingDiscloser discloser) {
56          sendToSlack(cardView, discloser);
57          sendToGoogleChat(cardView, discloser);
58      }
59  
60      /**
61       * Sends a notification to Slack.
62       *
63       * @param cardView the card view for the notification
64       * @param discloser the mail posting discloser
65       */
66      protected void sendToSlack(final CardView cardView, final SMailPostingDiscloser discloser) {
67          // https://api.slack.com/messaging/webhooks#posting_with_webhooks
68          final FessConfig fessConfig = ComponentUtil.getFessConfig();
69          final String slackWebhookUrls = fessConfig.getSlackWebhookUrls();
70          if (StringUtil.isBlank(slackWebhookUrls)) {
71              return;
72          }
73          final String body = toSlackMessage(discloser);
74          StreamUtil.split(slackWebhookUrls, "[,\\s]").of(stream -> stream.filter(StringUtil::isNotBlank).forEach(url -> {
75              try (CurlResponse response = Curl.post(url).header("Content-Type", "application/json").body(body).execute()) {
76                  if (response.getHttpStatusCode() == 200) {
77                      if (logger.isDebugEnabled()) {
78                          logger.debug("Sent {} to {}.", body, url);
79                      }
80                  } else {
81                      logger.warn("Failed to send {} to {}. HTTP Status is {}. {}", body, url, response.getHttpStatusCode(),
82                              response.getContentAsString());
83                  }
84              } catch (final IOException e) {
85                  logger.warn("Failed to send {} to {}.", body, url, e);
86              }
87          }));
88      }
89  
90      /**
91       * Converts the discloser to a Slack message format.
92       *
93       * @param discloser the mail posting discloser
94       * @return the formatted Slack message
95       */
96      protected String toSlackMessage(final SMailPostingDiscloser discloser) {
97          final StringBuilder buf = new StringBuilder(100);
98          buf.append("{\"text\":\"");
99          buf.append(LF);
100         buf.append(StringEscapeUtils.escapeJson(discloser.getSavedSubject().orElse(StringUtil.EMPTY).trim()));
101         buf.append(LF).append("```");
102         buf.append(LF).append(StringEscapeUtils.escapeJson(discloser.getSavedPlainText().orElse(StringUtil.EMPTY).trim()));
103         buf.append(LF).append("```\"}");
104         return buf.toString();
105     }
106 
107     /**
108      * Sends a notification to Google Chat.
109      *
110      * @param cardView the card view for the notification
111      * @param discloser the mail posting discloser
112      */
113     protected void sendToGoogleChat(final CardView cardView, final SMailPostingDiscloser discloser) {
114         // https://developers.google.com/hangouts/chat/how-tos/webhooks
115         final FessConfig fessConfig = ComponentUtil.getFessConfig();
116         final String googleChatWebhookUrls = fessConfig.getGoogleChatWebhookUrls();
117         if (StringUtil.isBlank(googleChatWebhookUrls)) {
118             return;
119         }
120         final String body = toGoogleChatMessage(discloser);
121         StreamUtil.split(googleChatWebhookUrls, "[,\\s]").of(stream -> stream.filter(StringUtil::isNotBlank).forEach(url -> {
122             try (CurlResponse response = Curl.post(url).header("Content-Type", "application/json").body(body).execute()) {
123                 if (response.getHttpStatusCode() == 200) {
124                     if (logger.isDebugEnabled()) {
125                         logger.debug("Sent {} to {}.", body, url);
126                     }
127                 } else {
128                     logger.warn("Failed to send {} to {}. HTTP Status is {}. {}", body, url, response.getHttpStatusCode(),
129                             response.getContentAsString());
130                 }
131             } catch (final IOException e) {
132                 logger.warn("Failed to send {} to {}.", body, url, e);
133             }
134         }));
135     }
136 
137     /**
138      * Converts the discloser to a Google Chat message format.
139      *
140      * @param discloser the mail posting discloser
141      * @return the formatted Google Chat message
142      */
143     protected String toGoogleChatMessage(final SMailPostingDiscloser discloser) {
144         final StringBuilder buf = new StringBuilder(100);
145         buf.append("{\"text\":\"");
146         buf.append(LF);
147         buf.append(StringEscapeUtils.escapeJson(discloser.getSavedSubject().orElse(StringUtil.EMPTY).trim()));
148         buf.append(LF).append("```");
149         buf.append(LF).append(StringEscapeUtils.escapeJson(discloser.getSavedPlainText().orElse(StringUtil.EMPTY).trim()));
150         buf.append(LF).append("```\"}");
151         return buf.toString();
152     }
153 }