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.widgets;
029
030import org.opencms.file.CmsGroup;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsResource;
033import org.opencms.i18n.CmsMessages;
034import org.opencms.main.CmsException;
035import org.opencms.main.CmsLog;
036import org.opencms.main.OpenCms;
037import org.opencms.security.CmsOrganizationalUnit;
038import org.opencms.util.CmsMacroResolver;
039import org.opencms.util.CmsStringUtil;
040import org.opencms.xml.types.A_CmsXmlContentValue;
041
042import java.util.ArrayList;
043import java.util.Iterator;
044import java.util.List;
045import java.util.Locale;
046import java.util.Map;
047import java.util.regex.Pattern;
048import java.util.regex.PatternSyntaxException;
049
050import org.apache.commons.logging.Log;
051
052/**
053 * Provides a widget for group selection select boxes.<p>
054 *
055 * This widget is configurable with the following options:<p>
056 * <ul>
057 * <li><code>groupfilter</code>: regular expression to filter available groups</li>
058 * <li><code>groups</code>: comma separated list of group names to show in the select box. <b>Note</b>:
059 *     if this configuration option if used,
060 *     <code>groupfilter</code> and <code>includesubous</code> are <i>not</i> considered anymore.</li>
061 * <li><code>includesubous</code>: boolean flag to indicate if sub OUs should be scanned for groups to select</li>
062 * <li><code>oufqn</code>: the fully qualified name of the OU to read the groups from</li>
063 * </ul>
064 * To map the selected group to a permission to set, use the following mapping configuration:<p>
065 * <code>&lt;mapping element="..." mapto="permission:GROUP:+r+v|GROUP.ALL_OTHERS:|GROUP.Projectmanagers:+r+v+w+c" /&gt;</code><p>
066 * This means that the +r+v permission is written for the principal <code>GROUP</code> on the resource.
067 * Additionally two permissions are written as default: for <code>ALL_OTHERS</code>, no allowed permission is set,
068 * for <code>Projectmanagers</code>, "+r+v+w+c" is set.<p>
069 *
070 * @since 8.0.0
071 */
072public class CmsSelectGroupWidget extends CmsSelectWidget {
073
074    /** Configuration option key: group filter. */
075    protected static final String CONFIGURATION_GROUPFILTER = "groupfilter";
076
077    /** Configuration option key: groups. */
078    protected static final String CONFIGURATION_GROUPS = "groups";
079
080    /** Configuration option key: include sub OUs. */
081    protected static final String CONFIGURATION_INCLUDESUBOUS = "includesubous";
082
083    /** Configuration option key: OU fully qualified name. */
084    protected static final String CONFIGURATION_OUFQN = "oufqn";
085
086    /** The log object for this class. */
087    private static final Log LOG = CmsLog.getLog(CmsSelectGroupWidget.class);
088
089    /** The configured group filter to match groups to show in the select box. */
090    Pattern m_groupFilter;
091
092    /** The configured group names to show in the select box. */
093    List<String> m_groupNames;
094
095    /** Indicates if sub OUs should be included when reading the groups. */
096    private boolean m_includeSubOus;
097
098    /** The fully qualified name of the OU to read the groups from. */
099    private String m_ouFqn;
100
101    /**
102     * Creates a new group select widget.<p>
103     */
104    public CmsSelectGroupWidget() {
105
106        // empty constructor is required for class registration
107        super();
108    }
109
110    /**
111     * Creates a group select widget with the specified select options.<p>
112     *
113     * @param configuration the configuration (possible options) for the group select box
114     */
115    public CmsSelectGroupWidget(String configuration) {
116
117        super(configuration);
118    }
119
120    /**
121     * @see org.opencms.widgets.I_CmsADEWidget#getConfiguration(org.opencms.file.CmsObject, org.opencms.xml.types.A_CmsXmlContentValue, org.opencms.i18n.CmsMessages, org.opencms.file.CmsResource, java.util.Locale)
122     */
123    @Override
124    public String getConfiguration(
125        CmsObject cms,
126        A_CmsXmlContentValue schemaType,
127        CmsMessages messages,
128        CmsResource resource,
129        Locale contentLocale) {
130
131        parseSelectOptions(cms, messages, schemaType);
132        String results = getConfiguration();
133
134        return results;
135    }
136
137    /**
138     * @see org.opencms.widgets.I_CmsADEWidget#getCssResourceLinks(org.opencms.file.CmsObject)
139     */
140    @Override
141    public List<String> getCssResourceLinks(CmsObject cms) {
142
143        return null;
144    }
145
146    /**
147     * @see org.opencms.widgets.I_CmsADEWidget#getInitCall()
148     */
149    @Override
150    public String getInitCall() {
151
152        return null;
153    }
154
155    /**
156     * @see org.opencms.widgets.I_CmsADEWidget#getJavaScriptResourceLinks(org.opencms.file.CmsObject)
157     */
158    @Override
159    public List<String> getJavaScriptResourceLinks(CmsObject cms) {
160
161        return null;
162    }
163
164    /**
165     * @see org.opencms.widgets.I_CmsADEWidget#isInternal()
166     */
167    @Override
168    public boolean isInternal() {
169
170        return true;
171    }
172
173    /**
174     * @see org.opencms.widgets.I_CmsWidget#newInstance()
175     */
176    @Override
177    public I_CmsWidget newInstance() {
178
179        return new CmsSelectGroupWidget(getConfiguration());
180    }
181
182    /**
183     * Returns the list of configured select options, parsing the configuration String if required.<p>
184     *
185     * The list elements are of type <code>{@link CmsSelectWidgetOption}</code>.
186     * The configuration String is parsed only once and then stored internally.<p>
187     *
188     * @param cms the current users OpenCms context
189     * @param messages the messages of this dialog
190     * @param param the widget parameter of this dialog
191     *
192     * @return the list of select options
193     *
194     * @see CmsSelectWidgetOption
195     */
196    protected List<CmsSelectWidgetOption> parseSelectOptions(
197        CmsObject cms,
198        CmsMessages messages,
199        I_CmsWidgetParameter param) {
200
201        // only create options if not already done
202        if (getSelectOptions() == null) {
203            // parse widget configuration
204            parseConfiguration(cms, messages);
205            List<CmsSelectWidgetOption> result = new ArrayList<CmsSelectWidgetOption>();
206
207            if (isUseGroupNames()) {
208                // a list of group names is configured, show them
209                for (Iterator<String> i = getGroupNames().iterator(); i.hasNext();) {
210                    String groupName = i.next();
211                    try {
212                        // ensure that only existing groups are available in the select box
213                        CmsGroup group = cms.readGroup(getOuFqn() + groupName);
214                        result.add(new CmsSelectWidgetOption(group.getName(), false, group.getSimpleName()));
215                    } catch (CmsException e) {
216                        // error reading the group by name, simply skip it
217                    }
218                }
219            } else {
220                // read the groups from an optionally configured OU and filter them if configured
221                try {
222                    List<CmsGroup> groups = OpenCms.getOrgUnitManager().getGroups(cms, getOuFqn(), isIncludeSubOus());
223                    for (Iterator<CmsGroup> i = groups.iterator(); i.hasNext();) {
224                        CmsGroup group = i.next();
225                        if (isUseGroupFilter()) {
226                            // check if group name matches the given regular expression
227                            if (!getGroupFilter().matcher(group.getSimpleName()).matches()) {
228                                continue;
229                            }
230                        }
231                        result.add(new CmsSelectWidgetOption(group.getName(), false, group.getSimpleName()));
232                    }
233                } catch (CmsException e) {
234                    // error reading the groups
235                }
236
237            }
238            setSelectOptions(result);
239        }
240        return getSelectOptions();
241    }
242
243    /**
244     * @see org.opencms.widgets.A_CmsSelectWidget#parseSelectOptions(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter)
245     */
246    @Override
247    protected List<CmsSelectWidgetOption> parseSelectOptions(
248        CmsObject cms,
249        I_CmsWidgetDialog widgetDialog,
250        I_CmsWidgetParameter param) {
251
252        return parseSelectOptions(cms, widgetDialog.getMessages(), param);
253    }
254
255    /**
256     * Returns the configured group filter to match groups to show in the select box.<p>
257     *
258     * @return the configured group filter to match groups to show in the select box
259     */
260    private Pattern getGroupFilter() {
261
262        return m_groupFilter;
263    }
264
265    /**
266     * Returns the configured group names to show in the select box.<p>
267     *
268     * @return configured group names to show in the select box
269     */
270    private List<String> getGroupNames() {
271
272        return m_groupNames;
273    }
274
275    /**
276     * Returns the fully qualified name of the OU to read the groups from.<p>
277     *
278     * @return the fully qualified name of the OU to read the groups from
279     */
280    private String getOuFqn() {
281
282        return m_ouFqn;
283    }
284
285    /**
286     * Returns if sub OUs should be considered when filtering the groups.<p>
287     *
288     * @return <code>true</code> if sub OUs should be considered, otherwise <code>false</code>
289     */
290    private boolean isIncludeSubOus() {
291
292        return m_includeSubOus;
293    }
294
295    /**
296     * Returns if a group filter is configured to match groups to show in the select box.<p>
297     *
298     * @return <code>true</code> if a group filter is configured, otherwise <code>false</code>
299     */
300    private boolean isUseGroupFilter() {
301
302        return getGroupFilter() != null;
303    }
304
305    /**
306     * Returns if group names are configured to show in the select box.<p>
307     *
308     * @return <code>true</code> if group names are configured, otherwise <code>false</code>
309     */
310    private boolean isUseGroupNames() {
311
312        return getGroupNames() != null;
313    }
314
315    /**
316     * Parses the widget configuration string.<p>
317     *
318     * @param cms the current users OpenCms context
319     * @param widgetDialog the dialog of this widget
320     */
321    private void parseConfiguration(CmsObject cms, CmsMessages widgetDialog) {
322
323        String configString = "";
324        if (widgetDialog != null) {
325            configString = CmsMacroResolver.resolveMacros(getConfiguration(), cms, widgetDialog);
326            Map<String, String> config = CmsStringUtil.splitAsMap(configString, "|", "=");
327            // get the list of group names to show
328            String groups = config.get(CONFIGURATION_GROUPS);
329            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(groups)) {
330                m_groupNames = CmsStringUtil.splitAsList(groups, ',', true);
331            }
332            // get the regular expression to filter the groups
333            String filter = config.get(CONFIGURATION_GROUPFILTER);
334            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(filter)) {
335                try {
336                    m_groupFilter = Pattern.compile(filter);
337                } catch (PatternSyntaxException e) {
338                    // log pattern syntax errors
339                    LOG.error(Messages.get().getBundle().key(Messages.LOG_ERR_WIDGET_SELECTGROUP_PATTERN_1, filter));
340                }
341            }
342            // get the OU to read the groups from
343            m_ouFqn = config.get(CONFIGURATION_OUFQN);
344            if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_ouFqn)) {
345                m_ouFqn = "";
346            } else if (!m_ouFqn.endsWith(CmsOrganizationalUnit.SEPARATOR)) {
347                m_ouFqn += CmsOrganizationalUnit.SEPARATOR;
348            }
349            // set the flag to include sub OUs
350            m_includeSubOus = Boolean.valueOf(config.get(CONFIGURATION_INCLUDESUBOUS)).booleanValue();
351        }
352    }
353}