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