org.openmrs.web.controller.OptionsFormController.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.web.controller.OptionsFormController.java

Source

/**
 * This Source Code Form is subject to the terms of the Mozilla Public License,
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
 *
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
 * graphic logo is a trademark of OpenMRS Inc.
 */
package org.openmrs.web.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.validator.EmailValidator;
import org.openmrs.PersonName;
import org.openmrs.User;
import org.openmrs.api.APIException;
import org.openmrs.api.AdministrationService;
import org.openmrs.api.LocationService;
import org.openmrs.api.PasswordException;
import org.openmrs.api.UserService;
import org.openmrs.api.context.Context;
import org.openmrs.messagesource.MessageSourceService;
import org.openmrs.util.OpenmrsConstants;
import org.openmrs.util.OpenmrsUtil;
import org.openmrs.util.PrivilegeConstants;
import org.openmrs.validator.ValidateUtil;
import org.openmrs.web.OptionsForm;
import org.openmrs.web.WebConstants;
import org.openmrs.web.WebUtil;
import org.openmrs.web.user.UserProperties;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.ObjectError;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.view.RedirectView;

/**
 * This is the controller for the "My Profile" page. This lets logged in users set personal
 * preferences, update their own information, etc.
 *
 * @see OptionsForm
 */
public class OptionsFormController extends SimpleFormController {

    /** Logger for this class and subclasses */
    protected final Log log = LogFactory.getLog(getClass());

    /**
     * @see org.springframework.web.servlet.mvc.AbstractFormController#processFormSubmission(javax.servlet.http.HttpServletRequest,
     *      javax.servlet.http.HttpServletResponse, java.lang.Object,
     *      org.springframework.validation.BindException)
     */
    protected ModelAndView processFormSubmission(HttpServletRequest request, HttpServletResponse response,
            Object object, BindException errors) throws Exception {
        OptionsForm opts = (OptionsForm) object;

        if (!"".equals(opts.getOldPassword())) {
            if ("".equals(opts.getNewPassword())) {
                errors.rejectValue("newPassword", "error.password.weak");
            } else if (!opts.getNewPassword().equals(opts.getConfirmPassword())) {
                errors.rejectValue("newPassword", "error.password.match");
                errors.rejectValue("confirmPassword", "error.password.match");
            }
        }

        if ("".equals(opts.getSecretQuestionPassword()) && opts.getSecretAnswerNew().isEmpty()
                && !opts.getSecretQuestionNew().equals(opts.getSecretQuestionCopy())) {
            errors.rejectValue("secretQuestionPassword", "error.password.incorrect");
        }

        if (!"".equals(opts.getSecretQuestionPassword())) {
            if (!opts.getSecretAnswerConfirm().equals(opts.getSecretAnswerNew())) {
                errors.rejectValue("secretAnswerNew", "error.options.secretAnswer.match");
                errors.rejectValue("secretAnswerConfirm", "error.options.secretAnswer.match");
            }
            if (opts.getSecretAnswerNew().isEmpty()) {
                errors.rejectValue("secretAnswerNew", "error.options.secretAnswer.empty");
            }
            if (opts.getSecretQuestionNew().isEmpty()) {
                errors.rejectValue("secretQuestionNew", "error.options.secretQuestion.empty");
            }
        }

        return super.processFormSubmission(request, response, object, errors);
    }

