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.file.CmsFile; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsResource; 033import org.opencms.file.CmsResourceFilter; 034import org.opencms.jsp.CmsJspActionElement; 035import org.opencms.main.CmsException; 036import org.opencms.security.CmsPermissionSet; 037import org.opencms.util.CmsStringUtil; 038import org.opencms.widgets.CmsCalendarWidget; 039import org.opencms.workplace.CmsMultiDialog; 040import org.opencms.workplace.CmsWorkplaceSettings; 041 042import java.text.ParseException; 043import java.util.Iterator; 044 045import jakarta.servlet.http.HttpServletRequest; 046import jakarta.servlet.http.HttpServletResponse; 047import jakarta.servlet.jsp.JspException; 048import jakarta.servlet.jsp.PageContext; 049 050/** 051 * Provides methods for the touch resource(s) dialog.<p> 052 * 053 * The following files use this class: 054 * <ul> 055 * <li>/commons/touch.jsp 056 * </ul> 057 * <p> 058 * 059 * @since 6.0.0 060 */ 061public class CmsTouch extends CmsMultiDialog { 062 063 /** Value for the action: touch. */ 064 public static final int ACTION_TOUCH = 100; 065 066 /** Default value for date last modified, the release and expire date. */ 067 public static final String DEFAULT_DATE_STRING = "-"; 068 069 /** The dialog type. */ 070 public static final String DIALOG_TYPE = "touch"; 071 072 /** Request parameter name for the content flag. */ 073 public static final String PARAM_CONTENT = "content"; 074 075 /** Request parameter name for timestamp. */ 076 public static final String PARAM_NEWTIMESTAMP = "newtimestamp"; 077 078 /** Request parameter name for the recursive flag. */ 079 public static final String PARAM_RECURSIVE = "recursive"; 080 081 /** Content parameter. */ 082 private String m_paramContent; 083 084 /** Timestamp parameter. */ 085 private String m_paramNewtimestamp; 086 087 /** Recursive parameter. */ 088 private String m_paramRecursive; 089 090 /** 091 * Public constructor.<p> 092 * 093 * @param jsp an initialized JSP action element 094 */ 095 public CmsTouch(CmsJspActionElement jsp) { 096 097 super(jsp); 098 } 099 100 /** 101 * Public constructor with JSP variables.<p> 102 * 103 * @param context the JSP page context 104 * @param req the JSP request 105 * @param res the JSP response 106 */ 107 public CmsTouch(PageContext context, HttpServletRequest req, HttpServletResponse res) { 108 109 this(new CmsJspActionElement(context, req, res)); 110 } 111 112 /** 113 * Performs a touch operation for a single resource.<p> 114 * 115 * @param resourceName the resource name of the resource to touch 116 * @param timeStamp the new time stamp 117 * @param recursive the flag if the touch operation is recursive 118 * @param correctDate the flag if the new time stamp is a correct date 119 * @param touchContent if the content has to be rewritten 120 * 121 * @throws CmsException if touching the resource fails 122 */ 123 public static void touchSingleResource( 124 CmsObject cms, 125 String resourceName, 126 long timeStamp, 127 boolean recursive, 128 boolean correctDate, 129 boolean touchContent) 130 throws CmsException { 131 132 CmsResource sourceRes = cms.readResource(resourceName, CmsResourceFilter.ALL); 133 if (!correctDate) { 134 // no date value entered, use current resource modification date 135 timeStamp = sourceRes.getDateLastModified(); 136 } 137 cms.setDateLastModified(resourceName, timeStamp, recursive); 138 139 if (touchContent) { 140 if (sourceRes.isFile()) { 141 hardTouch(cms, sourceRes); 142 } else if (recursive) { 143 Iterator<CmsResource> it = cms.readResources(resourceName, CmsResourceFilter.ALL, true).iterator(); 144 while (it.hasNext()) { 145 CmsResource subRes = it.next(); 146 if (subRes.isFile()) { 147 hardTouch(cms, subRes); 148 } 149 } 150 } 151 } 152 } 153 154 /** 155 * Rewrites the content of the given file.<p> 156 * 157 * @param resource the resource to rewrite the content for 158 * 159 * @throws CmsException if something goes wrong 160 */ 161 private static void hardTouch(CmsObject cms, CmsResource resource) throws CmsException { 162 163 CmsFile file = cms.readFile(resource); 164 file.setContents(file.getContents()); 165 cms.writeFile(file); 166 } 167 168 /** 169 * Performs the resource touching, will be called by the JSP page.<p> 170 * 171 * @throws JspException if problems including sub-elements occur 172 */ 173 public void actionTouch() throws JspException { 174 175 // save initialized instance of this class in request attribute for included sub-elements 176 getJsp().getRequest().setAttribute(SESSION_WORKPLACE_CLASS, this); 177 try { 178 if (performDialogOperation()) { 179 // if no exception is caused and "true" is returned the touch operation was successful 180 actionCloseDialog(); 181 } else { 182 // "false" returned, display "please wait" screen 183 getJsp().include(FILE_DIALOG_SCREEN_WAIT); 184 } 185 } catch (Throwable e) { 186 includeErrorpage(this, e); 187 } 188 } 189 190 /** 191 * Creates the "rewrite content" checkbox.<p> 192 * 193 * @return the String with the checkbox input field 194 */ 195 public String buildCheckContent() { 196 197 StringBuffer retValue = new StringBuffer(256); 198 199 retValue.append("<tr>\n\t<td colspan=\"3\" style=\"white-space: nowrap;\" unselectable=\"on\">"); 200 retValue.append("<input type=\"checkbox\" name=\""); 201 retValue.append(PARAM_CONTENT); 202 retValue.append("\" value=\"true\"> "); 203 retValue.append(key(Messages.GUI_TOUCH_MODIFY_CONTENT_0)); 204 retValue.append("</td>\n</tr>\n"); 205 return retValue.toString(); 206 } 207 208 /** 209 * Creates the "recursive" checkbox for touching subresources of folders.<p> 210 * 211 * @return the String with the checkbox input field or an empty String for folders. 212 */ 213 public String buildCheckRecursive() { 214 215 StringBuffer retValue = new StringBuffer(256); 216 217 // show the checkbox only for folders 218 if (isOperationOnFolder()) { 219 retValue.append("<tr>\n\t<td colspan=\"3\" style=\"white-space: nowrap;\" unselectable=\"on\">"); 220 retValue.append("<input type=\"checkbox\" name=\""); 221 retValue.append(PARAM_RECURSIVE); 222 retValue.append("\" value=\"true\"> "); 223 retValue.append(key(Messages.GUI_TOUCH_MODIFY_SUBRESOURCES_0)); 224 retValue.append("</td>\n</tr>\n"); 225 } 226 return retValue.toString(); 227 } 228 229 /** 230 * Creates the HTML JavaScript and stylesheet includes required by the calendar for the head of the page.<p> 231 * 232 * @return the necessary HTML code for the js and stylesheet includes 233 * 234 * @deprecated use {@link CmsCalendarWidget#calendarIncludes(java.util.Locale)}, this is just here so that old JSP still work 235 */ 236 @Deprecated 237 public String calendarIncludes() { 238 239 return CmsCalendarWidget.calendarIncludes(getLocale()); 240 } 241 242 /** 243 * Generates the HTML to initialize the JavaScript calendar element on the end of a page.<p> 244 * 245 * @param inputFieldId the ID of the input field where the date is pasted to 246 * @param triggerButtonId the ID of the button which triggers the calendar 247 * @param align initial position of the calendar popup element 248 * @param singleClick if true, a single click selects a date and closes the calendar, otherwise calendar is closed by doubleclick 249 * @param weekNumbers show the week numbers in the calendar or not 250 * @param mondayFirst show monday as first day of week 251 * @param dateStatusFunc name of the function which determines if/how a date should be disabled 252 * @param showTime true if the time selector should be shown, otherwise false 253 * @return the HTML code to initialize a calendar poup element 254 * 255 * @deprecated use {@link CmsCalendarWidget#calendarInit(org.opencms.i18n.CmsMessages, String, String, String, boolean, boolean, boolean, String, boolean)}, this is just here so that old JSP still work 256 */ 257 @Deprecated 258 public String calendarInit( 259 String inputFieldId, 260 String triggerButtonId, 261 String align, 262 boolean singleClick, 263 boolean weekNumbers, 264 boolean mondayFirst, 265 String dateStatusFunc, 266 boolean showTime) { 267 268 return CmsCalendarWidget.calendarInit( 269 getMessages(), 270 inputFieldId, 271 triggerButtonId, 272 align, 273 singleClick, 274 weekNumbers, 275 mondayFirst, 276 dateStatusFunc, 277 showTime); 278 } 279 280 /** 281 * Returns the current date and time as String formatted in localized pattern.<p> 282 * 283 * @return the current date and time as String formatted in localized pattern 284 */ 285 public String getCurrentDateTime() { 286 287 // get the current date & time 288 return CmsCalendarWidget.getCalendarLocalizedTime(getLocale(), getMessages(), System.currentTimeMillis()); 289 } 290 291 /** 292 * Returns the value of the content parameter, 293 * or null if this parameter was not provided.<p> 294 * 295 * The content parameter on files decides if also the content is rewritten.<p> 296 * 297 * @return the value of the content parameter 298 */ 299 public String getParamContent() { 300 301 return m_paramContent; 302 } 303 304 /** 305 * Returns the value of the new timestamp parameter, 306 * or null if this parameter was not provided.<p> 307 * 308 * The timestamp parameter stores the new timestamp as String.<p> 309 * 310 * @return the value of the new timestamp parameter 311 */ 312 public String getParamNewtimestamp() { 313 314 return m_paramNewtimestamp; 315 } 316 317 /** 318 * Returns the value of the recursive parameter, 319 * or null if this parameter was not provided.<p> 320 * 321 * The recursive parameter on folders decides if all subresources 322 * of the folder should be touched, too.<p> 323 * 324 * @return the value of the recursive parameter 325 */ 326 public String getParamRecursive() { 327 328 return m_paramRecursive; 329 } 330 331 /** 332 * Sets the value of the content parameter.<p> 333 * 334 * @param value the value to set 335 */ 336 public void setParamContent(String value) { 337 338 m_paramContent = value; 339 } 340 341 /** 342 * Sets the value of the new timestamp parameter.<p> 343 * 344 * @param value the value to set 345 */ 346 public void setParamNewtimestamp(String value) { 347 348 m_paramNewtimestamp = value; 349 } 350 351 /** 352 * Sets the value of the recursive parameter.<p> 353 * 354 * @param value the value to set 355 */ 356 public void setParamRecursive(String value) { 357 358 m_paramRecursive = value; 359 } 360 361 /** 362 * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, jakarta.servlet.http.HttpServletRequest) 363 */ 364 @Override 365 protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) { 366 367 // fill the parameter values in the get/set methods 368 fillParamValues(request); 369 370 // check the required permissions to touch the resource 371 if (!checkResourcePermissions(CmsPermissionSet.ACCESS_WRITE, false)) { 372 // no write permissions for the resource, set cancel action to close dialog 373 setParamAction(DIALOG_CANCEL); 374 } 375 376 // set the dialog type 377 setParamDialogtype(DIALOG_TYPE); 378 379 // set the action for the JSP switch 380 if (DIALOG_TYPE.equals(getParamAction())) { 381 setAction(ACTION_TOUCH); 382 } else if (DIALOG_WAIT.equals(getParamAction())) { 383 setAction(ACTION_WAIT); 384 } else if (DIALOG_CANCEL.equals(getParamAction())) { 385 setAction(ACTION_CANCEL); 386 } else if (DIALOG_LOCKS_CONFIRMED.equals(getParamAction())) { 387 setAction(ACTION_LOCKS_CONFIRMED); 388 } else { 389 setAction(ACTION_DEFAULT); 390 // build title for touch dialog 391 setDialogTitle(Messages.GUI_TOUCH_RESOURCE_1, Messages.GUI_TOUCH_MULTI_2); 392 } 393 } 394 395 /** 396 * Performs the resource touching.<p> 397 * 398 * @return true, if the resource was touched, otherwise false 399 * @throws CmsException if touching is not successful 400 */ 401 @Override 402 protected boolean performDialogOperation() throws CmsException { 403 404 // on folder touch or multi resource operation display "please wait" screen, not for simple file copy 405 if (!DIALOG_WAIT.equals(getParamAction())) { 406 // check if the "please wait" screen has to be shown 407 if (isMultiOperation()) { 408 // show please wait for every multi resource operation 409 return false; 410 } else { 411 // check if the single resource is a folder 412 CmsResource sourceRes = getCms().readResource(getParamResource(), CmsResourceFilter.ALL); 413 if (sourceRes.isFolder()) { 414 return false; 415 } 416 } 417 } 418 419 // get the new timestamp for the resource(s) from request parameter 420 long timeStamp = 0; 421 boolean correctDate = false; 422 try { 423 if (CmsStringUtil.isNotEmpty(getParamNewtimestamp())) { 424 timeStamp = CmsCalendarWidget.getCalendarDate(getMessages(), getParamNewtimestamp(), true); 425 correctDate = true; 426 } 427 } catch (ParseException e) { 428 throw new CmsException(Messages.get().container(Messages.ERR_PARSE_TIMESTAMP_1, getParamNewtimestamp()), e); 429 } 430 431 // get the flag if the touch is recursive from request parameter 432 boolean touchRecursive = Boolean.valueOf(getParamRecursive()).booleanValue(); 433 // get the flag to the touch the content from request parameter 434 boolean touchContent = Boolean.valueOf(getParamContent()).booleanValue(); 435 436 // now touch the resource(s) 437 Iterator<String> i = getResourceList().iterator(); 438 while (i.hasNext()) { 439 String resName = i.next(); 440 try { 441 // lock resource if autolock is enabled 442 checkLock(resName); 443 touchSingleResource(getCms(), resName, timeStamp, touchRecursive, correctDate, touchContent); 444 } catch (CmsException e) { 445 // collect exceptions to create a detailed output 446 addMultiOperationException(e); 447 } 448 } 449 checkMultiOperationException(Messages.get(), Messages.ERR_TOUCH_MULTI_0); 450 451 return true; 452 } 453}