<commit_before>/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.haulmont.cuba.gui.config;

import com.haulmont.bali.datastruct.Node;
import com.haulmont.bali.datastruct.Tree;
import com.haulmont.chile.core.model.*;
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributes;
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
import com.haulmont.cuba.core.entity.CategoryAttribute;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.core.sys.AppContext;
import com.haulmont.cuba.core.sys.xmlparsing.Dom4jTools;
import com.haulmont.cuba.gui.AppConfig;
import com.haulmont.cuba.gui.app.security.entity.AttributeTarget;
import com.haulmont.cuba.gui.app.security.entity.BasicPermissionTarget;
import com.haulmont.cuba.gui.app.security.entity.MultiplePermissionTarget;
import com.haulmont.cuba.gui.app.security.entity.OperationPermissionTarget;
import com.haulmont.cuba.security.role.RolesService;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.commons.text.StringTokenizer;
import org.dom4j.Document;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.persistence.MappedSuperclass;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * GenericUI class holding information about all permission targets.
 */
@Component("cuba_PermissionConfig")
public class PermissionConfig {

    private final Logger log = LoggerFactory.getLogger(PermissionConfig.class);

    @Inject
    protected DynamicAttributes dynamicAttributes;

    @Inject
    protected MetadataTools metadataTools;

    @Inject
    protected Dom4jTools dom4JTools;

    @Inject
    protected RolesService rolesService;

    public static final String PERMISSION_CONFIG_XML_PROP = "cuba.permissionConfig";

    private class Item {
        private Locale locale;

        private Tree<BasicPermissionTarget> screens;
        private Tree<BasicPermissionTarget> specific;

        private List<OperationPermissionTarget> entities;
        private List<MultiplePermissionTarget> entityAttributes;

        private Item(Locale locale) {
            this.locale = locale;

            compileScreens();
            compileEntitiesAndAttributes();
            compileSpecific();
        }

        private String getMessage(String key) {
            return messages.getMainMessage(key, locale);
        }

        private void compileScreens() {
            Node<BasicPermissionTarget> menuRoot = new Node<>(
                    new BasicPermissionTarget("root:menu", getMessage("permissionConfig.mainMenu"), null)
            );
            walkMenu(menuRoot);

            Node<BasicPermissionTarget> allRoot = new Node<>(
                    new BasicPermissionTarget("root:all", getMessage("permissionConfig.allScreens"), null)
            );
            walkAllScreens(allRoot);

            screens = new Tree<>(Arrays.asList(menuRoot, allRoot));
        }

        private void walkMenu(Node<BasicPermissionTarget> node) {
            for (MenuItem info : menuConfig.getRootItems()) {
                walkMenu(info, node);
            }
        }

        private void walkMenu(MenuItem info, Node<BasicPermissionTarget> node) {
            String id = info.getId();
            String caption = menuConfig.getItemCaption(info)
                    .replaceAll("<.+?>", "")
                    .replaceAll("&gt;", "");
            caption = StringEscapeUtils.unescapeHtml4(caption);

            if (info.getChildren() != null && !info.getChildren().isEmpty()) {
                Node<BasicPermissionTarget> n = new Node<>(new BasicPermissionTarget("category:" + id, caption, id));
                node.addChild(n);
                for (MenuItem item : info.getChildren()) {
                    walkMenu(item, n);
                }
            } else {
                if (!info.isSeparator()) {
                    Node<BasicPermissionTarget> n = new Node<>(new BasicPermissionTarget(
                            "item:" + id,
                            caption + " (" + id + ")",
                            id));
                    node.addChild(n);
                }
            }
        }

        private void walkAllScreens(Node<BasicPermissionTarget> allRoot) {
            // filter non-unique windows with specified agent
            windowConfig.getWindows().stream()
                    .distinct()
                    .sorted((w1, w2) -> {
                        String template1 = w1.getTemplate();
                        String template2 = w2.getTemplate();
                        if (template1 != null && template2 != null) {
                            if (template1.startsWith("/")) {
                                template1 = template1.substring(1);
                            }
                            if (template2.startsWith("/")) {
                                template2 = template2.substring(1);
                            }

                            return template1.compareTo(template2);
                        } else {
                            return w1.getId().compareTo(w2.getId());
                        }
                    })
                    .forEach(windowInfo -> walkScreen(windowInfo, allRoot));
            compactScreens(allRoot);
        }

