diff --git a/_config/config.yml b/_config/config.yml index 26777b4..f93d8a0 100755 --- a/_config/config.yml +++ b/_config/config.yml @@ -5,6 +5,10 @@ SilverStripe\Security\Group: extensions: - ilateral\SilverStripe\Users\Extensions\GroupExtension SilverStripe\Security\Member: + required_fields: + - "FirstName" + - "Surname" + - "Email" extensions: - ilateral\SilverStripe\Users\Extensions\MemberExtension SilverStripe\Control\Controller: diff --git a/changelog.md b/changelog.md index f866eb5..e639e75 100644 --- a/changelog.md +++ b/changelog.md @@ -39,6 +39,11 @@ Minor update to: * Add additional extension hooks when edit form submitted +# 1.3.0 + +* Switch to using frontend form fields to generate the "Edit Account Details" form +* Add better error handling on edit account submission + # 2.0.0 * SS4 support based on version 1.1.1 @@ -47,4 +52,9 @@ Minor update to: # 2.0.1 -* Add additional extension hooks when edit form submitted \ No newline at end of file +* Add additional extension hooks when edit form submitted + +# 2.1.0 + +* Switch to using frontend form fields to generate the "Edit Account Details" form +* Add better error handling on edit account submission \ No newline at end of file diff --git a/docs/en/Usage.md b/docs/en/Usage.md index 3cd5a4f..89bc58b 100644 --- a/docs/en/Usage.md +++ b/docs/en/Usage.md @@ -49,4 +49,39 @@ This module makes `$UserAccountNav` available to all your controllers. You can include this variable in your templates and it will add an account navigation menu. -If you wish to change the styling of this menu, simply edit the `Users_AccountNav.ss` template include. \ No newline at end of file +If you wish to change the styling of this menu, simply edit the `Users_AccountNav.ss` +template include. + +## Adding/Removing fields to the Edit Account form + +By default, this module generates an "Edit your account" view via: + + http://yoursite.com/users/account + +This view uses an instance of `Users_EditAccountForm` to generate the edit form. + +`Users_EditAccountForm` uses `Member::getFrontEndFields()` to generate the fieldlist, +it also uses the `Member.hidden_fields` config variable, as well as it's own +`ignore_member_fields` config variable, to remove fields from the EditForm. + +If you want to remove additional fields from this form (for example `Locale`), you can +add the following to your config.yml: + +```yml +Users_EditAccountForm: + ignore_member_fields: + - "Locale" +``` + +### Updating Required Fields + +This module uses `Member.required_fields` config variable to determine required fields. +If you added the Field `PhoneNumber` and wanted to make it required, you could do as below: + +```yml +Member: + db: + - "PhoneNumber" + required_fields: + - "PhoneNumber" +``` \ No newline at end of file diff --git a/lang/en.yml b/lang/en.yml index 17bf23d..ea35ece 100755 --- a/lang/en.yml +++ b/lang/en.yml @@ -10,6 +10,7 @@ en: DETAILSUPDATED: 'Account details updated' EDITDETAILS: 'Edit account details' EditAccountDetails: 'Edit account details' + FirstRegistered: 'First Registered' HELLO: Hi LOGIN: 'Log in' LOGOUT: Logout diff --git a/src/Users.php b/src/Users.php index 5bb3063..999f10a 100644 --- a/src/Users.php +++ b/src/Users.php @@ -10,8 +10,8 @@ * config, but will probably be extended in future to provide additional * functionality. * - * @author i-lateral (http://www.i-lateral.com) - * @package users + * @package Users + * @author i-lateral */ class Users { @@ -21,36 +21,36 @@ class Users /** * Minimum character length of the password required * on registration/account editing - * - * @var int + * + * @var int * @config - */ - private static $password_min_length = 6; + */ + private static $password_min_length = 6; - /** - * Maximum character length of the password required + /** + * Maximum character length of the password required * on registration/account editing - * - * @var int + * + * @var int * @config - */ - private static $password_max_length = 16; + */ + private static $password_max_length = 16; - /** - * Enforces strong password (at least one digit and one alphanumeric - * character) on registration/account editing - * - * @var boolean + /** + * Enforces strong password (at least one digit and one alphanumeric + * character) on registration/account editing + * + * @var boolean * @config - */ - private static $password_require_strong = false; + */ + private static $password_require_strong = false; /** * Stipulate if a user requires verification. NOTE this does not * actually deny the user the ability to login, it only alerts them * that they need validiation * - * @var boolean + * @var boolean * @config */ private static $require_verification = true; @@ -59,7 +59,7 @@ class Users * Stipulate whether to send a verification email to users after * registration * - * @var boolean + * @var boolean * @config */ private static $send_verification_email = false; @@ -68,7 +68,7 @@ class Users * Stipulate the sender address for emails sent from this module. If * not set, use the default @Email.admin_email instead. * - * @var string + * @var string * @config */ private static $send_email_from; @@ -76,7 +76,7 @@ class Users /** * Auto login users after registration * - * @var boolean + * @var boolean * @config */ private static $login_after_register = true; @@ -85,30 +85,20 @@ class Users * Add new users to the following groups. This is a list of group codes. * Adding a new code will add the user to this group * - * @var array + * @var array * @config */ private static $new_user_groups = [ "users-frontend" ]; - /** - * Add a group to the list of groups a new user is added to on - * registering. - * - * @param string Group code that will be used - */ - public static function addNewUserGroup($code) - { - Deprecation::notice("1.3", "addNewUserGroup depreciated, use global config instead"); - self::config()->new_user_groups[] = $code; - } - /** * Remove a group from the list of groups a new user is added to on * registering. * - * @param string Group code that will be used + * @param string $code Group code that will be used + * + * @return void */ public static function removeNewUserGroup($code) { @@ -121,30 +111,20 @@ public static function removeNewUserGroup($code) * Groups a user will be added to when verified. This should be an * array of group "codes", NOT names or ID's * - * @var array + * @var array * @config */ private static $verification_groups = [ "users-verified" ]; - /** - * Add a group toextends Object the list of groups a new user is added to on - * registering. - * - * @param string Group code that will be used - */ - public static function addVerificationGroup($code) - { - Deprecation::notice("1.3", "addVerificationGroup depreciated, use global config instead"); - self::config()->verification_groups[] = $code; - } - /** * Remove a group from the list of groups a new user is added to on * registering. * - * @param string Group code that will be used + * @param string $code Group code that will be used + * + * @return void */ public static function removeVerificationGroup($code) { diff --git a/src/control/AccountController.php b/src/control/AccountController.php index 6392f04..e59f618 100755 --- a/src/control/AccountController.php +++ b/src/control/AccountController.php @@ -23,7 +23,9 @@ /** * Controller that is used to allow users to manage their accounts via * the front end of the site. - * + * + * @package Users + * @author i-lateral */ class AccountController extends Controller implements PermissionProvider { @@ -38,7 +40,7 @@ class AccountController extends Controller implements PermissionProvider /** * Allowed sub-URL's on this controller * - * @var array + * @var array * @config */ private static $allowed_actions = [ @@ -96,7 +98,8 @@ public function getMember() /** * Setter for member * - * @param Member $member + * @param Member $member A member to associate + * * @return self */ public function setMember(Member $member) @@ -145,8 +148,9 @@ public function init() /** * Get the link to this controller * - * @param string $action - * @return string|null + * @param string $action The URL endpoint for this controller + * + * @return string */ public function Link($action = null) { @@ -159,8 +163,9 @@ public function Link($action = null) /** * Get an absolute link to this controller * - * @param string $action - * @return string|null + * @param string $action The URL endpoint for this controller + * + * @return string */ public function AbsoluteLink($action = null) { @@ -171,8 +176,9 @@ public function AbsoluteLink($action = null) * Get a relative (to the root url of the site) link to this * controller * - * @param string $action - * @return string|null + * @param string $action The URL endpoint for this controller + * + * @return string */ public function RelativeLink($action = null) { @@ -183,7 +189,9 @@ public function RelativeLink($action = null) /** * If content controller exists, return it's menu function + * * @param int $level Menu level to return. + * * @return ArrayList */ public function getMenu($level = 1) @@ -194,6 +202,13 @@ public function getMenu($level = 1) } } + /** + * Shortcut for getMenu + * + * @param int $level Menu level to return. + * + * @return ArrayList + */ public function Menu($level) { return $this->getMenu(); @@ -210,26 +225,30 @@ public function index() // Setup default profile summary sections $sections = ArrayList::create(); - $sections->push(ArrayData::create([ - "Title" => "", - "Content" => $this->renderWith( - "ilateral\\SilverStripe\\Users\\Includes\\ProfileSummary", - ["CurrentUser" => Security::getCurrentUser()] - ) - ])); + $sections->push(ArrayData::create( + [ + "Title" => "", + "Content" => $this->renderWith( + "ilateral\\SilverStripe\\Users\\Includes\\ProfileSummary", + ["CurrentUser" => Security::getCurrentUser()] + ) + ] + )); // Allow users to add extra content sections to the // summary $this->extend("updateIndexSections", $sections); - $this->customise([ - "Title" => _t('Users.ProfileSummary', 'Profile Summary'), - "MetaTitle" => _t('Users.ProfileSummary', 'Profile Summary'), - "Content" => $this->renderWith( - "ilateral\\SilverStripe\\Users\\Includes\\AccountSections", - ["Sections" => $sections] - ) - ]); + $this->customise( + [ + "Title" => _t('Users.ProfileSummary', 'Profile Summary'), + "MetaTitle" => _t('Users.ProfileSummary', 'Profile Summary'), + "Content" => $this->renderWith( + "ilateral\\SilverStripe\\Users\\Includes\\AccountSections", + ["Sections" => $sections] + ) + ] + ); $this->extend("onBeforeIndex"); @@ -250,11 +269,19 @@ public function edit() $form->loadDataFrom($member); } - $this->customise([ - "Title" => _t("Users.EditAccountDetails", "Edit account details"), - "MetaTitle" => _t("Users.EditAccountDetails", "Edit account details"), - "Form" => $form - ]); + $this->customise( + [ + "Title" => _t( + "Users.EditAccountDetails", + "Edit account details" + ), + "MetaTitle" => _t( + "Users.EditAccountDetails", + "Edit account details" + ), + "Form" => $form + ] + ); $this->extend("onBeforeEdit"); @@ -283,16 +310,27 @@ public function changepassword() // Is password changed, set a session message. if($password_set && $password_set == 1) { $form->sessionMessage( - _t("Users.PasswordChangedSuccessfully","Password Changed Successfully"), + _t( + "Users.PasswordChangedSuccessfully", + "Password Changed Successfully" + ), ValidationResult::TYPE_GOOD ); } - $this->customise([ - "Title" => _t("Security.ChangeYourPassword", "Change your password"), - "MetaTitle" => _t("Security.ChangeYourPassword", "Change your password"), - "Form" => $form - ]); + $this->customise( + [ + "Title" => _t( + "Security.ChangeYourPassword", + "Change your password" + ), + "MetaTitle" => _t( + "Security.ChangeYourPassword", + "Change your password" + ), + "Form" => $form + ] + ); $this->extend("onBeforeChangePassword"); diff --git a/src/control/RegisterController.php b/src/control/RegisterController.php index 22368c4..4565f71 100755 --- a/src/control/RegisterController.php +++ b/src/control/RegisterController.php @@ -29,6 +29,8 @@ * This is done by adding verified users to the groups stipulated by the * $verification_groups config variable * + * @package Users + * @author i-lateral */ class RegisterController extends Controller { @@ -84,6 +86,7 @@ class RegisterController extends Controller * email from multiple locations * * @param $member Member object to send email to + * * @return boolean */ protected function send_verification_email(Member $member) @@ -98,7 +101,8 @@ protected function send_verification_email(Member $member) /** * Get the link to this controller * - * @param string $action + * @param string $action The URL endpoint for this controller + * * @return string */ public function Link($action = null) @@ -112,8 +116,9 @@ public function Link($action = null) /** * Get an absolute link to this controller * - * @param string $action - * @return false|string + * @param string $action The URL endpoint for this controller + * + * @return string */ public function AbsoluteLink($action = null) { @@ -124,7 +129,8 @@ public function AbsoluteLink($action = null) * Get a relative (to the root url of the site) link to this * controller * - * @param string $action + * @param string $action The URL endpoint for this controller + * * @return string */ public function RelativeLink($action = null) @@ -136,7 +142,9 @@ public function RelativeLink($action = null) /** * If content controller exists, return it's menu function + * * @param int $level Menu level to return. + * * @return ArrayList */ public function getMenu($level = 1) @@ -147,6 +155,13 @@ public function getMenu($level = 1) } } + /** + * Shortcut for getMenu + * + * @param int $level Menu level to return. + * + * @return ArrayList + */ public function Menu($level) { return $this->getMenu(); @@ -318,7 +333,9 @@ public function RegisterForm() * etc) * * @param array $data User submitted data - * @param Form $form Registration form + * @param Form $form Registration form + * + * @return SS_HTTPResponse */ public function doRegister($data, $form) { diff --git a/src/extensions/ControllerExtension.php b/src/extensions/ControllerExtension.php index ecfe07b..1b3386e 100755 --- a/src/extensions/ControllerExtension.php +++ b/src/extensions/ControllerExtension.php @@ -8,7 +8,8 @@ * Extension for Controller that provide methods such as member management * interface to templates * - * @package users + * @package Users + * @author i-lateral */ class ControllerExtension extends Extension { diff --git a/src/extensions/GroupExtension.php b/src/extensions/GroupExtension.php index a93cd95..c228d03 100755 --- a/src/extensions/GroupExtension.php +++ b/src/extensions/GroupExtension.php @@ -9,6 +9,9 @@ /** * Overwrite group object so we can setup some more default groups + * + * @package Users + * @author i-lateral */ class GroupExtension extends DataExtension { diff --git a/src/extensions/MemberExtension.php b/src/extensions/MemberExtension.php index e895c17..8125302 100755 --- a/src/extensions/MemberExtension.php +++ b/src/extensions/MemberExtension.php @@ -15,14 +15,23 @@ use ilateral\SilverStripe\Users\Users; use ilateral\SilverStripe\Users\Control\RegisterController; +/** + * Overwrite Member object + * + * @package Users + * @author i-lateral + */ class MemberExtension extends DataExtension { private static $db = array( "VerificationCode" => "Varchar(40)" ); - private static $has_many = array(); - + /** + * Is the current member verified? + * + * @return boolean + */ public function isVerified() { return Permission::checkMember($this->owner, "USERS_VERIFIED"); @@ -32,7 +41,8 @@ public function isVerified() * Register a new user account using the provided data * and then return the current member * - * @param array $data + * @param array $data Array of data to create member from + * * @return Member */ public function Register($data) @@ -51,9 +61,11 @@ public function Register($data) // Add member to any groups that have been specified if (count(Users::config()->new_user_groups)) { - $groups = Group::get()->filter(array( + $groups = Group::get()->filter( + array( "Code" => Users::config()->new_user_groups - )); + ) + ); foreach ($groups as $group) { $group->Members()->add($this->owner); diff --git a/src/forms/EditAccountForm.php b/src/forms/EditAccountForm.php index 8221794..aa6e11d 100755 --- a/src/forms/EditAccountForm.php +++ b/src/forms/EditAccountForm.php @@ -13,25 +13,70 @@ use SilverStripe\Security\Member; use SilverStripe\Security\Security; use SilverStripe\ORM\ValidationResult; - +use SilverStripe\Core\Injector\Injector; + +/** + * Default form for editing Member details + * + * @package Users + * @author i-lateral + */ class EditAccountForm extends Form { + /** + * These fields will be ignored by the `Users_EditAccountForm` + * when generating fields + * + * @var array + */ + private static $ignore_member_fields = array( + "LastVisited", + "FailedLoginCount", + "DateFormat", + "TimeFormat", + "VerificationCode", + "Password", + "HasConfiguredDashboard", + "URLSegment", + "BlogProfileSummary", + "BlogProfileImage" + ); + + /** + * Setup this form + * + * @param Controller $controller Current Controller + * @param string $name Name of this form + * + * @return void + */ public function __construct($controller, $name = "Users_EditAccountForm") { - $fields = FieldList::create( - HiddenField::create("ID"), - TextField::create( - "FirstName", - _t('Member.FIRSTNAME', "First Name") - ), - TextField::create( - "Surname", - _t('Member.SURNAME', "Surname") - ), - EmailField::create( - "Email", - _t("Member.EMAIL", "Email") + $member = Injector::inst()->get(Member::class); + + $hidden_fields = array_merge( + $member->config()->hidden_fields, + static::config()->ignore_member_fields + ); + + $fields = $member->getFrontEndFields(); + + // Remove all "hidden fields" + foreach ($hidden_fields as $field_name) { + $fields->removeByName($field_name); + } + + // Add the current member ID + $fields->add(HiddenField::create("ID")); + + // Switch locale field + $fields->replaceField( + 'Locale', + DropdownField::create( + "Locale", + $member->fieldLabel("Locale"), + i18n::get_existing_translations() ) ); @@ -51,11 +96,9 @@ public function __construct($controller, $name = "Users_EditAccountForm") $this->extend("updateFormActions", $actions); - $required = RequiredFields::create([ - "FirstName", - "Surname", - "Email" - ]); + $required = RequiredFields::create( + $member->config()->required_fields + ); $this->extend("updateRequiredFields", $required); @@ -74,6 +117,8 @@ public function __construct($controller, $name = "Users_EditAccountForm") * Register a new member * * @param array $data User submitted data + * + * @return SS_HTTPResponse */ public function doUpdate($data) { @@ -85,14 +130,21 @@ public function doUpdate($data) // Check that a member isn't trying to mess up another users profile if (!empty($curr) && $member->canEdit($curr)) { - // Save member - $this->saveInto($member); - $member->write(); - - $this->sessionMessage( - _t("Users.DETAILSUPDATED", "Account details updated"), - ValidationResult::TYPE_GOOD - ); + try { + // Save member + $this->saveInto($member); + $member->write(); + + $this->sessionMessage( + _t("Users.DETAILSUPDATED", "Account details updated"), + ValidationResult::TYPE_GOOD + ); + } catch (Exception $e) { + $this->sessionMessage( + $e->getMessage(), + ValidationResult::TYPE_ERROR + ); + } } else { $this->sessionMessage( _t("Users.CANNOTEDIT", "You cannot edit this account"), diff --git a/templates/ilateral/SilverStripe/Users/Includes/ProfileSummary.ss b/templates/ilateral/SilverStripe/Users/Includes/ProfileSummary.ss index 38331a0..cb8b569 100644 --- a/templates/ilateral/SilverStripe/Users/Includes/ProfileSummary.ss +++ b/templates/ilateral/SilverStripe/Users/Includes/ProfileSummary.ss @@ -1,9 +1,10 @@ <% with $CurrentUser %>

- <% _t('Member.FIRSTNAME',"First Name") %> $FirstName
- <% _t('Member.SURNAME',"Surname") %> $Surname
- <% _t("Member.EMAIL","Email") %> $Email
+ <%t Member.FIRSTNAME "First Name" %> $FirstName
+ <%t Member.SURNAME "Surname" %> $Surname
+ <%t Member.EMAIL "Email" %> $Email
+ <%t Users.FirstRegistered "First Registered" %> $Created.Ago

<% end_with %> \ No newline at end of file