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.thesaurus.right;
017
018import java.util.Map;
019import java.util.Set;
020
021import org.apache.avalon.framework.context.Context;
022import org.apache.avalon.framework.context.ContextException;
023import org.apache.avalon.framework.context.Contextualizable;
024import org.apache.avalon.framework.service.ServiceException;
025import org.apache.avalon.framework.service.ServiceManager;
026import org.apache.cocoon.components.ContextHelper;
027import org.apache.cocoon.environment.Request;
028import org.apache.commons.collections.MapUtils;
029import org.apache.commons.lang3.StringUtils;
030
031import org.ametys.cms.content.archive.ArchiveConstants;
032import org.ametys.cms.contenttype.ContentTypesHelper;
033import org.ametys.cms.repository.Content;
034import org.ametys.cms.rights.ContentTypeAccessController;
035import org.ametys.core.group.GroupIdentity;
036import org.ametys.core.right.AccessController;
037import org.ametys.core.right.AccessController.Permission.PermissionType;
038import org.ametys.core.right.AccessExplanation;
039import org.ametys.core.right.RightsException;
040import org.ametys.core.right.RightsExtensionPoint;
041import org.ametys.core.user.UserIdentity;
042import org.ametys.plugins.core.impl.right.AbstractProfileStorageBasedAccessController;
043import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector;
044import org.ametys.plugins.thesaurus.ThesaurusDAO;
045import org.ametys.runtime.i18n.I18nizableText;
046import org.ametys.runtime.i18n.I18nizableTextParameter;
047
048/**
049 * {@link AccessController} for a thesaurus objects. The rights are checked on '/cms' context.
050 * Read access is allowed to any connected user.
051 */
052public class ThesaurusAccessController extends AbstractProfileStorageBasedAccessController implements Contextualizable
053{
054    /** The right context for thesaurus */
055    private static final String __APPLICATION_RIGHT_CONTEXT = "/cms";
056    
057    /** The right extension point */
058    protected RightsExtensionPoint _rightEP;
059    
060    private ContentTypesHelper _contentTypeHelper;
061
062    private Context _context;
063    
064    @Override
065    public void service(ServiceManager manager) throws ServiceException
066    {
067        super.service(manager);
068        _contentTypeHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE);
069        _rightEP = (RightsExtensionPoint) manager.lookup(RightsExtensionPoint.ROLE);
070    }
071    
072    public void contextualize(Context context) throws ContextException
073    {
074        _context = context;
075    }
076    
077    public boolean supports(Object object)
078    {
079        Request request = ContextHelper.getRequest(_context);
080        String currentWorkspace = RequestAttributeWorkspaceSelector.getForcedWorkspace(request);
081        
082        if (ArchiveConstants.ARCHIVE_WORKSPACE.equals(currentWorkspace))
083        {
084            return false;
085        }
086        
087        return object instanceof Content && _contentTypeHelper.isInstanceOf((Content) object, ThesaurusDAO.MICROTHESAURUS_ABSTRACT_CONTENT_TYPE);
088    }
089    
090    @Override
091    protected Object _convertContext(Object initialContext)
092    {
093        String siteName = _getSiteName();
094        return __APPLICATION_RIGHT_CONTEXT + (StringUtils.isNoneEmpty(siteName) ? "/" + siteName : "");
095    }
096    
097    /**
098     * Convert the asked right id to the real right to check
099     * @param rightId The asked right id
100     * @return the right to check
101     */
102    protected String _convertRightId(String rightId)
103    {
104        return "Thesaurus_Rights_EditTerm";
105    }
106
107    @Override
108    public AccessResult getPermission(UserIdentity user, Set<GroupIdentity> userGroups, String rightId, Object object)
109    {
110        return super.getPermission(user, userGroups, _convertRightId(rightId), object);
111    }
112    
113    @Override
114    public AccessExplanation explainPermission(UserIdentity user, Set<GroupIdentity> groups, String rightId, Object object)
115    {
116        return super.explainPermission(user, groups, _convertRightId(rightId), object);
117    }
118    
119    @Override
120    protected I18nizableText _getExplanationI18nText(PermissionDetails details)
121    {
122        return new I18nizableText("plugin.thesaurus", _getAccessExplanationI18nKey("PLUGINS_THESAURUS_ACCESS_CONTROLLER_", details), _getExplanationI18nParams(details));
123    }
124    
125    @Override
126    protected Map<String, I18nizableTextParameter> _getExplanationI18nParams(PermissionDetails details)
127    {
128        Map<String, I18nizableTextParameter> i18nParams = super._getExplanationI18nParams(details);
129        i18nParams.put("right", _rightEP.getExtension(_convertRightId(null)).getLabel());
130        return i18nParams;
131    }
132    
133    @Override
134    protected I18nizableText getObjectLabelForExplanation(Object object) throws RightsException
135    {
136        return new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_EXPLANATION_CONTEXT_LABEL");
137    }
138
139    @Override
140    public AccessResult getReadAccessPermission(UserIdentity user, Set<GroupIdentity> userGroups, Object object)
141    {
142        return AccessResult.ANY_CONNECTED_ALLOWED;
143    }
144    
145    @Override
146    public AccessExplanation explainReadAccessPermission(UserIdentity user, Set<GroupIdentity> groups, Object object)
147    {
148        return new AccessExplanation(
149                getId(),
150                getReadAccessPermission(user, groups, object),
151                new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_READ_ACCESS_EXPLANATION", Map.of("title", new I18nizableText(((Content) object).getTitle())))
152            );
153    }
154
155    @Override
156    public Map<String, AccessResult> getPermissionByRight(UserIdentity user, Set<GroupIdentity> userGroups, Object object)
157    {
158        return MapUtils.EMPTY_MAP;
159    }
160
161    @Override
162    public AccessResult getPermissionForAnonymous(String rightId, Object object)
163    {
164        return AccessResult.ANONYMOUS_DENIED;
165    }
166    
167    @Override
168    public AccessExplanation explainPermissionForAnonymous(String rightId, Object object)
169    {
170        return new AccessExplanation(
171                getId(),
172                getPermissionForAnonymous(rightId, object),
173                new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_ANONYMOUS_PERMISSION_EXPLANATION", Map.of("title", new I18nizableText(((Content) object).getTitle())))
174            );
175    }
176
177    @Override
178    public AccessResult getReadAccessPermissionForAnonymous(Object object)
179    {
180        return AccessResult.ANONYMOUS_DENIED;
181    }
182    
183    @Override
184    public AccessExplanation explainReadAccessPermissionForAnonymous(Object object)
185    {
186        return new AccessExplanation(
187                getId(),
188                getReadAccessPermissionForAnonymous(object),
189                new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_ANONYMOUS_PERMISSION_EXPLANATION", Map.of("title", new I18nizableText(((Content) object).getTitle())))
190            );
191    }
192
193    @Override
194    public AccessResult getPermissionForAnyConnectedUser(String rightId, Object object)
195    {
196        return AccessResult.ANY_CONNECTED_DENIED;
197    }
198    
199    @Override
200    public AccessExplanation explainPermissionForAnyConnectedUser(String rightId, Object object)
201    {
202        return new AccessExplanation(
203                getId(),
204                getPermissionForAnyConnectedUser(rightId, object),
205                new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_ANY_CONNECTED_PERMISSION_EXPLANATION")
206            );
207    }
208
209    @Override
210    public AccessResult getReadAccessPermissionForAnyConnectedUser(Object object)
211    {
212        return AccessResult.ANY_CONNECTED_ALLOWED;
213    }
214    
215    @Override
216    public AccessExplanation explainReadAccessPermissionForAnyConnectedUser(Object object)
217    {
218        return new AccessExplanation(
219                getId(),
220                getReadAccessPermissionForAnyConnectedUser(object),
221                new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_READ_ACCESS_EXPLANATION")
222            );
223    }
224
225    @Override
226    public Map<UserIdentity, AccessResult> getPermissionByUser(String rightId, Object object)
227    {
228        return MapUtils.EMPTY_MAP;
229    }
230
231    @Override
232    public Map<GroupIdentity, AccessResult> getReadAccessPermissionByGroup(Object object)
233    {
234        return MapUtils.EMPTY_MAP;
235    }
236    
237    @Override
238    public Map<UserIdentity, AccessResult> getReadAccessPermissionByUser(Object object)
239    {
240        return MapUtils.EMPTY_MAP;
241    }
242
243    @Override
244    public Map<GroupIdentity, AccessResult> getPermissionByGroup(String rightId, Object object)
245    {
246        return MapUtils.EMPTY_MAP;
247    }
248    
249    @Override
250    protected Set< ? extends Object> _convertWorkspaceToRootRightContexts(Set<Object> workspacesContexts)
251    {
252        return null;
253    }
254    
255    // FIXME To remove https://issues.ametys.org/browse/THES-86
256    private String _getSiteName()
257    {
258        Request request = ContextHelper.getRequest(_context);
259        String siteName = request.getParameter("siteName");
260        
261        if (siteName == null)
262        {
263            siteName = (String) request.getAttribute("siteName");
264        }
265        return siteName;
266    }
267
268    @Override
269    public Map<ExplanationObject, Map<Permission, AccessExplanation>> explainAllPermissions(UserIdentity identity, Set<GroupIdentity> groups)
270    {
271        AccessExplanation explanation = explainPermission(identity, groups, null, null);
272        if (explanation.accessResult() != AccessResult.UNKNOWN)
273        {
274            return Map.of(
275                    getExplanationObject("thesaurus"),
276                    Map.of(new Permission(PermissionType.ALL_RIGHTS, null), explanation)
277                );
278        }
279        return Map.of();
280    }
281    
282    @Override
283    protected boolean _isSupportedStoredContext(Object storedObject)
284    {
285        String siteName = _getSiteName();
286        String generalContext = __APPLICATION_RIGHT_CONTEXT + (StringUtils.isNoneEmpty(siteName) ? "/" + siteName : "");
287        return storedObject instanceof String str && StringUtils.equals(str, generalContext);
288    }
289    
290    public I18nizableText getObjectLabel(Object object) throws RightsException
291    {
292        return new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_ALL_CONTEXT");
293    }
294    
295    public I18nizableText getObjectCategory(Object object)
296    {
297        return ContentTypeAccessController.REFERENCE_TABLE_CONTEXT_CATEGORY;
298    }
299    
300    public int getObjectPriority(Object object)
301    {
302        // after root but before the content type
303        return 5;
304    }
305
306}