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.contextmenu; 029 030import static org.opencms.ui.contextmenu.CmsMenuItemVisibilityMode.VISIBILITY_ACTIVE; 031import static org.opencms.ui.contextmenu.CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 032import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.controlpermission; 033import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.defaultfile; 034import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.deleted; 035import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.file; 036import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.folder; 037import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.haseditor; 038import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.hassourcecodeeditor; 039import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.inproject; 040import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.mylock; 041import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.noinheritedlock; 042import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.nootherlock; 043import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.notdeleted; 044import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.notinproject; 045import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.notnew; 046import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.notonline; 047import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.notpointer; 048import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.notunchangedfile; 049import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.otherlock; 050import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.pagefolder; 051import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.pointer; 052import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.publishpermission; 053import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.replacable; 054import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.restrictedconfig; 055import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.roleeditor; 056import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.roleelementauthor; 057import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.rolerootadmin; 058import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.rolevfsmanager; 059import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.rolewpuser; 060import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.unlocked; 061import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.writepermisssion; 062import static org.opencms.ui.contextmenu.CmsVisibilityCheckFlag.xmlunmarshal; 063 064import org.opencms.file.CmsObject; 065import org.opencms.file.CmsResource; 066import org.opencms.file.CmsResourceFilter; 067import org.opencms.file.types.CmsResourceTypeImage; 068import org.opencms.file.types.CmsResourceTypePointer; 069import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 070import org.opencms.file.types.CmsResourceTypeXmlContent; 071import org.opencms.file.types.CmsResourceTypeXmlPage; 072import org.opencms.file.types.I_CmsResourceType; 073import org.opencms.loader.CmsDumpLoader; 074import org.opencms.lock.CmsLock; 075import org.opencms.main.CmsException; 076import org.opencms.main.CmsLog; 077import org.opencms.main.OpenCms; 078import org.opencms.security.CmsPermissionSet; 079import org.opencms.security.CmsRole; 080import org.opencms.ui.I_CmsDialogContext; 081import org.opencms.ui.editors.messagebundle.CmsMessageBundleEditorTypes.BundleType; 082import org.opencms.workplace.explorer.CmsResourceUtil; 083import org.opencms.xml.content.CmsXmlContentFactory; 084 085import java.util.Set; 086 087import org.apache.commons.logging.Log; 088 089import com.google.common.collect.Sets; 090 091/** 092 * Standard visibility check implementation.<p> 093 * 094 * Instances of this class are configured with a set of flags, each of which corresponds to a check to perform which 095 * may cause the context menu item to be hidden or deactivated.<p> 096 */ 097public final class CmsStandardVisibilityCheck extends A_CmsSimpleVisibilityCheck { 098 099 /** Default visibility check for 'edit-like' operations on folders. */ 100 public static final CmsStandardVisibilityCheck COPY_PAGE = new CmsStandardVisibilityCheck( 101 roleeditor, 102 notonline, 103 notdeleted, 104 pagefolder); 105 106 /** Default visibility check for 'edit-like' operations on resources. */ 107 public static final CmsStandardVisibilityCheck DEFAULT = new CmsStandardVisibilityCheck( 108 roleeditor, 109 notonline, 110 notdeleted, 111 writepermisssion, 112 inproject); 113 114 /** 115 * Default permissions but with 'element author' role requirement instead of 'editor' 116 */ 117 public static final I_CmsHasMenuItemVisibility DEFAULT_AUTHOR = new CmsStandardVisibilityCheck( 118 roleelementauthor, 119 notonline, 120 notdeleted, 121 writepermisssion, 122 inproject); 123 124 /** 125 * Check for operations which need a default file.<p> 126 */ 127 public static final I_CmsHasMenuItemVisibility DEFAULT_DEFAULTFILE = new CmsStandardVisibilityCheck( 128 roleeditor, 129 notonline, 130 notdeleted, 131 writepermisssion, 132 inproject, 133 defaultfile); 134 135 /** Default visibility check for 'edit-like' operations on folders. */ 136 public static final CmsStandardVisibilityCheck DEFAULT_FOLDERS = new CmsStandardVisibilityCheck( 137 folder, 138 roleeditor, 139 notonline, 140 notdeleted, 141 writepermisssion, 142 inproject); 143 144 /** Like DEFAULT, but only active for files. */ 145 public static final CmsStandardVisibilityCheck EDIT = new CmsStandardVisibilityCheck( 146 file, 147 notpointer, 148 roleeditor, 149 notonline, 150 notdeleted, 151 writepermisssion, 152 inproject, 153 xmlunmarshal, 154 haseditor, 155 restrictedconfig); 156 157 /** Like DEFAULT, but only active for files. */ 158 public static final CmsStandardVisibilityCheck EDIT_CODE = new CmsStandardVisibilityCheck( 159 file, 160 hassourcecodeeditor, 161 rolevfsmanager, 162 notonline, 163 notdeleted, 164 writepermisssion, 165 inproject, 166 haseditor, 167 restrictedconfig); 168 169 /** Visibility check for editing external links (pointers). */ 170 public static final I_CmsHasMenuItemVisibility EDIT_POINTER = new CmsStandardVisibilityCheck( 171 file, 172 roleeditor, 173 notonline, 174 notdeleted, 175 writepermisssion, 176 inproject, 177 pointer); 178 179 /** Check for locking resources. */ 180 public static final CmsStandardVisibilityCheck LOCK = new CmsStandardVisibilityCheck( 181 unlocked, 182 roleeditor, 183 notonline, 184 notdeleted, 185 inproject); 186 187 /** Visibility check used for copy to project dialog. */ 188 public static final CmsStandardVisibilityCheck OTHER_PROJECT = new CmsStandardVisibilityCheck( 189 roleeditor, 190 notonline, 191 notdeleted, 192 notinproject); 193 194 /** Visibility check for the permissions dialog. */ 195 public static final I_CmsHasMenuItemVisibility PERMISSIONS = new CmsStandardVisibilityCheck( 196 roleeditor, 197 notonline, 198 notdeleted, 199 writepermisssion, 200 controlpermission, 201 inproject); 202 203 /** Visibility check for publish option. */ 204 public static final CmsStandardVisibilityCheck PUBLISH = new CmsStandardVisibilityCheck( 205 notunchangedfile, 206 publishpermission, 207 notonline, 208 inproject); 209 210 /** Visibility check for the reindex function. */ 211 public static final CmsStandardVisibilityCheck REINDEX = new CmsStandardVisibilityCheck(rolerootadmin); 212 213 /** Check for the 'replace' operation. */ 214 public static final CmsStandardVisibilityCheck REPLACE = new CmsStandardVisibilityCheck( 215 replacable, 216 roleeditor, 217 notonline, 218 notdeleted, 219 writepermisssion, 220 inproject); 221 222 /** 'Replace' check, but with 'element author' role requirement instead of 'editor'. */ 223 public static final CmsStandardVisibilityCheck REPLACE_AUTHOR = new CmsStandardVisibilityCheck( 224 replacable, 225 roleelementauthor, 226 notonline, 227 notdeleted, 228 writepermisssion, 229 inproject); 230 231 /** Default check for 'locked resources' action. */ 232 public static final CmsStandardVisibilityCheck SHOW_LOCKS = new CmsStandardVisibilityCheck( 233 notonline, 234 inproject, 235 folder); 236 237 /** Permission check for stealing locks. */ 238 public static final I_CmsHasMenuItemVisibility STEAL_LOCK = new CmsStandardVisibilityCheck( 239 otherlock, 240 noinheritedlock, 241 inproject); 242 243 /** Visibility check for undelete option. */ 244 public static final CmsStandardVisibilityCheck UNDELETE = new CmsStandardVisibilityCheck( 245 roleeditor, 246 notonline, 247 deleted, 248 writepermisssion, 249 inproject); 250 251 /** Visibility check for the undo function. */ 252 public static final CmsStandardVisibilityCheck UNDO = new CmsStandardVisibilityCheck( 253 notunchangedfile, 254 notnew, 255 roleeditor, 256 notonline, 257 notdeleted, 258 writepermisssion, 259 inproject); 260 261 /** Visibility check for the undo function. */ 262 public static final CmsStandardVisibilityCheck UNDO_AUTHOR = new CmsStandardVisibilityCheck( 263 notunchangedfile, 264 notnew, 265 roleelementauthor, 266 notonline, 267 notdeleted, 268 writepermisssion, 269 inproject); 270 271 /** Visibility check for the undo function. */ 272 public static final CmsStandardVisibilityCheck UNLOCK = new CmsStandardVisibilityCheck( 273 mylock, 274 noinheritedlock, 275 inproject); 276 277 /** Default visibility check for view operations on resources. */ 278 public static final CmsStandardVisibilityCheck VIEW = new CmsStandardVisibilityCheck(roleeditor, notdeleted); 279 280 /** Default visibility check for view operations on resources. */ 281 public static final CmsStandardVisibilityCheck VIEW_AUTHOR = new CmsStandardVisibilityCheck( 282 roleelementauthor, 283 notdeleted); 284 285 /** Always active. */ 286 public static final I_CmsHasMenuItemVisibility VISIBLE = new CmsStandardVisibilityCheck(); 287 288 /** Logger instance for this class. */ 289 private static final Log LOG = CmsLog.getLog(CmsStandardVisibilityCheck.class); 290 291 /** The set of flags. */ 292 private Set<CmsVisibilityCheckFlag> m_flags = Sets.newHashSet(); 293 294 /** 295 * Creates a new instance using the given flags.<p> 296 * 297 * Note that the order of the flags does not matter; the checks corresponding to the flags are performed in a fixed order. 298 * 299 * @param flags the flags indicating which checks to perform 300 */ 301 public CmsStandardVisibilityCheck(CmsVisibilityCheckFlag... flags) { 302 303 for (CmsVisibilityCheckFlag flag : flags) { 304 m_flags.add(flag); 305 } 306 } 307 308 /** 309 * Helper method to make checking for a flag very short (character count).<p> 310 * 311 * @param flag the flag to check 312 * 313 * @return true if this instance was configured with the given flag 314 */ 315 public boolean flag(CmsVisibilityCheckFlag flag) { 316 317 return m_flags.contains(flag); 318 } 319 320 /** 321 * @see org.opencms.ui.contextmenu.A_CmsSimpleVisibilityCheck#getSingleVisibility(org.opencms.file.CmsObject, org.opencms.file.CmsResource) 322 */ 323 @Override 324 public CmsMenuItemVisibilityMode getSingleVisibility(CmsObject cms, CmsResource resource) { 325 326 boolean prioritize = false; 327 String inActiveKey = null; 328 if (resource != null) { 329 if (flag(roleeditor) && !OpenCms.getRoleManager().hasRoleForResource(cms, CmsRole.EDITOR, resource)) { 330 return VISIBILITY_INVISIBLE; 331 } 332 333 if (flag(roleelementauthor) 334 && !OpenCms.getRoleManager().hasRoleForResource(cms, CmsRole.ELEMENT_AUTHOR, resource)) { 335 return VISIBILITY_INVISIBLE; 336 } 337 338 if (flag(rolewpuser) 339 && !OpenCms.getRoleManager().hasRoleForResource(cms, CmsRole.WORKPLACE_USER, resource)) { 340 return VISIBILITY_INVISIBLE; 341 } 342 if (flag(rolevfsmanager)) { 343 if (!OpenCms.getRoleManager().hasRoleForResource(cms, CmsRole.VFS_MANAGER, resource)) { 344 return VISIBILITY_INVISIBLE; 345 } 346 } 347 348 if (flag(rolerootadmin) 349 && !OpenCms.getRoleManager().hasRoleForResource(cms, CmsRole.ROOT_ADMIN, resource)) { 350 return VISIBILITY_INVISIBLE; 351 } 352 } else { 353 if (flag(roleeditor) && !OpenCms.getRoleManager().hasRole(cms, CmsRole.EDITOR)) { 354 return VISIBILITY_INVISIBLE; 355 } 356 357 if (flag(rolewpuser) && !OpenCms.getRoleManager().hasRole(cms, CmsRole.WORKPLACE_USER)) { 358 return VISIBILITY_INVISIBLE; 359 } 360 } 361 if (flag(notonline) && cms.getRequestContext().getCurrentProject().isOnlineProject()) { 362 return VISIBILITY_INVISIBLE; 363 } 364 365 if ((resource != null)) { 366 CmsResourceUtil resUtil = new CmsResourceUtil(cms, resource); 367 if (flag(file) && !resource.isFile()) { 368 return VISIBILITY_INVISIBLE; 369 } 370 371 if (flag(defaultfile)) { 372 if (!resource.isFile()) { 373 return VISIBILITY_INVISIBLE; 374 } 375 try { 376 CmsResource parentFolder = cms.readParentFolder(resource.getStructureId()); 377 if (parentFolder == null) { 378 return VISIBILITY_INVISIBLE; 379 } 380 CmsResource defaultFile = cms.readDefaultFile(parentFolder, CmsResourceFilter.IGNORE_EXPIRATION); 381 if ((defaultFile == null) || !(defaultFile.getStructureId().equals(resource.getStructureId()))) { 382 return VISIBILITY_INVISIBLE; 383 } 384 } catch (CmsException e) { 385 LOG.error(e.getLocalizedMessage(), e); 386 return VISIBILITY_INVISIBLE; 387 } 388 } 389 390 if (flag(folder) && resource.isFile()) { 391 return VISIBILITY_INVISIBLE; 392 } 393 394 if (flag(pagefolder)) { 395 if (!resource.isFolder()) { 396 return VISIBILITY_INVISIBLE; 397 } 398 try { 399 CmsResource defaultFile; 400 defaultFile = cms.readDefaultFile("" + resource.getStructureId()); 401 if ((defaultFile == null) || !CmsResourceTypeXmlContainerPage.isContainerPage(defaultFile)) { 402 return VISIBILITY_INVISIBLE; 403 } 404 } catch (CmsException e) { 405 LOG.warn(e.getLocalizedMessage(), e); 406 return VISIBILITY_INVISIBLE; 407 } 408 } 409 410 if (flag(pointer) 411 && !OpenCms.getResourceManager().matchResourceType( 412 CmsResourceTypePointer.getStaticTypeName(), 413 resource.getTypeId())) { 414 return VISIBILITY_INVISIBLE; 415 } 416 417 if (flag(notpointer) 418 && OpenCms.getResourceManager().matchResourceType( 419 CmsResourceTypePointer.getStaticTypeName(), 420 resource.getTypeId())) { 421 return VISIBILITY_INVISIBLE; 422 } 423 424 if (flag(replacable)) { 425 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(resource); 426 boolean usesDumpLoader = type.getLoaderId() == CmsDumpLoader.RESOURCE_LOADER_ID; 427 if (!usesDumpLoader && !(type instanceof CmsResourceTypeImage)) { 428 return VISIBILITY_INVISIBLE; 429 } 430 431 } 432 433 if (flag(hassourcecodeeditor)) { 434 I_CmsResourceType type = resUtil.getResourceType(); 435 boolean hasSourcecodeEditor = (type instanceof CmsResourceTypeXmlContent) 436 || (type instanceof CmsResourceTypeXmlPage) 437 || (type instanceof CmsResourceTypePointer) 438 || OpenCms.getResourceManager().matchResourceType( 439 BundleType.PROPERTY.toString(), 440 resource.getTypeId()); 441 if (!hasSourcecodeEditor) { 442 return VISIBILITY_INVISIBLE; 443 } 444 } 445 446 if (flag(unlocked)) { 447 CmsLock lock = resUtil.getLock(); 448 if (!lock.isUnlocked()) { 449 return VISIBILITY_INVISIBLE; 450 } 451 prioritize = true; 452 } 453 454 if (flag(otherlock)) { 455 CmsLock lock = resUtil.getLock(); 456 if (lock.isUnlocked() || lock.isOwnedBy(cms.getRequestContext().getCurrentUser())) { 457 return VISIBILITY_INVISIBLE; 458 } 459 prioritize = true; 460 } 461 462 if (flag(nootherlock)) { 463 CmsLock lock = resUtil.getLock(); 464 if (!lock.isUnlocked() && !lock.isOwnedBy(cms.getRequestContext().getCurrentUser())) { 465 return VISIBILITY_INVISIBLE; 466 } 467 } 468 469 if (flag(mylock)) { 470 CmsLock lock = resUtil.getLock(); 471 if (!lock.isOwnedBy(cms.getRequestContext().getCurrentUser())) { 472 return VISIBILITY_INVISIBLE; 473 } 474 prioritize = true; 475 } 476 477 if (flag(noinheritedlock)) { 478 CmsLock lock = resUtil.getLock(); 479 if (lock.isInherited()) { 480 return VISIBILITY_INVISIBLE; 481 } 482 } 483 484 if (flag(notunchangedfile) && resource.isFile() && resUtil.getResource().getState().isUnchanged()) { 485 inActiveKey = Messages.GUI_CONTEXTMENU_TITLE_INACTIVE_UNCHANGED_0; 486 } 487 488 if (flag(notnew) && (inActiveKey == null) && resource.getState().isNew()) { 489 inActiveKey = Messages.GUI_CONTEXTMENU_TITLE_INACTIVE_NEW_UNCHANGED_0; 490 } 491 492 if (flag(restrictedconfig)) { 493 if (OpenCms.getADEManager().isEditorRestricted(cms, resource)) { 494 return VISIBILITY_INVISIBLE; 495 } 496 } 497 498 if (flag(xmlunmarshal)) { 499 if (CmsResourceTypeXmlContent.isXmlContent(resource)) { 500 try { 501 CmsXmlContentFactory.unmarshal(cms, cms.readFile(resource)); 502 } catch (Exception e) { 503 LOG.error(e.getLocalizedMessage(), e); 504 return VISIBILITY_INVISIBLE; 505 } 506 } 507 508 } 509 510 if (flag(haseditor) 511 && (OpenCms.getWorkplaceAppManager().getEditorForResource(cms, resource, false) == null)) { 512 return VISIBILITY_INVISIBLE; 513 } 514 515 if (flag(inproject) && (!resUtil.isInsideProject() || resUtil.getProjectState().isLockedForPublishing())) { 516 return VISIBILITY_INVISIBLE; 517 } 518 519 if (flag(notinproject) 520 && (resUtil.isInsideProject() || resUtil.getProjectState().isLockedForPublishing())) { 521 return VISIBILITY_INVISIBLE; 522 } 523 524 if (flag(publishpermission)) { 525 try { 526 if (!cms.hasPermissions( 527 resource, 528 CmsPermissionSet.ACCESS_DIRECT_PUBLISH, 529 false, 530 CmsResourceFilter.ALL)) { 531 return VISIBILITY_INVISIBLE; 532 } 533 } catch (CmsException e) { 534 LOG.error(e.getLocalizedMessage(), e); 535 } 536 } 537 538 if (flag(controlpermission)) { 539 try { 540 if (!cms.hasPermissions( 541 resource, 542 CmsPermissionSet.ACCESS_CONTROL, 543 false, 544 CmsResourceFilter.IGNORE_EXPIRATION)) { 545 return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 546 } 547 } catch (CmsException e) { 548 LOG.warn("Error checking context menu entry permissions", e); 549 return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 550 } 551 } 552 553 if (flag(writepermisssion)) { 554 try { 555 if (!resUtil.getLock().isLockableBy(cms.getRequestContext().getCurrentUser())) { 556 // set invisible if not lockable 557 return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 558 } 559 if (!resUtil.isEditable() 560 || !cms.hasPermissions( 561 resUtil.getResource(), 562 CmsPermissionSet.ACCESS_WRITE, 563 false, 564 CmsResourceFilter.ALL)) { 565 inActiveKey = Messages.GUI_CONTEXTMENU_TITLE_INACTIVE_PERM_WRITE_0; 566 } 567 } catch (CmsException e) { 568 LOG.debug("Error checking context menu entry permissions.", e); 569 return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 570 } 571 } 572 573 if (flag(notdeleted) && (inActiveKey == null) && resUtil.getResource().getState().isDeleted()) { 574 inActiveKey = Messages.GUI_CONTEXTMENU_TITLE_INACTIVE_DELETED_0; 575 } 576 577 if (flag(deleted) && !resource.getState().isDeleted()) { 578 return CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 579 } 580 581 } else { 582 return VISIBILITY_INVISIBLE; 583 } 584 if (inActiveKey != null) { 585 return CmsMenuItemVisibilityMode.VISIBILITY_INACTIVE.addMessageKey(inActiveKey).prioritize(prioritize); 586 } 587 return VISIBILITY_ACTIVE.prioritize(prioritize); 588 } 589 590 /** 591 * @see org.opencms.ui.contextmenu.I_CmsHasMenuItemVisibility#getVisibility(org.opencms.ui.I_CmsDialogContext) 592 */ 593 public CmsMenuItemVisibilityMode getVisibility(I_CmsDialogContext context) { 594 595 return getVisibility(context.getCms(), context.getResources()); 596 } 597 598 /** 599 * @see java.lang.Object#toString() 600 */ 601 @Override 602 public String toString() { 603 604 return "visibility[" + m_flags + "]"; 605 } 606}