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 GmbH & Co. KG, 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.workplace.commons;
029
030import org.opencms.configuration.CmsParameterConfiguration;
031import org.opencms.file.CmsResource;
032import org.opencms.file.CmsResource.CmsResourceDeleteMode;
033import org.opencms.file.CmsResourceFilter;
034import org.opencms.jsp.CmsJspActionElement;
035import org.opencms.main.CmsException;
036import org.opencms.main.CmsLog;
037import org.opencms.main.OpenCms;
038import org.opencms.security.CmsPermissionSet;
039import org.opencms.security.CmsRole;
040import org.opencms.util.CmsStringUtil;
041import org.opencms.workplace.CmsDialogSelector;
042import org.opencms.workplace.CmsMultiDialog;
043import org.opencms.workplace.CmsWorkplaceSettings;
044import org.opencms.workplace.I_CmsDialogHandler;
045import org.opencms.workplace.list.CmsListExplorerColumn;
046
047import java.io.IOException;
048import java.util.ArrayList;
049import java.util.Iterator;
050import java.util.List;
051
052import javax.servlet.ServletException;
053import javax.servlet.http.HttpServletRequest;
054import javax.servlet.http.HttpServletResponse;
055import javax.servlet.jsp.JspException;
056import javax.servlet.jsp.PageContext;
057
058import org.apache.commons.logging.Log;
059
060/**
061 * Provides methods for the delete resources dialog.<p>
062 *
063 * The following files use this class:
064 * <ul>
065 * <li>/commons/delete_standard.jsp
066 * </ul>
067 * <p>
068 *
069 * @since 6.0.0
070 */
071public class CmsDelete extends CmsMultiDialog implements I_CmsDialogHandler {
072
073    /** Value for the action: delete the resource. */
074    public static final int ACTION_DELETE = 100;
075
076    /** The dialog type. */
077    public static final String DIALOG_TYPE = "delete";
078
079    /** The log object for this class. */
080    public static final Log LOG = CmsLog.getLog(CmsDelete.class);
081
082    /** Request parameter name for the deletesiblings parameter. */
083    public static final String PARAM_DELETE_SIBLINGS = "deletesiblings";
084
085    /** The delete dialog URI. */
086    public static final String URI_DELETE_DIALOG = PATH_DIALOGS + "delete_standard.jsp";
087
088    /** The delete siblings parameter value. */
089    private String m_deleteSiblings;
090
091    /**
092     * Default constructor needed for dialog handler implementation.<p>
093     */
094    public CmsDelete() {
095
096        super(null);
097    }
098
099    /**
100     * Public constructor with JSP action element.<p>
101     *
102     * @param jsp an initialized JSP action element
103     */
104    public CmsDelete(CmsJspActionElement jsp) {
105
106        super(jsp);
107    }
108
109    /**
110     * Public constructor with JSP variables.<p>
111     *
112     * @param context the JSP page context
113     * @param req the JSP request
114     * @param res the JSP response
115     */
116    public CmsDelete(PageContext context, HttpServletRequest req, HttpServletResponse res) {
117
118        this(new CmsJspActionElement(context, req, res));
119    }
120
121    /**
122     * Performs the delete action, will be called by the JSP page.<p>
123     *
124     * @throws JspException if problems including sub-elements occur
125     */
126    public void actionDelete() throws JspException {
127
128        // save initialized instance of this class in request attribute for included sub-elements
129        getJsp().getRequest().setAttribute(SESSION_WORKPLACE_CLASS, this);
130        try {
131            boolean isFolder = false;
132            if (!isMultiOperation()) {
133                isFolder = getCms().readResource(getParamResource(), CmsResourceFilter.ALL).isFolder();
134            }
135            if (performDialogOperation()) {
136                // if no exception is caused and "true" is returned delete operation was successful
137                if (isMultiOperation() || isFolder) {
138                    // set request attribute to reload the explorer tree view
139                    List<String> folderList = new ArrayList<String>(1);
140                    folderList.add(CmsResource.getParentFolder(getResourceList().get(0)));
141                    getJsp().getRequest().setAttribute(REQUEST_ATTRIBUTE_RELOADTREE, folderList);
142                }
143                actionCloseDialog();
144            } else {
145                // "false" returned, display "please wait" screen
146                getJsp().include(FILE_DIALOG_SCREEN_WAIT);
147            }
148        } catch (Throwable e) {
149            // prepare common message part
150            includeErrorpage(this, e);
151        }
152    }
153
154    /**
155     * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#addConfigurationParameter(java.lang.String, java.lang.String)
156     */
157    @Override
158    public void addConfigurationParameter(String paramName, String paramValue) {
159
160        // not implemented yet
161
162    }
163
164    /**
165     * Returns the html for the confirmation message.<p>
166     *
167     * @return the html for the confirmation message
168     */
169    public String buildConfirmation() {
170
171        StringBuffer result = new StringBuffer(512);
172        boolean isFolder = false;
173        if (!isMultiOperation()) {
174            try {
175                isFolder = getCms().readResource(getParamResource(), CmsResourceFilter.ALL).isFolder();
176            } catch (CmsException e) {
177                // ignore
178            }
179        }
180        result.append("<div id='conf-msg'>\n");
181        if (isMultiOperation() || isFolder || (hasSiblings() && hasCorrectLockstate())) {
182            result.append(key(Messages.GUI_DELETE_MULTI_CONFIRMATION_0));
183        } else {
184            result.append(key(Messages.GUI_DELETE_CONFIRMATION_0));
185        }
186        result.append("\n</div>\n");
187        return result.toString();
188    }
189
190    /**
191     * Returns the html for the "delete siblings" options when deleting a a resource with siblings.<p>
192     *
193     * @return the html for the "delete siblings" options
194     */
195    public String buildDeleteSiblings() {
196
197        StringBuffer result = new StringBuffer(512);
198        if (isMultiOperation() || (hasSiblings() && hasCorrectLockstate())) {
199            // show only for multi resource operation or if resource has siblings and correct lock state
200            CmsResourceDeleteMode defaultMode = Boolean.valueOf(getParamDeleteSiblings()).booleanValue()
201            ? CmsResource.DELETE_REMOVE_SIBLINGS
202            : CmsResource.DELETE_PRESERVE_SIBLINGS;
203            if (!isMultiOperation()) {
204                result.append(key(Messages.GUI_DELETE_WARNING_SIBLINGS_0));
205                result.append("<p>");
206            }
207            result.append("<input type=\"radio\" name=\"");
208            result.append(PARAM_DELETE_SIBLINGS);
209            result.append("radio\" value=\"false\"");
210            if (defaultMode == CmsResource.DELETE_PRESERVE_SIBLINGS) {
211                result.append(" checked=\"checked\"");
212            }
213            result.append(" onclick='reloadDialog(false);'>&nbsp;");
214            result.append(key(Messages.GUI_DELETE_PRESERVE_SIBLINGS_0));
215            result.append("<br>");
216            result.append("<input type=\"radio\" name=\"");
217            result.append(PARAM_DELETE_SIBLINGS);
218            result.append("radio\" value=\"true\"");
219            if (defaultMode == CmsResource.DELETE_REMOVE_SIBLINGS) {
220                result.append(" checked=\"checked\"");
221            }
222            result.append(" onclick='reloadDialog(true);'>&nbsp;");
223            result.append(key(Messages.GUI_DELETE_ALL_SIBLINGS_0));
224            result.append("<p>");
225        }
226        return result.toString();
227    }
228
229    /**
230     * Returns html code for the possible broken relations.<p>
231     *
232     * @return html code for the possible broken relations
233     *
234     * @throws JspException if dialog actions fail
235     * @throws IOException in case of errros forwarding to the required result page
236     * @throws ServletException in case of errros forwarding to the required result page
237     */
238    public String buildReport() throws JspException, ServletException, IOException {
239
240        CmsDeleteBrokenRelationsList list = new CmsDeleteBrokenRelationsList(
241            getJsp(),
242            getResourceList(),
243            Boolean.valueOf(getParamDeleteSiblings()).booleanValue());
244        list.actionDialog();
245
246        StringBuffer result = new StringBuffer(512);
247        list.getList().setBoxed(false);
248        result.append("<input type='hidden' name='result' value='");
249        result.append(list.getList().getTotalSize()).append("'>\n");
250        result.append(CmsListExplorerColumn.getExplorerStyleDef());
251        result.append("<div style='height:150px; overflow: auto;'>\n");
252        result.append(list.getList().listHtml());
253        result.append("</div>\n");
254        return result.toString();
255    }
256
257    /**
258     * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#getConfiguration()
259     */
260    @Override
261    public CmsParameterConfiguration getConfiguration() {
262
263        return CmsParameterConfiguration.EMPTY_PARAMETERS;
264    }
265
266    /**
267     * @see org.opencms.workplace.I_CmsDialogHandler#getDialogHandler()
268     */
269    @Override
270    public String getDialogHandler() {
271
272        return CmsDialogSelector.DIALOG_DELETE;
273    }
274
275    /**
276     * @see org.opencms.workplace.I_CmsDialogHandler#getDialogUri(java.lang.String, CmsJspActionElement)
277     */
278    @Override
279    public String getDialogUri(String resource, CmsJspActionElement jsp) {
280
281        return URI_DELETE_DIALOG;
282    }
283
284    /**
285     * Returns the value of the boolean option to delete siblings.<p>
286     *
287     * @return the value of the boolean option to delete siblings as a lower case string
288     */
289    public String getParamDeleteSiblings() {
290
291        return m_deleteSiblings;
292    }
293
294    /**
295     * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#initConfiguration()
296     */
297    @Override
298    public void initConfiguration() {
299
300        // not implemented yet
301
302    }
303
304    /**
305     * Returns <code>true</code> if the current user is allowed
306     * to delete the selected resources.<p>
307     *
308     * @return <code>true</code> if the current user is allowed
309     *          to delete the selected resources
310     */
311    public boolean isCanDelete() {
312
313        return OpenCms.getWorkplaceManager().getDefaultUserSettings().isAllowBrokenRelations()
314            || OpenCms.getRoleManager().hasRole(getCms(), CmsRole.VFS_MANAGER);
315    }
316
317    /**
318     * Sets the value of the boolean option to delete siblings.<p>
319     *
320     * @param value the value of the boolean option to delete siblings
321     */
322    public void setParamDeleteSiblings(String value) {
323
324        m_deleteSiblings = value;
325    }
326
327    /**
328     * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest)
329     */
330    @Override
331    protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) {
332
333        // fill the parameter values in the get/set methods
334        fillParamValues(request);
335
336        if (CmsStringUtil.isEmptyOrWhitespaceOnly(getParamDeleteSiblings())) {
337            setParamDeleteSiblings(Boolean.toString(
338                getSettings().getUserSettings().getDialogDeleteFileMode() == CmsResource.DELETE_REMOVE_SIBLINGS));
339        }
340        // check the required permissions to delete the resource
341        if (!checkResourcePermissions(CmsPermissionSet.ACCESS_WRITE, false)) {
342            // no write permissions for the resource, set cancel action to close dialog
343            setParamAction(DIALOG_CANCEL);
344        }
345
346        // set the dialog type
347        setParamDialogtype(DIALOG_TYPE);
348        // set the action for the JSP switch
349        if (DIALOG_TYPE.equals(getParamAction())) {
350            setAction(ACTION_DELETE);
351        } else if (DIALOG_LOCKS_CONFIRMED.equals(getParamAction())) {
352            setAction(ACTION_LOCKS_CONFIRMED);
353        } else if (DIALOG_WAIT.equals(getParamAction())) {
354            setAction(ACTION_WAIT);
355        } else if (DIALOG_CANCEL.equals(getParamAction())) {
356            setAction(ACTION_CANCEL);
357        } else {
358            setAction(ACTION_DEFAULT);
359            // build title for delete dialog
360            setDialogTitle(Messages.GUI_DELETE_RESOURCE_1, Messages.GUI_DELETE_MULTI_2);
361        }
362    }
363
364    /**
365     * Performs the resource deletion.<p>
366     *
367     * @return true, if the resource(s) was/were deleted, otherwise false
368     * @throws CmsException if deletion is not successful
369     */
370    @Override
371    protected boolean performDialogOperation() throws CmsException {
372
373        // check if the current resource is a folder for single operation
374        boolean isFolder = isOperationOnFolder();
375        // on folder deletion or multi operation display "please wait" screen, not for simple file deletion
376        if ((isMultiOperation() || isFolder) && !DIALOG_WAIT.equals(getParamAction())) {
377            // return false, this will trigger the "please wait" screen
378            return false;
379        }
380
381        // determine the correct delete option
382        CmsResourceDeleteMode deleteOption = Boolean.valueOf(getParamDeleteSiblings()).booleanValue()
383        ? CmsResource.DELETE_REMOVE_SIBLINGS
384        : CmsResource.DELETE_PRESERVE_SIBLINGS;
385
386        Iterator<String> i = getResourceList().iterator();
387        // iterate the resources to delete
388        while (i.hasNext()) {
389            String resName = i.next();
390            try {
391                performSingleDeleteOperation(resName, deleteOption);
392            } catch (CmsException e) {
393                if (isMultiOperation()) {
394                    // collect exceptions to create a detailed output
395                    addMultiOperationException(e);
396                } else {
397                    // for single operation, throw the exception immediately
398                    throw e;
399                }
400            }
401        }
402        // check if exceptions occurred
403        checkMultiOperationException(Messages.get(), Messages.ERR_DELETE_MULTI_0);
404
405        return true;
406    }
407
408    /**
409     * Performs the delete operation for a single VFS resource.<p>
410     *
411     * @param resource the resource VFS path
412     * @param deleteOption the delete option for sibling deletion
413     * @throws CmsException if deleting the resource fails
414     */
415    protected void performSingleDeleteOperation(String resource, CmsResourceDeleteMode deleteOption)
416    throws CmsException {
417
418        // lock resource if autolock is enabled
419        checkLock(resource);
420        // delete the resource
421        getCms().deleteResource(resource, deleteOption);
422    }
423
424}