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.ui.apps.user;
029
030import org.opencms.file.CmsGroup;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsUser;
033import org.opencms.main.CmsException;
034import org.opencms.main.CmsLog;
035import org.opencms.main.OpenCms;
036import org.opencms.security.CmsAccessControlEntry;
037import org.opencms.security.CmsOrganizationalUnit;
038import org.opencms.security.CmsPrincipal;
039import org.opencms.security.CmsRole;
040import org.opencms.security.CmsRoleViolationException;
041import org.opencms.security.I_CmsPrincipal;
042import org.opencms.ui.A_CmsUI;
043import org.opencms.ui.CmsCssIcon;
044import org.opencms.ui.CmsUserIconHelper;
045import org.opencms.ui.CmsVaadinUtils;
046import org.opencms.ui.FontOpenCms;
047import org.opencms.ui.apps.A_CmsWorkplaceApp;
048import org.opencms.ui.apps.CmsAppWorkplaceUi;
049import org.opencms.ui.apps.CmsFileExplorer;
050import org.opencms.ui.apps.I_CmsAppUIContext;
051import org.opencms.ui.apps.Messages;
052import org.opencms.ui.apps.user.CmsGroupTable.TableProperty;
053import org.opencms.ui.components.CmsBasicDialog;
054import org.opencms.ui.components.CmsBasicDialog.DialogWidth;
055import org.opencms.ui.components.CmsInfoButton;
056import org.opencms.ui.components.CmsResourceInfo;
057import org.opencms.ui.components.CmsToolBar;
058import org.opencms.ui.components.OpenCmsTheme;
059import org.opencms.ui.dialogs.permissions.CmsPrincipalSelect;
060import org.opencms.ui.dialogs.permissions.CmsPrincipalSelect.WidgetType;
061import org.opencms.ui.dialogs.permissions.CmsPrincipalSelectDialog;
062import org.opencms.ui.dialogs.permissions.I_CmsPrincipalSelect;
063import org.opencms.util.CmsStringUtil;
064import org.opencms.util.CmsUUID;
065
066import java.util.ArrayList;
067import java.util.Collections;
068import java.util.LinkedHashMap;
069import java.util.List;
070import java.util.Map;
071import java.util.Set;
072import java.util.concurrent.ConcurrentHashMap;
073import java.util.function.Function;
074
075import org.apache.commons.logging.Log;
076
077import com.vaadin.server.ExternalResource;
078import com.vaadin.server.FontAwesome;
079import com.vaadin.server.Sizeable.Unit;
080import com.vaadin.ui.Button;
081import com.vaadin.ui.Button.ClickEvent;
082import com.vaadin.ui.Button.ClickListener;
083import com.vaadin.ui.Component;
084import com.vaadin.ui.HorizontalSplitPanel;
085import com.vaadin.ui.UI;
086import com.vaadin.ui.Window;
087import com.vaadin.ui.themes.ValoTheme;
088import com.vaadin.v7.data.Item;
089import com.vaadin.v7.data.Property.ValueChangeEvent;
090import com.vaadin.v7.data.Property.ValueChangeListener;
091import com.vaadin.v7.data.util.IndexedContainer;
092import com.vaadin.v7.event.FieldEvents.TextChangeEvent;
093import com.vaadin.v7.event.FieldEvents.TextChangeListener;
094import com.vaadin.v7.ui.ComboBox;
095import com.vaadin.v7.ui.Label;
096import com.vaadin.v7.ui.Table;
097import com.vaadin.v7.ui.TextField;
098import com.vaadin.v7.ui.VerticalLayout;
099
100/**
101 * App for the OU Management.<p>
102 */
103public class CmsAccountsApp extends A_CmsWorkplaceApp implements I_CmsPrincipalSelect {
104
105    /**
106     * Bean for the state of the app.<p>
107     */
108    class CmsStateBean {
109
110        /**the filter for tables. */
111        private String m_filter;
112
113        /**Group id to be opended (or null). */
114        private CmsUUID m_groupID;
115
116        /**ou path. */
117        private String m_path = "";
118
119        /**type of element to be openend. */
120        private I_CmsOuTreeType m_type;
121
122        /**
123         * public constructor.<p>
124         *
125         * @param path ou path
126         * @param type type to be opened
127         * @param groupID groupid
128         * @param filter filter string
129         */
130        public CmsStateBean(String path, I_CmsOuTreeType type, CmsUUID groupID, String filter) {
131
132            m_path = path.equals("/") ? "" : path;
133            m_type = type;
134            m_groupID = groupID;
135            m_filter = filter;
136        }
137
138        /**
139         * Gets group id.<p>
140         *
141         * @return group id
142         */
143        public CmsUUID getGroupID() {
144
145            return m_groupID;
146        }
147
148        /**
149         * Gets the ou path.<p>
150         *
151         * @return ou path
152         */
153        public String getPath() {
154
155            return m_path;
156        }
157
158        /**
159         * Gets the state string of the current bean.<p>
160         *
161         * @return state string
162         */
163        public String getState() {
164
165            String typeString = m_type.getId();
166            String groupString = "";
167            if (m_groupID != null) {
168                groupString = m_groupID.getStringValue();
169            }
170            return typeString + STATE_SEPERATOR + m_path + STATE_SEPERATOR + groupString + STATE_SEPERATOR + m_filter;
171
172        }
173
174        /**
175         * Gets the filter string for the table.<p>
176         *
177         * @return the table filter
178         */
179        public String getTableFilter() {
180
181            return m_filter;
182        }
183
184        /**
185         * Gets type of element to open.<p>
186         *
187         * @return type of element
188         */
189        public I_CmsOuTreeType getType() {
190
191            return m_type;
192        }
193    }
194
195    /**State seperator. */
196    public static String STATE_SEPERATOR = A_CmsWorkplaceApp.PARAM_SEPARATOR;
197
198    /** Default tree type provider. */
199    private static final CmsDefaultTreeTypeProvider DEFAULT_TREETYPES = new CmsDefaultTreeTypeProvider();
200
201    /** The log object for this class. */
202    private static final Log LOG = CmsLog.getLog(CmsAccountsApp.class);
203
204    /**Button to add an element. */
205    protected Button m_addElementButton;
206
207    /**CmsObject. */
208    protected CmsObject m_cms;
209
210    /** Toolbar button for CSV import/export in OUs. */
211    protected Button m_importExport;
212
213    /**vaadin component. */
214    protected CmsInfoButton m_infoButton;
215
216    /**vaadin component.*/
217    protected Button m_newButton;
218
219    /**vaadin component.*/
220    protected Button m_toggleButtonGroups;
221
222    /**vaadin component.*/
223    protected Button m_toggleButtonRole;
224
225    /**vaadin component.*/
226    protected Button m_toggleButtonUser;
227
228    /**Don't handle change event flag.*/
229    boolean m_doNotChange;
230
231    /**State bean. */
232    CmsStateBean m_stateBean;
233
234    /**Base ou. */
235    private String m_baseOU = "";
236
237    /**vaadin component.*/
238    private ComboBox m_filter;
239
240    /** The file table filter input. */
241    private TextField m_filterTable;
242
243    /**Class to handle visible and managable ous. */
244    private CmsOUHandler m_ouHandler;
245
246    /** The folder tree. */
247    private CmsOuTree m_ouTree;
248
249    /** Map for the cached password reset states. */
250    private Map<CmsUUID, Boolean> m_passwordResetStateCache = new ConcurrentHashMap<>();
251
252    /**vaadin component.*/
253    private HorizontalSplitPanel m_splitScreen;
254
255    /**vaadin component.*/
256    private I_CmsFilterableTable m_table;
257
258    /**
259     * constructor.<p>
260     */
261    public CmsAccountsApp() {
262
263        super();
264        try {
265            m_cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject());
266            m_cms.getRequestContext().setSiteRoot("");
267            m_ouHandler = new CmsOUHandler(m_cms);
268            m_baseOU = m_ouHandler.getBaseOU();
269
270        } catch (
271
272        CmsException e) {
273            //}
274        }
275        m_rootLayout.setMainHeightFull(true);
276        m_splitScreen = new HorizontalSplitPanel();
277        m_splitScreen.setSizeFull();
278        m_splitScreen.setSplitPosition(CmsFileExplorer.LAYOUT_SPLIT_POSITION, Unit.PIXELS);
279        m_rootLayout.setMainContent(m_splitScreen);
280        m_ouTree = new CmsOuTree(m_cms, this, m_baseOU);
281        m_splitScreen.setFirstComponent(m_ouTree);
282
283    }
284
285    /**
286     * Creates info panel for OUs.<p>
287     *
288     *
289     * @param ou to get panel for
290     * @return CmsResourceInfo
291     */
292    public static CmsResourceInfo getOUInfo(CmsOrganizationalUnit ou) {
293
294        String style = OpenCmsTheme.ICON_OU;
295        if (ou.hasFlagWebuser()) {
296            style = OpenCmsTheme.ICON_OU_WEB;
297        }
298        CmsCssIcon image = new CmsCssIcon(style);
299        return new CmsResourceInfo(
300            ou.getDisplayName(A_CmsUI.get().getLocale()),
301            ou.getDescription(A_CmsUI.get().getLocale()),
302            image);
303    }
304
305    /**
306     * Creates info panel for principals.<p>
307     *
308     * @param principal to get info panel for
309     * @return CmsResourceInfo
310     */
311    public static CmsResourceInfo getPrincipalInfo(I_CmsPrincipal principal) {
312
313        if (principal == null) {
314            return null;
315        }
316        if (principal instanceof CmsUser) {
317            CmsUser user = (CmsUser)principal;
318            CmsUserIconHelper helper = OpenCms.getWorkplaceAppManager().getUserIconHelper();
319            return new CmsResourceInfo(
320                user.getName(),
321                user.getEmail(),
322                new ExternalResource(helper.getTinyIconPath(A_CmsUI.getCmsObject(), user)));
323        }
324        if (principal.getId().equals(CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_ID)) {
325            return new CmsResourceInfo(
326                CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_LABEL_ALLOTHERS_0),
327                CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_DESCRIPTION_ALLOTHERS_0),
328                new CmsCssIcon(OpenCmsTheme.ICON_PRINCIPAL_ALL));
329        }
330        if (principal.getId().equals(CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_ID)) {
331            return new CmsResourceInfo(
332                CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_LABEL_OVERWRITEALL_0),
333                CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_DESCRIPTION_OVERWRITEALL_0),
334                new CmsCssIcon(OpenCmsTheme.ICON_PRINCIPAL_OVERWRITE));
335        }
336        CmsRole role = CmsRole.valueOfId(principal.getId());
337        if (role != null) {
338            return new CmsResourceInfo(
339                role.getName(A_CmsUI.get().getLocale()),
340                role.getDescription(A_CmsUI.get().getLocale()),
341                new CmsCssIcon(OpenCmsTheme.ICON_ROLE));
342        }
343        return new CmsResourceInfo(
344            principal.getName(),
345            principal.getDescription(A_CmsUI.get().getLocale()),
346            new CmsCssIcon(OpenCmsTheme.ICON_GROUP));
347    }
348
349    /**
350     * Adds additional properties for groups to a container.
351     *
352     * @param container the container to update
353     */
354    public void addGroupContainerProperties(IndexedContainer container) {
355
356        // do nothing
357
358    }
359
360    /**
361     * Adds additional properties for users to a container.
362     *
363     * @param container the container to update
364     */
365    public void addUserContainerProperties(IndexedContainer container) {
366
367        // do nothing
368
369    }
370
371    /**
372     * Checks if the given user is editable.<p>
373     *
374     * @param id the id of the user
375     * @return true if the user is editable
376     */
377    public boolean canEditUser(CmsUUID id) {
378
379        return true;
380    }
381
382    /**
383     * Checks if group members can be removed from the given OU.<p>
384     *
385     * @param group the group name
386     * @return true if group members can be removed from the given OU
387     */
388    public boolean canRemoveGroupMemebers(String group) {
389
390        return true;
391    }
392
393    /**
394     * Checks if a set of groups can be added to a user.<p>
395     *
396     * @param principal the user
397     * @param data the set of names of groups to check
398     *
399     * @return true if the groups can be added to the user
400     */
401    public boolean checkAddGroup(CmsUser principal, Set<String> data) {
402
403        return true;
404    }
405
406    /**
407     * Checks if a user can be removed from a set of groups.<p>
408     *
409     * @param principal the user
410     * @param items the names of groups to check
411     *
412     * @return true if the user can be removed from  the group
413     */
414    public boolean checkRemoveGroups(CmsUser principal, Set<String> items) {
415
416        return true;
417    }
418
419    /**
420     * Fills the container item representing a group.<p>
421     *
422     * @param item the item
423     * @param group the group
424     * @param indirects the indirect groups
425     */
426    public void fillGroupItem(Item item, CmsGroup group, List<CmsGroup> indirects) {
427
428        item.getItemProperty(TableProperty.Name).setValue(group.getName());
429        item.getItemProperty(TableProperty.Description).setValue(group.getDescription(A_CmsUI.get().getLocale()));
430        item.getItemProperty(TableProperty.OU).setValue(group.getOuFqn());
431        if (indirects.contains(group)) {
432            item.getItemProperty(TableProperty.INDIRECT).setValue(Boolean.TRUE);
433        }
434    }
435
436    /**
437    * Gets the app id.<p>
438    *
439    * @return the app id
440    */
441    public String getAppId() {
442
443        return CmsAccountsAppConfiguration.APP_ID;
444    }
445
446    /**
447     * Gets a data container for the groups available to be added to a user, excluding some groups.<p>
448     *
449     * @param cms the current CMS context
450     * @param ouFqn the OU for which to get the groups
451     * @param propCaption the property for the caption
452     * @param propIcon the property for the icon
453     * @param propOu the property for the OU
454     * @param groupsOfUser the groups to exclude
455     * @param iconProvider the icon provider
456     *
457     * @return the container with the group data
458     */
459    public IndexedContainer getAvailableGroupsContainerWithout(
460        CmsObject cms,
461        String ouFqn,
462        String propCaption,
463        String propIcon,
464        String propOu,
465        List<CmsGroup> groupsOfUser,
466        Function<CmsGroup, CmsCssIcon> iconProvider) {
467
468        // TODO Auto-generated method stub
469        return CmsVaadinUtils.getAvailableGroupsContainerWithout(
470            cms,
471            ouFqn,
472            propCaption,
473            propIcon,
474            propOu,
475            groupsOfUser,
476            iconProvider);
477    }
478
479    /**
480     * Gets the group edit parameters for a given group.<p>
481     *
482     * @param group a group
483     *
484     * @return the group edit parameters for the group
485     */
486    public CmsGroupEditParameters getGroupEditParameters(CmsGroup group) {
487
488        CmsGroupEditParameters params = new CmsGroupEditParameters();
489        return params;
490    }
491
492    /**
493     * Gets the icon for a group.<p>
494     *
495     * @param group the group
496     * @return the icon for the group
497     */
498    public CmsCssIcon getGroupIcon(CmsGroup group) {
499
500        return new CmsCssIcon("oc-icon-24-group");
501    }
502
503    /**
504     * Gets the cache for the password reset states.
505     * <p>The cache keys are user ids.
506     *
507     * @return the cache for the password reset states
508     */
509    public Map<CmsUUID, Boolean> getPasswordResetStateCache() {
510
511        return m_passwordResetStateCache;
512    }
513
514    /**
515     * Gets the user edit parameters.<p>
516     *
517     * @param user the user
518     * @return the user edit parameters
519     */
520    public CmsUserEditParameters getUserEditParameters(CmsUser user) {
521
522        CmsUserEditParameters params = new CmsUserEditParameters();
523        params.setEditEnabled(true);
524        params.setPasswordChangeEnabled(true);
525        return params;
526    }
527
528    /**
529     * Gets the container for the groups of an user for the purpose of editing them.<p>
530     *
531     * @param user the user
532     * @param propName the property for the name
533     * @param propIcon the property for the icon
534     * @param propStatus the property for the status
535     *
536     * @return the container with the user groups
537     */
538    public IndexedContainer getUserGroupsEditorContainer(
539        CmsUser user,
540        String propName,
541        String propIcon,
542        String propStatus) {
543
544        IndexedContainer container = new IndexedContainer();
545        container.addContainerProperty(propName, String.class, "");
546        container.addContainerProperty(CmsUserEditGroupsDialog.ID_OU, String.class, "");
547        container.addContainerProperty(propStatus, Boolean.class, Boolean.valueOf(true));
548        container.addContainerProperty(propIcon, CmsCssIcon.class, new CmsCssIcon("oc-icon-group-24"));
549        try {
550            for (CmsGroup group : m_cms.getGroupsOfUser(user.getName(), true)) {
551                Item item = container.addItem(group);
552                item.getItemProperty(propName).setValue(group.getSimpleName());
553                item.getItemProperty(CmsUserEditGroupsDialog.ID_OU).setValue(group.getOuFqn());
554                item.getItemProperty(propIcon).setValue(getGroupIcon(group));
555            }
556        } catch (CmsException e) {
557            LOG.error("Unable to read groups from user", e);
558        }
559        return container;
560    }
561
562    /**
563     * Gets list of users for organizational unit.<p>
564     *
565     * @param cms the CMS context
566     * @param ou the OU path
567     * @param recursive true if users from other OUs should be retrieved
568     *
569     * @return the list of users, without their additional info
570     *
571     * @throws CmsException if something goes wrong
572     */
573    public List<CmsUser> getUsersWithoutAdditionalInfo(
574        CmsObject cms,
575        I_CmsOuTreeType type,
576        String ou,
577        boolean recursive)
578    throws CmsException {
579
580        return CmsPrincipal.filterCoreUsers(
581            OpenCms.getOrgUnitManager().getUsersWithoutAdditionalInfo(cms, ou, recursive));
582    }
583
584    /**
585     * @see org.opencms.ui.dialogs.permissions.I_CmsPrincipalSelect#handlePrincipal(org.opencms.security.I_CmsPrincipal)
586     */
587    public void handlePrincipal(I_CmsPrincipal principal) {
588
589        if (m_stateBean.getType().isGroup()) {
590            try {
591                CmsGroup group = m_cms.readGroup(m_stateBean.getGroupID());
592                m_cms.addUserToGroup(principal.getName(), group.getName());
593
594            } catch (CmsException e) {
595                return;
596            }
597        }
598        if (m_stateBean.getType().isRole()) {
599            try {
600                OpenCms.getRoleManager().addUserToRole(
601                    m_cms,
602                    CmsRole.valueOfId(m_stateBean.getGroupID()).forOrgUnit(m_stateBean.getPath()),
603                    principal.getName());
604            } catch (CmsException e) {
605                return;
606            }
607        }
608        A_CmsUI.get().reload();
609    }
610
611    /**
612     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#initUI(org.opencms.ui.apps.I_CmsAppUIContext)
613     */
614    @Override
615    public void initUI(I_CmsAppUIContext context) {
616
617        context.addPublishButton(changed -> {/* do nothing*/});
618        super.initUI(context);
619    }
620
621    /**
622     * Checks if the given OU is manageable.<p>
623     *
624     * @param ou to check
625     * @return true if user is allowed to manage ou
626     */
627    public boolean isOUManagable(String ou) {
628
629        return m_ouHandler.isOUManagable(ou);
630    }
631
632    /**
633     * Checks if given ou is parent of a managable ou.<p>
634     *
635     * @param name to check
636     * @return boolean
637     */
638    public boolean isParentOfManagableOU(String name) {
639
640        return m_ouHandler.isParentOfManagableOU(name);
641    }
642
643    /**
644     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#openSubView(java.lang.String, boolean)
645     */
646    @Override
647    public void openSubView(String state, boolean updateState) {
648
649        if (updateState) {
650            CmsAppWorkplaceUi.get().changeCurrentAppState(state);
651        }
652
653        Component comp = getComponentForState(state);
654
655        updateInfoButton();
656        if (comp != null) {
657            VerticalLayout layout = new VerticalLayout();
658            layout.setSizeFull();
659            comp.setSizeFull();
660            layout.addComponent(m_table.getEmptyLayout());
661            layout.addComponent(m_table);
662            handleSetTable(m_table);
663            m_splitScreen.setSecondComponent(layout);
664        } else {
665            m_splitScreen.setSecondComponent(new Label("Malformed path, tool not available for path: " + state));
666            handleSetTable(null);
667        }
668        m_splitScreen.setSizeFull();
669        updateSubNav(getSubNavEntries(state));
670        updateBreadCrumb(getBreadCrumbForState(state));
671    }
672
673    /**
674     * Parses a given state string to state bean.<p>
675     *
676     * @param state to be read
677     * @param baseOU baseOu
678     * @return CmsStateBean
679     */
680    public CmsStateBean parseState(String state, String baseOU) {
681
682        String path = baseOU;
683        String filter = "";
684        I_CmsOuTreeType type = CmsOuTreeType.OU;
685        CmsUUID groupId = null;
686        List<String> fields = CmsStringUtil.splitAsList(state, STATE_SEPERATOR);
687        if (!fields.isEmpty()) {
688            if (fields.size() > 1) {
689                path = fields.get(1);
690                //Make sure to only show OUs which are under baseOU
691                if (path.equals("") | !path.startsWith(baseOU)) {
692                    path = baseOU;
693                }
694            }
695            for (I_CmsOuTreeType ty : getTreeTypeProvider().getTreeTypes()) {
696                if (fields.get(0).equals(ty.getId())) {
697                    type = ty;
698                }
699            }
700            if (fields.size() > 2) {
701                if (!CmsStringUtil.isEmptyOrWhitespaceOnly(fields.get(2))) {
702                    groupId = new CmsUUID(fields.get(2));
703                }
704            }
705            if (fields.size() > 3) {
706                filter = fields.get(3);
707            }
708        }
709        return new CmsStateBean(path, type, groupId, filter);
710    }
711
712    /**
713     * Reads the list of groups for an organizational unit.<p>
714     *
715     * @param cms the CMS context
716     * @param ou the OU path
717     * @param type the tree type
718     * @param subOus true if groups for sub-OUs should be read
719     * @return the list of groups for the OU
720     *
721     * @throws CmsException if something goes wrong
722     */
723    public List<CmsGroup> readGroupsForOu(CmsObject cms, String ou, I_CmsOuTreeType type, boolean subOus)
724    throws CmsException {
725
726        return CmsPrincipal.filterCoreGroups(OpenCms.getOrgUnitManager().getGroups(m_cms, ou, subOus));
727    }
728
729    /**
730     * Reloads the app with current state.<p>
731     */
732    public void reload() {
733
734        update(m_stateBean.getPath(), m_stateBean.getType(), m_stateBean.getGroupID());
735    }
736
737    /**
738     * Updates the app state.<p>
739     *
740     * @param ou to be opened
741     * @param type to be opened
742     * @param groupID to be openend(may be null)
743     */
744    public void update(String ou, I_CmsOuTreeType type, CmsUUID groupID) {
745
746        update(ou, type, groupID, m_filterTable.getValue());
747
748    }
749
750    /**
751     * Updates the app state.<p>
752     *
753     * @param ou to be opened
754     * @param type to be opened
755     * @param roleOrGroupID to be openend(may be null)
756     * @param filter filter string
757     */
758    public void update(String ou, I_CmsOuTreeType type, CmsUUID roleOrGroupID, String filter) {
759
760        CmsStateBean stateBean = new CmsStateBean(ou, type, roleOrGroupID, filter);
761
762        try {
763            m_ouTree.updateOU(OpenCms.getOrgUnitManager().readOrganizationalUnit(m_cms, ou));
764        } catch (CmsException e) {
765            LOG.error("Unable to read ou: " + ou);
766        }
767        openSubView(stateBean.getState(), true);
768
769    }
770
771    /**
772     * Creates a table for displaying groups.<p>
773     *
774     * @param path the path
775     * @param cmsAccountsApp the app instance
776     * @param type the tree type
777     * @param toggle the value of the 'sub-OU' toggle
778     *
779     * @return the table
780     */
781    protected I_CmsFilterableTable createGroupTable(
782        String path,
783        CmsAccountsApp cmsAccountsApp,
784        I_CmsOuTreeType type,
785        boolean toggle) {
786
787        return new CmsGroupTable(path, cmsAccountsApp, type, toggle);
788    }
789
790    /**
791     * Creates the overview table for the given OU.<p>
792     *
793     * @param ou the OU path
794     * @return the overview table for the given OU
795     */
796    protected I_CmsFilterableTable createOUTable(String ou) {
797
798        return new CmsOUTable(ou, this);
799    }
800
801    /**
802     * Creates the role table for  the given OU.<p>
803     *
804     * @param ou the OU path
805     * @return the role table for the given OU
806     */
807    protected I_CmsFilterableTable createRoleTable(String ou) {
808
809        return new CmsRoleTable(this, ou);
810    }
811
812    /**
813     * Creates user table for a specific group or role.<p>
814     *
815     * @param ou the OU path
816     * @param groupID the group id
817     * @param type the tree type
818     * @param showAll true if all users should be shown
819     * @param cmsAccountsApp the app instance
820     *
821     * @return the user table
822     */
823    protected I_CmsFilterableTable createUserTable(
824        String ou,
825        CmsUUID groupID,
826        I_CmsOuTreeType type,
827        boolean showAll,
828        CmsAccountsApp cmsAccountsApp) {
829
830        return new CmsUserTable(ou, groupID, type, showAll, cmsAccountsApp);
831    }
832
833    /**
834     * Creates the user table for an OU.<p>
835     *
836     * @param ou the OU path
837     * @param type the tree type
838     * @param cmsAccountsApp the app instance
839     * @param buttonPressed true if toggle button for users is active
840
841     * @return the user table
842     */
843    protected I_CmsFilterableTable createUserTable(
844        String ou,
845        I_CmsOuTreeType type,
846        CmsAccountsApp cmsAccountsApp,
847        boolean buttonPressed) {
848
849        return new CmsUserTable(ou, type, cmsAccountsApp, buttonPressed);
850    }
851
852    /**
853     * Filters table.<p>
854     *"
855     * @param text for filter
856     */
857    protected void filterTable(String text) {
858
859        if (m_table != null) {
860            m_table.filter(text);
861        }
862    }
863
864    /**
865     * Gets the additional buttons to display.<p>
866     *
867     * @return the additional buttons to display
868     */
869    protected List<Button> getAdditionalButtons() {
870
871        return new ArrayList<>();
872    }
873
874    /**
875     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getBreadCrumbForState(java.lang.String)
876     */
877    @Override
878    protected LinkedHashMap<String, String> getBreadCrumbForState(String state) {
879
880        try {
881            CmsStateBean bean = parseState(state, m_baseOU);
882            String[] ouPath = bean.getPath().split("/");
883            LinkedHashMap<String, String> crumbs = new LinkedHashMap<String, String>();
884
885            if ((bean.getPath().equals(m_baseOU))
886                && (CmsOuTreeType.OU.equals(bean.getType()) | (bean.getType() == null))) {
887                crumbs.put(
888                    "",
889                    CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_TOOL_NAME_0)
890                        + " ("
891                        + OpenCms.getOrgUnitManager().readOrganizationalUnit(m_cms, m_baseOU).getDisplayName(
892                            A_CmsUI.get().getLocale())
893                        + ")");
894                return crumbs;
895            }
896            CmsStateBean beanCr = new CmsStateBean(m_baseOU, CmsOuTreeType.OU, null, "");
897            crumbs.put(
898                getAppId() + "/" + beanCr.getState(),
899                CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_TOOL_NAME_0)
900                    + " ("
901                    + OpenCms.getOrgUnitManager().readOrganizationalUnit(m_cms, m_baseOU).getDisplayName(
902                        A_CmsUI.get().getLocale())
903                    + ")");
904            String base = "";
905            String pathOfLastElement = "";
906            for (String oP : ouPath) {
907                if (!oP.isEmpty()) {
908                    if ((oP + base).length() > m_baseOU.length()) {
909                        if (oP.equals(ouPath[ouPath.length - 1])) {
910                            CmsStateBean beanCrumb = new CmsStateBean(base + oP, CmsOuTreeType.OU, null, "");
911                            pathOfLastElement = getAppId() + "/" + beanCrumb.getState();
912                            crumbs.put("", oP);
913                        } else {
914                            CmsStateBean beanCrumb = new CmsStateBean(base + oP, CmsOuTreeType.OU, null, "");
915                            crumbs.put(getAppId() + "/" + beanCrumb.getState(), oP);
916                        }
917                    }
918                    base += oP + "/";
919                }
920            }
921            if (bean.getType() != null) {
922                if (!bean.getType().equals(CmsOuTreeType.OU)) {
923                    if (!pathOfLastElement.isEmpty()) {
924                        crumbs.put(pathOfLastElement, crumbs.get(""));
925                        crumbs.remove("");
926                    }
927                    if (bean.getGroupID() == null) {
928                        crumbs.put("", bean.getType().getName());
929                    } else {
930                        CmsStateBean beanCrumb = new CmsStateBean(bean.getPath(), bean.getType(), null, "");
931                        crumbs.put(getAppId() + "/" + beanCrumb.getState(), beanCrumb.getType().getName());
932                        if (bean.getType().equals(CmsOuTreeType.ROLE)) {
933                            crumbs.put("", CmsRole.valueOfId(bean.getGroupID()).getName(A_CmsUI.get().getLocale()));
934                        } else {
935                            crumbs.put("", m_cms.readGroup(bean.getGroupID()).getSimpleName());
936                        }
937                    }
938                }
939            }
940            return crumbs;
941        } catch (CmsException e) {
942            return null;
943        }
944    }
945
946    /**
947     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getComponentForState(java.lang.String)
948     */
949    @Override
950    protected Component getComponentForState(String state) {
951
952        m_stateBean = parseState(state, m_baseOU);
953
954        if (m_filter == null) {
955            iniButtons();
956        }
957
958        m_doNotChange = true;
959
960        m_filter.setValue(m_stateBean.getPath());
961        if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_stateBean.getTableFilter())) {
962            m_filterTable.setValue(m_stateBean.getTableFilter());
963        } else {
964            m_filterTable.setValue("");
965        }
966
967        m_newButton.setVisible((m_stateBean.getGroupID() == null) & isOUManagable(m_stateBean.getPath()));
968        m_toggleButtonRole.setVisible(m_stateBean.getType().isRole() && (m_stateBean.getGroupID() != null));
969        m_toggleButtonUser.setVisible(m_stateBean.getType().isUser());
970        m_importExport.setVisible(m_stateBean.getType().isOrgUnit());
971
972        m_toggleButtonGroups.setVisible(m_stateBean.getType().isGroup() && (m_stateBean.getGroupID() == null));
973        m_infoButton.setVisible(
974            m_stateBean.getType().isUser()
975                || (m_stateBean.getType().isRole() && (m_stateBean.getGroupID() != null))
976                || (m_stateBean.getType().isGroup() && (m_stateBean.getGroupID() != null)));
977        m_addElementButton.setVisible(
978            (m_stateBean.getType().isGroup() || m_stateBean.getType().isRole()) & (m_stateBean.getGroupID() != null));
979        m_ouTree.openPath(m_stateBean.getPath(), m_stateBean.getType(), m_stateBean.getGroupID());
980
981        m_doNotChange = false;
982        I_CmsFilterableTable table = null;
983        if (m_stateBean.getType().equals(CmsOuTreeType.OU)) {
984            m_table = createOUTable(m_stateBean.getPath());
985            table = m_table;
986        }
987        if (m_stateBean.getType().isUser()) {
988            m_table = createUserTable(
989                m_stateBean.getPath(),
990                m_stateBean.getType(),
991                this,
992                CmsVaadinUtils.isButtonPressed(m_toggleButtonUser));
993            table = m_table;
994        }
995        if (m_stateBean.getType().isGroup()) {
996            if (m_stateBean.getGroupID() == null) {
997                m_table = createGroupTable(
998                    m_stateBean.getPath(),
999                    this,
1000                    m_stateBean.getType(),
1001                    CmsVaadinUtils.isButtonPressed(m_toggleButtonGroups));
1002                table = m_table;
1003            } else {
1004                m_table = createUserTable(
1005                    m_stateBean.getPath(),
1006                    m_stateBean.getGroupID(),
1007                    m_stateBean.getType(),
1008                    false,
1009                    this);
1010                table = m_table;
1011            }
1012        }
1013        if (m_stateBean.getType().isRole()) {
1014            if (m_stateBean.getGroupID() == null) {
1015                m_table = createRoleTable(m_stateBean.getPath());
1016                table = m_table;
1017            } else {
1018                m_table = createUserTable(
1019                    m_stateBean.getPath(),
1020                    m_stateBean.getGroupID(),
1021                    m_stateBean.getType(),
1022                    CmsVaadinUtils.isButtonPressed(m_toggleButtonRole),
1023                    this);
1024                table = m_table;
1025            }
1026        }
1027        if ((table != null) && !CmsStringUtil.isEmptyOrWhitespaceOnly(m_filterTable.getValue())) {
1028            table.filter(m_filterTable.getValue());
1029        }
1030        return table;
1031    }
1032
1033    /**
1034     * Gets the group-, role-, or ou name.<p>
1035     *
1036     * @param stateBean to be read out
1037     * @return Name
1038     */
1039    protected String getElementName(CmsStateBean stateBean) {
1040
1041        if (stateBean.getType().equals(CmsOuTreeType.USER)) {
1042            try {
1043                return OpenCms.getOrgUnitManager().readOrganizationalUnit(m_cms, stateBean.getPath()).getDisplayName(
1044                    A_CmsUI.get().getLocale());
1045            } catch (CmsException e) {
1046                LOG.error("Unable to read OU", e);
1047            }
1048        }
1049        if (stateBean.getType().equals(CmsOuTreeType.ROLE)) {
1050            return CmsRole.valueOfId(stateBean.getGroupID()).getName(A_CmsUI.get().getLocale());
1051        } else {
1052            try {
1053                return m_cms.readGroup(stateBean.getGroupID()).getSimpleName();
1054            } catch (CmsException e) {
1055                LOG.error("Unable to read group", e);
1056            }
1057        }
1058        return "";
1059    }
1060
1061    /**
1062     * Gets the full user List including additionInfos.<p>
1063     *
1064     * @param users user list
1065     * @return List of user
1066     */
1067    protected List<CmsUser> getFullUser(List<CmsUser> users) {
1068
1069        List<CmsUser> res = new ArrayList<CmsUser>();
1070        for (CmsUser user : users) {
1071            try {
1072                res.add(m_cms.readUser(user.getId()));
1073            } catch (CmsException e) {
1074                LOG.error("Unable to read user", e);
1075            }
1076        }
1077        return res;
1078    }
1079
1080    /**
1081     * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getSubNavEntries(java.lang.String)
1082     */
1083    @Override
1084    protected List<NavEntry> getSubNavEntries(String state) {
1085
1086        return null;
1087    }
1088
1089    /**
1090     * Get the current toggle button.<p>
1091     *
1092     * @param stateBean to be read out
1093     * @return Button
1094     */
1095    protected Button getToggleButton(CmsStateBean stateBean) {
1096
1097        if (stateBean.getType().equals(CmsOuTreeType.USER)) {
1098            return m_toggleButtonUser;
1099        }
1100        if (stateBean.getType().equals(CmsOuTreeType.ROLE)) {
1101            return m_toggleButtonRole;
1102        } else {
1103            return m_toggleButtonGroups;
1104        }
1105    }
1106
1107    /**
1108     * Gets the tree type provider.<p>
1109     *
1110     * @return the tree type provider
1111     */
1112    protected I_CmsTreeTypeProvider getTreeTypeProvider() {
1113
1114        return DEFAULT_TREETYPES;
1115    }
1116
1117    /**
1118     * Gets all currently visible user.<p>
1119     *
1120     * @return List of CmsUser
1121     */
1122    protected List<CmsUser> getVisibleUser() {
1123
1124        if (m_table instanceof CmsUserTable) {
1125            return ((CmsUserTable)m_table).getVisibleUser();
1126        }
1127        return null;
1128    }
1129
1130    /**
1131     * Called when new table is shown.<p>
1132     *
1133     * @param component the table that is displayed
1134     */
1135    protected void handleSetTable(Component component) {
1136
1137        // do nothing
1138    }
1139
1140
1141    /**
1142     * Opens a dialog for a new item (ou, group or user).<p>
1143     */
1144    protected void openNewDialog() {
1145
1146        final Window window = CmsBasicDialog.prepareWindow(DialogWidth.wide);
1147        CmsBasicDialog dialog = new CmsNewElementDialog(m_cms, m_stateBean.getPath(), window, this);
1148        window.setContent(dialog);
1149        window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_ADD_ELEMENT_0));
1150        A_CmsUI.get().addWindow(window);
1151    }
1152    /**
1153     * opens a principle select dialog.<p>
1154     */
1155    void openAddUserDialog() {
1156
1157        CmsPrincipalSelectDialog dialog;
1158
1159        final Window window = CmsBasicDialog.prepareWindow(DialogWidth.max);
1160
1161        dialog = new CmsPrincipalSelectDialog(
1162            this,
1163            m_stateBean.getPath(),
1164            window,
1165            WidgetType.userwidget,
1166            true,
1167            CmsPrincipalSelect.PrincipalType.user);
1168
1169        try {
1170            dialog.setOuComboBoxEnabled(
1171                !OpenCms.getOrgUnitManager().readOrganizationalUnit(m_cms, m_stateBean.getPath()).hasFlagWebuser()
1172                    | m_stateBean.getType().equals(CmsOuTreeType.ROLE));
1173        } catch (CmsException e) {
1174            LOG.error("Can not read OU.", e);
1175        }
1176        window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_ADD_USER_TO_GROUP_0));
1177        window.setContent(dialog);
1178        A_CmsUI.get().addWindow(window);
1179
1180    }
1181
1182    /**
1183     * Toggles the table.<p>
1184     *
1185     * @param toggleButton the toggle button state
1186     */
1187    void toggleTable(Button toggleButton) {
1188
1189        I_CmsToggleTable table = (I_CmsToggleTable)m_table;
1190        table.toggle(!CmsVaadinUtils.isButtonPressed(toggleButton));
1191        CmsVaadinUtils.toggleButton(toggleButton);
1192        if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_filterTable.getValue())) {
1193            filterTable(m_filterTable.getValue());
1194        }
1195        updateInfoButton();
1196    }
1197
1198    /**
1199     * Initializes the toolbar buttons.<p>
1200     */
1201    private void iniButtons() {
1202
1203        m_newButton = CmsToolBar.createButton(
1204            FontOpenCms.WAND,
1205            CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_ADD_ELEMENT_0));
1206        m_newButton.addClickListener(new ClickListener() {
1207
1208            private static final long serialVersionUID = 1L;
1209
1210            public void buttonClick(ClickEvent event) {
1211
1212                openNewDialog();
1213            }
1214        });
1215        m_infoButton = new CmsInfoButton();
1216        Button csvButton = new Button(CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_EXPORT_ONLY_USER_0));
1217        csvButton.addClickListener(new ClickListener() {
1218
1219            private static final long serialVersionUID = 5472430305539438757L;
1220
1221            public void buttonClick(ClickEvent event) {
1222
1223                boolean includeTechnicalFields = false;
1224                try {
1225                    OpenCms.getRoleManager().checkRole(m_cms, CmsRole.ADMINISTRATOR);
1226                    includeTechnicalFields = true;
1227                } catch (CmsRoleViolationException e) {
1228                    // ok
1229                }
1230                Window window = CmsBasicDialog.prepareWindow(DialogWidth.wide);
1231                CmsUserCsvExportDialog dialog = new CmsUserCsvExportDialog(
1232                    getFullUser(getVisibleUser()),
1233                    m_stateBean.getPath(),
1234                    m_stateBean.getType(),
1235                    getElementName(m_stateBean),
1236                    CmsVaadinUtils.isButtonPressed(getToggleButton(m_stateBean)),
1237                    window,
1238                    includeTechnicalFields);
1239                window.setContent(dialog);
1240                A_CmsUI.get().addWindow(window);
1241
1242            }
1243
1244        });
1245
1246        m_infoButton.setAdditionalButton(csvButton);
1247
1248        m_addElementButton = CmsToolBar.createButton(
1249            FontAwesome.PLUS,
1250            CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_ADD_USER_TO_GROUP_0));
1251        m_addElementButton.addClickListener(new ClickListener() {
1252
1253            private static final long serialVersionUID = 1859694635385726953L;
1254
1255            public void buttonClick(ClickEvent event) {
1256
1257                openAddUserDialog();
1258
1259            }
1260        });
1261
1262        m_importExport = CmsToolBar.createButton(FontOpenCms.DOWNLOAD, CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_USER_IMEXPORT_CONTEXTMENUNAME_0));
1263        m_importExport.addClickListener(event -> {
1264            CmsOUTable.openImportExportDialog(A_CmsUI.getCmsObject(), m_stateBean.getPath());
1265        });
1266
1267
1268        m_toggleButtonRole = CmsToolBar.createButton(
1269            FontOpenCms.USERS,
1270            CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_ROLES_TOGGLE_0));
1271        m_toggleButtonRole.addClickListener(new ClickListener() {
1272
1273            private static final long serialVersionUID = 8265075332953321274L;
1274
1275            public void buttonClick(ClickEvent event) {
1276
1277                toggleTable(m_toggleButtonRole);
1278
1279            }
1280
1281        });
1282
1283        m_toggleButtonUser = CmsToolBar.createButton(
1284            FontOpenCms.USERS,
1285            CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_USER_TOGGLE_0));
1286        m_toggleButtonUser.addClickListener(new ClickListener() {
1287
1288            private static final long serialVersionUID = 8265075332953321274L;
1289
1290            public void buttonClick(ClickEvent event) {
1291
1292                toggleTable(m_toggleButtonUser);
1293
1294            }
1295
1296        });
1297
1298        m_toggleButtonGroups = CmsToolBar.createButton(
1299            FontOpenCms.USERS,
1300            CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_GROUPS_TOGGLE_0));
1301        m_toggleButtonGroups.addClickListener(new ClickListener() {
1302
1303            private static final long serialVersionUID = 8265075332953321274L;
1304
1305            public void buttonClick(ClickEvent event) {
1306
1307                toggleTable(m_toggleButtonGroups);
1308
1309            }
1310
1311        });
1312
1313        m_uiContext.addToolbarButton(m_newButton);
1314
1315        m_uiContext.addToolbarButton(m_addElementButton);
1316        m_uiContext.addToolbarButton(m_infoButton);
1317        m_uiContext.addToolbarButton(m_toggleButtonRole);
1318        m_uiContext.addToolbarButton(m_toggleButtonUser);
1319        m_uiContext.addToolbarButton(m_toggleButtonGroups);
1320        m_uiContext.addToolbarButton(m_importExport);
1321
1322        for (Button button : getAdditionalButtons()) {
1323            m_uiContext.addToolbarButton(button);
1324        }
1325        m_filter = CmsVaadinUtils.getOUComboBox(m_cms, m_baseOU, LOG);
1326        m_filter.setWidth("379px");
1327        m_infoLayout.addComponent(m_filter, 0);
1328
1329        m_filterTable = new TextField();
1330        m_filterTable.setIcon(FontOpenCms.FILTER);
1331        m_filterTable.setInputPrompt(
1332            Messages.get().getBundle(UI.getCurrent().getLocale()).key(Messages.GUI_EXPLORER_FILTER_0));
1333        m_filterTable.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
1334        //            m_filterTable.setWidth("200px");
1335        m_filterTable.addTextChangeListener(new TextChangeListener() {
1336
1337            private static final long serialVersionUID = 1L;
1338
1339            public void textChange(TextChangeEvent event) {
1340
1341                filterTable(event.getText());
1342            }
1343        });
1344        m_filterTable.setWidth("200px");
1345        m_infoLayout.addComponent(m_filterTable);
1346        m_infoLayout.addStyleName("o-many-elements");
1347        m_filter.addValueChangeListener(new ValueChangeListener() {
1348
1349            private static final long serialVersionUID = 1L;
1350
1351            public void valueChange(ValueChangeEvent event) {
1352
1353                if ((m_stateBean.getType() != null) & !m_doNotChange) {
1354                    update((String)event.getProperty().getValue(), CmsOuTreeType.OU, null);
1355                } else {
1356                    //
1357                }
1358            }
1359        });
1360        if (!m_ouHandler.isOUManagable(m_stateBean.getPath())) {
1361            boolean change = m_doNotChange;
1362            m_doNotChange = false;
1363            m_filter.select(m_filter.getItemIds().iterator().next());
1364            m_doNotChange = change;
1365        }
1366    }
1367
1368    /**
1369     * Updates the info button.<p>
1370     */
1371    private void updateInfoButton() {
1372
1373        if (m_stateBean.getType().isUser()) {
1374            Map<String, String> dataMap = new LinkedHashMap<String, String>();
1375            dataMap.put(
1376                CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_COUNT_0),
1377                String.valueOf(((Table)m_table).size()));
1378            try {
1379                int count = getUsersWithoutAdditionalInfo(
1380                    m_cms,
1381                    m_stateBean.getType(),
1382                    m_stateBean.getPath(),
1383                    true).size();
1384                if (count > ((Table)m_table).size()) {
1385                    dataMap.put(
1386                        CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_TOT_COUNT_0),
1387                        String.valueOf(count));
1388                }
1389            } catch (CmsException e) {
1390                //;
1391            }
1392            m_infoButton.replaceData(dataMap);
1393        } else {
1394            int size = ((Table)m_table).size();
1395            if (m_table instanceof CmsUserTable) {
1396                size = ((CmsUserTable)m_table).getVisibleUser().size();
1397            }
1398            m_infoButton.replaceData(
1399                Collections.singletonMap(
1400                    CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_COUNT_0),
1401                    String.valueOf(size)));
1402        }
1403    }
1404
1405}