]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 218917 - Allow the login name to be different from the email address
authorFrédéric Buclin <LpSolit@gmail.com>
Wed, 27 Apr 2016 16:50:13 +0000 (18:50 +0200)
committerFrédéric Buclin <LpSolit@gmail.com>
Wed, 27 Apr 2016 16:50:13 +0000 (18:50 +0200)
Original patch by Gervase Markham
r=gerv a=dkl

78 files changed:
Bugzilla/API/1_0/Resource/Bug.pm
Bugzilla/API/1_0/Resource/Bugzilla.pm
Bugzilla/API/1_0/Resource/Group.pm
Bugzilla/API/1_0/Resource/Product.pm
Bugzilla/API/1_0/Resource/User.pm
Bugzilla/API/1_0/Util.pm
Bugzilla/Auth.pm
Bugzilla/Auth/Verify.pm
Bugzilla/Auth/Verify/LDAP.pm
Bugzilla/Auth/Verify/RADIUS.pm
Bugzilla/Config.pm
Bugzilla/Config/Auth.pm
Bugzilla/Config/BugChange.pm
Bugzilla/Config/Common.pm
Bugzilla/DB/Schema.pm
Bugzilla/FlagType.pm
Bugzilla/Group.pm
Bugzilla/Hook.pm
Bugzilla/Install.pm
Bugzilla/Install/DB.pm
Bugzilla/Template.pm
Bugzilla/Token.pm
Bugzilla/User.pm
Bugzilla/Util.pm
Bugzilla/WebService/Bug.pm
Bugzilla/WebService/Bugzilla.pm
Bugzilla/WebService/Group.pm
Bugzilla/WebService/Product.pm
Bugzilla/WebService/Server/JSONRPC.pm
Bugzilla/WebService/Server/XMLRPC.pm
Bugzilla/WebService/User.pm
buglist.cgi
checksetup.pl
createaccount.cgi
docs/en/rst/administering/parameters.rst
docs/en/rst/administering/users.rst
docs/en/rst/api/core/v1/bug.rst
docs/en/rst/api/core/v1/bugzilla.rst
docs/en/rst/api/core/v1/user.rst
editgroups.cgi
editparams.cgi
editusers.cgi
email_in.pl
extensions/Voting/Extension.pm
sanitycheck.cgi
skins/standard/global.css
t/007util.t
t/008filter.t
template/en/default/account/auth/login-small.html.tmpl
template/en/default/account/auth/login.html.tmpl
template/en/default/account/cancel-token.txt.tmpl
template/en/default/account/create.html.tmpl
template/en/default/account/created.html.tmpl
template/en/default/account/email/confirm-new.html.tmpl
template/en/default/account/email/request-new.txt.tmpl
template/en/default/account/prefs/account.html.tmpl
template/en/default/account/request-new-password.html.tmpl
template/en/default/admin/flag-type/edit.html.tmpl
template/en/default/admin/groups/confirm-remove.html.tmpl
template/en/default/admin/groups/edit.html.tmpl
template/en/default/admin/params/auth.html.tmpl
template/en/default/admin/params/ldap.html.tmpl
template/en/default/admin/users/confirm-delete.html.tmpl
template/en/default/admin/users/list.html.tmpl
template/en/default/admin/users/search.html.tmpl
template/en/default/admin/users/userdata.html.tmpl
template/en/default/bug/edit.html.tmpl
template/en/default/bug/show.xml.tmpl
template/en/default/email/whine.txt.tmpl
template/en/default/global/messages.html.tmpl
template/en/default/global/user-error.html.tmpl
template/en/default/global/user.html.tmpl
template/en/default/reports/delete-series.html.tmpl
template/en/default/reports/edit-series.html.tmpl
token.cgi
userprefs.cgi
whineatnews.pl
xt/selenium/password_complexity.t

