001/*
002 *  Copyright 2019 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.odf.observation;
017
018import java.util.HashMap;
019import java.util.Map;
020
021import org.apache.avalon.framework.service.ServiceException;
022import org.apache.avalon.framework.service.ServiceManager;
023import org.apache.avalon.framework.service.Serviceable;
024import org.apache.commons.lang3.ArrayUtils;
025
026import org.ametys.cms.ObservationConstants;
027import org.ametys.cms.repository.Content;
028import org.ametys.cms.workflow.ContentWorkflowHelper;
029import org.ametys.cms.workflow.EditContentFunction;
030import org.ametys.core.observation.Event;
031import org.ametys.core.observation.Observer;
032import org.ametys.odf.course.Course;
033import org.ametys.odf.course.ShareableCourseConstants;
034import org.ametys.odf.course.ShareableCourseHelper;
035import org.ametys.odf.enumeration.OdfReferenceTableHelper;
036import org.ametys.odf.orgunit.OrgUnit;
037import org.ametys.odf.program.Program;
038import org.ametys.plugins.repository.AmetysObjectIterable;
039import org.ametys.plugins.repository.data.holder.values.SynchronizableValue;
040import org.ametys.plugins.repository.data.holder.values.SynchronizableValue.Mode;
041import org.ametys.plugins.workflow.AbstractWorkflowComponent;
042import org.ametys.plugins.workflow.component.CheckRightsCondition;
043import org.ametys.runtime.model.View;
044import org.ametys.runtime.plugin.component.AbstractLogEnabled;
045
046import com.opensymphony.workflow.WorkflowException;
047
048/**
049 * Observer to unlink the shareable field of a {@link Course} on {@link Content} deletion.
050 */
051public class ShareableFieldCourseObserver extends AbstractLogEnabled implements Observer, Serviceable
052{
053    private ContentWorkflowHelper _contentWorkflowHelper;
054    private ShareableCourseHelper _shareableCourseHelper;
055    
056    @Override
057    public void service(ServiceManager manager) throws ServiceException
058    {
059        _contentWorkflowHelper = (ContentWorkflowHelper) manager.lookup(ContentWorkflowHelper.ROLE);
060        _shareableCourseHelper = (ShareableCourseHelper) manager.lookup(ShareableCourseHelper.ROLE);
061    }
062    
063    @Override
064    public boolean supports(Event event)
065    {
066        if (event.getId().equals(ObservationConstants.EVENT_CONTENT_DELETING))
067        {
068            Content content = (Content) event.getArguments().get(ObservationConstants.ARGS_CONTENT);
069            return _isProgramContent(content)
070                || _isOrgUnitContent(content)
071                || _isDegreeContent(content)
072                || _isPeriodContent(content);
073        }
074        
075        return false;
076    }
077
078    @Override
079    public int getPriority(Event event)
080    {
081        return 0;
082    }
083
084    @Override
085    public void observe(Event event, Map<String, Object> transientVars) throws Exception
086    {
087        Content content = (Content) event.getArguments().get(ObservationConstants.ARGS_CONTENT);
088        String contentId = content.getId();
089        
090        if (_isProgramContent(content))
091        {
092            _editShareableField(_shareableCourseHelper.getShareableCourses(contentId, null, null, null), contentId, ShareableCourseConstants.PROGRAMS_FIELD_ATTRIBUTE_NAME);
093        }
094        else if (_isDegreeContent(content))
095        {
096            _editShareableField(_shareableCourseHelper.getShareableCourses(null, contentId, null, null), contentId, ShareableCourseConstants.DEGREES_FIELD_ATTRIBUTE_NAME);
097        }
098        else if (_isPeriodContent(content))
099        {
100            _editShareableField(_shareableCourseHelper.getShareableCourses(null, null, contentId, null), contentId, ShareableCourseConstants.PERIODS_FIELD_ATTRIBUTE_NAME);
101        }
102        else if (_isOrgUnitContent(content))
103        {
104            _editShareableField(_shareableCourseHelper.getShareableCourses(null, null, null, contentId), contentId, ShareableCourseConstants.ORGUNITS_FIELD_ATTRIBUTE_NAME);
105        }
106    }
107
108    /**
109     * Edit shareable fields
110     * @param courses the list of courses to edit shareable fields
111     * @param contentId the content id to remove from sharebale fields
112     * @param attributeNameToRemove the attribute name of the shareable field
113     * @throws WorkflowException if an error occurred
114     */
115    protected void _editShareableField(AmetysObjectIterable<Course> courses, String contentId, String attributeNameToRemove) throws WorkflowException
116    {
117        for (Course course : courses)
118        {
119            Map<String, Object> paramsEdit = new HashMap<>();
120            paramsEdit.put(CheckRightsCondition.FORCE, true); // Ignore the right condition
121            
122            Map<String, Object> contextParameters = new HashMap<>();
123            
124            contextParameters.put(EditContentFunction.QUIT, true);
125            
126            SynchronizableValue value = new SynchronizableValue(new String[] {contentId});
127            value.setMode(Mode.REMOVE);
128            contextParameters.put(EditContentFunction.VALUES_KEY, Map.of(attributeNameToRemove, value));
129            
130            View view = View.of(course.getModel(), attributeNameToRemove);
131            contextParameters.put(EditContentFunction.VIEW, view);
132            
133            paramsEdit.put(AbstractWorkflowComponent.CONTEXT_PARAMETERS_KEY, contextParameters);
134            _contentWorkflowHelper.doAction(course, 225, paramsEdit);
135        }
136    }
137    
138    private boolean _isProgramContent(Content content)
139    {
140        return content instanceof Program;
141    }
142    
143    private boolean _isOrgUnitContent(Content content)
144    {
145        return content instanceof OrgUnit;
146    }
147    
148    private boolean _isDegreeContent(Content content)
149    {
150        return ArrayUtils.contains(content.getTypes(), OdfReferenceTableHelper.DEGREE);
151    }
152    
153    private boolean _isPeriodContent(Content content)
154    {
155        return ArrayUtils.contains(content.getTypes(), OdfReferenceTableHelper.PERIOD);
156    }
157    
158}