1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.blogs.action;
24  
25  import com.liferay.portal.kernel.log.Log;
26  import com.liferay.portal.kernel.log.LogFactoryUtil;
27  import com.liferay.portal.kernel.util.ContentTypes;
28  import com.liferay.portal.kernel.util.GetterUtil;
29  import com.liferay.portal.kernel.util.HttpUtil;
30  import com.liferay.portal.kernel.util.ParamUtil;
31  import com.liferay.portal.kernel.util.StringPool;
32  import com.liferay.portal.kernel.util.Validator;
33  import com.liferay.portal.security.auth.PrincipalException;
34  import com.liferay.portal.service.ServiceContext;
35  import com.liferay.portal.service.ServiceContextFactory;
36  import com.liferay.portal.service.UserLocalServiceUtil;
37  import com.liferay.portal.struts.ActionConstants;
38  import com.liferay.portal.struts.PortletAction;
39  import com.liferay.portal.theme.ThemeDisplay;
40  import com.liferay.portal.util.Portal;
41  import com.liferay.portal.util.PortalUtil;
42  import com.liferay.portal.util.WebKeys;
43  import com.liferay.portlet.PortletPreferencesFactoryUtil;
44  import com.liferay.portlet.blogs.NoSuchEntryException;
45  import com.liferay.portlet.blogs.model.BlogsEntry;
46  import com.liferay.portlet.blogs.util.TrackbackVerifierUtil;
47  import com.liferay.portlet.messageboards.model.MBMessage;
48  import com.liferay.portlet.messageboards.model.MBMessageDisplay;
49  import com.liferay.portlet.messageboards.model.MBThread;
50  import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
51  import com.liferay.util.servlet.ServletResponseUtil;
52  
53  import javax.portlet.ActionRequest;
54  import javax.portlet.ActionResponse;
55  import javax.portlet.PortletConfig;
56  import javax.portlet.PortletPreferences;
57  
58  import javax.servlet.http.HttpServletRequest;
59  import javax.servlet.http.HttpServletResponse;
60  
61  import org.apache.struts.action.ActionForm;
62  import org.apache.struts.action.ActionMapping;
63  
64  /**
65   * <a href="TrackbackAction.java.html"><b><i>View Source</i></b></a>
66   *
67   * @author Alexander Chow
68   */
69  public class TrackbackAction extends PortletAction {
70  
71      public void processAction(
72              ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
73              ActionRequest actionRequest, ActionResponse actionResponse)
74          throws Exception {
75  
76          try {
77              addTrackback(actionRequest, actionResponse);
78          }
79          catch (NoSuchEntryException nsee) {
80              if (_log.isWarnEnabled()) {
81                  _log.warn(nsee, nsee);
82              }
83          }
84          catch (Exception e) {
85              _log.error(e, e);
86          }
87  
88          setForward(actionRequest, ActionConstants.COMMON_NULL);
89      }
90  
91      protected void addTrackback(
92              ActionRequest actionRequest, ActionResponse actionResponse)
93          throws Exception {
94  
95          ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
96              WebKeys.THEME_DISPLAY);
97  
98          String title = ParamUtil.getString(actionRequest, "title");
99          String excerpt = ParamUtil.getString(actionRequest, "excerpt");
100         String url = ParamUtil.getString(actionRequest, "url");
101         String blogName = ParamUtil.getString(actionRequest, "blog_name");
102 
103         if (!isCommentsEnabled(actionRequest)) {
104             sendError(
105                 actionResponse,
106                 "Comments have been disabled for this blog entry.");
107 
108             return;
109         }
110 
111         if (Validator.isNull(url)) {
112             sendError(
113                 actionResponse, "Trackback requires a valid permanent URL.");
114 
115             return;
116         }
117 
118         HttpServletRequest request = PortalUtil.getHttpServletRequest(
119             actionRequest);
120 
121         String remoteIp = request.getRemoteAddr();
122 
123         String trackbackIp = HttpUtil.getIpAddress(url);
124 
125         if (!remoteIp.equals(trackbackIp)) {
126             sendError(
127                 actionResponse,
128                 "Remote IP " + remoteIp + " does not match trackback URL's IP "
129                     + trackbackIp);
130 
131             return;
132         }
133 
134         try {
135             ActionUtil.getEntry(actionRequest);
136         }
137         catch (PrincipalException pe) {
138             sendError(
139                 actionResponse,
140                 "Blog entry must have guest VIEW permissions for trackbacks.");
141 
142             return;
143         }
144 
145         BlogsEntry entry = (BlogsEntry)actionRequest.getAttribute(
146             WebKeys.BLOGS_ENTRY);
147 
148         if (!entry.isAllowTrackbacks()) {
149             sendError(
150                 actionResponse,
151                 "Trackbacks are not enabled on this blog entry.");
152 
153             return;
154         }
155 
156         long userId = UserLocalServiceUtil.getDefaultUserId(
157             themeDisplay.getCompanyId());
158         String className = BlogsEntry.class.getName();
159         long classPK = entry.getEntryId();
160 
161         ServiceContext serviceContext = ServiceContextFactory.getInstance(
162             MBMessage.class.getName(), actionRequest);
163 
164         MBMessageDisplay messageDisplay =
165             MBMessageLocalServiceUtil.getDiscussionMessageDisplay(
166                 userId, className, classPK);
167 
168         MBThread thread = messageDisplay.getThread();
169 
170         long threadId = thread.getThreadId();
171         long parentMessageId = thread.getRootMessageId();
172         String body =
173             "[...] " + excerpt + " [...] [url=" + url + "]" +
174                 themeDisplay.translate("read-more") + "[/url]";
175 
176         MBMessage message = MBMessageLocalServiceUtil.addDiscussionMessage(
177             userId, blogName, className, classPK, threadId, parentMessageId,
178             title, body, serviceContext);
179 
180         String entryURL =
181             PortalUtil.getLayoutFullURL(themeDisplay) +
182                 Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
183                     entry.getUrlTitle();
184 
185         TrackbackVerifierUtil.addNewPost(
186             message.getMessageId(), url, entryURL);
187 
188         sendSuccess(actionResponse);
189     }
190 
191     protected boolean isCheckMethodOnProcessAction() {
192         return _CHECK_METHOD_ON_PROCESS_ACTION;
193     }
194 
195     protected boolean isCommentsEnabled(ActionRequest actionRequest)
196         throws Exception {
197 
198         PortletPreferences preferences = actionRequest.getPreferences();
199 
200         String portletResource = ParamUtil.getString(
201             actionRequest, "portletResource");
202 
203         if (Validator.isNotNull(portletResource)) {
204             preferences = PortletPreferencesFactoryUtil.getPortletSetup(
205                 actionRequest, portletResource);
206         }
207 
208         return GetterUtil.getBoolean(
209             preferences.getValue("enable-comments", null), true);
210     }
211 
212     protected void sendError(ActionResponse actionResponse, String msg)
213         throws Exception {
214 
215         sendResponse(actionResponse, msg, false);
216     }
217 
218     protected void sendResponse(
219             ActionResponse actionResponse, String msg, boolean success)
220         throws Exception {
221 
222         StringBuilder sb = new StringBuilder();
223 
224         sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
225         sb.append("<response>");
226 
227         if (success) {
228             sb.append("<error>0</error>");
229         }
230         else {
231             sb.append("<error>1</error>");
232             sb.append("<message>" + msg + "</message>");
233         }
234 
235         sb.append("</response>");
236 
237         HttpServletResponse response = PortalUtil.getHttpServletResponse(
238             actionResponse);
239 
240         ServletResponseUtil.sendFile(
241             response, null, sb.toString().getBytes(StringPool.UTF8),
242             ContentTypes.TEXT_XML_UTF8);
243     }
244 
245     protected void sendSuccess(ActionResponse actionResponse) throws Exception {
246         sendResponse(actionResponse, null, true);
247     }
248 
249     private static final boolean _CHECK_METHOD_ON_PROCESS_ACTION = false;
250 
251     private static Log _log = LogFactoryUtil.getLog(TrackbackAction.class);
252 
253 }