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.CmsObject;
031import org.opencms.file.CmsResource;
032import org.opencms.main.CmsException;
033import org.opencms.main.CmsIllegalArgumentException;
034import org.opencms.main.CmsLog;
035import org.opencms.main.OpenCms;
036import org.opencms.security.CmsDefaultValidationHandler;
037import org.opencms.security.CmsOrganizationalUnit;
038import org.opencms.ui.A_CmsUI;
039import org.opencms.ui.CmsVaadinUtils;
040import org.opencms.ui.apps.Messages;
041import org.opencms.ui.components.CmsBasicDialog;
042import org.opencms.ui.components.editablegroup.CmsEditableGroup;
043import org.opencms.ui.components.editablegroup.I_CmsEditableGroupRow;
044import org.opencms.ui.components.fileselect.CmsPathSelectField;
045import org.opencms.util.CmsFileUtil;
046
047import java.util.ArrayList;
048import java.util.Collections;
049import java.util.Iterator;
050import java.util.List;
051
052import org.apache.commons.logging.Log;
053
054import com.google.common.base.Supplier;
055import com.vaadin.ui.Button;
056import com.vaadin.ui.Button.ClickEvent;
057import com.vaadin.ui.Button.ClickListener;
058import com.vaadin.ui.Component;
059import com.vaadin.ui.FormLayout;
060import com.vaadin.ui.Window;
061import com.vaadin.v7.data.Property.ValueChangeEvent;
062import com.vaadin.v7.data.Property.ValueChangeListener;
063import com.vaadin.v7.data.Validator;
064import com.vaadin.v7.ui.AbstractField;
065import com.vaadin.v7.ui.CheckBox;
066import com.vaadin.v7.ui.Label;
067import com.vaadin.v7.ui.TextArea;
068import com.vaadin.v7.ui.TextField;
069
070/**
071 * Class for the ou edit and new dialog.<p>
072 */
073public class CmsOUEditDialog extends CmsBasicDialog {
074
075    /**
076     * Validator for ou name.<p>
077     */
078    protected class NameValidator implements Validator {
079
080        /**vaadin serial id. */
081        private static final long serialVersionUID = 6830449175508751039L;
082
083        /**
084         * @see com.vaadin.data.Validator#validate(java.lang.Object)
085         */
086        public void validate(Object value) throws InvalidValueException {
087
088            try {
089                CmsDefaultValidationHandler handler = new CmsDefaultValidationHandler();
090                handler.checkUserName((String)value);
091            } catch (CmsIllegalArgumentException e) {
092                throw new InvalidValueException(
093                    CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_USER_VALIDATION_LOGINNAME_INVALID_0));
094            }
095
096        }
097
098    }
099
100    /**
101     * Validator for resource names.<p>
102     */
103    protected class ResourceValidator implements Validator {
104
105        /**vaadin serial id. */
106        private static final long serialVersionUID = -2325058988240648143L;
107
108        /**
109         * @see com.vaadin.data.Validator#validate(java.lang.Object)
110         */
111        public void validate(Object value) throws InvalidValueException {
112
113            if (isInvalidResourceName((String)value)) {
114                throw new InvalidValueException(
115                    CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_OU_RESOURCE_NOT_VALID_0));
116            }
117
118            if (isOutOfOu((String)value)) {
119                throw new InvalidValueException(
120                    CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_OU_RESOURCE_OUT_OF_OU_0));
121            }
122
123        }
124    }
125
126    /**vaadim serial id. */
127    private static final long serialVersionUID = -1462196157732607548L;
128
129    /** The logger for this class. */
130    static Log LOG = CmsLog.getLog(CmsOUEditDialog.class.getName());
131
132    /**CmsObject. */
133    protected CmsObject m_cms;
134
135    /**OU to be edited, null if new one should be created. */
136    private CmsOrganizationalUnit m_ou;
137
138    /**vaadin component.*/
139    Button m_ok;
140
141    /**vaadin component.*/
142    private TextField m_name;
143
144    /**vaadin component.*/
145    private Button m_cancel;
146
147    /**vaadin component.*/
148    private TextArea m_description;
149
150    /**vaadin component.*/
151    Label m_parentOu;
152
153    /**vaadin component.*/
154    private CheckBox m_hideLogin;
155
156    /**vaadin component.*/
157    private CheckBox m_webuser;
158
159    /**vaadin component.*/
160    private FormLayout m_resLayout;
161
162    /** The group for the module resource fields. */
163    private CmsEditableGroup m_ouResources;
164
165    /**
166     * public constructor.<p>
167     *
168     * @param cms CmsObject
169     * @param ou id of group edit, null if ou should be created
170     * @param window window holding the dialog
171     * @param app
172     */
173    public CmsOUEditDialog(CmsObject cms, String ou, final Window window, final CmsAccountsApp app) {
174
175        CmsVaadinUtils.readAndLocalizeDesign(this, CmsVaadinUtils.getWpMessagesForCurrentLocale(), null);
176
177        if (ou != null) {
178            try {
179                displayResourceInfoDirectly(
180                    Collections.singletonList(
181                        CmsAccountsApp.getOUInfo(
182                            OpenCms.getOrgUnitManager().readOrganizationalUnit(A_CmsUI.getCmsObject(), ou))));
183            } catch (CmsException e1) {
184                LOG.error("Unable to read OU", e1);
185            }
186        }
187
188        m_cms = cms;
189        Supplier<Component> fieldFactory = new Supplier<Component>() {
190
191            public Component get() {
192
193                CmsPathSelectField field = new CmsPathSelectField();
194                field.setUseRootPaths(true);
195                field.setCmsObject(m_cms);
196                try {
197                    field.setValue(
198                        OpenCms.getOrgUnitManager().getResourcesForOrganizationalUnit(m_cms, m_parentOu.getValue()).get(
199                            0).getRootPath());
200                } catch (CmsException e) {
201                    //
202                }
203                return field;
204            }
205        };
206        m_ouResources = new CmsEditableGroup(
207            m_resLayout,
208            fieldFactory,
209            CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_OU_ADD_RESOURCE_0));
210        m_ouResources.init();
211
212        try {
213            if (ou != null) {
214                m_ou = OpenCms.getOrgUnitManager().readOrganizationalUnit(m_cms, ou);
215                m_name.setEnabled(false);
216                m_name.setValue(m_ou.getName());
217                m_description.setValue(m_ou.getDescription());
218                m_parentOu.setValue(m_ou.getParentFqn().equals("") ? "/" : m_ou.getParentFqn());
219                m_hideLogin.setValue(Boolean.valueOf(m_ou.hasFlagHideLogin()));
220                m_webuser.setValue(Boolean.valueOf(m_ou.hasFlagWebuser()));
221                m_webuser.setEnabled(false);
222                for (CmsResource resource : OpenCms.getOrgUnitManager().getResourcesForOrganizationalUnit(
223                    m_cms,
224                    m_ou.getName())) {
225                    CmsPathSelectField field = new CmsPathSelectField();
226                    field.setValue(resource.getRootPath());
227                    field.setUseRootPaths(true);
228                    field.setCmsObject(m_cms);
229                    m_ouResources.addRow(field);
230                }
231            }
232
233        } catch (CmsException e) {
234            LOG.error("unable to read group", e);
235        }
236        m_ok.setEnabled(m_ou != null);
237        m_ok.addClickListener(new ClickListener() {
238
239            private static final long serialVersionUID = 2337532424806798793L;
240
241            public void buttonClick(ClickEvent event) {
242
243                validate();
244                if (isValid()) {
245                    saveOU();
246                    window.close();
247                    app.reload();
248                }
249            }
250        });
251
252        m_cancel.addClickListener(new ClickListener() {
253
254            private static final long serialVersionUID = -6389260624197980323L;
255
256            public void buttonClick(ClickEvent event) {
257
258                window.close();
259            }
260        });
261
262        ValueChangeListener listener = new ValueChangeListener() {
263
264            private static final long serialVersionUID = -7480617292190495288L;
265
266            public void valueChange(ValueChangeEvent event) {
267
268                m_ok.setEnabled(true);
269            }
270        };
271
272        m_description.addValueChangeListener(listener);
273        m_name.addValueChangeListener(listener);
274    }
275
276    /**
277     * public constructor.<p>
278     *
279     * @param cms CmsObject
280     * @param window window holding dialog
281     * @param ou to create group in
282     */
283    public CmsOUEditDialog(CmsObject cms, Window window, String ou, CmsAccountsApp app) {
284
285        this(cms, null, window, app);
286        m_parentOu.setValue(ou.equals("") ? "/" : ou);
287        try {
288            displayResourceInfoDirectly(
289                Collections.singletonList(
290                    CmsAccountsApp.getOUInfo(
291                        OpenCms.getOrgUnitManager().readOrganizationalUnit(
292                            A_CmsUI.getCmsObject(),
293                            m_parentOu.getValue()))));
294        } catch (CmsException e1) {
295            LOG.error("Unable to read OU", e1);
296        }
297
298        CmsPathSelectField field = new CmsPathSelectField();
299        field.setUseRootPaths(true);
300        field.setCmsObject(m_cms);
301        try {
302            field.setValue(OpenCms.getOrgUnitManager().getResourcesForOrganizationalUnit(cms, ou).get(0).getRootPath());
303        } catch (Throwable e) {
304            // We simply do not set the field's value if something goes wrong.
305        }
306        m_ouResources.addRow(field);
307    }
308
309    /**
310     * Checks if given resource is invalid.<p>
311     *
312     * @param resourceName name of resource
313     * @return true if resourceName is invalid
314     */
315    protected boolean isInvalidResourceName(String resourceName) {
316
317        if (resourceName == null) {
318            return true;
319        }
320        try {
321
322            m_cms.readResource(resourceName);
323            return false;
324        } catch (CmsException e) {
325            //Ok, resource not valid..
326        }
327        return true;
328    }
329
330    /**
331     * Check if resource is in parent OU.<p>
332     *
333     * @param resourceName to check
334     * @return boolean
335     */
336    protected boolean isOutOfOu(String resourceName) {
337
338        if (resourceName == null) {
339            return true;
340        }
341        try {
342            boolean notOk = true;
343            for (CmsResource res : OpenCms.getOrgUnitManager().getResourcesForOrganizationalUnit(
344                m_cms,
345                m_parentOu.getValue())) {
346                if (resourceName.startsWith(res.getRootPath())) {
347                    notOk = false;
348                }
349            }
350            return notOk;
351        } catch (CmsException e) {
352            //
353        }
354        return true;
355    }
356
357    /**
358     * Checks if all fields are valid.<p>
359     *
360     * @return true, if all data are ok.
361     */
362    @SuppressWarnings("unchecked")
363    protected boolean isValid() {
364
365        boolean res = true;
366
367        res = res & m_description.isValid();
368        res = res & m_name.isValid();
369        if (!res) {
370            return res;
371        }
372        for (I_CmsEditableGroupRow row : m_ouResources.getRows()) {
373            if (!((AbstractField<String>)row.getComponent()).isValid()) {
374                return false;
375            }
376        }
377        return true;
378    }
379
380    /**
381     * Adds validators to fields.<p>
382     */
383    @SuppressWarnings("unchecked")
384    protected void validate() {
385
386        if (m_ou == null) {
387            m_name.removeAllValidators();
388            m_name.addValidator(new NameValidator());
389        }
390        m_description.setRequired(true);
391        m_description.setRequiredError("Required");
392
393        if (m_ouResources.getRows().isEmpty() & !m_webuser.getValue().booleanValue()) {
394            CmsPathSelectField field = new CmsPathSelectField();
395            field.setUseRootPaths(true);
396            field.setCmsObject(m_cms);
397            m_ouResources.addRow(field);
398        }
399        for (I_CmsEditableGroupRow row : m_ouResources.getRows()) {
400            ((AbstractField<String>)row.getComponent()).removeAllValidators();
401            ((AbstractField<String>)row.getComponent()).addValidator(new ResourceValidator());
402        }
403    }
404
405    /**
406     * Saves the OU.<p>
407     */
408    void saveOU() {
409
410        try {
411            List<String> resources = new ArrayList<String>();
412            for (I_CmsEditableGroupRow row : m_ouResources.getRows()) {
413                resources.add(((CmsPathSelectField)row.getComponent()).getValue());
414            }
415            if (m_ou == null) {
416                String parentOu = m_parentOu.getValue();
417                if (!parentOu.endsWith("/")) {
418                    parentOu += "/";
419                }
420                if (resources.contains("null")) {
421                    resources.remove("null");
422                }
423                List<String> resourceNames = CmsFileUtil.removeRedundancies(resources);
424                m_ou = OpenCms.getOrgUnitManager().createOrganizationalUnit(
425                    m_cms,
426                    parentOu + m_name.getValue(),
427                    m_description.getValue(),
428                    getFlags(),
429                    resourceNames.isEmpty() ? null : resourceNames.get(0));
430
431                if (!resourceNames.isEmpty()) {
432                    resourceNames.remove(0);
433                    Iterator<String> itResourceNames = CmsFileUtil.removeRedundancies(resourceNames).iterator();
434                    while (itResourceNames.hasNext()) {
435                        OpenCms.getOrgUnitManager().addResourceToOrgUnit(m_cms, m_ou.getName(), itResourceNames.next());
436                    }
437                }
438            } else {
439                m_ou.setDescription(m_description.getValue());
440                m_ou.setFlags(getFlags());
441                List<String> resourceNamesNew = CmsFileUtil.removeRedundancies(resources);
442                List<CmsResource> resourcesOld = OpenCms.getOrgUnitManager().getResourcesForOrganizationalUnit(
443                    m_cms,
444                    m_ou.getName());
445                List<String> resourceNamesOld = new ArrayList<String>();
446                Iterator<CmsResource> itResourcesOld = resourcesOld.iterator();
447                while (itResourcesOld.hasNext()) {
448                    CmsResource resourceOld = itResourcesOld.next();
449                    resourceNamesOld.add(m_cms.getSitePath(resourceOld));
450                }
451                Iterator<String> itResourceNamesNew = resourceNamesNew.iterator();
452                // add new resources to ou
453                while (itResourceNamesNew.hasNext()) {
454                    String resourceNameNew = itResourceNamesNew.next();
455                    if (!resourceNamesOld.contains(resourceNameNew)) {
456                        OpenCms.getOrgUnitManager().addResourceToOrgUnit(m_cms, m_ou.getName(), resourceNameNew);
457                    }
458                }
459                Iterator<String> itResourceNamesOld = resourceNamesOld.iterator();
460                // delete old resources from ou
461                while (itResourceNamesOld.hasNext()) {
462                    String resourceNameOld = itResourceNamesOld.next();
463                    if (!resourceNamesNew.contains(resourceNameOld)) {
464                        OpenCms.getOrgUnitManager().removeResourceFromOrgUnit(m_cms, m_ou.getName(), resourceNameOld);
465                    }
466                }
467                // write the edited organizational unit
468                OpenCms.getOrgUnitManager().writeOrganizationalUnit(m_cms, m_ou);
469            }
470        } catch (CmsException e) {
471            LOG.error("Unable to save OU", e);
472        }
473    }
474
475    /**
476     * Get OU-flags.<p>
477     *
478     * @return the flag int-value
479     */
480    private int getFlags() {
481
482        int flags = 0;
483        if (m_hideLogin.getValue().booleanValue()) {
484            flags += CmsOrganizationalUnit.FLAG_HIDE_LOGIN;
485        }
486        if (m_webuser.getValue().booleanValue()) {
487            flags += CmsOrganizationalUnit.FLAG_WEBUSERS;
488        }
489        return flags;
490    }
491}