001/*
002 *  Copyright 2010 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.odf.clientsideelement;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.HashSet;
021import java.util.List;
022import java.util.Map;
023import java.util.Set;
024import java.util.stream.Collectors;
025
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.commons.lang3.tuple.Pair;
029
030import org.ametys.cms.repository.Content;
031import org.ametys.core.ui.Callable;
032import org.ametys.odf.ODFHelper;
033import org.ametys.odf.ProgramItem;
034import org.ametys.odf.course.Course;
035import org.ametys.odf.helper.DeleteODFContentHelper;
036import org.ametys.odf.orgunit.OrgUnit;
037import org.ametys.odf.orgunit.RootOrgUnitProvider;
038
039/**
040 * This element creates an action button to delete a ODF content
041 */
042public class DeleteContentClientSideElement extends org.ametys.cms.clientsideelement.DeleteContentClientSideElement
043{
044    /** The root orgunit provider */
045    protected RootOrgUnitProvider _rootOrgUnitProvider;
046    
047    /** The delete ODF content helper */
048    protected DeleteODFContentHelper _deleteODFContentHelper;
049
050    /** The ODF helper */
051    protected ODFHelper _odfHelper;
052    
053    @Override
054    public void service(ServiceManager manager) throws ServiceException
055    {
056        super.service(manager);
057        _rootOrgUnitProvider = (RootOrgUnitProvider) manager.lookup(RootOrgUnitProvider.ROLE);
058        _deleteODFContentHelper = (DeleteODFContentHelper) manager.lookup(DeleteODFContentHelper.ROLE);
059        _odfHelper = (ODFHelper) manager.lookup(ODFHelper.ROLE);
060    }
061
062    @Override
063    protected boolean _hasRight(Content content)
064    {
065        return _deleteODFContentHelper.hasRight(content);
066    }
067    
068    @Override
069    protected boolean _isModifiable(Content content)
070    {
071        if (content instanceof OrgUnit && _rootOrgUnitProvider.isRoot(content.getId()))
072        {
073            // The root orgunit can not be deleted
074            return false;
075        }
076        
077        return super._isModifiable(content);
078    }
079    
080    @Override
081    protected boolean _isContentReferenced(Content content)
082    {
083        return _deleteODFContentHelper.isContentReferenced(content);
084    }
085    
086    /**
087     * Get information of the program item structure (type, if program has children)
088     * @param programItemIds the list of program item id
089     * @return a map of information
090     */
091    @Callable
092    public Map<String, Object> getStructureInfo(List<String> programItemIds)
093    {
094        Map<String, Object> results = new HashMap<>();
095        results.putAll(_odfHelper.getStructureInfo(programItemIds));
096        
097        // For the deletion, we need to have the number of content to delete
098        // Loop for each content to not count shareable content twice
099        // We need to split the course count with the other content because of the deletion mode
100        Set<String> onlyStructureContentsIds = new HashSet<>();
101        Set<String> courseIds = new HashSet<>();
102        for (String programItemId : programItemIds)
103        {
104            ProgramItem programItem = _resolver.resolveById(programItemId);
105            Pair<Set<String>, Set<String>> childContents = _getChildContents(programItem);
106            onlyStructureContentsIds.addAll(childContents.getLeft());
107            courseIds.addAll(childContents.getRight());
108        }
109        
110        results.put("nbOnlyStructureContents", onlyStructureContentsIds.size());
111        results.put("nbCourses", courseIds.size());
112        
113        return results;
114    }
115    
116    private Pair<Set<String>, Set<String>> _getChildContents(ProgramItem programItem)
117    {
118        Set<String> onlyStructureContentsIds = new HashSet<>();
119        Set<String> courseIds = new HashSet<>();
120
121        for (ProgramItem item : _odfHelper.getChildProgramItems(programItem))
122        {
123            if (item instanceof Course)
124            {
125                courseIds.add(item.getId());
126            }
127            else
128            {
129                onlyStructureContentsIds.add(item.getId());
130            }
131            Pair<Set<String>, Set<String>> childContents = _getChildContents(item);
132            onlyStructureContentsIds.addAll(childContents.getLeft());
133            courseIds.addAll(childContents.getRight());
134        }
135        
136        return Pair.of(onlyStructureContentsIds, courseIds);
137    } 
138    
139    /**
140     * Delete ODF contents
141     * @param contentsId The ids of contents to delete
142     * @param parameters the additional parameters
143     * @return the deleted and undeleted contents
144     */
145    @SuppressWarnings("unchecked")
146    @Callable
147    public Map<String, Object> deleteContents(List<String> contentsId, Map<String, Object> parameters)
148    {
149        Map<String, Map<String, Object>> initialContentParameters = new HashMap<>();
150        for (String contentId : contentsId)
151        {
152            initialContentParameters.put(contentId, getContentDefaultParameters(_resolver.resolveById(contentId)));
153        }
154        
155        Map<String, Object> deleteResults = _deleteODFContentHelper.deleteContents(contentsId, (String) parameters.get("mode"));
156        
157        Map<String, Object> updatedResults = new HashMap<>();
158        Set<Content> allReferencedContents = new HashSet<>();
159        Set<Content> allLockedContents = new HashSet<>();
160        Set<Content> allUnauthorizedContents = new HashSet<>();
161        Set<Content> allUnDeletedContents = new HashSet<>();
162        for (String deletedContentId : deleteResults.keySet())
163        {
164            Map<String, Object> deleteResult = (Map<String, Object>) deleteResults.get(deletedContentId);
165            Map<String, Object> updatedContentResults = new HashMap<>();
166            
167            if (deleteResult.containsKey("check-before-deletion-failed"))
168            {
169                updatedContentResults.put("check-before-deletion-failed", deleteResult.get("check-before-deletion-failed"));
170            }
171            
172            String initialContentId = (String) deleteResult.get("initial-content");
173            updatedContentResults.put("initial-content", initialContentParameters.get(initialContentId));
174            
175            List<Map<String, Object>> deletedContents = new ArrayList<>();
176            for (String deleteContentId : (Set<String>) deleteResult.get("deleted-contents"))
177            {
178                Map<String, Object> deleteParameters = new HashMap<>();
179                deleteParameters.put("id", deleteContentId);
180                deletedContents.add(deleteParameters);
181            }
182            updatedContentResults.put("deleted-contents", deletedContents);
183            
184            List<Map<String, Object>> undeletedContents = new ArrayList<>();
185            for (Content content : (Set<Content>) deleteResult.get("undeleted-contents"))
186            {
187                allUnDeletedContents.add(content);
188                undeletedContents.add(getContentDefaultParameters(content));
189            }
190            updatedContentResults.put("undeleted-contents", undeletedContents);
191            
192            List<Map<String, Object>> referencedContents = new ArrayList<>();
193            for (Content content : (Set<Content>) deleteResult.get("referenced-contents"))
194            {
195                allReferencedContents.add(content);
196                referencedContents.add(getContentDefaultParameters(content));
197            }
198            updatedContentResults.put("referenced-contents", referencedContents);
199            
200            // Update the description for locked contents
201            List<Map<String, Object>> updatedLockedContents = new ArrayList<>();
202            for (Content content : (Set<Content>) deleteResult.get("locked-contents"))
203            {
204                allLockedContents.add(content);
205                Map<String, Object> contentParameters = getContentDefaultParameters(content);
206                contentParameters.put("description", _getLockedDescription(content));
207                updatedLockedContents.add(contentParameters);
208            }
209            updatedContentResults.put("locked-contents", updatedLockedContents);
210    
211            // Update the description for unauthorized contents
212            List<Map<String, Object>> updatedUnauthorizedContents = new ArrayList<>();
213            for (Content content : (Set<Content>) deleteResult.get("unauthorized-contents"))
214            {
215                allUnauthorizedContents.add(content);
216                Map<String, Object> contentParameters = getContentDefaultParameters(content);
217                contentParameters.put("description", _getNoRightDescription(content));
218                updatedUnauthorizedContents.add(contentParameters);
219            }
220            updatedContentResults.put("unauthorized-contents", updatedUnauthorizedContents);
221            
222            updatedResults.put(deletedContentId, updatedContentResults);
223        }
224        
225        // Add the list of all referenced contents (removing duplicate contents)
226        List<Map<String, Object>> allReferencedContentsMap = allReferencedContents.stream()
227            .map(c -> getContentDefaultParameters(c))
228            .collect(Collectors.toList());
229        
230        updatedResults.put("all-referenced-contents", allReferencedContentsMap);
231        
232        // Add the list of all locked contents (removing duplicate contents)
233        List<Map<String, Object>> allLockedContentsMap = allLockedContents.stream()
234                .map(c -> getContentDefaultParameters(c))
235                .collect(Collectors.toList());
236            
237        updatedResults.put("all-locked-contents", allLockedContentsMap);
238            
239        // Add the list of all unauthorized contents (removing duplicate contents)
240        List<Map<String, Object>> allUnauthorizedContentsMap = allUnauthorizedContents.stream()
241                .map(c -> getContentDefaultParameters(c))
242                .collect(Collectors.toList());
243            
244        updatedResults.put("all-unauthorized-contents", allUnauthorizedContentsMap);
245        
246        // Add the list of all undeleted contents (removing duplicate contents)
247        List<Map<String, Object>> allUnDeletedContentsMap = allUnDeletedContents.stream()
248                .map(c -> getContentDefaultParameters(c))
249                .collect(Collectors.toList());
250            
251        updatedResults.put("all-undeleted-contents", allUnDeletedContentsMap);
252            
253        return updatedResults;
254    }
255    
256    @Override
257    protected Map<String, Object> getContentDefaultParameters(Content content)
258    {
259        Map<String, Object> contentDefaultParameters = super.getContentDefaultParameters(content);
260        
261        if (content instanceof ProgramItem && content.hasValue(ProgramItem.CODE) && contentDefaultParameters.containsKey("title"))
262        {
263            String title = (String) contentDefaultParameters.get("title");
264            contentDefaultParameters.put("title", title + " (" + content.getValue(ProgramItem.CODE) + ")");
265        }
266        
267        return contentDefaultParameters;
268    }
269}