001    /**
002     * Copyright (c) 2000-2013 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.StringUtil;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.kernel.workflow.WorkflowConstants;
029    import com.liferay.portal.security.auth.PrincipalException;
030    import com.liferay.portal.service.ServiceContext;
031    import com.liferay.portal.service.ServiceContextFactory;
032    import com.liferay.portal.service.UserLocalServiceUtil;
033    import com.liferay.portal.struts.ActionConstants;
034    import com.liferay.portal.struts.PortletAction;
035    import com.liferay.portal.theme.ThemeDisplay;
036    import com.liferay.portal.util.Portal;
037    import com.liferay.portal.util.PortalUtil;
038    import com.liferay.portal.util.WebKeys;
039    import com.liferay.portlet.blogs.NoSuchEntryException;
040    import com.liferay.portlet.blogs.model.BlogsEntry;
041    import com.liferay.portlet.blogs.util.LinkbackConsumerUtil;
042    import com.liferay.portlet.messageboards.model.MBMessage;
043    import com.liferay.portlet.messageboards.model.MBMessageDisplay;
044    import com.liferay.portlet.messageboards.model.MBThread;
045    import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
046    
047    import javax.portlet.ActionRequest;
048    import javax.portlet.ActionResponse;
049    import javax.portlet.PortletConfig;
050    import javax.portlet.PortletPreferences;
051    
052    import javax.servlet.http.HttpServletRequest;
053    import javax.servlet.http.HttpServletResponse;
054    
055    import org.apache.struts.action.ActionForm;
056    import org.apache.struts.action.ActionMapping;
057    
058    /**
059     * @author Alexander Chow
060     */
061    public class TrackbackAction extends PortletAction {
062    
063            @Override
064            public void processAction(
065                            ActionMapping actionMapping, ActionForm actionForm,
066                            PortletConfig portletConfig, ActionRequest actionRequest,
067                            ActionResponse actionResponse)
068                    throws Exception {
069    
070                    try {
071                            addTrackback(actionRequest, actionResponse);
072                    }
073                    catch (NoSuchEntryException nsee) {
074                            if (_log.isWarnEnabled()) {
075                                    _log.warn(nsee, nsee);
076                            }
077                    }
078                    catch (Exception e) {
079                            _log.error(e, e);
080                    }
081    
082                    setForward(actionRequest, ActionConstants.COMMON_NULL);
083            }
084    
085            protected void addTrackback(
086                            ActionRequest actionRequest, ActionResponse actionResponse)
087                    throws Exception {
088    
089                    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
090                            WebKeys.THEME_DISPLAY);
091    
092                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
093                            actionRequest);
094    
095                    HttpServletRequest originalRequest =
096                            PortalUtil.getOriginalServletRequest(request);
097    
098                    String title = ParamUtil.getString(originalRequest, "title");
099                    String excerpt = ParamUtil.getString(originalRequest, "excerpt");
100                    String url = ParamUtil.getString(originalRequest, "url");
101                    String blogName = ParamUtil.getString(originalRequest, "blog_name");
102    
103                    if (!isCommentsEnabled(actionRequest)) {
104                            sendError(
105                                    actionRequest, actionResponse,
106                                    "Comments have been disabled for this blog entry.");
107    
108                            return;
109                    }
110    
111                    if (Validator.isNull(url)) {
112                            sendError(
113                                    actionRequest, actionResponse,
114                                    "Trackback requires a valid permanent URL.");
115    
116                            return;
117                    }
118    
119                    String remoteIp = request.getRemoteAddr();
120    
121                    String trackbackIp = HttpUtil.getIpAddress(url);
122    
123                    if (!remoteIp.equals(trackbackIp)) {
124                            sendError(
125                                    actionRequest, actionResponse,
126                                    "Remote IP does not match trackback URL's IP.");
127    
128                            return;
129                    }
130    
131                    try {
132                            ActionUtil.getEntry(actionRequest);
133                    }
134                    catch (PrincipalException pe) {
135                            sendError(
136                                    actionRequest, actionResponse,
137                                    "Blog entry must have guest view permissions to enable " +
138                                            "trackbacks.");
139    
140                            return;
141                    }
142    
143                    BlogsEntry entry = (BlogsEntry)actionRequest.getAttribute(
144                            WebKeys.BLOGS_ENTRY);
145    
146                    if (!entry.isAllowTrackbacks()) {
147                            sendError(
148                                    actionRequest, 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 = entry.getGroupId();
157                    String className = BlogsEntry.class.getName();
158                    long classPK = entry.getEntryId();
159    
160                    MBMessageDisplay messageDisplay =
161                            MBMessageLocalServiceUtil.getDiscussionMessageDisplay(
162                                    userId, groupId, className, classPK,
163                                    WorkflowConstants.STATUS_APPROVED);
164    
165                    MBThread thread = messageDisplay.getThread();
166    
167                    long threadId = thread.getThreadId();
168                    long parentMessageId = thread.getRootMessageId();
169    
170                    url = StringUtil.replace(
171                            url,
172                            new String[] {StringPool.CLOSE_BRACKET, StringPool.OPEN_BRACKET},
173                            new String[] {"%5D", "%5B"});
174    
175                    String body =
176                            "[...] " + excerpt + " [...] [url=" + url + "]" +
177                                    themeDisplay.translate("read-more") + "[/url]";
178    
179                    ServiceContext serviceContext = ServiceContextFactory.getInstance(
180                            MBMessage.class.getName(), actionRequest);
181    
182                    MBMessage message = MBMessageLocalServiceUtil.addDiscussionMessage(
183                            userId, blogName, groupId, className, classPK, threadId,
184                            parentMessageId, title, body, serviceContext);
185    
186                    String entryURL =
187                            PortalUtil.getLayoutFullURL(themeDisplay) +
188                                    Portal.FRIENDLY_URL_SEPARATOR + "blogs/" + entry.getUrlTitle();
189    
190                    LinkbackConsumerUtil.addNewTrackback(
191                            message.getMessageId(), url, entryURL);
192    
193                    sendSuccess(actionRequest, actionResponse);
194            }
195    
196            @Override
197            protected boolean isCheckMethodOnProcessAction() {
198                    return _CHECK_METHOD_ON_PROCESS_ACTION;
199            }
200    
201            protected boolean isCommentsEnabled(ActionRequest actionRequest)
202                    throws Exception {
203    
204                    PortletPreferences portletPreferences = getStrictPortletSetup(
205                            actionRequest);
206    
207                    if (portletPreferences == null) {
208                            portletPreferences = actionRequest.getPreferences();
209                    }
210    
211                    return GetterUtil.getBoolean(
212                            portletPreferences.getValue("enableComments", null), true);
213            }
214    
215            protected void sendError(
216                            ActionRequest actionRequest, ActionResponse actionResponse,
217                            String msg)
218                    throws Exception {
219    
220                    sendResponse(actionRequest, actionResponse, msg, false);
221            }
222    
223            protected void sendResponse(
224                            ActionRequest actionRequest, ActionResponse actionResponse,
225                            String msg, boolean success)
226                    throws Exception {
227    
228                    StringBundler sb = new StringBundler(7);
229    
230                    sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
231                    sb.append("<response>");
232    
233                    if (success) {
234                            sb.append("<error>0</error>");
235                    }
236                    else {
237                            sb.append("<error>1</error>");
238                            sb.append("<message>");
239                            sb.append(msg);
240                            sb.append("</message>");
241                    }
242    
243                    sb.append("</response>");
244    
245                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
246                            actionRequest);
247                    HttpServletResponse response = PortalUtil.getHttpServletResponse(
248                            actionResponse);
249    
250                    ServletResponseUtil.sendFile(
251                            request, response, null, sb.toString().getBytes(StringPool.UTF8),
252                            ContentTypes.TEXT_XML_UTF8);
253            }
254    
255            protected void sendSuccess(
256                            ActionRequest actionRequest, ActionResponse actionResponse)
257                    throws Exception {
258    
259                    sendResponse(actionRequest, actionResponse, null, true);
260            }
261    
262            private static final boolean _CHECK_METHOD_ON_PROCESS_ACTION = false;
263    
264            private static Log _log = LogFactoryUtil.getLog(TrackbackAction.class);
265    
266    }