From: <gem...@li...> - 2011-11-10 17:15:22
|
Revision: 200 http://gemstracker.svn.sourceforge.net/gemstracker/?rev=200&view=rev Author: matijsdejong Date: 2011-11-10 17:15:11 +0000 (Thu, 10 Nov 2011) Log Message: ----------- Almost ready with #31. The user can edit his/her account and password. getAllowedOrganizations moved to User and UserLoader GemsEscort cleaned up TODO: lost password Modified Paths: -------------- branches/newUser2/classes/Gems/Default/AskAction.php branches/newUser2/classes/Gems/Default/ExportAction.php branches/newUser2/classes/Gems/Default/IndexAction.php branches/newUser2/classes/Gems/Default/OptionAction.php branches/newUser2/classes/Gems/Default/OrganizationAction.php branches/newUser2/classes/Gems/Project/Organization/MultiOrganizationInterface.php branches/newUser2/classes/Gems/User/User.php branches/newUser2/classes/Gems/User/UserLoader.php branches/newUser2/classes/GemsEscort.php Added Paths: ----------- branches/newUser2/classes/Gems/User/UserPasswordValidator.php Modified: branches/newUser2/classes/Gems/Default/AskAction.php =================================================================== --- branches/newUser2/classes/Gems/Default/AskAction.php 2011-11-10 15:47:29 UTC (rev 199) +++ branches/newUser2/classes/Gems/Default/AskAction.php 2011-11-10 17:15:11 UTC (rev 200) @@ -82,13 +82,14 @@ /*************** * Get the url * ***************/ - $url = $token->getUrl($language, $this->session->user_id ? $this->session->user_id : $respId); + $user = $this->loader->getCurrentUser(); + $url = $token->getUrl($language, $user->getUserId() ? $user->getUserId() : $respId); /************************ * Optional user logout * ************************/ - if (isset($this->session->user_logout) && $this->session->user_logout) { - $this->escort->afterLogout(); + if ($user->isLogoutOnSurvey()) { + $user->unsetAsCurrentUser(); } /*********************************** Modified: branches/newUser2/classes/Gems/Default/ExportAction.php =================================================================== --- branches/newUser2/classes/Gems/Default/ExportAction.php 2011-11-10 15:47:29 UTC (rev 199) +++ branches/newUser2/classes/Gems/Default/ExportAction.php 2011-11-10 17:15:11 UTC (rev 200) @@ -144,7 +144,7 @@ { //Read some data from tables, initialize defaults... $surveys = $this->db->fetchPairs('SELECT gsu_id_survey, gsu_survey_name FROM gems__surveys WHERE gsu_active = 1 ORDER BY gsu_survey_name'); - $organizations = $this->escort->getAllowedOrganizations(); + $organizations = $this->loader->getCurrentUser()->getAllowedOrganizations(); $types = $this->export->getExportClasses(); //Create the basic form @@ -230,7 +230,7 @@ $answerModel = $survey->getAnswerModel($language); //Now add the organization id => name mapping - $answerModel->set('organizationid', 'multiOptions', $this->escort->getAllowedOrganizations()); + $answerModel->set('organizationid', 'multiOptions', $this->loader->getCurrentUser()->getAllowedOrganizations()); if (count($answers) === 0) { $answers[0] = array('' => sprintf($this->_('No %s found.'), $this->getTopic(0))); Modified: branches/newUser2/classes/Gems/Default/IndexAction.php =================================================================== --- branches/newUser2/classes/Gems/Default/IndexAction.php 2011-11-10 15:47:29 UTC (rev 199) +++ branches/newUser2/classes/Gems/Default/IndexAction.php 2011-11-10 17:15:11 UTC (rev 200) @@ -66,21 +66,6 @@ public $menu; /** - * Extension point, use different auth adapter if needed depending on the provided formValues - * - * This could be an organization passed in the login-form or something else. - * - * @param array $formValues - * @return Zend_Auth_Adapter_Interface - */ - protected function _getAuthAdapter($formValues) { - $adapter = new Zend_Auth_Adapter_DbTable($this->db, 'gems__staff', 'gsf_login', 'gsf_password'); - $adapter->setIdentity($formValues['userlogin']); - $adapter->setCredential($this->escort->passwordHash(null, $formValues['password'], false)); - return $adapter; - } - - /** * New version of login form * * @return Gems_Form @@ -89,8 +74,6 @@ { Gems_Html::init(); - $this->track[] = 'Get login form.'; - $delayFactor = (isset($this->project->account) && isset($this->project->account['delayFactor']) ? $this->project->account['delayFactor'] : null); $form = new Gems_Form(array('labelWidthFactor' => $this->labelWidthFactor)); Modified: branches/newUser2/classes/Gems/Default/OptionAction.php =================================================================== --- branches/newUser2/classes/Gems/Default/OptionAction.php 2011-11-10 15:47:29 UTC (rev 199) +++ branches/newUser2/classes/Gems/Default/OptionAction.php 2011-11-10 17:15:11 UTC (rev 200) @@ -1,6 +1,5 @@ <?php - /** * Copyright (c) 2011, Erasmus MC * All rights reserved. @@ -26,58 +25,47 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** * - * @author Matijs de Jong - * @since 1.0 - * @version 1.1 - * @package Gems + * + * @package Gems * @subpackage Default + * @author Matijs de Jong <mj...@ma...> + * @copyright Copyright (c) 2011 Erasmus MC + * @license New BSD License + * @version $Id$ */ /** * - * @author Matijs de Jong - * @package Gems + * @package Gems * @subpackage Default + * @copyright Copyright (c) 2011 Erasmus MC + * @license New BSD License + * @since Class available since version 1.1 */ class Gems_Default_OptionAction extends Gems_Controller_BrowseEditAction { public $autoFilter = false; /** - * Adds elements from the model to the bridge that creates the form. * - * Overrule this function to add different elements to the browse table, without - * having to recode the core table building code. - * - * @param MUtil_Model_FormBridge $bridge - * @param MUtil_Model_ModelAbstract $model - * @param array $data The data that will later be loaded into the form - * @param optional boolean $new Form should be for a new element - * @return void|array When an array of new values is return, these are used to update the $data array in the calling function + * @var Gems_Project_ProjectSettings */ - protected function addFormElements(MUtil_Model_FormBridge $bridge, MUtil_Model_ModelAbstract $model, array $data, $new = false) - { - $bridge->addHidden( 'gus_id_user'); - $bridge->addHidden( 'gus_id_organization'); - $bridge->addHidden( 'gsf_id_user'); - $bridge->addExhibitor('gus_login', array('size' => 15, 'minlength' => 4)); - $bridge->addText( 'gsf_first_name'); - $bridge->addText( 'gsf_surname_prefix'); - $bridge->addText( 'gsf_last_name'); - $bridge->addText( 'gsf_email', array('size' => 30)); + public $project; - $bridge->addRadio( 'gsf_gender', 'separator', ''); - - $bridge->addSelect( 'gsf_iso_lang', array('label' => $this->_('Language'), 'multiOptions' => $this->util->getLocalized()->getLanguages())); - } - + /** + * Hook to perform action after a record (with changes) was saved + * + * As the data was already saved, it can NOT be changed anymore + * + * @param array $data + * @param boolean $isNew + * @return boolean True when you want to display the default 'saved' messages + */ public function afterSave(array $data, $isNew) { - $this->escort->loadLoginInfo($data['gus_login']); + // Reload the current user data + $this->loader->getUser($data['gsf_login'], $data['gsf_id_organization']); } public function changePasswordAction() @@ -87,20 +75,26 @@ *************/ $form = $this->createForm(); - $sql = "SELECT CASE WHEN gus_password IS NULL THEN 0 ELSE 1 END FROM gems__users WHERE gus_id_user = ? AND gus_id_organization = ?"; - if ($this->db->fetchOne($sql, array($this->session->user_id, $this->session->user_organization_id))) { - // Veld current password + $user = $this->loader->getCurrentUser(); + + $sql = "SELECT CASE WHEN gup_password IS NULL THEN 0 ELSE 1 END FROM gems__user_passwords WHERE gup_id_user = ?"; + + if ($this->db->fetchOne($sql, $user->getUserLoginId())) { + // Field current password + // + // This is only used when the password is already set, which may not always be the case + // e.g. when using embedded login in Pulse. $element = new Zend_Form_Element_Password('old_password'); $element->setLabel($this->_('Current password')); $element->setAttrib('size', 10); $element->setAttrib('maxlength', 20); $element->setRenderPassword(true); $element->setRequired(true); - $element->addValidator(new Gems_Validate_GemsPasswordUsername($this->session->user_login, 'old_password', $this->db)); + $element->addValidator(new Gems_User_UserPasswordValidator($user, $this->translate)); $form->addElement($element); } - // Veld new password + // Field new password $element = new Zend_Form_Element_Password('new_password'); $element->setLabel($this->_('New password')); $element->setAttrib('size', 10); @@ -111,7 +105,7 @@ $element->addValidator(new MUtil_Validate_IsConfirmed('repeat_password', $this->_('Repeat password'))); $form->addElement($element); - // Veld repeat password + // Field repeat password $element = new Zend_Form_Element_Password('repeat_password'); $element->setLabel($this->_('Repeat password')); $element->setAttrib('size', 10); @@ -131,20 +125,15 @@ ****************/ if ($this->_request->isPost() && $form->isValid($_POST)) { - $data['gus_id_user'] = $this->session->user_id; - $data['gus_id_organization'] = $this->session->user_organization_id; - $data['gus_password'] = $this->escort->passwordHash(null, $_POST['new_password']); + $data['gup_id_user'] = $user->getUserLoginId(); + $data['gup_password'] = $this->project->getValueHash($_POST['new_password']); - $this->getModel()->save($data); + $model = new MUtil_Model_TableModel('gems__user_passwords'); + Gems_Model::setChangeFieldsByPrefix($model, 'gup', $user->getUserId()); - // $data = $_POST; - // $data['name'] = ''; - // $data['type'] = $this->_('raw'); - - // $results = array(); - // $this->_runScript($data, $results); + $model->save($data); $this->addMessage($this->_('New password is active.')); - $this->afterSaveRoute($this->getRequest()); + $this->_reroute(array($this->getRequest()->getActionKey() => 'edit')); } else { if (isset($_POST['old_password'])) { @@ -185,23 +174,23 @@ */ public function createModel($detailed, $action) { - $model = new Gems_Model_UserModel('staff', 'gems__staff', array('gus_id_user' => 'gsf_id_user'), 'gsf'); - $model->copyKeys(); + $model = $this->loader->getModels()->getStaffModel(); - $model->set('gus_login', 'label', $this->_('Login Name')); - $model->set('gsf_email', 'label', $this->_('E-Mail')); - $model->set('gsf_first_name', 'label', $this->_('First name')); - $model->set('gsf_surname_prefix', 'label', $this->_('Surname prefix'), 'description', 'de, van der, \'t, etc...'); - $model->set('gsf_last_name', 'label', $this->_('Last name'), 'required', true); + $model->set('gsf_login', 'label', $this->_('Login Name'), 'elementClass', 'Exhibitor'); + $model->set('gsf_email', 'label', $this->_('E-Mail'), 'size', 30); + $model->set('gsf_first_name', 'label', $this->_('First name')); + $model->set('gsf_surname_prefix', 'label', $this->_('Surname prefix'), 'description', 'de, van der, \'t, etc...'); + $model->set('gsf_last_name', 'label', $this->_('Last name'), 'required', true); + $model->set('gsf_gender', 'label', $this->_('Gender'), 'multiOptions', $this->util->getTranslated()->getGenders(), + 'elementClass', 'Radio', 'separator', ''); + $model->set('gsf_iso_lang', 'label', $this->_('Language'), 'multiOptions', $this->util->getLocalized()->getLanguages()); - $model->set('gsf_gender', 'label', $this->_('Gender'), 'multiOptions', $this->util->getTranslated()->getGenders()); - return $model; } public function editAction() { - $this->getModel()->setFilter(array('gus_id_user' => $this->session->user_id)); + $this->getModel()->setFilter(array('gsf_id_user' => $this->loader->getCurrentUser()->getUserId())); if ($form = $this->processForm()) { $this->html->h3(sprintf($this->_('Options'), $this->getTopic())); @@ -222,7 +211,7 @@ WHERE glac.glac_name = 'index.login' ORDER BY glua.glua_created DESC LIMIT 10"; - $activity = $this->db->fetchAll($sql, $this->session->user_id); + $activity = $this->db->fetchAll($sql, $this->loader->getCurrentUser()->getUserId()); foreach (array_keys($activity) as $key) { $date = new MUtil_Date($activity[$key]['glua_created']); Modified: branches/newUser2/classes/Gems/Default/OrganizationAction.php =================================================================== --- branches/newUser2/classes/Gems/Default/OrganizationAction.php 2011-11-10 15:47:29 UTC (rev 199) +++ branches/newUser2/classes/Gems/Default/OrganizationAction.php 2011-11-10 17:15:11 UTC (rev 200) @@ -50,7 +50,7 @@ $url = base64_decode($request->getParam('current_uri')); $oldOrgId = $this->session->user_organization_id; - $allowedOrganizations = $this->escort->getAllowedOrganizations(); + $allowedOrganizations = $this->loader->getCurrentUser()->getAllowedOrganizations(); if ($orgId = array_search($org, $allowedOrganizations)) { $this->session->user_organization_id = $orgId; $this->session->user_organization_name = $allowedOrganizations[$orgId]; Modified: branches/newUser2/classes/Gems/Project/Organization/MultiOrganizationInterface.php =================================================================== --- branches/newUser2/classes/Gems/Project/Organization/MultiOrganizationInterface.php 2011-11-10 15:47:29 UTC (rev 199) +++ branches/newUser2/classes/Gems/Project/Organization/MultiOrganizationInterface.php 2011-11-10 17:15:11 UTC (rev 200) @@ -1,34 +1,34 @@ <?php - -/** - * Copyright (c) 2011, Erasmus MC - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Erasmus MC nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - + /** + * Copyright (c) 2011, Erasmus MC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Erasmus MC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** * Marker interface for Pulse Projects having respondents * in only multiple organization. * @@ -49,9 +49,4 @@ interface Gems_Project_Organization_MultiOrganizationInterface { public function getUserOrganization(); - - /** - * Return an array of OrgId=>OrgName with all organizations the currently logged in user has access to - */ - public function getAllowedOrganizations($userId = null); } Modified: branches/newUser2/classes/Gems/User/User.php =================================================================== --- branches/newUser2/classes/Gems/User/User.php 2011-11-10 15:47:29 UTC (rev 199) +++ branches/newUser2/classes/Gems/User/User.php 2011-11-10 17:15:11 UTC (rev 200) @@ -191,9 +191,19 @@ if (! $this->_vars instanceof Zend_Session_Namespace) { $sessionStore = $this->session; - if (($sessionStore->__get('user_name') == $this->_vars->offsetGet('user_name')) && - ($sessionStore->__get('user_organization_id') == $this->_vars->offsetGet('user_organization_id'))) { + $notCurrent = true; + foreach (array('user_id', 'user_organization_id') as $key) { + if ($sessionStore->__isset($key) && $this->_vars->offsetGet($key)) { + $notCurrent = $sessionStore->__get($key) != $this->_vars->offsetGet($key); + } else { + $notCurrent = $sessionStore->__isset($key) || $this->_vars->offsetGet($key); + } + if ($notCurrent) { + break; + } + } + if (! $notCurrent) { // When this is the case, use the Zend_Session_Namespace object with the current set values // This way changes to this user object are reflected in the CurrentUser object and vice versa. $this->setAsCurrentUser(); @@ -203,6 +213,16 @@ } /** + * Get an array of OrgId => Org Name for all allowed organizations for the current loggedin user + * + * @return array + */ + public function getAllowedOrganizations() + { + return $this->_getVar('allowedOrgs'); + } + + /** * Returns the full user name (first, prefix, last). * * @return string @@ -251,7 +271,12 @@ } /** + * Returns the user id, that identifies this user within this installation. * + * One user id might be connected to multiple logins for multiple organizations. + * + * YES! This is the one you need, not getUserLoginId(). + * * @return int */ public function getUserId() @@ -260,7 +285,24 @@ } /** + * Returns the User package user id, that is unique for each login / organization id + * combination, but does not directly identify this person. * + * In other words, this is not the id you use to track who changed what. It is only + * used by parts of the User package. + * + * @return int + */ + public function getUserLoginId() + { + if ($this->_hasVar('user_login_id')) { + return $this->_getVar('user_login_id'); + } + return 0; + } + + /** + * * @return boolean True when a user can log in. */ public function isActive() @@ -279,6 +321,16 @@ } /** + * True when this user requires a logout after answering a survey + * + * @return boolean + */ + public function isLogoutOnSurvey() + { + return (boolean) $this->_getVar('user_logout'); + } + + /** * Set this user as the current user. * * This means that the data about this user will be stored in a session. Modified: branches/newUser2/classes/Gems/User/UserLoader.php =================================================================== --- branches/newUser2/classes/Gems/User/UserLoader.php 2011-11-10 15:47:29 UTC (rev 199) +++ branches/newUser2/classes/Gems/User/UserLoader.php 2011-11-10 17:15:11 UTC (rev 200) @@ -268,6 +268,16 @@ } /** + * Get an array of OrgId => Org Name for all allowed organizations for the current loggedin user + * + * @return array + */ + public function getAllowedOrganizations() + { + return $this->db->fetchPairs("SELECT gor_id_organization, gor_name FROM gems__organizations WHERE gor_active = 1 ORDER BY gor_name"); + } + + /** * Get the currently loggin in user * * @return Gems_User_User @@ -319,7 +329,8 @@ ->where('gsf_login = ?') ->limit(1); - //For a multi-layout project we need to select the appropriate style too + // For a multi-layout project we need to select the appropriate style too, + // but as PATCHES may not be in effect we have to try two selects $select2 = clone $select; $select2->columns(array('user_style' => 'gor_style'), 'gems__organizations'); @@ -370,8 +381,9 @@ protected function getStaffUser($login_name, $organization) { $select = new Zend_Db_Select($this->db); - $select->from('gems__user_logins', array('user_login' => 'gul_login')) + $select->from('gems__user_logins', array('user_login_id' => 'gul_id_user')) ->join('gems__staff', 'gul_login = gsf_login AND gul_id_organization = gsf_id_organization', array( + 'user_login' => 'gsf_login', 'user_id' => 'gsf_id_user', 'user_email'=>'gsf_email', 'user_group'=>'gsf_id_primary_group', @@ -433,6 +445,11 @@ $values['user_active'] = true; } + if (! isset($values['allowedOrgs'])) { + //Load the allowed organizations + $values['allowedOrgs'] = $this->getAllowedOrganizations(); + } + return $this->_loadClass('User', true, array($values)); } Added: branches/newUser2/classes/Gems/User/UserPasswordValidator.php =================================================================== --- branches/newUser2/classes/Gems/User/UserPasswordValidator.php (rev 0) +++ branches/newUser2/classes/Gems/User/UserPasswordValidator.php 2011-11-10 17:15:11 UTC (rev 200) @@ -0,0 +1,118 @@ +<?php + +/** + * Copyright (c) 2011, Erasmus MC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Erasmus MC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * @package Gems + * @subpackage User + * @author Matijs de Jong <mj...@ma...> + * @copyright Copyright (c) 2011 Erasmus MC + * @license New BSD License + * @version $Id: Sample.php 203 2011-07-07 12:51:32Z matijs $ + */ + +/** + * + * + * @package Gems + * @subpackage User + * @copyright Copyright (c) 2011 Erasmus MC + * @license New BSD License + * @since Class available since version 1.5 + */ +class Gems_User_UserPasswordValidator implements Zend_Validate_Interface +{ + /** + * + * @var Gems_User_User + */ + private $_user; + + /** + * + * @var Zend_Translate + */ + private $_translate; + + /** + * + * @var boolean + */ + private $_valid = false; + + /** + * + * @param Gems_User_User $user The user to check + * @param Zend_Translate $translate Optional translator + */ + public function __construct(Gems_User_User $user, Zend_Translate $translate = null) + { + $this->_user = $user; + $this->_translate = $translate ? $translate : new MUtil_Translate_Adapter_Potemkin(); + } + + /** + * Returns true if and only if $value meets the validation requirements + * + * If $value fails validation, then this method returns false, and + * getMessages() will return an array of messages that explain why the + * validation failed. + * + * @param mixed $value + * @param mixed $content + * @return boolean + * @throws Zend_Validate_Exception If validation of $value is impossible + */ + public function isValid($value, $context = array()) + { + $this->_valid = $this->_user->checkPassword($value); + + return $this->_valid; + } + + /** + * Returns an array of messages that explain why the most recent isValid() + * call returned false. The array keys are validation failure message identifiers, + * and the array values are the corresponding human-readable message strings. + * + * If isValid() was never called or if the most recent isValid() call + * returned true, then this method returns an empty array. + * + * @return array + */ + public function getMessages() + { + if ($this->_valid) { + return array(); + + } else { + return array($this->_translate->_('Wrong password.')); + } + + + } +} Modified: branches/newUser2/classes/GemsEscort.php =================================================================== --- branches/newUser2/classes/GemsEscort.php 2011-11-10 15:47:29 UTC (rev 199) +++ branches/newUser2/classes/GemsEscort.php 2011-11-10 17:15:11 UTC (rev 200) @@ -791,7 +791,7 @@ 'controller' => 'organization', 'action' => 'change-ui'), null, true); $orgSwitch->raw('<form method="get" action="' . $url . '"><div><input type="hidden" name="current_uri" value="' . $currentUri . '" /><select name="org" onchange="javascript:this.form.submit();">'); - foreach ($this->getAllowedOrganizations() as $id => $org) { + foreach ($this->getLoader()->getCurrentUser()->getAllowedOrganizations() as $id => $org) { $selected = ''; if ($id == $this->session->user_organization_id) { $selected = ' selected="selected"'; @@ -924,43 +924,6 @@ } } - public function afterLogin($userName = null) - { - if (empty($userName)) { - $userName = $_POST['userlogin']; - } - - /** - * Reset number of failed logins - */ - try { - $sql = "UPDATE gems__user_logins SET gul_failed_logins = 0, gul_last_failed = NULL, gul_changed = CURRENT_TIMESTAMP WHERE gul_login = ?"; - $this->db->query($sql, array($userName)); - } catch (Exception $e) { - // swallow exception - } - } - - public function afterFailedLogin() - { - /** - * Store the failed login attempt - */ - try { - if (isset($_POST['userlogin'])) { - $sql = "UPDATE gems__user_logins SET gul_failed_logins = gul_failed_logins + 1, gul_last_failed = NOW(), gul_changed = CURRENT_TIMESTAMP WHERE gul_login = ?"; - $this->db->query($sql, array($_POST['userlogin'])); - } - } catch (Exception $e) { - // swallow exception - } - } - - public function afterLogout() - { - $this->session->unsetAll(); - } - /** * Hook 2: Called in $this->run(). * @@ -1091,27 +1054,7 @@ } /** - * Get an array of OrgId => Org Name for all allowed organizations for the current loggedin user * - * @@TODO Make ui to store allowed orgs in staff controller and change function to read these - * - * @return array - */ - public function getAllowedOrganizations($userId = null) - { - if (is_null($userId)) $userId = $this->session->user_id; - if ($userId == $this->session->user_id && isset($this->session->allowedOrgs)) { - //If user is current user, read from session - $allowedOrganizations = $this->session->allowedOrgs; - } else { - $allowedOrganizations = $this->db->fetchPairs("SELECT gor_id_organization, gor_name FROM gems__organizations WHERE gor_active = 1 ORDER BY gor_name"); - } - - return $allowedOrganizations; - } - - /** - * * @return int The current active organization id or 0 when not known */ public function getCurrentOrganization() @@ -1137,11 +1080,9 @@ */ public function getCurrentUserId() { - if (isset($this->session->user_id)) { - return $this->session->user_id; - } else { - return 0; - } + $id = $this->getLoader()->getCurrentUser()->getUserId(); + + return $id ? $id : 0; } public function getDatabasePaths() @@ -1270,52 +1211,11 @@ return false; } - public function loadLoginInfo($userName) - { - /** - * Read the needed parameters from the different tables, lots of renames for backward - * compatibility - */ - $select = new Zend_Db_Select($this->db); - $select->from('gems__staff', array( - 'user_id' => 'gsf_id_user', - 'user_login' => 'gsf_login', - 'user_email'=>'gsf_email', - 'user_group'=>'gsf_id_primary_group', - 'user_locale'=>'gsf_iso_lang', - 'user_logout'=>'gsf_logout_on_survey')) - ->columns(array('user_name'=>"(concat(coalesce(concat(`gems__staff`.`gsf_first_name`,_utf8' '),_utf8''),coalesce(concat(`gems__staff`.`gsf_surname_prefix`,_utf8' '),_utf8''),coalesce(`gems__staff`.`gsf_last_name`,_utf8'')))")) - ->join('gems__groups', 'gsf_id_primary_group = ggp_id_group', array('user_role'=>'ggp_role')) - ->join('gems__organizations', 'gus_id_organization = gor_id_organization', - array('user_organization_id'=>'gor_id_organization', 'user_organization_name'=>'gor_name')) - ->where('ggp_group_active = ?', 1) - ->where('gor_active = ?', 1) - ->where('gus_active = ?', 1) - ->where('gus_login = ?', $userName) - ->limit(1); - - //For a multi-layout project we need to select the appropriate style too - if ($this instanceof Gems_Project_Layout_MultiLayoutInterface) { - $select->columns(array('user_style' => 'gor_style'), 'gems__organizations'); - } - - - if ($result = $this->db->fetchRow($select, array(), Zend_Db::FETCH_ASSOC)) { - // $this->session is a session object so we cannot use $this->session = $result - foreach ($result as $name => $value) { - $this->session->$name = $value; - } - - if ($this instanceof Gems_Project_Organization_MultiOrganizationInterface) { - //Load the allowed organizations into the session - $this->session->allowedOrgs = $this->getAllowedOrganizations(); - } - } - } - /** * Return a hashed version of the input value. * + * @deprecated Since 1.5 + * * @param string $name Optional name, is here for ModelAbstract setOnSave compatibility * @param string $value The value to hash. * @param boolean $new Optional is new, is here for ModelAbstract setOnSave compatibility This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <gem...@li...> - 2011-11-11 17:48:50
|
Revision: 202 http://gemstracker.svn.sourceforge.net/gemstracker/?rev=202&view=rev Author: matijsdejong Date: 2011-11-11 17:48:42 +0000 (Fri, 11 Nov 2011) Log Message: ----------- Continuing #31: reset password now does send the mail, but the mail cannot be handled yet. Extended possibilities of UserDefinitionInterface.php Found bug in DatabaseModelAbstract.php: did not handle non-date strings well. Modified Paths: -------------- branches/newUser2/classes/Gems/Cookies.php branches/newUser2/classes/Gems/Default/IndexAction.php branches/newUser2/classes/Gems/Default/OptionAction.php branches/newUser2/classes/Gems/Project/ProjectSettings.php branches/newUser2/classes/Gems/User/StaffUserDefinition.php branches/newUser2/classes/Gems/User/User.php branches/newUser2/classes/Gems/User/UserDefinitionAbstract.php branches/newUser2/classes/Gems/User/UserDefinitionInterface.php branches/newUser2/classes/Gems/User/UserLoader.php branches/newUser2/classes/MUtil/Model/DatabaseModelAbstract.php Modified: branches/newUser2/classes/Gems/Cookies.php =================================================================== --- branches/newUser2/classes/Gems/Cookies.php 2011-11-11 11:41:20 UTC (rev 201) +++ branches/newUser2/classes/Gems/Cookies.php 2011-11-11 17:48:42 UTC (rev 202) @@ -26,7 +26,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * + * * @package Gems * @subpackage Cookies * @author Matijs de Jong <mj...@ma...> @@ -127,7 +127,9 @@ */ public static function setOrganization($organization, $basepath = '/') { - // Set the cookie for 30 days - return self::set(self::ORGANIZATION_COOKIE, $organization, 30, $basepath); + if ($organization) { + // Set the cookie for 30 days + return self::set(self::ORGANIZATION_COOKIE, $organization, 30, $basepath); + } } } Modified: branches/newUser2/classes/Gems/Default/IndexAction.php =================================================================== --- branches/newUser2/classes/Gems/Default/IndexAction.php 2011-11-11 11:41:20 UTC (rev 201) +++ branches/newUser2/classes/Gems/Default/IndexAction.php 2011-11-11 17:48:42 UTC (rev 202) @@ -66,20 +66,84 @@ public $menu; /** - * New version of login form + * @var Gems_Project_ProjectSettings + */ + public $project; + + /** + * Returns a link for the token input page. * + * @return MUtil_Form_Element_Html + */ + protected function _getAskTokenLinkElement() + { + // Veld token + $element = new MUtil_Form_Element_Html('askToken'); + $element->br(); + $element->actionLink(array('controller' => 'ask', 'action' => 'token'), $this->_('Enter your token...')); + + return $element; + } + + /** + * Returns a basic form for this action. + * + * @param $description Optional description, %s is filled with project name. * @return Gems_Form */ - protected function _getLoginForm() + protected function _getBasicForm($description = null) { Gems_Html::init(); - $delayFactor = (isset($this->project->account) && isset($this->project->account['delayFactor']) ? $this->project->account['delayFactor'] : null); - $form = new Gems_Form(array('labelWidthFactor' => $this->labelWidthFactor)); $form->setMethod('post'); - $form->setDescription(sprintf($this->_('Login to %s application'), $this->project->name)); + if ($description) { + $form->setDescription(sprintf($description, $this->project->getName())); + } + return $form; + } + + /** + * Returns a login form + * + * @return Gems_Form + */ + protected function _getLoginForm() + { + $form = $this->_getBasicForm($this->_('Login to %s application')); + $form->addElement($this->_getOrganizationElement()); + $form->addElement($this->_getUserLoginElement()); + $form->addElement($this->_getPasswordElement()); + $form->addElement($this->_getSubmitButton($this->_('Login'))); + $form->addElement($this->_getAskTokenLinkElement()); + $form->addElement($this->_getResetLinkElement()); + + return $form; + } + + /** + * Returns a link to the login page + * + * @return MUtil_Form_Element_Html + */ + protected function _getLoginLinkElement() + { + // Reset password + $element = new MUtil_Form_Element_Html('resetPassword'); + $element->br(); + $element->actionLink(array('controller' => 'index', 'action' => 'login'), $this->_('Back to login')); + + return $element; + } + + /** + * Returns an element for determining / selecting the organization. + * + * @return Zend_Form_Element_Xhtml + */ + protected function _getOrganizationElement() + { if ($this->escort instanceof Gems_Project_Organization_SingleOrganizationInterface) { $element = new Zend_Form_Element_Hidden('organization'); $element->setValue($this->escort->getRespondentOrganization()); @@ -93,16 +157,17 @@ $element->setValue($this->escort->getCurrentOrganization()); } } - $form->addElement($element); - // Veld inlognaam - $element = new Zend_Form_Element_Text('userlogin'); - $element->setLabel($this->_('Username')); - $element->setAttrib('size', 10); - $element->setAttrib('maxlength', 20); - $element->setRequired(true); - $form->addElement($element); + return $element; + } + /** + * Returns a password element. + * + * @return Zend_Form_Element_Password + */ + protected function _getPasswordElement() + { // Veld password $element = new Zend_Form_Element_Password('password'); $element->setLabel($this->_('Password')); @@ -110,38 +175,86 @@ $element->setAttrib('maxlength', 20); $element->setRequired(true); $element->addValidator(new Gems_User_LoginPasswordValidator($this->loader->getUserLoader(), 'userlogin', 'organization', $this->translate)); - $form->addElement($element); - // Submit knop - $element = new Zend_Form_Element_Submit('button'); - $element->setLabel($this->_('Login')); - $element->setAttrib('class', 'button'); - $form->addElement($element); + return $element; + } - // Veld token - $element = new MUtil_Form_Element_Html('askToken'); - $element->br(); - $element->actionLink(array('controller' => 'ask', 'action' => 'token'), $this->_('Enter your token...')); - $form->addElement($element); + /** + * Gets a reset password form. + * + * @return Gems_Form + */ + protected function _getResetForm() + { + $form = $this->_getBasicForm($this->_('Reset password for %s application')); + $form->addElement($this->_getOrganizationElement()); + $form->addElement($this->_getUserLoginElement()); + $form->addElement($this->_getSubmitButton($this->_('Reset password'))); + $form->addElement($this->_getLoginLinkElement()); + return $form; + } + + /** + * Returns a link to the reset password page + * + * @return MUtil_Form_Element_Html + */ + protected function _getResetLinkElement() + { // Reset password $element = new MUtil_Form_Element_Html('resetPassword'); $element->br(); $element->actionLink(array('controller' => 'index', 'action' => 'resetpassword'), $this->_('Lost password')); - $form->addElement($element); - return $form; + return $element; } - // Dummy: always rerouted by GemsEscort + /** + * Returns a submit button. + * + * @param string $label + * @return Zend_Form_Element_Submit + */ + protected function _getSubmitButton($label) + { + // Submit knop + $element = new Zend_Form_Element_Submit('button'); + $element->setLabel($label); + $element->setAttrib('class', 'button'); + + return $element; + } + + /** + * Returns a login name element. + * + * @return Zend_Form_Element_Text + */ + protected function _getUserLoginElement() + { + // Veld inlognaam + $element = new Zend_Form_Element_Text('userlogin'); + $element->setLabel($this->_('Username')); + $element->setAttrib('size', 10); + $element->setAttrib('maxlength', 20); + $element->setRequired(true); + + return $element; + } + + /** + * Dummy: always rerouted by GemsEscort + */ public function indexAction() { } + /** + * Default login page + */ public function loginAction() { - /** - * If already logged in, try to redirect to the first allowed and visible menu item - * if that fails, try to reroute to respondent/index - */ + // If already logged in, try to redirect to the first allowed and visible menu item + // if that fails, try to reroute to respondent/index if ($this->loader->getCurrentUser()->isActive()) { if ($menuItem = $this->menu->findFirst(array('allowed' => true, 'visible' => true))) { $redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector'); @@ -153,11 +266,13 @@ $form = $this->_getLoginForm(); - if ($this->_request->isPost()) { - if ($form->isValid($_POST, false)) { + $request = $this->getRequest(); + if ($request->isPost()) { + if ($form->isValid($request->getPost(), false)) { - if ($user = $this->loader->getUser($_POST['userlogin'], $_POST['organization'])) { + $user = $this->loader->getUser($request->getParam('userlogin'), $request->getParam('organization')); + if ($user->isActive()) { $user->setAsCurrentUser(); /** @@ -182,93 +297,37 @@ // This reroutes to the first available menu page after login $this->_reroute(array('controller' => null, 'action' => null), true); } + return; } } else { $errors = $form->getErrors(); - - $this->view->form = $form; } - } else { - $this->view->form = $form; } + $this->view->form = $form; } + /** + * Default logoff action + */ public function logoffAction() { $user = $this->loader->getCurrentUser(); $this->addMessage(sprintf($this->_('Good bye: %s.'), $user->getFullName())); $user->unsetAsCurrentUser(); - // Gems_Auth::getInstance()->clearIdentity(); $this->_reroute(array('action' => 'index'), true); } - protected function _getResetForm() - { - $form = new Gems_Form(array('labelWidthFactor' => $this->labelWidthFactor)); - $form->setMethod('post'); - $form->setDescription(sprintf($this->_('Reset password for %s application'), $this->project->name)); - - // Veld inlognaam - $element = new Zend_Form_Element_Text('userlogin'); - $element->setLabel($this->_('Username')); - $element->setAttrib('size', 10); - $element->setAttrib('maxlength', 20); - $element->setRequired(true); - $form->addElement($element); - - // Submit knop - $element = new Zend_Form_Element_Submit('button'); - $element->setLabel($this->_('Reset password')); - $element->setAttrib('class', 'button'); - $form->addElement($element); - - return $form; - } - + /** + * Reset password page. + */ public function resetpasswordAction() { $this->view->setScriptPath(GEMS_LIBRARY_DIR . '/views/scripts' ); - $form = $this->_getResetForm(); - $mail = new MUtil_Mail(); - $mail->setFrom('no...@er...'); - - if (isset($this->escort->project->email) && isset($this->escort->project->email['bcc'])) { - $mail->addBcc($this->escort->project->email['bcc']); - } - - /* - - if ($this->_request->isPost() && $form->isValid($_POST)) { - $sql = $this->db->quoteInto("SELECT gus_id_user, gsf_email, gus_reset_key, DATEDIFF(NOW(), gus_reset_requested) AS gsf_days FROM gems__users INNER JOIN gems__staff ON gus_id_user = gsf_id_user WHERE gus_login = ?", $_POST['userlogin']); - $result = $this->db->fetchRow($sql); - - if (empty($result) || empty($result['gsf_email'])) { - $this->addMessage($this->_('No such user found or no e-mail address known')); - } else if (!empty($result['gus_reset_key']) && $result['gsf_days'] < 1) { - $this->addMessage($this->_('Reset e-mail already sent, please try again after 24 hours')); - } else { - $email = $result['gsf_email']; - $key = md5(time() . $email); - $url = $this->util->getCurrentURI('index/resetpassword/key/' . $key); - - $this->db->update('gems__user_logins', array('gus_reset_key' => $key, 'gus_reset_requested' => new Zend_Db_Expr('NOW()')), 'gus_id_user = ' . $result['gus_id_user']); - - $mail->setSubject('Password reset requested'); - $mail->setBodyText('To reset your password, please click this link: ' . $url); - - $mail->addTo($email); - - try { - $mail->send(); - $this->addMessage($this->_('Follow the instructions in the e-mail')); - } catch (Exception $e) { - $this->addMessage($this->_('Unable to send e-mail')); - throw $e; - } - } - } else if ($key = $this->_request->getParam('key')) { + $request = $this->getRequest(); + if ($key = $request->getParam('key')) { + /* $sql = $this->db->quoteInto("SELECT gus_id_user, gsf_email FROM gems__users INNER JOIN gems__staff ON gus_id_user = gsf_id_user WHERE gus_reset_key = ?", $key); $result = $this->db->fetchRow($sql); @@ -293,9 +352,45 @@ } } else { $this->addMessage($this->_('Unknown request')); + } // */ + + } else { + $form = $this->_getResetForm(); + if ($request->isPost() && $form->isValid($request->getPost())) { + + $user = $this->loader->getUser($request->getParam('userlogin'), $request->getParam('organization')); + + If ($user->canResetPassword()) { + + $mail = new MUtil_Mail(); + $mail->setFrom('mj...@ma...'); + $mail->addTo($user->getEmailAddress(), $user->getFullName()); + + if (isset($this->escort->project->email) && isset($this->escort->project->email['bcc'])) { + $mail->addBcc($this->escort->project->email['bcc']); + } + + + $key = $user->getPasswordResetKey(); + + $url = $this->util->getCurrentURI('index/resetpassword/key/' . $key); + + $mail->setSubject('Password reset requested'); + $mail->setBodyText('To reset your password, please click this link: ' . $url); + + + try { + $mail->send(); + $this->addMessage($this->_('Follow the instructions in the e-mail.')); + } catch (Exception $e) { + $this->addMessage($this->_('Unable to send e-mail.')); + throw $e; + } + } else { + $this->addMessage($this->_('No such user found or no e-mail address known or user cannot be reset.')); + } } - } // */ - - $this->view->form = $form; + $this->view->form = $form; + } } } Modified: branches/newUser2/classes/Gems/Default/OptionAction.php =================================================================== --- branches/newUser2/classes/Gems/Default/OptionAction.php 2011-11-11 11:41:20 UTC (rev 201) +++ branches/newUser2/classes/Gems/Default/OptionAction.php 2011-11-11 17:48:42 UTC (rev 202) @@ -68,6 +68,9 @@ $this->loader->getUser($data['gsf_login'], $data['gsf_id_organization']); } + /** + * Allow a user to change his / her password. + */ public function changePasswordAction() { /************* @@ -75,11 +78,14 @@ *************/ $form = $this->createForm(); - $user = $this->loader->getCurrentUser(); + $user = $this->loader->getCurrentUser(); - $sql = "SELECT CASE WHEN gup_password IS NULL THEN 0 ELSE 1 END FROM gems__user_passwords WHERE gup_id_user = ?"; + if (! $user->canSetPassword()) { + $this->addMessage($this->_('You are not allowed to change your password.')); + return; + } - if ($this->db->fetchOne($sql, $user->getUserLoginId())) { + if ($user->hasPassword()) { // Field current password // // This is only used when the password is already set, which may not always be the case @@ -124,14 +130,8 @@ * Process form * ****************/ if ($this->_request->isPost() && $form->isValid($_POST)) { + $user->setPassword($_POST['new_password']); - $data['gup_id_user'] = $user->getUserLoginId(); - $data['gup_password'] = $this->project->getValueHash($_POST['new_password']); - - $model = new MUtil_Model_TableModel('gems__user_passwords'); - Gems_Model::setChangeFieldsByPrefix($model, 'gup', $user->getUserId()); - - $model->save($data); $this->addMessage($this->_('New password is active.')); $this->_reroute(array($this->getRequest()->getActionKey() => 'edit')); Modified: branches/newUser2/classes/Gems/Project/ProjectSettings.php =================================================================== --- branches/newUser2/classes/Gems/Project/ProjectSettings.php 2011-11-11 11:41:20 UTC (rev 201) +++ branches/newUser2/classes/Gems/Project/ProjectSettings.php 2011-11-11 17:48:42 UTC (rev 202) @@ -172,6 +172,15 @@ } /** + * Returns the public name of this project. + * @return string + */ + public function getName() + { + return $this->offsetGet('name'); + } + + /** * Returns the super admin name, if any * * @return string Modified: branches/newUser2/classes/Gems/User/StaffUserDefinition.php =================================================================== --- branches/newUser2/classes/Gems/User/StaffUserDefinition.php 2011-11-11 11:41:20 UTC (rev 201) +++ branches/newUser2/classes/Gems/User/StaffUserDefinition.php 2011-11-11 17:48:42 UTC (rev 202) @@ -36,8 +36,8 @@ */ /** + * A standard, database stored and authenticate staff user as of version 1.5. * - * * @package Gems * @subpackage User * @copyright Copyright (c) 2011 Erasmus MC @@ -59,6 +59,39 @@ protected $project; /** + * Return true if a password reset key can be created. + * + * Returns the setting for the definition whan no user is passed, otherwise + * returns the answer for this specific user. + * + * @param Gems_User_User $user Optional, the user whose password might change + * @return boolean + */ + public function canResetPassword(Gems_User_User $user = null) + { + if ($user) { + // Depends on the user. + return $user->hasEmailAddress() && $user->canSetPassword(); + } else { + return true; + } + } + + /** + * Return true if the password can be set. + * + * Returns the setting for the definition whan no user is passed, otherwise + * returns the answer for this specific user. + * + * @param Gems_User_User $user Optional, the user whose password might change + * @return boolean + */ + public function canSetPassword(Gems_User_User $user = null) + { + return true; + } + + /** * Checks the password for the specified $login_name and $organization. * * @param string $login_name @@ -82,6 +115,33 @@ } /** + * Return a password reset key + * + * @param Gems_User_User $user The user to create a key for. + * @return string + */ + public function getPasswordResetKey(Gems_User_User $user) + { + $model = new MUtil_Model_TableModel('gems__user_passwords'); + Gems_Model::setChangeFieldsByPrefix($model, 'gup', $user->getUserId()); + + $data['gup_id_user'] = $user->getUserLoginId(); + + $row = $model->loadFirst($data); + if ($row && $row['gup_reset_key']) { + // Keep using the key. + $data['gup_reset_key'] = $row['gup_reset_key']; + } else { + $data['gup_reset_key'] = $this->hashPassword(time() . $user->getEmailAddress()); + } + $data['gup_reset_requested'] = new Zend_Db_Expr('CURRENT_TIMESTAMP'); + + $model->save($data); + + return $data['gup_reset_key']; + } + + /** * Returns a user object, that may be empty if the user is unknown. * * @param string $login_name @@ -127,4 +187,43 @@ { return $this->project->getValueHash($password); } + + /** + * Return true if the user has a password. + * + * @param Gems_User_User $user The user to check + * @return boolean + */ + public function hasPassword(Gems_User_User $user) + { + $sql = "SELECT CASE WHEN gup_password IS NULL THEN 0 ELSE 1 END FROM gems__user_passwords WHERE gup_id_user = ?"; + + return (boolean) $this->db->fetchOne($sql, $user->getUserLoginId()); + } + + /** + * Set the password, if allowed for this user type. + * + * @param Gems_User_User $user The user whose password to change + * @param string $password + * @return Gems_User_UserDefinitionInterface (continuation pattern) + */ + public function setPassword(Gems_User_User $user, $password) + { + $data['gup_id_user'] = $user->getUserLoginId(); + $data['gup_reset_required'] = 0; + if (null === $password) { + // Passwords may be emptied. + $data['gup_password'] = null; + } else { + $data['gup_password'] = $this->hashPassword($password); + } + + $model = new MUtil_Model_TableModel('gems__user_passwords'); + Gems_Model::setChangeFieldsByPrefix($model, 'gup', $user->getUserId()); + + $model->save($data); + + return $this; + } } Modified: branches/newUser2/classes/Gems/User/User.php =================================================================== --- branches/newUser2/classes/Gems/User/User.php 2011-11-11 11:41:20 UTC (rev 201) +++ branches/newUser2/classes/Gems/User/User.php 2011-11-11 17:48:42 UTC (rev 202) @@ -84,6 +84,7 @@ } else { $this->_vars = $settings; } + $this->definition = $definition; } /** @@ -172,6 +173,26 @@ } /** + * Return true if a password reset key can be created. + * + * @return boolean + */ + public function canResetPassword() + { + return $this->isActive() && $this->definition->canResetPassword($this); + } + + /** + * Return true if the password can be set. + * + * @return boolean + */ + public function canSetPassword() + { + return $this->definition->canSetPassword(); + } + + /** * Checks the password for this user and handle the login security. * * @param string $password @@ -230,6 +251,16 @@ } /** + * Return true if this user has a password. + * + * @return boolean + */ + public function getEmailAddress() + { + return $this->_getVar('user_email'); + } + + /** * Returns the full user name (first, prefix, last). * * @return string @@ -278,6 +309,16 @@ } /** + * Return a password reset key + * + * @return string + */ + public function getPasswordResetKey() + { + return $this->definition->getPasswordResetKey($this); + } + + /** * Returns the user id, that identifies this user within this installation. * * One user id might be connected to multiple logins for multiple organizations. @@ -292,6 +333,8 @@ } /** + * Use ONLY in User package. + * * Returns the User package user id, that is unique for each login / organization id * combination, but does not directly identify this person. * @@ -309,7 +352,27 @@ } /** + * Return true if this user has a password. * + * @return boolean + */ + public function hasEmailAddress() + { + return $this->_hasVar('user_email'); + } + + /** + * Return true if this user has a password. + * + * @return boolean + */ + public function hasPassword() + { + return $this->definition->hasPassword(); + } + + /** + * * @return boolean True when a user can log in. */ public function isActive() @@ -324,7 +387,7 @@ */ public function isCurrentUser() { - return $this->_getVariableStore() instanceof Zend_Session_Namespace; + return $this->_vars instanceof Zend_Session_Namespace; } /** @@ -342,16 +405,17 @@ * * This means that the data about this user will be stored in a session. * - * @return Gems_User_UserAbstract + * @param boolean $signalLoader Do not set, except from UserLoader + * @return Gems_User_UserAbstract (continuation pattern) */ - public function setAsCurrentUser() + public function setAsCurrentUser($signalLoader = true) { // Get the current variables $oldStore = $this->_getVariableStore(); // When $oldStore is a Zend_Session_Namespace, then this user is already the current user. if (! $this->isCurrentUser()) { - $this->userLoader->getCurrentUser()->unsetAsCurrentUser(); + $this->userLoader->unsetCurrentUser(); $this->_vars = $this->session; @@ -359,25 +423,41 @@ $this->_vars->__set($name, $value); } - $this->userLoader->setCurrentUser($this); + if ($signalLoader) { + $this->userLoader->setCurrentUser($this); + } } return $this; } + /** + * Set the password, if allowed for this user type. + * + * @param string $password + * @return Gems_User_UserAbstract (continuation pattern) + */ + public function setPassword($password) + { + $this->definition->setPassword($this, $password); + return $this; + } + + /** * Unsets this user as the current user. * * This means that the data about this user will no longer be stored in a session. * - * @return Gems_User_UserAbstract + * @param boolean $signalLoader Do not set, except from UserLoader + * @return Gems_User_UserAbstract (continuation pattern) */ - public function unsetAsCurrentUser() + public function unsetAsCurrentUser($signalLoader = true) { // When $oldStore is a Zend_Session_Namespace, then this user is already the current user. if ($this->isCurrentUser()) { // Get the current variables - $oldStore = $this->_getVariableStore(); + $oldStore = $this->_vars; $this->_vars = new ArrayObject(); $this->_vars->setFlags(ArrayObject::STD_PROP_LIST); @@ -387,10 +467,12 @@ } // Clean up what is there now in the session. - $this->session->unsetAll(); + $oldStore->unsetAll(); - // Signal the loader - $this->userLoader->unsetCurrentUser(); + if ($signalLoader) { + // Signal the loader + $this->userLoader->unsetCurrentUser(); + } } return $this; Modified: branches/newUser2/classes/Gems/User/UserDefinitionAbstract.php =================================================================== --- branches/newUser2/classes/Gems/User/UserDefinitionAbstract.php 2011-11-11 11:41:20 UTC (rev 201) +++ branches/newUser2/classes/Gems/User/UserDefinitionAbstract.php 2011-11-11 17:48:42 UTC (rev 202) @@ -48,5 +48,66 @@ */ abstract class Gems_User_UserDefinitionAbstract extends MUtil_Registry_TargetAbstract implements Gems_User_UserDefinitionInterface { + /** + * Return true if a password reset key can be created. + * + * Returns the setting for the definition whan no user is passed, otherwise + * returns the answer for this specific user. + * + * @param Gems_User_User $user Optional, the user whose password might change + * @return boolean + */ + public function canResetPassword(Gems_User_User $user = null) + { + return false; + } + /** + * Return true if the password can be set. + * + * Returns the setting for the definition whan no user is passed, otherwise + * returns the answer for this specific user. + * + * @param Gems_User_User $user Optional, the user whose password might change + * @return boolean + */ + public function canSetPassword(Gems_User_User $user = null) + { + return false; + } + + /** + * Return a password reset key + * + * @param Gems_User_User $user The user to create a key for. + * @return string + */ + public function getPasswordResetKey(Gems_User_User $user) + { + throw new Gems_Exception_Coding(sprintf('A password reset key cannot be issued for %s users.', get_class($this))); + } + + /** + * Return true if the user has a password. + * + * @param Gems_User_User $user The user to check + * @return boolean + */ + public function hasPassword(Gems_User_User $user) + { + return false; + } + + /** + * Set the password, if allowed for this user type. + * + * @param Gems_User_User $user The user whose password to change + * @param string $password + * @return Gems_User_UserDefinitionInterface (continuation pattern) + */ + public function setPassword(Gems_User_User $user, $password) + { + throw new Gems_Exception_Coding(sprintf('The password cannot be set for %s users.', get_class($this))); + return $this; + } } Modified: branches/newUser2/classes/Gems/User/UserDefinitionInterface.php =================================================================== --- branches/newUser2/classes/Gems/User/UserDefinitionInterface.php 2011-11-11 11:41:20 UTC (rev 201) +++ branches/newUser2/classes/Gems/User/UserDefinitionInterface.php 2011-11-11 17:48:42 UTC (rev 202) @@ -47,6 +47,28 @@ interface Gems_User_UserDefinitionInterface { /** + * Return true if a password reset key can be created. + * + * Returns the setting for the definition whan no user is passed, otherwise + * returns the answer for this specific user. + * + * @param Gems_User_User $user Optional, the user whose password might change + * @return boolean + */ + public function canResetPassword(Gems_User_User $user = null); + + /** + * Return true if the password can be set. + * + * Returns the setting for the definition whan no user is passed, otherwise + * returns the answer for this specific user. + * + * @param Gems_User_User $user Optional, the user whose password might change + * @return boolean + */ + public function canSetPassword(Gems_User_User $user = null); + + /** * Checks the password for the specified $login_name and $organization. * * @param string $login_name @@ -57,6 +79,14 @@ public function checkPassword($login_name, $organization, $password); /** + * Return a password reset key + * + * @param Gems_User_User $user The user to create a key for. + * @return string + */ + public function getPasswordResetKey(Gems_User_User $user); + + /** * Returns a user object, that may be empty if the user is unknown. * * @param string $login_name @@ -64,4 +94,21 @@ * @return array Of data to fill the user with. */ public function getUserData($login_name, $organization); + + /** + * Return true if the user has a password. + * + * @param Gems_User_User $user The user to check + * @return boolean + */ + public function hasPassword(Gems_User_User $user); + + /** + * Set the password, if allowed for this user type. + * + * @param Gems_User_User $user The user whose password to change + * @param string $password + * @return Gems_User_UserDefinitionInterface (continuation pattern) + */ + public function setPassword(Gems_User_User $user, $password); } \ No newline at end of file Modified: branches/newUser2/classes/Gems/User/UserLoader.php =================================================================== --- branches/newUser2/classes/Gems/User/UserLoader.php 2011-11-11 11:41:20 UTC (rev 201) +++ branches/newUser2/classes/Gems/User/UserLoader.php 2011-11-11 17:48:42 UTC (rev 202) @@ -98,7 +98,8 @@ public function checkPassword($login_name, $organization, $password) { // MUtil_Echo::track($login_name, $organization, $password); - $definition = $this->getUserClass($login_name, $organization); + $defName = $this->getUserClassName($login_name, $organization); + $definition = $this->_getClass($defName); $success = $definition->checkPassword($login_name, $organization, $password); @@ -196,10 +197,11 @@ { if (! self::$currentUser) { if ($this->session->__isset('__user_definition')) { - $className = $this->session->__get('__user_definition'); - self::$currentUser = $this->_loadClass('User', true, array($this->session, new $className())); + $defName = $this->session->__get('__user_definition'); + self::$currentUser = $this->_loadClass('User', true, array($this->session, $this->_getClass($defName))); } else { self::$currentUser = $this->getUser(null, null); + self::$currentUser->setAsCurrentUser(); } } @@ -215,8 +217,10 @@ */ public function getUser($login_name, $organization) { - $definition = $this->getUserClass($login_name, $organization); + $defName = $this->getUserClassName($login_name, $organization); + $definition = $this->_getClass($defName); + $values = $definition->getUserData($login_name, $organization); if (! isset($values['user_active'])) { @@ -227,7 +231,7 @@ //Load the allowed organizations $values['allowedOrgs'] = $this->getAllowedOrganizations(); } - $values['__user_definition'] = get_class($definition); + $values['__user_definition'] = $defName; return $this->_loadClass('User', true, array($values, $definition)); } @@ -250,22 +254,22 @@ } /** - * Returns the user class, can be overloaded by subclasses. + * Returns the name of the user definition class of this user. * * @param string $login_name * @param int $organization - * @return Gems_User_UserDefinitionInterface + * @return string */ - protected function getUserClass($login_name, $organization) + protected function getUserClassName($login_name, $organization) { if ($this->isProjectUser($login_name)) { - return $this->_getClass('ProjectUserDefinition'); + return 'ProjectUserDefinition'; } try { $sql = "SELECT gul_user_class FROM gems__user_logins WHERE gul_can_login = 1 AND gul_login = ? AND gul_id_organization = ?"; if ($class = $this->db->fetchOne($sql, array($login_name, $organization))) { - return $this->_getClass($class . 'Definition'); + return $class . 'Definition'; } } catch (Zend_Db_Exception $e) { @@ -293,10 +297,10 @@ // MUtil_Echo::r($e); } - return $this->_getClass(self::USER_OLD_STAFF . 'Definition'); + return self::USER_OLD_STAFF . 'Definition'; } - return $this->_getClass('NoLoginDefinition'); + return 'NoLoginDefinition'; } protected function isProjectUser($login_name) @@ -312,29 +316,30 @@ */ public function setCurrentUser(Gems_User_User $user) { - $this->unsetCurrentUser(); - self::$currentUser = $user; + if ($user !== self::$currentUser) { + $this->unsetCurrentUser(); + self::$currentUser = $user; - // Double check in case this function was used as original - // start for setting the user. - if (! $user->isCurrentUser()) { - $user->setAsCurrentUser(); + // Double check in case this function was used as original + // start for setting the user. + if (! $user->isCurrentUser()) { + $user->setAsCurrentUser(true); + } } return $this; } /** - * Sets a new user as the current user. + * Removes the current user * - * @param Gems_User_User $user * @return Gems_User_UserLoader (continuation pattern) */ public function unsetCurrentUser() { // Remove if the currentUser still sees itself as the current user. if ((self::$currentUser instanceof Gems_User_User) && self::$currentUser->isCurrentUser()) { - self::$currentUser->unsetAsCurrentUser(); + self::$currentUser->unsetAsCurrentUser(false); } self::$currentUser = null; return $this; Modified: branches/newUser2/classes/MUtil/Model/DatabaseModelAbstract.php =================================================================== --- branches/newUser2/classes/MUtil/Model/DatabaseModelAbstract.php 2011-11-11 11:41:20 UTC (rev 201) +++ branches/newUser2/classes/MUtil/Model/DatabaseModelAbstract.php 2011-11-11 17:48:42 UTC (rev 202) @@ -598,12 +598,17 @@ public function formatSaveDate($name, $value, $new = false) { - if ($name) { + if ($name && (! ((null === $value) || ($value instanceof Zend_Db_Expr)))) { if ($saveFormat = $this->get($name, 'storageFormat')) { - $displayFormat = $this->get($name, 'dateFormat'); + if ($value instanceof Zend_Date) { + return $value->toString($saveFormat); + + } else { + $displayFormat = $this->get($name, 'dateFormat'); - return MUtil_Date::format($value, $saveFormat, $displayFormat); + return MUtil_Date::format($value, $saveFormat, $displayFormat); + } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <gem...@li...> - 2011-11-14 11:59:04
|
Revision: 204 http://gemstracker.svn.sourceforge.net/gemstracker/?rev=204&view=rev Author: matijsdejong Date: 2011-11-14 11:58:57 +0000 (Mon, 14 Nov 2011) Log Message: ----------- #31 ready, respondents login can be added Modified Paths: -------------- branches/newUser2/classes/Gems/Default/IndexAction.php branches/newUser2/classes/Gems/Default/OptionAction.php branches/newUser2/classes/Gems/User/StaffUserDefinition.php branches/newUser2/classes/Gems/User/User.php branches/newUser2/classes/Gems/User/UserDefinitionAbstract.php branches/newUser2/classes/Gems/User/UserDefinitionInterface.php branches/newUser2/classes/GemsEscort.php Modified: branches/newUser2/classes/Gems/Default/IndexAction.php =================================================================== --- branches/newUser2/classes/Gems/Default/IndexAction.php 2011-11-14 10:21:54 UTC (rev 203) +++ branches/newUser2/classes/Gems/Default/IndexAction.php 2011-11-14 11:58:57 UTC (rev 204) @@ -105,6 +105,16 @@ } /** + * Returns an element for keeping a reset key. + * + * @return Zend_Form_Element_Hidden + */ + protected function _getKeyElement() + { + return new Zend_Form_Element_Hidden('key'); + } + + /** * Returns a login form * * @return Gems_Form @@ -187,6 +197,7 @@ protected function _getResetForm() { $form = $this->_getBasicForm($this->_('Reset password for %s application')); + $form->addElement($this->_getKeyElement()); $form->addElement($this->_getOrganizationElement()); $form->addElement($this->_getUserLoginElement()); $form->addElement($this->_getSubmitButton($this->_('Reset password'))); @@ -326,42 +337,25 @@ $this->view->setScriptPath(GEMS_LIBRARY_DIR . '/views/scripts' ); $request = $this->getRequest(); - if ($key = $request->getParam('key')) { - /* - $sql = $this->db->quoteInto("SELECT gus_id_user, gsf_email FROM gems__users INNER JOIN gems__staff ON gus_id_user = gsf_id_user WHERE gus_reset_key = ?", $key); - $result = $this->db->fetchRow($sql); + $form = $this->_getResetForm(); + if ($request->isPost() && $form->isValid($request->getPost())) { - if (!empty($result)) { - // generate new password - $password = $this->escort->getRandomPassword(); - $passwordHash = $this->escort->passwordHash(null, $password, false); + $user = $this->loader->getUser($request->getParam('userlogin'), $request->getParam('organization')); - $mail->setSubject('New password'); - $mail->setBodyText('Your new password has been generated. Your new password is: ' . $password); - - $mail->addTo($result['gsf_email']); - - try { - $mail->send(); - $this->addMessage($this->_('An e-mail was sent containing your new password')); - $this->db->update('gems__users', array('gus_reset_key' => new Zend_Db_Expr('NULL'), 'gus_reset_requested' => new Zend_Db_Expr('NULL'), 'gus_password' => $passwordHash), 'gus_id_user = ' . $result['gus_id_user']); - $this->_reroute(array('action' => 'index'), true); - } catch (Exception $e) { - $this->addMessage($this->_('Unable to send e-mail')); - throw $e; - } - } else { - $this->addMessage($this->_('Unknown request')); - } // */ - - } else { - $form = $this->_getResetForm(); - if ($request->isPost() && $form->isValid($request->getPost())) { - - $user = $this->loader->getUser($request->getParam('userlogin'), $request->getParam('organization')); - - If ($user->canResetPassword()) { - + If ($user->canResetPassword()) { + if ($key = $request->getParam('key')) { + // Key has been passed by mail + if ($user->checkPasswordResetKey($key)) { + $user->setPasswordResetRequired(true); + $user->setAsCurrentUser(); + $this->addMessage($this->_('Reset accepted, enter your new password.')); + $user->gotoStartPage($this->menu, $request); + return; + } else { + $this->addMessage($this->_('This key timed out or does not belong to this user.')); + } + } else { + // P{ass mail by key $mail = new MUtil_Mail(); $mail->setFrom('mj...@ma...'); $mail->addTo($user->getEmailAddress(), $user->getFullName()); @@ -375,22 +369,26 @@ $url = $this->util->getCurrentURI('index/resetpassword/key/' . $key); - $mail->setSubject('Password reset requested'); - $mail->setBodyText('To reset your password, please click this link: ' . $url); + $mail->setSubject($this->_('Password reset requested')); + $mail->setBodyText(sprintf($this->_('To reset your password for %s, please click this link: %s'), GEMS_PROJECT_NAME_UC, $url)); try { $mail->send(); - $this->addMessage($this->_('Follow the instructions in the e-mail.')); + $this->addMessage($this->_('We sent you an e-mail with a reset link. Click on the link in the e-mail.')); } catch (Exception $e) { $this->addMessage($this->_('Unable to send e-mail.')); throw $e; } - } else { - $this->addMessage($this->_('No such user found or no e-mail address known or user cannot be reset.')); } + } else { + $this->addMessage($this->_('No such user found or no e-mail address known or user cannot be reset.')); } - $this->view->form = $form; } + if ($request->getParam('key')) { + $this->addMessage($this->_('We received your password reset key.')); + $this->addMessage($this->_('Please enter the organization and username belonging to this key.')); + } + $this->view->form = $form; } } Modified: branches/newUser2/classes/Gems/Default/OptionAction.php =================================================================== --- branches/newUser2/classes/Gems/Default/OptionAction.php 2011-11-14 10:21:54 UTC (rev 203) +++ branches/newUser2/classes/Gems/Default/OptionAction.php 2011-11-14 11:58:57 UTC (rev 204) @@ -85,7 +85,9 @@ return; } - if ($user->hasPassword()) { + if ($user->isPasswordResetRequired()) { + $this->menu->setVisible(false); + } elseif ($user->hasPassword()) { // Field current password // // This is only used when the password is already set, which may not always be the case @@ -151,7 +153,7 @@ $table->setAsFormLayout($form, true, true); $table['tbody'][0][0]->class = 'label'; // Is only one row with formLayout, so all in output fields get class. - if ($links = $this->createMenuLinks()) { + if (! $user->isPasswordResetRequired() && ($links = $this->createMenuLinks())) { $table->tf(); // Add empty cell, no label $linksCell = $table->tf($links); } Modified: branches/newUser2/classes/Gems/User/StaffUserDefinition.php =================================================================== --- branches/newUser2/classes/Gems/User/StaffUserDefinition.php 2011-11-14 10:21:54 UTC (rev 203) +++ branches/newUser2/classes/Gems/User/StaffUserDefinition.php 2011-11-14 11:58:57 UTC (rev 204) @@ -115,6 +115,28 @@ } /** + * Check whether a reset key is really linked to a user. + * + * @param Gems_User_User $user The user the key was created for (hopefully). + * @param string The key + * @return boolean + */ + public function checkPasswordResetKey(Gems_User_User $user, $key) + { + $model = new MUtil_Model_TableModel('gems__user_passwords'); + + $filter['gup_id_user'] = $user->getUserLoginId(); + $filter[] = 'DATE_ADD(gup_reset_requested, INTERVAL 24 HOUR) >= CURRENT_TIMESTAMP'; + + $row = $model->loadFirst($filter); + if ($row && $row['gup_reset_key']) { + return $key == $row['gup_reset_key']; + } + + return false; + } + + /** * Return a password reset key * * @param Gems_User_User $user The user to create a key for. @@ -127,7 +149,7 @@ $data['gup_id_user'] = $user->getUserLoginId(); - $row = $model->loadFirst($data); + $row = $model->loadFirst($data + array('DATE_ADD(gup_reset_requested, INTERVAL 24 HOUR) >= CURRENT_TIMESTAMP')); if ($row && $row['gup_reset_key']) { // Keep using the key. $data['gup_reset_key'] = $row['gup_reset_key']; @@ -166,6 +188,8 @@ 'user_organization_id'=>'gor_id_organization', 'user_organization_name'=>'gor_name', 'user_style' => 'gor_style')) + ->joinLeft('gems__user_passwords', 'gul_id_user = gup_id_user', + array('user_password_reset' => 'gup_reset_required')) ->where('ggp_group_active = 1') ->where('gor_active = 1') ->where('gsf_active = 1') @@ -210,8 +234,10 @@ */ public function setPassword(Gems_User_User $user, $password) { - $data['gup_id_user'] = $user->getUserLoginId(); - $data['gup_reset_required'] = 0; + $data['gup_id_user'] = $user->getUserLoginId(); + $data['gup_reset_key'] = null; + $data['gup_reset_requested'] = null; + $data['gup_reset_required'] = 0; if (null === $password) { // Passwords may be emptied. $data['gup_password'] = null; Modified: branches/newUser2/classes/Gems/User/User.php =================================================================== --- branches/newUser2/classes/Gems/User/User.php 2011-11-14 10:21:54 UTC (rev 203) +++ branches/newUser2/classes/Gems/User/User.php 2011-11-14 11:58:57 UTC (rev 204) @@ -204,6 +204,17 @@ } /** + * Check whether a reset key is really linked to this user. + * + * @param string The key + * @return boolean + */ + public function checkPasswordResetKey($key) + { + return $this->definition->checkPasswordResetKey($this, $key); + } + + /** * Should be called after answering the request to allow the Target * to check if all required registry values have been set correctly. * @@ -319,6 +330,16 @@ } /** + * Returns the current user role. + * + * @return string + */ + public function getRole() + { + return $this->_getVar('user_role'); + } + + /** * Returns the user id, that identifies this user within this installation. * * One user id might be connected to multiple logins for multiple organizations. @@ -352,6 +373,35 @@ } /** + * Redirects the user to his/her start page. + * + * @param Gems_Menu $menu + * @param Zend_Controller_Request_Abstract $request + * @return Gems_Menu_SubMenuItem + */ + public function gotoStartPage(Gems_Menu $menu, Zend_Controller_Request_Abstract $request) + { + if ($this->isPasswordResetRequired()) { + // Set menu OFF + $menu->setVisible(false); + + $menuItem = $menu->findFirst(array($request->getControllerKey() => 'option', $request->getActionKey() => 'change-password')); + // This may not yet be true, but is needed for the redirect. + $menuItem->set('allowed', true); + $menuItem->set('visible', true); + } else { + $menuItem = $menu->findFirst(array('allowed' => true, 'visible' => true)); + } + + if ($menuItem) { + $redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector'); + $redirector->gotoRoute($menuItem->toRouteUrl($request)); + } + + return $menuItem; + } + + /** * Return true if this user has a password. * * @return boolean @@ -368,7 +418,7 @@ */ public function hasPassword() { - return $this->definition->hasPassword(); + return $this->definition->hasPassword($this); } /** @@ -401,12 +451,22 @@ } /** + * True when this user must enter a new password. + * + * @return boolean + */ + public function isPasswordResetRequired() + { + return (boolean) $this->_getVar('user_password_reset'); + } + + /** * Set this user as the current user. * * This means that the data about this user will be stored in a session. * * @param boolean $signalLoader Do not set, except from UserLoader - * @return Gems_User_UserAbstract (continuation pattern) + * @return Gems_User_User (continuation pattern) */ public function setAsCurrentUser($signalLoader = true) { @@ -436,7 +496,7 @@ * Set the password, if allowed for this user type. * * @param string $password - * @return Gems_User_UserAbstract (continuation pattern) + * @return Gems_User_User (continuation pattern) */ public function setPassword($password) { @@ -445,12 +505,23 @@ } /** + * + * @param boolean $reset + * @return Gems_User_User (continuation pattern) + */ + public function setPasswordResetRequired($reset = true) + { + $this->_setVar('user_password_reset', (boolean) $reset); + return $this; + } + + /** * Unsets this user as the current user. * * This means that the data about this user will no longer be stored in a session. * * @param boolean $signalLoader Do not set, except from UserLoader - * @return Gems_User_UserAbstract (continuation pattern) + * @return Gems_User_User (continuation pattern) */ public function unsetAsCurrentUser($signalLoader = true) { Modified: branches/newUser2/classes/Gems/User/UserDefinitionAbstract.php =================================================================== --- branches/newUser2/classes/Gems/User/UserDefinitionAbstract.php 2011-11-14 10:21:54 UTC (rev 203) +++ branches/newUser2/classes/Gems/User/UserDefinitionAbstract.php 2011-11-14 11:58:57 UTC (rev 204) @@ -77,6 +77,18 @@ } /** + * Check whether a reset key is really linked to a user. + * + * @param Gems_User_User $user The user the key was created for (hopefully). + * @param string The key + * @return string + */ + public function checkPasswordResetKey(Gems_User_User $user, $key) + { + throw new Gems_Exception_Coding(sprintf('A password reset key cannot be issued for %s users.', get_class($this))); + } + + /** * Return a password reset key * * @param Gems_User_User $user The user to create a key for. Modified: branches/newUser2/classes/Gems/User/UserDefinitionInterface.php =================================================================== --- branches/newUser2/classes/Gems/User/UserDefinitionInterface.php 2011-11-14 10:21:54 UTC (rev 203) +++ branches/newUser2/classes/Gems/User/UserDefinitionInterface.php 2011-11-14 11:58:57 UTC (rev 204) @@ -79,6 +79,15 @@ public function checkPassword($login_name, $organization, $password); /** + * Check whether a reset key is really linked to a user. + * + * @param Gems_User_User $user The user the key was created for (hopefully). + * @param string The key + * @return string + */ + public function checkPasswordResetKey(Gems_User_User $user, $key); + + /** * Return a password reset key * * @param Gems_User_User $user The user to create a key for. Modified: branches/newUser2/classes/GemsEscort.php =================================================================== --- branches/newUser2/classes/GemsEscort.php 2011-11-14 10:21:54 UTC (rev 203) +++ branches/newUser2/classes/GemsEscort.php 2011-11-14 11:58:57 UTC (rev 204) @@ -1440,12 +1440,15 @@ */ public function routeShutdown(Zend_Controller_Request_Abstract $request) { + $loader = $this->getLoader(); + $user = $loader->getCurrentUser(); + // MUtil_Echo::r($request->getParams(), 'params'); // MUtil_Echo::r($request->getUserParams(), 'userparams'); // Load the menu. As building the menu can depend on all resources and the request, we do it here. // // PS: The REQUEST is needed because otherwise the locale for translate is not certain. - $this->menu = $this->getLoader()->createMenu($this); + $this->menu = $loader->createMenu($this); $this->_updateVariable('menu'); /** @@ -1453,7 +1456,7 @@ * directory with the name lock.txt */ if ($this->getUtil()->getMaintenanceLock()->isLocked()) { - if ($this->session->user_id && $this->session->user_role !== 'master') { + if ($user->isActive() && $user->getRole() !== 'master') { //Still allow logoff so we can relogin as master if (!('index' == $request->getControllerName() && 'logoff' == $request->getActionName())) { $this->setError( @@ -1461,6 +1464,7 @@ 401, $this->_('System is in maintenance mode')); } + $user->unsetAsCurrentUser(); } else { $this->addMessage($this->_('System is in maintenance mode')); MUtil_Echo::r($this->_('System is in maintenance mode')); @@ -1470,12 +1474,7 @@ // Gems does not use index/index if (('index' == $request->getControllerName()) && ('index' == $request->getActionName())) { // Instead Gems routes to the first available menu item when this is the request target - if ($menuItem = $this->menu->findFirst(array('allowed' => true, 'visible' => true))) { - $redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector'); - $redirector->gotoRoute($menuItem->toRouteUrl($request)); - //$menuItem->applyToRequest($request); - //$this->setControllerDirectory($request); // Maybe the controller directory to be used changed - } else { + if (! $user->gotoStartPage($this->menu, $request)) { $this->setError( $this->_('No access to site.'), 401, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |