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