From b0022b23be09a0a1247a3c82124a8a8e0c2ba505 Mon Sep 17 00:00:00 2001 From: "lorchard@mozilla.com" Date: Mon, 3 Aug 2009 19:05:06 +0000 Subject: [PATCH] Bug 506913 - Re-organize account registration page and add fields; Bug 506952 - Add descriptive/help text to BYOB registration process; Refactored profile and login models, profile now creates login on registration instead of vice versa; Reworked DB schema files to start tracking versioned changes; git-svn-id: https://svn.mozilla.org/projects/byob/trunk@48448 4eb1ac78-321c-0410-a911-ec516a8615a5 --- .gitignore | 1 + .../base.sql} | 0 ...30-001-bug-506913-registration-changes.sql | 14 + application/config/schema-mysql/current.sql | 287 ++++++++++++++++++ application/i18n/en_US/form_errors_auth.php | 35 ++- application/models/login.php | 37 --- application/models/profile.php | 68 ++++- application/models/repack.php | 6 +- application/views/auth_profiles/login.php | 2 + application/views/auth_profiles/register.php | 202 ++++++++++-- .../views/auth_profiles/register_success.php | 24 ++ .../views/auth_profiles/verifyemail.php | 14 + application/views/index/index.php | 24 +- css/main.css | 27 +- js/byob/main.js | 22 +- .../controllers/auth_profiles.php | 50 ++- modules/auth_profiles/models/auth_login.php | 70 ----- modules/auth_profiles/models/auth_profile.php | 70 +++++ .../views/auth_profiles/register_success.php | 1 + modules/lmo_utils/helpers/MY_form.php | 11 +- 20 files changed, 773 insertions(+), 192 deletions(-) rename application/config/{schema-mysql.sql => schema-mysql/base.sql} (100%) create mode 100644 application/config/schema-mysql/changes/20090730-001-bug-506913-registration-changes.sql create mode 100644 application/config/schema-mysql/current.sql create mode 100644 application/views/auth_profiles/register_success.php create mode 100644 application/views/auth_profiles/verifyemail.php create mode 100644 modules/auth_profiles/views/auth_profiles/register_success.php diff --git a/.gitignore b/.gitignore index 986d4e8..fae7c38 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ Thumbs.db *.swp *.swo xfers/ +bin/exhaust-queue.sh application/cache/ application/logs/ application/tests/log/ diff --git a/application/config/schema-mysql.sql b/application/config/schema-mysql/base.sql similarity index 100% rename from application/config/schema-mysql.sql rename to application/config/schema-mysql/base.sql diff --git a/application/config/schema-mysql/changes/20090730-001-bug-506913-registration-changes.sql b/application/config/schema-mysql/changes/20090730-001-bug-506913-registration-changes.sql new file mode 100644 index 0000000..0a4e58f --- /dev/null +++ b/application/config/schema-mysql/changes/20090730-001-bug-506913-registration-changes.sql @@ -0,0 +1,14 @@ +-- +-- Changes for bug 506913 for registration reorg +-- +ALTER TABLE `profiles` + DROP COLUMN `org_address`, + CHANGE COLUMN `full_name` `first_name` varchar(255), + ADD COLUMN `last_name` varchar(128), + ADD COLUMN `is_personal` tinyint(2) NOT NULL default '0', + ADD COLUMN `address_1` varchar(255), + ADD COLUMN `address_2` varchar(255), + ADD COLUMN `city` varchar(255), + ADD COLUMN `state` varchar(32), + ADD COLUMN `zip` varchar(32), + ADD COLUMN `country` varchar(255); diff --git a/application/config/schema-mysql/current.sql b/application/config/schema-mysql/current.sql new file mode 100644 index 0000000..ad8280b --- /dev/null +++ b/application/config/schema-mysql/current.sql @@ -0,0 +1,287 @@ +-- MySQL dump 10.11 +-- +-- Host: localhost Database: byob2_test +-- ------------------------------------------------------ +-- Server version 5.0.77-log + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `logevents` +-- + +DROP TABLE IF EXISTS `logevents`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `logevents` ( + `id` int(11) NOT NULL auto_increment, + `uuid` char(64) default NULL, + `profile_id` int(11) default NULL, + `action` varchar(255) default NULL, + `details` text, + `data` text, + `created` datetime default NULL, + PRIMARY KEY (`id`), + KEY `uuid` (`uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Table structure for table `login_email_verification_tokens` +-- + +DROP TABLE IF EXISTS `login_email_verification_tokens`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `login_email_verification_tokens` ( + `id` int(11) NOT NULL auto_increment, + `login_id` int(11) default NULL, + `token` varchar(32) default NULL, + `value` varchar(255) default NULL, + PRIMARY KEY (`id`), + KEY `login_email_verification_tokens_ibfk_2` (`login_id`), + CONSTRAINT `login_email_verification_tokens_ibfk_2` FOREIGN KEY (`login_id`) REFERENCES `logins` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Table structure for table `login_password_reset_tokens` +-- + +DROP TABLE IF EXISTS `login_password_reset_tokens`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `login_password_reset_tokens` ( + `id` int(11) NOT NULL auto_increment, + `login_id` int(11) default NULL, + `token` varchar(32) default NULL, + PRIMARY KEY (`id`), + KEY `login_password_reset_tokens_ibfk_2` (`login_id`), + CONSTRAINT `login_password_reset_tokens_ibfk_2` FOREIGN KEY (`login_id`) REFERENCES `logins` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Table structure for table `logins` +-- + +DROP TABLE IF EXISTS `logins`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `logins` ( + `id` int(11) NOT NULL auto_increment, + `login_name` varchar(64) NOT NULL, + `email` varchar(255) NOT NULL, + `password` varchar(32) NOT NULL, + `created` datetime default NULL, + `last_login` datetime default NULL, + `active` tinyint(2) NOT NULL default '1', + `modified` datetime default NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `login_name` (`login_name`), + KEY `email` (`email`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Table structure for table `logins_profiles` +-- + +DROP TABLE IF EXISTS `logins_profiles`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `logins_profiles` ( + `id` int(11) NOT NULL auto_increment, + `login_id` int(11) NOT NULL, + `profile_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `login_id_profile_id` (`login_id`,`profile_id`), + KEY `logins_profiles_ibfk_2` (`profile_id`), + CONSTRAINT `logins_profiles_ibfk_1` FOREIGN KEY (`login_id`) REFERENCES `logins` (`id`) ON DELETE CASCADE, + CONSTRAINT `logins_profiles_ibfk_2` FOREIGN KEY (`profile_id`) REFERENCES `profiles` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Table structure for table `message_queue` +-- + +DROP TABLE IF EXISTS `message_queue`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `message_queue` ( + `uuid` varchar(40) NOT NULL, + `owner` varchar(255) default NULL, + `batch_uuid` varchar(40) default NULL, + `batch_seq` int(11) default '0', + `created` datetime default NULL, + `modified` datetime default NULL, + `scheduled_for` datetime default NULL, + `reserved_at` datetime default NULL, + `reserved_until` datetime default NULL, + `finished_at` datetime default NULL, + `priority` int(11) default '0', + `topic` varchar(255) default NULL, + `object` varchar(255) default NULL, + `method` varchar(255) default NULL, + `context` text, + `body` text, + `signature` char(32) default NULL, + PRIMARY KEY (`uuid`), + KEY `created` (`created`), + KEY `priority` (`priority`), + KEY `batch_seq` (`batch_seq`), + KEY `signature` (`signature`), + KEY `reserved_at` (`reserved_at`), + KEY `finished_at` (`finished_at`), + KEY `scheduled_for` (`scheduled_for`), + KEY `batch_uuid` (`batch_uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Table structure for table `products` +-- + +DROP TABLE IF EXISTS `products`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `products` ( + `id` int(10) unsigned NOT NULL auto_increment, + `name` varchar(32) NOT NULL default 'Firefox', + `version` varchar(32) NOT NULL default '', + `url` varchar(255) NOT NULL default '', + `locales` varchar(255) NOT NULL default 'en-US', + `disable_migration` tinyint(1) default '0', + `created` datetime default NULL, + `modified` datetime default NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Table structure for table `profile_attributes` +-- + +DROP TABLE IF EXISTS `profile_attributes`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `profile_attributes` ( + `id` int(11) NOT NULL auto_increment, + `profile_id` int(11) NOT NULL, + `name` varchar(255) default NULL, + `value` text, + PRIMARY KEY (`id`), + UNIQUE KEY `profile_id_name` (`profile_id`,`name`), + CONSTRAINT `profile_attributes_ibfk_1` FOREIGN KEY (`profile_id`) REFERENCES `profiles` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Table structure for table `profiles` +-- + +DROP TABLE IF EXISTS `profiles`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `profiles` ( + `id` int(11) NOT NULL auto_increment, + `uuid` varchar(40) NOT NULL, + `screen_name` varchar(64) NOT NULL, + `first_name` varchar(128) NOT NULL, + `last_name` varchar(128) NOT NULL, + `phone` varchar(24) default NULL, + `fax` varchar(24) default NULL, + `org_name` varchar(255) default NULL, + `org_type` varchar(32) default NULL, + `org_type_other` varchar(32) default NULL, + `address_1` varchar(255), + `address_2` varchar(255), + `city` varchar(255), + `state` varchar(32), + `zip` varchar(32), + `country` varchar(255), + `created` datetime default NULL, + `modified` datetime default NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `uuid` (`uuid`), + UNIQUE KEY `screen_name` (`screen_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Table structure for table `profiles_roles` +-- + +DROP TABLE IF EXISTS `profiles_roles`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `profiles_roles` ( + `id` int(11) NOT NULL auto_increment, + `role_id` int(11) NOT NULL, + `profile_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `role_id_profile_id` (`role_id`,`profile_id`), + KEY `profiles_roles_ibfk_2` (`profile_id`), + CONSTRAINT `profiles_roles_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE, + CONSTRAINT `profiles_roles_ibfk_2` FOREIGN KEY (`profile_id`) REFERENCES `profiles` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Table structure for table `repacks` +-- + +DROP TABLE IF EXISTS `repacks`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `repacks` ( + `id` int(10) unsigned NOT NULL auto_increment, + `uuid` char(64) NOT NULL default '0', + `created` datetime default NULL, + `modified` datetime default NULL, + `profile_id` int(10) unsigned NOT NULL, + `product_id` int(10) unsigned NOT NULL, + `short_name` varchar(128) default NULL, + `title` varchar(255) default NULL, + `description` text, + `state` int(11) default '0', + `json_data` text, + PRIMARY KEY (`id`), + KEY `created_by` (`profile_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Table structure for table `roles` +-- + +DROP TABLE IF EXISTS `roles`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `roles` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(32) default NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2009-06-26 3:33:57 diff --git a/application/i18n/en_US/form_errors_auth.php b/application/i18n/en_US/form_errors_auth.php index 33f89c9..e150f86 100644 --- a/application/i18n/en_US/form_errors_auth.php +++ b/application/i18n/en_US/form_errors_auth.php @@ -40,6 +40,8 @@ $lang = array( 'password' => array( 'default' => 'Password is invalid.', + 'length' + => 'Password must be at least 6 characters long.', 'required' => 'Password is required.' ), @@ -50,6 +52,8 @@ $lang = array( => 'Password and confirmation must match.' ), 'screen_name' => array( + 'default' + => 'Screen name is not available.', 'required' => 'Screen name is required.', 'length' @@ -59,11 +63,17 @@ $lang = array( 'isScreenNameAvailable' => 'Screen name is not available.', ), - 'full_name' => array( + 'first_name' => array( 'required' - => 'Full name is required', + => 'First name is required', 'standard_text' - => 'Full name must contain only alphanumeric characters' + => 'First name must contain only alphanumeric characters' + ), + 'last_name' => array( + 'required' + => 'Last name is required', + 'standard_text' + => 'Last name must contain only alphanumeric characters' ), 'org_name' => array( 'required' @@ -99,4 +109,23 @@ $lang = array( 'default' => 'A valid new email confirmation is required' ), + + 'phone' => array( + 'default' => 'Phone number is required.' + ), + 'address_1' => array( + 'default' => 'Street address is required.' + ), + 'city' => array( + 'default' => 'City is required.' + ), + 'state' => array( + 'default' => 'State is required.' + ), + 'zip' => array( + 'default' => 'Zip is required.' + ), + 'country' => array( + 'default' => 'Country is required.' + ), ); diff --git a/application/models/login.php b/application/models/login.php index 2df6c53..3a4b4a3 100644 --- a/application/models/login.php +++ b/application/models/login.php @@ -122,41 +122,4 @@ class Login_Model extends Auth_Login_Model return $is_valid; } - /** - * Validate registration data - */ - public function validate_registration(&$data) - { - // Force screen name to match login name. - if (isset($data['login_name'])) - $data['screen_name'] = $data['login_name']; - - $profile_model = new Profile_Model(); - - $data = Validation::factory($data) - ->pre_filter('trim') - ->add_rules('login_name', - 'required', 'length[3,64]', 'valid::alpha_dash', - array($this, 'is_login_name_available')) - ->add_rules('email', - 'required', 'length[3,255]', 'valid::email', - array($this, 'is_email_available')) - ->add_rules('email_confirm', - 'required', 'valid::email', 'matches[email]') - ->add_rules('password', 'required') - ->add_rules('password_confirm', 'required', 'matches[password]') - ->add_rules('screen_name', - 'required', 'length[3,64]', 'valid::alpha_dash', - array($profile_model, 'is_screen_name_available')) - ->add_rules('full_name', 'required', 'valid::standard_text') - ->add_rules('org_name', 'required') - ; - - if ('post' == request::method() && !recaptcha::check()) { - $data->add_error('recaptcha', recaptcha::error()); - } - - return $data->validate(); - } - } diff --git a/application/models/profile.php b/application/models/profile.php index 64ef7f0..344613d 100644 --- a/application/models/profile.php +++ b/application/models/profile.php @@ -19,20 +19,34 @@ class Profile_Model extends Auth_Profile_Model public $table_column_titles = array( 'id' => 'ID', 'uuid' => 'UUID', + 'screen_name' => 'Screen name', - 'full_name' => 'Full name', + 'first_name' => 'First name', + 'last_name' => 'Last name', 'phone' => 'Phone', 'fax' => 'Fax', - 'org_address' => 'Organization address', + + 'is_personal' => 'Is personal account', + 'org_name' => 'Organization name', 'org_type' => 'Organization type', 'org_type_other' => 'Organization type (other)', + + 'address_1' => 'Street Address 1', + 'address_2' => 'Street Address 2', + 'city' => 'City', + 'state' => 'State', + 'zip' => 'Zip / Postal Code', + 'country' => 'Country', + 'created' => 'Created', 'modified' => 'Modified', ); public $search_column_names = array( - 'screen_name', 'full_name', 'org_name', 'modified', + 'screen_name', 'first_name', 'last_name', 'org_name', 'modified', + 'org_type', 'org_type_other', 'phone', 'fax', + 'address_1', 'address_2', 'city', 'state', 'zip', 'country', ); // }}} @@ -80,6 +94,54 @@ class Profile_Model extends Auth_Profile_Model } + /** + * Validate registration data + */ + public function validate_registration(&$data) + { + // Force screen name to match login name. + if (isset($data['login_name'])) + $data['screen_name'] = $data['login_name']; + + // TODO: Use login model to validate login properties + $login_model = new Login_Model(); + + $data = Validation::factory($data) + ->pre_filter('trim') + ->add_rules('login_name', + 'required', 'length[4,12]', 'valid::alpha_dash', + array($login_model, 'is_login_name_available')) + ->add_rules('email', + 'required', 'length[3,255]', 'valid::email', + array($login_model, 'is_email_available')) + ->add_rules('email_confirm', + 'required', 'valid::email', 'matches[email]') + ->add_rules('password', 'length[6,255]', 'required') + ->add_rules('password_confirm', 'required', 'matches[password]') + ->add_rules('screen_name', + 'required', 'length[3,64]', 'valid::alpha_dash', + array($this, 'is_screen_name_available')) + ->add_rules('first_name', 'required', 'valid::standard_text') + ->add_rules('last_name', 'required') + ->add_rules('phone', 'required') + ->add_rules('website', 'url') + ->add_rules('address_1', 'required') + ->add_rules('city', 'required') + ->add_rules('state', 'required') + ->add_rules('zip', 'required') + ->add_rules('country', 'required') + ; + if (!isset($data['is_personal']) || $data['is_personal'] != 1) { + $data->add_rules('org_name', 'required'); + } + + if ('post' == request::method() && !recaptcha::check()) { + $data->add_error('recaptcha', recaptcha::error()); + } + + return $data->validate(); + } + /** * Validate form data for profile modification, optionally saving if valid. */ diff --git a/application/models/repack.php b/application/models/repack.php index 028fa60..09c3204 100644 --- a/application/models/repack.php +++ b/application/models/repack.php @@ -176,10 +176,8 @@ class Repack_Model extends ManagedORM break; case 'bookmarks': - $data->add_callbacks('bookmarks_toolbar', - array($this, 'extractBookmarks')); - $data->add_callbacks('bookmarks_menu', - array($this, 'extractBookmarks')); + $data->add_callbacks('bookmarks_toolbar', array($this, 'extractBookmarks')); + $data->add_callbacks('bookmarks_menu', array($this, 'extractBookmarks')); break; case 'addons': diff --git a/application/views/auth_profiles/login.php b/application/views/auth_profiles/login.php index 12c1dc7..672dc0e 100644 --- a/application/views/auth_profiles/login.php +++ b/application/views/auth_profiles/login.php @@ -1,3 +1,5 @@ + +

