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