From 2e5bed21bd0f9420a663f9a603432c536b2035d0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roland=20H=C3=A4der?= Date: Sat, 28 Jun 2008 20:49:04 +0000 Subject: [PATCH] User class / resending of confirm link updated: - If the provided email address for resending confirmation link is missing the filter will now redirect to a configurable URL - New exception InvalidInterfaceException which will be thrown if a required interface is not implemented - Resend link does now create a new hash and updates the user table - Method BaseUser::ifEmailAddressExists() does now fix empty username attribute - New method User::updateDatabaseField() added which updates database table columns with specified values - Minor fixes applied --- .gitattributes | 1 + application/ship-simu/config.php | 7 ++- .../main/class_InvalidInterfaceException.php | 46 +++++++++++++++++ .../main/class_InvalidObjectException.php | 2 +- .../web/class_WebResendLinkCommand.php | 25 +++++++++ .../filter/update/class_UserUpdateFilter.php | 2 +- .../class_UserUnconfirmedVerifierFilter.php | 14 ++++- inc/classes/main/user/class_BaseUser.php | 22 +++++++- inc/classes/main/user/guest/class_Guest.php | 6 +-- inc/classes/main/user/user/class_User.php | 51 +++++++++++++++++-- 10 files changed, 161 insertions(+), 15 deletions(-) create mode 100644 inc/classes/exceptions/main/class_InvalidInterfaceException.php diff --git a/.gitattributes b/.gitattributes index 5edfb43..dccadbf 100644 --- a/.gitattributes +++ b/.gitattributes @@ -255,6 +255,7 @@ inc/classes/exceptions/main/class_InvalidArrayCountException.php -text inc/classes/exceptions/main/class_InvalidCommandException.php -text inc/classes/exceptions/main/class_InvalidCommandInstanceException.php -text inc/classes/exceptions/main/class_InvalidControllerException.php -text +inc/classes/exceptions/main/class_InvalidInterfaceException.php -text inc/classes/exceptions/main/class_InvalidObjectException.php -text inc/classes/exceptions/main/class_MissingArrayElementsException.php -text inc/classes/exceptions/main/class_MissingDecimalsThousandsSeperatorException.php -text diff --git a/application/ship-simu/config.php b/application/ship-simu/config.php index 52e75e3..5967ed3 100644 --- a/application/ship-simu/config.php +++ b/application/ship-simu/config.php @@ -106,8 +106,11 @@ $cfg->setConfigEntry('logout_done_url', "index.php?app=ship-simu&page=logout_don // CFG: LOGIN-USER-STATUS-URL $cfg->setConfigEntry('login_user_status_url', "index.php?app=ship-simu&page=login_area&action=status_problem"); -// CFG: LOGIN-USER-UNCONFIRMED-URL -$cfg->setConfigEntry('login_user_unconfirmed_url', "index.php?app=ship-simu&page=status_unconfirmed_problem"); +// CFG: USER-NOT-UNCONFIRMED-URL +$cfg->setConfigEntry('user_not_unconfirmed_url', "index.php?app=ship-simu&page=status&status=unconfirmed_problem"); + +// CFG: USER-UNCONFIRMED-EMAIL-MISSING-URL +$cfg->setConfigEntry('user_unconfirmed_email_missing_url', "index.php?app=ship-simu&page=status&status=unconfirmed_email_missing"); // CFG: LOGIN-DEFAULT-ACTION $cfg->setConfigEntry('login_default_action', "welcome"); diff --git a/inc/classes/exceptions/main/class_InvalidInterfaceException.php b/inc/classes/exceptions/main/class_InvalidInterfaceException.php new file mode 100644 index 0000000..a7fc71e --- /dev/null +++ b/inc/classes/exceptions/main/class_InvalidInterfaceException.php @@ -0,0 +1,46 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, this is free software + * @license GNU GPL 3.0 or any newer version + * @link http://www.ship-simu.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +class InvalidInterfaceException extends FrameworkException { + /** + * The constructor + * + * @param $classArray Array with exception data + * @param $code Code number for the exception + * @return void + */ + public function __construct (array $classArray, $code) { + // Add a message around the missing class + $message = sprintf("[%s:%d] Object does not implement expected interface .", + $classArray[0]->__toString(), + $this->getLine(), + $classArray[1] + ); + + // Call parent constructor + parent::__construct($message, $code); + } +} + +// [EOF] +?> diff --git a/inc/classes/exceptions/main/class_InvalidObjectException.php b/inc/classes/exceptions/main/class_InvalidObjectException.php index 17a8033..dc6cd4e 100644 --- a/inc/classes/exceptions/main/class_InvalidObjectException.php +++ b/inc/classes/exceptions/main/class_InvalidObjectException.php @@ -31,7 +31,7 @@ class InvalidObjectException extends FrameworkException { */ public function __construct (FrameworkInterface $class, $code) { // Add a message around the missing class - $message = sprintf("[%s:%d] Objects are not allowed here. (Object: %s)", + $message = sprintf("[%s:%d] Objects of type %s are not allowed here.", $class->__toString(), $this->getLine(), $class->getObjectDescription() diff --git a/inc/classes/main/commands/web/class_WebResendLinkCommand.php b/inc/classes/main/commands/web/class_WebResendLinkCommand.php index 138c44d..03aa64d 100644 --- a/inc/classes/main/commands/web/class_WebResendLinkCommand.php +++ b/inc/classes/main/commands/web/class_WebResendLinkCommand.php @@ -64,8 +64,18 @@ class WebResendLinkCommand extends BaseCommand implements Commandable { * @param $requestInstance An instance of a class with an Requestable interface * @param $responseInstance An instance of a class with an Responseable interface * @return void + * @throws InvalidInterfaceException If the user class does not implement ManageableUser */ public function execute (Requestable $requestInstance, Responseable $responseInstance) { + // Get user instance from registry + $userInstance = Registry::getRegistry()->getInstance('user'); + + // Does the user instance implement ManageableUser? + if (!$userInstance instanceof ManageableUser) { + // Throw exception here + throw new InvalidInterfaceException(array($userInstance, 'ManageableUser'), self::EXCEPTION_REQUIRED_INTERFACE_MISSING); + } // END - if + // Get template instance $templateInstance = $responseInstance->getTemplateInstance(); @@ -78,6 +88,21 @@ class WebResendLinkCommand extends BaseCommand implements Commandable { // Assign base URL $templateInstance->assignConfigVariable('base_url'); + // Get a RNG instance (Random Number Generator) + $rngInstance = ObjectFactory::createObjectByConfiguredName('rng_class'); + + // Generate a pseudo-random string + $randomString = $rngInstance->randomString(255); + + // Get a crypto instance + $cryptoInstance = ObjectFactory::createObjectByConfiguredName('crypto_class'); + + // Hash and encrypt the string + $hashedString = $cryptoInstance->hashString($cryptoInstance->encryptString($randomString)); + + // Update the user class + $userInstance->updateDatabaseField('confirm_hash', $hashedString); + // Get a mailer class $mailerInstance = ObjectFactory::createObjectByConfiguredName('mailer_class', array($templateInstance)); diff --git a/inc/classes/main/filter/update/class_UserUpdateFilter.php b/inc/classes/main/filter/update/class_UserUpdateFilter.php index 5f91bb0..babc67c 100644 --- a/inc/classes/main/filter/update/class_UserUpdateFilter.php +++ b/inc/classes/main/filter/update/class_UserUpdateFilter.php @@ -76,7 +76,7 @@ class UserUpdateFilter extends BaseFrameworkSystem implements Filterable { $authInstance->updateAuthData(); // Write all updates to the database - $userInstance->flushUpdates(); + $userInstance->flushPendingUpdates(); } } diff --git a/inc/classes/main/filter/verifier/class_UserUnconfirmedVerifierFilter.php b/inc/classes/main/filter/verifier/class_UserUnconfirmedVerifierFilter.php index a87ea95..f5ab58d 100644 --- a/inc/classes/main/filter/verifier/class_UserUnconfirmedVerifierFilter.php +++ b/inc/classes/main/filter/verifier/class_UserUnconfirmedVerifierFilter.php @@ -66,13 +66,25 @@ class UserUnconfirmedVerifierFilter extends BaseFrameworkSystem implements Filte // Get a user instance for comparison $userInstance = User::createUserByRequest($requestInstance); + // Is the email address valid? + if (!$userInstance->ifEmailAddressExists()) { + // Request is invalid! + $requestInstance->requestIsValid(false); + + // Redirect to configured URL + $responseInstance->redirectToConfiguredUrl('user_unconfirmed_email_missing_url'); + + // Stop processing here + exit(); + } // END - if + // Is the user account confirmed? if ($userInstance->getField('user_status') != $this->getConfigInstance()->readConfig('user_status_unconfirmed')) { // Request is invalid! $requestInstance->requestIsValid(false); // Redirect to configured URL - $responseInstance->redirectToConfiguredUrl('login_user_unconfirmed_url'); + $responseInstance->redirectToConfiguredUrl('user_not_unconfirmed_url'); // Stop processing here exit(); diff --git a/inc/classes/main/user/class_BaseUser.php b/inc/classes/main/user/class_BaseUser.php index e9ce25c..cee4fc3 100644 --- a/inc/classes/main/user/class_BaseUser.php +++ b/inc/classes/main/user/class_BaseUser.php @@ -187,6 +187,15 @@ class BaseUser extends BaseFrameworkSystem { if ($this->getResultInstance()->next()) { // Entry found $exists = true; + + // Is the username set? + if ($this->getUserName() == "") { + // Get current entry + $currEntry = $this->getResultInstance()->current(); + + // Set the username + $this->setUserName($currEntry['username']); + } // END - if } // END - if // Return the status @@ -258,14 +267,23 @@ class BaseUser extends BaseFrameworkSystem { * * @param $fieldName Field name which we shall get * @return $fieldValue Field value from the user - * @todo Do we need to secure this here against missing results? + * @throws NullPointerException If the result instance is null */ public final function getField ($fieldName) { // Default field value $fieldValue = null; + // Get result instance + $resultInstance = $this->getResultInstance(); + + // Is this instance null? + if (is_null($resultInstance)) { + // Then the user instance is no longer valid (expired cookies?) + throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER); + } // END - if + // Get current array - $fieldArray = $this->getResultInstance()->current(); + $fieldArray = $resultInstance->current(); // Does the field exist? if (isset($fieldArray[$fieldName])) { diff --git a/inc/classes/main/user/guest/class_Guest.php b/inc/classes/main/user/guest/class_Guest.php index 1dbd7be..7868a5a 100644 --- a/inc/classes/main/user/guest/class_Guest.php +++ b/inc/classes/main/user/guest/class_Guest.php @@ -93,7 +93,7 @@ class Guest extends BaseUser implements ManageableGuest, Registerable { /** * Updates the last activity timestamp and last performed action in the - * database result. You should call flushUpdates() to flush these updates + * database result. You should call flushPendingUpdates() to flush these updates * to the database layer. * * @param $requestInstance A requestable class instance @@ -104,11 +104,11 @@ class Guest extends BaseUser implements ManageableGuest, Registerable { } /** - * Flushs all updated entries to the database layer + * Flushs all pending updates to the database layer * * @return void */ - public function flushUpdates () { + public function flushPendingUpdates () { // No updates will be flushed to database! } } diff --git a/inc/classes/main/user/user/class_User.php b/inc/classes/main/user/user/class_User.php index e362faf..8343c33 100644 --- a/inc/classes/main/user/user/class_User.php +++ b/inc/classes/main/user/user/class_User.php @@ -47,6 +47,19 @@ class User extends BaseUser implements ManageableUser, Registerable { $this->generateUniqueId(); } + /** + * Destructor to always flush updates + * + * @return void + */ + public function __destruct () { + // Flush any updated entries to the database + $this->flushPendingUpdates(); + + // Call parent destructor + parent::__destruct(); + } + /** * Creates an instance of this user class by a provided username. This * factory method will check if the username is already taken and if not @@ -131,7 +144,7 @@ class User extends BaseUser implements ManageableUser, Registerable { /** * Updates the last activity timestamp and last performed action in the - * database result. You should call flushUpdates() to flush these updates + * database result. You should call flushPendingUpdates() to flush these updates * to the database layer. * * @param $requestInstance A requestable class instance @@ -168,16 +181,44 @@ class User extends BaseUser implements ManageableUser, Registerable { } /** - * Flushs all updated entries to the database layer + * Updates a given field with new value * + * @param $fieldName Field to update + * @param $fieldValue New value to store * @return void */ - public function flushUpdates () { - // Get a database wrapper - $wrapperInstance = ObjectFactory::createObjectByConfiguredName('user_db_wrapper_class'); + public function updateDatabaseField ($fieldName, $fieldValue) { + // Get a critieria instance + $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); + + // Add search criteria + $searchInstance->addCriteria(UserDatabaseWrapper::DB_COLUMN_USERNAME, $this->getUserName()); + $searchInstance->setLimit(1); + + // Now get another criteria + $updateInstance = ObjectFactory::createObjectByConfiguredName('update_criteria_class'); + + // And add our both entries + $updateInstance->addCriteria($fieldName, $fieldValue); + + // Add the search criteria for searching for the right entry + $updateInstance->setSearchInstance($searchInstance); + // Remember the update in database result + $this->getResultInstance()->add2UpdateQueue($updateInstance); + } + + /** + * Flushs all pending updates to the database layer + * + * @return void + */ + public function flushPendingUpdates () { // Do we have data to update? if ($this->getResultInstance()->ifDataNeedsFlush()) { + // Get a database wrapper + $wrapperInstance = ObjectFactory::createObjectByConfiguredName('user_db_wrapper_class'); + // Yes, then send the whole result to the database layer $wrapperInstance->doUpdateByResult($this->getResultInstance()); } // END - if -- 2.30.2