001/*
002 *  Copyright 2017 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.plugins.extraction.execution;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023import java.util.Objects;
024
025import org.apache.avalon.framework.parameters.Parameters;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.cocoon.environment.ObjectModelHelper;
029import org.apache.cocoon.environment.Redirector;
030import org.apache.cocoon.environment.Request;
031import org.apache.cocoon.environment.SourceResolver;
032import org.apache.commons.lang3.EnumUtils;
033import org.apache.commons.lang3.StringUtils;
034import org.apache.excalibur.source.SourceException;
035import org.apache.excalibur.source.TraversableSource;
036import org.apache.excalibur.source.impl.FileSource;
037
038import org.ametys.core.cocoon.JSonReader;
039import org.ametys.core.user.CurrentUserProvider;
040import org.ametys.core.user.UserIdentity;
041import org.ametys.plugins.core.ui.parameter.files.GetParameterFileAction;
042import org.ametys.plugins.extraction.ExtractionConstants;
043import org.ametys.plugins.extraction.execution.Extraction.ExtractionProfile;
044
045/**
046 * Action for getting extraction definition files
047 */
048public class GetExtractionDefinitionFilesAction extends GetParameterFileAction
049{
050    private CurrentUserProvider _currentUserProvider;
051    private ExtractionDefinitionReader _definitionReader;
052    private ExtractionDAO _extractionDAO;
053    
054    @Override
055    public void service(ServiceManager serviceManager) throws ServiceException
056    {
057        super.service(serviceManager);
058        _currentUserProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE);
059        _definitionReader = (ExtractionDefinitionReader) serviceManager.lookup(ExtractionDefinitionReader.ROLE);
060        _extractionDAO = (ExtractionDAO) serviceManager.lookup(ExtractionDAO.ROLE);
061    }
062    
063    @Override
064    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
065    {
066        UserIdentity userIdentity = _currentUserProvider.getUser();
067        
068        @SuppressWarnings("unchecked")
069        Map<String, Object> jsParameters = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT);
070
071        String profileId = StringUtils.defaultIfEmpty((String) jsParameters.get("profile"), ExtractionProfile.READ_ACCESS.name());
072        
073        if (!EnumUtils.isValidEnum(ExtractionProfile.class, profileId.toUpperCase()))
074        {
075            throw new IllegalArgumentException("Unexpected profile identifier : " + profileId);
076        }
077        
078        ExtractionProfile profile = ExtractionProfile.valueOf(profileId.toUpperCase());
079        
080        Request request = ObjectModelHelper.getRequest(objectModel);
081        
082        String path = Objects.toString(request.getParameter("path"), StringUtils.EMPTY);
083        
084        String rootURI = getRootURI(request);
085        TraversableSource rootDir = (TraversableSource) _srcResolver.resolveURI(rootURI);
086        TraversableSource currentDir = (TraversableSource) _srcResolver.resolveURI(rootURI + (path.length() > 0 ? "/" + path : ""));
087        List<Map<String, Object>> nodes = _fillNodes(currentDir, profile, rootDir, userIdentity);
088        
089        Map<String, Object> result = new HashMap<>();
090        result.put("nodes", nodes);
091        
092        request.setAttribute(JSonReader.OBJECT_TO_READ, result);
093        return EMPTY_MAP;
094    }
095        
096    private List<Map<String, Object>> _fillNodes(TraversableSource currentDir, ExtractionProfile profile, TraversableSource rootDir, UserIdentity userIdentity) throws SourceException, Exception
097    {
098        List<Map<String, Object>> nodes = new ArrayList<>();
099        
100        if (currentDir.exists())
101        {
102            for (TraversableSource child : (Collection<TraversableSource>) currentDir.getChildren())
103            {
104                if (!isIgnoredSource(child))
105                {
106                    if (child.isCollection())
107                    {
108                        Map<String, Object> properties = _extractionContainer2JsonObject(child, rootDir);
109
110                        switch (profile)
111                        {
112                            case WRITE_ACCESS:
113                                if ((boolean) properties.get("canWrite") || _extractionDAO.hasAnyWritableDescendant(userIdentity, child, true))
114                                {
115                                    nodes.add(properties);
116                                }
117                                break;
118                            case RIGHT_ACCESS:
119                                if ((boolean) properties.get("canAssignRights") || _extractionDAO.hasAnyAssignableDescendant(userIdentity, child))
120                                {
121                                    nodes.add(properties);
122                                }
123                                break;
124                            case READ_ACCESS:
125                            default:
126                                if ((boolean) properties.get("canRead") || _extractionDAO.hasAnyReadableDescendant(userIdentity, child))
127                                {
128                                    nodes.add(properties);
129                                }
130                                break;
131                        }
132                    }
133                    else
134                    {
135                        // To parse the extraction definition file only once, check here if the current user can read it
136                        Extraction extraction = _definitionReader.readExtractionDefinitionFile(((FileSource) child).getFile());
137                        switch (profile)
138                        {
139                            case WRITE_ACCESS:
140                                if (_extractionDAO.canWrite(userIdentity, child))
141                                {
142                                    nodes.add(_extraction2JsonObject(extraction, child, rootDir));
143                                }
144                                break;
145                            case RIGHT_ACCESS:
146                                if (_extractionDAO.canAssignRights(userIdentity, child))
147                                {
148                                    nodes.add(_extraction2JsonObject(extraction, child, rootDir));
149                                }
150                                break;
151                            case READ_ACCESS:
152                            default:
153                                if (_extractionDAO.canRead(userIdentity, child))
154                                {
155                                    nodes.add(_extraction2JsonObject(extraction, child, rootDir));
156                                }
157                                break;
158                        }
159                        
160                    }
161                }
162            }
163        }
164        return nodes;
165    }
166    @Override
167    protected String getRootURI(Request request)
168    {
169        return ExtractionConstants.DEFINITIONS_DIR;
170    }
171
172    
173    @Override
174    protected boolean isIgnoredSource(TraversableSource source)
175    {
176        return !source.isCollection() && !source.getName().endsWith(".xml");
177    }
178    
179    private Map<String, Object> _extraction2JsonObject(Extraction extraction, TraversableSource file, TraversableSource root)
180    {
181        Map<String, Object> jsonObject = super._resource2JsonObject(file, root);
182
183        jsonObject.putAll(_extractionDAO.getExtractionProperties(extraction, file));
184        
185        return jsonObject;
186    }
187    
188    private Map<String, Object> _extractionContainer2JsonObject(TraversableSource file, TraversableSource root)
189    {
190        Map<String, Object> jsonObject = super._collection2JsonObject(file, root);
191
192        jsonObject.putAll(_extractionDAO.getExtractionContainerProperties(file));
193        
194        return jsonObject;
195    }
196
197}