Sorry, that login has been disabled.

diff --git a/application/views/auth_profiles/register.php b/application/views/auth_profiles/register.php index d6e9020..7f29cf0 100644 --- a/application/views/auth_profiles/register.php +++ b/application/views/auth_profiles/register.php @@ -1,32 +1,174 @@ + + 'register'), array( - form::fieldset('login details', array('class'=>'login'), array( - form::field('input', 'login_name', 'Login name'), - form::field('input', 'email', 'Email'), - form::field('input', 'email_confirm', 'Email (confirm)'), - form::field('password', 'password', 'Password'), - form::field('password', 'password_confirm', 'Password (confirm)'), - )), - form::fieldset('personal details', array('class'=>'profile'), array( - form::field('input', 'full_name', 'Full Name'), - form::field('input', 'phone', 'Phone'), - form::field('input', 'fax', 'Fax'), - )), - form::fieldset('organization details', array('class'=>'organization'), array( - form::field('input', 'org_name', 'Name'), - form::field('textarea', 'org_address', 'Address'), - form::field('dropdown', 'org_type', 'Type', array( - 'options' => array( - 'corp' => 'Corporation', - 'nonprofit' => 'Non-Profit', - 'other' => 'Other', - ) - )), - form::field('input', 'org_type_other', 'Type (other)'), - )), - form::fieldset('finish', array(), array( - '
  • ' . recaptcha::html() . '
  • ', - form::field('submit', 'register', null, array('value'=>'Register')), - )) - )); +$state_list = array( + 'AL'=>"Alabama", 'AK'=>"Alaska", 'AZ'=>"Arizona", 'AR'=>"Arkansas", + 'CA'=>"California", 'CO'=>"Colorado", 'CT'=>"Connecticut", + 'DE'=>"Delaware", 'DC'=>"District Of Columbia", 'FL'=>"Florida", + 'GA'=>"Georgia", 'HI'=>"Hawaii", 'ID'=>"Idaho", 'IL'=>"Illinois", + 'IN'=>"Indiana", 'IA'=>"Iowa", 'KS'=>"Kansas", 'KY'=>"Kentucky", + 'LA'=>"Louisiana", 'ME'=>"Maine", 'MD'=>"Maryland", + 'MA'=>"Massachusetts", 'MI'=>"Michigan", 'MN'=>"Minnesota", + 'MS'=>"Mississippi", 'MO'=>"Missouri", 'MT'=>"Montana", + 'NE'=>"Nebraska", 'NV'=>"Nevada", 'NH'=>"New Hampshire", + 'NJ'=>"New Jersey", 'NM'=>"New Mexico", 'NY'=>"New York", + 'NC'=>"North Carolina", 'ND'=>"North Dakota", 'OH'=>"Ohio", + 'OK'=>"Oklahoma", 'OR'=>"Oregon", 'PA'=>"Pennsylvania", + 'RI'=>"Rhode Island", 'SC'=>"South Carolina", 'SD'=>"South Dakota", + 'TN'=>"Tennessee", 'TX'=>"Texas", 'UT'=>"Utah", 'VT'=>"Vermont", + 'VA'=>"Virginia", 'WA'=>"Washington", 'WV'=>"West Virginia", + 'WI'=>"Wisconsin", 'WY'=>"Wyoming" +); + +$countries = array( + "United States", "Canada", + "Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Antigua and + Barbuda", "Argentina", "Armenia", "Australia", "Austria", "Azerbaijan", + "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", + "Belize", "Benin", "Bhutan", "Bolivia", "Bosnia and Herzegovina", + "Botswana", "Brazil", "Brunei", "Bulgaria", "Burkina Faso", "Burundi", + "Cambodia", "Cameroon", "Cape Verde", "Central African Republic", + "Chad", "Chile", "China", "Colombi", "Comoros", "Congo (Brazzaville)", + "Congo", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba", "Cyprus", "Czech + Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "East + Timor (Timor Timur)", "Ecuador", "Egypt", "El Salvador", "Equatorial + Guinea", "Eritrea", "Estonia", "Ethiopia", "Fiji", "Finland", "France", + "Gabon", "Gambia, The", "Georgia", "Germany", "Ghana", "Greece", "Grenada", + "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Honduras", + "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", + "Israel", "Italy", "Jamaica", "Japan", "Jordan", "Kazakhstan", "Kenya", + "Kiribati", "Korea, North", "Korea, South", "Kuwait", "Kyrgyzstan", "Laos", + "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", + "Lithuania", "Luxembourg", "Macedonia", "Madagascar", "Malawi", "Malaysia", + "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", + "Mexico", "Micronesia", "Moldova", "Monaco", "Mongolia", "Morocco", + "Mozambique", "Myanmar", "Namibia", "Nauru", "Nepa", "Netherlands", "New + Zealand", "Nicaragua", "Niger", "Nigeria", "Norway", "Oman", "Pakistan", + "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", + "Poland", "Portugal", "Qatar", "Romania", "Russia", "Rwanda", "Saint Kitts + and Nevis", "Saint Lucia", "Saint Vincent", "Samoa", "San Marino", "Sao + Tome and Principe", "Saudi Arabia", "Senegal", "Serbia and Montenegro", + "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon + Islands", "Somalia", "South Africa", "Spain", "Sri Lanka", "Sudan", + "Suriname", "Swaziland", "Sweden", "Switzerland", "Syria", "Taiwan", + "Tajikistan", "Tanzania", "Thailand", "Togo", "Tonga", "Trinidad and + Tobago", "Tunisia", "Turkey", "Turkmenistan", "Tuvalu", "Uganda", + "Ukraine", "United Arab Emirates", "United Kingdom", + "Uruguay", "Uzbekistan", "Vanuatu", "Vatican City", "Venezuela", "Vietnam", + "Yemen", "Zambia", "Zimbabwe" +); +$country_list = array(); +foreach ($countries as $country) { + $country_list[$country] = $country; +} + +slot::start('login_details_intro'); +?> +
    +

    + This is your basic account information, and will be used to login to the Build + Your Own Browser application. Your e-mail address will be used for account + verification, status notifications, and password resets, and must be a valid + address. If you are creating a customized version of Firefox for distribution + by an organization, you must use an email account using that organization's + domain name to ensure your submissions are approved. +

    +

    * = Required field

    +
    + +
    +

    + We require information about you and, if applicable, the organization you + represent. It helps us understand who is using BYOB, and to give us additional + ways to contact you should the need arise. This information is used solely by + Mozilla, and will never be shared with or sold to anyone else. +

    +

    * = Required field

    +
    +'register'), array( + form::fieldset('Login Details', array('class'=>'login'), array( + '
  • ' . slot::get('login_details_intro') . '
  • ', + form::field('input', 'login_name', 'Login name', array('class'=>'required'), array( + "Enter the account name you will use to login to BYOB (4-12 ", + "characters in length; alphanumeric, underscore, and hyphens only)" + )), + form::field('input', 'email', 'Email', array('class'=>'required'), array( + )), + form::field('input', 'email_confirm', 'Email (confirm)', array('class'=>'required'), array( + "Enter a vaild email address. Verification will be ", + "required before your account is activated. If you are ", + "representing an organization, you must use an account with ", + "that organization's domain name or your submissions may be ", + "rejected." + )), + form::field('password', 'password', 'Password', array('class'=>'required'), array( + )), + form::field('password', 'password_confirm', 'Password (confirm)', array('class'=>'required'), array( + "Enter your password here. Passwords must be a minimum ", + "of six characters in length. If you forget your password, reset ", + "information will be sent to the email address above." + )), + )), + form::fieldset('Account Details', array('class'=>'account'), array( + '
  • ' . slot::get('account_details_intro') . '
  • ', + form::field('input', 'first_name', 'First Name', array('class'=>'required'), array( + 'Your given name.' + )), + form::field('input', 'last_name', 'Last Name', array('class'=>'required'), array( + 'Your surname.' + )), + + form::field('checkbox', 'is_personal', 'Personal account?', array('value'=>'1'), array( + "Please check this box if you are using the versions of ", + "Firefox you create for personal use (i.e. sharing with ", + "friends and family, etc.)" + )), + + form::field('dropdown', 'org_type', 'Organization Type', array( + 'options' => array( + 'corp' => 'Corporation', + 'nonprofit' => 'Non-Profit', + 'other' => 'Other', + ), + 'class'=>'required' + )), + form::field('input', 'org_type_other', '(other)'), + form::field('input', 'org_name', 'Organization Name', array('class'=>'required'), array( + "Please enter the full, legal name of the organization you represent here." + )), + + form::field('input', 'phone', 'Phone', array('class'=>'required'), array( + 'Your daytime contact number, with country code (US/Canada is "1").' + )), + form::field('input', 'fax', 'Fax', array(), array( + 'Your fax number, with country code (US/Canada is "1")' + )), + form::field('input', 'website', 'Website', array(), array( + 'Please provide the URL for your organizational or personal website.' + )), + + form::field('input', 'address_1', 'Street Address 1', array('class'=>'required')), + form::field('input', 'address_2', 'Street Address 2'), + form::field('input', 'city', 'City', array('class'=>'required')), + form::field('dropdown', 'state', 'State', array('class'=>'required', 'options'=>$state_list)), + form::field('input', 'zip', 'Zip / Postal Code', array('class'=>'required', 'class'=>'required'), array( + )), + form::field('dropdown', 'country', 'Country', array('class'=>'required', 'options'=>$country_list), array( + "Please provide your current mailing address or, if you are ", + "representing an organization, your organization's mailing address ", + "here." + )), + )), + form::fieldset('finish', array(), array( + '
  • ' . recaptcha::html() . '
  • ', + form::field('submit', 'register', null, array('value'=>'Register')), + )) +)); ?> diff --git a/application/views/auth_profiles/register_success.php b/application/views/auth_profiles/register_success.php new file mode 100644 index 0000000..94fe0e9 --- /dev/null +++ b/application/views/auth_profiles/register_success.php @@ -0,0 +1,24 @@ + +

    Registration successful

    + +

    + Your account has been created, but is not yet active. An email containing + information on how to activate your account has been sent to the address you + provided. You must activate your account before you can login to the Build Your + Own Browser application. Please check your email for this information, and + activate your account. +

    + +

    + If you do not receive this email within twenty-four hours, please contact us at + byob-help@mozilla.com. If you are using any spam prevention software, please + ensure that byob-registration@mozilla.com is whitelisted. +

    + +

    + You can also use the button below to re-send the account activation email: +

    + +
    + +
    diff --git a/application/views/auth_profiles/verifyemail.php b/application/views/auth_profiles/verifyemail.php new file mode 100644 index 0000000..c56e356 --- /dev/null +++ b/application/views/auth_profiles/verifyemail.php @@ -0,0 +1,14 @@ + +

    Invalid email verification token.

    + + +

    Account verification successful

    +

    + Welcome to Mozilla's Build Your Own Browser (BYOB) web application. + Your account has been successfully activated, and we've logged you in. + We've also set a cookie for you that will keep you logged in to the + application, so if you're using a computer that isn't always under your + control, you should log out when you're finished using BYOB by using the + "logout" link in the upper-right corner of every page. +

    + diff --git a/application/views/index/index.php b/application/views/index/index.php index a9c5d22..d5c4e76 100644 --- a/application/views/index/index.php +++ b/application/views/index/index.php @@ -2,16 +2,24 @@ - -

    Welcome!

    - -

    To get started building your own browser, - register and - login! - +

    + Welcome to Mozilla's Build Your Own Browser (BYOB) web application, a + web-based tool that allows you to lightly customize versions of Firefox + that you'd like to distribute to other people. To get started, we require + that you create an account and + login to the application. + All of the customized versions of Firefox you create with BYOB will be + associated with, and accessible through, this account. Registration takes just + a couple of minutes, requires information about you and the organization + you represent, if applicable. +

    -

    Welcome back!

    +

    + Welcome back to Mozilla's Build Your Own Browser (BYOB) web application, a + web-based tool that allows you to lightly customize versions of Firefox + that you'd like to distribute to other people. +

    0 ); + $.each([ 'org_name', 'org_type', 'org_type_other' ], function() { + if (checked) { + $('#'+this).attr('disabled', true) + .parent().removeClass('required'); + } else { + $('#'+this).removeAttr('disabled'); + $('#'+this).parent().addClass('required'); + } + }); + }; + org_personal.each(personal_cb).change(personal_cb); var org_type_other = org_fieldset.find('#org_type_other'); diff --git a/modules/auth_profiles/controllers/auth_profiles.php b/modules/auth_profiles/controllers/auth_profiles.php index eafc84b..e0612bd 100644 --- a/modules/auth_profiles/controllers/auth_profiles.php +++ b/modules/auth_profiles/controllers/auth_profiles.php @@ -27,7 +27,8 @@ class Auth_Profiles_Controller extends Local_Controller } } - $this->login_model = new Login_Model(); + $this->login_model = new Login_Model(); + $this->profile_model = new Profile_Model(); } /** @@ -62,32 +63,28 @@ class Auth_Profiles_Controller extends Local_Controller public function register() { $form_data = form::validate( - $this, $this->login_model, + $this, $this->profile_model, 'validate_registration', 'form_errors_auth' ); if (null===$form_data) return; - $new_login = $this->login_model - ->register_with_profile($form_data); + $new_profile = $this->profile_model + ->register_with_login($form_data); - if (!empty($new_login->email_verification_token)) { + if (!empty($new_profile->email_verification_token)) { email::send_view( - $new_login->new_email, + $new_profile->new_email, 'auth_profiles/register_email', array( 'email_verification_token' => - $new_login->email_verification_token, + $new_profile->email_verification_token, 'login_name' => - $new_login->login_name + $new_profile->login_name ) ); } - Session::instance()->set_flash( - 'message', - 'Check your email to verify your address before login.' - ); - - return url::redirect('login'); + $this->view->login_name = $new_profile->login_name; + $this->view->set_filename('auth_profiles/register_success'); } /** @@ -233,6 +230,8 @@ class Auth_Profiles_Controller extends Local_Controller ) ); $this->view->email_sent = TRUE; + $this->view->login_name = $params['login_name']; + $this->view->set_filename('auth_profiles/register_success'); } $this->view->login = $login; @@ -243,6 +242,11 @@ class Auth_Profiles_Controller extends Local_Controller */ public function verifyemail() { + if (false !== $this->input->get('success', false)) { + $this->view->valid_token = true; + return; + } + $token = ('post' == request::method()) ? $this->input->post('email_verification_token') : $this->input->get('email_verification_token'); @@ -253,21 +257,13 @@ class Auth_Profiles_Controller extends Local_Controller $this->view->invalid_token = true; return; } - $login->change_email($new_email); + //$login->change_email($new_email); // TODO: Make auto-login on email verification configurable? - if (!authprofiles::is_logged_in()) { - - $profile = $login->find_default_profile_for_login(); - $login->login(); - authprofiles::login($login->login_name, $login, $profile); - Session::instance()->set_flash( - 'message', - 'Email address verified. Welcome!' - ); - - return url::redirect('/home'); - } + $profile = $login->find_default_profile_for_login(); + $login->login(); + authprofiles::login($login->login_name, $login, $profile); + url::redirect(url::current().'?success=true'); } diff --git a/modules/auth_profiles/models/auth_login.php b/modules/auth_profiles/models/auth_login.php index 21dbf66..07ce598 100644 --- a/modules/auth_profiles/models/auth_login.php +++ b/modules/auth_profiles/models/auth_login.php @@ -88,44 +88,6 @@ class Auth_Login_Model extends ORM return true; } - - /** - * Create a new login and associated profile. - */ - public function register_with_profile($data, $force_email_verified=false) - { - $profile_data = array( - 'login_name' => $data['login_name'], - 'email' => ($force_email_verified) ? $data['email'] : '', - 'created' => gmdate('c', time()) - ); - - $new_login = ORM::factory('login')->set($profile_data)->save(); - - $new_login->change_password($data['password']); - - $profile_data['id'] = $new_login->id; - - if (!$force_email_verified) { - $profile_data['new_email'] = $data['email']; - $profile_data['email_verification_token'] = - $new_login->set_email_verification_token($data['email']); - } - - $new_profile = ORM::factory('profile')->set($data)->save(); - - $new_login->add($new_profile); - $new_login->save(); - - $data = array( - 'login' => $new_login->as_array(), - 'profile' => $new_profile->as_array() - ); - Event::run('auth_profiles.registered', $data); - - return arr::to_object($profile_data); - } - /** * Find the default profile for this login, usually the first registered. * @TODO: Change point for future multiple profiles per login @@ -307,38 +269,6 @@ class Auth_Login_Model extends ORM } - /** - * Replace incoming data with registration validator and return whether - * validation was successful. - * - * @param array Form data to validate - * @return boolean Validation success - */ - public function validate_registration(&$data) - { - $profile_model = new Profile_Model(); - - $data = Validation::factory($data) - ->pre_filter('trim') - ->add_rules('login_name', - 'required', 'length[3,64]', 'valid::alpha_dash', - array($this, 'is_login_name_available')) - ->add_rules('email', - 'required', 'length[3,255]', 'valid::email', - array($this, 'is_email_available')) - ->add_rules('email_confirm', - 'required', 'valid::email', 'matches[email]') - ->add_rules('password', 'required') - ->add_rules('password_confirm', 'required', 'matches[password]') - ->add_rules('screen_name', - 'required', 'length[3,64]', 'valid::alpha_dash', - array($profile_model, 'is_screen_name_available')) - ->add_rules('full_name', 'required', 'valid::standard_text') - ->add_rules('captcha', 'required', 'Captcha::valid') - ; - return $data->validate(); - } - /** * Replace incoming data with login validator and return whether * validation was successful. diff --git a/modules/auth_profiles/models/auth_profile.php b/modules/auth_profiles/models/auth_profile.php index dcd1481..91aff5b 100644 --- a/modules/auth_profiles/models/auth_profile.php +++ b/modules/auth_profiles/models/auth_profile.php @@ -95,6 +95,76 @@ class Auth_Profile_Model extends ORM } + /** + * Create a new login and associated profile. + */ + public function register_with_login($data, $force_email_verified=false) + { + $profile_data = array( + 'login_name' => $data['login_name'], + 'email' => ($force_email_verified) ? $data['email'] : '', + 'created' => gmdate('c', time()) + ); + + $new_login = ORM::factory('login')->set($profile_data)->save(); + + $new_login->change_password($data['password']); + + $profile_data['id'] = $new_login->id; + + if (!$force_email_verified) { + $profile_data['new_email'] = $data['email']; + $profile_data['email_verification_token'] = + $new_login->set_email_verification_token($data['email']); + } + + $new_profile = ORM::factory('profile')->set($data)->save(); + + $new_login->add($new_profile); + $new_login->save(); + + $data = array( + 'login' => $new_login->as_array(), + 'profile' => $new_profile->as_array() + ); + Event::run('auth_profiles.registered', $data); + + return arr::to_object($profile_data); + } + + + /** + * Replace incoming data with registration validator and return whether + * validation was successful. + * + * @param array Form data to validate + * @return boolean Validation success + */ + public function validate_registration(&$data) + { + $login_model = new Login_Model(); + + $data = Validation::factory($data) + ->pre_filter('trim') + ->add_rules('login_name', + 'required', 'length[3,64]', 'valid::alpha_dash', + array($this, 'is_login_name_available')) + ->add_rules('email', + 'required', 'length[3,255]', 'valid::email', + array($this, 'is_email_available')) + ->add_rules('email_confirm', + 'required', 'valid::email', 'matches[email]') + ->add_rules('password', 'required') + ->add_rules('password_confirm', 'required', 'matches[password]') + ->add_rules('screen_name', + 'required', 'length[3,64]', 'valid::alpha_dash', + array($profile_model, 'is_screen_name_available')) + ->add_rules('full_name', 'required', 'valid::standard_text') + ->add_rules('captcha', 'required', 'Captcha::valid') + ; + return $data->validate(); + } + /** * Validate form data for profile creation, optionally saving it if valid. */ diff --git a/modules/auth_profiles/views/auth_profiles/register_success.php b/modules/auth_profiles/views/auth_profiles/register_success.php new file mode 100644 index 0000000..99aacce --- /dev/null +++ b/modules/auth_profiles/views/auth_profiles/register_success.php @@ -0,0 +1 @@ +Check your email to verify your address before login. diff --git a/modules/lmo_utils/helpers/MY_form.php b/modules/lmo_utils/helpers/MY_form.php index 2d4088e..c381779 100644 --- a/modules/lmo_utils/helpers/MY_form.php +++ b/modules/lmo_utils/helpers/MY_form.php @@ -121,6 +121,10 @@ class form extends form_Core { if (null == $params) $params = array(); + $params_class = (isset($params['class'])) ? + $params['class'] : ''; + unset($params['class']); + if ('checkbox' == $type) { // For checkboxes, the checked attribute is the significant thing. $value = form::value($name, @$params['checked']); @@ -137,9 +141,8 @@ class form extends form_Core } else { $classes = array($type); - if (!empty($params['class'])) { - $classes[] = $params['class']; - unset($params['class']); + if (!empty($params_class)) { + $classes[] = $params_class; } if ('checkbox' == $type) { @@ -180,6 +183,8 @@ class form extends form_Core // List item classes consist of the name of the field type, along // with 'error' if field present in $form::errors $classes = array($type); + if (!empty($params_class)) + $classes[] = $params_class; if ('input' == $type) $classes[] = isset($params['type']) ? $params['type'] : 'text'; if (!empty(self::$errors) && array_key_exists($name, self::$errors))