diff options
Diffstat (limited to 'extensions/TagNewUsers/Extension.pm')
-rw-r--r-- | extensions/TagNewUsers/Extension.pm | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/extensions/TagNewUsers/Extension.pm b/extensions/TagNewUsers/Extension.pm new file mode 100644 index 000000000..4b78c7bc0 --- /dev/null +++ b/extensions/TagNewUsers/Extension.pm @@ -0,0 +1,264 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# 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/ +# +# 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 TagNewUsers Extension. +# +# The Initial Developer of the Original Code is the Mozilla Foundation +# Portions created by the Initial Developers are Copyright (C) 2011 the +# Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Byron Jones <bjones@mozilla.com> + +package Bugzilla::Extension::TagNewUsers; +use strict; +use base qw(Bugzilla::Extension); +use Bugzilla::Field; +use Bugzilla::User; +use Bugzilla::Install::Util qw(indicate_progress); +use Date::Parse; +use Scalar::Util qw(blessed); + +# users younger than PROFILE_AGE days will be tagged as new +use constant PROFILE_AGE => 60; + +# users with fewer comments than COMMENT_COUNT will be tagged as new +use constant COMMENT_COUNT => 25; + +our $VERSION = '1'; + +# +# install +# + +sub install_update_db { + my ($self) = @_; + my $dbh = Bugzilla->dbh; + + if (!$dbh->bz_column_info('profiles', 'comment_count')) { + $dbh->bz_add_column('profiles', 'comment_count', + {TYPE => 'INT3', NOTNULL => 1, DEFAULT => 0}); + my $sth = $dbh->prepare('UPDATE profiles SET comment_count=? WHERE userid=?'); + my $ra = $dbh->selectall_arrayref('SELECT who,COUNT(*) FROM longdescs GROUP BY who'); + my $count = 1; + my $total = scalar @$ra; + foreach my $ra_row (@$ra) { + indicate_progress({ current => $count++, total => $total, every => 25 }); + my ($user_id, $count) = @$ra_row; + $sth->execute($count, $user_id); + } + } + + if (!$dbh->bz_column_info('profiles', 'creation_ts')) { + $dbh->bz_add_column('profiles', 'creation_ts', + {TYPE => 'DATETIME'}); + my $creation_date_fieldid = get_field_id('creation_ts'); + my $sth = $dbh->prepare('UPDATE profiles SET creation_ts=? WHERE userid=?'); + my $ra = $dbh->selectall_arrayref(" + SELECT p.userid, a.profiles_when + FROM profiles p + LEFT JOIN profiles_activity a ON a.userid=p.userid + AND a.fieldid=$creation_date_fieldid + "); + my ($now) = Bugzilla->dbh->selectrow_array("SELECT NOW()"); + my $count = 1; + my $total = scalar @$ra; + foreach my $ra_row (@$ra) { + indicate_progress({ current => $count++, total => $total, every => 25 }); + my ($user_id, $when) = @$ra_row; + if (!$when) { + ($when) = $dbh->selectrow_array( + "SELECT bug_when FROM bugs_activity WHERE who=? ORDER BY bug_when " . + $dbh->sql_limit(1), + undef, $user_id + ); + } + if (!$when) { + ($when) = $dbh->selectrow_array( + "SELECT bug_when FROM longdescs WHERE who=? ORDER BY bug_when " . + $dbh->sql_limit(1), + undef, $user_id + ); + } + if (!$when) { + ($when) = $dbh->selectrow_array( + "SELECT creation_ts FROM bugs WHERE reporter=? ORDER BY creation_ts " . + $dbh->sql_limit(1), + undef, $user_id + ); + } + if (!$when) { + $when = $now; + } + + $sth->execute($when, $user_id); + } + } + + if (!$dbh->bz_column_info('profiles', 'first_patch_bug_id')) { + $dbh->bz_add_column('profiles', 'first_patch_bug_id', {TYPE => 'INT3'}); + my $sth_update = $dbh->prepare('UPDATE profiles SET first_patch_bug_id=? WHERE userid=?'); + my $sth_select = $dbh->prepare( + 'SELECT bug_id FROM attachments WHERE submitter_id=? AND ispatch=1 ORDER BY creation_ts ' . $dbh->sql_limit(1) + ); + my $ra = $dbh->selectcol_arrayref('SELECT DISTINCT submitter_id FROM attachments WHERE ispatch=1'); + my $count = 1; + my $total = scalar @$ra; + foreach my $user_id (@$ra) { + indicate_progress({ current => $count++, total => $total, every => 25 }); + $sth_select->execute($user_id); + my ($bug_id) = $sth_select->fetchrow_array; + $sth_update->execute($bug_id, $user_id); + } + } +} + +# +# objects +# + +BEGIN { + *Bugzilla::User::update_comment_count = \&_update_comment_count; + *Bugzilla::User::first_patch_bug_id = \&_first_patch_bug_id; +} + +sub object_columns { + my ($self, $args) = @_; + my ($class, $columns) = @$args{qw(class columns)}; + if ($class->isa('Bugzilla::User')) { + push(@$columns, qw(comment_count creation_ts first_patch_bug_id)); + } +} + +sub object_before_create { + my ($self, $args) = @_; + my ($class, $params) = @$args{qw(class params)}; + if ($class->isa('Bugzilla::User')) { + my ($timestamp) = Bugzilla->dbh->selectrow_array("SELECT NOW()"); + $params->{comment_count} = 0; + $params->{creation_ts} = $timestamp; + } elsif ($class->isa('Bugzilla::Attachment')) { + if ($params->{ispatch} && !Bugzilla->user->first_patch_bug_id) { + Bugzilla->user->first_patch_bug_id($params->{bug}->id); + } + } +} + +sub bug_end_of_create { + Bugzilla->user->update_comment_count(); +} + +sub bug_end_of_update { + Bugzilla->user->update_comment_count(); +} + +sub _update_comment_count { + my $self = shift; + my $dbh = Bugzilla->dbh; + + my $id = $self->id; + my ($count) = $dbh->selectrow_array( + "SELECT COUNT(*) FROM longdescs WHERE who=?", + undef, $id + ); + return if $self->{comment_count} == $count; + $dbh->do( + 'UPDATE profiles SET comment_count=? WHERE userid=?', + undef, $count, $id + ); + $self->{comment_count} = $count; +} + +sub _first_patch_bug_id { + my ($self, $bug_id) = @_; + return $self->{first_patch_bug_id} unless defined $bug_id; + + Bugzilla->dbh->do( + 'UPDATE profiles SET first_patch_bug_id=? WHERE userid=?', + undef, $bug_id, $self->id + ); + $self->{first_patch_bug_id} = $bug_id; +} + +# +# +# + +sub template_before_process { + my ($self, $args) = @_; + my ($vars, $file) = @$args{qw(vars file)}; + if ($file eq 'bug/comments.html.tmpl') { + + # only users in canconfirm will see the new-to-bugzilla tag + return unless Bugzilla->user->in_group('canconfirm'); + + # calculate if each user that has commented on the bug is new + foreach my $comment (@{$vars->{bug}{comments}}) { + my $user = $comment->author; + $user->{is_new} = $self->_user_is_new($user); + } + } +} + +sub _user_is_new { + my ($self, $user) = (shift, shift); + + # if the user can confirm bugs, they are no longer new + return 0 if $user->in_group('canconfirm'); + + # store the age in days, for the 'new to bugzilla' tooltip + my $age = sprintf("%.0f", (time() - str2time($user->{creation_ts})) / 86400); + $user->{creation_age} = $age; + + return + ($user->{comment_count} <= COMMENT_COUNT) + || ($user->{creation_age} <= PROFILE_AGE); +} + +sub mailer_before_send { + my ($self, $args) = @_; + my $email = $args->{email}; + + my ($bug_id) = ($email->header('Subject') =~ /^[^\d]+(\d+)/); + my $changer_login = $email->header('X-Bugzilla-Who'); + my $changed_fields = $email->header('X-Bugzilla-Changed-Fields'); + + if ($bug_id + && $changer_login + && $changed_fields =~ /Attachment Created/) + { + my $changer = Bugzilla::User->new({ name => $changer_login }); + if ($changer + && $changer->first_patch_bug_id + && $changer->first_patch_bug_id == $bug_id) + { + $email->header_set('X-Bugzilla-FirstPatch' => $bug_id); + } + } +} + +sub webservice_user_get { + my ($self, $args) = @_; + my ($webservice, $params, $users) = @$args{qw(webservice params users)}; + + foreach my $user (@$users) { + # Most of the time the hash values are XMLRPC::Data objects + my $email = blessed $user->{'email'} ? $user->{'email'}->value : $user->{'email'}; + if ($email) { + my $user_obj = Bugzilla::User->new({ name => $email }); + $user->{'is_new'} + = $webservice->type('boolean', $self->_user_is_new($user_obj) ? 1 : 0); + } + } +} + +__PACKAGE__->NAME; |