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