001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://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 org.apache.commons.logging.Log; 053 054import jakarta.servlet.ServletException; 055import jakarta.servlet.http.HttpServletRequest; 056import jakarta.servlet.http.HttpServletResponse; 057import jakarta.servlet.jsp.JspException; 058import jakarta.servlet.jsp.PageContext; 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);'> "); 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);'> "); 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, jakarta.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( 338 Boolean.toString( 339 getSettings().getUserSettings().getDialogDeleteFileMode() == CmsResource.DELETE_REMOVE_SIBLINGS)); 340 } 341 // check the required permissions to delete the resource 342 if (!checkResourcePermissions(CmsPermissionSet.ACCESS_WRITE, false)) { 343 // no write permissions for the resource, set cancel action to close dialog 344 setParamAction(DIALOG_CANCEL); 345 } 346 347 // set the dialog type 348 setParamDialogtype(DIALOG_TYPE); 349 // set the action for the JSP switch 350 if (DIALOG_TYPE.equals(getParamAction())) { 351 setAction(ACTION_DELETE); 352 } else if (DIALOG_LOCKS_CONFIRMED.equals(getParamAction())) { 353 setAction(ACTION_LOCKS_CONFIRMED); 354 } else if (DIALOG_WAIT.equals(getParamAction())) { 355 setAction(ACTION_WAIT); 356 } else if (DIALOG_CANCEL.equals(getParamAction())) { 357 setAction(ACTION_CANCEL); 358 } else { 359 setAction(ACTION_DEFAULT); 360 // build title for delete dialog 361 setDialogTitle(Messages.GUI_DELETE_RESOURCE_1, Messages.GUI_DELETE_MULTI_2); 362 } 363 } 364 365 /** 366 * Performs the resource deletion.<p> 367 * 368 * @return true, if the resource(s) was/were deleted, otherwise false 369 * @throws CmsException if deletion is not successful 370 */ 371 @Override 372 protected boolean performDialogOperation() throws CmsException { 373 374 // check if the current resource is a folder for single operation 375 boolean isFolder = isOperationOnFolder(); 376 // on folder deletion or multi operation display "please wait" screen, not for simple file deletion 377 if ((isMultiOperation() || isFolder) && !DIALOG_WAIT.equals(getParamAction())) { 378 // return false, this will trigger the "please wait" screen 379 return false; 380 } 381 382 // determine the correct delete option 383 CmsResourceDeleteMode deleteOption = Boolean.valueOf(getParamDeleteSiblings()).booleanValue() 384 ? CmsResource.DELETE_REMOVE_SIBLINGS 385 : CmsResource.DELETE_PRESERVE_SIBLINGS; 386 387 Iterator<String> i = getResourceList().iterator(); 388 // iterate the resources to delete 389 while (i.hasNext()) { 390 String resName = i.next(); 391 try { 392 performSingleDeleteOperation(resName, deleteOption); 393 } catch (CmsException e) { 394 if (isMultiOperation()) { 395 // collect exceptions to create a detailed output 396 addMultiOperationException(e); 397 } else { 398 // for single operation, throw the exception immediately 399 throw e; 400 } 401 } 402 } 403 // check if exceptions occurred 404 checkMultiOperationException(Messages.get(), Messages.ERR_DELETE_MULTI_0); 405 406 return true; 407 } 408 409 /** 410 * Performs the delete operation for a single VFS resource.<p> 411 * 412 * @param resource the resource VFS path 413 * @param deleteOption the delete option for sibling deletion 414 * @throws CmsException if deleting the resource fails 415 */ 416 protected void performSingleDeleteOperation(String resource, CmsResourceDeleteMode deleteOption) 417 throws CmsException { 418 419 // lock resource if autolock is enabled 420 checkLock(resource); 421 // delete the resource 422 getCms().deleteResource(resource, deleteOption); 423 } 424 425}