        private void walkScreen(WindowInfo windowInfo, Node<BasicPermissionTarget> allRoot) {
            String template = windowInfo.getTemplate();
            if (template != null) {
                String[] packages = template.split("/");
                if (packages[0].isEmpty()) {
                    packages = ArrayUtils.remove(packages, 0);
                }

                int count = 0;
                Node<BasicPermissionTarget> parentNode = allRoot;
                Node<BasicPermissionTarget> childNode;
                while ((childNode = findCategoryChildNode(getNodeId(packages, count), parentNode)) != null) {
                    count++;
                    parentNode = childNode;
                }

                do {
                    if (count == (packages.length - 1)) {
                        childNode = new Node<>(new BasicPermissionTarget(
                                "item:" + getNodeId(packages, count),
                                packages[count] + " (" + windowInfo.getId() + ")",
                                windowInfo.getId()));
                    } else {
                        childNode = new Node<>(new BasicPermissionTarget(
                                "category:all:" + getNodeId(packages, count),
                                packages[count],
                                null));
                    }

                    parentNode.addChild(childNode);
                    parentNode = childNode;
                } while (++count < packages.length);
            }
        }

        @Nullable
        private Node<BasicPermissionTarget> findCategoryChildNode(String id, Node<BasicPermissionTarget> parentNode) {
            return parentNode.getChildren().stream()
                    .filter(node -> node.getData().getId().equals("category:all:" + id))
                    .findFirst()
                    .orElse(null);
        }

        private String getNodeId(String[] packages, int endIndex) {
            return String.join(".", ArrayUtils.subarray(packages, 0, endIndex + 1));
        }

