/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE file at the root of the source * tree and available online at * * https://github.com/keeps/roda */ package org.roda.wui.api.controllers; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.io.IOUtils; import org.roda.core.RodaCoreFactory; import org.roda.core.common.UserUtility; import org.roda.core.data.common.RodaConstants; import org.roda.core.data.exceptions.AlreadyExistsException; import org.roda.core.data.exceptions.AuthorizationDeniedException; import org.roda.core.data.exceptions.EmailAlreadyExistsException; import org.roda.core.data.exceptions.GenericException; import org.roda.core.data.exceptions.IllegalOperationException; import org.roda.core.data.exceptions.InvalidTokenException; import org.roda.core.data.exceptions.NotFoundException; import org.roda.core.data.exceptions.UserAlreadyExistsException; import org.roda.core.data.v2.notifications.Notification; import org.roda.core.data.v2.notifications.Notification.NOTIFICATION_STATE; import org.roda.core.data.v2.user.Group; import org.roda.core.data.v2.user.RODAMember; import org.roda.core.data.v2.user.User; import org.roda.wui.client.browse.MetadataValue; import org.roda.wui.client.browse.bundle.UserExtraBundle; import org.roda.wui.common.server.ServerTools; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.jknack.handlebars.Handlebars; import com.github.jknack.handlebars.Template; public class UserManagementHelper { private static final Logger LOGGER = LoggerFactory.getLogger(UserManagementHelper.class); private UserManagementHelper() { // do nothing } protected static User retrieveUser(String username) throws GenericException { return RodaCoreFactory.getModelService().retrieveUserByName(username); } protected static Group retrieveGroup(String groupname) throws GenericException, NotFoundException { return RodaCoreFactory.getModelService().retrieveGroup(groupname); } protected static List<Group> listAllGroups() throws GenericException { return RodaCoreFactory.getModelService().listGroups(); } public static User registerUser(User user, String password, UserExtraBundle extra, String localeString, String servletPath) throws GenericException, UserAlreadyExistsException, EmailAlreadyExistsException { user.setExtra(getUserExtra(extra)); User updatedUser = UserUtility.resetGroupsAndRoles(user); User registeredUser = RodaCoreFactory.getModelService().registerUser(updatedUser, password, true); RodaCoreFactory.getIndexService().commit(RODAMember.class); if (!user.isActive()) { try { boolean generateNewToken = false; Notification notification = UserManagement.sendEmailVerification(servletPath, updatedUser.getName(), generateNewToken, localeString); if (notification.getState() == NOTIFICATION_STATE.FAILED) { registeredUser.setActive(true); boolean notify = true; RodaCoreFactory.getModelService().updateUser(registeredUser, password, notify); } } catch (NotFoundException | AlreadyExistsException | AuthorizationDeniedException e) { LOGGER.error("Error updating user", e); throw new GenericException(e); } } return registeredUser; } public static User createUser(User user, String password, UserExtraBundle extra) throws GenericException, EmailAlreadyExistsException, UserAlreadyExistsException, IllegalOperationException, NotFoundException { user.setExtra(getUserExtra(extra)); User addedUser = RodaCoreFactory.getModelService().createUser(user, password, true); RodaCoreFactory.getIndexService().commit(RODAMember.class); return addedUser; } public static User updateUser(User user, String password, UserExtraBundle extra) throws GenericException, AlreadyExistsException, NotFoundException, AuthorizationDeniedException { user.setExtra(getUserExtra(extra)); User modifiedUser = RodaCoreFactory.getModelService().updateUser(user, password, true); RodaCoreFactory.getIndexService().commit(RODAMember.class); return modifiedUser; } public static User updateMyUser(User user, String password, UserExtraBundle extra) throws GenericException, AlreadyExistsException, NotFoundException, AuthorizationDeniedException { user.setExtra(getUserExtra(extra)); User currentUser = RodaCoreFactory.getModelService().retrieveUserByName(user.getName()); User resetUser = resetUser(user, currentUser); User modifiedUser = RodaCoreFactory.getModelService().updateMyUser(resetUser, password, true); RodaCoreFactory.getIndexService().commit(RODAMember.class); return modifiedUser; } private static User resetUser(User newUser, User oldUser) { newUser.setActive(oldUser.isActive()); newUser.setDirectRoles(oldUser.getDirectRoles()); newUser.setAllRoles(oldUser.getAllRoles()); newUser.setGroups(oldUser.getGroups()); return newUser; } private static String getUserExtra(UserExtraBundle extra) throws GenericException { Handlebars handlebars = new Handlebars(); Map<String, String> data = new HashMap<>(); handlebars.registerHelper("field", (o, options) -> { return options.fn(); }); try (InputStream templateStream = RodaCoreFactory.getConfigurationFileAsStream( RodaConstants.USERS_TEMPLATE_FOLDER + "/" + RodaConstants.USER_EXTRA_METADATA_FILE)) { String rawTemplate = IOUtils.toString(templateStream, RodaConstants.DEFAULT_ENCODING); Template tmpl = handlebars.compileInline(rawTemplate); if (extra != null) { Set<MetadataValue> values = extra.getValues(); if (values != null) { values.forEach(metadataValue -> { String val = metadataValue.get("value"); if (val != null) { val = val.replaceAll("\\s", ""); if (!"".equals(val)) { data.put(metadataValue.get("name"), metadataValue.get("value")); } } }); } } // result = RodaUtils.indentXML(result); return tmpl.apply(data); } catch (IOException e) { LOGGER.error("Error getting template from stream"); } return ""; } public static void deleteUser(String username) throws GenericException, AuthorizationDeniedException { RodaCoreFactory.getModelService().deleteUser(username, true); RodaCoreFactory.getIndexService().commit(RODAMember.class); } public static void createGroup(Group group) throws GenericException, AlreadyExistsException { RodaCoreFactory.getModelService().createGroup(group, true); RodaCoreFactory.getIndexService().commit(RODAMember.class); } public static void updateGroup(Group group) throws GenericException, NotFoundException, AuthorizationDeniedException { RodaCoreFactory.getModelService().updateGroup(group, true); RodaCoreFactory.getIndexService().commit(RODAMember.class); } public static void deleteGroup(String groupname) throws GenericException, AuthorizationDeniedException { RodaCoreFactory.getModelService().deleteGroup(groupname, true); RodaCoreFactory.getIndexService().commit(RODAMember.class); } public static User confirmUserEmail(String username, String email, String emailConfirmationToken) throws InvalidTokenException, NotFoundException, GenericException { return RodaCoreFactory.getModelService().confirmUserEmail(username, email, emailConfirmationToken, true, true); } public static User requestPasswordReset(String username, String email) throws IllegalOperationException, NotFoundException, GenericException { return RodaCoreFactory.getModelService().requestPasswordReset(username, email, true, true); } public static User resetUserPassword(String username, String password, String resetPasswordToken) throws InvalidTokenException, IllegalOperationException, NotFoundException, GenericException { return RodaCoreFactory.getModelService().resetUserPassword(username, password, resetPasswordToken, true, true); } public static UserExtraBundle retrieveUserExtraBundle(String name) { if (!RodaConstants.SYSTEM_USERS.contains(name)) { String template = null; try (InputStream templateStream = RodaCoreFactory.getConfigurationFileAsStream( RodaConstants.USERS_TEMPLATE_FOLDER + "/" + RodaConstants.USER_EXTRA_METADATA_FILE)) { template = IOUtils.toString(templateStream, RodaConstants.DEFAULT_ENCODING); } catch (IOException e) { LOGGER.error("Error getting template from stream", e); } Set<MetadataValue> values = ServerTools.transform(template); try { User user = RodaCoreFactory.getModelService().retrieveUserByName(name); String userExtra = user.getExtra(); if (userExtra != null && !values.isEmpty()) { for (MetadataValue mv : values) { // clear the auto-generated values // mv.set("value", null); String xpathRaw = mv.get("xpath"); if (xpathRaw != null && xpathRaw.length() > 0) { String[] xpaths = xpathRaw.split("##%##"); String value; List<String> allValues = new ArrayList<>(); for (String xpath : xpaths) { allValues.addAll(ServerTools.applyXpath(userExtra, xpath)); } // if any of the values is different, concatenate all values in a // string, otherwise return the value boolean allEqual = allValues.stream().allMatch(s -> s.trim().equals(allValues.get(0).trim())); if (allEqual && !allValues.isEmpty()) { value = allValues.get(0); } else { value = String.join(" / ", allValues); } mv.set("value", value.trim()); } } } } catch (GenericException e) { // do nothing } return new UserExtraBundle(name, values); } else { return new UserExtraBundle(name); } } public static UserExtraBundle retrieveDefaultExtraBundle() { String template = null; try (InputStream templateStream = RodaCoreFactory.getConfigurationFileAsStream( RodaConstants.USERS_TEMPLATE_FOLDER + "/" + RodaConstants.USER_EXTRA_METADATA_FILE)) { template = IOUtils.toString(templateStream, RodaConstants.DEFAULT_ENCODING); } catch (IOException e) { LOGGER.error("Error getting template from stream", e); } return new UserExtraBundle("", ServerTools.transform(template)); } }