    /**
     * The onSubmit function receives the form/command object that was modified by the input form
     * and saves it to the db
     *
     * @see org.springframework.web.servlet.mvc.SimpleFormController#onSubmit(javax.servlet.http.HttpServletRequest,
     *      javax.servlet.http.HttpServletResponse, java.lang.Object,
     *      org.springframework.validation.BindException)
     * @should accept 2 characters as username
     * @should accept email address as username if enabled
     * @should reject 1 character as username
     * @should reject invalid email address as username if enabled
     */
    protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object obj,
            BindException errors) throws Exception {

        HttpSession httpSession = request.getSession();

        String view = getFormView();

        if (!errors.hasErrors()) {
            User loginUser = Context.getAuthenticatedUser();
            UserService us = Context.getUserService();
            User user = null;
            try {
                Context.addProxyPrivilege(PrivilegeConstants.GET_USERS);
                user = us.getUser(loginUser.getUserId());
            } finally {
                Context.removeProxyPrivilege(PrivilegeConstants.GET_USERS);
            }

            OptionsForm opts = (OptionsForm) obj;

            Map<String, String> properties = user.getUserProperties();

            properties.put(OpenmrsConstants.USER_PROPERTY_DEFAULT_LOCATION, opts.getDefaultLocation());

            Locale locale = WebUtil.normalizeLocale(opts.getDefaultLocale());
            if (locale != null) {
                properties.put(OpenmrsConstants.USER_PROPERTY_DEFAULT_LOCALE, locale.toString());
            }

            properties.put(OpenmrsConstants.USER_PROPERTY_PROFICIENT_LOCALES,
                    WebUtil.sanitizeLocales(opts.getProficientLocales()));
            properties.put(OpenmrsConstants.USER_PROPERTY_SHOW_RETIRED, opts.getShowRetiredMessage().toString());
            properties.put(OpenmrsConstants.USER_PROPERTY_SHOW_VERBOSE, opts.getVerbose().toString());
            properties.put(OpenmrsConstants.USER_PROPERTY_NOTIFICATION,
                    opts.getNotification() == null ? "" : opts.getNotification().toString());
            properties.put(OpenmrsConstants.USER_PROPERTY_NOTIFICATION_ADDRESS,
                    opts.getNotificationAddress() == null ? "" : opts.getNotificationAddress().toString());

            if (!"".equals(opts.getOldPassword())) {
                try {
                    String password = opts.getNewPassword();

                    // check password strength
                    if (password.length() > 0) {
                        try {
                            OpenmrsUtil.validatePassword(user.getUsername(), password,
                                    String.valueOf(user.getUserId()));
                        } catch (PasswordException e) {
                            errors.reject(e.getMessage());
                        }
                        if (password.equals(opts.getOldPassword()) && !errors.hasErrors()) {
                            errors.reject("error.password.different");
                        }

                        if (!password.equals(opts.getConfirmPassword())) {
                            errors.reject("error.password.match");
                        }
                    }

                    if (!errors.hasErrors()) {
                        us.changePassword(opts.getOldPassword(), password);
                        if (opts.getSecretQuestionPassword().equals(opts.getOldPassword())) {
                            opts.setSecretQuestionPassword(password);
                        }
                        new UserProperties(user.getUserProperties()).setSupposedToChangePassword(false);
                    }
                } catch (APIException e) {
                    errors.rejectValue("oldPassword", "error.password.match");
                }
            } else {
                // if they left the old password blank but filled in new
                // password
                if (!"".equals(opts.getNewPassword())) {
                    errors.rejectValue("oldPassword", "error.password.incorrect");
                }
            }

            if (!"".equals(opts.getSecretQuestionPassword())) {
                if (!errors.hasErrors()) {
                    try {
                        us.changeQuestionAnswer(opts.getSecretQuestionPassword(), opts.getSecretQuestionNew(),
                                opts.getSecretAnswerNew());
                    } catch (APIException e) {
                        errors.rejectValue("secretQuestionPassword", "error.password.match");
                    }
                }
            } else if (!"".equals(opts.getSecretAnswerNew())) {
                // if they left the old password blank but filled in new
                // password
                errors.rejectValue("secretQuestionPassword", "error.password.incorrect");
            }

            String notifyType = opts.getNotification();
            if (notifyType != null && (notifyType.equals("internal") || notifyType.equals("internalProtected")
                    || notifyType.equals("email"))) {
                if (opts.getNotificationAddress().isEmpty()) {
                    errors.reject("error.options.notificationAddress.empty");
                } else if (!EmailValidator.getInstance().isValid(opts.getNotificationAddress())) {
                    errors.reject("error.options.notificationAddress.invalid");
                }
            }

            if (opts.getUsername().length() > 0 && !errors.hasErrors()) {
                try {
                    Context.addProxyPrivilege(PrivilegeConstants.GET_USERS);
                    if (us.hasDuplicateUsername(user)) {
                        errors.rejectValue("username", "error.username.taken");
                    }
                } finally {
                    Context.removeProxyPrivilege(PrivilegeConstants.GET_USERS);
                }
            }

            if (!errors.hasErrors()) {
                user.setUsername(opts.getUsername());
                user.setUserProperties(properties);

                // new name
                PersonName newPersonName = opts.getPersonName();

                // existing name
                PersonName existingPersonName = user.getPersonName();

                // if two are not equal then make the new one the preferred,
                // make the old one voided
                if (!existingPersonName.equalsContent(newPersonName)) {
                    existingPersonName.setPreferred(false);
                    existingPersonName.setVoided(true);
                    existingPersonName.setVoidedBy(user);
                    existingPersonName.setDateVoided(new Date());
                    existingPersonName.setVoidReason("Changed name on own options form");

                    newPersonName.setPreferred(true);
                    user.addName(newPersonName);
                }

                Errors userErrors = new BindException(user, "user");
                ValidateUtil.validate(user, userErrors);

                if (userErrors.hasErrors()) {
                    for (ObjectError error : userErrors.getAllErrors()) {
                        errors.reject(error.getCode(), error.getArguments(), "");
                    }
                }

                if (errors.hasErrors()) {
                    return super.processFormSubmission(request, response, opts, errors);
                }

                try {
                    Context.addProxyPrivilege(PrivilegeConstants.EDIT_USERS);
                    Context.addProxyPrivilege(PrivilegeConstants.GET_USERS);

                    us.saveUser(user);
                    //trigger updating of the javascript file cache
                    PseudoStaticContentController.invalidateCachedResources(properties);
                    // update login user object so that the new name is visible
                    // in the webapp
                    Context.refreshAuthenticatedUser();
                } finally {
                    Context.removeProxyPrivilege(PrivilegeConstants.EDIT_USERS);
                    Context.removeProxyPrivilege(PrivilegeConstants.GET_USERS);
                }

                httpSession.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "options.saved");
            } else {
                return super.processFormSubmission(request, response, opts, errors);
            }

            view = getSuccessView();
        }
        return new ModelAndView(new RedirectView(view));
    }

    /**
     * This is called prior to displaying a form for the first time. It tells Spring the
     * form/command object to load into the request
     *
     * @see org.springframework.web.servlet.mvc.AbstractFormController#formBackingObject(javax.servlet.http.HttpServletRequest)
     */
    protected Object formBackingObject(HttpServletRequest request) throws ServletException {

        OptionsForm opts = new OptionsForm();

        if (Context.isAuthenticated()) {
            User user = Context.getAuthenticatedUser();

            Map<String, String> props = user.getUserProperties();
            opts.setDefaultLocation(props.get(OpenmrsConstants.USER_PROPERTY_DEFAULT_LOCATION));
            opts.setDefaultLocale(props.get(OpenmrsConstants.USER_PROPERTY_DEFAULT_LOCALE));
            opts.setProficientLocales(props.get(OpenmrsConstants.USER_PROPERTY_PROFICIENT_LOCALES));
            opts.setShowRetiredMessage(new Boolean(props.get(OpenmrsConstants.USER_PROPERTY_SHOW_RETIRED)));
            opts.setVerbose(new Boolean(props.get(OpenmrsConstants.USER_PROPERTY_SHOW_VERBOSE)));
            opts.setUsername(user.getUsername());

            PersonName personName;
            if (user.getPersonName() != null) {
                // Get a copy of the current person name and clear the id so that
                // they are separate objects
                personName = PersonName.newInstance(user.getPersonName());
                personName.setPersonNameId(null);
            } else {
                // use blank person name
                personName = new PersonName();
            }
            opts.setPersonName(personName);
            opts.setNotification(props.get(OpenmrsConstants.USER_PROPERTY_NOTIFICATION));
            opts.setNotificationAddress(props.get(OpenmrsConstants.USER_PROPERTY_NOTIFICATION_ADDRESS));
        }

        return opts;
    }

    /**
     * Called prior to form display. Allows for data to be put in the request to be used in the view
     *
     * @see org.springframework.web.servlet.mvc.SimpleFormController#referenceData(javax.servlet.http.HttpServletRequest)
     */
    protected Map<String, Object> referenceData(HttpServletRequest request) throws Exception {

        HttpSession httpSession = request.getSession();

        Map<String, Object> map = new HashMap<String, Object>();

        if (Context.isAuthenticated()) {

            LocationService ls = Context.getLocationService();

            // set location options
            map.put("locations", ls.getAllLocations());

            AdministrationService as = Context.getAdministrationService();

            // set language/locale options
            map.put("languages", as.getPresentationLocales());

            Object resetPasswordAttribute = httpSession.getAttribute("resetPassword");
            if (resetPasswordAttribute == null) {
                resetPasswordAttribute = "";
            } else {
                httpSession.removeAttribute("resetPassword");
            }
            map.put("resetPassword", resetPasswordAttribute);

            //generate the password hint depending on the security GP settings
            List<String> hints = new ArrayList<String>(5);
            int minChar = 1;
            MessageSourceService mss = Context.getMessageSourceService();
            try {
                String minCharStr = as.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_MINIMUM_LENGTH);
                if (StringUtils.isNotBlank(minCharStr)) {
                    minChar = Integer.valueOf(minCharStr);
                }
                if (minChar < 1) {
                    minChar = 1;
                }
            } catch (NumberFormatException e) {
                //ignore
            }

            hints.add(mss.getMessage("options.login.password.minCharacterCount", new Object[] { minChar }, null));
            addHint(hints, as.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_CANNOT_MATCH_USERNAME_OR_SYSTEMID),
                    mss.getMessage("options.login.password.cannotMatchUsername"));
            addHint(hints, as.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_UPPER_AND_LOWER_CASE),
                    mss.getMessage("options.login.password.containUpperCase"));
            addHint(hints, as.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_DIGIT),
                    mss.getMessage("options.login.password.containNumber"));
            addHint(hints, as.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_NON_DIGIT),
                    mss.getMessage("options.login.password.containNonNumber"));

            StringBuilder passwordHint = new StringBuilder("");
            for (int i = 0; i < hints.size(); i++) {
                if (i == 0) {
                    passwordHint.append(hints.get(i));
                } else if (i < (hints.size() - 1)) {
                    passwordHint.append(", ").append(hints.get(i));
                } else {
                    passwordHint.append(" and ").append(hints.get(i));
                }
            }

            map.put("passwordHint", passwordHint.toString());

        }

        return map;
    }

    /**
     * Utility method that check if a security property with boolean values is enabled and adds hint
     * message for it if it is not blank
     *
     * @param hints
     * @param gpValue the value of the global property
     * @param message the localized message to add
     */
    private void addHint(List<String> hints, String gpValue, String message) {
        if (Boolean.valueOf(gpValue) && !StringUtils.isBlank(message)) {
            hints.add(message);
        }
    }
}