        private void compactScreens(Node<BasicPermissionTarget> node) {
            if (node.getNumberOfChildren() > 0) {
                for (Node<BasicPermissionTarget> childNode : node.getChildren()) {<commit_msg>The menu items with the same template do not display correctly #2888<commit_after>/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.haulmont.cuba.gui.config;

import com.haulmont.bali.datastruct.Node;
import com.haulmont.bali.datastruct.Tree;
import com.haulmont.chile.core.model.*;
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributes;
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
import com.haulmont.cuba.core.entity.CategoryAttribute;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.core.sys.AppContext;
import com.haulmont.cuba.core.sys.xmlparsing.Dom4jTools;
import com.haulmont.cuba.gui.AppConfig;
import com.haulmont.cuba.gui.app.security.entity.AttributeTarget;
import com.haulmont.cuba.gui.app.security.entity.BasicPermissionTarget;
import com.haulmont.cuba.gui.app.security.entity.MultiplePermissionTarget;
import com.haulmont.cuba.gui.app.security.entity.OperationPermissionTarget;
import com.haulmont.cuba.security.role.RolesService;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.commons.text.StringTokenizer;
import org.dom4j.Document;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.persistence.MappedSuperclass;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * GenericUI class holding information about all permission targets.
 */
@Component("cuba_PermissionConfig")
public class PermissionConfig {

    private final Logger log = LoggerFactory.getLogger(PermissionConfig.class);

    @Inject
    protected DynamicAttributes dynamicAttributes;

    @Inject
    protected MetadataTools metadataTools;

    @Inject
    protected Dom4jTools dom4JTools;

    @Inject
    protected RolesService rolesService;

    public static final String PERMISSION_CONFIG_XML_PROP = "cuba.permissionConfig";

    private class Item {
        private Locale locale;

        private Tree<BasicPermissionTarget> screens;
        private Tree<BasicPermissionTarget> specific;

        private List<OperationPermissionTarget> entities;
        private List<MultiplePermissionTarget> entityAttributes;

        private Item(Locale locale) {
            this.locale = locale;

            compileScreens();
            compileEntitiesAndAttributes();
            compileSpecific();
        }

        private String getMessage(String key) {
            return messages.getMainMessage(key, locale);
        }

        private void compileScreens() {
            Node<BasicPermissionTarget> menuRoot = new Node<>(
                    new BasicPermissionTarget("root:menu", getMessage("permissionConfig.mainMenu"), null)
            );
            walkMenu(menuRoot);

            Node<BasicPermissionTarget> allRoot = new Node<>(
                    new BasicPermissionTarget("root:all", getMessage("permissionConfig.allScreens"), null)
            );
            walkAllScreens(allRoot);

            screens = new Tree<>(Arrays.asList(menuRoot, allRoot));
        }

        private void walkMenu(Node<BasicPermissionTarget> node) {
            for (MenuItem info : menuConfig.getRootItems()) {
                walkMenu(info, node);
            }
        }

        private void walkMenu(MenuItem info, Node<BasicPermissionTarget> node) {
            String id = info.getId();
            String caption = menuConfig.getItemCaption(info)
                    .replaceAll("<.+?>", "")
                    .replaceAll("&gt;", "");
            caption = StringEscapeUtils.unescapeHtml4(caption);

            if (info.getChildren() != null && !info.getChildren().isEmpty()) {
                Node<BasicPermissionTarget> n = new Node<>(new BasicPermissionTarget("category:" + id, caption, id));
                node.addChild(n);
                for (MenuItem item : info.getChildren()) {
                    walkMenu(item, n);
                }
            } else {
                if (!info.isSeparator()) {
                    Node<BasicPermissionTarget> n = new Node<>(new BasicPermissionTarget(
                            "item:" + id,
                            caption + " (" + id + ")",
                            id));
                    node.addChild(n);
                }
            }
        }

        private void walkAllScreens(Node<BasicPermissionTarget> allRoot) {
            // filter non-unique windows with specified agent
            windowConfig.getWindows().stream()
                    .distinct()
                    .sorted((w1, w2) -> {
                        String template1 = w1.getTemplate();
                        String template2 = w2.getTemplate();
                        if (template1 != null && template2 != null) {
                            if (template1.startsWith("/")) {
                                template1 = template1.substring(1);
                            }
                            if (template2.startsWith("/")) {
                                template2 = template2.substring(1);
                            }

                            return template1.compareTo(template2);
                        } else {
                            return w1.getId().compareTo(w2.getId());
                        }
                    })
                    .forEach(windowInfo -> walkScreen(windowInfo, allRoot));
            compactScreens(allRoot);
        }

        private void walkScreen(WindowInfo windowInfo, Node<BasicPermissionTarget> allRoot) {
            String template = windowInfo.getTemplate();
            if (template != null) {
                String[] packages = template.split("/");
                if (packages[0].isEmpty()) {
                    packages = ArrayUtils.remove(packages, 0);
                }

                int count = 0;
                Node<BasicPermissionTarget> parentNode = allRoot;
                Node<BasicPermissionTarget> childNode;
                while ((childNode = findCategoryChildNode(getNodeId(packages, count), parentNode)) != null) {
                    count++;
                    parentNode = childNode;
                }

                do {
                    if (count == (packages.length - 1)) {
                        childNode = new Node<>(new BasicPermissionTarget(
                                "item:" + String.join(".",getNodeId(packages, count), windowInfo.getId()),
                                packages[count] + " (" + windowInfo.getId() + ")",
                                windowInfo.getId()));
                    } else {
                        childNode = new Node<>(new BasicPermissionTarget(
                                "category:all:" + getNodeId(packages, count),
                                packages[count],
                                null));
                    }

                    parentNode.addChild(childNode);
                    parentNode = childNode;
                } while (++count < packages.length);
            }
        }

        @Nullable
        private Node<BasicPermissionTarget> findCategoryChildNode(String id, Node<BasicPermissionTarget> parentNode) {
            return parentNode.getChildren().stream()
                    .filter(node -> node.getData().getId().equals("category:all:" + id))
                    .findFirst()
                    .orElse(null);
        }

        private String getNodeId(String[] packages, int endIndex) {
            return String.join(".", ArrayUtils.subarray(packages, 0, endIndex + 1));
        }

        private void compactScreens(Node<BasicPermissionTarget> node) {
            if (node.getNumberOfChildren() > 0) {
                for (Node<BasicPermissionTarget> childNode : node.getChildren()) {
{'fraction_non_alphanumeric': 0.1, 'fraction_numerical': 0.005937136204889407, 'mean_word_length': 1.986961057023644, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6440144', 'n_tokens_mistral': 4365, 'n_tokens_neox': 4170, 'n_words': 924}