001/*
002 *  Copyright 2013 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.cms.clientsideelement.content;
017
018import java.util.ArrayList;
019import java.util.Arrays;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023import java.util.Set;
024
025import org.apache.avalon.framework.component.Component;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.avalon.framework.service.Serviceable;
029import org.apache.commons.lang.StringUtils;
030
031import org.ametys.cms.clientsideelement.SmartContentClientSideElement;
032import org.ametys.cms.repository.Content;
033import org.ametys.cms.repository.ModifiableContent;
034import org.ametys.cms.repository.WorkflowAwareContent;
035import org.ametys.cms.workflow.AbstractContentWorkflowComponent;
036import org.ametys.core.right.RightManager;
037import org.ametys.core.right.RightManager.RightResult;
038import org.ametys.core.user.CurrentUserProvider;
039import org.ametys.core.user.User;
040import org.ametys.core.user.UserIdentity;
041import org.ametys.core.user.UserManager;
042import org.ametys.plugins.repository.lock.LockHelper;
043import org.ametys.plugins.repository.lock.LockableAmetysObject;
044import org.ametys.plugins.workflow.support.WorkflowProvider;
045import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow;
046import org.ametys.runtime.i18n.I18nizableText;
047
048import com.opensymphony.workflow.spi.Step;
049
050/**
051 * Component helper for {@link SmartContentClientSideElement}
052 *
053 */
054public class SmartContentClientSideElementHelper implements Serviceable, Component
055{
056    /** The Avalon Role */
057    public static final String ROLE = SmartContentClientSideElementHelper.class.getName();
058    
059    private UserManager _userManager;
060    private WorkflowProvider _workflowProvider;
061    private CurrentUserProvider _userProvider;
062    private RightManager _rightManager;
063    
064    @Override
065    public void service(ServiceManager manager) throws ServiceException
066    {
067        _userManager = (UserManager) manager.lookup(UserManager.ROLE);
068        _workflowProvider = (WorkflowProvider) manager.lookup(WorkflowProvider.ROLE);
069        _userProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE);
070        _rightManager = (RightManager) manager.lookup(RightManager.ROLE);
071    }
072    
073    /**
074     * Determines if the workflow step is correct
075     * @param parameters The client side element 's parameters
076     * @param content the content
077     * @return true if the workflow step is incorrect
078     */
079    public boolean isWorkflowStepCorrect(Map<String, Object> parameters, Content content)
080    {
081        WorkflowAwareContent waContent = (WorkflowAwareContent) content;
082        AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(waContent);
083        long wId = waContent.getWorkflowId();
084        List<Step> steps = workflow.getCurrentSteps(wId);
085        
086        List<Integer> stepIds = new ArrayList<>();
087        for (Step step : steps)
088        {
089            stepIds.add(step.getStepId());
090        }
091
092        String correctStepsAsString = parameters.get("enabled-on-workflow-step-only").toString();
093        String[] correctStepsAsStringArray = correctStepsAsString.split(", ?");
094        
095        for (String correctStepAsString : correctStepsAsStringArray)
096        {
097            if (!StringUtils.isEmpty(correctStepAsString) && stepIds.contains(Integer.parseInt(correctStepAsString)))
098            {
099                return true;
100            }
101        }
102        
103        return false;
104    }
105    
106    /**
107     * Get i18n description when user can not do action because he has no right on content
108     * @param parameters The client side element 's parameters
109     * @param content The content
110     * @return The {@link I18nizableText} description
111     */
112    public I18nizableText getNoRightDescription (Map<String, Object> parameters, Content content)
113    {
114        List<String> rightI18nParameters = new ArrayList<>();
115        rightI18nParameters.add(content.getTitle());
116        
117        I18nizableText ed = (I18nizableText) parameters.get("noright-content-description");
118        return  new I18nizableText(ed.getCatalogue(), ed.getKey(), rightI18nParameters);
119    }
120    
121    /**
122     * Get i18n description when user can not do action because the content is locked
123     * @param parameters The client side element 's parameters
124     * @param content The content
125     * @return The {@link I18nizableText} description
126     */
127    public I18nizableText getLockedDescription (Map<String, Object> parameters, Content content)
128    {
129        UserIdentity currentLockerIdentity = ((LockableAmetysObject) content).getLockOwner();
130        User currentLocker = currentLockerIdentity != null ? _userManager.getUser(currentLockerIdentity.getPopulationId(), currentLockerIdentity.getLogin()) : null;
131        
132        List<String> lockI18nParameters = new ArrayList<>();
133        lockI18nParameters.add(content.getTitle());
134        lockI18nParameters.add(currentLocker != null ? currentLocker.getFullName() : "");
135        lockI18nParameters.add(currentLockerIdentity != null ? currentLockerIdentity.getLogin() : "Anonymous");
136        
137        I18nizableText ed = (I18nizableText) parameters.get("locked-content-description");
138        return new I18nizableText(ed.getCatalogue(), ed.getKey(), lockI18nParameters);
139    }
140    
141    /**
142     * Get i18n description when user can not do action because there is no workflow action unvailable
143     * @param parameters The client side element 's parameters
144     * @param content The content
145     * @return The {@link I18nizableText} description
146     */
147    public I18nizableText getWorkflowActionUnvailableDescription (Map<String, Object> parameters, Content content)
148    {
149        List<String> workflowI18nParameters = new ArrayList<>();
150        workflowI18nParameters.add(content.getTitle());
151        
152        I18nizableText ed = (I18nizableText) parameters.get("workflowaction-content-description");
153        return new I18nizableText(ed.getCatalogue(), ed.getKey(), workflowI18nParameters);
154    }
155    
156    /**
157     * Get i18n description when user can not do action because the workflow step is incorrect
158     * @param parameters The client side element 's parameters
159     * @param content The content
160     * @return The {@link I18nizableText} description
161     */
162    public I18nizableText getIncorrectWorkflowStepDescription (Map<String, Object> parameters, Content content)
163    {
164        List<String> workflowI18nParameters = new ArrayList<>();
165        workflowI18nParameters.add(content.getTitle());
166        
167        I18nizableText ed = (I18nizableText) parameters.get("workflowstep-content-description");
168        return new I18nizableText(ed.getCatalogue(), ed.getKey(), workflowI18nParameters);
169    }
170    
171    /**
172     * Get i18n description when user can not do action because the content is not modifiable
173     * @param parameters The client side element 's parameters
174     * @param content The content
175     * @return The {@link I18nizableText} description
176     */
177    public I18nizableText getNoModifiableDescription (Map<String, Object> parameters, Content content)
178    {
179        List<String> modifiableI18nParameters = new ArrayList<>();
180        modifiableI18nParameters.add(content.getTitle());
181        
182        I18nizableText ed = (I18nizableText) parameters.get("nomodifiable-content-description");
183        return new I18nizableText(ed.getCatalogue(), ed.getKey(), modifiableI18nParameters);
184    }
185    
186    /**
187     * Get i18n description when user can do action
188     * @param parameters The client side element 's parameters
189     * @param content The content
190     * @return The {@link I18nizableText} description
191     */
192    public I18nizableText getAllRightDescription (Map<String, Object> parameters, Content content)
193    {
194        List<String> allrightI18nParameters = new ArrayList<>();
195        allrightI18nParameters.add(content.getTitle());
196        
197        I18nizableText ed = (I18nizableText) parameters.get("allright-content-description");
198        return new I18nizableText(ed.getCatalogue(), ed.getKey(), allrightI18nParameters);
199    }
200    
201    /**
202     * Determines if the content is locked
203     * @param content the content
204     * @return true if the content is locked
205     */
206    public boolean isLocked(Content content)
207    {
208        if (content instanceof LockableAmetysObject)
209        {
210            LockableAmetysObject lockableContent = (LockableAmetysObject) content;
211            if (lockableContent.isLocked() && !LockHelper.isLockOwner(lockableContent, _userProvider.getUser()))
212            {
213                return true;
214            }
215        }
216        
217        return false;
218    }
219    
220    /**
221     * Determines if the content is modifiable
222     * @param content the content
223     * @return true if the content is modifiable
224     */
225    public boolean isModifiable(Content content)
226    {
227        return content instanceof ModifiableContent;
228    }
229    
230    /**
231     * Determines if the user has sufficient right for the given content
232     * @param rights The client side element 's rights
233     * @param content the content
234     * @return true if user has sufficient right
235     */
236    public boolean hasRight (Map<String, String> rights, Content content)
237    {
238        if (rights.isEmpty())
239        {
240            return true;
241        }
242        
243        Set<String> rightsToCheck = rights.keySet();
244        for (String rightToCheck : rightsToCheck)
245        {
246            if (StringUtils.isNotEmpty(rightToCheck))
247            {
248                if (_rightManager.hasRight(_userProvider.getUser(), rightToCheck, content) == RightResult.RIGHT_ALLOW)
249                {
250                    return true;
251                }
252            }
253        }
254        
255        return false;
256    }
257    
258    /**
259     * Determines if the workflow action is correct
260     * @param parameters The client side element 's parameters
261     * @param content the content
262     * @return true if the workflow action is incorrect
263     */
264    public int workflowAction(Map<String, Object> parameters, Content content)
265    {
266        WorkflowAwareContent waContent = (WorkflowAwareContent) content;
267        AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(waContent);
268        long wId = waContent.getWorkflowId();
269        
270        Map<String, Object> vars = new HashMap<>();
271        vars.put(AbstractContentWorkflowComponent.CONTENT_KEY, content);
272        int[] actionIds = workflow.getAvailableActions(wId, vars);
273        Arrays.sort(actionIds);
274        
275        String correctActionsAsString = parameters.get("enabled-on-workflow-action-only").toString();
276        String[] correctActionsAsStringArray = correctActionsAsString.split(", ?");
277        
278        int correctActionId = -1;
279        for (String correctActionAsString : correctActionsAsStringArray)
280        {
281            int actionId = Integer.parseInt(correctActionAsString);
282            if (!StringUtils.isEmpty(correctActionAsString) && Arrays.binarySearch(actionIds, actionId) >= 0)
283            {
284                correctActionId = actionId;
285                break;
286            }
287        }
288        
289        return correctActionId;
290    }
291    
292}