001/*
002 *  Copyright 2024 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.core.right;
017
018import java.util.List;
019import java.util.Map;
020import java.util.Set;
021import java.util.stream.Collectors;
022
023import org.apache.commons.lang.StringUtils;
024
025import org.ametys.core.group.Group;
026import org.ametys.core.right.AccessController.AccessResult;
027import org.ametys.runtime.i18n.I18nizableText;
028
029/**
030 * Explanation of an {@link AccessResult} provided by an {@link AccessController}
031 * @param accessControllerId the controller id
032 * @param accessResult the access result
033 * @param explanation The explanation as a {@link I18nizableText}
034 */
035public record AccessExplanation(String accessControllerId, AccessResult accessResult, I18nizableText explanation) implements Comparable<AccessExplanation> {
036    
037    /**
038     * Helper to build a {@link I18nizableText} for profiles
039     * @param profiles the profile
040     * @return the {@link I18nizableText}
041     */
042    public static I18nizableText profilesToI18nizableText(Set<Profile> profiles)
043    {
044        List<String> profileLabel = profiles.stream()
045            .map(Profile::getLabel)
046            .map(escapeHTML -> StringUtils.replace(StringUtils.replace(escapeHTML, "&", "&amp;"), "<", "&lt;"))
047            .sorted()
048            .collect(Collectors.toList());
049        
050        return elementsToI18nizableText(profileLabel);
051    }
052    
053    /**
054     * Helper to build a {@link I18nizableText} for groups
055     * @param groups the profile
056     * @return the {@link I18nizableText}
057     */
058    public static I18nizableText groupsToI18nizableText(Set<Group> groups)
059    {
060        List<String> groupLabel = groups.stream()
061            .map(Group::getLabel)
062            .sorted()
063            .collect(Collectors.toList());
064        
065        return elementsToI18nizableText(groupLabel);
066    }
067    
068    /**
069     * Helper to build a {@link I18nizableText} for a list of String
070     * @param elements the strings
071     * @return the {@link I18nizableText}
072     */
073    public static I18nizableText elementsToI18nizableText(List<String> elements)
074    {
075        if (elements.size() == 1)
076        {
077            return new I18nizableText(elements.get(0));
078        }
079        else
080        {
081            String elementsExceptLast = StringUtils.join(elements.subList(0, elements.size() - 1), ", ");
082            String lastElement = elements.get(elements.size() - 1);
083            
084            return new I18nizableText("plugin.core", "PLUGINS_CORE_RIGHTS_EXPLAIN_TOOL_LIST_OF_ELEMENTS", Map.of("elementsExceptLast", new I18nizableText(elementsExceptLast), "lastElement", new I18nizableText(lastElement)));
085        }
086    }
087
088    public int compareTo(AccessExplanation o)
089    {
090        // order by AccessResult
091        int diff = this.accessResult().compareTo(o.accessResult());
092        if (diff != 0)
093        {
094            return diff;
095        }
096        // and controller id as a fallback to keep consistent ordering
097        else
098        {
099            return o.accessControllerId().compareTo(o.accessControllerId());
100        }
101    }
102}
103