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