001/*
002 *  Copyright 2016 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.rights;
017
018import java.util.Collections;
019import java.util.HashSet;
020import java.util.List;
021import java.util.Objects;
022import java.util.Set;
023
024import org.apache.avalon.framework.context.Context;
025import org.apache.avalon.framework.context.ContextException;
026import org.apache.avalon.framework.context.Contextualizable;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.cocoon.components.ContextHelper;
030import org.apache.cocoon.environment.Request;
031
032import org.ametys.cms.content.ContentHelper;
033import org.ametys.cms.content.archive.ArchiveConstants;
034import org.ametys.cms.repository.Content;
035import org.ametys.core.right.AccessController;
036import org.ametys.odf.ODFHelper;
037import org.ametys.odf.ProgramItem;
038import org.ametys.odf.course.Course;
039import org.ametys.odf.courselist.CourseList;
040import org.ametys.odf.coursepart.CoursePart;
041import org.ametys.odf.orgunit.OrgUnit;
042import org.ametys.odf.person.Person;
043import org.ametys.odf.program.AbstractProgram;
044import org.ametys.odf.program.Container;
045import org.ametys.plugins.core.impl.right.AbstractHierarchicalAccessController;
046import org.ametys.plugins.repository.AmetysObject;
047import org.ametys.plugins.repository.AmetysObjectResolver;
048import org.ametys.plugins.repository.RepositoryConstants;
049import org.ametys.plugins.repository.collection.AmetysObjectCollection;
050import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector;
051
052/**
053 * {@link AccessController} for a ODF {@link Content}
054 */
055public class ODFContentHierarchicalAccessController extends AbstractHierarchicalAccessController<AmetysObject> implements Contextualizable
056{
057    /** The helper for root content */
058    protected ODFHelper _odfHelper;
059    /** The helper for contents */
060    protected ContentHelper _contentHelper;
061    /** The avalon context */
062    protected Context _context;
063    /** Ametys Object Resolver */
064    protected AmetysObjectResolver _resolver;
065
066
067    public void contextualize(Context context) throws ContextException
068    {
069        _context = context;
070    }
071    
072    @Override
073    public void service(ServiceManager manager) throws ServiceException
074    {
075        super.service(manager);
076        _odfHelper = (ODFHelper) manager.lookup(ODFHelper.ROLE);
077        _contentHelper = (ContentHelper) manager.lookup(ContentHelper.ROLE);
078        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
079    }
080    
081    @Override
082    public boolean isSupported(Object object)
083    {
084        return object instanceof ProgramItem || object instanceof OrgUnit || object instanceof Person || object instanceof CoursePart;
085    }
086    
087    @Override
088    protected Set<AmetysObject> _getParents(AmetysObject object)
089    {
090        if (!(object instanceof Content))
091        {
092            return null;
093        }
094        
095        Set<AmetysObject> parents = new HashSet<>();
096        
097        if (object instanceof ProgramItem programItem)
098        {
099            parents.addAll(_odfHelper.getParentProgramItems(programItem));
100            parents.addAll(_getOrgUnits(programItem));
101        }
102        else if (object instanceof OrgUnit orgUnit)
103        {
104            OrgUnit parentOrgUnit = orgUnit.getParentOrgUnit();
105            if (parentOrgUnit != null)
106            {
107                parents.add(parentOrgUnit);
108            }
109        }
110        else if (object instanceof CoursePart coursePart)
111        {
112            List<Course> parentCourses = coursePart.getCourses();
113            if (!parentCourses.isEmpty())
114            {
115                parents.addAll(parentCourses);
116            }
117        }
118        
119        // default
120        AmetysObject parent = object.getParent();
121        boolean parentAdded = false;
122        if (parent instanceof AmetysObjectCollection collection && (RepositoryConstants.NAMESPACE_PREFIX + ":contents").equals(collection.getName()))
123        {
124            Request request = ContextHelper.getRequest(_context);
125            String originalWorkspace = RequestAttributeWorkspaceSelector.getForcedWorkspace(request);
126            if (ArchiveConstants.ARCHIVE_WORKSPACE.equals(originalWorkspace))
127            {
128                try
129                {
130                    RequestAttributeWorkspaceSelector.setForcedWorkspace(request, RepositoryConstants.DEFAULT_WORKSPACE);
131                    AmetysObject parentFromDefault = _resolver.resolveByPath(parent.getPath());
132                    parents.add(parentFromDefault);
133                    parentAdded = true;
134                }
135                finally
136                {
137                    RequestAttributeWorkspaceSelector.setForcedWorkspace(request, originalWorkspace);
138                }
139            }
140        }
141        if (!parentAdded)
142        {
143            parents.add(parent);
144        }
145        
146        return parents;
147    }
148    
149    private List<OrgUnit> _getOrgUnits(ProgramItem programItem)
150    {
151        Set<String> ouIds = new HashSet<>();
152        
153        if (programItem instanceof AbstractProgram abstractProgram)
154        {
155            ouIds.addAll(abstractProgram.getOrgUnits());
156        }
157        else if (programItem instanceof Container container)
158        {
159            ouIds.addAll(container.getOrgUnits());
160        }
161        else if (programItem instanceof CourseList courseList)
162        {
163            List<Course> parentCourses = courseList.getParentCourses();
164            for (Course parentCourse : parentCourses)
165            {
166                ouIds.addAll(parentCourse.getOrgUnits());
167            }
168        }
169        else if (programItem instanceof Course course)
170        {
171            ouIds.addAll(course.getOrgUnits());
172        }
173
174        return ouIds.stream()
175                    .filter(Objects::nonNull)
176                    .map(_resolver::resolveById)
177                    .map(OrgUnit.class::cast)
178                    .toList();
179    }
180    
181    @Override
182    protected Set< ? extends Object> _convertWorkspaceToRootRightContexts(Set<Object> workspacesContexts)
183    {
184        if (workspacesContexts.contains("/cms"))
185        {
186            return Collections.singleton(_odfHelper.getRootContent());
187        }
188        return null;
189    }
190}