001/*
002 *  Copyright 2014 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.lock;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.avalon.framework.component.Component;
024import org.apache.avalon.framework.logger.AbstractLogEnabled;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.avalon.framework.service.Serviceable;
028import org.apache.commons.lang.StringUtils;
029
030import org.ametys.cms.content.ContentHelper;
031import org.ametys.cms.repository.Content;
032import org.ametys.core.right.RightManager;
033import org.ametys.core.right.RightManager.RightResult;
034import org.ametys.core.ui.Callable;
035import org.ametys.core.user.CurrentUserProvider;
036import org.ametys.core.user.UserIdentity;
037import org.ametys.plugins.core.user.UserHelper;
038import org.ametys.plugins.repository.AmetysObjectResolver;
039import org.ametys.plugins.repository.AmetysRepositoryException;
040import org.ametys.plugins.repository.lock.LockAwareAmetysObject;
041import org.ametys.plugins.repository.lock.LockHelper;
042import org.ametys.plugins.repository.lock.LockableAmetysObject;
043
044
045/**
046 * Unlock or lock one or several content(s) 
047 */
048public class LockContentManager extends AbstractLogEnabled implements Serviceable, Component
049{
050    
051    /** The component role. */
052    public static final String ROLE = LockContentManager.class.getName();
053    
054    /** The "unlock all" right ID. */
055    public static final String UNLOCK_ALL_RIGHT = "CMS_Rights_UnlockAll";
056    
057    /** The rights manager */
058    protected RightManager _rightManager;
059    /** The Ametys object resolver */
060    protected AmetysObjectResolver _resolver;
061    /**  The current user provider.*/
062    protected CurrentUserProvider _currentUserProvider;
063    /** Helper for users */
064    protected UserHelper _userHelper;
065    /** The content helper */
066    protected ContentHelper _contentHelper;
067    
068    @Override
069    public void service(ServiceManager smanager) throws ServiceException
070    {
071        _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE);
072        _userHelper = (UserHelper) smanager.lookup(UserHelper.ROLE);
073        _rightManager = (RightManager) smanager.lookup(RightManager.ROLE);
074        _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE);
075        _contentHelper = (ContentHelper) smanager.lookup(ContentHelper.ROLE);
076    }
077    
078    /**
079     * Test if the current user can unlock the given locked object.<br>
080     * A user can unlock a locked object if he is the lock owner, or if he has the right to unlock all objects.
081     * @param object the locked object to test.
082     * @return true if the current user can unlock the given locked object, false otherwise.
083     */
084    public boolean canUnlock(LockAwareAmetysObject object)
085    {
086        return canUnlock(object, _currentUserProvider.getUser());
087    }
088    
089    /**
090     * Test if a specific user can unlock the given locked object.<br>
091     * A user can unlock a locked object if he is the lock owner, or if he has the right to unlock all objects.
092     * @param object the locked object to test.
093     * @param user the user.
094     * @return true if the current user can unlock the given locked object, false otherwise.
095     */
096    public boolean canUnlock(LockAwareAmetysObject object, UserIdentity user)
097    {
098        return LockHelper.isLockOwner(object, user) || canUnlockAll(user);
099    }
100    
101    /**
102     * Test if the current user has the right to unlock all contents.
103     * @return true if the current user has the right to unlock all contents, false otherwise.
104     */
105    public boolean canUnlockAll()
106    {
107        return canUnlockAll(_currentUserProvider.getUser());
108    }
109    
110    /**
111     * Test if a specific user has the right to unlock all contents.
112     * @param user the user.
113     * @return true if the user has the right to unlock all contents, false otherwise.
114     */
115    public boolean canUnlockAll(UserIdentity user)
116    {
117        return _rightManager.hasRight(_currentUserProvider.getUser(), UNLOCK_ALL_RIGHT, "/cms") == RightResult.RIGHT_ALLOW;
118    }
119    
120    /**
121     * Unlock or lock contents
122     * @param contents the contents to unlock or lock
123     * @param mode the mode ('lock' or 'unlock')
124     * @return the result JSON map
125     */
126    @Callable
127    public Map<String, Object> unlockOrLock(List<String> contents, String mode) 
128    {
129        Map<String, Object> result = new HashMap<>();
130        
131        if ("unlock".equals(mode))
132        {
133            result = unlock(contents);
134        }
135        else
136        {
137            result = lock(contents);
138        }
139        
140        result.put("mode", mode);
141        return result;
142    }
143    
144    /**
145     * Unlock contents
146     * @param contents The ids of contents to unlock
147     * @return the result JSON map
148     */
149    protected Map<String, Object> unlock(List<String> contents)
150    {
151        UserIdentity currentUser = _currentUserProvider.getUser();
152        boolean canDelockAll = _rightManager.hasRight(currentUser, "CMS_Rights_UnlockAll", "/cms") == RightResult.RIGHT_ALLOW;
153        
154        List<String> unlockContentsId = new ArrayList<>();
155        String unlockedContents = "";
156        String stillLockedContents = "";
157        String failLockedContents = "";
158        
159        for (String contentId : contents)
160        {
161            LockableAmetysObject lockableContent = (LockableAmetysObject) _resolver.resolveById(contentId);
162            if (!lockableContent.isLocked())
163            {
164                getLogger().warn("The content '" + contentId + "' is not locked anymore.");
165            }
166            else if (!LockHelper.isLockOwner(lockableContent, currentUser) && !canDelockAll)
167            {
168                getLogger().warn("The user '" + currentUser + "' try to unlock content '" + contentId + "' but he is not the lock owner");
169                
170                if (stillLockedContents.length() > 0)
171                {
172                    stillLockedContents += ", ";
173                }
174                stillLockedContents += _contentHelper.getTitle((Content) lockableContent);
175            }
176            else
177            {
178                try
179                {
180                    lockableContent.unlock();
181                    
182                    unlockContentsId.add(contentId);
183                    if (unlockedContents.length() > 0)
184                    {
185                        unlockedContents += ", ";
186                    }
187                    unlockedContents += _contentHelper.getTitle((Content) lockableContent);
188                    if (getLogger().isDebugEnabled())
189                    {
190                        getLogger().debug("The user was unlocked content '" + contentId + "'");
191                    }
192                    
193                }
194                catch (AmetysRepositoryException e)
195                {
196                    getLogger().error("Unable to unlock content '" + contentId + "'", e);
197                    
198                    if (failLockedContents.length() > 0)
199                    {
200                        failLockedContents += ", ";
201                    }
202                    failLockedContents += _contentHelper.getTitle((Content) lockableContent);
203                }
204            }
205        }
206        
207        Map<String, Object> result = new HashMap<>();
208        
209        result.put("unlocked-contents-id", StringUtils.join(unlockContentsId, ","));
210        result.put("unlocked-contents", unlockedContents);
211        result.put("still-locked-contents", stillLockedContents);
212        result.put("fail-unlocked-contents", failLockedContents);
213        
214        return result;
215    }
216    
217    /**
218     * Lock contents
219     * @param contents The ids of contents to lock
220     * @return the result JSON map
221     */
222    protected Map<String, Object> lock (List<String> contents)
223    {
224        List<String> lockContentsId = new ArrayList<>();
225        String lockedContents = "";
226        String alreadyLockedContents = "";
227        String failUnlockedContents = "";
228        
229        for (String contentId : contents)
230        {
231            LockableAmetysObject lockableContent = (LockableAmetysObject) _resolver.resolveById(contentId);
232            if (lockableContent.isLocked() && !LockHelper.isLockOwner(lockableContent, _currentUserProvider.getUser()))
233            {
234                getLogger().warn("The content '" + contentId + "' is already locked.");
235                if (alreadyLockedContents.length() > 0)
236                {
237                    alreadyLockedContents += ", ";
238                }
239                alreadyLockedContents += _contentHelper.getTitle((Content) lockableContent);
240            }
241            else if (!lockableContent.isLocked())
242            {
243                try
244                {
245                    lockableContent.lock();
246                    lockContentsId.add(contentId);
247                    if (lockedContents.length() > 0)
248                    {
249                        lockedContents += ", ";
250                    }
251                    lockedContents += _contentHelper.getTitle((Content) lockableContent);
252                }
253                catch (AmetysRepositoryException e)
254                {
255                    getLogger().error("Unable to lock content '" + contentId + "'", e);
256                    if (failUnlockedContents.length() > 0)
257                    {
258                        failUnlockedContents += ", ";
259                    }
260                    failUnlockedContents += _contentHelper.getTitle((Content) lockableContent);
261                }
262            }
263        }
264        
265        Map<String, Object> result = new HashMap<>();
266        
267        result.put("locked-contents-id", StringUtils.join(lockContentsId, ","));
268        result.put("locked-contents", lockedContents);
269        result.put("already-locked-contents", alreadyLockedContents);
270        result.put("fail-locked-contents", failUnlockedContents);
271        
272        UserIdentity currentUser = _currentUserProvider.getUser();
273        result.put("lockOwner", _userHelper.user2json(currentUser));
274        
275        return result;
276    }
277}