diff --git a/Bugzilla.pm b/Bugzilla.pm index b6e80a934..15314a64f 100644 --- a/Bugzilla.pm +++ b/Bugzilla.pm @@ -592,6 +592,15 @@ sub login $class->set_user($authenticated_user); } + if ($class->sudoer) + { + $class->sudoer->update_last_seen_date(); + } + else + { + $class->user->update_last_seen_date(); + } + return $class->user; } diff --git a/Bugzilla/Auth.pm b/Bugzilla/Auth.pm index 07e48ead0..fb2e010c7 100644 --- a/Bugzilla/Auth.pm +++ b/Bugzilla/Auth.pm @@ -88,7 +88,7 @@ sub login { # Make sure the user isn't disabled. my $user = $login_info->{user}; - if ($user->disabledtext) { + if (!$user->is_enabled) { return $self->_handle_login_result({ failure => AUTH_DISABLED, user => $user }, $type); } diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index 4b7ded037..94f1db77f 100644 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -3247,7 +3247,7 @@ sub get_access_user_list return $dbh->selectall_arrayref(" SELECT p.userid, p.login_name, p.realname FROM profiles p - WHERE p.disabledtext = '' AND p.disable_mail = 0 AND p.userid in (".join(",", @user_ids).") + WHERE p.is_enabled = 1 AND p.disable_mail = 0 AND p.userid in (".join(",", @user_ids).") ORDER BY p.realname"); } diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm index 05d5516f9..5b43345f6 100644 --- a/Bugzilla/DB/Schema.pm +++ b/Bugzilla/DB/Schema.pm @@ -708,6 +708,8 @@ use constant ABSTRACT_SCHEMA => { disable_mail => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, mybugslink => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'TRUE'}, extern_id => {TYPE => 'varchar(255)'}, + is_enabled => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'TRUE'}, + last_seen_date => {TYPE => 'DATETIME'}, ], INDEXES => [ profiles_login_name_idx => {FIELDS => ['login_name'], TYPE => 'UNIQUE'}, diff --git a/Bugzilla/Group.pm b/Bugzilla/Group.pm index 23ce20727..b8a9a0686 100644 --- a/Bugzilla/Group.pm +++ b/Bugzilla/Group.pm @@ -193,7 +193,7 @@ sub users_in_group my $users = Bugzilla::Object::match('Bugzilla::User', { Bugzilla::User->ID_FIELD => [ keys %$res ], - disabledtext => '', + is_enabled => 1, }); for my $user (@$users) { diff --git a/Bugzilla/Install/DB.pm b/Bugzilla/Install/DB.pm index d8a2692be..151c80f11 100644 --- a/Bugzilla/Install/DB.pm +++ b/Bugzilla/Install/DB.pm @@ -609,6 +609,12 @@ sub update_table_definitions # 2009-05-07 ghendricks@novell.com - Bug 77193 _add_isactive_to_product_fields(); + # 2011-06-15 dkl@mozilla.com - Bug 658929 + _migrate_disabledtext_boolean(); + + # 2011-11-01 glob@mozilla.com - Bug 240437 + $dbh->bz_add_column('profiles', 'last_seen_date', {TYPE => 'DATETIME'}); + # New product fields $dbh->bz_add_column('products', wiki_url => {TYPE => 'varchar(255)', NOTNULL => 1, DEFAULT => "''"}); $dbh->bz_add_column('products', notimetracking => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 0}); @@ -3668,6 +3674,16 @@ sub _add_isactive_to_product_fields { $dbh->bz_add_column('milestones', 'isactive', {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'TRUE'}); } +sub _migrate_disabledtext_boolean { + my $dbh = Bugzilla->dbh; + if (!$dbh->bz_column_info('profiles', 'is_enabled')) { + $dbh->bz_add_column("profiles", 'is_enabled', + {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'TRUE'}); + $dbh->do("UPDATE profiles SET is_enabled = 0 + WHERE disabledtext != ''"); + } +} + # Fill 'fieldvaluecontrol' table when upgrading a stock Bugzilla installation sub _make_fieldvaluecontrol { diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index 36329287e..453fe06f8 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -80,6 +80,7 @@ use constant DEFAULT_USER => { 'showmybugslink' => 0, 'disabledtext' => '', 'disable_mail' => 0, + 'is_enabled' => 1, }; my $SUPERUSER = {}; @@ -97,6 +98,8 @@ use constant DB_COLUMNS => ( 'profiles.mybugslink AS showmybugslink', 'profiles.disabledtext', 'profiles.disable_mail', + 'profiles.is_enabled', + 'profiles.last_seen_date', ); use constant NAME_FIELD => 'login_name'; use constant ID_FIELD => 'userid'; @@ -110,6 +113,7 @@ use constant VALIDATORS => { disabledtext => \&_check_disabledtext, login_name => \&check_login_name_for_creation, realname => \&_check_realname, + extern_id => \&_check_extern_id, }; sub UPDATE_COLUMNS { @@ -119,6 +123,8 @@ sub UPDATE_COLUMNS { disabledtext login_name realname + extern_id + is_enabled ); push(@cols, 'cryptpassword') if exists $self->{cryptpassword}; return @cols; @@ -160,8 +166,20 @@ sub is_super_user return $self eq $SUPERUSER; } -sub update { +sub create +{ my $self = shift; + my ($params) = @_; + $params->{is_enabled} = !defined $params->{disabledtext} || $params->{disabledtext} eq ''; + $self->SUPER::create($params); +} + +sub update +{ + my $self = shift; + + $self->{is_enabled} = !defined $self->{disabledtext} || $self->{disabledtext} eq ''; + my $changes = $self->SUPER::update(@_); my $dbh = Bugzilla->dbh; @@ -190,6 +208,22 @@ sub update { sub _check_disable_mail { return $_[1] ? 1 : 0; } sub _check_disabledtext { return trim($_[1]) || ''; } +# Check whether the extern_id is unique. +sub _check_extern_id { + my ($invocant, $extern_id) = @_; + $extern_id = trim($extern_id); + return undef unless defined($extern_id) && $extern_id ne ""; + if (!ref($invocant) || $invocant->extern_id ne $extern_id) { + my $existing_login = $invocant->new({ extern_id => $extern_id }); + if ($existing_login) { + ThrowUserError( 'extern_id_exists', + { extern_id => $extern_id, + existing_login_name => $existing_login->login }); + } + } + return $extern_id; +} + # This is public since createaccount.cgi needs to use it before issuing # a token for account creation. sub check_login_name_for_creation { @@ -245,6 +279,15 @@ sub set_name { sub set_password { $_[0]->set('cryptpassword', $_[1]); } +sub update_last_seen_date { + my $self = shift; + return unless $self->id; + my $dbh = Bugzilla->dbh; + Bugzilla->dbh->do( + 'UPDATE profiles SET last_seen_date = NOW() WHERE userid = ?', + undef, $self->id + ); +} ################################################################################ # Methods @@ -254,11 +297,12 @@ sub set_password { $_[0]->set('cryptpassword', $_[1]); } sub name { $_[0]->{realname}; } sub login { $_[0]->{login_name}; } sub email { $_[0]->login . Bugzilla->params->{'emailsuffix'}; } -sub disabledtext { $_[0]->{'disabledtext'}; } -sub is_disabled { $_[0]->disabledtext ? 1 : 0; } +sub disabledtext { $_[0]->{disabledtext}; } +sub is_enabled { $_[0]->{is_enabled} } sub showmybugslink { $_[0]->{showmybugslink}; } sub email_disabled { $_[0]->{disable_mail}; } sub email_enabled { !($_[0]->{disable_mail}); } +sub last_seen_date { $_[0]->{last_seen_date}; } sub cryptpassword { my $self = shift; # We don't store it because we never want it in the object (we @@ -1165,7 +1209,7 @@ sub match { "AND group_id IN(" . join(', ', (-1, @{$user->visible_groups_inherited})) . ") "; } - $query .= " AND disabledtext = '' " if $exclude_disabled; + $query .= " AND is_enabled = 1 " if $exclude_disabled; $query .= $dbh->sql_limit($limit) if $limit; # Execute the query, retrieve the results, and make them into @@ -1210,7 +1254,7 @@ sub match { if (Bugzilla->params->{'usevisibilitygroups'}) { $query .= " AND isbless = 0 AND group_id IN(" . join(', ', (-1, @{$user->visible_groups_inherited})) . ") "; } - $query .= " AND disabledtext = '' " if $exclude_disabled; + $query .= " AND is_enabled = 1 " if $exclude_disabled; $query .= $dbh->sql_limit($limit) if $limit; my $user_ids = $dbh->selectcol_arrayref($query, undef, @bind); @users = @{Bugzilla::User->new_from_list($user_ids)}; @@ -1677,7 +1721,7 @@ sub get_userlist " ON user_group_map.user_id = userid AND isbless = 0" . " AND group_id IN (" . join(', ', -1, @{$self->visible_groups_inherited}) . ")" : " 1 FROM profiles"). - " WHERE disabledtext = '' ". + " WHERE is_enabled = 1 ". $dbh->sql_group_by('userid', 'login_name, realname'); my $sth = $dbh->prepare($query); diff --git a/Bugzilla/WebService/User.pm b/Bugzilla/WebService/User.pm index fd9bac149..888dce22a 100644 --- a/Bugzilla/WebService/User.pm +++ b/Bugzilla/WebService/User.pm @@ -221,7 +221,7 @@ sub get { real_name => $self->type('string', $_->name), name => $self->type('string', $_->login), email => $self->type('string', $_->email), - can_login => $self->type('boolean', $_->is_disabled ? 0 : 1), + can_login => $self->type('boolean', $_->is_enabled), email_enabled => $self->type('boolean', $_->email_enabled), login_denied_text => $self->type('string', $_->disabledtext), }} @$in_group; @@ -233,7 +233,7 @@ sub get { real_name => $self->type('string', $_->name), name => $self->type('string', $_->login), email => $self->type('string', $_->email), - can_login => $self->type('boolean', $_->is_disabled ? 0 : 1), + can_login => $self->type('boolean', $_->is_enabled), }} @$in_group; } diff --git a/editusers.cgi b/editusers.cgi index 9ca85fb1a..c1849e01f 100755 --- a/editusers.cgi +++ b/editusers.cgi @@ -76,7 +76,8 @@ if ($action eq 'search') { my $matchstr = $cgi->param('matchstr'); my $matchtype = $cgi->param('matchtype'); my $grouprestrict = $cgi->param('grouprestrict') || '0'; - my $query = 'SELECT DISTINCT userid, login_name, realname, disabledtext ' . + 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; diff --git a/show-mail-groups.cgi b/show-mail-groups.cgi index cfd415364..39a2810ff 100755 --- a/show-mail-groups.cgi +++ b/show-mail-groups.cgi @@ -1,5 +1,6 @@ #!/usr/bin/perl -wT # CustIS Bug 12253 +# FIXME: Move somewhere or remove hardcode Группа% use strict; use lib qw(. lib); diff --git a/template/en/default/admin/users/edit.html.tmpl b/template/en/default/admin/users/edit.html.tmpl index 3efa4b8bf..147510b05 100644 --- a/template/en/default/admin/users/edit.html.tmpl +++ b/template/en/default/admin/users/edit.html.tmpl @@ -107,6 +107,17 @@ [% END %] + + + Last Login: + + [% IF otheruser.last_seen_date %] + [% otheruser.last_seen_date FILTER html %] + [% ELSE %] + never + [% END %] + +

diff --git a/template/en/default/admin/users/list.html.tmpl b/template/en/default/admin/users/list.html.tmpl index cb05e827b..ab28205ad 100644 --- a/template/en/default/admin/users/list.html.tmpl +++ b/template/en/default/admin/users/list.html.tmpl @@ -42,6 +42,9 @@ {name => 'realname' heading => 'Real name' } + {name => 'last_seen_date' + heading => 'Last Login' + } {heading => 'Account History' content => 'View' contentlink => 'editusers.cgi?action=activity' _ @@ -69,7 +72,7 @@ [% FOREACH thisuser = users %] [% IF !thisuser.realname %] [%# We cannot pass one class now and one class later. %] - [% SET classes = (thisuser.disabledtext ? "bz_inactive missing" : "missing") %] + [% SET classes = (thisuser.is_enabled ? "missing" : "bz_inactive missing") %] [% overrides.realname.login_name.${thisuser.login_name} = { content => "missing" override_content => 1 @@ -77,7 +80,7 @@ override_class => 1 } %] - [% ELSIF thisuser.disabledtext %] + [% ELSIF !thisuser.is_enabled %] [% overrides.realname.login_name.${thisuser.login_name} = { class => "bz_inactive" override_class => 1 @@ -85,7 +88,7 @@ %] [% END %] - [% IF thisuser.disabledtext %] + [% IF !thisuser.is_enabled %] [% overrides.login_name.login_name.${thisuser.login_name} = { class => "bz_inactive" override_class => 1 diff --git a/token.cgi b/token.cgi index fc7ba7bc5..5175528f0 100755 --- a/token.cgi +++ b/token.cgi @@ -114,7 +114,7 @@ if ( $action eq 'reqpw' ) { $user_account = Bugzilla::User->check($login_name); # Make sure the user account is active. - if ($user_account->is_disabled) { + if (!$user_account->is_enabled) { ThrowUserError('account_disabled', {disabled_reason => get_text('account_disabled', {account => $login_name})}); }