From 5b19a7d87f3f77e971e5859e7886d1320c5d34f3 Mon Sep 17 00:00:00 2001 From: topunix Date: Sat, 15 Mar 2025 16:41:51 -0400 Subject: [PATCH 001/113] Adding test change --- template/en/default/account/prefs/account.html.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/en/default/account/prefs/account.html.tmpl b/template/en/default/account/prefs/account.html.tmpl index 43536d6c70..f6b0ddff8e 100644 --- a/template/en/default/account/prefs/account.html.tmpl +++ b/template/en/default/account/prefs/account.html.tmpl @@ -31,7 +31,7 @@
- +
Your real name:Your real namex: From 9126b9341b41f228870900edf945116e7822f54e Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 2 Apr 2025 17:37:50 -0400 Subject: [PATCH 002/113] Adding new auth, and new_login to Account page --- Bugzilla/Auth.pm | 12 +++++ .../default/account/prefs/account.html.tmpl | 47 +++++-------------- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/Bugzilla/Auth.pm b/Bugzilla/Auth.pm index e76f59843a..d2bbac3cdc 100644 --- a/Bugzilla/Auth.pm +++ b/Bugzilla/Auth.pm @@ -182,6 +182,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; } @@ -474,6 +478,14 @@ Returns: C if users are allowed to create new Bugzilla accounts, Description: Whether or not current login system uses extern_id. +=item C + +Description: Whether or not the current login system allows users to + change their own login. +Params: None +Returns: C if users can change their own login, + C otherwise. + =item C Description: Whether or not the current login system allows users to diff --git a/template/en/default/account/prefs/account.html.tmpl b/template/en/default/account/prefs/account.html.tmpl index f6b0ddff8e..9ab60bf586 100644 --- a/template/en/default/account/prefs/account.html.tmpl +++ b/template/en/default/account/prefs/account.html.tmpl @@ -31,12 +31,22 @@
- + + + + + [%# BMO - moved field hook from end of file to here to group with other account fields %] [% Hook.process('field') %] @@ -57,43 +67,10 @@ - [% IF user.authorizer.can_change_email && Param('allowemailchange') %] - [% IF login_change_date %] - [% IF new_login_name %] - - - - - - - - - [% ELSE %] - - - - - - - - - [% END %] - [% ELSE %] - - - - - [% END %] - [% END %] - + [%# this section is shared by both the needinfo and review extensions %] + [%# only show the label once %] + [% IF request_blocked_header %] + + [% ELSE %] + [% request_blocked_header = 1 %] + + [% END %] + + From c785e57a53cd123911c61d1a5ecfcf331149a432 Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 10 Apr 2025 14:39:39 -0400 Subject: [PATCH 014/113] Adding hook file for email tab --- .../hook/account/prefs/email-field.html.tmpl | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 extensions/Needinfo/template/en/default/hook/account/prefs/email-field.html.tmpl diff --git a/extensions/Needinfo/template/en/default/hook/account/prefs/email-field.html.tmpl b/extensions/Needinfo/template/en/default/hook/account/prefs/email-field.html.tmpl new file mode 100644 index 0000000000..7b8eeacc8e --- /dev/null +++ b/extensions/Needinfo/template/en/default/hook/account/prefs/email-field.html.tmpl @@ -0,0 +1,25 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + + + [%# this section is shared by both the needinfo and review extensions %] + [%# only show the label once %] + [% IF request_blocked_header %] + + [% ELSE %] + [% request_blocked_header = 1 %] + + [% END %] + + From de4807e2c6d11b47006242a865d4521439989633 Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 13 Apr 2025 13:07:26 -0400 Subject: [PATCH 015/113] Removing account-field --- .../account/prefs/account-field.html.tmpl | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 extensions/Review/template/en/default/hook/account/prefs/account-field.html.tmpl diff --git a/extensions/Review/template/en/default/hook/account/prefs/account-field.html.tmpl b/extensions/Review/template/en/default/hook/account/prefs/account-field.html.tmpl deleted file mode 100644 index baf3a6b942..0000000000 --- a/extensions/Review/template/en/default/hook/account/prefs/account-field.html.tmpl +++ /dev/null @@ -1,26 +0,0 @@ -[%# This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - # - # This Source Code Form is "Incompatible With Secondary Licenses", as - # defined by the Mozilla Public License, v. 2.0. - #%] - - - [%# this section is shared by both the needinfo and review extensions %] - [%# only show the label once %] - [% IF request_blocked_header %] - - [% ELSE %] - [% request_blocked_header = 1 %] - - [% END %] - - From 24f728384a6f33eefcbc001dfb089e6b86799884 Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 13 Apr 2025 13:08:21 -0400 Subject: [PATCH 016/113] Removing account-field --- .../account/prefs/account-field.html.tmpl | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 extensions/Needinfo/template/en/default/hook/account/prefs/account-field.html.tmpl diff --git a/extensions/Needinfo/template/en/default/hook/account/prefs/account-field.html.tmpl b/extensions/Needinfo/template/en/default/hook/account/prefs/account-field.html.tmpl deleted file mode 100644 index 7b8eeacc8e..0000000000 --- a/extensions/Needinfo/template/en/default/hook/account/prefs/account-field.html.tmpl +++ /dev/null @@ -1,25 +0,0 @@ -[%# This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - # - # This Source Code Form is "Incompatible With Secondary Licenses", as - # defined by the Mozilla Public License, v. 2.0. - #%] - - - [%# this section is shared by both the needinfo and review extensions %] - [%# only show the label once %] - [% IF request_blocked_header %] - - [% ELSE %] - [% request_blocked_header = 1 %] - - [% END %] - - From 5e529413b4e1c387820098dda02943195d786aab Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 14 Apr 2025 13:22:57 -0400 Subject: [PATCH 017/113] Rename email-field file to account-field, reversing change --- .../account/prefs/account-field.html.tmpl | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 extensions/Needinfo/template/en/default/hook/account/prefs/account-field.html.tmpl diff --git a/extensions/Needinfo/template/en/default/hook/account/prefs/account-field.html.tmpl b/extensions/Needinfo/template/en/default/hook/account/prefs/account-field.html.tmpl new file mode 100644 index 0000000000..7b8eeacc8e --- /dev/null +++ b/extensions/Needinfo/template/en/default/hook/account/prefs/account-field.html.tmpl @@ -0,0 +1,25 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + + + [%# this section is shared by both the needinfo and review extensions %] + [%# only show the label once %] + [% IF request_blocked_header %] + + [% ELSE %] + [% request_blocked_header = 1 %] + + [% END %] + + From 67674b8319e890e87a847e21f5616201c2907f33 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 14 Apr 2025 13:25:36 -0400 Subject: [PATCH 018/113] Removing email-field.html.tmpl, reversing change --- .../hook/account/prefs/email-field.html.tmpl | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 extensions/Needinfo/template/en/default/hook/account/prefs/email-field.html.tmpl diff --git a/extensions/Needinfo/template/en/default/hook/account/prefs/email-field.html.tmpl b/extensions/Needinfo/template/en/default/hook/account/prefs/email-field.html.tmpl deleted file mode 100644 index 7b8eeacc8e..0000000000 --- a/extensions/Needinfo/template/en/default/hook/account/prefs/email-field.html.tmpl +++ /dev/null @@ -1,25 +0,0 @@ -[%# This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - # - # This Source Code Form is "Incompatible With Secondary Licenses", as - # defined by the Mozilla Public License, v. 2.0. - #%] - - - [%# this section is shared by both the needinfo and review extensions %] - [%# only show the label once %] - [% IF request_blocked_header %] - - [% ELSE %] - [% request_blocked_header = 1 %] - - [% END %] - - From a4be2f2b7c2c363cee5b8b4017d9e060a3edc819 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 14 Apr 2025 13:44:52 -0400 Subject: [PATCH 019/113] Rename email-field file to account-field, reversing change --- .../account/prefs/account-field.html.tmpl | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 extensions/Review/template/en/default/hook/account/prefs/account-field.html.tmpl diff --git a/extensions/Review/template/en/default/hook/account/prefs/account-field.html.tmpl b/extensions/Review/template/en/default/hook/account/prefs/account-field.html.tmpl new file mode 100644 index 0000000000..baf3a6b942 --- /dev/null +++ b/extensions/Review/template/en/default/hook/account/prefs/account-field.html.tmpl @@ -0,0 +1,26 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + + + [%# this section is shared by both the needinfo and review extensions %] + [%# only show the label once %] + [% IF request_blocked_header %] + + [% ELSE %] + [% request_blocked_header = 1 %] + + [% END %] + + From 574d95ba10193edc089afff94930273df23526f3 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 14 Apr 2025 13:45:38 -0400 Subject: [PATCH 020/113] Removing email-field.html.tmpl, reversing change --- .../hook/account/prefs/email-field.html.tmpl | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 extensions/Review/template/en/default/hook/account/prefs/email-field.html.tmpl diff --git a/extensions/Review/template/en/default/hook/account/prefs/email-field.html.tmpl b/extensions/Review/template/en/default/hook/account/prefs/email-field.html.tmpl deleted file mode 100644 index baf3a6b942..0000000000 --- a/extensions/Review/template/en/default/hook/account/prefs/email-field.html.tmpl +++ /dev/null @@ -1,26 +0,0 @@ -[%# This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - # - # This Source Code Form is "Incompatible With Secondary Licenses", as - # defined by the Mozilla Public License, v. 2.0. - #%] - - - [%# this section is shared by both the needinfo and review extensions %] - [%# only show the label once %] - [% IF request_blocked_header %] - - [% ELSE %] - [% request_blocked_header = 1 %] - - [% END %] - - From d92a37a69c14c66ef6a5c90aff98f80577da63b0 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 14 Apr 2025 13:48:59 -0400 Subject: [PATCH 021/113] Reversed tab check to account --- extensions/Review/Extension.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/Review/Extension.pm b/extensions/Review/Extension.pm index 2443280b08..45ee8b0cb3 100644 --- a/extensions/Review/Extension.pm +++ b/extensions/Review/Extension.pm @@ -708,7 +708,7 @@ sub webservice { sub user_preferences { my ($self, $args) = @_; - return unless $args->{current_tab} eq 'email' && $args->{save_changes}; + return unless $args->{current_tab} eq 'account' && $args->{save_changes}; my $input = Bugzilla->input_params; my $settings = Bugzilla->user->settings; From bb4399f0acd60afe3c4350c9bd8ac9565e4adc55 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 14 Apr 2025 13:49:30 -0400 Subject: [PATCH 022/113] Reversed tab check to account --- extensions/Needinfo/Extension.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/Needinfo/Extension.pm b/extensions/Needinfo/Extension.pm index 149a11605f..5bc670584f 100644 --- a/extensions/Needinfo/Extension.pm +++ b/extensions/Needinfo/Extension.pm @@ -285,7 +285,7 @@ sub object_before_delete { sub user_preferences { my ($self, $args) = @_; - return unless $args->{current_tab} eq 'email' && $args->{save_changes}; + return unless $args->{current_tab} eq 'account' && $args->{save_changes}; my $input = Bugzilla->input_params; my $settings = Bugzilla->user->settings; From edf8b6df84780134b4f47063382da6c3b7739ab0 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 14 Apr 2025 14:34:51 -0400 Subject: [PATCH 023/113] Returning email address field --- .../default/account/prefs/account.html.tmpl | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/template/en/default/account/prefs/account.html.tmpl b/template/en/default/account/prefs/account.html.tmpl index 9ab60bf586..d58a65b0f3 100644 --- a/template/en/default/account/prefs/account.html.tmpl +++ b/template/en/default/account/prefs/account.html.tmpl @@ -60,6 +60,39 @@ [% END %] [% IF can_change.size %] + + [% IF user.authorizer.can_change_email && Param('allowemailchange') %] + [% IF login_change_date %] + [% IF new_login_name %] + + + + + + + + + [% ELSE %] + + + + + + + + + [% END %] + [% ELSE %] + + + + + [% END %] + [% END %] + From 6b1e0647f029f01424e85ddd612384e87fe7a07b Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 14 Apr 2025 16:30:31 -0400 Subject: [PATCH 024/113] Revert changes to userprefs.cgi from 4205bd7d00c61ef7a9bbf7aec0a8a198af98a8bb --- userprefs.cgi | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/userprefs.cgi b/userprefs.cgi index b795f959ab..30e5a3a031 100755 --- a/userprefs.cgi +++ b/userprefs.cgi @@ -135,10 +135,42 @@ sub SaveAccount { if (Bugzilla::Token::HasEmailChangeToken($user->id)) { ThrowUserError("login_change_during_email_change"); } - + $user->set_login($new_login); } + if ( $user->authorizer->can_change_email + && Bugzilla->params->{"allowemailchange"} + && $new_login_name) + { + if ($user->login ne $new_login_name) { + $oldpassword || ThrowUserError("old_password_required"); + + # 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. + validate_email_syntax($new_login_name) + || ThrowUserError('illegal_email_address', {addr => $new_login_name}); + is_available_username($new_login_name) + || ThrowUserError("account_exists", {email => $new_login_name}); + + if ($user->mfa) { + push @mfa_events, + { + type => 'set_login', + reason => 'changing your email address', + login => $new_login_name, + }; + } + else { + Bugzilla::Token::IssueEmailChangeToken($user, $new_login_name); + $vars->{email_changes_saved} = 1; + } + } + } $user->set_name($cgi->param('realname')); $user->update({keep_session => 1, keep_tokens => 1}); From 0ccb69d1876fe79fc9be4b655a22fad714938f74 Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 16 Apr 2025 17:12:54 -0400 Subject: [PATCH 025/113] Adding secondary email placeholder --- template/en/default/account/prefs/account.html.tmpl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/template/en/default/account/prefs/account.html.tmpl b/template/en/default/account/prefs/account.html.tmpl index d58a65b0f3..99c04218c1 100644 --- a/template/en/default/account/prefs/account.html.tmpl +++ b/template/en/default/account/prefs/account.html.tmpl @@ -65,7 +65,7 @@ [% IF login_change_date %] [% IF new_login_name %] - + @@ -74,7 +74,7 @@ [% ELSE %] - + @@ -91,6 +91,13 @@ [% END %] + + + + [% END %] From 03a91d621634f9bea48df05ebbe1e9b6c5eb23d0 Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 16 Apr 2025 18:18:50 -0400 Subject: [PATCH 026/113] Adding profiles_emails table --- Bugzilla/DB/Schema.pm | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm index a11b9639ac..b2a627460d 100644 --- a/Bugzilla/DB/Schema.pm +++ b/Bugzilla/DB/Schema.pm @@ -1016,6 +1016,24 @@ use constant ABSTRACT_SCHEMA => { ], }, + profiles_emails => { + FIELDS => [ + id => {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1}, + user_id => { + TYPE => 'INT3', + NOTNULL => 1, + REFERENCES => {TABLE => 'profiles', COLUMN => 'userid', DELETE => 'CASCADE'} + }, + email => {TYPE => 'varchar(255)', NOTNULL => 1}, + is_primary => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, + last_modified => {TYPE => 'DATETIME', NOTNULL => 1}, + ], + INDEXES => [ + profiles_emails_userid_idx => ['user_id'], + profiles_emails_email_idx => {FIELDS => ['email'], TYPE => 'UNIQUE'}, + ], + }, + profile_mfa => { FIELDS => [ id => {TYPE => 'INTSERIAL', NOTNULL => 1, PRIMARYKEY => 1}, From 8676091e6443524118c864b395175d4c20beb4c9 Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 18 Apr 2025 15:28:12 -0400 Subject: [PATCH 027/113] Change column name --- Bugzilla/DB/Schema.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm index b2a627460d..d638ff5588 100644 --- a/Bugzilla/DB/Schema.pm +++ b/Bugzilla/DB/Schema.pm @@ -1024,9 +1024,9 @@ use constant ABSTRACT_SCHEMA => { NOTNULL => 1, REFERENCES => {TABLE => 'profiles', COLUMN => 'userid', DELETE => 'CASCADE'} }, - email => {TYPE => 'varchar(255)', NOTNULL => 1}, - is_primary => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, - last_modified => {TYPE => 'DATETIME', NOTNULL => 1}, + email => {TYPE => 'varchar(255)', NOTNULL => 1}, + is_primary_email => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, + last_modified => {TYPE => 'DATETIME', NOTNULL => 1}, ], INDEXES => [ profiles_emails_userid_idx => ['user_id'], From d3fded145287d1b629f5a38dd70e78c7d0cc60e2 Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 20 Apr 2025 13:53:29 -0400 Subject: [PATCH 028/113] Added new column --- Bugzilla/DB/Schema.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm index d638ff5588..e6c4afc66f 100644 --- a/Bugzilla/DB/Schema.pm +++ b/Bugzilla/DB/Schema.pm @@ -1026,6 +1026,7 @@ use constant ABSTRACT_SCHEMA => { }, email => {TYPE => 'varchar(255)', NOTNULL => 1}, is_primary_email => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, + notify => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, last_modified => {TYPE => 'DATETIME', NOTNULL => 1}, ], INDEXES => [ From e49fe87f585ff3ca40df6857aa5f7d9b8ac9486f Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 20 Apr 2025 14:38:25 -0400 Subject: [PATCH 029/113] Adding more test fields for emails --- template/en/default/account/prefs/account.html.tmpl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/template/en/default/account/prefs/account.html.tmpl b/template/en/default/account/prefs/account.html.tmpl index 99c04218c1..f4bbf0a3d7 100644 --- a/template/en/default/account/prefs/account.html.tmpl +++ b/template/en/default/account/prefs/account.html.tmpl @@ -86,7 +86,9 @@ @@ -95,6 +97,8 @@ From 40df3f205a1f47860811a23e07f8c8b2810147a7 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 21 Apr 2025 14:38:27 -0400 Subject: [PATCH 030/113] Added login name to answers --- conf/checksetup_answers.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/checksetup_answers.txt b/conf/checksetup_answers.txt index 2c8e7e6b7c..e2bbc716d7 100644 --- a/conf/checksetup_answers.txt +++ b/conf/checksetup_answers.txt @@ -1,3 +1,4 @@ +$answer{'ADMIN_LOGIN_NAME'} = 'admin_bmo_test'; $answer{'ADMIN_EMAIL'} = 'admin@bmo.test'; $answer{'ADMIN_OK'} = 'Y'; $answer{'ADMIN_PASSWORD'} = 'password01!'; From 3bc163b4bc82c7871f45aabcc422c80c901cc0e4 Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 23 Apr 2025 14:05:20 -0400 Subject: [PATCH 031/113] Adding Bugzilla::User::Email --- Bugzilla/User/Email.pm | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Bugzilla/User/Email.pm diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm new file mode 100644 index 0000000000..13270d8ec8 --- /dev/null +++ b/Bugzilla/User/Email.pm @@ -0,0 +1,35 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::User::Email; + +use 5.10.1; +use strict; +use warnings; + +use base qw(Bugzilla::Object); + +use Bugzilla::Constants; + +############# +# Constants # +############# + +use constant DB_TABLE => 'profiles_emails'; + + +sub create { + my ($class, $params) = @_; + my $user_email = $class->SUPER::create($params); + + + # Return the newly created user email account. + return $user_email; +} +1; + +__END__ From 26c7dda66878d4e7c1fd3027489ebb0e3e34d41c Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 23 Apr 2025 15:08:46 -0400 Subject: [PATCH 032/113] Adding creation of email account to Bugzilla::User::create() --- Bugzilla/User.pm | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index 5f5184ee8e..b338b847a7 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -16,6 +16,7 @@ use Bugzilla::Util; use Bugzilla::Constants; use Bugzilla::Search::Recent; use Bugzilla::User::Setting; +use Bugzilla::User::Email; use Bugzilla::Product; use Bugzilla::Classification; use Bugzilla::Field; @@ -23,6 +24,7 @@ use Bugzilla::Group; use Bugzilla::Hook; use Bugzilla::BugUserLastVisit; + use DateTime::TimeZone; use List::Util qw(max); use List::MoreUtils qw(any); @@ -2587,6 +2589,17 @@ sub create { = _generate_nickname($params->{realname}, $params->{login_name}, 0); my $user = $class->SUPER::create($params); + # Create a user email account + my $email_data = { + user_id => $user->id, + email => $params->{admin_email}, + is_primary_email => 1, + notify => 1, + last_modified => Bugzilla::Util::DateTime::now(), + }; + + my $user_email = Bugzilla::User::Email->create($email_data); + # Turn on all email for the new user require Bugzilla::BugMail; my %relationships = Bugzilla::BugMail::relationships(); From 3256359b83211e78ee016fe0e271e30e4d88419f Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 25 Apr 2025 18:23:44 -0400 Subject: [PATCH 033/113] Removed unneeded columns --- Bugzilla/DB/Schema.pm | 2 -- 1 file changed, 2 deletions(-) diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm index e6c4afc66f..9880484aed 100644 --- a/Bugzilla/DB/Schema.pm +++ b/Bugzilla/DB/Schema.pm @@ -1026,8 +1026,6 @@ use constant ABSTRACT_SCHEMA => { }, email => {TYPE => 'varchar(255)', NOTNULL => 1}, is_primary_email => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, - notify => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, - last_modified => {TYPE => 'DATETIME', NOTNULL => 1}, ], INDEXES => [ profiles_emails_userid_idx => ['user_id'], From ca84658e31099b0cfe9a2217505996e499c1e991 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 28 Apr 2025 16:33:09 -0400 Subject: [PATCH 034/113] Added validators and columns --- Bugzilla/User/Email.pm | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index 13270d8ec8..cdf09b3c23 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -22,14 +22,39 @@ use Bugzilla::Constants; use constant DB_TABLE => 'profiles_emails'; +use constant DB_COLUMNS => qw( + profiles_emails.id + profiles_emails.user_id + profiles_emails.email + profiles_emails.is_primary_email +); + + +use constant VALIDATORS => { + user_id => \&_check_user_id, + email => \&_check_email, + is_primary_email => \&Bugzilla::Object::check_boolean, +}; + + sub create { my ($class, $params) = @_; my $user_email = $class->SUPER::create($params); - # Return the newly created user email account. return $user_email; } + +############################### +### Validators ### +############################### + +sub _check_user_id { +return 1; +} +sub _check_email { +return 1; +} 1; __END__ From 0b8dadd4dda074d35717320b0d8cd824d9e34891 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 28 Apr 2025 17:13:30 -0400 Subject: [PATCH 035/113] Adding email widget --- .../default/account/prefs/account.html.tmpl | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/template/en/default/account/prefs/account.html.tmpl b/template/en/default/account/prefs/account.html.tmpl index f4bbf0a3d7..ce24938b85 100644 --- a/template/en/default/account/prefs/account.html.tmpl +++ b/template/en/default/account/prefs/account.html.tmpl @@ -24,6 +24,22 @@ # new_login_name: string. The user's new Bugzilla login whilst not confirmed. (optional) #%] + + + [%# BMO - add hook for displaying user-profile link %] [% Hook.process('start') %] @@ -84,24 +100,16 @@ [% END %] [% ELSE %] - + [% END %] - - - - [% END %] From ba60296080057b490d0469cf7de38680135f0eb0 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 28 Apr 2025 19:45:12 -0400 Subject: [PATCH 036/113] Enhanced email widget --- .../default/account/prefs/account.html.tmpl | 100 +++++++++++++++--- 1 file changed, 88 insertions(+), 12 deletions(-) diff --git a/template/en/default/account/prefs/account.html.tmpl b/template/en/default/account/prefs/account.html.tmpl index ce24938b85..accb1d5747 100644 --- a/template/en/default/account/prefs/account.html.tmpl +++ b/template/en/default/account/prefs/account.html.tmpl @@ -23,19 +23,93 @@ # 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) #%] - + @@ -102,10 +176,12 @@ function addEmailField() { From 24c1366b68602d82f11cbb4f860cd742b356f228 Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 30 Apr 2025 18:13:45 -0400 Subject: [PATCH 037/113] Added mutators, accessors, update, and check_user_id validator --- Bugzilla/User/Email.pm | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index cdf09b3c23..eef83768e7 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -36,6 +36,11 @@ use constant VALIDATORS => { is_primary_email => \&Bugzilla::Object::check_boolean, }; +use constant UPDATE_COLUMNS => qw(email is_primary_email); + +# There's no gain to caching these objects +use constant USE_MEMCACHED => 0; + sub create { my ($class, $params) = @_; @@ -45,12 +50,37 @@ sub create { return $user_email; } +sub update { + my ($class, $params) = @_; + my $updated_email = $class->SUPER::update($params); + + # Return the updated user email account. + return $updated_email; +} + + +############################### +#### Accessors ###### +############################### + +sub email { return $_[0]->{email}; } +sub user_id { return $_[0]->{'user_id'}; } + +############ +# Mutators # +############ + +sub set_email { $_[0]->set('email', $_[1]); } +sub set_primary_email { $_[0]->set('is_primary_email', $_[1]); } + ############################### ### Validators ### ############################### sub _check_user_id { -return 1; + my ($invocant, $id) = @_; + require Bugzilla::User; + return Bugzilla::User->check({id => $id})->id; } sub _check_email { return 1; From f54b3cf7c5bba115473104b05318f54e7cbbe136 Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 30 Apr 2025 18:26:59 -0400 Subject: [PATCH 038/113] Added check email validator --- Bugzilla/User/Email.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index eef83768e7..8ca49ca8f5 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -14,6 +14,7 @@ use warnings; use base qw(Bugzilla::Object); use Bugzilla::Constants; +use Bugzilla::Util; ############# # Constants # @@ -82,9 +83,8 @@ sub _check_user_id { require Bugzilla::User; return Bugzilla::User->check({id => $id})->id; } -sub _check_email { -return 1; -} + +sub _check_email { return validate_email_syntax($_[1]); } 1; __END__ From 884c21f899318e552a448968e460f86d4187a0dc Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 30 Apr 2025 19:04:33 -0400 Subject: [PATCH 039/113] Added remove_from_db --- Bugzilla/User/Email.pm | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index 8ca49ca8f5..b7d1d6ad4a 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -42,6 +42,24 @@ use constant UPDATE_COLUMNS => qw(email is_primary_email); # There's no gain to caching these objects use constant USE_MEMCACHED => 0; +############################### +#### Accessors ###### +############################### + +sub email { return $_[0]->{email}; } +sub user_id { return $_[0]->{'user_id'}; } +sub is_primary_email { return $_[0]->{'is_primary_email'}; } + +############ +# Mutators # +############ + +sub set_email { $_[0]->set('email', $_[1]); } +sub set_primary_email { $_[0]->set('is_primary_email', $_[1]); } + +############################### +#### Constructors ##### +############################### sub create { my ($class, $params) = @_; @@ -59,20 +77,10 @@ sub update { return $updated_email; } - -############################### -#### Accessors ###### -############################### - -sub email { return $_[0]->{email}; } -sub user_id { return $_[0]->{'user_id'}; } - -############ -# Mutators # -############ - -sub set_email { $_[0]->set('email', $_[1]); } -sub set_primary_email { $_[0]->set('is_primary_email', $_[1]); } +sub remove_from_db { + my $self = shift; + return is_primary_email($self) ? 0 : $self->SUPER::remove_from_db(); +} ############################### ### Validators ### From 503010fcc4a9a81740af4b50686061bc63828e95 Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 30 Apr 2025 19:49:48 -0400 Subject: [PATCH 040/113] Updated button styling --- template/en/default/account/prefs/account.html.tmpl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/template/en/default/account/prefs/account.html.tmpl b/template/en/default/account/prefs/account.html.tmpl index accb1d5747..c587781eb5 100644 --- a/template/en/default/account/prefs/account.html.tmpl +++ b/template/en/default/account/prefs/account.html.tmpl @@ -41,10 +41,12 @@ padding: 4px 8px; cursor: pointer; font-size: 0.9em; + font-weight: bold; border-radius: 4px; } .delete-btn:hover { background: #ff1a1a; + color: white; } .fade-out { opacity: 0; From 3d53c2508f86b80f1972541d94167a51a8d0d446 Mon Sep 17 00:00:00 2001 From: topunix Date: Sat, 3 May 2025 20:41:06 -0400 Subject: [PATCH 041/113] Adding display_order column --- Bugzilla/DB/Schema.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm index 9880484aed..56c1639df3 100644 --- a/Bugzilla/DB/Schema.pm +++ b/Bugzilla/DB/Schema.pm @@ -1026,6 +1026,7 @@ use constant ABSTRACT_SCHEMA => { }, email => {TYPE => 'varchar(255)', NOTNULL => 1}, is_primary_email => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, + display_order => {TYPE => 'INT1', NOTNULL => 1, DEFAULT => 1}, ], INDEXES => [ profiles_emails_userid_idx => ['user_id'], From 35ddd0517a2ea726cbed51f3f85691ae2a014eaf Mon Sep 17 00:00:00 2001 From: topunix Date: Sat, 3 May 2025 21:52:37 -0400 Subject: [PATCH 042/113] Added get_user_emails subroutine --- Bugzilla/User/Email.pm | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index b7d1d6ad4a..ff30b29fed 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -22,7 +22,6 @@ use Bugzilla::Util; use constant DB_TABLE => 'profiles_emails'; - use constant DB_COLUMNS => qw( profiles_emails.id profiles_emails.user_id @@ -30,7 +29,6 @@ use constant DB_COLUMNS => qw( profiles_emails.is_primary_email ); - use constant VALIDATORS => { user_id => \&_check_user_id, email => \&_check_email, @@ -77,6 +75,14 @@ sub update { return $updated_email; } +sub get_user_emails { + my ($user_id) = @_; + my $dbh = Bugzilla->dbh; + my $emails_ref = $dbh->selectall_arrayref("SELECT email, is_primary_email, display_order FROM profiles_emails WHERE user_id = ?", + undef, $user_id); + return $emails_ref || []; +} + sub remove_from_db { my $self = shift; return is_primary_email($self) ? 0 : $self->SUPER::remove_from_db(); From d54ed69f035bbb86b959753a0cd311f4e13f9773 Mon Sep 17 00:00:00 2001 From: topunix Date: Sat, 3 May 2025 22:02:17 -0400 Subject: [PATCH 043/113] added display_order to update_columns --- Bugzilla/User/Email.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index ff30b29fed..3edfffd808 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -35,7 +35,7 @@ use constant VALIDATORS => { is_primary_email => \&Bugzilla::Object::check_boolean, }; -use constant UPDATE_COLUMNS => qw(email is_primary_email); +use constant UPDATE_COLUMNS => qw(email is_primary_email display_order); # There's no gain to caching these objects use constant USE_MEMCACHED => 0; From bb5367488c250beaf787f27a7addfd4a00f50ad9 Mon Sep 17 00:00:00 2001 From: topunix Date: Sat, 3 May 2025 22:32:17 -0400 Subject: [PATCH 044/113] Change to remove_from_db --- Bugzilla/User/Email.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index 3edfffd808..d10943d7a1 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -85,7 +85,7 @@ sub get_user_emails { sub remove_from_db { my $self = shift; - return is_primary_email($self) ? 0 : $self->SUPER::remove_from_db(); + return $self->is_primary_email ? 0 : $self->SUPER::remove_from_db(); } ############################### From 393eb9d6ad5bc0727ff00b024c056aeaa49b73c7 Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 4 May 2025 19:53:40 -0400 Subject: [PATCH 045/113] Added reIndexEmailFields() and inline comments --- .../default/account/prefs/account.html.tmpl | 96 +++++++++++++++++-- 1 file changed, 88 insertions(+), 8 deletions(-) diff --git a/template/en/default/account/prefs/account.html.tmpl b/template/en/default/account/prefs/account.html.tmpl index c587781eb5..92d8857b61 100644 --- a/template/en/default/account/prefs/account.html.tmpl +++ b/template/en/default/account/prefs/account.html.tmpl @@ -55,63 +55,143 @@ From 0bd16d30f768037f9445c8ff376b9a36a06d0c5c Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 4 May 2025 20:07:56 -0400 Subject: [PATCH 046/113] Updated input attributes for primary email --- template/en/default/account/prefs/account.html.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/en/default/account/prefs/account.html.tmpl b/template/en/default/account/prefs/account.html.tmpl index 92d8857b61..6e877f37e3 100644 --- a/template/en/default/account/prefs/account.html.tmpl +++ b/template/en/default/account/prefs/account.html.tmpl @@ -260,7 +260,7 @@ function reIndexEmailFields() { - - - - [%# BMO - moved field hook from end of file to here to group with other account fields %] [% Hook.process('field') %] @@ -232,12 +50,23 @@ function reIndexEmailFields() { [% END %] [% IF can_change.size %] + + + + + + + [% IF user.authorizer.can_change_email && Param('allowemailchange') %] [% IF login_change_date %] [% IF new_login_name %] - + @@ -246,7 +75,7 @@ function reIndexEmailFields() { [% ELSE %] - + @@ -256,31 +85,15 @@ function reIndexEmailFields() { [% END %] [% ELSE %] - + [% END %] [% END %] - - - - - - - - - + + + + [%# BMO - moved field hook from end of file to here to group with other account fields %] [% Hook.process('field') %] @@ -87,7 +96,7 @@ From 1f32d29de7c36bef7c351c1ee9aa3760cfdc17cb Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 12 May 2025 00:55:52 -0400 Subject: [PATCH 067/113] Added new_login_name and new_email --- userprefs.cgi | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/userprefs.cgi b/userprefs.cgi index 30e5a3a031..7ee52c8d14 100755 --- a/userprefs.cgi +++ b/userprefs.cgi @@ -20,6 +20,7 @@ use Bugzilla::Search; use Bugzilla::Util; use Bugzilla::Error; use Bugzilla::User; +use Bugzilla::User::Email; use Bugzilla::User::Setting qw(clear_settings_cache); use Bugzilla::User::Session; use Bugzilla::User::APIKey; @@ -84,8 +85,8 @@ sub SaveAccount { my $oldpassword = $cgi->param('old_password'); my $pwd1 = $cgi->param('new_password1'); my $pwd2 = $cgi->param('new_password2'); - my $new_login = clean_text(scalar $cgi->param('new_login')); my $new_login_name = trim($cgi->param('new_login_name')); + my $new_email = trim($cgi->param('new_email')); my @mfa_events; if ($user->authorizer->can_change_password @@ -123,11 +124,11 @@ sub SaveAccount { } if ($user->authorizer->can_change_login - && $new_login - && $user->login ne $new_login) + && $new_login_name + && $user->login ne $new_login_name) { - if ($new_login =~ /@/) + if ($new_login_name =~ /@/) { ThrowUserError("login_at_sign_disallowed"); } @@ -136,14 +137,14 @@ sub SaveAccount { ThrowUserError("login_change_during_email_change"); } - $user->set_login($new_login); + $user->set_login($new_login_name); } if ( $user->authorizer->can_change_email && Bugzilla->params->{"allowemailchange"} - && $new_login_name) + && $new_email) { - if ($user->login ne $new_login_name) { + if ($user->email ne $new_email) { $oldpassword || ThrowUserError("old_password_required"); # Block multiple email changes for the same user. @@ -151,22 +152,18 @@ sub SaveAccount { ThrowUserError("email_change_in_progress"); } - # Before changing an email address, confirm one does not exist. - validate_email_syntax($new_login_name) - || ThrowUserError('illegal_email_address', {addr => $new_login_name}); - is_available_username($new_login_name) - || ThrowUserError("account_exists", {email => $new_login_name}); + Bugzilla::User::Email->check_email_for_creation($new_email); if ($user->mfa) { push @mfa_events, { type => 'set_login', reason => 'changing your email address', - login => $new_login_name, + login => $new_email, }; } else { - Bugzilla::Token::IssueEmailChangeToken($user, $new_login_name); + Bugzilla::Token::IssueEmailChangeToken($user, $new_email); $vars->{email_changes_saved} = 1; } } @@ -1026,6 +1023,7 @@ my $token = $cgi->param('token'); check_token_data($token, 'edit_user_prefs') if $save_changes || $disable_account; + # Do any saving, and then display the current tab. SWITCH: for ($current_tab_name) { From 01400e4a7c8c749ee41c487a6d7de8dee9990bb0 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 12 May 2025 01:26:57 -0400 Subject: [PATCH 068/113] Added email_changed --- template/en/default/global/messages.html.tmpl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/template/en/default/global/messages.html.tmpl b/template/en/default/global/messages.html.tmpl index 1329ca5cbc..16d85d38dd 100644 --- a/template/en/default/global/messages.html.tmpl +++ b/template/en/default/global/messages.html.tmpl @@ -554,6 +554,10 @@ [%+ 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 [% milestone.name FILTER html %] has been created. From 528f4c132521ed5dcdedd9baa3b7df6c39199c4b Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 12 May 2025 04:04:39 -0400 Subject: [PATCH 069/113] Updated email_exists --- template/en/default/global/user-error.html.tmpl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index 4429a37721..106376dda3 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -562,7 +562,12 @@ [% ELSIF error == "email_exists" %] [% title = "Email Address Already Exists" %] - There is already an account with that email address. + There is already an account with + [% IF email %] + the email address [% email FILTER html %]. + [% ELSE %] + that email address. + [% END %] [% ELSIF error == "email_no_text_plain" %] Your message did not contain any text.[% terms.Bugzilla %] does not From 410cecc8465ac32d37931f37f17005084818f4c8 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 12 May 2025 04:06:12 -0400 Subject: [PATCH 070/113] Updated account_exists --- template/en/default/global/user-error.html.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index 106376dda3..5ede62bfd6 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -72,7 +72,7 @@ [% title = "Account Already Exists" %] There is already an account with [% IF email %] - the login name [% email FILTER html %]. + the login name [% login FILTER html %]. [% ELSE %] that login name. [% END %] From d6a216a54555a1644d88d4b1a729f29924766d35 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 12 May 2025 04:09:28 -0400 Subject: [PATCH 071/113] Replaced key name in user error --- Bugzilla/User.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index 716f933c19..d636ac045a 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -339,7 +339,7 @@ sub check_login_name_for_creation { # Check the name if it's a new user, or if we're changing the name. if (!ref($invocant) || $invocant->login ne $name) { is_available_username($name) - || ThrowUserError('account_exists', {email => $name}); + || ThrowUserError('account_exists', {login => $name}); } return $name; From 6202e373096782d1a4c3dedd39a44f9e178509fd Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 12 May 2025 05:50:35 -0400 Subject: [PATCH 072/113] Updated changeEmail() and confirm_create_account() --- token.cgi | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/token.cgi b/token.cgi index 3dabf959bf..9555f32d39 100755 --- a/token.cgi +++ b/token.cgi @@ -18,6 +18,7 @@ use Bugzilla::Util; use Bugzilla::Error; use Bugzilla::Token; use Bugzilla::User; +use Bugzilla::User::Email; use Date::Format; use Date::Parse; @@ -289,21 +290,20 @@ 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 (Bugzilla::User::Email->get_user_by_email($new_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}); + ThrowUserError("email_exists", {'email' => $new_email}); } - # Update the user's login name in the profiles table and delete the token + # Update the user's email address and delete the token # from the tokens table. + + my $user_email = Bugzilla::User::Email->new('name' => $old_email); + $user_email->set_email($new_email); + $user_email->update(); + $dbh->bz_start_transaction(); - $dbh->do( - q{UPDATE profiles - SET login_name = ? - WHERE userid = ?}, undef, ($new_email, $userid) - ); - Bugzilla->memcached->clear({table => 'profiles', id => $userid}); $dbh->do('DELETE FROM tokens WHERE token = ?', undef, $token); $dbh->do( q{DELETE FROM tokens WHERE userid = ? @@ -321,7 +321,7 @@ sub changeEmail { # Let the user know their email address has been changed. - $vars->{'message'} = "login_changed"; + $vars->{'message'} = "email_changed"; $template->process("global/message.html.tmpl", $vars) || ThrowTemplateError($template->error()); @@ -419,8 +419,13 @@ sub confirm_create_account { Bugzilla->assert_password_is_secure($password1); Bugzilla->assert_passwords_match($password1, $password2); + # 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, + email => $email, realname => scalar $cgi->param('realname'), cryptpassword => $password1 }); From 91f7d0db5a9c09dcac9004b46e6a1eab92b95a0f Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 12 May 2025 07:16:39 -0400 Subject: [PATCH 073/113] Added email creation --- Bugzilla/User.pm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index d636ac045a..366a9e0dce 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -2590,6 +2590,15 @@ sub create { = _generate_nickname($params->{realname}, $params->{login_name}, 0); my $user = $class->SUPER::create($params); + # Create a user email account + my $email_data = { + user_id => $user->id, + email => $params->{email}, + is_primary_email => 1 + }; + + my $user_email = Bugzilla::User::Email->create($email_data); + # Turn on all email for the new user require Bugzilla::BugMail; my %relationships = Bugzilla::BugMail::relationships(); From ca3054cbc72c16a8e4e8862d0582406427cf375f Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 12 May 2025 08:04:57 -0400 Subject: [PATCH 074/113] Replaced username with login, added email to create_or_update_user() --- Bugzilla/Auth/Verify.pm | 44 +++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/Bugzilla/Auth/Verify.pm b/Bugzilla/Auth/Verify.pm index 1436b37d2b..6ceff31321 100644 --- a/Bugzilla/Auth/Verify.pm +++ b/Bugzilla/Auth/Verify.pm @@ -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 = $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) { $extern_user_id = $dbh->selectrow_array( @@ -55,27 +56,27 @@ sub create_or_update_user { # If we have both a valid extern_id and a valid username, and they are # not the same id, then we have a conflict. - if ( $username_user_id + if ( $login_user_id && $extern_user_id - && $username_user_id ne $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} + {extern_id => $extern_id, extern_user => $extern_name, username => $login} }; } # If we have a valid username, 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 { + 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 => $login} }; # external authentication @@ -83,23 +84,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, cryptpassword => $password, realname => $real_name - }); - $username_user_id = $user->id; + my $user = Bugzilla::User->create({ + login_name => $login, + email => $email, + cryptpassword => $password, + realname => $real_name}); + $login_user_id = $user->id; } # If we have a valid username 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 @@ -117,13 +119,13 @@ sub create_or_update_user { # Now that we have a valid User, we need to see if any data has to be # updated. my $user_updated = 0; - if ($username && lc($user->login) ne lc($username)) { - validate_email_syntax($username) || return { + if ($email && lc($user->email) ne lc($email)) { + validate_email_syntax($email) || return { failure => AUTH_ERROR, error => 'auth_invalid_email', - details => {addr => $username} + details => {addr => $email} }; - $user->set_login($username); + $user->set_email($email); $user_updated = 1; } if ($real_name && $user->name ne $real_name) { From 27a5c4ab4778ddae911368d06460c1eb410c0138 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 12 May 2025 08:22:53 -0400 Subject: [PATCH 075/113] Added set_email() --- Bugzilla/User.pm | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index 366a9e0dce..c136e91702 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -442,6 +442,19 @@ sub _generate_nickname { return $nick; } +sub set_email { + my ($self, $email) = @_; + # Create a user email account + my $email_data = { + user_id => $self->id, + email => $email, + is_primary_email => 1 + }; + + my $user_email = Bugzilla::User::Email->create($email_data); +} + + sub set_name { my ($self, $name) = @_; $self->set('realname', $name); @@ -2590,14 +2603,7 @@ sub create { = _generate_nickname($params->{realname}, $params->{login_name}, 0); my $user = $class->SUPER::create($params); - # Create a user email account - my $email_data = { - user_id => $user->id, - email => $params->{email}, - is_primary_email => 1 - }; - - my $user_email = Bugzilla::User::Email->create($email_data); + $user->set_email($params->{email}); # Turn on all email for the new user require Bugzilla::BugMail; From 816bdf71b6ff290db77134ddb7d79cd031c5ed2c Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 12 May 2025 22:33:21 -0400 Subject: [PATCH 076/113] Added email to user create --- Bugzilla/Install.pm | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Bugzilla/Install.pm b/Bugzilla/Install.pm index c56700514b..b76258c621 100644 --- a/Bugzilla/Install.pm +++ b/Bugzilla/Install.pm @@ -31,6 +31,7 @@ use Bugzilla::User::Setting; use Bugzilla::Util qw(get_text); use Bugzilla::Version; + use constant STATUS_WORKFLOW => ( [undef, 'UNCONFIRMED'], [undef, 'CONFIRMED'], @@ -464,14 +465,9 @@ sub create_admin { my $admin = Bugzilla::User->create({ - login_name => $login, realname => $full_name, cryptpassword => $password + login_name => $login, email => $email, realname => $full_name, cryptpassword => $password }); - # Create email record - Bugzilla::User::Email->create({ - user_id => $admin->id, email => $email, is_primary_email => 1, display_order => 1 - }); - make_admin($admin); } From dbf8e7dd5586aa91af9c86403926b28d125620d4 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 12 May 2025 23:16:10 -0400 Subject: [PATCH 077/113] Added login_name fallback to set_email --- Bugzilla/User.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index c136e91702..1e8c2c44ab 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -2603,7 +2603,7 @@ sub create { = _generate_nickname($params->{realname}, $params->{login_name}, 0); my $user = $class->SUPER::create($params); - $user->set_email($params->{email}); + $user->set_email($params->{email} || $params->{login_name}); # Turn on all email for the new user require Bugzilla::BugMail; From 4e82f4c00520502ae5e6e88e9b8bb6f14dca34ae Mon Sep 17 00:00:00 2001 From: topunix Date: Tue, 13 May 2025 01:10:30 -0400 Subject: [PATCH 078/113] Expand token data unpacking --- token.cgi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/token.cgi b/token.cgi index 9555f32d39..5ab0fcfae4 100755 --- a/token.cgi +++ b/token.cgi @@ -409,7 +409,7 @@ sub confirm_create_account { my $token = shift; Bugzilla->user->check_account_creation_enabled; - my (undef, undef, $login_name) = Bugzilla::Token::GetTokenData($token); + my ($user_id, $date, $data, $tokentype) = Bugzilla::Token::GetTokenData($token); my $password1 = $cgi->param('passwd1'); my $password2 = $cgi->param('passwd2'); @@ -424,7 +424,7 @@ sub confirm_create_account { $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 => $password1 From dd7e44108a2294de527555bfaabde0744d52ed8d Mon Sep 17 00:00:00 2001 From: topunix Date: Tue, 13 May 2025 01:59:32 -0400 Subject: [PATCH 079/113] Added email param to issue_new_user_account_token() --- Bugzilla/Token.pm | 60 +++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Bugzilla/Token.pm b/Bugzilla/Token.pm index 96de234de1..4a674ee55c 100644 --- a/Bugzilla/Token.pm +++ b/Bugzilla/Token.pm @@ -96,44 +96,44 @@ 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 $dbh = Bugzilla->dbh; - my $template = Bugzilla->template; - my $vars = {}; - - # Is there already a pending request for this login name? 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 at least 10 minutes old before sending a new email. - - my $pending_requests = $dbh->selectrow_array( - 'SELECT COUNT(*) + my ($login, $email) = @_; + my $dbh = Bugzilla->dbh; + my $template = Bugzilla->template; + my $vars = {}; + + # 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()', '-', 10, 'MINUTE'), undef, - ('account', $login_name) - ); + . $dbh->sql_date_math('NOW()', '-', ACCOUNT_CHANGE_INTERVAL, 'MINUTE'), + undef, 'account'); - ThrowUserError('too_soon_for_new_token', {'type' => 'account'}) - if $pending_requests; + 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->{'expiration_ts'} = ctime($token_ts + MAX_TOKEN_AGE * 86400); - $vars->{'token'} = $token; + $vars->{'login'} = $login; + $vars->{'email'} = $email; + $vars->{'expiration_ts'} = ctime($token_ts + MAX_TOKEN_AGE * 86400); + $vars->{'token'} = $token; - my $message; - $template->process('account/email/request-new.txt.tmpl', $vars, \$message) - || ThrowTemplateError($template->error()); + my $message; + $template->process('account/email/request-new.txt.tmpl', $vars, \$message) + || ThrowTemplateError($template->error()); - # In 99% of cases, the user getting the confirmation email is the same one - # who made the request, and so it is reasonable to send the email in the same - # language used to view the "Create a New Account" page (we cannot use their - # user prefs as the user has no account yet!). - MessageToMTA($message); + # In 99% of cases, the user getting the confirmation email is the same one + # who made the request, and so it is reasonable to send the email in the same + # language used to view the "Create a New Account" page (we cannot use their + # user prefs as the user has no account yet!). + MessageToMTA($message, SEND_NOW); } sub IssueEmailChangeToken { From e452a75ba671b3698263a4b7f76da54212838f00 Mon Sep 17 00:00:00 2001 From: topunix Date: Tue, 13 May 2025 02:37:18 -0400 Subject: [PATCH 080/113] Added email param --- createaccount.cgi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/createaccount.cgi b/createaccount.cgi index f0fd407305..52f6b2909a 100644 --- a/createaccount.cgi +++ b/createaccount.cgi @@ -36,8 +36,9 @@ if (defined($login)) { # the create account form. my $token = $cgi->param('token'); check_hash_token($token, ['create_account']); - - $user->check_and_send_account_creation_confirmation($login); + + my $email = $cgi->param('email'); + $user->check_and_send_account_creation_confirmation($login, $email); $vars->{'login'} = $login; $template->process("account/created.html.tmpl", $vars) From 9b01505d51a56217fbd3374f3e1ede71736d73d6 Mon Sep 17 00:00:00 2001 From: topunix Date: Tue, 13 May 2025 02:38:55 -0400 Subject: [PATCH 081/113] Added email var --- createaccount.cgi | 1 + 1 file changed, 1 insertion(+) diff --git a/createaccount.cgi b/createaccount.cgi index 52f6b2909a..2aa656e565 100644 --- a/createaccount.cgi +++ b/createaccount.cgi @@ -40,6 +40,7 @@ if (defined($login)) { my $email = $cgi->param('email'); $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()); From c705a05483e27ae6a6a207809967b2b115f27c44 Mon Sep 17 00:00:00 2001 From: topunix Date: Tue, 13 May 2025 03:13:19 -0400 Subject: [PATCH 082/113] Added email string --- template/en/default/account/created.html.tmpl | 36 ++++++------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/template/en/default/account/created.html.tmpl b/template/en/default/account/created.html.tmpl index 539fb44c2a..f87571936b 100644 --- a/template/en/default/account/created.html.tmpl +++ b/template/en/default/account/created.html.tmpl @@ -1,30 +1,16 @@ -[%# The contents of this file are subject to the Mozilla Public - # License Version 1.1 (the "License"); you may not use this file - # except in compliance with the License. You may obtain a copy of - # the License at http://www.mozilla.org/MPL/ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. # - # Software distributed under the License is distributed on an "AS - # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - # implied. See the License for the specific language governing - # rights and limitations under the License. - # - # The Original Code is the Bugzilla Bug Tracking System. - # - # The Initial Developer of the Original Code is Netscape Communications - # Corporation. Portions created by Netscape are - # Copyright (C) 1998 Netscape Communications Corporation. All - # Rights Reserved. - # - # Contributor(s): Gervase Markham - # Frédéric Buclin + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. #%] [%# 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. #%] -[% PROCESS global/variables.none.tmpl %] - [% title = BLOCK %] Request for new user account '[% login FILTER html %]' submitted [% END %] @@ -32,9 +18,9 @@ [% PROCESS global/header.html.tmpl title = title %]

- 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 [% email FILTER html %] 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.

-[% PROCESS global/footer.html.tmpl %] +[% PROCESS global/footer.html.tmpl %] From 0f705a99cbb4c4ca9345b022c4ed0da34ed21527 Mon Sep 17 00:00:00 2001 From: topunix Date: Tue, 13 May 2025 03:26:23 -0400 Subject: [PATCH 083/113] Updated template to use email in form --- template/en/default/account/create.html.tmpl | 99 +++++++++++--------- 1 file changed, 53 insertions(+), 46 deletions(-) diff --git a/template/en/default/account/create.html.tmpl b/template/en/default/account/create.html.tmpl index 5ce75fab80..b01da57cd0 100644 --- a/template/en/default/account/create.html.tmpl +++ b/template/en/default/account/create.html.tmpl @@ -1,67 +1,74 @@ -[%# The contents of this file are subject to the Mozilla Public - # License Version 1.1 (the "License"); you may not use this file - # except in compliance with the License. You may obtain a copy of - # the License at http://www.mozilla.org/MPL/ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. # - # Software distributed under the License is distributed on an "AS - # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - # implied. See the License for the specific language governing - # rights and limitations under the License. - # - # The Original Code is the Bugzilla Bug Tracking System. - # - # The Initial Developer of the Original Code is Netscape Communications - # Corporation. Portions created by Netscape are - # Copyright (C) 1998 Netscape Communications Corporation. All - # Rights Reserved. - # - # Contributor(s): Gervase Markham + # This Source Code Form is "Incompatible With Secondary Licenses", as + # 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/variables.none.tmpl %] - -[% title = BLOCK %] - Create a new [% terms.Bugzilla %] account -[% END %] - [% PROCESS global/header.html.tmpl - title = title - onload = "document.forms['account_creation_form'].login.focus();" %] + title = "Create a new $terms.Bugzilla account" +%]

To create a [% terms.Bugzilla %] account, all you need to do is to enter -[% IF Param('emailsuffix') == '' %] - a legitimate email address. -[% ELSE %] - an account name which when combined with [% Param('emailsuffix') %] - corresponds to an address where you receive email. -[% END %] + a login name of your choice and a legitimate email address. You will receive an email at this address to confirm the creation of your account. You will not be able to log in until you receive the email. If it doesn't arrive within a reasonable amount of time, you may contact - the maintainer of this [% terms.Bugzilla %] installation + the maintainer of this Bugzilla installation at [% Param("maintainer") %].

-[% IF Param('createemailregexp') == '.*' && Param('emailsuffix') == '' %] +

+ If you already have an account and want to change your + [% IF Param('allowemailchange') %] + email address or + [% END %] + login name, you can change it from the Preferences page after logging in. +

+ +

+ 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 %]. Note that your email address will + never be displayed to logged out users. Only registered users will be able to see it. +

+ +[% IF Param('createemailregexp') == '.*' %]

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. + tracking system. Activity on most [% terms.bugs %] will be visible to + registered users. + That 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 %] -[% PROCESS "account/auth/signup-form.html.tmpl" %] + +
+ +
+ + + (no whitespaces and no @ character, unless it matches your email address) + +
+
+ +
+ + +
-[% Hook.process('additional_methods') %] +
+ + + +
+ [% PROCESS global/footer.html.tmpl %] From 4e5d7e958866fcb72a4c692820ac3a6bc82a3ebc Mon Sep 17 00:00:00 2001 From: topunix Date: Tue, 13 May 2025 04:00:22 -0400 Subject: [PATCH 084/113] Added email param to check_and_send_account_creation_confirmation() --- Bugzilla/User.pm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index 1e8c2c44ab..274ecf8b84 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -2792,21 +2792,22 @@ sub check_account_creation_enabled { } sub check_and_send_account_creation_confirmation { - my ($self, $login) = @_; + my ($self, $login, $email) = @_; $login = $self->check_login_name_for_creation($login); + $email = Bugzilla::User::Email->check_email_for_creation($email); my $creation_regexp = Bugzilla->params->{'createemailregexp'}; - if ($login !~ /$creation_regexp/i) { + if ($email !~ /$creation_regexp/i) { ThrowUserError('account_creation_restricted'); } # BMO - add a hook to allow extra validation prior to account creation. - Bugzilla::Hook::process("user_verify_login", {login => $login}); + Bugzilla::Hook::process("user_verify_login", {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); } # This is used in a few performance-critical areas where we don't want to From c400a97b7f4c78def3777d0b1fa1b936f2841e94 Mon Sep 17 00:00:00 2001 From: topunix Date: Tue, 13 May 2025 04:15:30 -0400 Subject: [PATCH 085/113] Added email to user error --- Bugzilla/User/Email.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index ddcbf6a36d..2f1c336e11 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -141,7 +141,7 @@ sub check_email_for_creation { || ThrowUserError('illegal_email_address', {addr => $email}); if ($invocant->get_user_by_email($email)) { - ThrowUserError('email_exists'); + ThrowUserError("email_exists", {'email' => $email}) } return $email; From e93b725a0482a0df95d3b994abdeabcd34f10cce Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 14 May 2025 01:04:14 -0400 Subject: [PATCH 086/113] Replace emailaddress with login for User --- template/en/default/account/cancel-token.txt.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/en/default/account/cancel-token.txt.tmpl b/template/en/default/account/cancel-token.txt.tmpl index bc35e2d4c6..d64d68188b 100644 --- a/template/en/default/account/cancel-token.txt.tmpl +++ b/template/en/default/account/cancel-token.txt.tmpl @@ -36,7 +36,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 %] From 320ae8add087e56a91f35163ba64a2a313f0c1c9 Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 14 May 2025 01:09:24 -0400 Subject: [PATCH 087/113] Added userid check for emailaddress and login vars --- Bugzilla/Token.pm | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Bugzilla/Token.pm b/Bugzilla/Token.pm index 4a674ee55c..dbb95bc59b 100644 --- a/Bugzilla/Token.pm +++ b/Bugzilla/Token.pm @@ -388,7 +388,18 @@ 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; From 1c8af66a4ccde7da6c4a0ecf32007d7e6e576a3a Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 15 May 2025 19:36:05 -0400 Subject: [PATCH 088/113] Fallback to user login if primary email is undefined --- Bugzilla/User.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index 274ecf8b84..448c3d1f0f 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -633,7 +633,7 @@ sub update_last_seen_date { sub name { $_[0]->{realname}; } sub login { $_[0]->{login_name}; } sub extern_id { $_[0]->{extern_id}; } -sub email { Bugzilla::User::Email->get_primary_email_of_user($_[0]->{userid});} +sub email { Bugzilla::User::Email->get_primary_email_of_user($_[0]->{userid}) || $_[0]->login;} sub disabledtext { $_[0]->{'disabledtext'}; } sub is_enabled { $_[0]->{'is_enabled'} ? 1 : 0; } sub showmybugslink { $_[0]->{showmybugslink}; } From 565af338db271822d16f3fda5e1679338db8010f Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 15 May 2025 20:21:52 -0400 Subject: [PATCH 089/113] Update password reset error message to require email address --- template/en/default/global/user-error.html.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index 5ede62bfd6..fb0fa3dba7 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -1245,8 +1245,8 @@ 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. + [% title = "Email Address Required" %] + You must enter your email address when requesting to change your password. [% ELSIF error == "login_at_sign_disallowed" %] [% title = "Illegal Character in Login" %] From ac3abe2da535a430d3faf793cf8e6622246f81e5 Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 15 May 2025 20:45:09 -0400 Subject: [PATCH 090/113] Added ACCOUNT_CHANGE_INTERVAL constant --- Bugzilla/Constants.pm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm index 46512dec9a..a69e792e28 100644 --- a/Bugzilla/Constants.pm +++ b/Bugzilla/Constants.pm @@ -166,6 +166,7 @@ use Memoize; MAX_SUDO_TOKEN_AGE MAX_LOGIN_ATTEMPTS LOGIN_LOCKOUT_INTERVAL + ACCOUNT_CHANGE_INTERVAL MAX_STS_AGE SAFE_PROTOCOLS @@ -473,6 +474,10 @@ use constant MAX_LOGIN_ATTEMPTS => 5; # account is locked. use constant LOGIN_LOCKOUT_INTERVAL => 30; +# The time in minutes a user must wait before they can request another email to +# create a new account or change their password. +use constant ACCOUNT_CHANGE_INTERVAL => 10; + # The maximum number of seconds the Strict-Transport-Security header # will remain valid. BMO uses one year. use constant MAX_STS_AGE => 31536000; From 13eca3db19e45df0bb799df133387c069867d057 Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 15 May 2025 20:53:02 -0400 Subject: [PATCH 091/113] Fix: Update password change error message and condition --- template/en/default/global/user-error.html.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index fb0fa3dba7..251283037d 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -1244,9 +1244,9 @@ [% title = "Invalid Keyword Name" %] You may not use commas or whitespace in a keyword name. - [% ELSIF error == "login_needed_for_password_change" %] + [% ELSIF error == "email_needed_for_password_change" %] [% title = "Email Address Required" %] - You must enter your email address when requesting to change your password. + You must enter an email address when requesting to change your password. [% ELSIF error == "login_at_sign_disallowed" %] [% title = "Illegal Character in Login" %] From f4f20704b9abd70c0f14cc697535c9606b577a12 Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 15 May 2025 20:54:00 -0400 Subject: [PATCH 092/113] Fixed error name --- token.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/token.cgi b/token.cgi index 5ab0fcfae4..f65ed549a2 100755 --- a/token.cgi +++ b/token.cgi @@ -90,7 +90,7 @@ if ($token) { my $user_account; if ($action eq 'reqpw') { my $login_name = $cgi->param('loginname') - || ThrowUserError("login_needed_for_password_change"); + || ThrowUserError("email_needed_for_password_change"); # check verification methods unless (Bugzilla->user->authorizer->can_change_password) { From f9510152c370e2a6196243a1365c3c72c37c71fc Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 15 May 2025 21:29:35 -0400 Subject: [PATCH 093/113] Refactor: Standardize on email variable for password requests and update user lookup --- token.cgi | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/token.cgi b/token.cgi index f65ed549a2..4e0c11b2a4 100755 --- a/token.cgi +++ b/token.cgi @@ -89,7 +89,7 @@ if ($token) { # the list of allowed verification methods. my $user_account; if ($action eq 'reqpw') { - my $login_name = $cgi->param('loginname') + my $email = $cgi->param('loginname') || ThrowUserError("email_needed_for_password_change"); # check verification methods @@ -102,15 +102,19 @@ if ($action eq 'reqpw') { my $token = $cgi->param('token'); check_hash_token($token, ['reqpw']); - validate_email_syntax($login_name) - || ThrowUserError('illegal_email_address', {addr => $login_name}); + validate_email_syntax($email) + || ThrowUserError('illegal_email_address', {addr => $email}); - $user_account = Bugzilla::User->check($login_name); + my $user_id = Bugzilla::User::Email->get_user_by_email($email); + # Make sure we have a fallback in case profiles.login still has email address + my $user_account = $user_id + ? Bugzilla::User->new({ id => $user_id }) + : Bugzilla::User->new({ name => $email }); # Make sure the user account is active or was deactivated due to inactivity if (!$user_account->is_enabled && $user_account->password_change_reason ne 'Inactive Account') { ThrowUserError('account_disabled', - {disabled_reason => get_text('account_disabled', {account => $login_name})}); + {disabled_reason => get_text('account_disabled', {account => $email})}); } } From 077be0c47d9c288187fa3395606857e29274e5f4 Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 16 May 2025 12:43:07 -0400 Subject: [PATCH 094/113] Removed SEND_NOW --- Bugzilla/Token.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/Token.pm b/Bugzilla/Token.pm index dbb95bc59b..1632362a3a 100644 --- a/Bugzilla/Token.pm +++ b/Bugzilla/Token.pm @@ -133,7 +133,7 @@ sub issue_new_user_account_token { # who made the request, and so it is reasonable to send the email in the same # language used to view the "Create a New Account" page (we cannot use their # user prefs as the user has no account yet!). - MessageToMTA($message, SEND_NOW); + MessageToMTA($message); } sub IssueEmailChangeToken { From da852f63d4757804eaee7de2b946cb3abec2cd1d Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 16 May 2025 13:16:24 -0400 Subject: [PATCH 095/113] Refactor: Implement user lookup when 'name' parameter is present --- Bugzilla/User.pm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index 448c3d1f0f..25ad0f9bd7 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -156,6 +156,18 @@ sub new { $param = {condition => 'extern_id = ?', values => [$param->{extern_id}]}; $_[0] = $param; } + elsif (exists $param->{name}) { + my $email = $param->{name}; + + validate_email_syntax($email) + || ThrowUserError('illegal_email_address', {addr => $email}); + + my $user_id = Bugzilla::User::Email->get_user_by_email($email); + if ($user_id) { + $param->{id} = $user_id; + delete $param->{name}; + } + } } $user = $class->SUPER::new(@_); From 6262b9725f7a7bf8d3bdb4a10512f2648a5cf852 Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 16 May 2025 13:36:16 -0400 Subject: [PATCH 096/113] Added invalid_email error --- template/en/default/global/user-error.html.tmpl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index 251283037d..ca422aea26 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -1118,6 +1118,12 @@ [% title = "Invalid Flag ID" %] The flag id [% flag_id FILTER html %] is invalid. + [% ELSIF error == "invalid_email" %] + [% title = "Invalid Email Address" %] + The address [% email FILTER html %] 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 From 7d6638b5edf9c8cd3d9c39c6cd316fbe1758bf92 Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 16 May 2025 14:26:55 -0400 Subject: [PATCH 097/113] Refactor: Simplify user instantiation and rely on constructor for validation --- token.cgi | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/token.cgi b/token.cgi index 4e0c11b2a4..68de8667fe 100755 --- a/token.cgi +++ b/token.cgi @@ -102,14 +102,11 @@ if ($action eq 'reqpw') { my $token = $cgi->param('token'); check_hash_token($token, ['reqpw']); - validate_email_syntax($email) - || ThrowUserError('illegal_email_address', {addr => $email}); - - my $user_id = Bugzilla::User::Email->get_user_by_email($email); - # Make sure we have a fallback in case profiles.login still has email address - my $user_account = $user_id - ? Bugzilla::User->new({ id => $user_id }) - : Bugzilla::User->new({ name => $email }); + my $user_account = Bugzilla::User->new({ name => $email }); + + unless ($user_account) { + ThrowUserError("invalid_email", {email => $email}); + } # Make sure the user account is active or was deactivated due to inactivity if (!$user_account->is_enabled && $user_account->password_change_reason ne 'Inactive Account') { From b4e4a2ea57a44deb546d1a82c1392c43143615f2 Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 16 May 2025 18:15:19 -0400 Subject: [PATCH 098/113] Added email syntax check to password reset --- token.cgi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/token.cgi b/token.cgi index 68de8667fe..7cf14a8c84 100755 --- a/token.cgi +++ b/token.cgi @@ -102,6 +102,9 @@ if ($action eq 'reqpw') { my $token = $cgi->param('token'); check_hash_token($token, ['reqpw']); + validate_email_syntax($email) + || ThrowUserError('illegal_email_address', {addr => $email}); + my $user_account = Bugzilla::User->new({ name => $email }); unless ($user_account) { From 01f647776b7728a5f0dd67e22d580591fcb34153 Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 16 May 2025 18:16:08 -0400 Subject: [PATCH 099/113] Removed email syntax check in constructor to allow non-email logins --- Bugzilla/User.pm | 3 --- 1 file changed, 3 deletions(-) diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index 25ad0f9bd7..bb8f977af4 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -158,9 +158,6 @@ sub new { } elsif (exists $param->{name}) { my $email = $param->{name}; - - validate_email_syntax($email) - || ThrowUserError('illegal_email_address', {addr => $email}); my $user_id = Bugzilla::User::Email->get_user_by_email($email); if ($user_id) { From 1e6938775178f88e1ea7e8dd42d9538abc16357e Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 16 May 2025 18:27:14 -0400 Subject: [PATCH 100/113] Added email address to search options --- template/en/default/admin/users/search.html.tmpl | 1 + 1 file changed, 1 insertion(+) diff --git a/template/en/default/admin/users/search.html.tmpl b/template/en/default/admin/users/search.html.tmpl index 4e11560385..08a014843d 100644 --- a/template/en/default/admin/users/search.html.tmpl +++ b/template/en/default/admin/users/search.html.tmpl @@ -39,6 +39,7 @@

From 02779c7b87b59a60c2eb4b1fdcc1a48cbef7fe7e Mon Sep 17 00:00:00 2001 From: topunix Date: Sat, 17 May 2025 17:48:26 -0400 Subject: [PATCH 101/113] Added email column --- template/en/default/admin/users/list.html.tmpl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/template/en/default/admin/users/list.html.tmpl b/template/en/default/admin/users/list.html.tmpl index e03f089c74..1e32de7947 100644 --- a/template/en/default/admin/users/list.html.tmpl +++ b/template/en/default/admin/users/list.html.tmpl @@ -39,6 +39,9 @@ contentlink => 'editusers.cgi?action=edit&userid=%%userid%%' _ listselectionurlparams } + {name => 'email' + heading => 'Email address' + } {name => 'realname' heading => 'Real name' } From bae60f8c4b728b63ad7dd897e7b8c03261f78cbf Mon Sep 17 00:00:00 2001 From: topunix Date: Sat, 17 May 2025 18:33:45 -0400 Subject: [PATCH 102/113] feat: Add email to user profile query --- editusers.cgi | 52 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/editusers.cgi b/editusers.cgi index 1a5b24979c..b2e89f3b17 100755 --- a/editusers.cgi +++ b/editusers.cgi @@ -77,15 +77,28 @@ elsif ($action eq 'list') { my $matchstr = trim($cgi->param('matchstr')); my $matchtype = $cgi->param('matchtype'); my $grouprestrict = $cgi->param('grouprestrict') || '0'; - my $query - = 'SELECT DISTINCT userid, login_name, realname, is_enabled, ' - . $dbh->sql_date_format('last_seen_date', '%Y-%m-%d') - . ' AS last_seen_date ' - . 'FROM profiles'; + my @bindValues; my $nextCondition; my $visibleGroups; + my $select_fields = 'profiles.userid, profiles.login_name, profiles.realname, profiles.is_enabled, ' + . $dbh->sql_date_format('profiles.last_seen_date', '%Y-%m-%d') . ' AS last_seen_date'; + + # Add email as a column from profiles_emails table + $select_fields .= ', profiles_emails.email AS email'; + + my $query = 'SELECT DISTINCT ' . $select_fields . ' FROM profiles'; + + # Join the two tables by userid + $query .= ' INNER JOIN profiles_emails ON profiles.userid = profiles_emails.user_id'; + + my $expr; + if ($matchvalue eq 'email') { + $expr = 'profiles_emails.email'; + $nextCondition = 'WHERE'; + } + # If a group ID is given, make sure it is a valid one. my $group; if ($grouprestrict) { @@ -128,20 +141,21 @@ elsif ($action eq 'list') { # Handle selection by login name, real name, or userid. if (defined($matchtype)) { $query .= " $nextCondition "; - my $expr = ""; - if ($matchvalue eq 'userid') { - if ($matchstr) { - my $stored_matchstr = $matchstr; - detaint_natural($matchstr) - || ThrowUserError('illegal_user_id', {userid => $stored_matchstr}); + if (!$expr) { + if ($matchvalue eq 'userid') { + if ($matchstr) { + my $stored_matchstr = $matchstr; + detaint_natural($matchstr) + || ThrowUserError('illegal_user_id', {userid => $stored_matchstr}); + } + $expr = "profiles.userid"; + } + elsif ($matchvalue eq 'realname') { + $expr = "profiles.realname"; + } + else { + $expr = "profiles.login_name"; } - $expr = "profiles.userid"; - } - elsif ($matchvalue eq 'realname') { - $expr = "profiles.realname"; - } - else { - $expr = "profiles.login_name"; } if ($matchtype =~ /^(regexp|notregexp|exact)$/) { @@ -176,9 +190,9 @@ elsif ($action eq 'list') { } $query .= ' ORDER BY profiles.login_name'; + $vars->{'users'} = $dbh->selectall_arrayref($query, {'Slice' => {}}, @bindValues); - } if ($matchtype && $matchtype eq 'exact' && scalar(@{$vars->{'users'}}) == 1) { From 9d3824b072091425dd520c756509acdec2ada4d4 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 19 May 2025 20:18:03 -0400 Subject: [PATCH 103/113] Added email to user account --- .../en/default/admin/users/userdata.html.tmpl | 58 ++++++++++++------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/template/en/default/admin/users/userdata.html.tmpl b/template/en/default/admin/users/userdata.html.tmpl index 0abca2baf5..290609b9b9 100644 --- a/template/en/default/admin/users/userdata.html.tmpl +++ b/template/en/default/admin/users/userdata.html.tmpl @@ -17,7 +17,7 @@ # # editform: is this an edit form? (It's a create form otherwise) # editusers: is viewing user member of editusers? - # otheruser: Bugzilla::User object of user to edit + # user: Bugzilla::User object of user to edit #%]

@@ -25,28 +25,44 @@ + + + + [% IF default_authorizer.extern_id_used %] @@ -57,9 +73,9 @@ [% IF editusers || disableusers %] + id="name" value="[% user.name FILTER html %]"> [% ELSE %] - [% otheruser.name FILTER html %] + [% user.name FILTER html %] [% END %] @@ -69,7 +85,7 @@ - [% IF otheruser.bounce_count %] + [% IF user.bounce_count %] [% END %] @@ -128,7 +144,7 @@ maxrows = 10 defaultrows = 10 cols = 60 - defaultcontent = otheruser.disabledtext + defaultcontent = user.disabledtext %]
(If non-empty, then the account will be disabled, and this text should explain why.) @@ -141,10 +157,10 @@ From 43e65a442e2dc7b3388cbcc168192846af2047c5 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 19 May 2025 21:02:01 -0400 Subject: [PATCH 104/113] Prevented error with unrecognized column (email) --- Bugzilla/User.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index bb8f977af4..28ff779aa2 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -2610,9 +2610,10 @@ sub create { $dbh->bz_start_transaction(); $params->{nickname} = _generate_nickname($params->{realname}, $params->{login_name}, 0); + my $email = exists $params->{email} ? delete $params->{email} : $params->{login_name}; my $user = $class->SUPER::create($params); - $user->set_email($params->{email} || $params->{login_name}); + $user->set_email($email); # Turn on all email for the new user require Bugzilla::BugMail; From 8621cfacdd4d3b10d6729223459b4b48ff439b3e Mon Sep 17 00:00:00 2001 From: topunix Date: Tue, 20 May 2025 16:13:59 -0400 Subject: [PATCH 105/113] Replace user with otheruser --- .../en/default/admin/users/userdata.html.tmpl | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/template/en/default/admin/users/userdata.html.tmpl b/template/en/default/admin/users/userdata.html.tmpl index 290609b9b9..da31608d8f 100644 --- a/template/en/default/admin/users/userdata.html.tmpl +++ b/template/en/default/admin/users/userdata.html.tmpl @@ -17,7 +17,7 @@ # # editform: is this an edit form? (It's a create form otherwise) # editusers: is viewing user member of editusers? - # user: Bugzilla::User object of user to edit + # otheruser: Bugzilla::User object of user to edit #%] @@ -25,16 +25,16 @@ @@ -43,14 +43,14 @@ @@ -60,9 +60,9 @@ @@ -73,9 +73,9 @@ [% IF editusers || disableusers %] + id="name" value="[% otheruser.name FILTER html %]"> [% ELSE %] - [% user.name FILTER html %] + [% otheruser.name FILTER html %] [% END %] @@ -85,7 +85,7 @@ - [% IF user.bounce_count %] + [% IF otheruser.bounce_count %] [% END %] @@ -156,11 +156,11 @@ From 0363a1f82ca6035a6ea76553658eb468ba7ea8a5 Mon Sep 17 00:00:00 2001 From: topunix Date: Tue, 20 May 2025 20:52:04 -0400 Subject: [PATCH 106/113] Docs: Update login name and email field help text --- docs/en/rst/administering/users.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/en/rst/administering/users.rst b/docs/en/rst/administering/users.rst index 064354bba5..4eface54c8 100644 --- a/docs/en/rst/administering/users.rst +++ b/docs/en/rst/administering/users.rst @@ -27,8 +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). +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), @@ -56,11 +55,13 @@ 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 + This is the user's login name, which we encourage to be different + from the user's email address and real name. + +- *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). + email address themselves (to any valid email address). - *Real Name*: The user's real name. Note that Bugzilla does not require this to create an account. From a6ee967852385c54976a028c2d647da00d8d1222 Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 22 May 2025 13:23:26 -0400 Subject: [PATCH 107/113] Added _copy_valid_emails_to_profiles_emails() --- Bugzilla/Install/DB.pm | 47 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/Bugzilla/Install/DB.pm b/Bugzilla/Install/DB.pm index 0265b33507..a20052c37d 100644 --- a/Bugzilla/Install/DB.pm +++ b/Bugzilla/Install/DB.pm @@ -817,7 +817,8 @@ sub update_table_definitions { $dbh->bz_alter_column('user_request_log', 'attach_id', {TYPE => 'INT5', NOTNULL => 0}); _populate_attachment_storage_class(); - + # Bug 1963773 - topunixguy@gmail.com + _copy_valid_emails_to_profiles_emails(); ################################################################ # New --TABLE-- changes should go *** A B O V E *** this point # ################################################################ @@ -4393,6 +4394,50 @@ sub _populate_attachment_storage_class { } } +sub _copy_valid_emails_to_profiles_emails { + my $dbh = Bugzilla->dbh; + + my ($total) = $dbh->selectrow_array("SELECT COUNT(*) FROM profiles"); + print "Populating profiles_emails table. There are $total emails to process.\n"; + + my $select_sth = $dbh->prepare('SELECT userid, email, login_name FROM profiles'); + my $check_sth = $dbh->prepare('SELECT 1 FROM profiles_emails WHERE user_id = ?'); + my $insert_sth = $dbh->prepare(' + INSERT INTO profiles_emails (user_id, email, is_primary_email, display_order) + VALUES (?, ?, 1, 1) + '); + + $select_sth->execute(); + + while (my $row = $select_sth->fetchrow_hashref) { + my $user_id = $row->{userid}; + + # Skip if the user already has an entry + $check_sth->execute($user_id); + next if $check_sth->fetchrow_array; + + my $email = $row->{email}; + my $login = $row->{login_name}; + + my $valid_email; + if (validate_email_syntax($email)) { + $valid_email = $email; + } elsif (validate_email_syntax($login)) { + $valid_email = $login; + } + + next unless defined $valid_email; + + eval { + $insert_sth->execute($user_id, $valid_email); + }; + warn "Failed to insert email for user $user_id: $@" if $@; + } + + $select_sth->finish; + $check_sth->finish; + $insert_sth->finish; +} 1; From 93457d17d7be04792b2cf1dee1c067602856da4c Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 22 May 2025 15:04:43 -0400 Subject: [PATCH 108/113] Fix: Handle undefined email address in validation --- Bugzilla/Config/Common.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/Config/Common.pm b/Bugzilla/Config/Common.pm index 14d72115a5..f1388a240f 100644 --- a/Bugzilla/Config/Common.pm +++ b/Bugzilla/Config/Common.pm @@ -79,7 +79,7 @@ sub check_regexp { sub check_email { my ($value) = @_; my ($address) = Email::Address::XS->parse($value); - if (!$address->is_valid) { + if (defined $address && !$address->is_valid) { return "must be a valid email address."; } return ""; From 87be5ddfd8b5598ed1dd122350240ef15b53d5cd Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 22 May 2025 15:10:58 -0400 Subject: [PATCH 109/113] Fix: Improve email population and validation in DB install --- Bugzilla/Install/DB.pm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Bugzilla/Install/DB.pm b/Bugzilla/Install/DB.pm index a20052c37d..fadd36de32 100644 --- a/Bugzilla/Install/DB.pm +++ b/Bugzilla/Install/DB.pm @@ -4398,6 +4398,11 @@ sub _copy_valid_emails_to_profiles_emails { my $dbh = Bugzilla->dbh; my ($total) = $dbh->selectrow_array("SELECT COUNT(*) FROM profiles"); + unless ($total) { + print "Skipping profiles_emails population: no profiles to process.\n"; + return; + } + print "Populating profiles_emails table. There are $total emails to process.\n"; my $select_sth = $dbh->prepare('SELECT userid, email, login_name FROM profiles'); @@ -4420,9 +4425,9 @@ sub _copy_valid_emails_to_profiles_emails { my $login = $row->{login_name}; my $valid_email; - if (validate_email_syntax($email)) { + if (defined $email && $email ne '' && validate_email_syntax($email)) { $valid_email = $email; - } elsif (validate_email_syntax($login)) { + } elsif (defined $login && $login ne '' && validate_email_syntax($login)) { $valid_email = $login; } From c2852abdc590619de3d673393de82142d52550f2 Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 22 May 2025 16:00:19 -0400 Subject: [PATCH 110/113] Refactor: Handle optional 'email' column in profiles table during DB install --- Bugzilla/Install/DB.pm | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Bugzilla/Install/DB.pm b/Bugzilla/Install/DB.pm index fadd36de32..7254407221 100644 --- a/Bugzilla/Install/DB.pm +++ b/Bugzilla/Install/DB.pm @@ -4403,9 +4403,18 @@ sub _copy_valid_emails_to_profiles_emails { return; } - print "Populating profiles_emails table. There are $total emails to process.\n"; + # Check if 'email' column exists in 'profiles' + my $columns = $dbh->selectcol_arrayref( + "SHOW COLUMNS FROM profiles LIKE 'email'" + ); + my $has_email_column = scalar(@$columns) > 0; + + # Build SELECT statement dynamically + my $select_sql = 'SELECT userid, login_name'; + $select_sql .= ', email' if $has_email_column; + $select_sql .= ' FROM profiles'; - my $select_sth = $dbh->prepare('SELECT userid, email, login_name FROM profiles'); + my $select_sth = $dbh->prepare($select_sql); my $check_sth = $dbh->prepare('SELECT 1 FROM profiles_emails WHERE user_id = ?'); my $insert_sth = $dbh->prepare(' INSERT INTO profiles_emails (user_id, email, is_primary_email, display_order) @@ -4421,7 +4430,7 @@ sub _copy_valid_emails_to_profiles_emails { $check_sth->execute($user_id); next if $check_sth->fetchrow_array; - my $email = $row->{email}; + my $email = $has_email_column ? $row->{email} : undef; my $login = $row->{login_name}; my $valid_email; From e33ec457d6baeb730ca8b5e8ce4e6c1ebfb60e3e Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 22 May 2025 17:31:18 -0400 Subject: [PATCH 111/113] Fix: Log 'unknown' if remote IP is not available during user creation audit --- extensions/BMO/Extension.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/BMO/Extension.pm b/extensions/BMO/Extension.pm index ff587d4785..2da60905dd 100644 --- a/extensions/BMO/Extension.pm +++ b/extensions/BMO/Extension.pm @@ -967,7 +967,7 @@ sub object_end_of_create { my $user = $args->{object}; # Log real IP addresses for auditing - Bugzilla->audit(sprintf('<%s> created user %s', remote_ip(), $user->login)); + Bugzilla->audit(sprintf('<%s> created user %s', remote_ip() || 'unknown', $user->login)); # Add default searches to new user's footer my $dbh = Bugzilla->dbh; From 1880bfec43000c62f56a0ba03cffd421cdcdcac1 Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 12 Jun 2025 14:49:14 -0400 Subject: [PATCH 112/113] Removed tabs to resolve whitespace error from test file --- Bugzilla/Auth/Verify.pm | 8 ++++---- Bugzilla/User.pm | 2 +- template/en/default/account/auth/login.html.tmpl | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Bugzilla/Auth/Verify.pm b/Bugzilla/Auth/Verify.pm index 6ceff31321..c305dd8738 100644 --- a/Bugzilla/Auth/Verify.pm +++ b/Bugzilla/Auth/Verify.pm @@ -65,7 +65,7 @@ sub create_or_update_user { failure => AUTH_ERROR, error => "extern_id_conflict", details => - {extern_id => $extern_id, extern_user => $extern_name, username => $login} + {extern_id => $extern_id, extern_user => $extern_name, username => $login} }; } @@ -86,9 +86,9 @@ sub create_or_update_user { # that is too involved to be done right now. my $user = Bugzilla::User->create({ login_name => $login, - email => $email, - cryptpassword => $password, - realname => $real_name}); + email => $email, + cryptpassword => $password, + realname => $real_name}); $login_user_id = $user->id; } diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index 28ff779aa2..d817dacaf2 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -162,7 +162,7 @@ sub new { my $user_id = Bugzilla::User::Email->get_user_by_email($email); if ($user_id) { $param->{id} = $user_id; - delete $param->{name}; + delete $param->{name}; } } } diff --git a/template/en/default/account/auth/login.html.tmpl b/template/en/default/account/auth/login.html.tmpl index 0a4d4d643a..88770ae0a7 100644 --- a/template/en/default/account/auth/login.html.tmpl +++ b/template/en/default/account/auth/login.html.tmpl @@ -47,7 +47,7 @@
Your real namex:Your real name:
Your login name: + [% IF user.authorizer.can_change_login %] + + [% ELSE %] + [% user.login FILTER html %] + [% END %] +
Your current password is required to - confirm [% can_change.join(' or ') FILTER html %] - changes. + confirm password changes.
Pending email address:[% new_login_name FILTER html %]
Change request expires:[% login_change_date FILTER time %]
Confirmed email address:[% user.login FILTER html %]
Completion date:[% login_change_date FILTER time %]
New email address: - - [% INCLUDE "mfa/protected.html.tmpl" %] -
Current password: From e9cdb7a6df10c608c4da2a750bc3b267262b3122 Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 2 Apr 2025 19:38:03 -0400 Subject: [PATCH 003/113] Added new user errors and save new_login to userprefs.cgi --- template/en/default/global/user-error.html.tmpl | 13 +++++++++++++ userprefs.cgi | 16 +++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index bec1d067f0..69ab78eaab 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -1239,6 +1239,19 @@ [% 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" %] + New login names may not contain the "@" sign + + [% 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" %] You can't use %user% without being logged in, because %user% refers diff --git a/userprefs.cgi b/userprefs.cgi index d7a5eb146a..b65c251087 100755 --- a/userprefs.cgi +++ b/userprefs.cgi @@ -84,6 +84,7 @@ sub SaveAccount { my $oldpassword = $cgi->param('old_password'); my $pwd1 = $cgi->param('new_password1'); my $pwd2 = $cgi->param('new_password2'); + my $new_login = clean_text(scalar $cgi->param('new_login')); my $new_login_name = trim($cgi->param('new_login_name')); my @mfa_events; @@ -120,7 +121,20 @@ sub SaveAccount { } } } - + + if ($user->authorizer->can_change_login + && $new_login + && $user->login ne $new_login) + { + + if ($new_login =~ /@/) + { + ThrowUserError("login_at_sign_disallowed"); + } + + $user->set_login($new_login); + } + if ( $user->authorizer->can_change_email && Bugzilla->params->{"allowemailchange"} && $new_login_name) From b4e10d88fef68195128a261be24db27d842add9c Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 2 Apr 2025 19:58:02 -0400 Subject: [PATCH 004/113] Added error check, login_change_during_email_change --- userprefs.cgi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/userprefs.cgi b/userprefs.cgi index b65c251087..30e5a3a031 100755 --- a/userprefs.cgi +++ b/userprefs.cgi @@ -131,6 +131,10 @@ sub SaveAccount { { ThrowUserError("login_at_sign_disallowed"); } + + if (Bugzilla::Token::HasEmailChangeToken($user->id)) { + ThrowUserError("login_change_during_email_change"); + } $user->set_login($new_login); } From 43a556657a9ee80211b5be9c914dde8508a3d053 Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 4 Apr 2025 12:00:49 -0400 Subject: [PATCH 005/113] updated small login field --- template/en/default/account/auth/login-small.html.tmpl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/template/en/default/account/auth/login-small.html.tmpl b/template/en/default/account/auth/login-small.html.tmpl index 201d0cb99e..6b27d00989 100644 --- a/template/en/default/account/auth/login-small.html.tmpl +++ b/template/en/default/account/auth/login-small.html.tmpl @@ -53,11 +53,13 @@ class="bz_login" name="Bugzilla_login" title="Login" - placeholder="Email" - aria-label="Email" - type="email" + placeholder="Email or loginname" + aria-label="Email or loginname" + type="text" required + pattern="^[^\s@]+@[^\s@]+\.[^\s@]+$|^[^\s@]+$" > + Date: Fri, 4 Apr 2025 12:23:22 -0400 Subject: [PATCH 006/113] changed loginname to login in placeholder --- template/en/default/account/auth/login-small.html.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/template/en/default/account/auth/login-small.html.tmpl b/template/en/default/account/auth/login-small.html.tmpl index 6b27d00989..345461a2eb 100644 --- a/template/en/default/account/auth/login-small.html.tmpl +++ b/template/en/default/account/auth/login-small.html.tmpl @@ -53,8 +53,8 @@ class="bz_login" name="Bugzilla_login" title="Login" - placeholder="Email or loginname" - aria-label="Email or loginname" + placeholder="Email or login" + aria-label="Email or login" type="text" required pattern="^[^\s@]+@[^\s@]+\.[^\s@]+$|^[^\s@]+$" From 3ceeed923ef980542a4cdbadb08b8d7c428c4ce4 Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 4 Apr 2025 12:25:35 -0400 Subject: [PATCH 007/113] Updated login input --- template/en/default/account/auth/login.html.tmpl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/template/en/default/account/auth/login.html.tmpl b/template/en/default/account/auth/login.html.tmpl index 53ea9b283d..0a4d4d643a 100644 --- a/template/en/default/account/auth/login.html.tmpl +++ b/template/en/default/account/auth/login.html.tmpl @@ -38,18 +38,22 @@ [% USE Bugzilla %]

- I need an email address and password to continue. + I need an email/login and password to continue.

Request blocking: + + +
Request blocking: + + +
Request blocking: - - -
Request blocking: - - -
Request blocking: + + +
Request blocking: - - -
Request blocking: + + +
Request blocking: - - -
Pending email address:[% new_login_name FILTER html %]
Change request expires:[% login_change_date FILTER time %]
Confirmed email address:[% user.login FILTER html %]
Completion date:[% login_change_date FILTER time %]
Primary email address: + + [% INCLUDE "mfa/protected.html.tmpl" %] +

Pending email address:Pending primary email address: [% new_login_name FILTER html %]
Confirmed email address:Confirmed primary email address: [% user.login FILTER html %]
Secondary email address: + + [% INCLUDE "mfa/protected.html.tmpl" %] +
Primary email address: - + + + [% INCLUDE "mfa/protected.html.tmpl" %]
Secondary email address: + + [% INCLUDE "mfa/protected.html.tmpl" %]
Primary email address:Email addresses: - - - +
+ +
+

[% INCLUDE "mfa/protected.html.tmpl" %]
Secondary email address: - - - - [% INCLUDE "mfa/protected.html.tmpl" %] -
Email addresses: -
- +
+
-

+

[% INCLUDE "mfa/protected.html.tmpl" %]


From 50b6e718ff810110e3074b31b67b318ece0cb56e Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 5 May 2025 09:22:00 -0400 Subject: [PATCH 047/113] Added display_order constants --- Bugzilla/User/Email.pm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index d10943d7a1..7f4fd24c81 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -27,12 +27,14 @@ use constant DB_COLUMNS => qw( profiles_emails.user_id profiles_emails.email profiles_emails.is_primary_email + profiles_emails.display_order ); use constant VALIDATORS => { user_id => \&_check_user_id, email => \&_check_email, is_primary_email => \&Bugzilla::Object::check_boolean, + display_order => \&Bugzilla::Object::check_boolean, }; use constant UPDATE_COLUMNS => qw(email is_primary_email display_order); @@ -54,6 +56,7 @@ sub is_primary_email { return $_[0]->{'is_primary_email'}; } sub set_email { $_[0]->set('email', $_[1]); } sub set_primary_email { $_[0]->set('is_primary_email', $_[1]); } +sub set_display_order { $_[0]->set('display_order', $_[1]); } ############################### #### Constructors ##### From 2a3a8a300236e73c3313f5fff72f809c6eb04b92 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 5 May 2025 10:34:28 -0400 Subject: [PATCH 048/113] Fixed check_email validator --- Bugzilla/User/Email.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index 7f4fd24c81..36a696c310 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -101,7 +101,7 @@ sub _check_user_id { return Bugzilla::User->check({id => $id})->id; } -sub _check_email { return validate_email_syntax($_[1]); } +sub _check_email { return validate_email_syntax($_[1]) ? $_[1] : 0; } 1; __END__ From 0a34409e1a7d1431dbebafec744fbdf3978666d6 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 5 May 2025 18:55:29 -0400 Subject: [PATCH 049/113] Added find_user_by_email() --- Bugzilla/User/Email.pm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index 36a696c310..c8c3ee5479 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -86,6 +86,15 @@ sub get_user_emails { return $emails_ref || []; } + +sub find_user_by_email { + my ($email) = @_; + my $dbh = Bugzilla->dbh; + my ($user_id) = $dbh->selectrow_array("SELECT user_id FROM profiles_emails WHERE email = ? LIMIT 1", undef, $email); + # We use the defined-or operator because a user_id might be 0 + return $email // 0; +} + sub remove_from_db { my $self = shift; return $self->is_primary_email ? 0 : $self->SUPER::remove_from_db(); From 177fc271dcc9a46637f2093d2419fb794a730bb4 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 5 May 2025 19:16:06 -0400 Subject: [PATCH 050/113] Renamed subroutine --- Bugzilla/User/Email.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index c8c3ee5479..cc19473acb 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -78,7 +78,7 @@ sub update { return $updated_email; } -sub get_user_emails { +sub get_emails_by_user { my ($user_id) = @_; my $dbh = Bugzilla->dbh; my $emails_ref = $dbh->selectall_arrayref("SELECT email, is_primary_email, display_order FROM profiles_emails WHERE user_id = ?", From e4ca9a401cdd7591851451b5d71db1c2eba366c8 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 5 May 2025 19:21:51 -0400 Subject: [PATCH 051/113] Renamed subroutine for parity --- Bugzilla/User/Email.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index cc19473acb..f383e4874f 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -87,7 +87,7 @@ sub get_emails_by_user { } -sub find_user_by_email { +sub get_user_by_email { my ($email) = @_; my $dbh = Bugzilla->dbh; my ($user_id) = $dbh->selectrow_array("SELECT user_id FROM profiles_emails WHERE email = ? LIMIT 1", undef, $email); From 8f4e0abd29275e1e4e138d0ab466f9a259e4b426 Mon Sep 17 00:00:00 2001 From: topunix Date: Mon, 5 May 2025 20:03:04 -0400 Subject: [PATCH 052/113] Converted to methods --- Bugzilla/User/Email.pm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index f383e4874f..3a683239af 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -79,16 +79,15 @@ sub update { } sub get_emails_by_user { - my ($user_id) = @_; + my ($class, $user_id) = @_; my $dbh = Bugzilla->dbh; my $emails_ref = $dbh->selectall_arrayref("SELECT email, is_primary_email, display_order FROM profiles_emails WHERE user_id = ?", undef, $user_id); return $emails_ref || []; } - sub get_user_by_email { - my ($email) = @_; + my ($class, $email) = @_; my $dbh = Bugzilla->dbh; my ($user_id) = $dbh->selectrow_array("SELECT user_id FROM profiles_emails WHERE email = ? LIMIT 1", undef, $email); # We use the defined-or operator because a user_id might be 0 From ec0ffabb38440aa5890b53f983fa7bf0092d957c Mon Sep 17 00:00:00 2001 From: topunix Date: Wed, 7 May 2025 07:10:11 -0400 Subject: [PATCH 053/113] Added new(), validator, and name_field --- Bugzilla/User/Email.pm | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index 3a683239af..6126e7516f 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -15,26 +15,28 @@ use base qw(Bugzilla::Object); use Bugzilla::Constants; use Bugzilla::Util; +use Scalar::Util qw(looks_like_number); ############# # Constants # ############# use constant DB_TABLE => 'profiles_emails'; +use constant NAME_FIELD => 'email'; use constant DB_COLUMNS => qw( - profiles_emails.id - profiles_emails.user_id - profiles_emails.email - profiles_emails.is_primary_email - profiles_emails.display_order + id + user_id + email + is_primary_email + display_order ); use constant VALIDATORS => { user_id => \&_check_user_id, email => \&_check_email, is_primary_email => \&Bugzilla::Object::check_boolean, - display_order => \&Bugzilla::Object::check_boolean, + display_order => \&_check_display_order, }; use constant UPDATE_COLUMNS => qw(email is_primary_email display_order); @@ -62,6 +64,14 @@ sub set_display_order { $_[0]->set('display_order', $_[1]); } #### Constructors ##### ############################### +sub new { + my ($class, $params) = @_; + my $email = $class->SUPER::new($params); + + # Return the newly created user email account. + return $email; +} + sub create { my ($class, $params) = @_; my $user_email = $class->SUPER::create($params); @@ -72,7 +82,7 @@ sub create { sub update { my ($class, $params) = @_; - my $updated_email = $class->SUPER::update($params); + my $updated_email = $class->SUPER::update(); # Return the updated user email account. return $updated_email; @@ -110,6 +120,21 @@ sub _check_user_id { } sub _check_email { return validate_email_syntax($_[1]) ? $_[1] : 0; } + +sub _check_display_order { + my ($invocant, $value) = @_; + + unless (defined $value && looks_like_number($value)) { + return 0; + } + if ($value == int($value) && $value >= 1) { + return $value; + } else { + return 0; + } +} + + 1; __END__ From dcc01f64fd66252830f20088ca9e4434c744d957 Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 8 May 2025 22:33:59 -0400 Subject: [PATCH 054/113] Added install_admin_get_login_name --- template/en/default/global/messages.html.tmpl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/template/en/default/global/messages.html.tmpl b/template/en/default/global/messages.html.tmpl index ce0b31cac1..1329ca5cbc 100644 --- a/template/en/default/global/messages.html.tmpl +++ b/template/en/default/global/messages.html.tmpl @@ -684,6 +684,9 @@ [% title = BLOCK %]Flag Type '[% flag_type.name FILTER html %]' Deactivated[% END %] The flag type [% flag_type.name FILTER html %] has been deactivated. + [% ELSIF message_tag == "install_admin_get_login_name" %] + Enter the login name of the administrator: + [% ELSIF message_tag == "install_admin_get_email" %] Enter the e-mail address of the administrator: From c6ff94db7388bb6c2fd7207554761857b18a585e Mon Sep 17 00:00:00 2001 From: topunix Date: Thu, 8 May 2025 23:32:35 -0400 Subject: [PATCH 055/113] Added email_exists --- template/en/default/global/user-error.html.tmpl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index 18342b4ae3..4429a37721 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -560,6 +560,10 @@ [% title = "Email Address Confirmation Failed" %] Email address confirmation failed. + [% ELSIF error == "email_exists" %] + [% title = "Email Address Already Exists" %] + There is already an account with that email address. + [% ELSIF error == "email_no_text_plain" %] Your message did not contain any text.[% terms.Bugzilla %] does not accept HTML-only email, or HTML email with attachments. From f4847f8c0b93516d8fc83c7c44ce14f17877cb14 Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 9 May 2025 00:26:00 -0400 Subject: [PATCH 056/113] Improved validator --- Bugzilla/User/Email.pm | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index 6126e7516f..ae5e4ba1a7 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -34,7 +34,7 @@ use constant DB_COLUMNS => qw( use constant VALIDATORS => { user_id => \&_check_user_id, - email => \&_check_email, + email => \&check_email_for_creation, is_primary_email => \&Bugzilla::Object::check_boolean, display_order => \&_check_display_order, }; @@ -109,6 +109,8 @@ sub remove_from_db { return $self->is_primary_email ? 0 : $self->SUPER::remove_from_db(); } + + ############################### ### Validators ### ############################### @@ -119,7 +121,18 @@ sub _check_user_id { return Bugzilla::User->check({id => $id})->id; } -sub _check_email { return validate_email_syntax($_[1]) ? $_[1] : 0; } +sub check_email_for_creation { + my ($invocant, $email) = @_; + + validate_email_syntax($email) + || ThrowUserError('illegal_email_address', {addr => $email}); + + if ($invocant->get_user_by_email($email)) { + ThrowUserError('email_exists'); + } + + return $email; +} sub _check_display_order { my ($invocant, $value) = @_; From 567860a4405e745aedf25cccb7d2f304070eb9ad Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 9 May 2025 00:28:15 -0400 Subject: [PATCH 057/113] Added Bugzilla::Error --- Bugzilla/User/Email.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index ae5e4ba1a7..8936f28e51 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -15,6 +15,7 @@ use base qw(Bugzilla::Object); use Bugzilla::Constants; use Bugzilla::Util; +use Bugzilla::Error; use Scalar::Util qw(looks_like_number); ############# From 5cd3cb607130be392e453186f06bb8f4b08ec796 Mon Sep 17 00:00:00 2001 From: topunix Date: Fri, 9 May 2025 00:41:45 -0400 Subject: [PATCH 058/113] Added email to admin install process --- Bugzilla/Install.pm | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Bugzilla/Install.pm b/Bugzilla/Install.pm index c982c072ed..c56700514b 100644 --- a/Bugzilla/Install.pm +++ b/Bugzilla/Install.pm @@ -26,6 +26,7 @@ use Bugzilla::Error; use Bugzilla::Group; use Bugzilla::Product; use Bugzilla::User; +use Bugzilla::User::Email; use Bugzilla::User::Setting; use Bugzilla::Util qw(get_text); use Bugzilla::Version; @@ -420,16 +421,17 @@ sub create_admin { return if $admin_count; my %answer = %{Bugzilla->installation_answers}; - my $login = $answer{'ADMIN_EMAIL'}; + my $login = $answer{'ADMIN_LOGIN_NAME'}; + my $email = $answer{'ADMIN_EMAIL'}; my $password = $answer{'ADMIN_PASSWORD'}; my $full_name = $answer{'ADMIN_REALNAME'}; - if (!$login || !$password || !$full_name) { + if (!$login || !$email || !$password || !$full_name) { print "\n" . get_text('install_admin_setup') . "\n\n"; } while (!$login) { - print get_text('install_admin_get_email') . ' '; + print get_text('install_admin_get_login_name') . ' '; $login = ; chomp $login; eval { Bugzilla::User->check_login_name_for_creation($login); }; @@ -439,6 +441,17 @@ sub create_admin { } } + while (!$email) { + print get_text('install_admin_get_email') . ' '; + $email = ; + chomp $email; + eval { Bugzilla::User::Email->check_email_for_creation($email); }; + if ($@) { + print $@ . "\n"; + undef $email; + } + } + while (!defined $full_name) { print get_text('install_admin_get_name') . ' '; $full_name = ; @@ -453,6 +466,12 @@ sub create_admin { = Bugzilla::User->create({ login_name => $login, realname => $full_name, cryptpassword => $password }); + + # Create email record + Bugzilla::User::Email->create({ + user_id => $admin->id, email => $email, is_primary_email => 1, display_order => 1 + }); + make_admin($admin); } From adf220150916c1ee18c7c71eeb85bee8f5c8ae9e Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 11 May 2025 00:12:54 -0400 Subject: [PATCH 059/113] Fixed bug --- Bugzilla/User/Email.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index 8936f28e51..e7f6df5f09 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -102,7 +102,7 @@ sub get_user_by_email { my $dbh = Bugzilla->dbh; my ($user_id) = $dbh->selectrow_array("SELECT user_id FROM profiles_emails WHERE email = ? LIMIT 1", undef, $email); # We use the defined-or operator because a user_id might be 0 - return $email // 0; + return $user_id // 0; } sub remove_from_db { From 58bde1bacbffde443c6b2748db0ce02cd1de9061 Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 11 May 2025 00:58:14 -0400 Subject: [PATCH 060/113] Fixed comment --- Bugzilla/User/Email.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index e7f6df5f09..e9296d581e 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -69,7 +69,7 @@ sub new { my ($class, $params) = @_; my $email = $class->SUPER::new($params); - # Return the newly created user email account. + # Return the user email account. return $email; } From 4b0e7dcd7830d3864e1ff9279cc2d748b974ee2f Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 11 May 2025 03:23:35 -0400 Subject: [PATCH 061/113] removed comment --- Bugzilla/User/Email.pm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index e9296d581e..1d4da0d6fb 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -67,10 +67,8 @@ sub set_display_order { $_[0]->set('display_order', $_[1]); } sub new { my ($class, $params) = @_; - my $email = $class->SUPER::new($params); - - # Return the user email account. - return $email; + my $user_email = $class->SUPER::new($params); + return $user_email; } sub create { From 0d7d7fb6c8422e824aa148a918a3be731b705404 Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 11 May 2025 04:27:05 -0400 Subject: [PATCH 062/113] Added get_primary_email_of_user() --- Bugzilla/User/Email.pm | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Bugzilla/User/Email.pm b/Bugzilla/User/Email.pm index 1d4da0d6fb..ddcbf6a36d 100644 --- a/Bugzilla/User/Email.pm +++ b/Bugzilla/User/Email.pm @@ -103,6 +103,20 @@ sub get_user_by_email { return $user_id // 0; } +sub get_primary_email_of_user { + my ($class, $user_id) = @_; + my $emails_ref = $class->get_emails_by_user($user_id); + + for my $email_info (@$emails_ref) { + my ($email, $is_primary) = @$email_info; + if ($is_primary == 1) { + return $email; + } + } + + return undef; # No primary email found +} + sub remove_from_db { my $self = shift; return $self->is_primary_email ? 0 : $self->SUPER::remove_from_db(); From 7c60d1724f99b6a93ab1e512216c2be8a5439d07 Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 11 May 2025 04:43:02 -0400 Subject: [PATCH 063/113] Updated email accessor to use Bugzilla::User::Email --- Bugzilla/User.pm | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index b338b847a7..716f933c19 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -345,6 +345,7 @@ sub check_login_name_for_creation { return $name; } + sub _check_password { my ($self, $pass) = @_; @@ -619,7 +620,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 { Bugzilla::User::Email->get_primary_email_of_user($_[0]->{userid});} sub disabledtext { $_[0]->{'disabledtext'}; } sub is_enabled { $_[0]->{'is_enabled'} ? 1 : 0; } sub showmybugslink { $_[0]->{showmybugslink}; } @@ -2589,17 +2590,6 @@ sub create { = _generate_nickname($params->{realname}, $params->{login_name}, 0); my $user = $class->SUPER::create($params); - # Create a user email account - my $email_data = { - user_id => $user->id, - email => $params->{admin_email}, - is_primary_email => 1, - notify => 1, - last_modified => Bugzilla::Util::DateTime::now(), - }; - - my $user_email = Bugzilla::User::Email->create($email_data); - # Turn on all email for the new user require Bugzilla::BugMail; my %relationships = Bugzilla::BugMail::relationships(); From 5e2c5f7f66e3e13f24b5ba28508e18fe79fd7dfe Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 11 May 2025 05:06:28 -0400 Subject: [PATCH 064/113] Replaced email with login_name --- scripts/entrypoint.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/entrypoint.pl b/scripts/entrypoint.pl index dc5facf6a2..a61611c148 100755 --- a/scripts/entrypoint.pl +++ b/scripts/entrypoint.pl @@ -123,14 +123,14 @@ sub cmd_dev_httpd { run( 'perl', 'scripts/generate_bmo_data.pl', '--param' => 'use_mailer_queue=0', - 'admin@bmo.test' + 'admin_bmo_test' ); } require Bugzilla; my $answers = Bugzilla->installation_answers($ENV{BZ_ANSWERS_FILE}); my $BZ_URLBASE = $::ENV{'BMO_urlbase'}; - my $LOGIN_USER = "Admin user: $answers->{'ADMIN_EMAIL'}"; + my $LOGIN_USER = "Admin user: $answers->{'ADMIN_LOGIN_NAME'}"; my $LOGIN_PASS = "Admin password: $answers->{'ADMIN_PASSWORD'}"; print < Date: Sun, 11 May 2025 21:38:35 -0400 Subject: [PATCH 065/113] Revert account.html.tmpl to version from 07ece2b --- .../default/account/prefs/account.html.tmpl | 217 ++---------------- 1 file changed, 15 insertions(+), 202 deletions(-) diff --git a/template/en/default/account/prefs/account.html.tmpl b/template/en/default/account/prefs/account.html.tmpl index 6e877f37e3..43536d6c70 100644 --- a/template/en/default/account/prefs/account.html.tmpl +++ b/template/en/default/account/prefs/account.html.tmpl @@ -23,178 +23,6 @@ # 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) #%] - - - [%# BMO - add hook for displaying user-profile link %] [% Hook.process('start') %] @@ -209,16 +37,6 @@ function reIndexEmailFields() { placeholder="optional, but encouraged">
Your login name: - [% IF user.authorizer.can_change_login %] - - [% ELSE %] - [% user.login FILTER html %] - [% END %] -

+ Your current password is required to + confirm [% can_change.join(' or ') FILTER html %] + changes. +
Pending primary email address:Pending email address: [% new_login_name FILTER html %]
Confirmed primary email address:Confirmed email address: [% user.login FILTER html %]
Email addresses:New email address: -
- -
-

+ [% INCLUDE "mfa/protected.html.tmpl" %]

- Your current password is required to - confirm password changes. -
Current password: From c8c2e96f952d0d607fc27c6744136be28571a183 Mon Sep 17 00:00:00 2001 From: topunix Date: Sun, 11 May 2025 23:15:59 -0400 Subject: [PATCH 066/113] Added login_name and new_email fields --- template/en/default/account/prefs/account.html.tmpl | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/template/en/default/account/prefs/account.html.tmpl b/template/en/default/account/prefs/account.html.tmpl index 43536d6c70..cdc60b587b 100644 --- a/template/en/default/account/prefs/account.html.tmpl +++ b/template/en/default/account/prefs/account.html.tmpl @@ -37,7 +37,16 @@ placeholder="optional, but encouraged">
Your login name: + [% IF user.authorizer.can_change_login %] + + [% ELSE %] + [% user.login FILTER html %] + [% END %] +
New email address: - + [% INCLUDE "mfa/protected.html.tmpl" %]
[% IF editusers %] + id="login" value="[% user.login FILTER html %]"> [% IF editform %] - [% IF !otheruser.in_group('bz_sudo_protect') %] + [% IF !user.in_group('bz_sudo_protect') %]
Impersonate this user + [%- user.login FILTER uri %]">Impersonate this user [% END %] [% END %] [% ELSE %] - [% otheruser.login FILTER html %] + [% user.login FILTER html %] [% END %]
+ [% IF editusers %] + + [% IF editform %] + [% IF !user.in_group('bz_sudo_protect') %] +
+ [% END %] + [% END %] + [% ELSE %] + [% user.email FILTER html %] + [% END %] +
[% IF editusers %] + id="extern_id" value="[% user.extern_id FILTER html %]"> [% ELSE %] - [% otheruser.extern_id FILTER html %] + [% user.extern_id FILTER html %] [% END %]
@@ -79,16 +95,16 @@ [%# if a user's cryptpassword is '*' it means they use an auth provider # such as GitHub, or you can't log in with that account. in either case # forcing a password reset isn't valid %] - [% IF otheruser.cryptpassword != '*' && editform %] + [% IF user.cryptpassword != '*' && editform %]
+ [% " checked" IF user.password_change_required %]>
Password change reason (will be displayed to the user):
[% END %] @@ -101,20 +117,20 @@
+ [% IF user.email_disabled %] checked="checked" [% END %]>
- ( - [% otheruser.bounce_count FILTER html %]) + ( + [% user.bounce_count FILTER html %])
[% IF user.in_group('bz_can_disable_mfa') %] - [% IF otheruser.mfa %] + [% IF user.mfa %]
[% IF editusers %] + id="login" value="[% otheruser.login FILTER html %]"> [% IF editform %] - [% IF !user.in_group('bz_sudo_protect') %] + [% IF !otheruser.in_group('bz_sudo_protect') %]
Impersonate this user + [%- otheruser.login FILTER uri %]">Impersonate this user [% END %] [% END %] [% ELSE %] - [% user.login FILTER html %] + [% otheruser.login FILTER html %] [% END %]
[% IF editusers %] + id="email" value="[% otheruser.email FILTER html %]"> [% IF editform %] - [% IF !user.in_group('bz_sudo_protect') %] + [% IF !otheruser.in_group('bz_sudo_protect') %]
[% END %] [% END %] [% ELSE %] - [% user.email FILTER html %] + [% otheruser.email FILTER html %] [% END %]
[% IF editusers %] + id="extern_id" value="[% otheruser.extern_id FILTER html %]"> [% ELSE %] - [% user.extern_id FILTER html %] + [% otheruser.extern_id FILTER html %] [% END %]
@@ -95,16 +95,16 @@ [%# if a user's cryptpassword is '*' it means they use an auth provider # such as GitHub, or you can't log in with that account. in either case # forcing a password reset isn't valid %] - [% IF user.cryptpassword != '*' && editform %] + [% IF otheruser.cryptpassword != '*' && editform %]
+ [% " checked" IF otheruser.password_change_required %]>
Password change reason (will be displayed to the user):
[% END %] @@ -117,20 +117,20 @@
+ [% IF otheruser.email_disabled %] checked="checked" [% END %]>
( - [% user.bounce_count FILTER html %]) + [% otheruser.bounce_count FILTER html %])
- [% IF user.in_group('bz_can_disable_mfa') %] - [% IF user.mfa %] + [% IF otheruser.in_group('bz_can_disable_mfa') %] + [% IF otheruser.mfa %]