index 781ac3176f1d2b40e004fa2a9601ec29ddaf8900..b0182a5e3db3c56a159e9e26e187c0a2cfef0983 100644 (file)
@@ -509,7 +509,7 @@ sub _translate_comment {
     my $comment_hash = {
         id            => as_int($comment->id),
         bug_id        => as_int($comment->bug_id),
-        creator       => as_email($comment->author->login),
+        creator       => as_login($comment->author->login),
         time          => as_datetime($comment->creation_ts),
         creation_time => as_datetime($comment->creation_ts),
         is_private    => as_boolean($comment->is_private),
@@ -1431,7 +1431,7 @@ sub _bug_to_hash {
         $item{alias} = as_string_array($bug->alias);
     }
     if (filter_wants $params, 'assigned_to') {
-        $item{'assigned_to'} = as_email($bug->assigned_to->login);
+        $item{'assigned_to'} = as_login($bug->assigned_to->login);
         $item{'assigned_to_detail'} = $self->_user_to_hash($bug->assigned_to, $params, undef, 'assigned_to');
     }
     if (filter_wants $params, 'blocks') {
@@ -1444,14 +1444,14 @@ sub _bug_to_hash {
         $item{component} = as_string($bug->component);
     }
     if (filter_wants $params, 'cc') {
-        $item{'cc'} = as_email_array($bug->cc);
+        $item{'cc'} = as_login_array($bug->cc);
         $item{'cc_detail'} = [ map { $self->_user_to_hash($_, $params, undef, 'cc') } @{ $bug->cc_users } ];
     }
     if (filter_wants $params, 'creation_time') {
         $item{'creation_time'} = as_datetime($bug->creation_ts);
     }
     if (filter_wants $params, 'creator') {
-        $item{'creator'} = as_email($bug->reporter->login);
+        $item{'creator'} = as_login($bug->reporter->login);
         $item{'creator_detail'} = $self->_user_to_hash($bug->reporter, $params, undef, 'creator');
     }
     if (filter_wants $params, 'depends_on') {
@@ -1477,7 +1477,7 @@ sub _bug_to_hash {
     }
     if (filter_wants $params, 'qa_contact') {
         my $qa_login = $bug->qa_contact ? $bug->qa_contact->login : '';
-        $item{'qa_contact'} = as_email($qa_login);
+        $item{'qa_contact'} = as_login($qa_login);
         if ($bug->qa_contact) {
             $item{'qa_contact_detail'} = $self->_user_to_hash($bug->qa_contact, $params, undef, 'qa_contact');
         }
@@ -1546,8 +1546,7 @@ sub _user_to_hash {
     my $item = filter $filters, {
         id        => as_int($user->id),
         real_name => as_string($user->name),
-        name      => as_email($user->login),
-        email     => as_email($user->email),
+        name      => as_login($user->login),
     }, $types, $prefix;
     return $item;
 }
@@ -1571,7 +1570,7 @@ sub _attachment_to_hash {
     # creator requires an extra lookup, so we only send them if
     # the filter wants them.
     if (filter_wants $filters, 'creator', $types, $prefix) {
-        $item->{'creator'} = as_email($attach->attacher->login);
+        $item->{'creator'} = as_login($attach->attacher->login);
     }
 
     if (filter_wants $filters, 'data', $types, $prefix) {
@@ -1603,7 +1602,7 @@ sub _flag_to_hash {
 
     foreach my $field (qw(setter requestee)) {
         my $field_id = $field . "_id";
-        $item->{$field} = as_email($flag->$field->login)
+        $item->{$field} = as_login($flag->$field->login)
             if $flag->$field_id;
     }
 
@@ -2672,10 +2671,6 @@ C<string> The 'real' name for this user, if any.
 
 C<string> The user's Bugzilla login.
 
-=item C<email>
-
-C<string> The user's email address. Currently this is the same value as the name.
-
 =back
 
 =back
index f5bb2f4170b2a9383da1cd016c903df4c5a4d95e..fc2e15e9033190b164f669cc011b7f98e8220f2f 100644 (file)
@@ -69,7 +69,6 @@ use constant PARAMETERS_LOGGED_IN => qw(
     defaultseverity
     duplicate_or_move_bug_status
     emailregexpdesc
-    emailsuffix
     letsubmitterchoosemilestone
     letsubmitterchoosepriority
     mailfrom
@@ -82,6 +81,7 @@ use constant PARAMETERS_LOGGED_IN => qw(
     requirelogin
     search_allow_no_criteria
     urlbase
+    use_email_as_login
     use_see_also
     useclassification
     usemenuforusers
@@ -449,7 +449,6 @@ A logged-in user can access the following parameters (listed alphabetically):
     C<defaultseverity>,
     C<duplicate_or_move_bug_status>,
     C<emailregexpdesc>,
-    C<emailsuffix>,
     C<letsubmitterchoosemilestone>,
     C<letsubmitterchoosepriority>,
     C<mailfrom>,
@@ -462,6 +461,7 @@ A logged-in user can access the following parameters (listed alphabetically):
     C<requirelogin>,
     C<search_allow_no_criteria>,
     C<urlbase>,
+    C<use_email_as_login>,
     C<use_see_also>,
     C<useclassification>,
     C<usemenuforusers>,
index 43a2521fb6fa1dc8bf0fddb8cb8c99003ccfaffd..f3b55b3fd8144b8b0cf039b1b0f0fc45646e1175 100644 (file)
@@ -247,8 +247,8 @@ sub _get_group_membership {
         map {{
             id                => as_int($_->id),
             real_name         => as_string($_->name),
-            name              => as_string($_->login),
-            email             => as_string($_->email),
+            name              => as_login($_->login),
+            email             => as_email($_->email),
             can_login         => as_boolean($_->is_enabled),
             email_enabled     => as_boolean($_->email_enabled),
             login_denied_text => as_string($_->disabledtext),
@@ -571,12 +571,12 @@ C<string> The actual name of the user.
 
 =item email
 
-C<string> The email address of the user.
+C<string> If you are in the editusers group, returns the email address of the
+user, else returns nothing.
 
 =item name
 
-C<string> The login name of the user. Note that in some situations this is
-different than their email.
+C<string> The login name of the user.
 
 =item can_login
 
index d3576a734f2c2f0e1d134fc3b085103d9e62db92..02581b0edc8497a48dd04165f870bb9b982bec66 100644 (file)
@@ -322,9 +322,9 @@ sub _component_to_hash {
         name        => as_string($component->name),
         description => as_string($component->description),
         default_assigned_to =>
-            as_email($component->default_assignee->login),
+            as_login($component->default_assignee->login),
         default_qa_contact =>
-            as_email($component->default_qa_contact ?
+            as_login($component->default_qa_contact ?
                      $component->default_qa_contact->login : ""),
         sort_key => 0, # sort_key is returned to match Bug.fields
         is_active => as_boolean($component->is_active),
index a214bd81f24c0d6a3ad74b060b7ad6bb322c65ae..101a70529a06b5b98b3bfde2de57d7970c48ce0a 100644 (file)
@@ -53,13 +53,11 @@ use constant PUBLIC_METHODS => qw(
 );
 
 use constant MAPPED_FIELDS => {
-    email => 'login',
     full_name => 'name',
     login_denied_text => 'disabledtext',
 };
 
 use constant MAPPED_RETURNS => {
-    login_name => 'email',
     realname => 'full_name',
     disabledtext => 'login_denied_text',
 };
@@ -158,8 +156,11 @@ sub offer_account_by_email {
     my $email = trim($params->{email})
         || ThrowCodeError('param_required', { param => 'email' });
 
+    my $login = Bugzilla->params->{use_email_as_login} ? $email : trim($params->{login});
+    $login or ThrowCodeError('param_required', { param => 'login' });
+
     Bugzilla->user->check_account_creation_enabled;
-    Bugzilla->user->check_and_send_account_creation_confirmation($email);
+    Bugzilla->user->check_and_send_account_creation_confirmation($login, $email);
     return undef;
 }
 
@@ -174,11 +175,16 @@ sub create {
 
     my $email = trim($params->{email})
         || ThrowCodeError('param_required', { param => 'email' });
+
+    my $login = Bugzilla->params->{use_email_as_login} ? $email : trim($params->{login});
+    $login or ThrowCodeError('param_required', { param => 'login' });
+
     my $realname = trim($params->{full_name});
     my $password = trim($params->{password}) || '*';
 
     my $user = Bugzilla::User->create({
-        login_name    => $email,
+        login_name    => $login,
+        email         => $email,
         realname      => $realname,
         cryptpassword => $password
     });
@@ -225,7 +231,7 @@ sub get {
         @users = map { filter $params, {
                      id        => as_int($_->id),
                      real_name => as_string($_->name),
-                     name      => as_email($_->login),
+                     name      => as_login($_->login),
                  } } @$in_group;
 
         return { users => \@users };
@@ -277,12 +283,12 @@ sub get {
         my $user_info = filter $params, {
             id        => as_int($user->id),
             real_name => as_string($user->name),
-            name      => as_email($user->login),
-            email     => as_email($user->email),
+            name      => as_login($user->login),
             can_login => as_boolean($user->is_enabled ? 1 : 0),
         };
 
         if (Bugzilla->user->in_group('editusers')) {
+            $user_info->{email}             = as_email($user->email),
             $user_info->{email_enabled}     = as_boolean($user->email_enabled);
             $user_info->{login_denied_text} = as_string($user->disabledtext);
         }
@@ -651,6 +657,8 @@ This is the recommended way to create a Bugzilla account.
 
 =item C<email> (string) - the email to send the offer to.
 
+=item C<login> (string) - the login of the user account.
+
 =back
 
 =item B<Returns> (nothing)
@@ -699,6 +707,11 @@ are the same as below.
 
 =item C<email> (string) - The email address for the new user.
 
+=item C<login> (string) - The login name for the new user.
+If the installation has the C<use_email_as_login> parameter switched on, then
+this parameter is ignored, and the value of the C<email> parameter will
+be used as the login name for the new account.
+
 =item C<full_name> (string) B<Optional> - The user's full name. Will
 be set to empty if not specified.
 
@@ -768,7 +781,7 @@ C<array> Contains ids of user to update.
 
 =item C<names>
 
-C<array> Contains email/login of user to update.
+C<array> Contains login of user to update.
 
 =item C<full_name>
 
@@ -996,8 +1009,7 @@ C<string> The email address of the user.
 
 =item name
 
-C<string> The login name of the user. Note that in some situations this is
-different than their email.
+C<string> The login name of the user.
 
 =item can_login
 
@@ -1083,7 +1095,7 @@ C<string> The CGI parameters for the saved report.
 B<Note>: If you are not logged in to Bugzilla when you call this function, you
 will only be returned the C<id>, C<name>, and C<real_name> items. If you are
 logged in and not in editusers group, you will only be returned the C<id>, C<name>,
-C<real_name>, C<email>, C<can_login>, and C<groups> items. The groups returned are
+C<real_name>, C<can_login>, and C<groups> items. The groups returned are
 filtered based on your permission to bless each group.
 The C<saved_searches> and C<saved_reports> items are only returned if you are
 querying your own account, even if you are in the editusers group.
index ce4487c1fc59964dec3767cf4acf19b69433cd04..13c3eebacf60dc6ad90e9904b787682eb084265b 100644 (file)
@@ -33,9 +33,10 @@ our @EXPORT = qw(
     as_datetime
     as_double
     as_email
-    as_email_array
     as_int
     as_int_array
+    as_login
+    as_login_array
     as_name_array
     as_string
     as_string_array
@@ -367,8 +368,8 @@ sub as_string   { defined $_[0] ? $_[0] . ''  : JSON::null }
 
 # array types
 
-sub as_email_array  { [ map { as_email($_) }        @{ $_[0] // [] } ] }
 sub as_int_array    { [ map { as_int($_) }          @{ $_[0] // [] } ] }
+sub as_login_array  { [ map { as_login($_) }        @{ $_[0] // [] } ] }
 sub as_name_array   { [ map { as_string($_->name) } @{ $_[0] // [] } ] }
 sub as_string_array { [ map { as_string($_) }       @{ $_[0] // [] } ] }
 
@@ -380,10 +381,14 @@ sub as_datetime {
         : JSON::null;
 }
 
-sub as_email    {
+sub as_login    {
     defined $_[0]
-        ? ( Bugzilla->params->{webservice_email_filter} ? email_filter($_[0]) : $_[0] . '' )
-        : JSON::null
+        ? ( Bugzilla->params->{use_email_as_login} ? email_filter($_[0]) : $_[0] . '' )
+        : JSON::null;
+}
+
+sub as_email    {
+    defined($_[0]) && Bugzilla->user->in_group('editusers') ? $_[0] . '' : JSON::null;
 }
 
 sub as_base64   {
@@ -496,13 +501,9 @@ double value. If parameter is undefined, returns JSON::null.
 
 =head2 as_email
 
-Takes an email address as a parameter if filters it if C<webservice_email_filter> is
-enabled in the system settings. If parameter is undefined, returns JSON::null.
-
-=head2 as_email_array
-
-Similar to C<as_email>, but takes an array reference to a list of values and
-returns an array reference with the converted values.
+Takes an email address as a parameter. If the user is in the editusers group,
+it returns the email address, unchanged. If the parameter is undefined or the
+user is not in the editusers group, it returns JSON::null.
 
 =head2 as_int
 
@@ -514,6 +515,18 @@ value. If parameter is undefined, returns JSON::null.
 Similar to C<as_int>, but takes an array reference to a list of values and
 returns an array reference with the converted values.
 
+=head2 as_login
+
+Takes a login name as a parameter. If C<use_email_as_login> is enabled and the
+user is logged out, it returns the local part of the email address (the part
+before '@'). Else it returns the full login name. If parameter is undefined,
+returns JSON::null.
+
+=head2 as_login_array
+
+Similar to C<as_login>, but takes an array reference to a list of values and
+returns an array reference with the converted values.
+
 =head2 as_name_array
 
 Takes a list of L<Bugzilla::Object> values and returns an array of new values
index 399f68d24eb888f68518443e099802d8fa8fba29..d693bf12d3f4d3dbfa1efa10123d90eb5ea6da13 100644 (file)
@@ -136,6 +136,10 @@ sub extern_id_used {
            ||  $self->{_verifier}->extern_id_used;
 }
 
+sub can_change_login {
+    return $_[0]->user_can_create_account;
+}
+
 sub can_change_email {
     return $_[0]->user_can_create_account;
 }
@@ -412,6 +416,14 @@ Returns:     C<true> if users are allowed to create new Bugzilla accounts,
 
 Description: Whether or not current login system uses extern_id.
 
+=item C<can_change_login>
+
+Description: Whether or not the current login system allows users to
+             change their own login.
+Params:      None
+Returns:     C<true> if users can change their own login,
+             C<false> otherwise.
+
 =item C<can_change_email>
 
 Description: Whether or not the current login system allows users to
index ef5b749b1bfecfd0b3aaa1feab53759587d7666f..20318b3a546ca083877aec9b78f4fd8b32a4946f 100644 (file)
@@ -36,7 +36,8 @@ sub create_or_update_user {
     my $dbh = Bugzilla->dbh;
 
     my $extern_id = $params->{extern_id};
-    my $username  = $params->{bz_username} || $params->{username};
+    my $login     = $params->{bz_username} || $params->{username};
+    my $email     = Bugzilla->params->{use_email_as_login} ? $login : $params->{email};
     my $password  = $params->{password} || '*';
     my $real_name = $params->{realname} || '';
     my $user_id   = $params->{user_id};
@@ -44,7 +45,7 @@ sub create_or_update_user {
     # A passed-in user_id always overrides anything else, for determining
     # what account we should return.
     if (!$user_id) {
-        my $username_user_id = login_to_id($username || '');
+        my $login_user_id = login_to_id($login || '');
         my $extern_user_id;
         if ($extern_id) {
             trick_taint($extern_id);
@@ -52,26 +53,26 @@ sub create_or_update_user {
                  FROM profiles WHERE extern_id = ?', undef, $extern_id);
         }
 
-        # If we have both a valid extern_id and a valid username, and they are
+        # If we have both a valid extern_id and a valid login, and they are
         # not the same id, then we have a conflict.
-        if ($username_user_id && $extern_user_id
-            && $username_user_id ne $extern_user_id)
+        if ($login_user_id && $extern_user_id
+            && $login_user_id ne $extern_user_id)
         {
             my $extern_name = Bugzilla::User->new($extern_user_id)->login;
             return { failure => AUTH_ERROR, error => "extern_id_conflict",
                      details => {extern_id   => $extern_id,
                                  extern_user => $extern_name,
-                                 username    => $username} };
+                                 username    => $login} };
         }
 
-        # If we have a valid username, but no valid id,
+        # If we have a valid login, but no valid id,
         # then we have to create the user. This happens when we're
-        # passed only a username, and that username doesn't exist already.
-        if ($username && !$username_user_id && !$extern_user_id) {
-            validate_email_syntax($username)
-              || return { failure => AUTH_ERROR, 
+        # passed only a login, and that login doesn't exist already.
+        if ($login && !$login_user_id && !$extern_user_id) {
+            validate_email_syntax($email)
+              || return { failure => AUTH_ERROR,
                           error   => 'auth_invalid_email',
-                          details => {addr => $username} };
+                          details => {addr => $email} };
             # Usually we'd call validate_password, but external authentication
             # systems might follow different standards than ours. So in this
             # place here, we call trick_taint without checks.
@@ -79,23 +80,24 @@ sub create_or_update_user {
 
             # XXX Theoretically this could fail with an error, but the fix for
             # that is too involved to be done right now.
-            my $user = Bugzilla::User->create({ 
-                login_name    => $username, 
+            my $user = Bugzilla::User->create({
+                login_name    => $login,
+                email         => $email,
                 cryptpassword => $password,
                 realname      => $real_name});
-            $username_user_id = $user->id;
+            $login_user_id = $user->id;
         }
 
-        # If we have a valid username id and an extern_id, but no valid
+        # If we have a valid login id and an extern_id, but no valid
         # extern_user_id, then we have to set the user's extern_id.
-        if ($extern_id && $username_user_id && !$extern_user_id) {
+        if ($extern_id && $login_user_id && !$extern_user_id) {
             $dbh->do('UPDATE profiles SET extern_id = ? WHERE userid = ?',
-                     undef, $extern_id, $username_user_id);
-            Bugzilla->memcached->clear({ table => 'profiles', id => $username_user_id });
+                     undef, $extern_id, $login_user_id);
+            Bugzilla->memcached->clear({ table => 'profiles', id => $login_user_id });
         }
 
         # Finally, at this point, one of these will give us a valid user id.
-        $user_id = $extern_user_id || $username_user_id;
+        $user_id = $extern_user_id || $login_user_id;
     }
 
     # If we still don't have a valid user_id, then we weren't passed
@@ -109,11 +111,15 @@ sub create_or_update_user {
     # Now that we have a valid User, we need to see if any data has to be updated.
     my $changed = 0;
 
-    if ($username && lc($user->login) ne lc($username)) {
-        validate_email_syntax($username)
+    if ($email && lc($user->email) ne lc($email)) {
+        validate_email_syntax($email)
           || return { failure => AUTH_ERROR, error => 'auth_invalid_email',
-                      details => {addr => $username} };
-        $user->set_login($username);
+                      details => {addr => $email} };
+        $user->set_email($email);
+        $changed = 1;
+    }
+    if ($login && lc($user->login) ne lc($login)) {
+        $user->set_login($login);
         $changed = 1;
     }
     if ($real_name && $user->name ne $real_name) {
index cd2e6437047b06022d8d52909dd9a6a013d8ea75..2ff38a2179081844bf06f7d314cdaf8c50221c3c 100644 (file)
@@ -99,23 +99,21 @@ sub check_credentials {
         my @emails = $user_entry->get_value($mail_attr);
 
         # Default to the first email address returned.
-        $params->{bz_username} = $emails[0];
+        $params->{email} = $emails[0];
 
         if (@emails > 1) {
             # Cycle through the adresses and check if they're Bugzilla logins.
             # Use the first one that returns a valid id. 
             foreach my $email (@emails) {
-                if ( login_to_id($email) ) {
-                    $params->{bz_username} = $email;
+                if ( email_to_id($email) ) {
+                    $params->{email} = $email;
                     last;
                 }
             }
         }
-
-    } else {
-        $params->{bz_username} = $username;
     }
 
+    $params->{bz_username} = $username;
     $params->{realname}  ||= $user_entry->get_value("displayName");
     $params->{realname}  ||= $user_entry->get_value("cn");
 
index 60be52a076f10596a6edaa1b5c678b4b945f64b8..163058c54010829bd1630dfd7efaf266b9867e5d 100644 (file)
@@ -46,8 +46,10 @@ sub check_credentials {
                        Bugzilla->params->{'RADIUS_NAS_IP'} || undef)
         || return { failure => AUTH_LOGINFAILED };
 
+    $params->{bz_username} = $username;
+
     # Build the user account's e-mail address.
-    $params->{bz_username} = $username . $address_suffix;
+    $params->{email} = $username . $address_suffix;
 
     return $params;
 }
index 7a7ba3a3e1dfd6bebc942b7fae8d55e238fd6ab0..79b468f0c8d640c8e11cee7a56030e7ac1812b14 100644 (file)
@@ -29,7 +29,10 @@ use File::Basename;
 # when it shouldn't
 %Bugzilla::Config::EXPORT_TAGS =
   (
-   admin => [qw(update_params SetParam write_params)],
+   admin => [qw(update_params
+                SetParam
+                call_param_onchange_handlers
+                write_params)],
   );
 Exporter::export_ok_tags('admin');
 
@@ -78,7 +81,7 @@ sub param_panels {
 sub SetParam {
     my ($name, $value) = @_;
 
-    _load_params unless %params;
+    _load_params() unless %params;
     die "Unknown param $name" unless (exists $params{$name});
 
     my $entry = $params{$name};
@@ -96,6 +99,19 @@ sub SetParam {
     Bugzilla->params->{$name} = $value;
 }
 
+sub call_param_onchange_handlers {
+    my ($changes) = @_;
+
+    _load_params() unless %params;
+
+    foreach my $name (@$changes) {
+        my $param = $params{$name};
+        if (exists $param->{'onchange'}) {
+            $param->{'onchange'}->(Bugzilla->params->{$name});
+        }
+    }
+}
+
 sub update_params {
     my ($params) = @_;
     my $answer = Bugzilla->installation_answers;
@@ -211,7 +227,7 @@ sub update_params {
 
     # --- DEFAULTS FOR NEW PARAMS ---
 
-    _load_params unless %params;
+    _load_params() unless %params;
     foreach my $name (keys %params) {
         my $item = $params{$name};
         unless (exists $param->{$name}) {
@@ -228,8 +244,10 @@ sub update_params {
         }
     }
 
-    # Bug 452525: OR based groups are on by default for new installations
-    $param->{'or_groups'} = 1 if $new_install;
+    if ($new_install) {
+        $param->{'or_groups'} = 1;
+        $param->{'use_email_as_login'} = 0;
+    }
 
     # --- REMOVE OLD PARAMS ---
 
@@ -341,6 +359,7 @@ Bugzilla::Config - Configuration parameters for Bugzilla
 
   update_params();
   SetParam($param, $value);
+  call_param_onchange_handlers(\@changes);
   write_params();
 
 =head1 DESCRIPTION
@@ -371,6 +390,16 @@ Prints out information about what it's doing, if it makes any changes.
 May prompt the user for input, if certain required parameters are not
 specified.
 
+=item C<call_param_onchange_handlers(\@changes)>
+
+Expects a list of parameter names.
+For each parameter, checks whether there is a change handler defined,
+and if so, calls it.
+
+Params:  C<\@changes> (required) - A list of parameter names.
+
+Returns: nothing
+
 =item C<write_params($params)>
 
 Description: Writes the parameters to disk.
index 219e834ee6d0859ab66bc3afe8deabace413e0d6..326c4cd3f6a7683135b3564183a98280c946e0d2 100644 (file)
@@ -74,12 +74,6 @@ sub get_param_list {
    default => '0'
   },
 
-  {
-   name => 'webservice_email_filter',
-   type => 'b',
-   default => 0
-  },
-
   {
    name => 'emailregexp',
    type => 't',
@@ -95,9 +89,10 @@ sub get_param_list {
   },
 
   {
-   name => 'emailsuffix',
-   type => 't',
-   default => ''
+   name => 'use_email_as_login',
+   type => 'b',
+   default => '1',
+   onchange => \&change_use_email_as_login
   },
 
   {
index b8a80dd94b86460cf154a205a96fa78935e028c4..b6cd7ae43688b6c0d20420ec80c44dfe53742ac7 100644 (file)
@@ -38,7 +38,8 @@ sub get_param_list {
    type => 's',
    choices => \@closed_bug_statuses,
    default => $closed_bug_statuses[0],
-   checker => \&check_bug_status
+   checker => \&check_bug_status,
+   onchange => \&change_duplicate_or_move_bug_status
   },
 
   {
index 6e89fdcaebc6790e6e52a4b34a1679d816ca3779..e6e0d4a2336f709535e8608217c81b51cd313baa 100644 (file)
@@ -29,6 +29,8 @@ use parent qw(Exporter);
        check_bug_status check_smtp_auth check_theschwartz_available
        check_maxattachmentsize check_email check_smtp_ssl
        check_comment_taggers_group check_smtp_server check_resolution
+
+       change_use_email_as_login change_duplicate_or_move_bug_status
 );
 
 # Checking functions for the various values
@@ -362,18 +364,36 @@ sub check_comment_taggers_group {
     return check_group($group_name);
 }
 
+# Change handler functions for various parameters
+
+# If use_email_as_login is turned on, update all login names to be email
+# addresses.
+sub change_use_email_as_login {
+    my $newvalue = shift;
+    if ($newvalue) {
+        Bugzilla->dbh->do('UPDATE profiles SET login_name = email');
+    }
+}
+
+sub change_duplicate_or_move_bug_status {
+    my $newvalue = shift;
+    Bugzilla::Status::add_missing_bug_status_transitions($newvalue);
+}
+
 # OK, here are the parameter definitions themselves.
 #
 # Each definition is a hash with keys:
 #
-# name    - name of the param
-# desc    - description of the param (for editparams.cgi)
-# type    - see below
-# choices - (optional) see below
-# default - default value for the param
-# checker - (optional) checking function for validating parameter entry
-#           It is called with the value of the param as the first arg and a
-#           reference to the param's hash as the second argument
+# name     - name of the param
+# desc     - description of the param (for editparams.cgi)
+# type     - see below
+# choices  - (optional) see below
+# default  - default value for the param
+# checker  - (optional) checking function for validating parameter entry.
+#            It is called with the value of the param as the first arg
+#            and a reference to the param's hash as the second argument.
+# onchange - (optional) handling function for parameter changes.
+#            The argument is the new value of the param.
 #
 # The type value can be one of the following:
 #
@@ -467,6 +487,17 @@ Checks that the value is a valid regexp
 Checks that the required modules for comment tagging are installed, and that a
 valid group is provided.
 
+=item C<change_use_email_as_login>
+
+Change handler for "use_email_as_login" parameter - if param is changed to
+true, updates login_name field to be the value of the email field for all
+users.
+
+=item C<change_duplicate_or_move_bug_status>
+
+Change handler for "duplicate_or_move_bug_status" parameter - if param is
+changed, insert all missing transitions to the new bug status.
+
 =back
 
 =head1 B<Methods in need of POD>
index ca3839ca6e0f6482b1d8e3cfdad285af75189f21..76ea3c0c8a7dc3e9b6b87a53ab50c95f15521b56 100644 (file)
@@ -930,6 +930,7 @@ use constant ABSTRACT_SCHEMA => {
             userid         => {TYPE => 'MEDIUMSERIAL', NOTNULL => 1,
                                PRIMARYKEY => 1},
             login_name     => {TYPE => 'varchar(255)', NOTNULL => 1},
+            email          => {TYPE => 'varchar(255)', NOTNULL => 1},
             cryptpassword  => {TYPE => 'varchar(128)'},
             realname       => {TYPE => 'varchar(255)', NOTNULL => 1,
                                DEFAULT => "''"},
@@ -948,7 +949,9 @@ use constant ABSTRACT_SCHEMA => {
             profiles_login_name_idx => {FIELDS => ['login_name'],
                                         TYPE => 'UNIQUE'},
             profiles_extern_id_idx => {FIELDS => ['extern_id'],
-                                       TYPE   => 'UNIQUE'}
+                                       TYPE   => 'UNIQUE'},
+            profiles_email_idx => {FIELDS => ['email'],
+                                   TYPE => 'UNIQUE'}
         ],
     },
 
index cbf831bc5dbd5d4f5e67dcb61d0c79d6768f9366..644a02e7fd3c2293ce0e61094e1468ccc1e5aee4 100644 (file)
@@ -301,8 +301,8 @@ sub _check_cc_list {
 
     my @addresses = split(/[,\s]+/, $cc_list);
     my $addr_spec = $Email::Address::addr_spec;
-    # We do not call check_email_syntax() because these addresses do not
-    # require to match 'emailregexp' and do not depend on 'emailsuffix'.
+    # We do not call check_email_syntax() because these addresses are not
+    # required to match 'emailregexp'.
     foreach my $address (@addresses) {
         ($address !~ /\P{ASCII}/ && $address =~ /^$addr_spec$/)
           || ThrowUserError('illegal_email_address',
index 9ea851c2000505ea74f5106f37182b3549a18357..61c085c0ea2b8b2f551284d822c6661f7b45f69b 100644 (file)
@@ -322,7 +322,7 @@ sub _rederive_regexp {
     my ($self) = @_;
 
     my $dbh = Bugzilla->dbh;
-    my $sth = $dbh->prepare("SELECT userid, login_name, group_id
+    my $sth = $dbh->prepare("SELECT userid, email, group_id
                                FROM profiles
                           LEFT JOIN user_group_map
                                  ON user_group_map.user_id = profiles.userid
@@ -337,8 +337,8 @@ sub _rederive_regexp {
                                  AND grant_type = ? and isbless = 0");
     $sth->execute($self->id, GRANT_REGEXP);
     my $regexp = $self->user_regexp;
-    while (my ($uid, $login, $present) = $sth->fetchrow_array) {
-        if ($regexp ne '' and $login =~ /$regexp/i) {
+    while (my ($uid, $email, $present) = $sth->fetchrow_array) {
+        if ($regexp ne '' and $email =~ /$regexp/i) {
             $sthadd->execute($uid, $self->id, GRANT_REGEXP) unless $present;
         } else {
             $sthdel->execute($uid, $self->id, GRANT_REGEXP) if $present;
index 8d0976d9c69524d0a6b94155a4248e74a4cda864..3f902cab07b472e707e19300b7edf355e0e93d90 100644 (file)
@@ -1631,10 +1631,14 @@ Params:
 
 =over
 
+=item C<email>
+
+The email address of the new account.
+
 =item C<login>
 
-The login of the new account. This is usually an email address, unless the
-C<emailsuffix> parameter is not empty.
+The login of the new account. This will be the same as the email address if
+the "use_email_as_login" parameter is set, otherwise it may be different.
 
 =back
 
index e1ed65c363c15a47381683b6c09f7c250c4d6ca1..37c87a2b168d82cb89f006e0eb699e251c02887a 100644 (file)
@@ -308,27 +308,47 @@ sub create_admin {
     my $template = Bugzilla->template;
 
     my $admin_group = new Bugzilla::Group({ name => 'admin' });
-    my $admin_inheritors = 
+    my $admin_inheritors =
         Bugzilla::Group->flatten_group_membership($admin_group->id);
     my $admin_group_ids = join(',', @$admin_inheritors);
 
     my ($admin_count) = $dbh->selectrow_array(
-        "SELECT COUNT(*) FROM user_group_map 
+        "SELECT COUNT(*) FROM user_group_map
           WHERE group_id IN ($admin_group_ids)");
 
     return if $admin_count;
 
     my %answer    = %{Bugzilla->installation_answers};
-    my $login     = $answer{'ADMIN_EMAIL'};
+    my $login     = $answer{'ADMIN_LOGIN'};
+    my $email     = $answer{'ADMIN_EMAIL'};
     my $password  = $answer{'ADMIN_PASSWORD'};
     my $full_name = $answer{'ADMIN_REALNAME'};
 
-    if (!$login || !$password || !$full_name) {
+    if (!($login || Bugzilla->params->{'use_email_as_login'})
+        || !$email
+        || !$password)
+    {
         say "\n" . get_text('install_admin_setup') . "\n";
     }
 
-    while (!$login) {
+    while (!$email) {
         print get_text('install_admin_get_email') . ' ';
+        $email = <STDIN>;
+        chomp $email;
+        eval { Bugzilla::User->check_email($email); };
+        if ($@) {
+            say $@;
+            undef $email;
+        }
+    }
+
+    # Make sure the email address is used as login when required.
+    if (Bugzilla->params->{'use_email_as_login'}) {
+        $login = $email;
+    }
+
+    while (!$login) {
+        print get_text('install_admin_get_login') . ' ';
         $login = <STDIN>;
         chomp $login;
         eval { Bugzilla::User->check_login_name($login); };
@@ -349,7 +369,8 @@ sub create_admin {
             get_text('install_admin_get_password'));
     }
 
-    my $admin = Bugzilla::User->create({ login_name    => $login, 
+    my $admin = Bugzilla::User->create({ login_name    => $login,
+                                         email         => $email,
                                          realname      => $full_name,
                                          cryptpassword => $password });
     make_admin($admin);
index a6ca1e90ff3531d792141a6c877be6e3d2e44c50..b7ca7c657be2587f753f5e3fcc2b7d887f464512 100644 (file)
@@ -748,6 +748,10 @@ sub update_table_definitions {
     # 2015-12-16 LpSolit@gmail.com - Bug 1232578
     _sanitize_audit_log_table();
 
+    # 2016-04-27 wurblzap@gmail.com and gerv@gerv.net - Bug 218917
+    # Split login_name into login_name and email columns
+    _split_login_and_email($old_params);
+
     ################################################################
     # New --TABLE-- changes should go *** A B O V E *** this point #
     ################################################################
@@ -3957,6 +3961,27 @@ sub _sanitize_audit_log_table {
     }
 }
 
+sub _split_login_and_email {
+    my ($old_params) = (@_);
+
+    my $dbh = Bugzilla->dbh;
+    $dbh->bz_add_column('profiles', 'email',
+                        {TYPE => 'varchar(255)', NOTNULL => 1}, '');
+    $dbh->do('UPDATE profiles SET email = login_name');
+
+    # This change obsoletes the 'emailsuffix' parameter. If it is in use,
+    # append it to all the values in the 'email' column.
+    my $suffix = $old_params->{'emailsuffix'};
+    if ($suffix) {
+        $dbh->do('UPDATE profiles SET email = ' . $dbh->sql_string_concat('email', '?'),
+                 undef, $suffix);
+    }
+
+    $dbh->bz_add_index('profiles', 'profiles_email_idx',
+                       {TYPE => 'UNIQUE', FIELDS => ['email']});
+}
+
+
 1;
 
 __END__
index 618d80cfa9062147731355f3f24bc53a281acb1b..dea207f2118e28f5e0056dbdab95ae30737e3b70 100644 (file)
@@ -1170,7 +1170,7 @@ sub create {
                 my $cache = Bugzilla->request_cache;
 
                 return $cache->{login_not_email} //=
-                  ($params->{emailsuffix}
+                  (!$params->{use_email_as_login}
                      || ($params->{user_verify_class} =~ /LDAP/ && $params->{LDAPmailattribute})
                      || ($params->{user_verify_class} =~ /RADIUS/ && $params->{RADIUS_email_suffix}))
                   ? 1 : 0;
index b6f07468e215929b0f3c6fefcc0524be641d5cb5..4f522bda9529d5fa64989086c0acf9c5140e7282 100644 (file)
@@ -89,30 +89,32 @@ sub check_auth_delegation_token {
 # Creates and sends a token to create a new user account.
 # It assumes that the login has the correct format and is not already in use.
 sub issue_new_user_account_token {
-    my $login_name = shift;
+    my ($login, $email) = @_;
     my $dbh = Bugzilla->dbh;
     my $template = Bugzilla->template;
     my $vars = {};
 
-    # Is there already a pending request for this login name? If yes, do not throw
+    # Is there already a pending request for this email? If yes, do not throw
     # an error because the user may have lost their email with the token inside.
     # But to prevent using this way to mailbomb an email address, make sure
     # the last request is old enough before sending a new email (default: 10 minutes).
 
+    my $regexp = "^$email:";
     my $pending_requests = $dbh->selectrow_array(
         'SELECT COUNT(*)
            FROM tokens
           WHERE tokentype = ?
-                AND ' . $dbh->sql_istrcmp('eventdata', '?') . '
+                AND ' . $dbh->sql_regexp('eventdata', $dbh->quote($regexp)) . '
                 AND issuedate > '
                     . $dbh->sql_date_math('NOW()', '-', ACCOUNT_CHANGE_INTERVAL, 'MINUTE'),
-        undef, ('account', $login_name));
+        undef, 'account');
 
     ThrowUserError('too_soon_for_new_token', {'type' => 'account'}) if $pending_requests;
 
-    my ($token, $token_ts) = _create_token(undef, 'account', $login_name);
+    my ($token, $token_ts) = _create_token(undef, 'account', "$email:$login");
 
-    $vars->{'email'} = $login_name . Bugzilla->params->{'emailsuffix'};
+    $vars->{'login'} = $login;
+    $vars->{'email'} = $email;
     $vars->{'expiration_ts'} = ctime($token_ts + MAX_TOKEN_AGE * 86400);
     $vars->{'token'} = $token;
 
@@ -131,15 +133,15 @@ sub IssueEmailChangeToken {
     my $new_email = shift;
     my $user = Bugzilla->user;
 
-    my ($token, $token_ts) = _create_token($user->id, 'emailold', $user->login . ":$new_email");
-    my $newtoken = _create_token($user->id, 'emailnew', $user->login . ":$new_email");
+    my ($token, $token_ts) = _create_token($user->id, 'emailold', $user->email . ":$new_email");
+    my $newtoken = _create_token($user->id, 'emailnew', $user->email . ":$new_email");
 
     # Mail the user the token along with instructions for using it.
 
     my $template = Bugzilla->template_inner($user->setting('lang'));
     my $vars = {};
 
-    $vars->{'newemailaddress'} = $new_email . Bugzilla->params->{'emailsuffix'};
+    $vars->{'newemailaddress'} = $new_email;
     $vars->{'expiration_ts'} = ctime($token_ts + MAX_TOKEN_AGE * 86400);
 
     # First send an email to the new address. If this one doesn't exist,
@@ -335,7 +337,17 @@ sub Cancel {
     # is no entry in the 'profiles' table.
     my $user = new Bugzilla::User($userid);
 
-    $vars->{'emailaddress'} = $userid ? $user->email : $eventdata;
+    if ($userid) {
+        $vars->{'emailaddress'} = $user->email;
+        $vars->{'login'} = $user->login;
+    }
+    else {
+        # Be careful! Some logins may contain ":" in them.
+        my ($email, $login) = split(':', $eventdata, 2);
+        $vars->{'emailaddress'} = $email;
+        $vars->{'login'} = $login;
+    }
+
     $vars->{'remoteaddress'} = remote_ip();
     $vars->{'token'} = $token;
     $vars->{'tokentype'} = $tokentype;
@@ -511,7 +523,7 @@ Bugzilla::Token - Provides different routines to manage tokens.
 
     use Bugzilla::Token;
 
-    Bugzilla::Token::issue_new_user_account_token($login_name);
+    Bugzilla::Token::issue_new_user_account_token($login, $email);
     Bugzilla::Token::IssueEmailChangeToken($user, $new_email);
     Bugzilla::Token::IssuePasswordToken($user);
     Bugzilla::Token::DeletePasswordTokens($user_id, $reason);
@@ -539,14 +551,15 @@ Bugzilla::Token - Provides different routines to manage tokens.
 
  Returns:     The token.
 
-=item C<issue_new_user_account_token($login_name)>
+=item C<issue_new_user_account_token($login, $email)>
 
  Description: Creates and sends a token per email to the email address
               requesting a new user account. It doesn't check whether
               the user account already exists. The user will have to
               use this token to confirm the creation of their user account.
 
- Params:      $login_name - The new login name requested by the user.
+ Params:      $login - The new login name requested by the user.
+              $email - The email address to be associated with the account.
 
  Returns:     Nothing. It throws an error if the same user made the same
               request in the last few minutes.
index 91defebb4719126abbd4d565ae4423b52d0e1811..c1e3adee32af2215f55e3408d2ba16ec9809eb9b 100644 (file)
@@ -32,7 +32,7 @@ use URI;
 use URI::QueryParam;
 
 use parent qw(Bugzilla::Object Exporter);
-@Bugzilla::User::EXPORT = qw(is_available_username
+@Bugzilla::User::EXPORT = qw(is_available_email email_to_id
     login_to_id validate_password validate_password_check
     USER_MATCH_MULTIPLE USER_MATCH_FAILED USER_MATCH_SUCCESS
     MATCH_SKIP_CONFIRM
@@ -50,12 +50,13 @@ use constant MATCH_SKIP_CONFIRM  => 1;
 
 use constant DEFAULT_USER => {
     'userid'         => 0,
-    'realname'       => '',
     'login_name'     => '',
+    'email'          => '',
+    'realname'       => '',
     'showmybugslink' => 0,
     'disabledtext'   => '',
     'disable_mail'   => 0,
-    'is_enabled'     => 1, 
+    'is_enabled'     => 1,
 };
 
 use constant DB_TABLE => 'profiles';
@@ -69,6 +70,7 @@ sub DB_COLUMNS {
     return (
         'profiles.userid',
         'profiles.login_name',
+        'profiles.email',
         'profiles.realname',
         'profiles.mybugslink AS showmybugslink',
         'profiles.disabledtext',
@@ -88,9 +90,10 @@ use constant VALIDATORS => {
     disable_mail  => \&_check_disable_mail,
     disabledtext  => \&_check_disabledtext,
     login_name    => \&check_login_name,
+    email         => \&check_email,
     realname      => \&_check_realname,
     extern_id     => \&_check_extern_id,
-    is_enabled    => \&_check_is_enabled, 
+    is_enabled    => \&_check_is_enabled,
 };
 
 sub UPDATE_COLUMNS {
@@ -99,6 +102,7 @@ sub UPDATE_COLUMNS {
         disable_mail
         disabledtext
         login_name
+        email
         realname
         extern_id
         is_enabled
@@ -108,7 +112,8 @@ sub UPDATE_COLUMNS {
 };
 
 use constant VALIDATOR_DEPENDENCIES => {
-    is_enabled => ['disabledtext'], 
+    is_enabled => ['disabledtext'],
+    login_name => ['email'],
 };
 
 use constant EXTRA_REQUIRED_FIELDS => qw(is_enabled);
@@ -222,7 +227,7 @@ sub update {
     my $dbh = Bugzilla->dbh;
     $self->_update_groups($group_changes, $changes);
 
-    if (exists $changes->{login_name}) {
+    if (exists $changes->{email}) {
         # Delete all the tokens related to the userid
         $dbh->do('DELETE FROM tokens WHERE userid = ?', undef, $self->id)
           unless $options->{keep_tokens};
@@ -231,15 +236,16 @@ sub update {
     }
 
     # Logout the user if necessary.
-    Bugzilla->logout_user($self) 
+    Bugzilla->logout_user($self)
         if (!$options->{keep_session}
             && (exists $changes->{login_name}
+                || exists $changes->{email}
                 || exists $changes->{disabledtext}
                 || exists $changes->{cryptpassword}));
 
     # XXX Can update profiles_activity here as soon as it understands
     #     field names like login_name.
-    
+
     return $changes;
 }
 
@@ -266,23 +272,53 @@ sub _check_extern_id {
     return $extern_id;
 }
 
-# This is public since createaccount.cgi needs to use it before issuing
-# a token for account creation.
 sub check_login_name {
-    my ($invocant, $name) = @_;
-    $name = trim($name);
-    $name || ThrowUserError('user_login_required');
-    check_email_syntax($name);
+    my ($invocant, $login, undef, $data) = @_;
+
+    # No control characters
+    $login = clean_text($login);
+    $login || ThrowUserError('user_login_required');
+    # No whitespace
+    $login !~ /\s/ || ThrowUserError('login_illegal_character');
+
+    # No @ sign unless login is email (VALIDATOR_DEPENDENCIES means
+    # this will be set already)
+    if ($login =~ /@/) {
+        my $email = ref($invocant) ? $invocant->email : $data->{email};
+        # We should really use fc() instead of lc(), but this requires Perl 5.16.
+        ThrowUserError('login_at_sign_disallowed') unless lc($login) eq lc($email);
+    }
+    # We set the max length to 127 to ensure logins aren't truncated when
+    # inserted into the tokens.eventdata field.
+    length($login) <= 127 or ThrowUserError('login_too_long');
+
+    trick_taint($login);
+
+    # Check the login name if it's a new user, or if we're changing the login name.
+    if (!ref($invocant) || lc($invocant->login) ne lc($login)) {
+        if (login_to_id($login)) {
+            ThrowUserError('account_exists', { login => $login });
+        }
+    }
 
-    # Check the name if it's a new user, or if we're changing the name.
-    if (!ref($invocant) || lc($invocant->login) ne lc($name)) {
-        my @params = ($name);
-        push(@params, $invocant->login) if ref($invocant);
-        is_available_username(@params)
-            || ThrowUserError('account_exists', { email => $name });
+    return $login;
+}
+
+sub check_email {
+    my ($invocant, $email) = @_;
+    $email = clean_text($email);
+    $email || ThrowUserError('email_required');
+
+    check_email_syntax($email);
+
+    # Check the email if it's a new user, or if we're changing the email.
+    my $old_email = ref($invocant) ? $invocant->email : undef;
+    if (!defined($old_email) || lc($old_email) ne lc($email)) {
+        is_available_email($email, $old_email)
+            || ThrowUserError('account_exists', { email => $email });
     }
 
-    return $name;
+    return $email;
 }
 
 sub _check_password {
@@ -325,6 +361,12 @@ sub set_login {
     delete $self->{nick};
 }
 
+sub set_email {
+    my ($self, $email) = @_;
+    $self->set('email', $email);
+    $self->set_login($email) if Bugzilla->params->{'use_email_as_login'};
+}
+
 sub set_name {
     my ($self, $name) = @_;
     $self->set('realname', $name);
@@ -470,7 +512,7 @@ sub update_last_seen_date {
 sub name  { $_[0]->{realname};   }
 sub login { $_[0]->{login_name}; }
 sub extern_id { $_[0]->{extern_id}; }
-sub email { $_[0]->login . Bugzilla->params->{'emailsuffix'}; }
+sub email { $_[0]->{email}; }
 sub disabledtext { $_[0]->{'disabledtext'}; }
 sub is_enabled { $_[0]->{'is_enabled'} ? 1 : 0; }
 sub showmybugslink { $_[0]->{showmybugslink}; }
@@ -502,14 +544,17 @@ sub authorizer {
 
 # Generate a string to identify the user by name + login if the user
 # has a name or by login only if they don't.
+#
+# See also get_userlist(), which constructs pseudo-Bugzilla::Users, including
+# the 'identity' value.
 sub identity {
     my $self = shift;
 
     return "" unless $self->id;
 
     if (!defined $self->{identity}) {
-        $self->{identity} = 
-          $self->name ? $self->name . " <" . $self->login. ">" : $self->login;
+        $self->{identity} =
+          $self->name ? $self->name . " (" . $self->login. ")" : $self->login;
     }
 
     return $self->{identity};
@@ -521,6 +566,7 @@ sub nick {
     return "" unless $self->id;
 
     if (!defined $self->{nick}) {
+        # This has the correct result even if the login does not contain an @.
         $self->{nick} = (split(/@/, $self->login, 2))[0];
     }
 
@@ -1730,8 +1776,8 @@ sub can_bless {
 }
 
 sub match {
-    # Generates a list of users whose login name (email address) or real name
-    # matches a substring or wildcard.
+    # Generates a list of users whose login name or real name matches a
+    # substring or wildcard.
     # This is also called if matches are disabled (for error checking), but
     # in this case only the exact match code will end up running.
 
@@ -1780,8 +1826,10 @@ sub match {
         @users = @{Bugzilla::User->new_from_list($user_ids)};
     }
     else {    # try an exact match
-        # Exact matches don't care if a user is disabled.
+        # Exact matches don't care if a user is disabled, and match
+        # login names only.
         trick_taint($str);
+
         my $user_id = $dbh->selectrow_array('SELECT userid FROM profiles
                                              WHERE ' . $dbh->sql_istrcmp('login_name', '?'),
                                              undef, $str);
@@ -2253,7 +2301,7 @@ sub get_userlist {
     while (my($login, $name, $visible) = $sth->fetchrow_array) {
         push @userlist, {
             login => $login,
-            identity => $name ? "$name <$login>" : $login,
+            identity => $name ? "$name ($login)" : $login,
             visible => $visible,
         };
     }
@@ -2375,17 +2423,15 @@ sub check_current_password {
 # Subroutines #
 ###############
 
-sub is_available_username {
-    my ($username, $old_username) = @_;
+sub is_available_email {
+    my ($email, $old_email) = @_;
 
-    if(login_to_id($username) != 0) {
-        return 0;
-    }
+    return 0 if email_to_id($email);
 
     my $dbh = Bugzilla->dbh;
-    # $username is safe because it is only used in SELECT placeholders.
-    trick_taint($username);
-    # Reject if the new login is part of an email change which is
+    # $email is safe because it is only used in SELECT placeholders.
+    trick_taint($email);
+    # Reject if the new email is part of an email change which is
     # still in progress
     #
     # substring/locate stuff: bug 165221; this used to use regexes, but that
@@ -2401,13 +2447,13 @@ sub is_available_username {
              OR (tokentype = 'emailnew'
                 AND SUBSTRING(eventdata, (" .
                     $dbh->sql_position(q{':'}, 'eventdata') . "+ 1), LENGTH(eventdata)) = ?)",
-         undef, ($username, $username));
+         undef, ($email, $email));
 
     if ($eventdata) {
         # Allow thru owner of token
-        if ($old_username
-            && (($tokentype eq 'emailnew' && $eventdata eq "$old_username:$username")
-                || ($tokentype eq 'emailold' && $eventdata eq "$username:$old_username")))
+        if ($old_email
+            && (($tokentype eq 'emailnew' && $eventdata eq "$old_email:$email")
+                || ($tokentype eq 'emailold' && $eventdata eq "$email:$old_email")))
         {
             return 1;
         }
@@ -2429,24 +2475,27 @@ sub check_account_creation_enabled {
 }
 
 sub check_and_send_account_creation_confirmation {
-    my ($self, $login) = @_;
+    my ($self, $login, $email) = @_;
+    my $class = ref($self) || $self;
     my $dbh = Bugzilla->dbh;
 
     $dbh->bz_start_transaction;
 
-    $login = $self->check_login_name($login);
+    $email = $class->check_email($email);
+    $login = $class->check_login_name($login, undef, { email => $email });
     my $creation_regexp = Bugzilla->params->{'createemailregexp'};
 
-    if ($login !~ /$creation_regexp/i) {
+    if ($email !~ /$creation_regexp/i) {
         ThrowUserError('account_creation_restricted');
     }
 
     # Allow extensions to do extra checks.
-    Bugzilla::Hook::process('user_check_account_creation', { login => $login });
+    Bugzilla::Hook::process('user_check_account_creation',
+                            { login => $login, email => $email });
 
     # Create and send a token for this new account.
     require Bugzilla::Token;
-    Bugzilla::Token::issue_new_user_account_token($login);
+    Bugzilla::Token::issue_new_user_account_token($login, $email);
 
     $dbh->bz_commit_transaction;
 }
@@ -2458,20 +2507,17 @@ sub login_to_id {
     my $dbh = Bugzilla->dbh;
     my $cache = Bugzilla->request_cache->{user_login_to_id} ||= {};
 
-    # We cache lookups because this function showed up as taking up a 
+    # We cache lookups because this function showed up as taking up a
     # significant amount of time in profiles of xt/search.t. However,
-    # for users that don't exist, we re-do the check every time, because
-    # otherwise we break is_available_username.
+    # for users that don't exist, we re-do the check every time.
     my $user_id;
     if (defined $cache->{$login}) {
         $user_id = $cache->{$login};
     }
     else {
-        # No need to validate $login -- it will be used by the following SELECT
-        # statement only, so it's safe to simply trick_taint.
         trick_taint($login);
         $user_id = $dbh->selectrow_array(
-            "SELECT userid FROM profiles 
+            "SELECT userid FROM profiles
               WHERE " . $dbh->sql_istrcmp('login_name', '?'), undef, $login);
         $cache->{$login} = $user_id;
     }
@@ -2485,6 +2531,24 @@ sub login_to_id {
     }
 }
 
+sub email_to_id {
+    my ($email, $throw_error) = @_;
+    my $dbh = Bugzilla->dbh;
+    trick_taint($email);
+    my $user_id = $dbh->selectrow_array("SELECT userid FROM profiles WHERE " .
+                                        $dbh->sql_istrcmp('email', '?'),
+                                        undef, $email);
+    if ($user_id) {
+        return $user_id;
+    }
+    elsif ($throw_error) {
+        ThrowUserError('invalid_email', { email => $email });
+    }
+    else {
+        return 0;
+    }
+}
+
 sub validate_password {
     my $check = validate_password_check(@_);
     ThrowUserError($check) if $check;
@@ -2532,14 +2596,15 @@ Bugzilla::User - Object for a Bugzilla user
 
   my $user = new Bugzilla::User($id);
 
-  my @get_selectable_classifications = 
+  my @get_selectable_classifications =
       $user->get_selectable_classifications;
 
   # Class Functions
-  $user = Bugzilla::User->create({ 
-      login_name    => $username, 
-      realname      => $realname, 
-      cryptpassword => $plaintext_password, 
+  $user = Bugzilla::User->create({
+      login_name    => $username,
+      email         => $email,
+      realname      => $realname,
+      cryptpassword => $plaintext_password,
       disabledtext  => $disabledtext,
       disable_mail  => 0});
 
@@ -2595,6 +2660,27 @@ database changes and so on.
 
 =back
 
+=head2 Validators
+
+=over
+
+=item C<check_email>
+
+Returns the sanitized email address if that email address is well formatted
+and not already used by another user account. Else an error is thrown.
+
+=item C<check_login_name>
+
+Returns the sanitized login name if:
+
+1) it is not already used by another user account; and
+2) it contains no forbidden characters, which means no whitespace characters; and
+3) it contains no @ character (unless it exactly matches the email address of the account).
+
+Else an error is thrown.
+
+=back
+
 =head2 Saved and Shared Queries
 
 =over
@@ -2734,8 +2820,7 @@ Returns the login name for this user.
 
 =item C<email>
 
-Returns the user's email address. Currently this is the same value as the
-login.
+Returns the user's email address.
 
 =item C<name>
 
@@ -2754,10 +2839,10 @@ otherwise.
 
 =item C<nick>
 
-Returns a user "nickname" -- i.e. a shorter, not-necessarily-unique name by
-which to identify the user. Currently the part of the user's email address
-before the at sign (@), but that could change, especially if we implement
-usernames not dependent on email address.
+Usually, this is an alias for C<login>.
+If email addresses are used as logins, though, then this is the part of the
+user's email address before the at sign (@). In this case, nicks are not
+unique.
 
 =item C<authorizer>
 
@@ -3141,7 +3226,8 @@ called "statically," just like a normal procedural function.
 The same as L<Bugzilla::Object/create>.
 
 Params: login_name - B<Required> The login name for the new user.
-        realname - The full name for the new user.
+        email - B<Required> The email address of the new user.
+        realname - The full name of the new user.
         cryptpassword  - B<Required> The password for the new user.
             Even though the name says "crypt", you should just specify
             a plain-text password. If you specify '*', the user will not
@@ -3162,30 +3248,29 @@ user with that username. Returns a C<Bugzilla::User> object.
 Checks that users can create new user accounts, and throws an error
 if user creation is disabled.
 
-=item C<check_and_send_account_creation_confirmation($login)>
+=item C<check_and_send_account_creation_confirmation($login, $email)>
 
 If the user request for a new account passes validation checks, an email
 is sent to this user for confirmation. Otherwise an error is thrown
 indicating why the request has been rejected.
 
-=item C<is_available_username>
+=item C<is_available_email>
 
-Returns a boolean indicating whether or not the supplied username is
+Returns a boolean indicating whether or not the supplied email address is
 already taken in Bugzilla.
 
-Params: $username (scalar, string) - The full login name of the username 
-            that you are checking.
-        $old_username (scalar, string) - If you are checking an email-change
-            token, insert the "old" username that the user is changing from,
-            here. Then, as long as it's the right user for that token, they
-            can change their username to $username. (That is, this function
+Params: $email (scalar, string) - The email address that you are checking.
+        $old_email (scalar, string) - If you are checking an email-change
+            token, insert the "old" address that the user is changing from,
+            here. Then, as long as it's the right user for that token, he
+            can change his email to $email. (That is, this function
             will return a boolean true value).
 
 =item C<login_to_id($login, $throw_error)>
 
 Takes a login name of a Bugzilla user and changes that into a numeric
 ID for that user. This ID can then be passed to Bugzilla::User::new to
-create a new user.
+create a new user object.
 
 If no valid user exists with that login name, then the function returns 0.
 However, if $throw_error is set, the function will throw a user error
@@ -3197,6 +3282,11 @@ of a user, but you don't want the full weight of Bugzilla::User.
 However, consider using a Bugzilla::User object instead of this function
 if you need more information about the user than just their ID.
 
+=item C<email_to_id($email, $throw_error)>
+
+Same as C<login_to_id>, but operates on an email address instead of a login
+name.
+
 =item C<validate_password($passwd1, $passwd2)>
 
 Returns true if a password is valid (i.e. meets Bugzilla's
@@ -3282,8 +3372,6 @@ L<Bugzilla|Bugzilla>
 
 =item groups_with_icon
 
-=item check_login_name
-
 =item set_extern_id
 
 =item mail_settings
@@ -3300,6 +3388,8 @@ L<Bugzilla|Bugzilla>
 
 =item set_login
 
+=item set_email
+
 =item set_password
 
 =item last_seen_date
index 06022ce7ce9106554aeb94106b2b8325db652682..e673a920eea059bd2e84a4cf23b35c11a15afd7c 100644 (file)
@@ -690,9 +690,8 @@ sub generate_random_password {
 }
 
 sub validate_email_syntax {
-    my ($addr) = @_;
+    my ($email) = @_;
     my $match = Bugzilla->params->{'emailregexp'};
-    my $email = $addr . Bugzilla->params->{'emailsuffix'};
     # This regexp follows RFC 2822 section 3.4.1.
     my $addr_spec = $Email::Address::addr_spec;
     # RFC 2822 section 2.1 specifies that email addresses must
@@ -700,7 +699,7 @@ sub validate_email_syntax {
     # Email::Address::addr_spec doesn't enforce this.
     # We set the max length to 127 to ensure addresses aren't truncated when
     # inserted into the tokens.eventdata field.
-    if ($addr =~ /$match/
+    if ($email =~ /$match/
         && $email !~ /\P{ASCII}/
         && $email =~ /^$addr_spec$/
         && length($email) <= 127)
@@ -713,11 +712,10 @@ sub validate_email_syntax {
 }
 
 sub check_email_syntax {
-    my ($addr) = @_;
+    my ($email) = @_;
 
     unless (validate_email_syntax(@_)) {
-        my $email = $addr . Bugzilla->params->{'emailsuffix'};
-        ThrowUserError('illegal_email_address', { addr => $email });
+        ThrowUserError('illegal_email_address', { email => $email });
     }
 }
 
index 2279395a14e31c52345191ba463d2a609de8bb9f..d137000a9f998d884f931486760218bc36aad779 100644 (file)
@@ -366,7 +366,7 @@ sub _translate_comment {
     my $comment_hash = {
         id            => $self->type('int', $comment->id),
         bug_id        => $self->type('int', $comment->bug_id),
-        creator       => $self->type('email', $comment->author->login),
+        creator       => $self->type('login', $comment->author->login),
         time          => $self->type('dateTime', $comment->creation_ts),
         creation_time => $self->type('dateTime', $comment->creation_ts),
         is_private    => $self->type('boolean', $comment->is_private),
@@ -1308,7 +1308,7 @@ sub _bug_to_hash {
         $item{alias} = [ map { $self->type('string', $_) } @{ $bug->alias } ];
     }
     if (filter_wants $params, 'assigned_to') {
-        $item{'assigned_to'} = $self->type('email', $bug->assigned_to->login);
+        $item{'assigned_to'} = $self->type('login', $bug->assigned_to->login);
         $item{'assigned_to_detail'} = $self->_user_to_hash($bug->assigned_to, $params, undef, 'assigned_to');
     }
     if (filter_wants $params, 'blocks') {
@@ -1322,7 +1322,7 @@ sub _bug_to_hash {
         $item{component} = $self->type('string', $bug->component);
     }
     if (filter_wants $params, 'cc') {
-        my @cc = map { $self->type('email', $_) } @{ $bug->cc };
+        my @cc = map { $self->type('login', $_) } @{ $bug->cc };
         $item{'cc'} = \@cc;
         $item{'cc_detail'} = [ map { $self->_user_to_hash($_, $params, undef, 'cc') } @{ $bug->cc_users } ];
     }
@@ -1330,7 +1330,7 @@ sub _bug_to_hash {
         $item{'creation_time'} = $self->type('dateTime', $bug->creation_ts);
     }
     if (filter_wants $params, 'creator') {
-        $item{'creator'} = $self->type('email', $bug->reporter->login);
+        $item{'creator'} = $self->type('login', $bug->reporter->login);
         $item{'creator_detail'} = $self->_user_to_hash($bug->reporter, $params, undef, 'creator');
     }
     if (filter_wants $params, 'depends_on') {
@@ -1361,7 +1361,7 @@ sub _bug_to_hash {
     }
     if (filter_wants $params, 'qa_contact') {
         my $qa_login = $bug->qa_contact ? $bug->qa_contact->login : '';
-        $item{'qa_contact'} = $self->type('email', $qa_login);
+        $item{'qa_contact'} = $self->type('login', $qa_login);
         if ($bug->qa_contact) {
             $item{'qa_contact_detail'} = $self->_user_to_hash($bug->qa_contact, $params, undef, 'qa_contact');
         }
@@ -1433,8 +1433,7 @@ sub _user_to_hash {
     my $item = filter $filters, {
         id        => $self->type('int', $user->id),
         real_name => $self->type('string', $user->name),
-        name      => $self->type('email', $user->login),
-        email     => $self->type('email', $user->email),
+        name      => $self->type('login', $user->login),
     }, $types, $prefix;
     return $item;
 }
@@ -1455,10 +1454,10 @@ sub _attachment_to_hash {
         is_patch         => $self->type('int', $attach->ispatch),
     }, $types, $prefix;
 
-    # creator requires an extra lookup, so we only send them if
-    # the filter wants them.
+    # creator requires an extra lookup, so we only send it if
+    # the filter wants it.
     if (filter_wants $filters, 'creator', $types, $prefix) {
-        $item->{'creator'} = $self->type('email', $attach->attacher->login);
+        $item->{'creator'} = $self->type('login', $attach->attacher->login);
     }
 
     if (filter_wants $filters, 'data', $types, $prefix) {
@@ -1490,7 +1489,7 @@ sub _flag_to_hash {
 
     foreach my $field (qw(setter requestee)) {
         my $field_id = $field . "_id";
-        $item->{$field} = $self->type('email', $flag->$field->login)
+        $item->{$field} = $self->type('login', $flag->$field->login)
             if $flag->$field_id;
     }
 
@@ -2575,10 +2574,6 @@ C<string> The 'real' name for this user, if any.
 
 C<string> The user's Bugzilla login.
 
-=item C<email>
-
-C<string> The user's email address. Currently this is the same value as the name.
-
 =back
 
 =back
@@ -2698,7 +2693,11 @@ in Bugzilla B<4.4>.
 
 =item REST API call added in Bugzilla B<5.0>.
 
-=item In Bugzilla B<5.0>, the following items were added to the bugs return value: C<assigned_to_detail>, C<creator_detail>, C<qa_contact_detail>. 
+=item In Bugzilla B<5.0>, the following items were added to the bugs return
+value: C<assigned_to_detail>, C<creator_detail>, C<qa_contact_detail>.
+
+=item Since Bugzilla B<6.0>, the email address of users is private and is no
+longer returned as part of the user detail hash.
 
 =back
 
index 67e40a15ff561930babcd4816b6250295b0336f2..c0df4754f75c1f4f4496491d46227168c1ad466b 100644 (file)
@@ -62,7 +62,6 @@ use constant PARAMETERS_LOGGED_IN => qw(
     defaultseverity
     duplicate_or_move_bug_status
     emailregexpdesc
-    emailsuffix
     letsubmitterchoosemilestone
     letsubmitterchoosepriority
     mailfrom
@@ -75,6 +74,7 @@ use constant PARAMETERS_LOGGED_IN => qw(
     resolution_forbidden_with_open_blockers
     search_allow_no_criteria
     urlbase
+    use_email_as_login
     use_see_also
     useclassification
     usemenuforusers
@@ -417,7 +417,6 @@ A logged-in user can access the following parameters (listed alphabetically):
     C<defaultseverity>,
     C<duplicate_or_move_bug_status>,
     C<emailregexpdesc>,
-    C<emailsuffix>,
     C<letsubmitterchoosemilestone>,
     C<letsubmitterchoosepriority>,
     C<mailfrom>,
@@ -430,6 +429,7 @@ A logged-in user can access the following parameters (listed alphabetically):
     C<resolution_forbidden_with_open_blockers>,
     C<search_allow_no_criteria>,
     C<urlbase>,
+    C<use_email_as_login>,
     C<use_see_also>,
     C<useclassification>,
     C<usemenuforusers>,
index ec09604c416eb9f438ccfd4d3db8fe696e05ac4a..a9539f83d76dbfb75f367de1398c60e752f2cc70 100644 (file)
@@ -210,8 +210,8 @@ sub _get_group_membership {
         map {{
             id                => $self->type('int', $_->id),
             real_name         => $self->type('string', $_->name),
-            name              => $self->type('string', $_->login),
-            email             => $self->type('string', $_->email),
+            name              => $self->type('login', $_->login),
+            email             => $self->type('email', $_->email),
             can_login         => $self->type('boolean', $_->is_enabled),
             email_enabled     => $self->type('boolean', $_->email_enabled),
             login_denied_text => $self->type('string', $_->disabledtext),
@@ -282,7 +282,7 @@ name of the group.
 
 =item C<user_regexp>
 
-C<string> A regular expression. Any user whose Bugzilla username matches
+C<string> A regular expression. Any user whose Bugzilla email address matches
 this regular expression will automatically be granted membership in this group.
 
 =item C<is_active>
@@ -553,8 +553,7 @@ C<string> The email address of the user.
 
 =item name
 
-C<string> The login name of the user. Note that in some situations this is
-different than their email.
+C<string> The login name of the user.
 
 =item can_login
 
index 879d8eac15b702ac2e3c0b192c967920580a04ed..66bd32808edaafa80a365cb40ea67a97d85b6522 100644 (file)
@@ -271,9 +271,9 @@ sub _component_to_hash {
         description =>
             $self->type('string' , $component->description),
         default_assigned_to =>
-            $self->type('email', $component->default_assignee->login),
+            $self->type('login', $component->default_assignee->login),
         default_qa_contact =>
-            $self->type('email', $component->default_qa_contact ?
+            $self->type('login', $component->default_qa_contact ?
                                  $component->default_qa_contact->login : ""),
         sort_key =>  # sort_key is returned to match Bug.fields
             0,
index 93d315fde217700586e1f18071aa29d15cf13bd0..b488c8de5fc28f7adde593723fda5357c8b15386 100644 (file)
@@ -222,8 +222,11 @@ sub type {
         utf8::encode($value) if utf8::is_utf8($value);
         $retval = encode_base64($value, '');
     }
-    elsif ($type eq 'email' && Bugzilla->params->{'webservice_email_filter'}) {
-        $retval = email_filter($value);
+    elsif ($type eq 'login') {
+        $retval = Bugzilla->params->{'use_email_as_login'} ? email_filter($retval) : "$retval";
+    }
+    elsif ($type eq 'email') {
+        $retval = Bugzilla->user->in_group('editusers') ? "$retval" : '';
     }
 
     return $retval;
index f697f0927bcd39e19f0682c5707500f898faa332..c6461abd68d158c70bb8d289c94a5d3821974489 100644 (file)
@@ -35,11 +35,13 @@ BEGIN {
             $value = Bugzilla::WebService::Server->datetime_format_outbound($value);
             $value =~ s/-//g;
         }
+        elsif ($type eq 'login') {
+            $type = 'string';
+            $value = email_filter($value) if Bugzilla->params->{'use_email_as_login'};
+        }
         elsif ($type eq 'email') {
             $type = 'string';
-            if (Bugzilla->params->{'webservice_email_filter'}) {
-                $value = email_filter($value);
-            }
+            $value = '' unless Bugzilla->user->in_group('editusers');
         }
         return XMLRPC::Data->type($type)->value($value);
     };
index 079e0782e06dfae0d1ec93413fe44b108051a909..d69df505653f1a29ed1eb375555dca3067e7c476 100644 (file)
@@ -43,13 +43,11 @@ use constant PUBLIC_METHODS => qw(
 );
 
 use constant MAPPED_FIELDS => {
-    email => 'login',
     full_name => 'name',
     login_denied_text => 'disabledtext',
 };
 
 use constant MAPPED_RETURNS => {
-    login_name => 'email',
     realname => 'full_name',
     disabledtext => 'login_denied_text',
 };
@@ -67,7 +65,7 @@ sub login {
         return $self->_login_to_hash($user);
     }
 
-    # Username and password params are required 
+    # Login name and password params are required
     foreach my $param ("login", "password") {
         (defined $params->{$param} || defined $params->{'Bugzilla_' . $param})
             || ThrowCodeError('param_required', { param => $param });
@@ -103,8 +101,11 @@ sub offer_account_by_email {
     my $email = trim($params->{email})
         || ThrowCodeError('param_required', { param => 'email' });
 
+    my $login = Bugzilla->params->{use_email_as_login} ? $email : trim($params->{login});
+    $login or ThrowCodeError('param_required', { param => 'login' });
+
     Bugzilla->user->check_account_creation_enabled;
-    Bugzilla->user->check_and_send_account_creation_confirmation($email);
+    Bugzilla->user->check_and_send_account_creation_confirmation($login, $email);
     return undef;
 }
 
@@ -119,11 +120,16 @@ sub create {
 
     my $email = trim($params->{email})
         || ThrowCodeError('param_required', { param => 'email' });
+
+    my $login = Bugzilla->params->{use_email_as_login} ? $email : trim($params->{login});
+    $login or ThrowCodeError('param_required', { param => 'login' });
+
     my $realname = trim($params->{full_name});
     my $password = trim($params->{password}) || '*';
 
     my $user = Bugzilla::User->create({
-        login_name    => $email,
+        login_name    => $login,
+        email         => $email,
         realname      => $realname,
         cryptpassword => $password
     });
@@ -170,7 +176,7 @@ sub get {
         @users = map { filter $params, {
                      id        => $self->type('int', $_->id),
                      real_name => $self->type('string', $_->name),
-                     name      => $self->type('email', $_->login),
+                     name      => $self->type('login', $_->login),
                  } } @$in_group;
 
         return { users => \@users };
@@ -222,12 +228,12 @@ sub get {
         my $user_info = filter $params, {
             id        => $self->type('int', $user->id),
             real_name => $self->type('string', $user->name),
-            name      => $self->type('email', $user->login),
-            email     => $self->type('email', $user->email),
+            name      => $self->type('login', $user->login),
             can_login => $self->type('boolean', $user->is_enabled ? 1 : 0),
         };
 
         if (Bugzilla->user->in_group('editusers')) {
+            $user_info->{email}             = $self->type('email', $user->email),
             $user_info->{email_enabled}     = $self->type('boolean', $user->email_enabled);
             $user_info->{login_denied_text} = $self->type('string', $user->disabledtext);
         }
@@ -605,10 +611,15 @@ and real name.
 
 This is the recommended way to create a Bugzilla account.
 
-=item B<Param>
+=item B<Params>
 
 =over
 
+=item C<login> (string) - the login name for the new account.
+If the installation has the C<use_email_as_login> parameter switched on, then
+this parameter is ignored, and the value of the C<email> parameter will
+be used as the login name for the new account.
+
 =item C<email> (string) - the email to send the offer to.
 
 =back
@@ -659,7 +670,12 @@ are the same as below.
 
 =over
 
-=item C<email> (string) - The email address for the new user.
+=item C<login> (string) - the login name for the new account.
+If the installation has the C<use_email_as_login> parameter switched on, then
+this parameter is ignored, and the value of the C<email> parameter will
+be used as the login name for the new account.
+
+=item C<email> (string) - The email address for the new account's user.
 
 =item C<full_name> (string) B<Optional> - The user's full name. Will
 be set to empty if not specified.
@@ -675,7 +691,7 @@ resetting their password) or by the administrator.
 
 =item B<Returns>
 
-A hash containing one item, C<id>, the numeric id of the user that was
+A hash containing one item, C<id>, the numeric id of the user account that was
 created.
 
 =item B<Errors>
@@ -737,7 +753,7 @@ C<array> Contains ids of user to update.
 
 =item C<names>
 
-C<array> Contains email/login of user to update.
+C<array> Contains login name of user to update.
 
 =item C<full_name>
 
@@ -745,8 +761,10 @@ C<string> The new name of the user.
 
 =item C<email>
 
-C<string> The email of the user. Note that email used to login to bugzilla.
-Also note that you can only update one user at a time when changing the 
+C<string> The email address of the user. It may be required that this is the
+same as the login name. If you send different values in that case, the results
+are undefined.
+Note that you can only update one user at a time when changing the
 login name / email. (An error will be thrown if you try to update this field 
 for multiple users at once.)
 
@@ -967,8 +985,7 @@ C<string> The email address of the user.
 
 =item name
 
-C<string> The login name of the user. Note that in some situations this is 
-different than their email.
+C<string> The login name of the user.
 
 =item can_login
 
@@ -1054,7 +1071,7 @@ C<string> The CGI parameters for the saved report.
 B<Note>: If you are not logged in to Bugzilla when you call this function, you
 will only be returned the C<id>, C<name>, and C<real_name> items. If you are
 logged in and not in editusers group, you will only be returned the C<id>, C<name>, 
-C<real_name>, C<email>, C<can_login>, and C<groups> items. The groups returned are
+C<real_name>, C<can_login>, and C<groups> items. The groups returned are
 filtered based on your permission to bless each group.
 The C<saved_searches> and C<saved_reports> items are only returned if you are
 querying your own account, even if you are in the editusers group.
index 941ec6ed4c832feb45ffa1b54af01a5fc493f32b..69069ba82fa52e366d9884a9331b71eb394502fb 100755 (executable)
@@ -909,11 +909,11 @@ if (!$user->in_group('editbugs')) {
 }
 
 my @bugowners = keys %$bugowners;
-if (scalar(@bugowners) > 1 && $user->in_group('editbugs')) {
-    my $suffix = Bugzilla->params->{'emailsuffix'};
-    map(s/$/$suffix/, @bugowners) if $suffix;
-    my $bugowners = join(",", @bugowners);
-    $vars->{'bugowners'} = $bugowners;
+if (scalar(@bugowners) > 1
+    && $user->in_group('editbugs')
+    && Bugzilla->params->{'use_email_as_login'})
+{
+    $vars->{'bugowners'} = join(",", @bugowners);
 }
 
 # Whether or not to split the column titles across two rows to make
index aacdf41be45a00696141d7086abb303aa4d28c6a..05d98f9e15d1fa995d84c8ef9f4ff175dede75e3 100755 (executable)
@@ -461,6 +461,7 @@ The format of that file is as follows:
 
  (Any localconfig variable or parameter can be specified as above.)
 
+ $answer{'ADMIN_LOGIN'} = 'myadmin';
  $answer{'ADMIN_EMAIL'} = 'myadmin@mydomain.net';
  $answer{'ADMIN_PASSWORD'} = 'fooey';
  $answer{'ADMIN_REALNAME'} = 'Joel Peshkin';
index 754b1b552444d67669c0b7c148a93ed3f5eb8852..3b3dd7c1f717c915b7b0a5f8817cb57582084fdc 100755 (executable)
@@ -27,22 +27,25 @@ my $vars = { doc_section => 'using/creating-an-account.html' };
 
 print $cgi->header();
 
-my $login = $cgi->param('login');
+my $email = $cgi->param('email');
+my $login = Bugzilla->params->{'use_email_as_login'} ? $email : $cgi->param('login');
+
 my $request_new_password = $cgi->param('request_new_password');
 
 if ($request_new_password) {
     $template->process('account/request-new-password.html.tmpl', $vars)
       || ThrowTemplateError($template->error());
 }
-elsif (defined($login)) {
+elsif ($email && $login) {
     $user->check_account_creation_enabled;
     # Check the hash token to make sure this user actually submitted
     # the create account form.
     my $token = $cgi->param('token');
     check_hash_token($token, ['create_account']);
 
-    $user->check_and_send_account_creation_confirmation($login);
+    $user->check_and_send_account_creation_confirmation($login, $email);
     $vars->{'login'} = $login;
+    $vars->{'email'} = $email;
 
     $template->process("account/created.html.tmpl", $vars)
       || ThrowTemplateError($template->error());
index 0d2d180292947e0529d372f6665a5a3c721809c7..5835d654f018e22cc2809b0802430e416a2c7687 100644 (file)
@@ -169,12 +169,6 @@ requirelogin
     If this option is set, all access to the system beyond the front page will
     require a login. No anonymous users will be permitted.
 
-webservice_email_filter
-    Filter email addresses returned by the WebService API depending on if the
-    user is logged in or not. This works similarly to how the web UI currently
-    filters email addresses. If requirelogin is enabled, then this parameter
-    has no effect as users must be logged in to use Bugzilla anyway.
-
 emailregexp
     Defines the regular expression used to validate email addresses used for
     login names. The default attempts to match fully qualified email addresses
@@ -186,12 +180,6 @@ emailregexpdesc
     This description is shown to the user to explain which email addresses are
     allowed by the :param:`emailregexp` param.
 
-emailsuffix
-    This is a string to append to any email addresses when actually sending mail
-    to that address. It is useful if you have changed the :param:`emailregexp`
-    param to only allow local usernames, but you want the mail to be delivered
-    to username\@my.local.hostname.
-
 createemailregexp
     This defines the (case-insensitive) regexp to use for email addresses that
     are permitted to self-register. The default (:paramval:`.*`) permits any
@@ -499,9 +487,8 @@ address. The LDAP authentication builds on top of this scheme, rather
 than replacing it. The initial log-in is done with a username and
 password for the LDAP directory. Bugzilla tries to bind to LDAP using
 those credentials and, if successful, tries to map this account to a
-Bugzilla account. If an LDAP mail attribute is defined, the value of this
-attribute is used; otherwise, the :param:`emailsuffix` parameter is appended to
-the LDAP username to form a full email address. If an account for this address
+Bugzilla account. An LDAP mail attribute must be defined.
+If an account for this address
 already exists in the Bugzilla installation, it will log in to that account.
 If no account for that email address exists, one is created at the time
 of login. (In this case, Bugzilla will attempt to use the "displayName"
index e32db2f053c40a8db324fc744fd8a4c355380063..7d5b33399c3f53f0e3fc3f523703d82b4f89e3b2 100644 (file)
@@ -27,9 +27,7 @@ will appear in the Administration page.
 
 The first screen is a search form to search for existing user
 accounts. You can run searches based either on the user ID, real
-name or login name (i.e. the email address, or just the first part
-of the email address if the :param:`emailsuffix` parameter is set).
-The search can be conducted
+name, login name or email address. The search can be conducted
 in different ways using the listbox to the right of the text entry
 box. You can match by case-insensitive substring (the default),
 regular expression, a *reverse* regular expression
@@ -55,13 +53,15 @@ Modifying Users
 Once you have found your user, you can change the following
 fields:
 
-- *Login Name*:
-  This is generally the user's full email address. However, if you
-  have are using the :param:`emailsuffix` parameter, this may
-  just be the user's login name. Unless you turn off the
+- *Email Address*:
+  This is the user's full email address. Unless you turn off the
   :param:`allowemailchange` parameter, users can change their
   login names themselves (to any valid email address).
 
+- *Login Name*:
+  This is the user's login name, if it is (or can be) different from their email
+  address (i.e. if the "use_email_as_login" parameter is switched off).
+
 - *Real Name*: The user's real name. Note that
   Bugzilla does not require this to create an account.
 
index e13b171296630a98bc99560aa323026a8c5fa5ff..8b253a32c9bfbd610674fc4e7be3e33c53061799 100644 (file)
@@ -251,8 +251,6 @@ name       type    description
 id         int     The user ID for this user.
 real_name  string  The 'real' name for this user, if any.
 name       string  The user's Bugzilla login.
-email      string  The user's email address. Currently this is the same value as
-                   the name.
 =========  ======  ==============================================================
 
 Flag object:
@@ -291,6 +289,11 @@ field name in ``include_fields``.
 * 102 (Access Denied)
   You do not have access to the bug_id you specified.
 
+**History**
+
+Since Bugzilla 6.0, the email address of users is private and is no longer
+returned as part of the user object.
+
 .. _rest_history:
 
 Bug History
index 5aca556ecbc8dc06c9a03863e0a4a7218af48798..f0ba58e654e89616233ac83c03fb1d57f3c4286b 100644 (file)
@@ -178,7 +178,6 @@ Example response for authenticated user:
           "defaultseverity" : "normal",
           "duplicate_or_move_bug_status" : "RESOLVED",
           "emailregexp" : "^[\\w\\.\\+\\-=']+@[\\w\\.\\-]+\\.[\\w\\-]+$",
-          "emailsuffix" : "",
           "letsubmitterchoosemilestone" : "1",
           "letsubmitterchoosepriority" : "1",
           "mailfrom" : "bugzilla-daemon@example.com",
@@ -214,7 +213,6 @@ A logged-in user can access the following parameters (listed alphabetically):
 * defaultseverity
 * duplicate_or_move_bug_status
 * emailregexpdesc
-* emailsuffix
 * letsubmitterchoosemilestone
 * letsubmitterchoosepriority
 * mailfrom
index 0638ef758c75327b5d758fc6bac7243505c08824..90728287e15d11b2ecb64e19456aeb6a4c731dac 100644 (file)
@@ -142,6 +142,8 @@ to perform this action.
 ==========  ======  =============================================================
 name        type    description
 ==========  ======  =============================================================
+**login**   string  The login name for the new user. Ignored if the
+                    *use_email_as_login* parameter is true.
 **email**   string  The email address for the new user.
 full_name   string  The user's full name. Will be set to empty if not specified.
 password    string  The password for the new user account, in plain text. It
@@ -173,6 +175,10 @@ id    int   The numeric ID of the user that was created.
   The password specified is too short. (Usually, this means the
   password is under three characters.)
 
+**History**
+
+The *login* parameter has been added in Bugzilla 6.0.
+
 .. _rest_user_update:
 
 Update User
@@ -203,8 +209,7 @@ login names using the ``ids`` or ``names`` parameters respectively.
 **ids**            array    Additional IDs of users to update.
 **names**          array    Additional login names of users to update.
 full_name          string   The new name of the user.
-email              string   The email of the user. Note that email used to
-                            login to bugzilla. Also note that you can only
+email              string   The email of the user. Also note that you can only
                             update one user at a time when changing the login
                             name / email. (An error will be thrown if you try to
                             update this field for multiple users at once.)
@@ -357,8 +362,7 @@ id                 int      The unique integer ID that Bugzilla uses to represen
                             this will not change.
 real_name          string   The actual name of the user. May be blank.
 email              string   The email address of the user.
-name               string   The login name of the user. Note that in some
-                            situations this is different than their email.
+name               string   The login name of the user.
 can_login          boolean  A boolean value to indicate if the user can login
                             into bugzilla.
 email_enabled      boolean  A boolean value to indicate if bug-related mail will
@@ -404,7 +408,7 @@ query  string  The CGI parameters for the saved report.
 If you are not authenticated when you call this function, you will only be
 returned the ``id``, ``name``, and ``real_name`` items. If you are authenticated
 and not in 'editusers' group, you will only be returned the ``id``, ``name``,
-``real_name``, ``email``, ``can_login``, and ``groups`` items. The groups
+``real_name``, ``can_login``, and ``groups`` items. The groups
 returned are filtered based on your permission to bless each group. The
 ``saved_searches`` and ``saved_reports`` items are only returned if you are
 querying your own account, even if you are in the editusers group.
index 49bebb04bba55fbc459d56846c868b54d3fe751c..36c262fde32c0bfb2bcc143aafd4cb4a69781062 100755 (executable)
@@ -303,7 +303,7 @@ if ($action eq 'remove_regexp') {
 
     my @deleted;
     foreach my $member (@$users) {
-        if ($regexp eq '' || $member->login =~ m/$regexp/i) {
+        if ($regexp eq '' || $member->email =~ m/$regexp/i) {
             $sth_delete->execute($member->id, $group->id);
             push(@deleted, $member);
         }
index 502d2a564f86beddcbc9ecd067e38240fc673659..796d80d416c835f7910fd35281ac20bc69cc0329 100755 (executable)
@@ -135,12 +135,11 @@ if ($action eq 'save' && $current_module) {
             if (($name eq "shutdownhtml") && ($value ne "")) {
                 $vars->{'shutdown_is_active'} = 1;
             }
-            if ($name eq 'duplicate_or_move_bug_status') {
-                Bugzilla::Status::add_missing_bug_status_transitions($value);
-            }
         }
     }
 
+    call_param_onchange_handlers(\@changes);
+
     $vars->{'message'} = 'parameters_updated';
     $vars->{'param_changed'} = \@changes;
 
index 9d89d2efa1a871e72dda817b999292222beacbb9..3bc648509b3105a0bcd3580041d65b8d5198deca 100755 (executable)
@@ -72,7 +72,7 @@ if ($action eq 'search') {
     my $grouprestrict = $cgi->param('grouprestrict') || '0';
     # 0 = disabled only, 1 = enabled only, 2 = everyone
     my $is_enabled    = $cgi->param('is_enabled') // 2;
-    my $query = 'SELECT DISTINCT userid, login_name, realname, is_enabled, ' .
+    my $query = 'SELECT DISTINCT userid, login_name, email, realname, is_enabled, ' .
                 $dbh->sql_date_format('last_seen_date', '%Y-%m-%d') . ' AS last_seen_date ' .
                 'FROM profiles';
     my @bindValues;
@@ -98,7 +98,8 @@ if ($action eq 'search') {
                         };
             $nextCondition = 'AND';
         }
-    } else {
+    }
+    else {
         $visibleGroups = 1;
         if ($grouprestrict eq '1') {
             $query .= qq{, user_group_map AS ugm
@@ -116,10 +117,10 @@ if ($action eq 'search') {
         $vars->{'users'} = {};
     }
     else {
-        # Handle selection by login name, real name, or userid.
+        # Handle selection by login name, email, real name, or userid.
         if (defined($matchtype)) {
             $query .= " $nextCondition ";
-            my $expr = "";
+            my $expr = '';
             if ($matchvalue eq 'userid') {
                 if ($matchstr) {
                     my $stored_matchstr = $matchstr;
@@ -127,6 +128,8 @@ if ($action eq 'search') {
                         || ThrowUserError('illegal_user_id', {userid => $stored_matchstr});
                 }
                 $expr = "profiles.userid";
+            } elsif ($matchvalue eq 'email') {
+                $expr = 'profiles.email';
             } elsif ($matchvalue eq 'realname') {
                 $expr = "profiles.realname";
             } else {
@@ -182,7 +185,8 @@ if ($action eq 'search') {
         my $match_user_id = $vars->{'users'}[0]->{'userid'};
         my $match_user = check_user($match_user_id);
         edit_processing($match_user);
-    } else {
+    }
+    else {
         $template->process('admin/users/list.html.tmpl', $vars)
             || ThrowTemplateError($template->error());
     }
@@ -211,8 +215,14 @@ if ($action eq 'search') {
     my $password = $cgi->param('password');
     $password = '*' if !defined $password;
 
+    my $login_name = $cgi->param('login');
+    my $email      = $cgi->param('email');
+
+    $login_name = $email if Bugzilla->params->{use_email_as_login};
+
     my $new_user = Bugzilla::User->create({
-        login_name    => scalar $cgi->param('login'),
+        login_name    => $login_name,
+        email         => $email,
         cryptpassword => $password,
         realname      => scalar $cgi->param('name'),
         disabledtext  => scalar $cgi->param('disabledtext'),
@@ -268,7 +278,9 @@ if ($action eq 'search') {
     # is not authorized.
     my $changes = {};
     if ($editusers) {
-        $otherUser->set_login(scalar $cgi->param('login'));
+        $otherUser->set_login(scalar $cgi->param('login'))
+            unless Bugzilla->params->{use_email_as_login};
+        $otherUser->set_email(scalar $cgi->param('email'));
         $otherUser->set_name(scalar $cgi->param('name'));
         $otherUser->set_password(scalar $cgi->param('password'))
             if $cgi->param('password');
index c34d2fc24ac0123f84c644816d43acd928d0c06c..cb3c4883e8d99874a8cf715a19821561624800f0 100755 (executable)
@@ -508,10 +508,6 @@ Bugzilla::Hook::process('email_in_after_parse', { fields => $mail_fields });
 my $attachments = delete $mail_fields->{'attachments'};
 
 my $username = $mail_fields->{'reporter'};
-# If emailsuffix is in use, we have to remove it from the email address.
-if (my $suffix = Bugzilla->params->{'emailsuffix'}) {
-    $username =~ s/\Q$suffix\E$//i;
-}
 
 my $user = Bugzilla::User->check($username);
 Bugzilla->set_user($user);
index a0ed8f3fd541ea5086b4a0bc8852d09cc077317a..3de790d836dea5f593b6c7e0dff618b90bd02ad7 100644 (file)
@@ -746,7 +746,7 @@ sub _remove_votes {
 
     my $whopart = ($who) ? " AND votes.who = $who" : "";
 
-    my $sth = $dbh->prepare("SELECT profiles.login_name, " .
+    my $sth = $dbh->prepare("SELECT profiles.email, " .
                             "profiles.userid, votes.vote_count, " .
                             "products.votesperuser, products.maxvotesperbug " .
                             "FROM profiles " .
@@ -756,8 +756,8 @@ sub _remove_votes {
                             "WHERE votes.bug_id = ? " . $whopart);
     $sth->execute($id);
     my @list;
-    while (my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = $sth->fetchrow_array()) {
-        push(@list, [$name, $userid, $oldvotes, $votesperuser, $maxvotesperbug]);
+    while (my ($email, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = $sth->fetchrow_array()) {
+        push(@list, [$email, $userid, $oldvotes, $votesperuser, $maxvotesperbug]);
     }
 
     # @messages stores all emails which have to be sent, if any.
@@ -766,7 +766,7 @@ sub _remove_votes {
 
     if (scalar(@list)) {
         foreach my $ref (@list) {
-            my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = (@$ref);
+            my ($email, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = (@$ref);
 
             $maxvotesperbug = min($votesperuser, $maxvotesperbug);
 
@@ -797,7 +797,7 @@ sub _remove_votes {
             # Now lets send the e-mail to alert the user to the fact that their votes have
             # been reduced or removed.
             my $vars = {
-                'to' => $name . Bugzilla->params->{'emailsuffix'},
+                'to' => $email,
                 'bugid' => $id,
                 'reason' => $reason,
 
index 85f73bc6dd2735a2eeaba07b2cf087021510f5f3..4c29f90fe9eb5a286b66aaba4738feb70c0990d3 100755 (executable)
@@ -645,7 +645,7 @@ DoubleCrossCheck("milestones", "product_id", "value",
 
 Status('profile_login_start');
 
-my $sth = $dbh->prepare(q{SELECT userid, login_name FROM profiles});
+my $sth = $dbh->prepare(q{SELECT userid, email FROM profiles});
 $sth->execute;
 
 while (my ($id, $email) = $sth->fetchrow_array) {
index f85976516a2219fe85b9ba06b59d09bf7121e9f6..90cd1743de51f06b5ec68d2221fe6cf89960ef9b 100644 (file)
@@ -530,6 +530,24 @@ input.requestee {
     font-weight: bold;
 }
 
+form.table_layout div {
+    margin-bottom: 0.4em;
+}
+
+form.table_layout label {
+    font-weight: bold;
+    width: 8em;
+    display: inline-block;
+    float: left;
+    text-align: right;
+    padding-right: 0.5em;
+}
+
+.flex {
+    display: flex;
+    flex-wrap: wrap;
+}
+
 .throw_error a:visited {
     color: darkblue ;
 }
index 8f54e828e5c2778344b29ad9e12d5e8f60d36699..5861c2d35064114fc3039fcd5e21835d04ef7113 100644 (file)
@@ -66,7 +66,6 @@ foreach my $input (keys %email_strings) {
 # validate_email_syntax. We need to override some parameters.
 my $params = Bugzilla->params;
 $params->{emailregexp} = '.*';
-$params->{emailsuffix} = '';
 my $ascii_email = 'admin@company.com';
 # U+0430 returns the Cyrillic "а", which looks similar to the ASCII "a".
 my $utf8_email = "\N{U+0430}dmin\@company.com";
index cd0af0735c2d693eff365289d7580e6edaa6085d..0da18c38a9987737e49f4ca590ccc613a0ef9aa5 100644 (file)
@@ -161,7 +161,7 @@ sub directive_ok {
 
     # Directives
     return 1 if $directive =~ /^(IF|END|UNLESS|FOREACH|PROCESS|INCLUDE|
-                                 BLOCK|USE|ELSE|NEXT|LAST|DEFAULT|
+                                 BLOCK|USE|ELSE|NEXT|LAST|DEFAULT|CALL|
                                  ELSIF|SET|SWITCH|CASE|WHILE|RETURN|STOP|
                                  TRY|CATCH|FINAL|THROW|CLEAR|MACRO|FILTER)/x;
 
index 97d96a5af3e114c4f45c08dcf6bd8fff6761ce80..5536d306a3ffa4ba75b5c3e4ee1e6da5bfe6e747 100644 (file)
     <form action="token.cgi" method="post" id="forgot_form[% qs_suffix %]"
           class="mini_forgot bz_default_hidden">
       <label for="login[% qs_suffix FILTER html %]">Login:</label>
-      <input name="loginname" size="20" id="login[% qs_suffix FILTER html %]" required
-        [% IF login_not_email %]
-          placeholder="Your Login"
-        [% ELSE %]
-          type="email" placeholder="Your Email Address"
-        [% END %]>
+      <input name="email" size="20" id="login[% qs_suffix FILTER html %]" required
+             type="email" placeholder="Your Email Address">
       <input id="forgot_button[% qs_suffix %]" value="Reset Password"
              type="submit">
       <input type="hidden" name="a" value="reqpw">
index afa77df7f36f6691084d9c0c2622f7c19c325b1c..ac0fbcb995f6233c852a59047a8c6f9c1312cb0c 100644 (file)
@@ -40,7 +40,6 @@
       <td>
         <input id="Bugzilla_login" name="Bugzilla_login"
                [%- ' type="email"' UNLESS login_not_email %] autofocus required>
-        [% Param('emailsuffix') FILTER html %]
       </td>
     </tr>
 
index 384f2cfe09b9444fe1fdbe9521bef875cd4fafc0..46e05843514dd8bda9af5e9f75deddac5c4fa3e7 100644 (file)
@@ -21,7 +21,7 @@ to [% Param('maintainer') %] if you suspect foul play.
 
             Token: [% token %]
        Token Type: [% tokentype %]
-             User: [% emailaddress %]
+             User: [% login %]
        Issue Date: [% issuedate FILTER time("%Y-%m-%d %H:%M:%S %Z", timezone) %]
        Event Data: [% eventdata %]
 Canceled Because: [% PROCESS cancelactionmessage %]
index 5711a726f3b4dd98fe7129f67a483ee0ad5a1c10..e67848beb91d6c117b879e1d023ef9477b7ef40d 100644 (file)
@@ -6,25 +6,16 @@
   # defined by the Mozilla Public License, v. 2.0.
   #%]
 
-[%# INTERFACE
-  # none
-  # 
-  # Param("maintainer") is used to display the maintainer's email.
-  # Param("emailsuffix") is used to pre-fill the email field.
-  #%]
-
 [% PROCESS global/header.html.tmpl
            title = "Create a new $terms.Bugzilla account"
 %]
 
 <p>
   To create a [% terms.Bugzilla %] account, all you need to do is to enter
-[% IF Param('emailsuffix') == '' %]
+  [% IF !Param('use_email_as_login') %]
+    a login name of your choice and
+  [% END %]
   a legitimate email address.
-[% ELSE %]
-  an account name which when combined with [% Param('emailsuffix') %]
-  corresponds to an address where you receive email.
-[% END %]
   You will receive an email at this address to confirm the creation of your
   account. <b>You will not be able to log in until you receive the email.</b>
   If it doesn't arrive within a reasonable amount of time, you may contact
   at <a href="mailto:[% Param("maintainer") %]">[% Param("maintainer") %]</a>.
 </p>
 
-[% IF Param('allowemailchange') %]
 <p>
   If you already have an account and want to change your
-  [% IF Param('emailsuffix') == '' %]
-    email address,
-  [% ELSE %]
-    login name,
+  [% IF Param('allowemailchange') %]
+    email address or
   [% END %]
-  you can change it from the Preferences page after logging in.
+  login name, you can change it from the Preferences page after logging in.
 </p>
-[% END %]
 
 <p>
   A user account is required to report new [% terms.bugs %] or to comment into
   existing ones, as you may be contacted for more information if needed.
   This also lets other users clearly identify who is the author of comments
   or changes made into [% terms.bugs %]. <b>Note that your email address will
-  <em>never</em> be displayed to logged out users. Only registered users will be
-  able to see it.</b>
+  <em>never</em> be displayed to
+  [% IF Param('use_email_as_login') %]
+    logged out users. Only registered users will be able to see it.</b>
+  [% ELSE %]
+    other users, unless you decide to use your email address as login. Only
+    your login is visible to other users.</b>
+  [% END %]
 </p>
 
-[% IF Param('createemailregexp') == '.*' && Param('emailsuffix') == '' %]
+[% IF Param('createemailregexp') == '.*' %]
 <p>
   <b>PRIVACY NOTICE:</b> [% terms.Bugzilla %] is an open [% terms.bug %]
-  tracking system. Activity on most [% terms.bugs %], including email
-  addresses, will be visible to registered users. We <b>recommend</b> using a
-  secondary account or free web email service (such as Gmail, Yahoo,
-  Hotmail, or similar) to avoid receiving spam at your primary email address.
+  tracking system. Activity on most [% terms.bugs %] will be visible to
+  registered users.
+  [% IF Param('use_email_as_login') %]
+    That includes email addresses. We <b>recommend</b> using a
+    secondary account or free web email service (such as Gmail, Yahoo,
+    Hotmail, or similar) to avoid receiving spam at your primary email address.
+  [% END %]
 </p>
 [% END %]
 
-<form id="account_creation_form" method="get" action="createaccount.cgi">
-  <span class="label">
-    [% IF Param('emailsuffix') %]
-      Login:
-    [% ELSE %]
-      Email address:
-    [% END %]
-  </span>
-  <input size="35" id="login" name="login" autofocus
-         [%- ' type="email"' UNLESS Param('emailsuffix') %] required>
-  [% Param('emailsuffix') FILTER html %]
-  <input type="hidden" id="token" name="token" value="[% issue_hash_token(['create_account']) FILTER html %]">
-  <input type="submit" id="send" value="Send">
+<form id="account_creation_form" action="createaccount.cgi" class="table_layout">
+  [% IF !Param('use_email_as_login') %]
+    <div>
+      <label for="login">Login</label>
+      <div class="flex">
+        <input size="35" id="login" name="login" autofocus required>
+        <span class="bz_info">
+          (no whitespaces and no @ character, unless it matches your email address)
+        </span>
+      </div>
+    </div>
+  [% END %]
+
+  <div>
+    <label for="email">Email Address</label>
+    <input size="35" id="email" name="email" type="email"
+           [%~ " autofocus" IF Param('use_email_as_login') %] required>
+  </div>
+
+  <div>
+    <label>&nbsp;</label>
+    <input type="hidden" id="token" name="token"
+           value="[% issue_hash_token(['create_account']) FILTER html %]">
+    <input type="submit" id="send" value="Send">
+  </div>
 </form>
 
 [% PROCESS global/footer.html.tmpl %]
index f35deca8313994e4f083a7fca7021a8e54d801e4..f87571936b75d6bd82056a0ad81c833fbb64009b 100644 (file)
@@ -7,7 +7,8 @@
   #%]
 
 [%# INTERFACE:
-  # login: string. The user's Bugzilla login email address.
+  # login: string. The user's Bugzilla login.
+  # email: string. The user's Bugzilla email address.
   #%]
 
 [% title = BLOCK %]
@@ -17,9 +18,9 @@
 [% PROCESS global/header.html.tmpl title = title %]
 
 <p>
-  A confirmation email has been sent containing a link to continue
-  creating an account. The link will expire if an account is not
-  created within [% constants.MAX_TOKEN_AGE FILTER html %] days.
+  A confirmation email has been sent to <em>[% email FILTER html %]</em> containing
+  a link to continue creating an account. The link will expire if an account is
+  not created within [% constants.MAX_TOKEN_AGE FILTER html %] days.
 </p>
 
 [% PROCESS global/footer.html.tmpl %] 
index 3b98660040a49c29138ff4ae75a9d54a87a1fc9a..87a1c6440dbac3b33d9d200b2c341c0b9085b8b6 100644 (file)
@@ -9,26 +9,40 @@
 [%# INTERFACE:
   # token: string. The token to be used in the user account creation.
   # email: email address of the user account.
+  # login: login of the user account.
   # expiration_ts: expiration date of the token.
   #%]
 
-[% title = BLOCK %]Create a new user account for '[% email FILTER html %]'[% END %]
-[% PROCESS "global/header.html.tmpl"
-           title = title
-%]
+[% title = BLOCK %]Create a new user account for '[% login FILTER html %]'[% END %]
+[% PROCESS "global/header.html.tmpl" title = title %]
 
 [% password_complexity = Param('password_complexity') %]
 
 <p>
   To create your account, you must enter a password in the form below.
-  Your email address and Real Name (if provided) will be shown with
-  changes you make.
+  Your real name is optional, but recommended.
 </p>
 
 <form id="confirm_account_form" method="post" action="token.cgi">
   <input type="hidden" name="t" value="[% token FILTER html %]">
   <input type="hidden" name="a" value="confirm_new_account">
   <table>
+    [% IF !Param('use_email_as_login') %]
+      <tr>
+        <th>Login:</th>
+        <td>
+          [% IF login_already_in_use %]
+            <input id="login" name="login" required value="[% login FILTER html %]">
+            <span class="warning">
+              The login '[% login FILTER html %]' has been taken by another
+              user since you requested your account. Please choose another login.
+            </span>
+          [% ELSE %]
+            [% login FILTER html %]
+          [% END %]
+        </td>
+      </tr>
+    [% END %]
     <tr>
       <th>Email Address:</th>
       <td>[% email FILTER html %]</td>
index 8ca0ff1222500d9862a81c473ea648d485365c99..b56bf4f79f247d3b68acfe8abad9ddc11ec84c43 100644 (file)
@@ -10,6 +10,7 @@
   # token: random string used to authenticate the transaction.
   # expiration_ts: expiration date of the token.
   # email: email address of the new account.
+  # login: login name of the new account.
   #%]
 
 From: [% Param('mailfrom') %]
@@ -18,7 +19,7 @@ Subject: [% terms.Bugzilla %]: confirm account creation
 X-Bugzilla-Type: admin
 
 [%+ terms.Bugzilla %] has received a request to create a user account
-using your email address ([% email %]).
+[%+ "($login)" IF !Param('use_email_as_login') %] using your email address ([% email %]).
 
 To continue creating an account using this email address, visit the 
 following link by [% expiration_ts FILTER time("%B %e, %Y at %H:%M %Z") %]:
@@ -31,11 +32,14 @@ again by going to:
 
 [%+ urlbase %]createaccount.cgi
 
-[% IF Param('createemailregexp') == '.*' && Param('emailsuffix') == '' %]
-PRIVACY NOTICE: [% terms.Bugzilla %] is an open [% terms.bug %] tracking system. Activity on most
-[%+ terms.bugs %], including email addresses, will be visible to the public. We recommend
-using a secondary account or free web email service (such as Gmail, Yahoo,
-Hotmail, or similar) to avoid receiving spam at your primary email address.
+[% IF Param('createemailregexp') == '.*' %]
+PRIVACY NOTICE: [% terms.Bugzilla %] is an open [% terms.bug %] tracking
+system. Activity on most [%+ terms.bugs %] will be visible to the public.
+[% IF Param('use_email_as_login') %]
+This includes email addresses. We recommend using a secondary account or free
+web email service (such as Gmail, Yahoo, Hotmail, or similar) to avoid
+receiving spam at your primary email address.
+[% END %]
 [% END %]
 
 If you do not wish to create an account, or if this request was made in
index ddfc79aafc6a3da2c4a0b343e1f0cfed2d6df75f..81eb61f60989f98e2bdde34b154dd5b0d84db98f 100644 (file)
@@ -7,17 +7,17 @@
   #%]
 
 [%# INTERFACE:
-  # realname: string. The user's real name, if any.
-  # login_change_date: string. The date the email change will be complete. (optional)
-  # new_login_name:    string. The user's new Bugzilla login whilst not confirmed. (optional)
+  # email_change_date: string. The date the email change will be complete. (optional)
+  # new_email:         string. The user's new email address whilst not confirmed. (optional)
   #%]
 
 <table>
   [% IF user.authorizer.can_change_password
-        || (user.authorizer.can_change_email && Param('allowemailchange')) %]
+        || (user.authorizer.can_change_email && Param('allowemailchange'))
+        ||  user.authorizer.can_change_login %]
     <tr>
-      <td colspan="3">
-        Please enter your existing password to confirm account changes.
+      <td colspan="2">
+        Please enter your current password to confirm any changes in this section.
       </td>
     </tr>
     <tr>
@@ -27,9 +27,6 @@
         <input type="password" name="old_password" id="old_password">
       </td>
     </tr>
-    <tr>
-      <td colspan="2"><hr></td>
-    </tr>
   [% END %]
 
   [% IF user.authorizer.can_change_password %]
@@ -37,6 +34,9 @@
       <th><label for="new_password1">New password:</label></th>
       <td>
         <input type="password" name="new_password1" id="new_password1">
+        <span class="bz_info">
+          (Leave empty to keep current password)
+        </span>
       </td>
     </tr>
 
     </tr>
   [% END %]
 
-  <tr>
-    <th>
-      <label for="realname">Your real name (optional, but encouraged):</label>
-    </th>
-    <td>
-      <input size="35" name="realname" id="realname" value="[% realname FILTER html %]">
-    </td>
-  </tr>  
+  [% UNLESS Param('use_email_as_login') %]
+    <tr>
+      <th><label for="new_login">Your login name:</label></th>
+      <td>
+        [% IF user.authorizer.can_change_login %]
+          <input size="35" name="new_login" id="new_login"
+                 value="[% user.login FILTER html %]">
+        [% ELSE %]
+          [% user.login FILTER html %]
+        [% END %]
+      </td>
+    </tr>
+  [% END %]
 
-  [% IF user.authorizer.can_change_email && Param('allowemailchange') %]
-    [% IF login_change_date %]
-      [% IF new_login_name %]
-        <tr>
-          <th>Pending email address:</th>
-          <td>[% new_login_name FILTER html %]</td>
-        </tr>
-        <tr>
-          <th>Change request expires:</th>
-          <td>[% login_change_date FILTER time %]</td>
-        </tr>
-      [% ELSE %]
-        <tr>
-          <th>Confirmed email address:</th>
-          <td>[% user.login FILTER html %]</td>
-        </tr>
-        <tr>
-          <th>Completion date:</th>
-          <td>[% login_change_date FILTER time %]</td>
-        </tr>
-      [% END %]
+  [% IF user.authorizer.can_change_email
+        && Param('allowemailchange')
+        && email_change_date %]
+    [% IF new_email %]
+      <tr>
+        <th><label>Pending email address:</label></th>
+        <td>[% new_email FILTER html %]</td>
+      </tr>
+      <tr>
+        <th><label>Change request expires:</label></th>
+        <td>[% email_change_date FILTER time %]</td>
+      </tr>
     [% ELSE %]
       <tr>
-        <th>
-          <label for="new_login_name">
-            [% IF Param('emailsuffix') %]
-              New login:
-            [% ELSE %]
-              New email address:
-            [% END %]
-          </label>
-        </th>
-        <td>
-          <input size="35" id="new_login_name" name="new_login_name"
-                 [%- ' type="email"' UNLESS Param('emailsuffix') %]>
-        </td>
+        <th><label>Confirmed email address:</label></th>
+        <td>[% user.email FILTER html %]</td>
+      </tr>
+      <tr>
+        <th><label>Completion date:</label></th>
+        <td>[% email_change_date FILTER time %]</td>
       </tr>
     [% END %]
+  [% ELSE %]
+    <tr>
+      <th>
+        <label for="new_email">
+          Your email address[% "/login" IF Param('use_email_as_login') %]:
+        </label>
+      </th>
+      <td>
+        [% IF user.authorizer.can_change_email && Param('allowemailchange') %]
+          <input size="35" name="new_email" id="new_email"
+                 value="[% user.email FILTER html %]"
+                 [%~ ' type="email"' IF Param('use_email_as_login') %]>
+        [% ELSE %]
+          [% user.email FILTER html %]
+        [% END %]
+      </td>
+    </tr>
   [% END %]
 
+  <tr>
+    <td colspan="2"><hr></td>
+  </tr>
+
+  <tr>
+    <th>
+      <label for="realname">Your real name (optional, but encouraged):</label>
+    </th>
+    <td>
+      <input size="35" name="realname" id="realname"
+             value="[% user.name FILTER html %]">
+    </td>
+  </tr>
+
   [% Hook.process('field') %]
 
 </table>
index a94b3a114846d462b5985e39be0106d7c1dc485b..73caa6dcbe1120d0b07daf76291b77e2fe0ec957 100644 (file)
 
 [% IF user.authorizer.can_change_password %]
   <p>
-    If you have an account, but have forgotten your password, enter your
-    [% IF Param('emailsuffix') %]
-      login name
-    [% ELSE %]
-      email address
-    [% END %]
-    below and submit a request to change your password. An email with details
-    on how to reset your password will be sent.
+    If you have an account, but have forgotten your password, enter your email
+    address below and submit a request to change your password. An email with
+    details on how to reset your password will be sent.
   </p>
 
   <form id="forgot_password" method="get" action="token.cgi">
     <input type="hidden" name="a" value="reqpw">
-    <input id="loginname" [% IF !Param('emailsuffix') %]type="email"[% END %]
-           name="loginname" autofocus required>
+    <input id="email" type="email" name="email" autofocus required>
     <input type="hidden" id="token" name="token"
            value="[% issue_hash_token(['reqpw']) FILTER html %]">
     <input type="submit" id="request" value="Reset Password">
index 7505ebd8c39a3ad45dc7d3cce3e6af79b7828484..1fccea4a59a6bfe58586bf71862dc6a593222d6c 100644 (file)
         if requestable, who should get carbon copied on email notification of requests.
         This is a comma-separated list of full e-mail addresses which do not
         need to be [% terms.Bugzilla %] logins.
-        [% IF Param('emailsuffix') %]
-          Note that the configured emailsuffix
-          <kbd>[% Param('emailsuffix') %]</kbd> will <em>not</em> be appended
-          to these addresses, so you should add it explicitly if so desired.
-        [% END %]<br>
+        <br>
         <input type="text" name="cc_list" value="[% type.cc_list FILTER html %]" size="80"
                maxlength="200" [%- ' disabled="disabled"' UNLESS can_fully_edit %]>
       </td>
index 3249ee384219c7be3633b88c8dc4ce1b1aabacfe..ef3e44a91e3f6cfccae4532a9ca6eecce62d735d 100644 (file)
@@ -12,7 +12,7 @@
   #%]
 
 [% IF regexp %]
-  [% title = "Confirm: Remove Explicit Members in the Regular Expression?" %]
+  [% title = "Confirm: Remove Explicit Members Using A Regular Expression?" %]
 [% ELSE %]
   [% title = "Confirm: Remove All Explicit Members?" %]
 [% END %]
 
 [% IF regexp %]
   <p>This option will remove all users from '[% group.name FILTER html %]'
-    whose login names match the regular expression:
+    whose email addresses match the regular expression:
     '[% regexp FILTER html %]'</p>
 [% ELSE %]
-  <p>This option will remove all explicitly defined users
+  <p>This option will remove all explicitly-added users
     from '[% group.name FILTER html %].'</p>
 [% END %]
   
index 3e64fa7c4a86a6f04b95da55771bf02835bec6d2..5a20ef36e387a8a01e1c74699990f7b3e1eaca61 100644 (file)
 
 <form method="post" action="editgroups.cgi">
   <fieldset id="mass-remove">
-    <legend>Remove all explicit memberships from users whose login names
+    <legend>Remove all explicit memberships from users whose email addresses
       match the following regular expression:</legend>
     <input type="text" size="20" name="regexp">
     <input type="submit" id="remove-membership" value="Remove Memberships">
index 06f85ed26288cf54a45663c9c5d9abda73f20562..79fa8123beae0607a4640ee9b0755d31ccacb11e 100644 (file)
                   "front page will require a login. No anonymous users will " _
                   "be permitted.",
 
-  webservice_email_filter =>
-    "Filter email addresses returned by the WebService API depending on " _
-    "if the user is logged in or not. This works similarly to how the " _
-    "web UI currently filters email addresses. If <var>requirelogin</var> " _
-    "is enabled, then this parameter has no effect as users must be logged " _
-    "in to use Bugzilla.",
-
   emailregexp =>
     "This defines the regular expression to use for legal email addresses. " _
     "The default tries to match fully qualified email addresses. " _
     "Use <kbd>.*</kbd> to accept any email address following the " _
     "<a href=\"http://tools.ietf.org/html/rfc2822#section-3.4.1\">RFC 2822</a> " _
-    "specification. Another popular value to put here is <kbd>^[^@]+$</kbd>, " _
-    "which means 'local usernames, no @ allowed.'",
+    "specification.",
 
   emailregexpdesc => "This description explains valid addresses that " _
                      "are allowed by the <var>emailregexp</var> param.",
 
-  emailsuffix => "This is a string to append to any email addresses when actually " _
-                 "sending mail to that address. It is useful if you have changed " _
-                 "the <var>emailregexp</var> param to only allow local usernames, " _
-                 "but you want the mail to be delivered to username@my.local.hostname.",
-
   createemailregexp => "This defines the (case-insensitive) regexp to use for email addresses that are " _
                        "permitted to self-register using a 'New Account' feature. The " _
                        "default (.*) permits any account matching the emailregexp " _
                        "will be permitted to create their own accounts and all accounts " _
                        "will have to be created by an administrator.",
 
+  use_email_as_login => "If switched on, users will log in with the email " _
+                        "address of the account. If switched off, they will " _
+                        "log in with a separate identifier.<br>" _
+                        "<strong>Switching this from off to on results in " _
+                        "the destructive act of the login name for all users " _
+                        "being set to their email address!</strong>",
+
   password_complexity =>
     "Set the complexity required for passwords. In all cases must the passwords " _
     "be at least ${constants.USER_PASSWORD_MIN_LENGTH} characters long." _
index ab3521f27eb0fa201b7c0959b6022012296f4912..d31aad825e37262766a01a7276f667fbd006fc87 100644 (file)
 
   LDAPmailattribute => "The name of the attribute of a user in your " _
                        "directory that contains the email address, to be " _
-                       "used as Bugzilla username. If this parameter " _
-                       "is empty, Bugzilla will use the LDAP username"_
-                       " as the Bugzilla username. You may also want" _
-                       " to set the \"emailsuffix\" parameter, in this case.",
+                       "used to send the user email.",
 
   LDAPfilter => "LDAP filter to AND with the <var>LDAPuidattribute</var> for " _
                 "filtering the list of valid users." }
index 4dab8b4713989e328154e37eee7fd07db4975f8e..07b6ccb25e3d20541c3e51131f3d29a214e59d73 100644 (file)
     <th>Field</th>
     <th>Value</th>
   </tr>
+  [% IF !Param('use_email_as_login') %]
+    <tr>
+      <th>Login:</th>
+      <td>[% otheruser.login FILTER html %]</td>
+    </tr>
+  [% END %]
   <tr>
-    <th>Login name:</th>
-    <td>[% otheruser.login FILTER html %]</td>
+    <th>Email address:</th>
+    <td>[% otheruser.email FILTER html %]</td>
   </tr>
   <tr>
     <th>Real name:</th>
index f90996882ceab79bf9067f955d0fc592501afd8f..168e6dd90c0c46c8fc5ef919c5ae744e1a42f5ef 100644 (file)
 [% listselectionurlparams = INCLUDE listselectionurlparams %]
 
 [% columns =
-  [{name               => 'login_name'
-    heading            => 'Edit user...'
-    contentlink        => 'editusers.cgi?action=edit&amp;userid=%%userid%%' _
-                          listselectionurlparams
-   }
-   {name               => 'realname'
-    heading            => 'Real name'
-   }
-   {name               => 'last_seen_date'
-    heading            => 'Last Login'
-   }
-   {heading            => 'Account History'
-    content            => 'View'
-    contentlink        => 'editusers.cgi?action=activity' _
-                                  '&amp;userid=%%userid%%' _
-                                  listselectionurlparams
+  [{name        => 'login_name'
+    heading     => 'Edit user...'
+    contentlink => 'editusers.cgi?action=edit&amp;userid=%%userid%%' _
+                   listselectionurlparams
+   },
+   {name        => 'email'
+    heading     => 'Email address'
+   },
+   {name        => 'realname'
+    heading     => 'Real name'
+   },
+   {name        => 'last_seen_date'
+    heading     => 'Last Login'
+   },
+   {name        => 'view_history_link',
+    heading     => 'Account History'
+    content     => 'View'
+    contentlink => 'editusers.cgi?action=activity' _
+                    '&amp;userid=%%userid%%' _
+                    listselectionurlparams
+   },
+   {name        => 'action_link',
+    heading     => 'Action'
+    content     => 'Delete'
+    contentlink => 'editusers.cgi?action=del' _
+                      '&amp;userid=%%userid%%' _
+                      listselectionurlparams
    }
   ]
-%]
+ %]
+
+[%# Eliminate inappropriate columns, starting at the end %]
+[% IF NOT (Param('allowuserdeletion') && editusers) %]
+  [% CALL columns.splice(5, 1) %]
+[% END %]
 
-[% IF Param('allowuserdeletion') && editusers %]
-  [% columns.push({heading     => 'Action'
-                   content     => 'Delete'
-                   contentlink => 'editusers.cgi?action=del' _
-                                  '&amp;userid=%%userid%%' _
-                                  listselectionurlparams
-                  }
-                 )
-  %]
+[% IF Param('use_email_as_login') %]
+  [% CALL columns.splice(1, 1) %]
 [% END %]
 
 [%# Disabled users are crossed out. Missing realnames are noticed in red. %]
index 17477a01222e9bd03fa23296c68a095f1c026fc8..f71589480201a50b3eac18086e40d77c61360058 100644 (file)
@@ -30,6 +30,7 @@
 <p><label for="matchvalue">List users with</label>
 <select id="matchvalue" name="matchvalue">
   <option value="login_name">login name</option>
+  <option value="email">email address</option>
   <option value="realname">real name</option>
   <option value="userid">user id</option>
 </select>
index c08cd001808a3dcb83641f69ad47888da4e8405c..8f925e69aa9017300f516cbece17755684d70897 100644 (file)
   var disable_mail_manually_set = [% (otheruser.email_disabled ? 1 : 0) FILTER js %];
 </script>
 
+[% IF NOT Param('use_email_as_login') %]
+  <tr>
+    <th><label for="login">Login:</label></th>
+    <td>
+      [% IF editusers %]
+        <input size="64" maxlength="255" id="login" name="login"
+               value="[% otheruser.login FILTER html %]"
+               [%- " autofocus" UNLESS editform %] required>
+      [% ELSE %]
+        [% otheruser.login FILTER html %]
+      [% END %]
+    </td>
+  </tr>
+[% END %]
 <tr>
-  <th><label for="login">Login name:</label></th>
+  <th>
+    <label for="email">
+      Email address [% ' (login)' IF Param('use_email_as_login') %]:
+    </label>
+  </th>
   <td>
     [% IF editusers %]
-      <input size="64" maxlength="255" id="login" name="login"
-             value="[% otheruser.login FILTER html %]"
-             [%- " autofocus" UNLESS editform %] required>
+      <input size="64" maxlength="255" id="email" name="email"
+             value="[% otheruser.email FILTER html %]"
+             [%- " autofocus" IF Param('use_email_as_login') AND NOT editform %] required>
       [% IF editform %]
         [% IF !otheruser.in_group('bz_sudo_protect') %]
           <br>
@@ -32,7 +50,7 @@
         [% END %]
       [% END %]
     [% ELSE %]
-      [% otheruser.login FILTER html %]
+      [% otheruser.email FILTER html %]
     [% END %]
   </td>
 </tr>
index 7f2b741f6283b69c3dbe608e11f1974ed1c0ab3c..d10053702e14dd9dde4b319159532f7fb8cf2670 100644 (file)
           users
         [% END %]
         [% IF user.id %]
-          [% IF bug.cc.contains( user.email ) %]
+          [% IF bug.cc.contains( user.login ) %]
             including you
           [% END %]
         [% END %]
index 2b2d32d5a2b60dac6725c7478dac637961137c34..fe5f4f6f45acb42c3b678101b59a8813ffcce9f3 100644 (file)
@@ -18,7 +18,7 @@
           %]
           maintainer="[% Param('maintainer') FILTER xml %]"
 [% IF user.id %]
-          exporter="[% user.email FILTER email FILTER xml %]"
+          exporter="[% user.login FILTER email FILTER xml %]"
 [% END %]
 >
 
@@ -76,7 +76,7 @@
             <type>[% a.contenttype FILTER xml %]</type>
             <size>[% a.datasize FILTER xml %]</size>
             <attacher[% IF a.attacher.name != '' %] name="[% a.attacher.name FILTER xml %]"[% END -%]>
-            [% a.attacher.email FILTER email FILTER xml %]</attacher>
+            [% a.attacher.login FILTER email FILTER xml %]</attacher>
             [%# This is here so automated clients can still use attachment.cgi %]
             [% IF displayfields.token && user.id %]
               <token>[% issue_hash_token([a.id, a.modification_time]) FILTER xml %]</token>
     [% IF field == 'reporter' OR field == 'assigned_to' OR
           field == 'qa_contact' %]
       [% name = val.name %]
-      [% val = val.email FILTER email %]
+      [% val = val.login FILTER email %]
     [% ELSIF field == 'cc' %]
         [% val = val FILTER email %]
     [% ELSIF field == 'creation_ts' OR field == 'delta_ts' %]
           id="[% flag.id FILTER xml %]"
           type_id="[% flag.type_id FILTER xml %]"
           status="[% flag.status FILTER xml %]"
-          setter="[% flag.setter.email FILTER email FILTER xml %]"
+          setter="[% flag.setter.login FILTER email FILTER xml %]"
       [% IF flag.status == "?" && flag.requestee %]
-          requestee="[% flag.requestee.email FILTER email FILTER xml %]"
+          requestee="[% flag.requestee.login FILTER email FILTER xml %]"
       [% END %]
     />
   [% END %]
     [% IF c.is_about_attachment %]
       <attachid>[% c.extra_data FILTER xml %]</attachid>
     [% END %]
-    <who name="[% c.author.name FILTER xml %]">[% c.author.email FILTER email FILTER xml %]</who>
+    <who name="[% c.author.name FILTER xml %]">[% c.author.login FILTER email FILTER xml %]</who>
     <bug_when>[% c.creation_ts FILTER time("%Y-%m-%d %T %z") FILTER xml %]</bug_when>
     [% IF user.is_timetracker && (c.work_time - 0 != 0) %]
       <work_time>[% PROCESS formattimeunit time_unit = c.work_time FILTER xml %]</work_time>
index 106a94a5e6d704b4efb3578966d858bfeaff4cef..5844c92f332ad8edcdec68f573768e4f26db0300 100644 (file)
@@ -7,7 +7,7 @@
   #%]
 
 From: [% Param("mailfrom") %]
-To: [% email %][% Param("emailsuffix") %]
+To: [% email %]
 Subject: Your [% terms.Bugzilla %] [%+ terms.bug %] list needs attention.
 X-Bugzilla-Type: whine
 
index 77b13859cd6acdfa6967b8e365d3fcd3a3727ccb..9f646460164c1045a53641ba62e5b24550e66d95 100644 (file)
@@ -22,7 +22,7 @@
 
   [% ELSIF message_tag == "account_creation_canceled" %]
     [% title = "User Account Creation Canceled" %]
-    The creation of the user account [% account FILTER html %] has been
+    The creation of the user account '[% login FILTER html %]' has been
     canceled.
 
   [% ELSIF message_tag == "account_updated" %]
@@ -35,6 +35,8 @@
           <li>
             [% IF    field == 'login_name' %]
               The login is now [% otheruser.login FILTER html %].
+            [% ELSIF field == 'email' %]
+              The email is now [% otheruser.email FILTER html %].
             [% ELSIF field == 'realname' %]
               The real name has been updated.
             [% ELSIF field == 'cryptpassword' %]
@@ -89,8 +91,8 @@
     successfully.
 
   [% ELSIF message_tag == "account_disabled" %]
-    Logging in with this user account [% account FILTER html %] is disabled, so
-    you cannot change its password.
+    Logging in with the user account with email address [% email FILTER html %]
+    is disabled, so you cannot change its password.
 
   [% ELSIF message_tag == "attachment_creation_failed" %]
     The [% terms.bug %] was created successfully, but attachment creation
     [%+ terms.Bugzilla %]...
 
   [% ELSIF message_tag == "migrate_user_created" %]
-    User created: [% created.email FILTER html %]
+    User created: [% created.login FILTER html %]
     [% IF password %] Password: [% password FILTER html %][% END %]
 
   [% ELSIF message_tag == "migrate_value_created" %]
     [%+ field_descs.${field.name} FILTER html %] value
     created: [% value FILTER html %]
 
+  [% ELSIF message_tag == "email_changed" %]
+    [% title = "Email Changed" %]
+    Your email address has been updated.
+
   [% ELSIF message_tag == "milestone_created" %]
     [% title = "Milestone Created" %]
     The milestone <em>[% milestone.name FILTER html %]</em> has been created.
   [% ELSIF message_tag == "password_change_request" %]
     [% title = "Request to Change Password" %]
     A token for changing your password has been emailed to
-    <em>[% login_name FILTER html %]</em>.
+    <em>[% email FILTER html %]</em>.
     Follow the instructions in that email to change your password.
 
   [% ELSIF message_tag == "password_changed" %]
     [% title = BLOCK %]Flag Type '[% flag_type.name FILTER html %]' Deactivated[% END %]
     The flag type <em>[% flag_type.name FILTER html %]</em> has been deactivated.
 
+  [% ELSIF message_tag == "install_admin_get_login" %]
+    Enter the login name the administrator will log in with:
+
   [% ELSIF message_tag == "install_admin_get_email" %]
     Enter the e-mail address of the administrator:
 
index bd8c54f2d32d0e4ef5b75db39321cdf25e013370..bdb90a2a224b71502953e8eb826d103b59b8683a 100644 (file)
   [% ELSIF error == "account_exists" %]
     [% title = "Account Already Exists" %]
     There is already an account with
-    [% IF email %]
-      the login name [% email FILTER html %].
+    [% IF login %]
+      the login name [% login FILTER html %].
+    [% ELSIF email %]
+      the email address [% email FILTER html %].
     [% ELSE %]
-      that login name.
+      that login name or email address.
     [% END %]
 
   [% ELSIF error == "account_locked" %]
     [% title = "Email Change Already In Progress" %]
     Email change already in progress; please check your email.
 
+  [% ELSIF error == "email_needed_for_password_change" %]
+    [% title = "Email Address Required" %]
+    You must enter an email address when requesting to change your password.
+
   [% ELSIF error == "email_no_body" %]
     Your message did not contain any text, as far as we could tell.
 
+  [% ELSIF error == "email_required" %]
+    [% title = "Email Address Required" %]
+    [% admindocslinks = {'useradmin.html' => 'User administration'} %]
+    You must enter an email address for the new user.
+
   [% ELSIF error == "empty_group_description" %]
     [% title = "The group description cannot be empty" %]
     You must enter a description for the group.
     [% IF format %]
       Please use the format '<code>[% format FILTER html %]</code>'.
     [% END %]
-    
+
   [% ELSIF error == "illegal_email_address" %]
     [% title = "Invalid Email Address" %]
-    The e-mail address you entered (<b>[% addr FILTER html %]</b>) 
+    The e-mail address you entered (<b>[% email FILTER html %]</b>)
     didn't pass our syntax checking for a legal email address.
     [% IF default %]
       A legal address must contain exactly one '@',
     [% title = "Invalid Dimensions" %]
     The width or height specified is not a positive integer.
 
+  [% ELSIF error == "invalid_email" %]
+    [% title = "Invalid Email Address" %]
+    The address <tt>[% email FILTER html %]</tt> is not a valid email address.
+    Either you misspelled it, or the person has not
+    registered for a [% terms.Bugzilla %] account.
+
   [% ELSIF error == "invalid_format" %]
     [% title = "Invalid Format" %]
     The format "[% format FILTER html %]" is invalid (must be one of
   [% ELSIF error == "keyword_blank_description" %]
     [% title = "Blank Keyword Description Not Allowed" %]
     You must enter a non-blank description for the keyword.
-     
+
   [% ELSIF error == "keyword_blank_name" %]
     [% title = "Blank Keyword Name Not Allowed" %]
     You must enter a non-blank name for the keyword.
-     
+
   [% ELSIF error == "keyword_invalid_name" %]
     [% title = "Invalid Keyword Name" %]
     You may not use commas or whitespace in a keyword name.
-     
-  [% ELSIF error == "login_needed_for_password_change" %]
-    [% title = "Login Name Required" %]
-    You must enter a login name when requesting to change your password.
+
+  [% ELSIF error == "login_at_sign_disallowed" %]
+    [% title = "Illegal Character in Login" %]
+    Login names may not contain the "@" sign unless you are setting your
+    login name to be identical to your email address.
+
+  [% ELSIF error == "login_change_during_email_change" %]
+    [% title = "Login Change Not Permitted" %]
+    You may not change your login name while you are in the middle of the
+    process of changing your email address.
+
+  [% ELSIF error == "login_illegal_character" %]
+    [% title = "Illegal Character In Login" %]
+    Login names are not allowed to contain space characters.
 
   [% ELSIF error == "login_required_for_pronoun" %]
     [% title = "Login Name Required" %]
     [%# Used for non-web-based LOGIN_REQUIRED situations. %]
     You must log in before using this part of [% terms.Bugzilla %].
 
+  [% ELSIF error == "login_too_long" %]
+    [% title = "Login Too Long" %]
+    Your login name is too long. It cannot exceed 127 characters.
+
   [% ELSIF error == "markdown_disabled" %]
     Markdown feature is not enabled.
 
     You did not enter your current password correctly.
 
   [% ELSIF error == "current_password_required" %]
-    [% title = "Old Password Required" %]
-    You must enter your old password to change your email address.
+    [% title = "Current Password Required" %]
+    You must enter your current password to edit your account.
 
   [% ELSIF error == "password_change_requests_not_allowed" %]
     [% title = "Password Change Requests Not Allowed" %]
     The password must be at least
     [%+ constants.USER_PASSWORD_MIN_LENGTH FILTER html %] characters long.
     [% IF locked_user %]
-      You must <a href="token.cgi?a=reqpw&amp;loginname=[% locked_user.email FILTER uri %]&amp;token=[% issue_hash_token(['reqpw']) FILTER uri %]">
+      You must <a href="token.cgi?a=reqpw&amp;email=[% locked_user.email FILTER uri %]&amp;token=[% issue_hash_token(['reqpw']) FILTER uri %]">
       request a new password</a> in order to log in again.
     [% END %]
 
       [% END %]
     </ul>
     [% IF locked_user %]
-      You must <a href="token.cgi?a=reqpw&amp;loginname=[% locked_user.email FILTER uri %]&amp;token=[% issue_hash_token(['reqpw']) FILTER uri %]">
+      You must <a href="token.cgi?a=reqpw&amp;email=[% locked_user.email FILTER uri %]&amp;token=[% issue_hash_token(['reqpw']) FILTER uri %]">
       request a new password</a> in order to log in again.
     [% END %]
 
index 7050c6d378ab7abcb5905ba99524176a743ce328..0ee303fe9049274fcd0224e979d9e788be26f878 100644 (file)
 
 <span class="vcard">
   [% FILTER collapse %]
-    [% IF user.id %]
-      <a class="email" href="mailto:[% who.email FILTER html %]"
-         title="[% who.identity FILTER html %]">
-    [%- END -%]
-    [% IF who.name %]
-       <span class="fn">[% who.name FILTER html %]</span>
+    [% IF Param("use_email_as_login") %]
+      [% IF user.id %]
+        <a class="email" href="mailto:[% who.email FILTER html %]"
+           title="[% who.identity FILTER html %]">
+      [%- END -%]
+      [% IF who.name %]
+         <span class="fn">[% who.name FILTER html %]</span>
+      [% ELSE %]
+        [% who.login FILTER email FILTER html %]
+      [% END %]
+      [% '</a>' IF user.id %]
     [% ELSE %]
-      [% who.login FILTER email FILTER html %]
+      [% who.identity FILTER html %]
     [% END %]
-    [% '</a>' IF user.id %]
   [% END %]
 </span>
index d19178ce32bc91b2c9df3f780d372b0e15b52b78..bb440c2b4ac3c9f735bc63d66eb7644ad6f466f4 100644 (file)
@@ -21,8 +21,7 @@
 </p>
 <p>
   [% IF series.creator %]
-    This series has been created by <a href="mailto:[% series.creator.email FILTER html %]">
-    [% series.creator.email FILTER html %]</a>
+    This series has been created by [% series.creator.login FILTER html %]
   [% ELSE %]
     This series has been automatically created by Bugzilla
   [% END %]
index ad6bb32f400e0eaa00af1ce6072860fd1ea9974e..8cf1616c021d52fa3d7c9614e7a845c93eccf55f 100644 (file)
@@ -33,8 +33,7 @@
 <p>
   <b>Creator</b>: 
   [% IF default.creator %]
-    <a href="mailto:[% default.creator.email FILTER html %]">
-    [% default.creator.email FILTER html %]</a>
+    [% default.creator.login FILTER html %]
   [% ELSE %]
     (automatically created by Bugzilla)
   [% END %]
index babcc028ba5f92ae43ba22636d7bf80c2f062ab9..b2792306e04505c16565eeffc4475e84d7a234a1 100755 (executable)
--- a/token.cgi
+++ b/token.cgi
@@ -122,22 +122,22 @@ sub requestChangePassword {
     my $token = $cgi->param('token');
     check_hash_token($token, ['reqpw']);
 
-    my $login_name = $cgi->param('loginname')
-      or ThrowUserError("login_needed_for_password_change");
+    my $email = $cgi->param('email')
+      or ThrowUserError("email_needed_for_password_change");
 
-    check_email_syntax($login_name);
-    my $user = new Bugzilla::User({ name => $login_name });
+    my $userid = email_to_id($email, 'throw_error_if_not_exist');
+    my $user = new Bugzilla::User($userid);
 
     # Make sure the user account is active.
-    if ($user && !$user->is_enabled) {
+    if (!$user->is_enabled) {
         ThrowUserError('account_disabled',
-                       {disabled_reason => get_text('account_disabled', {account => $login_name})});
+                       {disabled_reason => get_text('account_disabled', {email => $email})});
     }
 
-    Bugzilla::Token::IssuePasswordToken($user) if $user;
+    Bugzilla::Token::IssuePasswordToken($user);
 
     $vars->{'message'} = "password_change_request";
-    $vars->{'login_name'} = $login_name;
+    $vars->{'email'} = $email;
 
     print $cgi->header();
     $template->process("global/message.html.tmpl", $vars)
@@ -208,7 +208,7 @@ sub changeEmail {
     my ($old_email, $new_email) = split(/:/,$eventdata);
 
     $dbh->bz_start_transaction();
-    
+
     my $user = Bugzilla::User->check({ id => $userid });
     my $cgipassword  = $cgi->param('password');
 
@@ -218,14 +218,14 @@ sub changeEmail {
 
     # The new email address should be available as this was 
     # confirmed initially so cancel token if it is not still available
-    if (! is_available_username($new_email,$old_email)) {
+    if (!is_available_email($new_email, $old_email)) {
         $vars->{'email'} = $new_email; # Needed for Bugzilla::Token::Cancel's mail
         Bugzilla::Token::Cancel($token, "account_exists", $vars);
         ThrowUserError("account_exists", { email => $new_email } );
     } 
 
-    # Update the user's login name in the profiles table.
-    $user->set_login($new_email);
+    # Update the user's email address in the profiles table.
+    $user->set_email($new_email);
     $user->update({ keep_session => 1, keep_tokens => 1 });
     delete_token($token);
     $dbh->do(q{DELETE FROM tokens WHERE userid = ?
@@ -256,8 +256,8 @@ sub cancelChangeEmail {
         my $user = Bugzilla::User->check({ id => $userid });
 
         # check to see if it has been altered
-        if ($user->login ne $old_email) {
-            $user->set_login($old_email);
+        if ($user->email ne $old_email) {
+            $user->set_email($old_email);
             $user->update({ keep_tokens => 1 });
 
             $vars->{'message'} = "email_change_canceled_reinstated";
@@ -285,13 +285,20 @@ sub cancelChangeEmail {
 }
 
 sub request_create_account {
-    my ($date, $login_name, $token) = @_;
+    my ($date, $data, $token) = @_;
 
     Bugzilla->user->check_account_creation_enabled;
 
-    $vars->{'token'} = $token;
-    $vars->{'email'} = $login_name . Bugzilla->params->{'emailsuffix'};
-    $vars->{'expiration_ts'} = ctime(str2time($date) + MAX_TOKEN_AGE * 86400);
+    # Be careful! Some logins may contain ":" in them.
+    my ($email, $login) = split(':', $data, 2);
+    $vars = {
+      token => $token,
+      login => $login,
+      email => $email,
+      # Make sure nobody else chose this login meanwhile.
+      login_already_in_use => login_to_id($login) ? 1 : 0,
+      expiration_ts => ctime(str2time($date) + MAX_TOKEN_AGE * 86400)
+    };
 
     print $cgi->header();
     $template->process('account/email/confirm-new.html.tmpl', $vars)
@@ -299,7 +306,7 @@ sub request_create_account {
 }
 
 sub confirm_create_account {
-    my ($login_name, $token) = @_;
+    my ($data, $token) = @_;
 
     Bugzilla->user->check_account_creation_enabled;
 
@@ -308,8 +315,13 @@ sub confirm_create_account {
     # Make sure that these never show up anywhere in the UI.
     $cgi->delete('passwd1', 'passwd2');
 
+    # Be careful! Some logins may contain ":" in them.
+    my ($email, $login) = split(':', $data, 2);
+    $login = $cgi->param('login') if login_to_id($login);
+
     my $otheruser = Bugzilla::User->create({
-        login_name => $login_name, 
+        login_name => $login,
+        email      => $email,
         realname   => scalar $cgi->param('realname'),
         cryptpassword => $password});
 
@@ -332,10 +344,11 @@ sub confirm_create_account {
 }
 
 sub cancel_create_account {
-    my ($login_name, $token) = @_;
+    my ($data, $token) = @_;
 
     $vars->{'message'} = 'account_creation_canceled';
-    $vars->{'account'} = $login_name;
+    # Be careful! Some logins may contain ":" in them.
+    ($vars->{'email'}, $vars->{'login'}) = split(':', $data, 2);
     Bugzilla::Token::Cancel($token, $vars->{'message'});
 
     print $cgi->header();
index c94c63f5f76ae445c22498003200cc6e87ed3714..54cad3c5156d140b1d3d6b6987ff48866ef1aaff 100755 (executable)
@@ -37,8 +37,6 @@ sub DoAccount {
     my $dbh = Bugzilla->dbh;
     my $user = Bugzilla->user;
 
-    $vars->{'realname'} = $user->name;
-
     if (Bugzilla->params->{'allowemailchange'}
         && $user->authorizer->can_change_email)
     {
@@ -55,11 +53,11 @@ sub DoAccount {
            ORDER BY tokentype ASC " . $dbh->sql_limit(1), undef, $user->id);
         if (scalar(@token) > 0) {
             my ($tokentype, $change_date, $eventdata) = @token;
-            $vars->{'login_change_date'} = $change_date;
+            $vars->{'email_change_date'} = $change_date;
 
             if($tokentype eq 'emailnew') {
                 my ($oldemail,$newemail) = split(/:/,$eventdata);
-                $vars->{'new_login_name'} = $newemail;
+                $vars->{'new_email'} = $newemail;
             }
         }
     }
@@ -77,7 +75,8 @@ sub SaveAccount {
     my $verified_password;
     my $pwd1 = $cgi->param('new_password1');
     my $pwd2 = $cgi->param('new_password2');
-    my $new_login_name = trim(scalar $cgi->param('new_login_name'));
+    my $new_login = clean_text(scalar $cgi->param('new_login'));
+    my $new_email = clean_text(scalar $cgi->param('new_email'));
 
     if ($user->authorizer->can_change_password
         && ($pwd1 ne "" || $pwd2 ne ""))
@@ -95,28 +94,47 @@ sub SaveAccount {
         }
     }
 
+    # This is used only if email and login are separate
+    if ($user->authorizer->can_change_login
+        && !Bugzilla->params->{"use_email_as_login"}
+        && $new_login
+        && $user->login ne $new_login)
+    {
+        $verified_password || $user->check_current_password($oldpassword);
+
+        if ($new_login =~ /@/ &&
+            $new_login ne $user->email)
+        {
+            ThrowUserError("login_at_sign_disallowed");
+        }
+
+        if (Bugzilla::Token::HasEmailChangeToken($user->id)) {
+            ThrowUserError("login_change_during_email_change");
+        }
+
+        $user->set_login($new_login);
+    }
+
+    # This is used for the single value if use_email_as_login is true, or for
+    # the email address otherwise.
     if ($user->authorizer->can_change_email
         && Bugzilla->params->{"allowemailchange"}
-        && $new_login_name)
+        && $new_email
+        && $user->email ne $new_email)
     {
-        if ($user->login ne $new_login_name) {
-            $verified_password || $user->check_current_password($oldpassword);
+        $verified_password || $user->check_current_password($oldpassword);
 
-            # Block multiple email changes for the same user.
-            if (Bugzilla::Token::HasEmailChangeToken($user->id)) {
-                ThrowUserError("email_change_in_progress");
-            }
+        # Block multiple email changes for the same user.
+        if (Bugzilla::Token::HasEmailChangeToken($user->id)) {
+            ThrowUserError("email_change_in_progress");
+        }
 
-            # Before changing an email address, confirm one does not exist.
-            check_email_syntax($new_login_name);
-            is_available_username($new_login_name)
-              || ThrowUserError("account_exists", {email => $new_login_name});
+        # Before changing to an email address, confirm it does not exist.
+        $user->check_email($new_email);
 
-            $vars->{'email_token'} = Bugzilla::Token::IssueEmailChangeToken($new_login_name);
-            $vars->{'email_changes_saved'} = 1;
-        }
+        $vars->{'email_token'} = Bugzilla::Token::IssueEmailChangeToken($new_email);
+        $vars->{'email_changes_saved'} = 1;
     }
-
     $user->set_name(scalar $cgi->param('realname'));
     $user->update({ keep_session => 1, keep_tokens => 1 });
     $dbh->bz_commit_transaction;
index 660cc617ff9739988723eac1f08eff3b3be60e21..2113bb819bea4e20a71bbdbb44359b449c136348 100755 (executable)
@@ -47,28 +47,28 @@ my $slt_bugs = $dbh->selectall_arrayref($query, undef, 'CONFIRMED', 'NEW',
                                                        'REOPENED');
 
 foreach my $bug (@$slt_bugs) {
-    my ($id, $desc, $email) = @$bug;
-    if (!defined $bugs{$email}) {
-        $bugs{$email} = [];
+    my ($id, $desc, $login) = @$bug;
+    if (!defined $bugs{$login}) {
+        $bugs{$login} = [];
     }
-    if (!defined $desc{$email}) {
-        $desc{$email} = [];
+    if (!defined $desc{$login}) {
+        $desc{$login} = [];
     }
-    push @{$bugs{$email}}, $id;
-    push @{$desc{$email}}, $desc;
+    push @{$bugs{$login}}, $id;
+    push @{$desc{$login}}, $desc;
 }
 
 
-foreach my $email (sort (keys %bugs)) {
-    my $user = new Bugzilla::User({name => $email});
+foreach my $login (sort (keys %bugs)) {
+    my $user = new Bugzilla::User({name => $login});
     next if $user->email_disabled;
 
-    my $vars = {'email' => $email};
+    my $vars = {'email' => $user->email};
 
     my @bugs = ();
-    foreach my $i (@{$bugs{$email}}) {
+    foreach my $i (@{$bugs{$login}}) {
         my $bug = {};
-        $bug->{'summary'} = shift(@{$desc{$email}});
+        $bug->{'summary'} = shift(@{$desc{$login}});
         $bug->{'id'} = $i;
         push @bugs, $bug;
     }
@@ -81,5 +81,5 @@ foreach my $email (sort (keys %bugs)) {
 
     MessageToMTA($msg);
 
-    say "$email      " . join(" ", @{$bugs{$email}});
+    say $user->email . "      " . join(" ", @{$bugs{$login}});
 }
index 0e75e6b9dc08624d64ad62fa323a20ccf0b6133d..fe6159b2ce50c6285787d4aef1154a261efc8ca6 100644 (file)
@@ -20,8 +20,7 @@ my ($sel, $config) = get_selenium();
 log_in($sel, $config, 'admin');
 
 set_parameters($sel, {"Administrative Policies" => {"allowuserdeletion-on" => undef},
-                      "User Authentication"     => {"createemailregexp" => {type => "text", value => '.*'},
-                                                    "emailsuffix" => {type => "text", value => ''}} });
+                      "User Authentication"     => {"createemailregexp" => {type => "text", value => '.*'}} });
 
 # Set the password complexity to MIXED LETTERS.
 # Password must contain at least one UPPER and one lowercase letter.