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 ODF content structure (type, if program has children)
088     * @param odfContentIds the list of ODF content id
089     * @return a map of information
090     */
091    @Callable
092    public Map<String, Object> getStructureInfo(List<String> odfContentIds)
093    {
094        Map<String, Object> results = new HashMap<>();
095        results.putAll(_odfHelper.getStructureInfo(odfContentIds));
096        
097        List<ProgramItem> programItems = odfContentIds.stream()
098                .map(id -> _resolver.resolveById(id))
099                .filter(ProgramItem.class::isInstance)
100                .map(ProgramItem.class::cast)
101                .toList();
102        if (!programItems.isEmpty())
103        {
104            // For the program item deletion, we need to have the number of content to delete
105            // Loop for each content to not count shareable content twice
106            // We need to split the course count with the other content because of the deletion mode
107            Set<String> onlyStructureContentsIds = new HashSet<>();
108            Set<String> courseIds = new HashSet<>();
109            for (ProgramItem programItem : programItems)
110            {
111                Pair<Set<String>, Set<String>> childContents = _getChildContents(programItem);
112                onlyStructureContentsIds.addAll(childContents.getLeft());
113                courseIds.addAll(childContents.getRight());
114            }
115            
116            results.put("nbOnlyStructureContents", onlyStructureContentsIds.size());
117            results.put("nbCourses", courseIds.size());
118        }
119        
120        return results;
121    }
122    
123    private Pair<Set<String>, Set<String>> _getChildContents(ProgramItem programItem)
124    {
125        Set<String> onlyStructureContentsIds = new HashSet<>();
126        Set<String> courseIds = new HashSet<>();
127
128        for (ProgramItem item : _odfHelper.getChildProgramItems(programItem))
129        {
130            if (item instanceof Course)
131            {
132                courseIds.add(item.getId());
133            }
134            else
135            {
136                onlyStructureContentsIds.add(item.getId());
137            }
138            Pair<Set<String>, Set<String>> childContents = _getChildContents(item);
139            onlyStructureContentsIds.addAll(childContents.getLeft());
140            courseIds.addAll(childContents.getRight());
141        }
142        
143        return Pair.of(onlyStructureContentsIds, courseIds);
144    } 
145    
146    /**
147     * Delete ODF contents
148     * @param contentsId The ids of contents to delete
149     * @param parameters the additional parameters
150     * @return the deleted and undeleted contents
151     */
152    @SuppressWarnings("unchecked")
153    @Callable
154    public Map<String, Object> deleteContents(List<String> contentsId, Map<String, Object> parameters)
155    {
156        Map<String, Map<String, Object>> initialContentParameters = new HashMap<>();
157        for (String contentId : contentsId)
158        {
159            initialContentParameters.put(contentId, getContentDefaultParameters(_resolver.resolveById(contentId)));
160        }
161        
162        Map<String, Object> deleteResults = _deleteODFContentHelper.deleteContents(contentsId, (String) parameters.get("mode"));
163        
164        Map<String, Object> updatedResults = new HashMap<>();
165        Set<Content> allReferencedContents = new HashSet<>();
166        Set<Content> allLockedContents = new HashSet<>();
167        Set<Content> allUnauthorizedContents = new HashSet<>();
168        Set<Content> allUnDeletedContents = new HashSet<>();
169        for (String deletedContentId : deleteResults.keySet())
170        {
171            Map<String, Object> deleteResult = (Map<String, Object>) deleteResults.get(deletedContentId);
172            Map<String, Object> updatedContentResults = new HashMap<>();
173            
174            if (deleteResult.containsKey("check-before-deletion-failed"))
175            {
176                updatedContentResults.put("check-before-deletion-failed", deleteResult.get("check-before-deletion-failed"));
177            }
178            
179            String initialContentId = (String) deleteResult.get("initial-content");
180            updatedContentResults.put("initial-content", initialContentParameters.get(initialContentId));
181            
182            List<Map<String, Object>> deletedContents = new ArrayList<>();
183            for (String deleteContentId : (Set<String>) deleteResult.get("deleted-contents"))
184            {
185                Map<String, Object> deleteParameters = new HashMap<>();
186                deleteParameters.put("id", deleteContentId);
187                deletedContents.add(deleteParameters);
188            }
189            updatedContentResults.put("deleted-contents", deletedContents);
190            
191            List<Map<String, Object>> undeletedContents = new ArrayList<>();
192            for (Content content : (Set<Content>) deleteResult.get("undeleted-contents"))
193            {
194                allUnDeletedContents.add(content);
195                undeletedContents.add(getContentDefaultParameters(content));
196            }
197            updatedContentResults.put("undeleted-contents", undeletedContents);
198            
199            List<Map<String, Object>> referencedContents = new ArrayList<>();
200            for (Content content : (Set<Content>) deleteResult.get("referenced-contents"))
201            {
202                allReferencedContents.add(content);
203                referencedContents.add(getContentDefaultParameters(content));
204            }
205            updatedContentResults.put("referenced-contents", referencedContents);
206            
207            // Update the description for locked contents
208            List<Map<String, Object>> updatedLockedContents = new ArrayList<>();
209            for (Content content : (Set<Content>) deleteResult.get("locked-contents"))
210            {
211                allLockedContents.add(content);
212                Map<String, Object> contentParameters = getContentDefaultParameters(content);
213                contentParameters.put("description", _getLockedDescription(content));
214                updatedLockedContents.add(contentParameters);
215            }
216            updatedContentResults.put("locked-contents", updatedLockedContents);
217    
218            // Update the description for unauthorized contents
219            List<Map<String, Object>> updatedUnauthorizedContents = new ArrayList<>();
220            for (Content content : (Set<Content>) deleteResult.get("unauthorized-contents"))
221            {
222                allUnauthorizedContents.add(content);
223                Map<String, Object> contentParameters = getContentDefaultParameters(content);
224                contentParameters.put("description", _getNoRightDescription(content));
225                updatedUnauthorizedContents.add(contentParameters);
226            }
227            updatedContentResults.put("unauthorized-contents", updatedUnauthorizedContents);
228            
229            updatedResults.put(deletedContentId, updatedContentResults);
230        }
231        
232        // Add the list of all referenced contents (removing duplicate contents)
233        List<Map<String, Object>> allReferencedContentsMap = allReferencedContents.stream()
234            .map(c -> getContentDefaultParameters(c))
235            .collect(Collectors.toList());
236        
237        updatedResults.put("all-referenced-contents", allReferencedContentsMap);
238        
239        // Add the list of all locked contents (removing duplicate contents)
240        List<Map<String, Object>> allLockedContentsMap = allLockedContents.stream()
241                .map(c -> getContentDefaultParameters(c))
242                .collect(Collectors.toList());
243            
244        updatedResults.put("all-locked-contents", allLockedContentsMap);
245            
246        // Add the list of all unauthorized contents (removing duplicate contents)
247        List<Map<String, Object>> allUnauthorizedContentsMap = allUnauthorizedContents.stream()
248                .map(c -> getContentDefaultParameters(c))
249                .collect(Collectors.toList());
250            
251        updatedResults.put("all-unauthorized-contents", allUnauthorizedContentsMap);
252        
253        // Add the list of all undeleted contents (removing duplicate contents)
254        List<Map<String, Object>> allUnDeletedContentsMap = allUnDeletedContents.stream()
255                .map(c -> getContentDefaultParameters(c))
256                .collect(Collectors.toList());
257            
258        updatedResults.put("all-undeleted-contents", allUnDeletedContentsMap);
259            
260        return updatedResults;
261    }
262    
263    @Override
264    protected Map<String, Object> getContentDefaultParameters(Content content)
265    {
266        Map<String, Object> contentDefaultParameters = super.getContentDefaultParameters(content);
267        
268        if (content instanceof ProgramItem && content.hasValue(ProgramItem.CODE) && contentDefaultParameters.containsKey("title"))
269        {
270            String title = (String) contentDefaultParameters.get("title");
271            contentDefaultParameters.put("title", title + " (" + content.getValue(ProgramItem.CODE) + ")");
272        }
273        
274        return contentDefaultParameters;
275    }
276}