001/*
002 *  Copyright 2017 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.frontedition;
017
018import java.util.HashMap;
019import java.util.List;
020import java.util.Map;
021
022import javax.jcr.RepositoryException;
023
024import org.apache.avalon.framework.component.Component;
025import org.apache.avalon.framework.context.Context;
026import org.apache.avalon.framework.context.ContextException;
027import org.apache.avalon.framework.context.Contextualizable;
028import org.apache.avalon.framework.logger.AbstractLogEnabled;
029import org.apache.avalon.framework.service.ServiceException;
030import org.apache.avalon.framework.service.ServiceManager;
031import org.apache.avalon.framework.service.Serviceable;
032import org.apache.cocoon.components.ContextHelper;
033import org.apache.cocoon.environment.Request;
034
035import org.ametys.cms.repository.Content;
036import org.ametys.core.ui.Callable;
037import org.ametys.plugins.repository.AmetysObject;
038import org.ametys.plugins.repository.AmetysObjectResolver;
039import org.ametys.plugins.repository.AmetysRepositoryException;
040import org.ametys.plugins.repository.UnknownAmetysObjectException;
041import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject;
042import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector;
043import org.ametys.web.repository.page.Page;
044import org.ametys.web.repository.page.ZoneDAO;
045import org.ametys.web.repository.page.ZoneItem;
046
047/**
048 * Various helpers for front-edition plugin
049 */
050public class FrontEditionHelper extends AbstractLogEnabled implements Serviceable, Component, Contextualizable
051{
052    /** Avalon Role */
053    public static final String ROLE = FrontEditionHelper.class.getName();
054    
055    /** The Ametys object resolver */
056    private AmetysObjectResolver _ametysObjectResolver;
057    private ZoneDAO _zoneDAO;
058    /** Context */
059    private Context _context;
060    
061    public void service(ServiceManager manager) throws ServiceException
062    {
063        _ametysObjectResolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
064        _zoneDAO = (ZoneDAO) manager.lookup(ZoneDAO.ROLE);
065    }
066
067    public void contextualize(Context context) throws ContextException
068    {
069        _context = context;
070    }
071    
072    /**
073     * Get the first available parent for the current page, in the live workspace
074     * @param pageId id of the page that need to be checked
075     * @return path of the parent (can be this page if available in live)
076     */
077    @Callable
078    public String firstAvailableParentInLivePath(String pageId)
079    {
080        AmetysObject resolveById = _ametysObjectResolver.resolveById(pageId);
081        if (resolveById instanceof Page)
082        {
083            Page page = (Page) resolveById;
084            return firstAvailableParentInLivePath(page);
085        }
086        else
087        {
088            return "";
089        }
090    }
091    /**
092     * Get the first available parent for the requested page, in the live version
093     * @param page page to check
094     * @return path of the parent (can be this page if available in live)
095     */
096    public String firstAvailableParentInLivePath(Page page)
097    {
098        Request request = ContextHelper.getRequest(_context);
099        if (page == null)
100        {
101            return "";
102        }
103        AmetysObject available = page;
104        Page availablePage = null;
105        boolean found = false;
106        String forcedWorkspace = RequestAttributeWorkspaceSelector.getForcedWorkspace(request);
107        try
108        {
109            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, "live");
110    
111            while (!found)
112            {
113                try
114                {
115                    AmetysObject resolveById = _ametysObjectResolver.resolveById(available.getId());
116                    if (resolveById != null)
117                    {
118                        found = true;
119                    }
120                    else
121                    {
122                        available = available.getParent();
123                    }
124                }
125                catch (UnknownAmetysObjectException e)
126                {
127                    available = available.getParent();
128                }
129            }
130
131            if (available instanceof Page)
132            {
133                availablePage = (Page) available;
134            }
135        }
136        finally
137        {
138            //reset workspace
139            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, forcedWorkspace);
140        }
141        return availablePage == null ? "" : availablePage.getPathInSitemap();
142    }
143
144    /**
145     * Get the name of a workflow action by it's id
146     * @param contentId id of the content to check if action is available
147     * @param workflowName name of the workflow checked
148     * @param actionIds actions where the name needs to be retreived
149     * @return workwflow action name
150     */
151    @Callable
152    public Map<Integer, String> getWorkflowActionName(String contentId, String workflowName, List<Integer> actionIds)
153    {
154        Map<Integer, String> result = new HashMap<>();
155        for (Integer actionId : actionIds)
156        {
157            boolean hasWorkflowRight = AmetysFrontEditionHelper.hasWorkflowRight(actionId, contentId, false);
158            if (hasWorkflowRight)
159            {
160                String translatedName = AmetysFrontEditionHelper.getWorkflowName(workflowName, actionId);
161                result.put(actionId, translatedName);
162            }
163        }
164        return result;
165    }
166    
167    /**
168     * Check if contents are modifiable and check all attributes restriction
169     * @param actionId the edit action id
170     * @param contentIds the id of contents
171     * @param checkEditionMode Check if we are in edition mode or not
172     * @return A Map with content id as key. The value is null if content is unmodifiable or a map of content informations as an array with path of unmodifiable attributes otherwise
173     */
174    @Callable
175    public Map<String, Object> getModifiableContents(int actionId, List<String> contentIds, boolean checkEditionMode)
176    {
177        Map<String, Object> result = new HashMap<>();
178        for (String contentId : contentIds)
179        {
180            Content content = _ametysObjectResolver.resolveById(contentId);
181            
182            Map<String, Object> contentInfo = new HashMap<>();
183            contentInfo.put("unmodifiableAttributes", AmetysFrontEditionHelper.getUnmodifiableAttributes(content, List.of(actionId), checkEditionMode));
184            contentInfo.put("rights", AmetysFrontEditionHelper.getRightsForContent(content));
185            
186            result.put(contentId, contentInfo);
187        }
188        
189        return result;
190    }
191    
192    /**
193     * Move a zone item of a page before/after another zone item of the same page
194     * @param zoneItemId zone item to move
195     * @param zoneName name of the zone
196     * @param pageId page Id
197     * @param offset how many item back/forward to move ? (negative for up, positive to down)
198     * @return true if success
199     * @throws UnknownAmetysObjectException If an error occurred
200     * @throws AmetysRepositoryException If an error occurred
201     * @throws RepositoryException If an error occurred
202     */
203    @Callable
204    public boolean moveZoneItemId(String zoneItemId, String zoneName, String pageId, int offset) throws UnknownAmetysObjectException, AmetysRepositoryException, RepositoryException
205    {
206        ZoneItem zoneItem = _ametysObjectResolver.resolveById(zoneItemId);
207        AmetysObject parent = zoneItem.getParent();
208        if (parent instanceof DefaultTraversableAmetysObject)
209        {
210            DefaultTraversableAmetysObject traversableParent = (DefaultTraversableAmetysObject) parent;
211            long itemPosition = traversableParent.getChildPosition(zoneItem);
212            long targetPosition = itemPosition + offset;
213            ZoneItem targetZoneItem = traversableParent.getChildAt(targetPosition);
214            return _zoneDAO.moveZoneItemTo(zoneItemId, zoneName, offset < 0, targetZoneItem.getId(), pageId);
215        }
216        return false;
217    }
218}