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.ReferenceTableAccessController;
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    @Override
078    public boolean isSupported(Object object)
079    {
080        Request request = ContextHelper.getRequest(_context);
081        String currentWorkspace = RequestAttributeWorkspaceSelector.getForcedWorkspace(request);
082        
083        if (ArchiveConstants.ARCHIVE_WORKSPACE.equals(currentWorkspace))
084        {
085            return false;
086        }
087        
088        return object instanceof Content && _contentTypeHelper.isInstanceOf((Content) object, ThesaurusDAO.MICROTHESAURUS_ABSTRACT_CONTENT_TYPE);
089    }
090    
091    @Override
092    protected Object _convertContext(Object initialContext)
093    {
094        String siteName = _getSiteName();
095        return __APPLICATION_RIGHT_CONTEXT + (StringUtils.isNoneEmpty(siteName) ? "/" + siteName : "");
096    }
097    
098    /**
099     * Convert the asked right id to the real right to check
100     * @param rightId The asked right id
101     * @return the right to check
102     */
103    protected String _convertRightId(String rightId)
104    {
105        return "Thesaurus_Rights_EditTerm";
106    }
107
108    @Override
109    public AccessResult getPermission(UserIdentity user, Set<GroupIdentity> userGroups, String rightId, Object object)
110    {
111        return super.getPermission(user, userGroups, _convertRightId(rightId), object);
112    }
113    
114    @Override
115    public AccessExplanation explainPermission(UserIdentity user, Set<GroupIdentity> groups, String rightId, Object object)
116    {
117        return super.explainPermission(user, groups, _convertRightId(rightId), object);
118    }
119    
120    @Override
121    protected I18nizableText _getExplanationI18nText(PermissionDetails details)
122    {
123        return new I18nizableText("plugin.thesaurus", _getAccessExplanationI18nKey("PLUGINS_THESAURUS_ACCESS_CONTROLLER_", details), _getExplanationI18nParams(details));
124    }
125    
126    @Override
127    protected Map<String, I18nizableTextParameter> _getExplanationI18nParams(PermissionDetails details)
128    {
129        Map<String, I18nizableTextParameter> i18nParams = super._getExplanationI18nParams(details);
130        i18nParams.put("right", _rightEP.getExtension(_convertRightId(null)).getLabel());
131        return i18nParams;
132    }
133    
134    @Override
135    protected I18nizableText getObjectLabelForExplanation(Object object) throws RightsException
136    {
137        return new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_EXPLANATION_CONTEXT_LABEL");
138    }
139
140    @Override
141    public AccessResult getReadAccessPermission(UserIdentity user, Set<GroupIdentity> userGroups, Object object)
142    {
143        return AccessResult.ANY_CONNECTED_ALLOWED;
144    }
145    
146    @Override
147    public AccessExplanation explainReadAccessPermission(UserIdentity user, Set<GroupIdentity> groups, Object object)
148    {
149        return new AccessExplanation(
150                getId(),
151                getReadAccessPermission(user, groups, object),
152                new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_READ_ACCESS_EXPLANATION", Map.of("title", new I18nizableText(((Content) object).getTitle())))
153            );
154    }
155
156    @Override
157    public Map<String, AccessResult> getPermissionByRight(UserIdentity user, Set<GroupIdentity> userGroups, Object object)
158    {
159        return MapUtils.EMPTY_MAP;
160    }
161
162    @Override
163    public AccessResult getPermissionForAnonymous(String rightId, Object object)
164    {
165        return AccessResult.ANONYMOUS_DENIED;
166    }
167    
168    @Override
169    public AccessExplanation explainPermissionForAnonymous(String rightId, Object object)
170    {
171        return new AccessExplanation(
172                getId(),
173                AccessResult.ANONYMOUS_DENIED,
174                new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_ANONYMOUS_PERMISSION_EXPLANATION", Map.of("title", new I18nizableText(((Content) object).getTitle())))
175            );
176    }
177
178    @Override
179    public AccessResult getReadAccessPermissionForAnonymous(Object object)
180    {
181        return AccessResult.ANONYMOUS_DENIED;
182    }
183    
184    @Override
185    public AccessExplanation explainReadAccessPermissionForAnonymous(Object object)
186    {
187        return new AccessExplanation(
188                getId(),
189                AccessResult.ANONYMOUS_DENIED,
190                new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_ANONYMOUS_PERMISSION_EXPLANATION", Map.of("title", new I18nizableText(((Content) object).getTitle())))
191            );
192    }
193
194    @Override
195    public AccessResult getPermissionForAnyConnectedUser(String rightId, Object object)
196    {
197        return AccessResult.ANY_CONNECTED_DENIED;
198    }
199    
200    @Override
201    public AccessExplanation explainPermissionForAnyConnectedUser(String rightId, Object object)
202    {
203        return new AccessExplanation(
204                getId(),
205                AccessResult.ANY_CONNECTED_DENIED,
206                new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_ANY_CONNECTED_PERMISSION_EXPLANATION")
207            );
208    }
209
210    @Override
211    public AccessResult getReadAccessPermissionForAnyConnectedUser(Object object)
212    {
213        return AccessResult.ANY_CONNECTED_ALLOWED;
214    }
215    
216    @Override
217    public AccessExplanation explainReadAccessPermissionForAnyConnectedUser(Object object)
218    {
219        return new AccessExplanation(
220                getId(),
221                AccessResult.ANY_CONNECTED_ALLOWED,
222                new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_READ_ACCESS_EXPLANATION")
223            );
224    }
225
226    @Override
227    public Map<UserIdentity, AccessResult> getPermissionByUser(String rightId, Object object)
228    {
229        return MapUtils.EMPTY_MAP;
230    }
231
232    @Override
233    public Map<GroupIdentity, AccessResult> getReadAccessPermissionByGroup(Object object)
234    {
235        return MapUtils.EMPTY_MAP;
236    }
237    
238    @Override
239    public Map<UserIdentity, AccessResult> getReadAccessPermissionByUser(Object object)
240    {
241        return MapUtils.EMPTY_MAP;
242    }
243
244    @Override
245    public Map<GroupIdentity, AccessResult> getPermissionByGroup(String rightId, Object object)
246    {
247        return MapUtils.EMPTY_MAP;
248    }
249    
250    @Override
251    protected Set< ? extends Object> _convertWorkspaceToRootRightContexts(Set<Object> workspacesContexts)
252    {
253        return null;
254    }
255    
256    // FIXME To remove https://issues.ametys.org/browse/THES-86
257    private String _getSiteName()
258    {
259        Request request = ContextHelper.getRequest(_context);
260        String siteName = request.getParameter("siteName");
261        
262        if (siteName == null)
263        {
264            siteName = (String) request.getAttribute("siteName");
265        }
266        return siteName;
267    }
268
269    @Override
270    public Map<ExplanationObject, Map<Permission, AccessExplanation>> explainAllPermissions(UserIdentity identity, Set<GroupIdentity> groups)
271    {
272        AccessExplanation explanation = explainPermission(identity, groups, null, null);
273        if (explanation.accessResult() != AccessResult.UNKNOWN)
274        {
275            return Map.of(
276                    getExplanationObject("thesaurus"),
277                    Map.of(new Permission(PermissionType.ALL_RIGHTS, null), explanation)
278                );
279        }
280        return Map.of();
281    }
282    
283    @Override
284    protected boolean _isSupportedStoredContext(Object storedObject)
285    {
286        String siteName = _getSiteName();
287        String generalContext = __APPLICATION_RIGHT_CONTEXT + (StringUtils.isNoneEmpty(siteName) ? "/" + siteName : "");
288        return storedObject instanceof String str && StringUtils.equals(str, generalContext);
289    }
290    
291    public I18nizableText getObjectLabel(Object object) throws RightsException
292    {
293        return new I18nizableText("plugin.thesaurus", "PLUGINS_THESAURUS_ACCESS_CONTROLLER_ALL_CONTEXT");
294    }
295    
296    public I18nizableText getObjectCategory(Object object)
297    {
298        return ReferenceTableAccessController.REFERENCE_TABLE_CONTEXT_CATEGORY;
299    }
300    
301    public int getObjectPriority(Object object)
302    {
303        // after root but before the content type
304        return 5;
305    }
306
307}