001    /**
002     * Copyright (c) 2000-2012 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.portal.action;
016    
017    import com.liferay.portal.kernel.json.JSONFactoryUtil;
018    import com.liferay.portal.kernel.json.JSONObject;
019    import com.liferay.portal.kernel.servlet.ServletResponseUtil;
020    import com.liferay.portal.kernel.servlet.StringServletResponse;
021    import com.liferay.portal.kernel.staging.StagingUtil;
022    import com.liferay.portal.kernel.util.Constants;
023    import com.liferay.portal.kernel.util.ContentTypes;
024    import com.liferay.portal.kernel.util.HttpUtil;
025    import com.liferay.portal.kernel.util.InstancePool;
026    import com.liferay.portal.kernel.util.ParamUtil;
027    import com.liferay.portal.kernel.util.PropertiesParamUtil;
028    import com.liferay.portal.kernel.util.StringBundler;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.UnicodeProperties;
031    import com.liferay.portal.kernel.workflow.WorkflowConstants;
032    import com.liferay.portal.model.Layout;
033    import com.liferay.portal.model.LayoutRevision;
034    import com.liferay.portal.model.LayoutTypePortlet;
035    import com.liferay.portal.model.Portlet;
036    import com.liferay.portal.model.PortletApp;
037    import com.liferay.portal.model.PortletConstants;
038    import com.liferay.portal.model.ResourceConstants;
039    import com.liferay.portal.security.permission.ActionKeys;
040    import com.liferay.portal.security.permission.PermissionChecker;
041    import com.liferay.portal.service.LayoutRevisionLocalServiceUtil;
042    import com.liferay.portal.service.LayoutServiceUtil;
043    import com.liferay.portal.service.PortletLocalServiceUtil;
044    import com.liferay.portal.service.ResourceLocalServiceUtil;
045    import com.liferay.portal.service.ServiceContext;
046    import com.liferay.portal.service.ServiceContextFactory;
047    import com.liferay.portal.service.permission.LayoutPermissionUtil;
048    import com.liferay.portal.service.permission.PortletPermissionUtil;
049    import com.liferay.portal.servlet.NamespaceServletRequest;
050    import com.liferay.portal.struts.JSONAction;
051    import com.liferay.portal.theme.ThemeDisplay;
052    import com.liferay.portal.util.LayoutClone;
053    import com.liferay.portal.util.LayoutCloneFactory;
054    import com.liferay.portal.util.PortalUtil;
055    import com.liferay.portal.util.WebKeys;
056    import com.liferay.portlet.PortletPreferencesFactoryUtil;
057    import com.liferay.util.servlet.DynamicServletRequest;
058    
059    import java.util.LinkedHashSet;
060    import java.util.Set;
061    
062    import javax.portlet.PortletPreferences;
063    
064    import javax.servlet.http.HttpServletRequest;
065    import javax.servlet.http.HttpServletResponse;
066    
067    import org.apache.struts.action.Action;
068    import org.apache.struts.action.ActionForm;
069    import org.apache.struts.action.ActionMapping;
070    
071    /**
072     * @author Brian Wing Shun Chan
073     */
074    public class UpdateLayoutAction extends JSONAction {
075    
076            @Override
077            public String getJSON(
078                            ActionMapping mapping, ActionForm form, HttpServletRequest request,
079                            HttpServletResponse response)
080                    throws Exception {
081    
082                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
083                            WebKeys.THEME_DISPLAY);
084    
085                    long userId = themeDisplay.getUserId();
086    
087                    Layout layout = themeDisplay.getLayout();
088                    LayoutTypePortlet layoutTypePortlet =
089                            themeDisplay.getLayoutTypePortlet();
090    
091                    PermissionChecker permissionChecker =
092                            themeDisplay.getPermissionChecker();
093    
094                    String cmd = ParamUtil.getString(request, Constants.CMD);
095    
096                    String portletId = ParamUtil.getString(request, "p_p_id");
097    
098                    boolean updateLayout = true;
099                    boolean deletePortlet = false;
100    
101                    if (cmd.equals(Constants.ADD)) {
102                            String columnId = ParamUtil.getString(request, "p_p_col_id", null);
103                            int columnPos = ParamUtil.getInteger(request, "p_p_col_pos", -1);
104    
105                            portletId = layoutTypePortlet.addPortletId(
106                                    userId, portletId, columnId, columnPos);
107    
108                            if (layoutTypePortlet.isCustomizable() &&
109                                    layoutTypePortlet.isCustomizedView() &&
110                                    !layoutTypePortlet.isColumnDisabled(columnId)) {
111    
112                                    updateLayout = false;
113                            }
114                    }
115                    else if (cmd.equals(Constants.DELETE)) {
116                            if (layoutTypePortlet.hasPortletId(portletId)) {
117                                    layoutTypePortlet.removePortletId(userId, portletId);
118    
119                                    if (layoutTypePortlet.isCustomizable() &&
120                                            layoutTypePortlet.isCustomizedView()) {
121    
122                                            updateLayout = false;
123                                            deletePortlet = false;
124                                    }
125                                    else {
126                                            deletePortlet = true;
127                                    }
128                            }
129                    }
130                    else if (cmd.equals("drag")) {
131                            if (LayoutPermissionUtil.contains(
132                                            permissionChecker, layout, ActionKeys.UPDATE)) {
133    
134                                    String height = ParamUtil.getString(request, "height");
135                                    String width = ParamUtil.getString(request, "width");
136                                    String top = ParamUtil.getString(request, "top");
137                                    String left = ParamUtil.getString(request, "left");
138    
139                                    PortletPreferences preferences =
140                                            PortletPreferencesFactoryUtil.getLayoutPortletSetup(
141                                                    layout, portletId);
142    
143                                    StringBundler sb = new StringBundler(12);
144    
145                                    sb.append("height=");
146                                    sb.append(height);
147                                    sb.append("\n");
148                                    sb.append("width=");
149                                    sb.append(width);
150                                    sb.append("\n");
151                                    sb.append("top=");
152                                    sb.append(top);
153                                    sb.append("\n");
154                                    sb.append("left=");
155                                    sb.append(left);
156                                    sb.append("\n");
157    
158                                    preferences.setValue("portlet-freeform-styles", sb.toString());
159    
160                                    preferences.store();
161                            }
162                    }
163                    else if (cmd.equals("minimize")) {
164                            boolean restore = ParamUtil.getBoolean(request, "p_p_restore");
165    
166                            if (restore) {
167                                    layoutTypePortlet.removeStateMinPortletId(portletId);
168                            }
169                            else {
170                                    layoutTypePortlet.addStateMinPortletId(portletId);
171                            }
172    
173                            updateLayout = false;
174                    }
175                    else if (cmd.equals("move")) {
176                            String columnId = ParamUtil.getString(request, "p_p_col_id");
177                            int columnPos = ParamUtil.getInteger(request, "p_p_col_pos");
178    
179                            layoutTypePortlet.movePortletId(
180                                    userId, portletId, columnId, columnPos);
181    
182                            if (layoutTypePortlet.isCustomizable() &&
183                                    layoutTypePortlet.isCustomizedView() &&
184                                    !layoutTypePortlet.isColumnDisabled(columnId)) {
185    
186                                    updateLayout = false;
187                            }
188                    }
189                    else if (cmd.equals("redo_layout_revision")) {
190                            long layoutRevisionId = ParamUtil.getLong(
191                                    request, "layoutRevisionId");
192                            long layoutSetBranchId = ParamUtil.getLong(
193                                    request, "layoutSetBranchId");
194    
195                            ServiceContext serviceContext = ServiceContextFactory.getInstance(
196                                    request);
197    
198                            LayoutRevisionLocalServiceUtil.updateStatus(
199                                    userId, layoutRevisionId, WorkflowConstants.STATUS_DRAFT,
200                                    serviceContext);
201    
202                            StagingUtil.setRecentLayoutRevisionId(
203                                    request, layoutSetBranchId, layout.getPlid(), layoutRevisionId);
204    
205                            updateLayout = false;
206                    }
207                    else if (cmd.equals("select_layout_revision")) {
208                            long layoutRevisionId = ParamUtil.getLong(
209                                    request, "layoutRevisionId");
210                            long layoutSetBranchId = ParamUtil.getLong(
211                                    request, "layoutSetBranchId");
212    
213                            StagingUtil.setRecentLayoutRevisionId(
214                                    request, layoutSetBranchId, layout.getPlid(), layoutRevisionId);
215    
216                            updateLayout = false;
217                    }
218                    else if (cmd.equals("toggle_customized_view")) {
219                            updateLayout = false;
220                    }
221                    else if (cmd.equals("update_type_settings")) {
222                            UnicodeProperties layoutTypeSettingsProperties =
223                                    layout.getTypeSettingsProperties();
224    
225                            UnicodeProperties formTypeSettingsProperties =
226                                    PropertiesParamUtil.getProperties(
227                                            request, "TypeSettingsProperties--");
228    
229                            layoutTypeSettingsProperties.putAll(formTypeSettingsProperties);
230                    }
231                    else if (cmd.equals("undo_layout_revision")) {
232                            long layoutRevisionId = ParamUtil.getLong(
233                                    request, "layoutRevisionId");
234                            long layoutSetBranchId = ParamUtil.getLong(
235                                    request, "layoutSetBranchId");
236    
237                            ServiceContext serviceContext = ServiceContextFactory.getInstance(
238                                    request);
239    
240                            LayoutRevision layoutRevision =
241                                    LayoutRevisionLocalServiceUtil.updateStatus(
242                                            userId, layoutRevisionId, WorkflowConstants.STATUS_INACTIVE,
243                                            serviceContext);
244    
245                            StagingUtil.setRecentLayoutRevisionId(
246                                    request, layoutSetBranchId, layout.getPlid(),
247                                    layoutRevision.getParentLayoutRevisionId());
248    
249                            updateLayout = false;
250                    }
251    
252                    if (updateLayout) {
253    
254                            // LEP-3648
255    
256                            layoutTypePortlet.resetModes();
257                            layoutTypePortlet.resetStates();
258    
259                            layout = LayoutServiceUtil.updateLayout(
260                                    layout.getGroupId(), layout.isPrivateLayout(),
261                                    layout.getLayoutId(), layout.getTypeSettings());
262    
263                            // See LEP-1411. Delay the delete of extraneous portlet resources
264                            // only after the user has proven that he has the valid permissions.
265    
266                            if (deletePortlet) {
267                                    String rootPortletId = PortletConstants.getRootPortletId(
268                                            portletId);
269    
270                                    ResourceLocalServiceUtil.deleteResource(
271                                            layout.getCompanyId(), rootPortletId,
272                                            ResourceConstants.SCOPE_INDIVIDUAL,
273                                            PortletPermissionUtil.getPrimaryKey(
274                                                    layout.getPlid(), portletId));
275                            }
276                    }
277                    else {
278                            LayoutClone layoutClone = LayoutCloneFactory.getInstance();
279    
280                            if (layoutClone != null) {
281                                    layoutClone.update(
282                                            request, layout.getPlid(), layout.getTypeSettings());
283                            }
284                    }
285    
286                    if (cmd.equals(Constants.ADD) && (portletId != null)) {
287                            addPortlet(mapping, form, request, response, portletId);
288                    }
289    
290                    return StringPool.BLANK;
291            }
292    
293            protected void addPortlet(
294                            ActionMapping mapping, ActionForm form, HttpServletRequest request,
295                            HttpServletResponse response, String portletId)
296                    throws Exception {
297    
298                    // Run the render portlet action to add a portlet without refreshing.
299    
300                    Action renderPortletAction = (Action)InstancePool.get(
301                            RenderPortletAction.class.getName());
302    
303                    // Pass in the portlet id because the portlet id may be the instance id.
304                    // Namespace the request if necessary. See LEP-4644.
305    
306                    long companyId = PortalUtil.getCompanyId(request);
307    
308                    Portlet portlet = PortletLocalServiceUtil.getPortletById(
309                            companyId, portletId);
310    
311                    DynamicServletRequest dynamicRequest = null;
312    
313                    if (portlet.isPrivateRequestAttributes()) {
314                            String portletNamespace = PortalUtil.getPortletNamespace(
315                                    portlet.getPortletId());
316    
317                            dynamicRequest = new NamespaceServletRequest(
318                                    request, portletNamespace, portletNamespace);
319                    }
320                    else {
321                            dynamicRequest = new DynamicServletRequest(request);
322                    }
323    
324                    dynamicRequest.setParameter("p_p_id", portletId);
325    
326                    String dataType = ParamUtil.getString(request, "dataType");
327    
328                    if (dataType.equals("json")) {
329                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
330    
331                            StringServletResponse stringResponse = new StringServletResponse(
332                                    response);
333    
334                            renderPortletAction.execute(
335                                    mapping, form, dynamicRequest, stringResponse);
336    
337                            populatePortletJSONObject(
338                                    request, stringResponse, portlet, jsonObject);
339    
340                            response.setContentType(ContentTypes.TEXT_JAVASCRIPT);
341    
342                            ServletResponseUtil.write(response, jsonObject.toString());
343                    }
344                    else {
345                            renderPortletAction.execute(
346                                    mapping, form, dynamicRequest, response);
347                    }
348            }
349    
350            protected String getRootPortletId(Portlet portlet) {
351    
352                    // Workaround for portlet.getRootPortletId() because that does not
353                    // return the proper root portlet ID for OpenSocial and WSRP portlets
354    
355                    Portlet rootPortlet = portlet.getRootPortlet();
356    
357                    return rootPortlet.getPortletId();
358            }
359    
360            protected void populatePortletJSONObject(
361                            HttpServletRequest request, StringServletResponse stringResponse,
362                            Portlet portlet, JSONObject jsonObject)
363                    throws Exception {
364    
365                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
366                            WebKeys.THEME_DISPLAY);
367    
368                    LayoutTypePortlet layoutTypePortlet =
369                            themeDisplay.getLayoutTypePortlet();
370    
371                    jsonObject.put("refresh", !portlet.isAjaxable());
372                    jsonObject.put("portletHTML", stringResponse.getString().trim());
373    
374                    Set<String> footerCssSet = new LinkedHashSet<String>();
375                    Set<String> footerJavaScriptSet = new LinkedHashSet<String>();
376                    Set<String> headerCssSet = new LinkedHashSet<String>();
377                    Set<String> headerJavaScriptSet = new LinkedHashSet<String>();
378    
379                    boolean portletOnLayout = false;
380    
381                    String rootPortletId = getRootPortletId(portlet);
382                    String portletId = portlet.getPortletId();
383    
384                    for (Portlet layoutPortlet : layoutTypePortlet.getAllPortlets()) {
385    
386                            // Check to see if an instance of this portlet is already in the
387                            // layout, but ignore the portlet that was just added
388    
389                            String layoutPortletRootPortletId = getRootPortletId(layoutPortlet);
390    
391                            if (rootPortletId.equals(layoutPortletRootPortletId) &&
392                                    !portletId.equals(layoutPortlet.getPortletId())) {
393    
394                                    portletOnLayout = true;
395    
396                                    break;
397                            }
398                    }
399    
400                    PortletApp portletApp = portlet.getPortletApp();
401    
402                    if (!portletOnLayout && portlet.isAjaxable()) {
403                            Portlet rootPortlet = portlet.getRootPortlet();
404    
405                            for (String footerPortalCss : portlet.getFooterPortalCss()) {
406                                    if (!HttpUtil.hasProtocol(footerPortalCss)) {
407                                            footerPortalCss =
408                                                    PortalUtil.getPathContext() + footerPortalCss;
409    
410                                            footerPortalCss = PortalUtil.getStaticResourceURL(
411                                                    request, footerPortalCss, rootPortlet.getTimestamp());
412                                    }
413    
414                                    footerCssSet.add(footerPortalCss);
415                            }
416    
417                            for (String footerPortalJavaScript :
418                                            portlet.getFooterPortalJavaScript()) {
419    
420                                    if (!HttpUtil.hasProtocol(footerPortalJavaScript)) {
421                                            footerPortalJavaScript =
422                                                    PortalUtil.getPathContext() + footerPortalJavaScript;
423    
424                                            footerPortalJavaScript = PortalUtil.getStaticResourceURL(
425                                                    request, footerPortalJavaScript,
426                                                    rootPortlet.getTimestamp());
427                                    }
428    
429                                    footerJavaScriptSet.add(footerPortalJavaScript);
430                            }
431    
432                            for (String footerPortletCss : portlet.getFooterPortletCss()) {
433                                    if (!HttpUtil.hasProtocol(footerPortletCss)) {
434                                            footerPortletCss =
435                                                    portletApp.getContextPath() + footerPortletCss;
436    
437                                            footerPortletCss = PortalUtil.getStaticResourceURL(
438                                                    request, footerPortletCss, rootPortlet.getTimestamp());
439                                    }
440    
441                                    footerCssSet.add(footerPortletCss);
442                            }
443    
444                            for (String footerPortletJavaScript :
445                                            portlet.getFooterPortletJavaScript()) {
446    
447                                    if (!HttpUtil.hasProtocol(footerPortletJavaScript)) {
448                                            footerPortletJavaScript =
449                                                    portletApp.getContextPath() + footerPortletJavaScript;
450    
451                                            footerPortletJavaScript = PortalUtil.getStaticResourceURL(
452                                                    request, footerPortletJavaScript,
453                                                    rootPortlet.getTimestamp());
454                                    }
455    
456                                    footerJavaScriptSet.add(footerPortletJavaScript);
457                            }
458    
459                            for (String headerPortalCss : portlet.getHeaderPortalCss()) {
460                                    if (!HttpUtil.hasProtocol(headerPortalCss)) {
461                                            headerPortalCss =
462                                                    PortalUtil.getPathContext() + headerPortalCss;
463    
464                                            headerPortalCss = PortalUtil.getStaticResourceURL(
465                                                    request, headerPortalCss, rootPortlet.getTimestamp());
466                                    }
467    
468                                    headerCssSet.add(headerPortalCss);
469                            }
470    
471                            for (String headerPortalJavaScript :
472                                            portlet.getHeaderPortalJavaScript()) {
473    
474                                    if (!HttpUtil.hasProtocol(headerPortalJavaScript)) {
475                                            headerPortalJavaScript =
476                                                    PortalUtil.getPathContext() + headerPortalJavaScript;
477    
478                                            headerPortalJavaScript = PortalUtil.getStaticResourceURL(
479                                                    request, headerPortalJavaScript,
480                                                    rootPortlet.getTimestamp());
481                                    }
482    
483                                    headerJavaScriptSet.add(headerPortalJavaScript);
484                            }
485    
486                            for (String headerPortletCss : portlet.getHeaderPortletCss()) {
487                                    if (!HttpUtil.hasProtocol(headerPortletCss)) {
488                                            headerPortletCss =
489                                                    portletApp.getContextPath() + headerPortletCss;
490    
491                                            headerPortletCss = PortalUtil.getStaticResourceURL(
492                                                    request, headerPortletCss, rootPortlet.getTimestamp());
493                                    }
494    
495                                    headerCssSet.add(headerPortletCss);
496                            }
497    
498                            for (String headerPortletJavaScript :
499                                            portlet.getHeaderPortletJavaScript()) {
500    
501                                    if (!HttpUtil.hasProtocol(headerPortletJavaScript)) {
502                                            headerPortletJavaScript =
503                                                    portletApp.getContextPath() + headerPortletJavaScript;
504    
505                                            headerPortletJavaScript = PortalUtil.getStaticResourceURL(
506                                                    request, headerPortletJavaScript,
507                                                    rootPortlet.getTimestamp());
508                                    }
509    
510                                    headerJavaScriptSet.add(headerPortletJavaScript);
511                            }
512                    }
513    
514                    String footerCssPaths = JSONFactoryUtil.serialize(
515                            footerCssSet.toArray(new String[footerCssSet.size()]));
516    
517                    jsonObject.put(
518                            "footerCssPaths", JSONFactoryUtil.createJSONArray(footerCssPaths));
519    
520                    String footerJavaScriptPaths = JSONFactoryUtil.serialize(
521                            footerJavaScriptSet.toArray(
522                                    new String[footerJavaScriptSet.size()]));
523    
524                    jsonObject.put(
525                            "footerJavaScriptPaths",
526                            JSONFactoryUtil.createJSONArray(footerJavaScriptPaths));
527    
528                    String headerCssPaths = JSONFactoryUtil.serialize(
529                            headerCssSet.toArray(new String[headerCssSet.size()]));
530    
531                    jsonObject.put(
532                            "headerCssPaths", JSONFactoryUtil.createJSONArray(headerCssPaths));
533    
534                    String headerJavaScriptPaths = JSONFactoryUtil.serialize(
535                            headerJavaScriptSet.toArray(
536                                    new String[headerJavaScriptSet.size()]));
537    
538                    jsonObject.put(
539                            "headerJavaScriptPaths",
540                            JSONFactoryUtil.createJSONArray(headerJavaScriptPaths));
541            }
542    
543    }