001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.blogs.action;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.servlet.ServletResponseUtil;
020    import com.liferay.portal.kernel.util.ContentTypes;
021    import com.liferay.portal.kernel.util.GetterUtil;
022    import com.liferay.portal.kernel.util.HttpUtil;
023    import com.liferay.portal.kernel.util.ParamUtil;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.Validator;
027    import com.liferay.portal.security.auth.PrincipalException;
028    import com.liferay.portal.struts.ActionConstants;
029    import com.liferay.portal.struts.PortletAction;
030    import com.liferay.portal.theme.ThemeDisplay;
031    import com.liferay.portal.util.PortalUtil;
032    import com.liferay.portal.util.WebKeys;
033    import com.liferay.portlet.blogs.NoSuchEntryException;
034    import com.liferay.portlet.blogs.TrackbackValidationException;
035    import com.liferay.portlet.blogs.model.BlogsEntry;
036    import com.liferay.portlet.blogs.trackback.Trackback;
037    import com.liferay.portlet.blogs.trackback.TrackbackImpl;
038    
039    import javax.portlet.ActionRequest;
040    import javax.portlet.ActionResponse;
041    import javax.portlet.PortletConfig;
042    import javax.portlet.PortletPreferences;
043    
044    import javax.servlet.http.HttpServletRequest;
045    import javax.servlet.http.HttpServletResponse;
046    
047    import org.apache.struts.action.ActionForm;
048    import org.apache.struts.action.ActionMapping;
049    
050    /**
051     * @author Alexander Chow
052     */
053    public class TrackbackAction extends PortletAction {
054    
055            public TrackbackAction() {
056                    _trackback = new TrackbackImpl();
057            }
058    
059            @Override
060            public void processAction(
061                            ActionMapping actionMapping, ActionForm actionForm,
062                            PortletConfig portletConfig, ActionRequest actionRequest,
063                            ActionResponse actionResponse)
064                    throws Exception {
065    
066                    try {
067                            addTrackback(actionRequest, actionResponse);
068                    }
069                    catch (NoSuchEntryException nsee) {
070                            if (_log.isWarnEnabled()) {
071                                    _log.warn(nsee, nsee);
072                            }
073                    }
074                    catch (Exception e) {
075                            _log.error(e, e);
076                    }
077    
078                    setForward(actionRequest, ActionConstants.COMMON_NULL);
079            }
080    
081            protected TrackbackAction(Trackback trackback) {
082                    _trackback = trackback;
083            }
084    
085            protected void addTrackback(
086                            ActionRequest actionRequest, ActionResponse actionResponse)
087                    throws Exception {
088    
089                    try {
090                            BlogsEntry entry = getBlogsEntry(actionRequest);
091    
092                            validate(entry);
093    
094                            ThemeDisplay themeDisplay =
095                                    (ThemeDisplay)actionRequest.getAttribute(WebKeys.THEME_DISPLAY);
096    
097                            HttpServletRequest request = PortalUtil.getHttpServletRequest(
098                                    actionRequest);
099    
100                            HttpServletRequest originalRequest =
101                                    PortalUtil.getOriginalServletRequest(request);
102    
103                            String excerpt = ParamUtil.getString(originalRequest, "excerpt");
104                            String url = ParamUtil.getString(originalRequest, "url");
105                            String blogName = ParamUtil.getString(originalRequest, "blog_name");
106                            String title = ParamUtil.getString(originalRequest, "title");
107    
108                            validate(actionRequest, request.getRemoteAddr(), url);
109    
110                            _trackback.addTrackback(
111                                    entry, themeDisplay, excerpt, url, blogName, title,
112                                    new TrackbackServiceContextFunction(actionRequest));
113                    }
114                    catch (TrackbackValidationException tve) {
115                            sendError(actionRequest, actionResponse, tve.getMessage());
116    
117                            return;
118                    }
119    
120                    sendSuccess(actionRequest, actionResponse);
121            }
122    
123            protected BlogsEntry getBlogsEntry(ActionRequest actionRequest)
124                    throws Exception {
125    
126                    try {
127                            ActionUtil.getEntry(actionRequest);
128                    }
129                    catch (PrincipalException pe) {
130                            throw new TrackbackValidationException(
131                                    "Blog entry must have guest view permissions to enable " +
132                                            "trackbacks");
133                    }
134    
135                    return (BlogsEntry)actionRequest.getAttribute(WebKeys.BLOGS_ENTRY);
136            }
137    
138            @Override
139            protected boolean isCheckMethodOnProcessAction() {
140                    return _CHECK_METHOD_ON_PROCESS_ACTION;
141            }
142    
143            protected boolean isCommentsEnabled(ActionRequest actionRequest)
144                    throws Exception {
145    
146                    PortletPreferences portletPreferences = getStrictPortletSetup(
147                            actionRequest);
148    
149                    if (portletPreferences == null) {
150                            portletPreferences = actionRequest.getPreferences();
151                    }
152    
153                    return GetterUtil.getBoolean(
154                            portletPreferences.getValue("enableComments", null), true);
155            }
156    
157            protected void sendError(
158                            ActionRequest actionRequest, ActionResponse actionResponse,
159                            String msg)
160                    throws Exception {
161    
162                    sendResponse(actionRequest, actionResponse, msg, false);
163            }
164    
165            protected void sendResponse(
166                            ActionRequest actionRequest, ActionResponse actionResponse,
167                            String msg, boolean success)
168                    throws Exception {
169    
170                    StringBundler sb = new StringBundler(7);
171    
172                    sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
173                    sb.append("<response>");
174    
175                    if (success) {
176                            sb.append("<error>0</error>");
177                    }
178                    else {
179                            sb.append("<error>1</error>");
180                            sb.append("<message>");
181                            sb.append(msg);
182                            sb.append("</message>");
183                    }
184    
185                    sb.append("</response>");
186    
187                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
188                            actionRequest);
189                    HttpServletResponse response = PortalUtil.getHttpServletResponse(
190                            actionResponse);
191    
192                    ServletResponseUtil.sendFile(
193                            request, response, null, sb.toString().getBytes(StringPool.UTF8),
194                            ContentTypes.TEXT_XML_UTF8);
195            }
196    
197            protected void sendSuccess(
198                            ActionRequest actionRequest, ActionResponse actionResponse)
199                    throws Exception {
200    
201                    sendResponse(actionRequest, actionResponse, null, true);
202            }
203    
204            protected void validate(
205                            ActionRequest actionRequest, String remoteIP, String url)
206                    throws Exception {
207    
208                    if (!isCommentsEnabled(actionRequest)) {
209                            throw new TrackbackValidationException("Comments are disabled");
210                    }
211    
212                    if (Validator.isNull(url)) {
213                            throw new TrackbackValidationException(
214                                    "Trackback requires a valid permanent URL");
215                    }
216    
217                    String trackbackIP = HttpUtil.getIpAddress(url);
218    
219                    if (!remoteIP.equals(trackbackIP)) {
220                            throw new TrackbackValidationException(
221                                    "Remote IP does not match the trackback URL's IP");
222                    }
223            }
224    
225            protected void validate(BlogsEntry entry)
226                    throws TrackbackValidationException {
227    
228                    if (!entry.isAllowTrackbacks()) {
229                            throw new TrackbackValidationException(
230                                    "Trackbacks are not enabled");
231                    }
232            }
233    
234            private static final boolean _CHECK_METHOD_ON_PROCESS_ACTION = false;
235    
236            private static final Log _log = LogFactoryUtil.getLog(
237                    TrackbackAction.class);
238    
239            private final Trackback _trackback;
240    
241    }