/* * Copyright (C) 2010 - 2012 Interactive Media Management * Copyright (C) 2014 Allan Lykke Christensen * * This program 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, either version 3 of the License, or * (at your option) any later version. * * This program 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 dk.i2m.converge.jsf.beans; import dk.i2m.commons.FileUtils; import dk.i2m.commons.ImageUtils; import dk.i2m.converge.core.ConfigurationKey; import dk.i2m.converge.core.DataNotFoundException; import dk.i2m.converge.core.content.catalogue.Catalogue; import dk.i2m.converge.core.newswire.NewswireService; import dk.i2m.converge.core.security.SystemPrivilege; import dk.i2m.converge.core.security.UserAccount; import dk.i2m.converge.core.security.UserRole; import dk.i2m.converge.core.wiki.Page; import dk.i2m.converge.core.workflow.Outlet; import dk.i2m.converge.core.workflow.Section; import dk.i2m.converge.ejb.facades.*; import dk.i2m.converge.jsf.beans.administrator.Catalogues; import dk.i2m.converge.jsf.model.MenuHelper; import dk.i2m.converge.jsf.model.MenuItem; import dk.i2m.converge.jsf.model.MenuItems; import dk.i2m.jsf.JsfUtils; import java.io.IOException; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.PostConstruct; import javax.ejb.EJB; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; import javax.servlet.http.HttpServletRequest; import org.richfaces.event.UploadEvent; /** * Session scoped managed bean controlling the current user session. This class * is responsible for containing and providing information about the current * user logged in. * * @author Allan Lykke Christensen */ public class UserSession { private static final Logger LOG = Logger.getLogger(UserSession.class.getName()); @EJB private UserFacadeLocal userFacade; @EJB private CatalogueFacadeLocal catalogueFacade; @EJB private SystemFacadeLocal systemFacade; @EJB private WikiFacadeBeanLocal wikiFacade; private UserAccount user; /** * Menu items appearing on the page header. */ private List<MenuItem> items = new ArrayList<MenuItem>(); /** * Sub-menu items. */ private List<MenuItem> submenuItems = new ArrayList<MenuItem>(); private MenuItem administration = new MenuItem(); private MenuItem selectedMenu; private MenuItem sectionMenu; private Map<String, List<Outlet>> privilegedOutlets = new HashMap<String, List<Outlet>>(); private Map<String, Boolean> privileges = new HashMap<String, Boolean>(); private Map<Long, Boolean> catalogueEditor = new HashMap<Long, Boolean>(); private List<Catalogue> catalogues = new ArrayList<Catalogue>(); private NewswireService selectedNewswireService; private Page displayWikiPage = null; private String wikiPageTitle; /** * Creates a new instance of {@link UserSession}. */ public UserSession() { } @PostConstruct public void onInit() throws UserSessionException { fetchUser(); updatePrivileges(); generateMenu(); } /** * Internal method for updating the user privileges. */ private void updatePrivileges() { String uid = getUser().getUsername(); List<UserRole> userRoles = getUser().getUserRoles(); this.catalogues = catalogueFacade.findCataloguesByUser(uid); this.catalogueEditor.clear(); List<Catalogue> allCatalogues = catalogueFacade.findAllCatalogues(); for (Catalogue c : allCatalogues) { this.catalogueEditor.put(c.getId(), userRoles.contains(c. getEditorRole())); } } /** * Determines if the user is an administrator. * * @return {@code true} if the user is an administrator, otherwise * {@code false} */ public boolean isAdministrator() { return isUserInRole("ADMINISTRATOR"); } /** * Gets the current user, or {@code null} if the user is not logged in. * * @return Current user logged in */ public UserAccount getUser() { return user; } /** * Determines if the current user is in a given role. * * @param role Name of the role * @return {@code true} if the user is in the given role, otherwise * {@code false} */ public boolean isUserInRole(String role) { FacesContext ctx = FacesContext.getCurrentInstance(); return ctx.getExternalContext().isUserInRole(role); } /** * Determines if the current user is an editor of a catalogue. * <p/> * @return {@code true} if the current user is an editor of a catalogue, * otherwise {@code false} */ public boolean isCatalogueEditor() { return userFacade.isCatalogueEditor(getUser().getUsername()); } /** * Gets a {@link Map} of {@link Catalogues} with the {@link Catalogue} id in * the key of the {@link Map}, and a {@link Boolean} value in the value of * the {@link Map}. The {@link Boolean} value indicates if the current user * is an editor for the given {@link Catalogue}. * <p/> * @return {@link Map} of {@link Catalogues} indicator whether the current * user is an editor. */ public Map<Long, Boolean> getCatalogueEditorRole() { return catalogueEditor; } /** * Resets the "active" status on all items. */ public void resetActive() { for (MenuItem item : items) { item.setActive(false); } for (MenuItem item : submenuItems) { item.setActive(false); } this.administration.setActive(false); } /** * Get a {@link List} of all {@link MenuItem}s. * * @return {@link List} of all {@link MenuItem}s on the page header */ public List<MenuItem> getItems() { return this.items; } /** * Get a {@link List} of all {@link MenuItem}s to be displayed in the * sub-menu. * * @return {@link List} of all {@link MenuItem}s on the sub-menu */ public List<MenuItem> getSubmenuItems() { return submenuItems; } public MenuItem getAdministration() { return administration; } public void setAdministration(MenuItem administration) { this.administration = administration; } public MenuItem getSelectedMenu() { return selectedMenu; } public void setSelectedMenu(MenuItem selectedMenu) { this.selectedMenu = selectedMenu; } public MenuItem getSectionMenu() { return sectionMenu; } public void setSectionMenu(MenuItem sectionMenu) { this.sectionMenu = sectionMenu; } public boolean isShowSectionMenu() { if (this.sectionMenu == null) { return false; } else { return true; } } /** * Fetches user information and authorisation. This method should only be * executed once per user session. * * @throws UserSessionException If a user is not currently logged in or if * the user could not be found in the database and directory */ private void fetchUser() throws UserSessionException { FacesContext ctx = FacesContext.getCurrentInstance(); String uid = ctx.getExternalContext().getRemoteUser(); String ip = ((HttpServletRequest) FacesContext.getCurrentInstance(). getExternalContext().getRequest()).getRemoteAddr(); LOG.log(Level.FINE, "Initialising user session for {0}", uid); privilegedOutlets.clear(); // Used by the session overview to see the name of the users logged in JsfUtils.getHttpSession().setAttribute("uid", uid); JsfUtils.getHttpSession().setAttribute("ip", ip); if (uid != null && !uid.isEmpty()) { try { user = userFacade.findById(uid, true); for (SystemPrivilege p : SystemPrivilege.values()) { privilegedOutlets.put(p.name(), user.getPrivilegedOutlets(p)); privileges.put(p.name(), user.isPrivileged(p)); } if (user.getPreferredLocale() != null) { setLocale(user.getPreferredLocale()); } } catch (DataNotFoundException ex) { throw new UserSessionException(ex); } } else { throw new UserSessionException("User is not logged in"); } } private void generateMenu() { // Set-up menu items MenuItems menuItems = MenuHelper.getInstance().getMenuItems(); for (MenuItem item : menuItems.getItems()) { boolean show = false; if (item.isPrivilegesAvailable()) { for (String p : item.getPrivileges()) { SystemPrivilege sp = SystemPrivilege.valueOf(p); if (user.isPrivileged(sp)) { show = true; } } } else { show = true; } if (show) { item.setMenuManager(this); if (item.isActive()) { selectedMenu = item; } if (item.getType().equalsIgnoreCase(MenuItem.TYPE_ADMIN)) { setupAdminMenu(item); } else if (item.getType().equalsIgnoreCase(MenuItem.TYPE_SUBMENU)) { addSubmenuItem(item); } else { addMenuItem(item); } } else { LOG.log(Level.FINE, "Not showing {0}", item.getId()); } } List<Page> wikiPages = wikiFacade.findSubmenuPages(); for (Page page : wikiPages) { String menuId = "lnkWikiPage" + page.getId(); String menuAction = "wiki:" + page.getTitle(); MenuItem item = new MenuItem(menuId, page.getTitle(), menuAction, this); item.setStyle(page.getSubmenuStyle()); addSubmenuItem(item); } } /** * Helper method for adding a {@link MenuItem} to the page header. * * @param menuItem {@link MenuItem} to add to the page header */ private void addMenuItem(MenuItem menuItem) { this.items.add(menuItem); } /** * Helper method for adding a {@link MenuItem} to the sub-menu. * * @param menuItem {@link MenuItem} to add to the sub-menu */ private void addSubmenuItem(MenuItem menuItem) { this.submenuItems.add(menuItem); } /** * Helper method for adding a {@link MenuItem} to the page header. * * @param menuItem {@link MenuItem} to add to the page header */ private void setupAdminMenu(MenuItem menuItem) { administration = menuItem; } /** * Determine if the current user is allowed to create new assignments. * <p/> * @return {@code true} if the current user is allowed to create either news * items for outlets or media items for catalogues, otherwise {@code false} */ public boolean isPrivilegedToCreateNewAssignments() { return !getPrivilegedOutlets().isEmpty() || !getMyCatalogues().isEmpty(); } /** * Gets a {@link Map} of {@link Outlet}s indexed by the privileges of the * current user. The name of the {@link SystemPrivilege} is used as the key * and the value is a {@link List} of the {@link Outlet} where the user has * the given privilege. * * @return {@link Map} of {@link Outlet}s indexed by privilege */ public Map<String, List<Outlet>> getPrivilegedOutlets() { return privilegedOutlets; } public Map<String, Outlet> getMyNewsItemsOutlets() { Map<String, Outlet> outlets = new LinkedHashMap<String, Outlet>(); for (Outlet outlet : getUser().getPrivilegedOutlets( SystemPrivilege.MY_NEWS_ITEMS)) { outlets.put(outlet.getTitle(), outlet); } return outlets; } public Map<String, Section> getMyNewsItemsOutletSections() { Map<String, Section> sections = new LinkedHashMap<String, Section>(); if (getUser().getDefaultOutlet() != null) { for (Section section : getUser().getDefaultOutlet().getSections()) { if (section.isActive()) { sections.put(section.getFullName(), section); } } } return sections; } /** * Gets the privileged catalogues of the current user. * <p/> * @return {@link Map} of privileged catalogues of the current user */ public Map<String, Catalogue> getMyCatalogues() { Map<String, Catalogue> mine = new LinkedHashMap<String, Catalogue>(); for (Catalogue c : this.catalogues) { mine.put(c.getName(), c); } return mine; } /** * Gets a {@link Map} of privileges and whether the current user has the * given privilege. The name of the {@link SystemPrivilege} is used as the * key and the value is a {@link Boolean} that indicates whether the user * has the privilege or not. * * @return {@link Map} of privileges for the current user */ public Map<String, Boolean> getPrivileged() { return privileges; } public NewswireService getSelectedNewswireService() { return selectedNewswireService; } public void setSelectedNewswireService( NewswireService selectedNewswireService) { this.selectedNewswireService = selectedNewswireService; } /** * Event handler for updating the profile of the user. * * @param event Event that invoked the handler */ public void onUpdateProfile(ActionEvent event) { userFacade.update(this.user); try { fetchUser(); } catch (UserSessionException ex) { LOG.log(Level.SEVERE, null, ex); JsfUtils.createMessage("frmPage", FacesMessage.SEVERITY_ERROR, Bundle.i18n.name(), "Generic_AN_ERROR_OCCURRED_X", new Object[]{ex.getMessage()}); } JsfUtils.createMessage("frmPage", FacesMessage.SEVERITY_INFO, Bundle.i18n.name(), "MyProfile_PROFILE_UPDATED"); } /** * Event handler for uploading a new profile photo. * * @param event Event that invoked the handler */ public void onUploadProfilePhoto(UploadEvent event) { if (event == null) { return; } org.richfaces.model.UploadItem item = event.getUploadItem(); if (item.isTempFile()) { java.io.File tempFile = item.getFile(); String workingDirectory = systemFacade.getProperty( ConfigurationKey.WORKING_DIRECTORY) + System.getProperty( "file.separator") + "users" + System.getProperty( "file.separator"); try { byte[] uploadedFile = FileUtils.getBytes(tempFile); byte[] thumb = ImageUtils.generateThumbnail(uploadedFile, 48, 48, 100); FileUtils.writeToFile(thumb, workingDirectory + user.getId() + ".jpg"); } catch (IOException ex) { LOG.log(Level.WARNING, ex.getMessage()); LOG.log(Level.FINEST, "", ex); } catch (InterruptedException ex) { LOG.log(Level.WARNING, ex.getMessage()); LOG.log(Level.FINEST, "", ex); } } else { LOG.log(Level.SEVERE, "RichFaces is not set-up to use tempFiles for storing file uploads"); } } /** * Gets the URL of the user photo. * <p/> * @return URL of the user photo */ public String getPhotoUrl() { Long unique = java.util.Calendar.getInstance().getTimeInMillis(); return "/UserPhoto?uid=" + getUser().getId() + "&t=" + unique; } /** * Sets the {@link Locale} of the current user. * <p/> * @param locale {@link Locale} of the current user */ private void setLocale(Locale locale) { FacesContext.getCurrentInstance().getViewRoot().setLocale(locale); } /** * Event handler (setPropertyActionListener) for selecting the wiki page * that should be displayed. * <p/> * @param wikiPage Name of the wiki page to be displayed. */ public void setLoadWikiPage(String wikiPage) { this.wikiPageTitle = wikiPage; String pageTitle = wikiPage.replaceFirst("wiki:", ""); try { setDisplayWikiPage(wikiFacade.findPageByTitle(pageTitle)); } catch (DataNotFoundException ex) { LOG.log(Level.WARNING, "Unknown wiki page requested. {0}", ex. getMessage()); } } /** * Event handler for preparation of a new wiki page. * * @param event Event that invoked the handler */ public void onCreateWikiPage(ActionEvent event) { this.displayWikiPage = new Page(); } /** * Event handler for saving the currently opened wiki page. * <p/> * @param event Event that invoked the handler */ public void onSaveWikiPage(ActionEvent event) { displayWikiPage.setLastUpdater(getUser()); if (displayWikiPage.getId() == null) { displayWikiPage.setSubmenu(true); displayWikiPage = wikiFacade.create(displayWikiPage); } else { wikiFacade.update(displayWikiPage); } this.items.clear(); this.submenuItems.clear(); generateMenu(); } /** * Event handler for deleting the currently selected wiki page. * * @param event Event that invoked the handler */ public void onDeleteWikiPage(ActionEvent event) { wikiFacade.deletePageById(displayWikiPage.getId()); this.items.clear(); this.submenuItems.clear(); generateMenu(); } /** * Sets the wiki page that has to be displayed. * <p/> * @param displayWikiPage Wiki page to display */ public void setDisplayWikiPage(Page displayWikiPage) { this.displayWikiPage = displayWikiPage; } /** * Gets the wiki page that should be displayed. * <p/> * @return Wiki page that should be displayed */ public Page getDisplayWikiPage() { return displayWikiPage; } }