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.UserLocalServiceUtil;
35  import com.liferay.portal.struts.ActionConstants;
36  import com.liferay.portal.struts.PortletAction;
37  import com.liferay.portal.theme.ThemeDisplay;
38  import com.liferay.portal.util.Portal;
39  import com.liferay.portal.util.PortalUtil;
40  import com.liferay.portal.util.WebKeys;
41  import com.liferay.portlet.PortletPreferencesFactoryUtil;
42  import com.liferay.portlet.blogs.NoSuchEntryException;
43  import com.liferay.portlet.blogs.model.BlogsEntry;
44  import com.liferay.portlet.blogs.util.TrackbackVerifierUtil;
45  import com.liferay.portlet.messageboards.model.MBMessage;
46  import com.liferay.portlet.messageboards.model.MBMessageDisplay;
47  import com.liferay.portlet.messageboards.model.MBThread;
48  import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
49  import com.liferay.util.servlet.ServletResponseUtil;
50  
51  import javax.portlet.ActionRequest;
52  import javax.portlet.ActionResponse;
53  import javax.portlet.PortletConfig;
54  import javax.portlet.PortletPreferences;
55  
56  import javax.servlet.http.HttpServletRequest;
57  import javax.servlet.http.HttpServletResponse;
58  
59  import org.apache.struts.action.ActionForm;
60  import org.apache.struts.action.ActionMapping;
61  
62  /**
63   * <a href="TrackbackAction.java.html"><b><i>View Source</i></b></a>
64   *
65   * @author Alexander Chow
66   */
67  public class TrackbackAction extends PortletAction {
68  
69      public void processAction(
70              ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
71              ActionRequest actionRequest, ActionResponse actionResponse)
72          throws Exception {
73  
74          try {
75              addTrackback(actionRequest, actionResponse);
76          }
77          catch (NoSuchEntryException nsee) {
78              if (_log.isWarnEnabled()) {
79                  _log.warn(nsee, nsee);
80              }
81          }
82          catch (Exception e) {
83              _log.error(e, e);
84          }
85  
86          setForward(actionRequest, ActionConstants.COMMON_NULL);
87      }
88  
89      protected void addTrackback(
90              ActionRequest actionRequest, ActionResponse actionResponse)
91          throws Exception {
92  
93          ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
94              WebKeys.THEME_DISPLAY);
95  
96          String title = ParamUtil.getString(actionRequest, "title");
97          String excerpt = ParamUtil.getString(actionRequest, "excerpt");
98          String url = ParamUtil.getString(actionRequest, "url");
99          String blogName = ParamUtil.getString(actionRequest, "blog_name");
100 
101         if (!isCommentsEnabled(actionRequest)) {
102             sendError(
103                 actionResponse,
104                 "Comments have been disabled for this blog entry.");
105 
106             return;
107         }
108 
109         if (Validator.isNull(url)) {
110             sendError(
111                 actionResponse, "Trackback requires a valid permanent URL.");
112 
113             return;
114         }
115 
116         HttpServletRequest request = PortalUtil.getHttpServletRequest(
117             actionRequest);
118 
119         String remoteIp = request.getRemoteAddr();
120 
121         String trackbackIp = HttpUtil.getIpAddress(url);
122 
123         if (!remoteIp.equals(trackbackIp)) {
124             sendError(
125                 actionResponse,
126                 "Remote IP " + remoteIp + " does not match trackback URL's IP "
127                     + trackbackIp);
128 
129             return;
130         }
131 
132         try {
133             ActionUtil.getEntry(actionRequest);
134         }
135         catch (PrincipalException pe) {
136             sendError(
137                 actionResponse,
138                 "Entry must have guest view permissions to enable trackbacks");
139 
140             return;
141         }
142 
143         BlogsEntry entry = (BlogsEntry)actionRequest.getAttribute(
144             WebKeys.BLOGS_ENTRY);
145 
146         if (!entry.isAllowTrackbacks()) {
147             sendError(
148                 actionResponse,
149                 "Trackbacks are not enabled on this blog entry.");
150 
151             return;
152         }
153 
154         long userId = UserLocalServiceUtil.getDefaultUserId(
155             themeDisplay.getCompanyId());
156         long groupId = themeDisplay.getScopeGroupId();
157         String className = BlogsEntry.class.getName();
158         long classPK = entry.getEntryId();
159 
160         MBMessageDisplay messageDisplay =
161             MBMessageLocalServiceUtil.getDiscussionMessageDisplay(
162                 userId, className, classPK);
163 
164         MBThread thread = messageDisplay.getThread();
165 
166         long threadId = thread.getThreadId();
167         long parentMessageId = thread.getRootMessageId();
168         String body =
169             "[...] " + excerpt + " [...] [url=" + url + "]" +
170                 themeDisplay.translate("read-more") + "[/url]";
171 
172         MBMessage message = MBMessageLocalServiceUtil.addDiscussionMessage(
173             userId, blogName, groupId, className, classPK, threadId,
174             parentMessageId, title, body, themeDisplay);
175 
176         String entryURL =
177             PortalUtil.getLayoutFullURL(themeDisplay) +
178                 Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
179                     entry.getUrlTitle();
180 
181         TrackbackVerifierUtil.addNewPost(
182             message.getMessageId(), url, entryURL);
183 
184         sendSuccess(actionResponse);
185     }
186 
187     protected boolean isCheckMethodOnProcessAction() {
188         return _CHECK_METHOD_ON_PROCESS_ACTION;
189     }
190 
191     protected boolean isCommentsEnabled(ActionRequest actionRequest)
192         throws Exception {
193 
194         PortletPreferences prefs = actionRequest.getPreferences();
195 
196         String portletResource = ParamUtil.getString(
197             actionRequest, "portletResource");
198 
199         if (Validator.isNotNull(portletResource)) {
200             prefs = PortletPreferencesFactoryUtil.getPortletSetup(
201                 actionRequest, portletResource);
202         }
203 
204         return GetterUtil.getBoolean(
205             prefs.getValue("enable-comments", null), true);
206     }
207 
208     protected void sendError(ActionResponse actionResponse, String msg)
209         throws Exception {
210 
211         sendResponse(actionResponse, msg, false);
212     }
213 
214     protected void sendResponse(
215             ActionResponse actionResponse, String msg, boolean success)
216         throws Exception {
217 
218         StringBuilder sb = new StringBuilder();
219 
220         sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
221         sb.append("<response>");
222 
223         if (success) {
224             sb.append("<error>0</error>");
225         }
226         else {
227             sb.append("<error>1</error>");
228             sb.append("<message>" + msg + "</message>");
229         }
230 
231         sb.append("</response>");
232 
233         HttpServletResponse response = PortalUtil.getHttpServletResponse(
234             actionResponse);
235 
236         ServletResponseUtil.sendFile(
237             response, null, sb.toString().getBytes(StringPool.UTF8),
238             ContentTypes.TEXT_XML_UTF8);
239     }
240 
241     protected void sendSuccess(ActionResponse actionResponse) throws Exception {
242         sendResponse(actionResponse, null, true);
243     }
244 
245     private static final boolean _CHECK_METHOD_ON_PROCESS_ACTION = false;
246 
247     private static Log _log = LogFactoryUtil.getLog(TrackbackAction.class);
248 
249 }