///////////////////////////////////////////////////////////////////////////// // // Project ProjectForge Community Edition // www.projectforge.org // // Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de) // // ProjectForge is dual-licensed. // // This community edition is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation; version 3 of the License. // // This community edition is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General // Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, see http://www.gnu.org/licenses/. // ///////////////////////////////////////////////////////////////////////////// package org.projectforge.web; import java.io.Serializable; import org.apache.commons.lang.Validate; import org.apache.wicket.Page; import org.projectforge.access.AccessChecker; import org.projectforge.user.PFUserDO; import org.projectforge.user.ProjectForgeGroup; import org.projectforge.user.UserRight; import org.projectforge.user.UserRightAccessCheck; import org.projectforge.user.UserRightId; import org.projectforge.user.UserRightValue; import org.projectforge.user.UserRights; import org.projectforge.web.wicket.WicketApplication; /** * The menu is defined once. The user's personal menu is calculated by this menu definitions (which menu entries are visible and which not). * @author Kai Reinhard (k.reinhard@micromata.de) */ public class MenuItemDef implements Serializable { private static final long serialVersionUID = 6793153590139785117L; private String id; private String i18nKey; private MenuItemDef parent, mobileParentMenu; private Class< ? extends Page> pageClass; private String url; private String[] params; private boolean newWindow; private Class< ? extends Page> mobilePageClass; private boolean visible = true; private ProjectForgeGroup[] visibleForGroups; private UserRightId requiredRightId; private UserRightValue[] requiredRightValues; private int orderNumber, mobileMenuOrderNumber; private boolean mobileMenuSupport = false; private boolean desktopMenuSupport = true; private boolean visibleForRestrictedUsers; /** * Overwrite this if you need special access checking. * @param context * @return true (at default). */ protected boolean isVisible(final MenuBuilderContext context) { return visible; } public boolean isVisible() { return this.visible; } /** * @param visible * @return this for chaining. */ public MenuItemDef setVisible(final boolean visible) { this.visible = visible; return this; } /** * Most menus aren't visibly for restrictedUsers. * @return the visibleByRestrictedUsers */ public boolean isVisibleForRestrictedUsers() { return visibleForRestrictedUsers; } /** * @param visibleForRestrictedUsers the visibleByRestrictedUsers to set * @return this for chaining. */ public MenuItemDef setVisibleForRestrictedUsers(final boolean visibleForRestrictedUsers) { this.visibleForRestrictedUsers = visibleForRestrictedUsers; return this; } /** * Creates a menu entry if the user has access to. * @return null if not visible otherwise the created MenuEntry. */ protected MenuEntry createMenuEntry(final Menu menu, final MenuBuilderContext context) { if (visibleForRestrictedUsers == false && context.getLoggedInUser().isRestrictedUser() == true) { // Restricted users have not access to. return null; } if (context.isMobileMenu() == true && mobileMenuSupport == false) { // this menu item doesn't support the mobile menu. return null; } if (context.isMobileMenu() == false && desktopMenuSupport == false) { // this menu item doesn't support the desktop menu. return null; } if (requiredRightId != null && hasRight(context.getAccessChecker(), context.getLoggedInUser()) == false) { return null; } if (isVisible(context) == false) { return null; } final ProjectForgeGroup[] visibleForGroups = getVisibleForGroups(); if (visibleForGroups != null && visibleForGroups.length > 0 && context.getAccessChecker().isLoggedInUserMemberOfGroup(visibleForGroups) == false) { // Do nothing because menu is not visible for logged in user. return null; } final MenuEntry menuEntry = new MenuEntry(this, context); afterMenuEntryCreation(menuEntry, context); menuEntry.setMenu(menu); return menuEntry; } /** * Override this method if some modifications needed after a menu entry for an user's menu is created. * @param createdMenuEntry The fresh created menu entry (is never null). * @param context */ protected void afterMenuEntryCreation(final MenuEntry createdMenuEntry, final MenuBuilderContext context) { } public MenuItemDef() { } /** * @param parent The parent menu entry * @param id The unique id * @param orderNumber The order of the sibling menu entries is done implemented by this order number (ascending order). * @param i18nKey For displaying the menu entry localized. * @param pageClass The linked page class (if the user clicks on this menu entry). * @param requiredRightId Reduce the visibility of this menu entry (if wanted): which user right is required? * @param requiredRightValues Reducing the visibility: which right values are required? */ public MenuItemDef(final MenuItemDef parent, final String id, final int orderNumber, final String i18nKey, final Class< ? extends Page> pageClass, final UserRightId requiredRightId, final UserRightValue... requiredRightValues) { this(parent, id, orderNumber, i18nKey, pageClass, null, requiredRightId, requiredRightValues); } /** * @param parent The parent menu entry * @param id The unique id * @param orderNumber The order of the sibling menu entries is done implemented by this order number (ascending order). * @param i18nKey For displaying the menu entry localized. * @param pageClass The linked page class (if the user clicks on this menu entry). * @param params Parameters used when calling the pageClass (PageParameters). * @param requiredRightId Reduce the visibility of this menu entry (if wanted): which user right is required? * @param requiredRightValues Reducing the visibility: which right values are required? */ public MenuItemDef(final MenuItemDef parent, final String id, final int orderNumber, final String i18nKey, final Class< ? extends Page> pageClass, final String[] params, final UserRightId requiredRightId, final UserRightValue... requiredRightValues) { this.parent = parent; this.id = id; this.orderNumber = orderNumber; this.i18nKey = i18nKey; this.pageClass = pageClass; this.params = params; this.requiredRightId = requiredRightId; this.requiredRightValues = requiredRightValues; } /** * @param parent The parent menu entry * @param id The unique id * @param orderNumber The order of the sibling menu entries is done implemented by this order number (ascending order). * @param i18nKey For displaying the menu entry localized. * @param pageClass The linked page class (if the user clicks on this menu entry). * @param visibleForGroups Reduce the visibility of this menu entry (if wanted). */ public MenuItemDef(final MenuItemDef parent, final String id, final int orderNumber, final String i18nKey, final Class< ? extends Page> pageClass, final ProjectForgeGroup... visibleForGroups) { this(parent, id, orderNumber, i18nKey, pageClass, null, visibleForGroups); } /** * @param parent The parent menu entry * @param id The unique id * @param orderNumber The order of the sibling menu entries is done implemented by this order number (ascending order). * @param i18nKey For displaying the menu entry localized. * @param pageClass The linked page class (if the user clicks on this menu entry). * @param params Parameters used when calling the pageClass (PageParameters). * @param visibleForGroups Reduce the visibility of this menu entry (if wanted). */ public MenuItemDef(final MenuItemDef parent, final String id, final int orderNumber, final String i18nKey, final Class< ? extends Page> pageClass, final String[] params, final ProjectForgeGroup... visibleForGroups) { this.parent = parent; this.id = id; this.orderNumber = orderNumber; this.i18nKey = i18nKey; this.pageClass = pageClass; this.params = params; this.visibleForGroups = visibleForGroups; } /** * @param parent The parent menu entry * @param id The unique id * @param orderNumber The order of the sibling menu entries is done implemented by this order number (ascending order). * @param i18nKey For displaying the menu entry localized. * @param url The linked url (if the user clicks on this menu entry). * @param visibleForGroups Reduce the visibility of this menu entry (if wanted). */ public MenuItemDef(final MenuItemDef parent, final String id, final int orderNumber, final String i18nKey, final String url, final ProjectForgeGroup... visibleForGroups) { this(parent, id, orderNumber, i18nKey, url, false, visibleForGroups); } /** * @param parent The parent menu entry * @param id The unique id * @param orderNumber The order of the sibling menu entries is done implemented by this order number (ascending order). * @param i18nKey For displaying the menu entry localized. * @param url The linked url (if the user clicks on this menu entry). * @param newWindow If true, then the link will be opened in a new browser window. * @param visibleForGroups Reduce the visibility of this menu entry (if wanted). */ public MenuItemDef(final MenuItemDef parent, final String id, final int orderNumber, final String i18nKey, final String url, final boolean newWindow, final ProjectForgeGroup... visibleForGroups) { this.parent = parent; this.id = id; this.orderNumber = orderNumber; this.i18nKey = i18nKey; this.url = url; this.newWindow = newWindow; this.visibleForGroups = visibleForGroups; } /** * A menu entry without a link (e. g. a parent menu entry). * @param parent The parent menu entry * @param id The unique id * @param orderNumber The order of the sibling menu entries is done implemented by this order number (ascending order). * @param i18nKey For displaying the menu entry localized. * @param visibleForGroups Reduce the visibility of this menu entry (if wanted). */ public MenuItemDef(final MenuItemDef parent, final String id, final int orderNumber, final String i18nKey, final ProjectForgeGroup... visibleForGroups) { this.parent = parent; this.id = id; this.orderNumber = orderNumber; this.i18nKey = i18nKey; this.visibleForGroups = visibleForGroups; } /** * @param parent The parent menu entry * @param id The unique id * @param orderNumber The order of the sibling menu entries is done implemented by this order number (ascending order). * @param i18nKey For displaying the menu entry localized. * @param url The linked url (if the user clicks on this menu entry). * @param requiredRightId Reduce the visibility of this menu entry (if wanted): which user right is required? * @param requiredRightValues Reducing the visibility: which right values are required? */ public MenuItemDef(final MenuItemDef parent, final String id, final int orderNumber, final String i18nKey, final String url, final UserRightId requiredRightId, final UserRightValue... requiredRightValues) { this(parent, id, orderNumber, i18nKey, url, false, requiredRightId, requiredRightValues); } /** * @param parent The parent menu entry * @param id The unique id * @param orderNumber The order of the sibling menu entries is done implemented by this order number (ascending order). * @param i18nKey For displaying the menu entry localized. * @param url The linked url (if the user clicks on this menu entry). * @param newWindow If true, then the link will be opened in a new browser window. * @param requiredRightId Reduce the visibility of this menu entry (if wanted): which user right is required? * @param requiredRightValues Reducing the visibility: which right values are required? */ public MenuItemDef(final MenuItemDef parent, final String id, final int orderNumber, final String i18nKey, final String url, final boolean newWindow, final UserRightId requiredRightId, final UserRightValue... requiredRightValues) { this.parent = parent; this.id = id; this.orderNumber = orderNumber; this.i18nKey = i18nKey; this.url = url; this.newWindow = newWindow; this.requiredRightId = requiredRightId; this.requiredRightValues = requiredRightValues; } /** * @return parent menu item definition or null if this definition represents a top level menu item. */ public MenuItemDef getParent() { return parent; } /** * @return Id used for html markup and for referencing in config.xml. */ public String getId() { return id; } /** * Order number for sorting menu entries. */ public int getOrderNumber() { return orderNumber; } /** * If set to false then this menu entry will not be displayed in the classical web menu version. Default is true. * @param desktopMenuSupport */ public void setDesktopMenuSupport(final boolean desktopMenuSupport) { this.desktopMenuSupport = desktopMenuSupport; } /** * Will be automatically set if any setter regarding mobile menu properties is calles (with not-null params), default is false. * @param mobileMenuSupport */ public void setMobileMenuSupport(final boolean mobileMenuSupport) { this.mobileMenuSupport = mobileMenuSupport; } /** * Order number for sorting menu entries (mobile menu). */ public int getMobileMenuOrderNumber() { return mobileMenuOrderNumber; } /** * @return The parent menu entry of the mobile menu. */ public MenuItemDef getMobileParentMenu() { return mobileParentMenu; } /** * TODO: Not yet supported. The menu entry is set as a top level menu entry. * @param mobileParentEntry * @param mobileMenuOrderNumber * @return this for chaining. */ public MenuItemDef setMobileMenu(final MenuItemDef mobileParentEntry, final Class< ? extends Page> mobilePageClass, final int mobileMenuOrderNumber) { this.mobileParentMenu = mobileParentEntry; setMobileMenu(mobilePageClass, mobileMenuOrderNumber); return this; } /** * Adds the given menu entry as root menu entry. * @param mobileParentEntry * @param mobileMenuOrderNumber * @return this for chaining. */ public MenuItemDef setMobileMenu(final Class< ? extends Page> mobilePageClass, final int mobileMenuOrderNumber) { this.mobileMenuSupport = true; this.mobilePageClass = mobilePageClass; this.mobileMenuOrderNumber = mobileMenuOrderNumber; return this; } /** * @return Key used in the i18n resource bundle. */ public String getI18nKey() { return i18nKey; } /** * @return Wicket page or null for non Wicket pages. */ public Class< ? extends Page> getPageClass() { return pageClass; } /** * @param pageClass the pageClass to set * @return this for chaining. */ public void setPageClass(final Class< ? extends Page> pageClass) { this.pageClass = pageClass; } /** * @return Wicket page or null for non Wicket pages. */ public Class< ? extends Page> getMobilePageClass() { return mobilePageClass; } /** * @return true, if pageClass (Wicket page) is given otherwise false. */ public boolean isWicketPage() { return this.pageClass != null; } public boolean hasUrl() { return url != null; } /** * @return true if this menu entry has a link (to a Wicket page or an url). Otherwise false (e. g. if this menu item def represents only a * menu with sub menus). */ public boolean isLink() { return isWicketPage() == true || hasUrl() == true; } /** * @return The url for non-Wicket pages (relative to "secure/") or the bookmarkable url for Wicket pages (relative to "wa/"). */ public String getUrl() { if (url == null) { // Late binding: may be this enum class was instantiated before WicketApplication was initialized. this.url = WicketApplication.getBookmarkableMountPath(this.pageClass); } return url; } public String[] getParams() { return params; } public boolean isNewWindow() { return newWindow; } public ProjectForgeGroup[] getVisibleForGroups() { return visibleForGroups; } public UserRightId getRequiredRightId() { return requiredRightId; } public UserRightValue[] getRequiredRightValues() { return requiredRightValues; } public boolean hasRight(final AccessChecker accessChecker, final PFUserDO loggedInUser) { if (requiredRightId == null || requiredRightValues == null) { // Should not occur, for security reasons deny at default. return false; } if (requiredRightValues.length == 0) { final UserRight right = UserRights.instance().getRight(requiredRightId); if (right instanceof UserRightAccessCheck< ? >) { Validate.notNull(loggedInUser); return (((UserRightAccessCheck< ? >) right).hasSelectAccess(loggedInUser) == true); } else { // Should not occur, for security reasons deny at default. return false; } } if (accessChecker.hasLoggedInUserRight(requiredRightId, false, requiredRightValues) == true) { return true; } return false; } @Override public String toString() { return id; } }