001/*
002 *  Copyright 2018 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.odfpilotage.manager;
017
018import java.io.File;
019import java.io.FileInputStream;
020import java.io.InputStream;
021import java.util.ArrayList;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025
026import org.apache.avalon.framework.configuration.Configurable;
027import org.apache.avalon.framework.configuration.Configuration;
028import org.apache.avalon.framework.configuration.ConfigurationException;
029import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
030import org.apache.avalon.framework.context.ContextException;
031import org.apache.avalon.framework.context.Contextualizable;
032import org.apache.avalon.framework.service.ServiceException;
033import org.apache.avalon.framework.service.ServiceManager;
034import org.apache.avalon.framework.service.Serviceable;
035import org.apache.cocoon.Constants;
036import org.apache.cocoon.environment.Context;
037import org.apache.commons.lang.StringUtils;
038
039import org.ametys.cms.contenttype.AttributeDefinition;
040import org.ametys.cms.contenttype.MetadataDefinition;
041import org.ametys.cms.repository.Content;
042import org.ametys.odf.ProgramItem;
043import org.ametys.odf.contenttype.ODFContentTypeMetadataManager;
044import org.ametys.odf.program.Program;
045import org.ametys.plugins.odfpilotage.helper.PilotageStatusHelper;
046import org.ametys.plugins.odfpilotage.helper.PilotageStatusHelper.PilotageStatus;
047import org.ametys.plugins.repository.AmetysRepositoryException;
048
049/**
050 * The odf content type metadata manager for pilotage
051 */
052public class ODFPilotageContentTypeMetadataManager extends ODFContentTypeMetadataManager implements Configurable, Contextualizable, Serviceable
053{
054    private static String _METADATA_FILE_PATH = "/org/ametys/plugins/odfpilotage/manager/restrictions.xml";
055    private static String _METADATA_FILE_PATH_TO_OVERRIDE = "/WEB-INF/param/odf/pilotage/restrictions.xml";
056
057    /** The Cocoon context */
058    protected Context _cocoonContext;
059    
060    /** The pilotage status helper */
061    protected PilotageStatusHelper _pilotageStatusHelper; 
062    
063    /** The map of disabled metadatas for each content type and each pilotage status */
064    protected Map<String, Map<PilotageStatus, List<String>>> _disabledMetadata;
065    
066    @Override
067    public void service(ServiceManager manager) throws ServiceException
068    {
069        _pilotageStatusHelper = (PilotageStatusHelper) manager.lookup(PilotageStatusHelper.ROLE);
070    }
071    
072    @Override
073    public void contextualize(org.apache.avalon.framework.context.Context context) throws ContextException
074    {
075        _cocoonContext = (Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
076    }
077    
078    @Override
079    public void configure(Configuration configuration) throws ConfigurationException
080    {
081        _disabledMetadata = new HashMap<>();
082        
083        try
084        {
085            File metadataXml = new File(_cocoonContext.getRealPath(_METADATA_FILE_PATH_TO_OVERRIDE));
086            if (!metadataXml.isFile())
087            {
088                try (InputStream is = getClass().getResourceAsStream(_METADATA_FILE_PATH))
089                {
090                    Configuration cfg = new DefaultConfigurationBuilder().build(is);
091                    _fillDisableMetadataMap(cfg);
092                }
093            }
094            else
095            {
096                try (InputStream is = new FileInputStream(metadataXml))
097                {
098                    Configuration cfg = new DefaultConfigurationBuilder().build(is);
099                    _fillDisableMetadataMap(cfg);
100                }
101            }
102        }
103        catch (Exception e)
104        {
105            throw new ConfigurationException("Error while parsing metadata.xml", e);
106        }
107    }
108
109    /**
110     * Fill the disabled metadata from the configuration
111     * @param cfg the configuration
112     * @throws ConfigurationException if an error occurred
113     */
114    protected void _fillDisableMetadataMap(Configuration cfg) throws ConfigurationException
115    {
116        for (Configuration contentTypeConf : cfg.getChildren("content-type"))
117        {
118            Map<PilotageStatus, List<String>> metadataByState = new HashMap<>();
119            for (Configuration statusConf : contentTypeConf.getChildren("status"))
120            {
121                List<String> metadatas = new ArrayList<>();
122                for (Configuration metadataConf : statusConf.getChildren("metadata"))
123                {
124                    metadatas.add(metadataConf.getAttribute("path"));
125                }
126                
127                String statusName = statusConf.getAttribute("name");
128                PilotageStatus pilotageStatus = StringUtils.isNotBlank(statusName) ? PilotageStatus.valueOf(statusName) : PilotageStatus.NONE;
129
130                metadataByState.put(pilotageStatus, metadatas);
131            }
132            
133            _disabledMetadata.put(contentTypeConf.getAttribute("id"), metadataByState);
134        }
135    }
136    
137    @Override
138    public boolean canWrite(Content content, AttributeDefinition definition) throws AmetysRepositoryException
139    {
140        boolean canWrite = super.canWrite(content, definition);
141        String attributePath = definition.getPath();
142        return _canWrite(content, canWrite, attributePath);
143    }
144    
145    @Override
146    @Deprecated
147    public boolean canWrite(Content content, MetadataDefinition metadataDef) throws AmetysRepositoryException
148    {
149        boolean canWrite = super.canWrite(content, metadataDef);
150        String attributePath = metadataDef.getId();
151        return _canWrite(content, canWrite, attributePath);
152    }
153    
154    private boolean _canWrite(Content content, boolean canWrite, String attributePath)
155    {
156        if (content == null || !(content instanceof ProgramItem))
157        {
158            return canWrite;
159        }
160        
161        Program parentProgramWithHigherPilotageStatus = _pilotageStatusHelper.getParentProgramWithHigherPilotageStatus((ProgramItem) content);
162        if (parentProgramWithHigherPilotageStatus != null && !_pilotageStatusHelper.hasEditSuperRight(parentProgramWithHigherPilotageStatus))
163        {
164            PilotageStatus pilotageStatus = _pilotageStatusHelper.getPilotageStatus(parentProgramWithHigherPilotageStatus);
165            if (canWrite)
166            {
167                for (String type : content.getTypes())
168                {
169                    if (_disabledMetadata.containsKey(type))
170                    {
171                        Map<PilotageStatus, List<String>> pilotageStatusMetadata = _disabledMetadata.get(type);
172                        for (PilotageStatus status : _getStatusToCheck(pilotageStatus))
173                        {
174                            if (pilotageStatusMetadata.containsKey(status))
175                            {
176                                List<String> metadata = pilotageStatusMetadata.get(status);
177                                if (metadata.contains(attributePath))
178                                {
179                                    return false;
180                                }
181                            }
182                        }
183                    }
184                }
185            }
186            
187            return canWrite;
188        }
189        
190        return true;
191    }
192
193    /**
194     * Get the list of pilotage status to check
195     * @param pilotageStatus the pilotage status of the content
196     * @return the list of pilotage status to check
197     */
198    protected List<PilotageStatus> _getStatusToCheck(PilotageStatus pilotageStatus)
199    {
200        List<PilotageStatus> statusToCheck = new ArrayList<>();
201        switch (pilotageStatus)
202        {
203            case MENTION_VALIDATED:
204                statusToCheck.add(PilotageStatus.MENTION_VALIDATED);
205                break;
206            case ORGUNIT_VALIDATED:
207                statusToCheck.add(PilotageStatus.MENTION_VALIDATED);
208                statusToCheck.add(PilotageStatus.ORGUNIT_VALIDATED);
209                break;
210            case CFVU_VALIDATED:
211                statusToCheck.add(PilotageStatus.MENTION_VALIDATED);
212                statusToCheck.add(PilotageStatus.ORGUNIT_VALIDATED);
213                statusToCheck.add(PilotageStatus.CFVU_VALIDATED);
214                break;
215            case CFVU_MCC_VALIDATED:
216                statusToCheck.add(PilotageStatus.MENTION_VALIDATED);
217                statusToCheck.add(PilotageStatus.ORGUNIT_VALIDATED);
218                statusToCheck.add(PilotageStatus.CFVU_VALIDATED);
219                statusToCheck.add(PilotageStatus.CFVU_MCC_VALIDATED);
220                break;
221            default:
222                break;
223        }
224        return statusToCheck;
225    }
226}