001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.gwt.shared;
029
030import org.opencms.file.CmsResource;
031import org.opencms.util.CmsStringUtil;
032
033import java.util.ArrayList;
034import java.util.Collections;
035import java.util.HashMap;
036import java.util.HashSet;
037import java.util.List;
038import java.util.Map;
039import java.util.Set;
040
041import com.google.common.base.Joiner;
042import com.google.gwt.user.client.rpc.IsSerializable;
043
044/**
045 * Contains information about which folders should restrict uploads.
046 */
047public class CmsUploadRestrictionInfo implements IsSerializable {
048
049    /**
050     * Helper class for building a new CmsUploadRestrictionInfo object.
051     */
052    public static class Builder {
053
054        /** 'Enabled' status. */
055        private Map<String, Boolean> m_tempUploadEnabledMap = new HashMap<>();
056
057        /** 'Types' status. */
058        private Map<String, Set<String>> uploadTypesMap = new HashMap<>();
059
060        /**
061         * Adds a new entry.
062         *
063         * <p>The info string has the format 'key1:value1|key2:value2|....'. Currently the keys 'types' and 'enabled' are supported;
064         * 'enabled' (format: 'enabled:true') enables/disables uploads, and 'types' (format: 'types:jpg,png' sets the allowed file extensions.
065         *
066         * @param path the path
067         * @param info the upload info entry
068         * @return the builder instance
069         */
070        public Builder add(String path, String info) {
071
072            Map<String, String> parsedInfo = CmsStringUtil.splitAsMap(info, "|", ":");
073            path = normalizePath(path);
074            String enabledStr = parsedInfo.get(KEY_ENABLED);
075            if (enabledStr != null) {
076                m_tempUploadEnabledMap.put(path, Boolean.valueOf(enabledStr));
077            }
078            String typesStr = parsedInfo.get(KEY_TYPES);
079            if (typesStr != null) {
080                Set<String> types = new HashSet<>();
081                for (String type : typesStr.split(",")) {
082                    type = type.trim().toLowerCase();
083                    if (type.startsWith(".")) {
084                        type = type.substring(1);
085                    }
086                    if (type.length() > 0) {
087                        types.add(type);
088                    }
089                }
090                uploadTypesMap.put(path, types);
091            }
092            return this;
093
094        }
095
096        /**
097         * Creates a new upload restriction info object.
098         *
099         * @return the new object
100         */
101        @SuppressWarnings("synthetic-access")
102        public CmsUploadRestrictionInfo build() {
103
104            CmsUploadRestrictionInfo result = new CmsUploadRestrictionInfo();
105            result.m_uploadEnabledMap = m_tempUploadEnabledMap;
106            result.m_uploadTypesMap = uploadTypesMap;
107            return result;
108        }
109
110    }
111
112    /** The 'enabled' key. */
113    public static final String KEY_ENABLED = "enabled";
114
115    /** The 'types' key. */
116    public static final String KEY_TYPES = "types";
117
118    /** The default upload restriction that allows everything. */
119    public static final String UNRESTRICTED_UPLOADS = "enabled:true|types:*";
120
121    /** Map to keep track of enabled/disabled status. */
122    private Map<String, Boolean> m_uploadEnabledMap = new HashMap<>();
123
124    /** Map to keep track of allowed file extensions. */
125    private Map<String, Set<String>> m_uploadTypesMap = new HashMap<>();
126
127    /**
128     * Creates a new instance.
129     */
130    protected CmsUploadRestrictionInfo() {}
131
132    /**
133     * Normalizes a path.
134     *
135     * @param path the path
136     * @return the normalized path
137     */
138    static String normalizePath(String path) {
139
140        if (!path.endsWith("/")) {
141            path = path + "/";
142        }
143        return path;
144    }
145
146    /**
147     * Check if a given file extension is allowed for the given upload path.
148     *
149     * @param path the root path of the upload folder
150     * @param extension the file extension to check
151     * @return true if the file extension is valid for uploads to the folder
152     */
153    public boolean checkTypeAllowed(String path, String extension) {
154
155        Set<String> types = getTypes(path);
156        if (extension.startsWith(".")) {
157            extension = extension.substring(1);
158        }
159        extension = extension.toLowerCase();
160        boolean result = types.contains(extension) || types.contains("*");
161        return result;
162    }
163
164    /**
165     * Gets the 'accept' attribute to use for the file input element for the given upload folder.
166     *
167     * @param path the upload folder root path
168     * @return the 'accept' attribute that should be used for the file input
169     */
170    public String getAcceptAttribute(String path) {
171
172        Set<String> types = getTypes(path);
173        List<String> suffixes = new ArrayList<>();
174        for (String type : types) {
175            if ("*".equals(type)) {
176                return "";
177            } else {
178                suffixes.add("." + type);
179            }
180        }
181        return Joiner.on(",").join(suffixes);
182    }
183
184    /**
185     * Checks if the upload should be enabled for the given upload path.
186     *
187     * @param originalPath the upload root path
188     * @return true if the upload is enabled
189     */
190    public boolean isUploadEnabled(String originalPath) {
191
192        String path = originalPath;
193
194        while (path != null) {
195            path = normalizePath(path);
196            Boolean value = m_uploadEnabledMap.get(path);
197            if (value != null) {
198                return value.booleanValue();
199            }
200            path = CmsResource.getParentFolder(path);
201        }
202        return true;
203    }
204
205    /**
206     * Gets the valid extensions for uploads to a given upload folder
207     *
208     * @param path the upload folder root path
209     * @return the valid extensions
210     */
211    protected Set<String> getTypes(String path) {
212
213        while (path != null) {
214            path = normalizePath(path);
215            Set<String> value = m_uploadTypesMap.get(path);
216            if (value != null) {
217                return value;
218
219            }
220            path = CmsResource.getParentFolder(path);
221        }
222        return Collections.emptySet();
223    }
224
225}