From 120b63d507a3316666b25494bc890a024948aef8 Mon Sep 17 00:00:00 2001 From: Max Kanat-Alexander Date: Mon, 15 Feb 2010 15:22:55 -0800 Subject: Bug 372979: Make voting into an extension r=mkanat, a=mkanat, a=LpSolit --- .bzrignore | 1 - Bugzilla/Bug.pm | 158 +--- Bugzilla/BugMail.pm | 11 +- Bugzilla/Comment.pm | 2 +- Bugzilla/Config/BugFields.pm | 6 - Bugzilla/Constants.pm | 8 +- Bugzilla/DB/Schema.pm | 27 - Bugzilla/Field.pm | 1 - Bugzilla/Install/DB.pm | 54 +- Bugzilla/Object.pm | 3 +- Bugzilla/Product.pm | 147 ---- Bugzilla/Search.pm | 18 +- Bugzilla/Search/Quicksearch.pm | 18 - Bugzilla/WebService/Bug.pm | 10 +- buglist.cgi | 18 - bugzilla.dtd | 3 +- colchange.cgi | 3 - contrib/merge-users.pl | 1 - docs/en/images/bzLifecycle.xml | 3 +- editproducts.cgi | 22 +- editusers.cgi | 4 - extensions/Voting/Extension.pm | 861 +++++++++++++++++++++ .../account/prefs/email-relationships.html.tmpl | 22 + .../hook/admin/products/edit-common-rows.html.tmpl | 60 ++ .../hook/admin/products/updated-changes.html.tmpl | 102 +++ .../admin/sanitycheck/messages-statuses.html.tmpl | 40 + .../admin/users/confirm-delete-warn_safe.html.tmpl | 38 + .../hook/bug/edit-after_importance.html.tmpl | 41 + .../default/hook/bug/format_comment-type.txt.tmpl | 23 + .../hook/bug/process/header-title.html.tmpl | 24 + .../hook/bug/process/results-title.html.tmpl | 21 + .../default/hook/global/field-descs-end.none.tmpl | 22 + .../default/hook/global/reason-descs-end.none.tmpl | 23 + .../hook/global/user-error-errors.html.tmpl | 55 ++ .../hook/search/form-email_numbering_end.html.tmpl | 31 + .../search-report-select-rep_fields.html.tmpl | 21 + .../template/en/default/pages/voting.html.tmpl | 69 ++ .../template/en/default/pages/voting/bug.html.tmpl | 61 ++ .../en/default/pages/voting/user.html.tmpl | 185 +++++ .../en/default/voting/delete-all.html.tmpl | 51 ++ .../en/default/voting/votes-removed.txt.tmpl | 55 ++ extensions/Voting/web/style.css | 24 + importxml.pl | 1 - process_bug.cgi | 15 - query.cgi | 2 +- report.cgi | 1 - sanitycheck.cgi | 108 +-- skins/standard/show_bug.css | 3 +- skins/standard/voting.css | 24 - template/en/default/account/prefs/email.html.tmpl | 55 +- .../en/default/admin/params/bugfields.html.tmpl | 5 - .../en/default/admin/products/create.html.tmpl | 3 - .../default/admin/products/edit-common.html.tmpl | 33 +- template/en/default/admin/products/list.html.tmpl | 17 +- .../en/default/admin/products/updated.html.tmpl | 84 +- .../default/admin/sanitycheck/messages.html.tmpl | 25 - .../default/admin/users/confirm-delete.html.tmpl | 23 +- template/en/default/bug/edit.html.tmpl | 19 +- template/en/default/bug/format_comment.txt.tmpl | 4 +- template/en/default/bug/process/header.html.tmpl | 4 +- template/en/default/bug/process/results.html.tmpl | 3 +- template/en/default/bug/votes/delete-all.html.tmpl | 51 -- .../en/default/bug/votes/list-for-bug.html.tmpl | 60 -- .../en/default/bug/votes/list-for-user.html.tmpl | 185 ----- template/en/default/email/newchangedmail.txt.tmpl | 37 +- template/en/default/email/votes-removed.txt.tmpl | 55 -- template/en/default/filterexceptions.pl | 16 - template/en/default/global/field-descs.none.tmpl | 1 - template/en/default/global/reason-descs.none.tmpl | 40 + .../en/default/global/site-navigation.html.tmpl | 7 +- template/en/default/global/user-error.html.tmpl | 39 - template/en/default/list/list.rdf.tmpl | 2 +- template/en/default/pages/voting.html.tmpl | 69 -- template/en/default/search/form.html.tmpl | 23 +- template/en/default/search/search-help.html.tmpl | 3 - .../default/search/search-report-select.html.tmpl | 4 +- template/en/default/sidebar.xul.tmpl | 3 - votes.cgi | 346 +-------- 78 files changed, 2005 insertions(+), 1712 deletions(-) create mode 100644 extensions/Voting/Extension.pm create mode 100644 extensions/Voting/template/en/default/hook/account/prefs/email-relationships.html.tmpl create mode 100644 extensions/Voting/template/en/default/hook/admin/products/edit-common-rows.html.tmpl create mode 100644 extensions/Voting/template/en/default/hook/admin/products/updated-changes.html.tmpl create mode 100644 extensions/Voting/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl create mode 100644 extensions/Voting/template/en/default/hook/admin/users/confirm-delete-warn_safe.html.tmpl create mode 100644 extensions/Voting/template/en/default/hook/bug/edit-after_importance.html.tmpl create mode 100644 extensions/Voting/template/en/default/hook/bug/format_comment-type.txt.tmpl create mode 100644 extensions/Voting/template/en/default/hook/bug/process/header-title.html.tmpl create mode 100644 extensions/Voting/template/en/default/hook/bug/process/results-title.html.tmpl create mode 100644 extensions/Voting/template/en/default/hook/global/field-descs-end.none.tmpl create mode 100644 extensions/Voting/template/en/default/hook/global/reason-descs-end.none.tmpl create mode 100644 extensions/Voting/template/en/default/hook/global/user-error-errors.html.tmpl create mode 100644 extensions/Voting/template/en/default/hook/search/form-email_numbering_end.html.tmpl create mode 100644 extensions/Voting/template/en/default/hook/search/search-report-select-rep_fields.html.tmpl create mode 100644 extensions/Voting/template/en/default/pages/voting.html.tmpl create mode 100644 extensions/Voting/template/en/default/pages/voting/bug.html.tmpl create mode 100644 extensions/Voting/template/en/default/pages/voting/user.html.tmpl create mode 100644 extensions/Voting/template/en/default/voting/delete-all.html.tmpl create mode 100644 extensions/Voting/template/en/default/voting/votes-removed.txt.tmpl create mode 100644 extensions/Voting/web/style.css delete mode 100644 skins/standard/voting.css delete mode 100644 template/en/default/bug/votes/delete-all.html.tmpl delete mode 100644 template/en/default/bug/votes/list-for-bug.html.tmpl delete mode 100644 template/en/default/bug/votes/list-for-user.html.tmpl delete mode 100644 template/en/default/email/votes-removed.txt.tmpl create mode 100644 template/en/default/global/reason-descs.none.tmpl delete mode 100644 template/en/default/pages/voting.html.tmpl diff --git a/.bzrignore b/.bzrignore index 8415e356b..5ee4b214d 100644 --- a/.bzrignore +++ b/.bzrignore @@ -27,6 +27,5 @@ /skins/contrib/Dusk/show_bug.css /skins/contrib/Dusk/show_multiple.css /skins/contrib/Dusk/summarize-time.css -/skins/contrib/Dusk/voting.css /skins/contrib/Dusk/yui .DS_Store diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index 336b9cfe1..b3f0fe58e 100644 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -57,7 +57,6 @@ use URI::QueryParam; use base qw(Bugzilla::Object Exporter); @Bugzilla::Bug::EXPORT = qw( bug_alias_to_id - RemoveVotes CheckIfVotedConfirmed LogActivityEntry editable_bug_fields ); @@ -631,7 +630,6 @@ sub run_create_validators { # You can't set these fields on bug creation (or sometimes ever). delete $params->{resolution}; - delete $params->{votes}; delete $params->{lastdiffed}; delete $params->{bug_id}; @@ -967,7 +965,6 @@ sub remove_from_db { # - flags # - keywords # - longdescs - # - votes # Also, the attach_data table uses attachments.attach_id as a foreign # key, and so indirectly depends on a bug deletion too. @@ -983,7 +980,6 @@ sub remove_from_db { undef, ($bug_id, $bug_id)); $dbh->do("DELETE FROM flags WHERE bug_id = ?", undef, $bug_id); $dbh->do("DELETE FROM keywords WHERE bug_id = ?", undef, $bug_id); - $dbh->do("DELETE FROM votes WHERE bug_id = ?", undef, $bug_id); # The attach_data table doesn't depend on bugs.bug_id directly. my $attach_ids = @@ -1819,7 +1815,7 @@ sub fields { bug_status resolution dup_id see_also bug_file_loc status_whiteboard keywords priority bug_severity target_milestone - dependson blocked votes everconfirmed + dependson blocked everconfirmed reporter assigned_to cc estimated_time remaining_time actual_time deadline), @@ -2870,14 +2866,6 @@ sub show_attachment_flags { return $self->{'show_attachment_flags'}; } -sub use_votes { - my ($self) = @_; - return 0 if $self->{'error'}; - - return Bugzilla->params->{'usevotes'} - && $self->product_obj->votes_per_user > 0; -} - sub groups { my $self = shift; return $self->{'groups'} if exists $self->{'groups'}; @@ -3019,20 +3007,6 @@ sub choices { return $self->{'choices'}; } -sub votes { - my ($self) = @_; - return 0 if $self->{error}; - return $self->{votes} if defined $self->{votes}; - - my $dbh = Bugzilla->dbh; - $self->{votes} = $dbh->selectrow_array( - 'SELECT SUM(vote_count) FROM votes - WHERE bug_id = ? ' . $dbh->sql_group_by('bug_id'), - undef, $self->bug_id); - $self->{votes} ||= 0; - return $self->{votes}; -} - # Convenience Function. If you need speed, use this. If you need # other Bug fields in addition to this, just create a new Bug with # the alias. @@ -3312,136 +3286,6 @@ sub CountOpenDependencies { return @dependencies; } -# If a bug is moved to a product which allows less votes per bug -# compared to the previous product, extra votes need to be removed. -sub RemoveVotes { - my ($id, $who, $reason) = (@_); - my $dbh = Bugzilla->dbh; - - my $whopart = ($who) ? " AND votes.who = $who" : ""; - - my $sth = $dbh->prepare("SELECT profiles.login_name, " . - "profiles.userid, votes.vote_count, " . - "products.votesperuser, products.maxvotesperbug " . - "FROM profiles " . - "LEFT JOIN votes ON profiles.userid = votes.who " . - "LEFT JOIN bugs ON votes.bug_id = bugs.bug_id " . - "LEFT JOIN products ON products.id = bugs.product_id " . - "WHERE votes.bug_id = ? " . $whopart); - $sth->execute($id); - my @list; - while (my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = $sth->fetchrow_array()) { - push(@list, [$name, $userid, $oldvotes, $votesperuser, $maxvotesperbug]); - } - - # @messages stores all emails which have to be sent, if any. - # This array is passed to the caller which will send these emails itself. - my @messages = (); - - if (scalar(@list)) { - foreach my $ref (@list) { - my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = (@$ref); - - $maxvotesperbug = min($votesperuser, $maxvotesperbug); - - # If this product allows voting and the user's votes are in - # the acceptable range, then don't do anything. - next if $votesperuser && $oldvotes <= $maxvotesperbug; - - # If the user has more votes on this bug than this product - # allows, then reduce the number of votes so it fits - my $newvotes = $maxvotesperbug; - - my $removedvotes = $oldvotes - $newvotes; - - if ($newvotes) { - $dbh->do("UPDATE votes SET vote_count = ? " . - "WHERE bug_id = ? AND who = ?", - undef, ($newvotes, $id, $userid)); - } else { - $dbh->do("DELETE FROM votes WHERE bug_id = ? AND who = ?", - undef, ($id, $userid)); - } - - # Notice that we did not make sure that the user fit within the $votesperuser - # range. This is considered to be an acceptable alternative to losing votes - # during product moves. Then next time the user attempts to change their votes, - # they will be forced to fit within the $votesperuser limit. - - # Now lets send the e-mail to alert the user to the fact that their votes have - # been reduced or removed. - my $vars = { - 'to' => $name . Bugzilla->params->{'emailsuffix'}, - 'bugid' => $id, - 'reason' => $reason, - - 'votesremoved' => $removedvotes, - 'votesold' => $oldvotes, - 'votesnew' => $newvotes, - }; - - my $voter = new Bugzilla::User($userid); - my $template = Bugzilla->template_inner($voter->settings->{'lang'}->{'value'}); - - my $msg; - $template->process("email/votes-removed.txt.tmpl", $vars, \$msg); - push(@messages, $msg); - } - Bugzilla->template_inner(""); - - my $votes = $dbh->selectrow_array("SELECT SUM(vote_count) " . - "FROM votes WHERE bug_id = ?", - undef, $id) || 0; - $dbh->do("UPDATE bugs SET votes = ? WHERE bug_id = ?", - undef, ($votes, $id)); - } - # Now return the array containing emails to be sent. - return @messages; -} - -# If a user votes for a bug, or the number of votes required to -# confirm a bug has been reduced, check if the bug is now confirmed. -sub CheckIfVotedConfirmed { - my $id = shift; - my $bug = new Bugzilla::Bug($id); - - my $ret = 0; - if (!$bug->everconfirmed - and $bug->product_obj->votes_to_confirm - and $bug->votes >= $bug->product_obj->votes_to_confirm) - { - $bug->add_comment('', { type => CMT_POPULAR_VOTES }); - - if ($bug->bug_status eq 'UNCONFIRMED') { - # Get a valid open state. - my $new_status; - foreach my $state (@{$bug->status->can_change_to}) { - if ($state->is_open && $state->name ne 'UNCONFIRMED') { - $new_status = $state->name; - last; - } - } - ThrowCodeError('no_open_bug_status') unless $new_status; - - # We cannot call $bug->set_status() here, because a user without - # canconfirm privs should still be able to confirm a bug by - # popular vote. We already know the new status is valid, so it's safe. - $bug->{bug_status} = $new_status; - $bug->{everconfirmed} = 1; - delete $bug->{'status'}; # Contains the status object. - } - else { - # If the bug is in a closed state, only set everconfirmed to 1. - # Do not call $bug->_set_everconfirmed(), for the same reason as above. - $bug->{everconfirmed} = 1; - } - $bug->update(); - - $ret = 1; - } - return $ret; -} - ################################################################################ # check_can_change_field() defines what users are allowed to change. You # can add code here for site-specific policy changes, according to the diff --git a/Bugzilla/BugMail.pm b/Bugzilla/BugMail.pm index 204c4ba9a..e7694c32e 100644 --- a/Bugzilla/BugMail.pm +++ b/Bugzilla/BugMail.pm @@ -377,12 +377,6 @@ sub Send { # the relationships in a hash. The keys are userids, the values are an # array of role constants. - # Voters - my $voters = $dbh->selectcol_arrayref( - "SELECT who FROM votes WHERE bug_id = ?", undef, ($id)); - - $recipients{$_}->{+REL_VOTER} = BIT_DIRECT foreach (@$voters); - # CCs $recipients{$_}->{+REL_CC} = BIT_DIRECT foreach (@ccs); @@ -405,8 +399,8 @@ sub Send { foreach my $ref (@$diffs) { my ($who, $whoname, $what, $when, $old, $new) = (@$ref); if ($old) { - # You can't stop being the reporter, and mail isn't sent if you - # remove your vote. + # You can't stop being the reporter, so we don't check that + # relationship here. # Ignore people whose user account has been deleted or renamed. if ($what eq "CC") { foreach my $cc_user (split(/[\s,]+/, $old)) { @@ -462,7 +456,6 @@ sub Send { foreach my $user_id (keys %recipients) { my %rels_which_want; my $sent_mail = 0; - my $user = new Bugzilla::User($user_id); # Deleted users must be excluded. next unless $user; diff --git a/Bugzilla/Comment.pm b/Bugzilla/Comment.pm index 300357313..60d26012f 100644 --- a/Bugzilla/Comment.pm +++ b/Bugzilla/Comment.pm @@ -148,7 +148,7 @@ sub set_type { sub _check_extra_data { my ($invocant, $extra_data, $type) = @_; $type = $invocant->type if ref $invocant; - if ($type == CMT_NORMAL or $type == CMT_POPULAR_VOTES) { + if ($type == CMT_NORMAL) { if (defined $extra_data) { ThrowCodeError('comment_extra_data_not_allowed', { type => $type, extra_data => $extra_data }); diff --git a/Bugzilla/Config/BugFields.pm b/Bugzilla/Config/BugFields.pm index 9f3ddc9ab..d0de9dac6 100644 --- a/Bugzilla/Config/BugFields.pm +++ b/Bugzilla/Config/BugFields.pm @@ -71,12 +71,6 @@ sub get_param_list { default => 0 }, - { - name => 'usevotes', - type => 'b', - default => 0 - }, - { name => 'usebugaliases', type => 'b', diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm index 8ab7455ff..d626c9749 100644 --- a/Bugzilla/Constants.pm +++ b/Bugzilla/Constants.pm @@ -90,7 +90,6 @@ use File::Basename; CMT_NORMAL CMT_DUPE_OF CMT_HAS_DUPE - CMT_POPULAR_VOTES CMT_MOVED_TO CMT_ATTACHMENT_CREATED CMT_ATTACHMENT_UPDATED @@ -98,7 +97,7 @@ use File::Basename; THROW_ERROR RELATIONSHIPS - REL_ASSIGNEE REL_QA REL_REPORTER REL_CC REL_VOTER REL_GLOBAL_WATCHER + REL_ASSIGNEE REL_QA REL_REPORTER REL_CC REL_GLOBAL_WATCHER REL_ANY POS_EVENTS @@ -282,7 +281,7 @@ use constant MAX_COMMENT_LENGTH => 65535; use constant CMT_NORMAL => 0; use constant CMT_DUPE_OF => 1; use constant CMT_HAS_DUPE => 2; -use constant CMT_POPULAR_VOTES => 3; +# Type 3 was CMT_POPULAR_VOTES, which moved to the Voting extension. use constant CMT_MOVED_TO => 4; use constant CMT_ATTACHMENT_CREATED => 5; use constant CMT_ATTACHMENT_UPDATED => 6; @@ -295,7 +294,7 @@ use constant REL_ASSIGNEE => 0; use constant REL_QA => 1; use constant REL_REPORTER => 2; use constant REL_CC => 3; -use constant REL_VOTER => 4; +# REL 4 was REL_VOTER, before it was moved ino an extension. use constant REL_GLOBAL_WATCHER => 5; # We need these strings for the X-Bugzilla-Reasons header @@ -307,7 +306,6 @@ use constant RELATIONSHIPS => { REL_REPORTER , "Reporter", REL_QA , "QAcontact", REL_CC , "CC", - REL_VOTER , "Voter", REL_GLOBAL_WATCHER, "GlobalWatcher" }; diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm index 27ae3be8a..21c0e7970 100644 --- a/Bugzilla/DB/Schema.pm +++ b/Bugzilla/DB/Schema.pm @@ -273,8 +273,6 @@ use constant ABSTRACT_SCHEMA => { COLUMN => 'userid'}}, status_whiteboard => {TYPE => 'MEDIUMTEXT', NOTNULL => 1, DEFAULT => "''"}, - votes => {TYPE => 'INT3', NOTNULL => 1, - DEFAULT => '0'}, # Note: keywords field is only a cache; the real data # comes from the keywords table keywords => {TYPE => 'MEDIUMTEXT', NOTNULL => 1, @@ -309,7 +307,6 @@ use constant ABSTRACT_SCHEMA => { bugs_resolution_idx => ['resolution'], bugs_target_milestone_idx => ['target_milestone'], bugs_qa_contact_idx => ['qa_contact'], - bugs_votes_idx => ['votes'], ], }, @@ -434,24 +431,6 @@ use constant ABSTRACT_SCHEMA => { ], }, - votes => { - FIELDS => [ - who => {TYPE => 'INT3', NOTNULL => 1, - REFERENCES => {TABLE => 'profiles', - COLUMN => 'userid', - DELETE => 'CASCADE'}}, - bug_id => {TYPE => 'INT3', NOTNULL => 1, - REFERENCES => {TABLE => 'bugs', - COLUMN => 'bug_id', - DELETE => 'CASCADE'}}, - vote_count => {TYPE => 'INT2', NOTNULL => 1}, - ], - INDEXES => [ - votes_who_idx => ['who'], - votes_bug_id_idx => ['bug_id'], - ], - }, - attachments => { FIELDS => [ attach_id => {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, @@ -1223,12 +1202,6 @@ use constant ABSTRACT_SCHEMA => { description => {TYPE => 'MEDIUMTEXT'}, isactive => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 1}, - votesperuser => {TYPE => 'INT2', NOTNULL => 1, - DEFAULT => 0}, - maxvotesperbug => {TYPE => 'INT2', NOTNULL => 1, - DEFAULT => '10000'}, - votestoconfirm => {TYPE => 'INT2', NOTNULL => 1, - DEFAULT => 0}, defaultmilestone => {TYPE => 'varchar(20)', NOTNULL => 1, DEFAULT => "'---'"}, allows_unconfirmed => {TYPE => 'BOOLEAN', NOTNULL => 1, diff --git a/Bugzilla/Field.pm b/Bugzilla/Field.pm index 17e4194c2..c2ab6e11b 100644 --- a/Bugzilla/Field.pm +++ b/Bugzilla/Field.pm @@ -188,7 +188,6 @@ use constant DEFAULT_FIELDS => ( buglist => 1}, {name => 'reporter', desc => 'ReportedBy', in_new_bugmail => 1, buglist => 1}, - {name => 'votes', desc => 'Votes', buglist => 1}, {name => 'qa_contact', desc => 'QAContact', in_new_bugmail => 1, buglist => 1}, {name => 'cc', desc => 'CC', in_new_bugmail => 1}, diff --git a/Bugzilla/Install/DB.pm b/Bugzilla/Install/DB.pm index 65137e593..66461bf45 100644 --- a/Bugzilla/Install/DB.pm +++ b/Bugzilla/Install/DB.pm @@ -168,11 +168,6 @@ sub update_table_definitions { $dbh->bz_add_column('bugs', 'everconfirmed', {TYPE => 'BOOLEAN', NOTNULL => 1}, 1); - $dbh->bz_add_column('products', 'maxvotesperbug', - {TYPE => 'INT2', NOTNULL => 1, DEFAULT => '10000'}); - $dbh->bz_add_column('products', 'votestoconfirm', - {TYPE => 'INT2', NOTNULL => 1}, 0); - _populate_milestones_table(); # 2000-03-22 Changed the default value for target_milestone to be "---" @@ -363,8 +358,10 @@ sub update_table_definitions { {TYPE => 'MEDIUMTEXT', NOTNULL => 1, DEFAULT => "''"}); $dbh->bz_alter_column('bugs', 'keywords', {TYPE => 'MEDIUMTEXT', NOTNULL => 1, DEFAULT => "''"}); - $dbh->bz_alter_column('bugs', 'votes', - {TYPE => 'INT3', NOTNULL => 1, DEFAULT => '0'}); + if ($dbh->bz_column_info('bugs', 'votes')) { + $dbh->bz_alter_column('bugs', 'votes', + {TYPE => 'INT3', NOTNULL => 1, DEFAULT => '0'}); + } $dbh->bz_alter_column('bugs', 'lastdiffed', {TYPE => 'DATETIME'}); @@ -469,11 +466,14 @@ sub update_table_definitions { if ($dbh->bz_column_info('products', 'disallownew')){ $dbh->bz_alter_column('products', 'disallownew', {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 0}); + + if ($dbh->bz_column_info('products', 'votesperuser')) { + $dbh->bz_alter_column('products', 'votesperuser', + {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0}); + $dbh->bz_alter_column('products', 'votestoconfirm', + {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0}); + } } - $dbh->bz_alter_column('products', 'votesperuser', - {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0}); - $dbh->bz_alter_column('products', 'votestoconfirm', - {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0}); # 2006-08-04 LpSolit@gmail.com - Bug 305941 $dbh->bz_drop_column('profiles', 'refreshed_when'); @@ -654,14 +654,14 @@ sub _add_bug_vote_cache { # (P.S. All is not lost; it appears that the latest betas of MySQL # support a new table format which will allow 32 indices.) - $dbh->bz_drop_column('bugs', 'area'); - if (!$dbh->bz_column_info('bugs', 'votes')) { + if ($dbh->bz_column_info('bugs', 'area')) { + $dbh->bz_drop_column('bugs', 'area'); $dbh->bz_add_column('bugs', 'votes', {TYPE => 'INT3', NOTNULL => 1, DEFAULT => 0}); $dbh->bz_add_index('bugs', 'bugs_votes_idx', [qw(votes)]); + $dbh->bz_add_column('products', 'votesperuser', + {TYPE => 'INT2', NOTNULL => 1}, 0); } - $dbh->bz_add_column('products', 'votesperuser', - {TYPE => 'INT2', NOTNULL => 1}, 0); } sub _update_product_name_definition { @@ -896,9 +896,11 @@ sub _add_unique_login_name_index_to_profiles { ["votes", "who"], ["longdescs", "who"]) { my ($table, $field) = (@$i); - print " Updating $table.$field...\n"; - $dbh->do("UPDATE $table SET $field = $u1 " . - "WHERE $field = $u2"); + if ($dbh->bz_table_info($table)) { + print " Updating $table.$field...\n"; + $dbh->do("UPDATE $table SET $field = $u1 " . + "WHERE $field = $u2"); + } } $dbh->do("DELETE FROM profiles WHERE userid = $u2"); } @@ -2206,9 +2208,9 @@ sub _rename_votes_count_and_force_group_refresh { # # Renaming the 'count' column in the votes table because Sybase doesn't # like it - if ($dbh->bz_column_info('votes', 'count')) { - $dbh->bz_rename_column('votes', 'count', 'vote_count'); - } + return if !$dbh->bz_table_info('votes'); + return if $dbh->bz_column_info('votes', 'count'); + $dbh->bz_rename_column('votes', 'count', 'vote_count'); } sub _fix_group_with_empty_name { @@ -2266,7 +2268,9 @@ sub _migrate_email_prefs_to_new_table { "Reporter" => REL_REPORTER, "QAcontact" => REL_QA, "CClist" => REL_CC, - "Voter" => REL_VOTER); + # REL_VOTER was "4" before it was moved to an + # extension. + "Voter" => 4); my %events = ("Removeme" => EVT_ADDED_REMOVED, "Comments" => EVT_COMMENT, @@ -3343,8 +3347,10 @@ sub _add_allows_unconfirmed_to_product_table { if (!$dbh->bz_column_info('products', 'allows_unconfirmed')) { $dbh->bz_add_column('products', 'allows_unconfirmed', { TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE' }); - $dbh->do('UPDATE products SET allows_unconfirmed = 1 - WHERE votestoconfirm > 0'); + if ($dbh->bz_column_info('products', 'votestoconfirm')) { + $dbh->do('UPDATE products SET allows_unconfirmed = 1 + WHERE votestoconfirm > 0'); + } } } diff --git a/Bugzilla/Object.pm b/Bugzilla/Object.pm index dac8962ff..11db7567b 100644 --- a/Bugzilla/Object.pm +++ b/Bugzilla/Object.pm @@ -278,7 +278,8 @@ sub set { my ($self, $field, $value) = @_; # This method is protected. It's used to help implement set_ functions. - caller->isa('Bugzilla::Object') + my $caller = caller; + $caller->isa('Bugzilla::Object') || $caller->isa('Bugzilla::Extension') || ThrowCodeError('protection_violation', { caller => caller, superclass => __PACKAGE__, diff --git a/Bugzilla/Product.pm b/Bugzilla/Product.pm index 6b00fcbf6..975af7d5d 100644 --- a/Bugzilla/Product.pm +++ b/Bugzilla/Product.pm @@ -48,9 +48,6 @@ use constant DB_COLUMNS => qw( classification_id description isactive - votesperuser - maxvotesperbug - votestoconfirm defaultmilestone allows_unconfirmed ); @@ -66,9 +63,6 @@ use constant UPDATE_COLUMNS => qw( description defaultmilestone isactive - votesperuser - maxvotesperbug - votestoconfirm allows_unconfirmed ); @@ -80,9 +74,6 @@ use constant VALIDATORS => { version => \&_check_version, defaultmilestone => \&_check_default_milestone, isactive => \&Bugzilla::Object::check_boolean, - votesperuser => \&_check_votes_per_user, - maxvotesperbug => \&_check_votes_per_bug, - votestoconfirm => \&_check_votes_to_confirm, create_series => \&Bugzilla::Object::check_boolean }; @@ -155,99 +146,6 @@ sub update { $dbh->bz_start_transaction(); my ($changes, $old_self) = $self->SUPER::update(@_); - # We also have to fix votes. - my @msgs; # Will store emails to send to voters. - if ($changes->{maxvotesperbug} || $changes->{votesperuser} || $changes->{votestoconfirm}) { - # We cannot |use| these modules, due to dependency loops. - require Bugzilla::Bug; - import Bugzilla::Bug qw(RemoveVotes CheckIfVotedConfirmed); - require Bugzilla::User; - import Bugzilla::User qw(user_id_to_login); - - # 1. too many votes for a single user on a single bug. - my @toomanyvotes_list = (); - if ($self->max_votes_per_bug < $self->votes_per_user) { - my $votes = $dbh->selectall_arrayref( - 'SELECT votes.who, votes.bug_id - FROM votes - INNER JOIN bugs - ON bugs.bug_id = votes.bug_id - WHERE bugs.product_id = ? - AND votes.vote_count > ?', - undef, ($self->id, $self->max_votes_per_bug)); - - foreach my $vote (@$votes) { - my ($who, $id) = (@$vote); - # If some votes are removed, RemoveVotes() returns a list - # of messages to send to voters. - push(@msgs, RemoveVotes($id, $who, 'votes_too_many_per_bug')); - my $name = user_id_to_login($who); - - push(@toomanyvotes_list, {id => $id, name => $name}); - } - } - $changes->{'too_many_votes'} = \@toomanyvotes_list; - - # 2. too many total votes for a single user. - # This part doesn't work in the general case because RemoveVotes - # doesn't enforce votesperuser (except per-bug when it's less - # than maxvotesperbug). See Bugzilla::Bug::RemoveVotes(). - - my $votes = $dbh->selectall_arrayref( - 'SELECT votes.who, votes.vote_count - FROM votes - INNER JOIN bugs - ON bugs.bug_id = votes.bug_id - WHERE bugs.product_id = ?', - undef, $self->id); - - my %counts; - foreach my $vote (@$votes) { - my ($who, $count) = @$vote; - if (!defined $counts{$who}) { - $counts{$who} = $count; - } else { - $counts{$who} += $count; - } - } - my @toomanytotalvotes_list = (); - foreach my $who (keys(%counts)) { - if ($counts{$who} > $self->votes_per_user) { - my $bug_ids = $dbh->selectcol_arrayref( - 'SELECT votes.bug_id - FROM votes - INNER JOIN bugs - ON bugs.bug_id = votes.bug_id - WHERE bugs.product_id = ? - AND votes.who = ?', - undef, ($self->id, $who)); - - foreach my $bug_id (@$bug_ids) { - # RemoveVotes() returns a list of messages to send - # in case some voters had too many votes. - push(@msgs, RemoveVotes($bug_id, $who, 'votes_too_many_per_user')); - my $name = user_id_to_login($who); - - push(@toomanytotalvotes_list, {id => $bug_id, name => $name}); - } - } - } - $changes->{'too_many_total_votes'} = \@toomanytotalvotes_list; - - # 3. enough votes to confirm - my $bug_list = - $dbh->selectcol_arrayref('SELECT bug_id FROM bugs WHERE product_id = ? - AND bug_status = ? AND votes >= ?', - undef, ($self->id, 'UNCONFIRMED', $self->votes_to_confirm)); - - my @updated_bugs = (); - foreach my $bug_id (@$bug_list) { - my $confirmed = CheckIfVotedConfirmed($bug_id); - push (@updated_bugs, $bug_id) if $confirmed; - } - $changes->{'confirmed_bugs'} = \@updated_bugs; - } - # Also update group settings. if ($self->{check_group_controls}) { require Bugzilla::Bug; @@ -364,11 +262,6 @@ sub update { delete $self->{check_group_controls}; Bugzilla->user->clear_product_cache(); - # Now that changes have been committed, we can send emails to voters. - foreach my $msg (@msgs) { - MessageToMTA($msg); - } - return $changes; } @@ -524,37 +417,6 @@ sub _check_milestone_url { return $url; } -sub _check_votes_per_user { - return _check_votes(@_, 0); -} - -sub _check_votes_per_bug { - return _check_votes(@_, 10000); -} - -sub _check_votes_to_confirm { - return _check_votes(@_, 0); -} - -# This subroutine is only used internally by other _check_votes_* validators. -sub _check_votes { - my ($invocant, $votes, $field, $default) = @_; - - detaint_natural($votes); - # On product creation, if the number of votes is not a valid integer, - # we silently fall back to the given default value. - # If the product already exists and the change is illegal, we complain. - if (!defined $votes) { - if (ref $invocant) { - ThrowUserError('product_illegal_votes', {field => $field, votes => $_[1]}); - } - else { - $votes = $default; - } - } - return $votes; -} - ##################################### # Implement Bugzilla::Field::Choice # ##################################### @@ -618,9 +480,6 @@ sub set_name { $_[0]->set('name', $_[1]); } sub set_description { $_[0]->set('description', $_[1]); } sub set_default_milestone { $_[0]->set('defaultmilestone', $_[1]); } sub set_is_active { $_[0]->set('isactive', $_[1]); } -sub set_votes_per_user { $_[0]->set('votesperuser', $_[1]); } -sub set_votes_per_bug { $_[0]->set('maxvotesperbug', $_[1]); } -sub set_votes_to_confirm { $_[0]->set('votestoconfirm', $_[1]); } sub set_allows_unconfirmed { $_[0]->set('allows_unconfirmed', $_[1]); } sub set_group_controls { @@ -876,9 +735,6 @@ sub flag_types { sub allows_unconfirmed { return $_[0]->{'allows_unconfirmed'}; } sub description { return $_[0]->{'description'}; } sub is_active { return $_[0]->{'isactive'}; } -sub votes_per_user { return $_[0]->{'votesperuser'}; } -sub max_votes_per_bug { return $_[0]->{'maxvotesperbug'}; } -sub votes_to_confirm { return $_[0]->{'votestoconfirm'}; } sub default_milestone { return $_[0]->{'defaultmilestone'}; } sub classification_id { return $_[0]->{'classification_id'}; } @@ -939,9 +795,6 @@ Bugzilla::Product - Bugzilla product class. my $name = $product->name; my $description = $product->description; my isactive = $product->is_active; - my votesperuser = $product->votes_per_user; - my maxvotesperbug = $product->max_votes_per_bug; - my votestoconfirm = $product->votes_to_confirm; my $defaultmilestone = $product->default_milestone; my $classificationid = $product->classification_id; my $allows_unconfirmed = $product->allows_unconfirmed; diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm index d85da01a4..52c99903d 100644 --- a/Bugzilla/Search.pm +++ b/Bugzilla/Search.pm @@ -86,10 +86,8 @@ use constant SPECIAL_ORDER_JOIN => { # 3. title: The title of the column as displayed to users. # # Note: There are a few hacks in the code that deviate from these definitions. -# In particular, when the list is sorted by the "votes" field the word -# "DESC" is added to the end of the field to sort in descending order, -# and the redundant short_desc column is removed when the client -# requests "all" columns. +# In particular, the redundant short_desc column is removed when the +# client requests "all" columns. # # This is really a constant--that is, once it's been called once, the value # will always be the same unless somebody adds a new custom field. But @@ -281,18 +279,6 @@ sub init { push(@supptables, "LEFT JOIN flagtypes ON flagtypes.id = flags.type_id"); } - my $minvotes; - if (defined $params->param('votes')) { - my $c = trim($params->param('votes')); - if ($c ne "") { - if ($c !~ /^[0-9]*$/) { - ThrowUserError("illegal_at_least_x_votes", - { value => $c }); - } - push(@specialchart, ["votes", "greaterthan", $c - 1]); - } - } - # If the user has selected all of either status or resolution, change to # selecting none. This is functionally equivalent, but quite a lot faster. # Also, if the status is __open__ or __closed__, translate those diff --git a/Bugzilla/Search/Quicksearch.pm b/Bugzilla/Search/Quicksearch.pm index 2f9e0734f..1e0bdc437 100644 --- a/Bugzilla/Search/Quicksearch.pm +++ b/Bugzilla/Search/Quicksearch.pm @@ -339,12 +339,6 @@ sub _handle_special_first_chars { sub _handle_field_names { my ($or_operand, $negate, $unknownFields, $ambiguous_fields) = @_; - # votes:xx ("at least xx votes") - if ($or_operand =~ /^votes:([0-9]+)$/) { - addChart('votes', 'greaterthan', $1 - 1, $negate); - return 1; - } - # Flag and requestee shortcut if ($or_operand =~ /^(?:flag:)?([^\?]+\?)([^\?]*)$/) { addChart('flagtypes.name', 'substring', $1, $negate); @@ -454,18 +448,6 @@ sub _special_field_syntax { return 1; } - # Votes (votes>xx) - if ($word =~ m/^votes>([0-9]+)$/) { - addChart('votes', 'greaterthan', $1, $negate); - return 1; - } - - # Votes (votes>=xx, votes=>xx) - if ($word =~ m/^votes(>=|=>)([0-9]+)$/) { - addChart('votes', 'greaterthan', $2-1, $negate); - return 1; - } - return 0; } diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm index 711a45f44..1d7b9f7d9 100644 --- a/Bugzilla/WebService/Bug.pm +++ b/Bugzilla/WebService/Bug.pm @@ -386,9 +386,6 @@ sub search { if (my $when = delete $params->{creation_ts}) { $params->{WHERE}->{'creation_ts >= ?'} = $when; } - if (my $votes = delete $params->{votes}) { - $params->{WHERE}->{'votes >= ?'} = $votes; - } if (my $summary = delete $params->{short_desc}) { my @strings = ref $summary ? @$summary : ($summary); my @likes = ("short_desc LIKE ?") x @strings; @@ -1687,11 +1684,6 @@ C The "URL" field of a bug. C The Version field of a bug. -=item C - -C Searches for bugs with this many votes or greater. May not -be an array. - =item C C Search the "Status Whiteboard" field on bugs for a substring. @@ -1722,6 +1714,8 @@ for that value. =item Added in Bugzilla B<3.4>. +=item Searching by C was removed in Bugzilla B<3.8>. + =back =back diff --git a/buglist.cgi b/buglist.cgi index b8cfa6336..48fe2d873 100755 --- a/buglist.cgi +++ b/buglist.cgi @@ -653,18 +653,6 @@ else { # and are hard-coded into the display templates. @displaycolumns = grep($_ ne 'bug_id', @displaycolumns); -# Add the votes column to the list of columns to be displayed -# in the bug list if the user is searching for bugs with a certain -# number of votes and the votes column is not already on the list. - -# Some versions of perl will taint 'votes' if this is done as a single -# statement, because the votes param is tainted at this point -my $votes = $params->param('votes'); -$votes ||= ""; -if (trim($votes) && !grep($_ eq 'votes', @displaycolumns)) { - push(@displaycolumns, 'votes'); -} - # Remove the timetracking columns if they are not a part of the group # (happens if a user had access to time tracking and it was revoked/disabled) if (!Bugzilla->user->is_timetracker) { @@ -806,12 +794,6 @@ if ($order) { # Special handlings for certain columns next if $column_name eq 'relevance' && !$fulltext; - # If we are sorting by votes, sort in descending order if - # no explicit sort order was given. - if ($column_name eq 'votes' && !$direction) { - $direction = "DESC"; - } - if (exists $columns->{$column_name}) { $direction = " $direction" if $direction; push(@order, "$column_name$direction"); diff --git a/bugzilla.dtd b/bugzilla.dtd index 64f575b62..b449d6ba4 100644 --- a/bugzilla.dtd +++ b/bugzilla.dtd @@ -5,7 +5,7 @@ maintainer CDATA #REQUIRED exporter CDATA #IMPLIED > - + @@ -39,7 +39,6 @@ - diff --git a/colchange.cgi b/colchange.cgi index 409f15e5a..15bdac599 100755 --- a/colchange.cgi +++ b/colchange.cgi @@ -55,9 +55,6 @@ if (Bugzilla->params->{"useclassification"}) { push(@masterlist, ("product", "component", "version", "op_sys")); -if (Bugzilla->params->{"usevotes"}) { - push (@masterlist, "votes"); -} if (Bugzilla->params->{"usebugaliases"}) { unshift(@masterlist, "alias"); } diff --git a/contrib/merge-users.pl b/contrib/merge-users.pl index 80c516e04..6c1ed1377 100755 --- a/contrib/merge-users.pl +++ b/contrib/merge-users.pl @@ -129,7 +129,6 @@ my $changes = { flags => ['setter_id', 'requestee_id'], cc => ['who bug_id'], longdescs => ['who'], - votes => ['who'], # Tables affecting global behavior / other users. components => ['initialowner', 'initialqacontact'], component_cc => ['user_id component_id'], diff --git a/docs/en/images/bzLifecycle.xml b/docs/en/images/bzLifecycle.xml index 1adc6b70c..dda8ac48a 100644 --- a/docs/en/images/bzLifecycle.xml +++ b/docs/en/images/bzLifecycle.xml @@ -968,8 +968,7 @@ UNCONFIRMED state# - #Bug confirmed or -receives enough votes# + #Bug confirmed# diff --git a/editproducts.cgi b/editproducts.cgi index 8433ed16b..4a302aa6c 100755 --- a/editproducts.cgi +++ b/editproducts.cgi @@ -186,11 +186,6 @@ if ($action eq 'new') { create_series => scalar $cgi->param('createseries'), allows_unconfirmed => scalar $cgi->param('allows_unconfirmed'), ); - if (Bugzilla->params->{'usevotes'}) { - $create_params{votesperuser} = $cgi->param('votesperuser'); - $create_params{maxvotesperbug} = $cgi->param('maxvotesperbug'); - $create_params{votestoconfirm} = $cgi->param('votestoconfirm'); - } my $product = Bugzilla::Product->create(\%create_params); delete_token($token); @@ -295,16 +290,13 @@ if ($action eq 'update') { my $product_old_name = trim($cgi->param('product_old_name') || ''); my $product = $user->check_can_admin_product($product_old_name); - $product->set_name($product_name); - $product->set_description(scalar $cgi->param('description')); - $product->set_default_milestone(scalar $cgi->param('defaultmilestone')); - $product->set_is_active(scalar $cgi->param('is_active')); - if (Bugzilla->params->{'usevotes'}) { - $product->set_votes_per_user(scalar $cgi->param('votesperuser')); - $product->set_votes_per_bug(scalar $cgi->param('maxvotesperbug')); - $product->set_votes_to_confirm(scalar $cgi->param('votestoconfirm')); - } - $product->set_allows_unconfirmed(scalar $cgi->param('allows_unconfirmed')); + $product->set_all({ + name => $product_name, + description => scalar $cgi->param('description'), + is_active => scalar $cgi->param('is_active'), + allows_unconfirmed => scalar $cgi->param('allows_unconfirmed'), + default_milestone => scalar $cgi->param('defaultmilestone'), + }); my $changes = $product->update(); diff --git a/editusers.cgi b/editusers.cgi index e63f29fc5..7ce6bb9d2 100755 --- a/editusers.cgi +++ b/editusers.cgi @@ -424,9 +424,6 @@ if ($action eq 'search') { $vars->{'series'} = $dbh->selectrow_array( 'SELECT COUNT(*) FROM series WHERE creator = ?', undef, $otherUserID); - $vars->{'votes'} = $dbh->selectrow_array( - 'SELECT COUNT(*) FROM votes WHERE who = ?', - undef, $otherUserID); $vars->{'watch'}{'watched'} = $dbh->selectrow_array( 'SELECT COUNT(*) FROM watch WHERE watched = ?', undef, $otherUserID); @@ -537,7 +534,6 @@ if ($action eq 'search') { $dbh->do('DELETE FROM tokens WHERE userid = ?', undef, $otherUserID); $dbh->do('DELETE FROM user_group_map WHERE user_id = ?', undef, $otherUserID); - $dbh->do('DELETE FROM votes WHERE who = ?', undef, $otherUserID); $dbh->do('DELETE FROM watch WHERE watcher = ? OR watched = ?', undef, ($otherUserID, $otherUserID)); diff --git a/extensions/Voting/Extension.pm b/extensions/Voting/Extension.pm new file mode 100644 index 000000000..e111ac785 --- /dev/null +++ b/extensions/Voting/Extension.pm @@ -0,0 +1,861 @@ +# -*- 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 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): Terry Weissman +# Stephan Niemz +# Christopher Aillon +# Gervase Markham +# Frédéric Buclin +# Max Kanat-Alexander + +package Bugzilla::Extension::Voting; +use strict; +use base qw(Bugzilla::Extension); + +use Bugzilla::Bug; +use Bugzilla::Constants; +use Bugzilla::Error; +use Bugzilla::Field; +use Bugzilla::Mailer; +use Bugzilla::User; +use Bugzilla::Util qw(detaint_natural); + +use List::Util qw(min); + +use constant NAME => 'Voting'; +use constant DEFAULT_VOTES_PER_BUG => 1; +# These came from Bugzilla itself, so they maintain the old numbers +# they had before. +use constant CMT_POPULAR_VOTES => 3; +use constant REL_VOTER => 4; + +################ +# Installation # +################ + +our $VERSION = BUGZILLA_VERSION; + +sub db_schema_abstract_schema { + my ($self, $args) = @_; + $args->{'schema'}->{'votes'} = { + FIELDS => [ + who => {TYPE => 'INT3', NOTNULL => 1, + REFERENCES => {TABLE => 'profiles', + COLUMN => 'userid', + DELETE => 'CASCADE'}}, + bug_id => {TYPE => 'INT3', NOTNULL => 1, + REFERENCES => {TABLE => 'bugs', + COLUMN => 'bug_id', + DELETE => 'CASCADE'}}, + vote_count => {TYPE => 'INT2', NOTNULL => 1}, + ], + INDEXES => [ + votes_who_idx => ['who'], + votes_bug_id_idx => ['bug_id'], + ], + }; +} + +sub install_update_db { + my $dbh = Bugzilla->dbh; + # Note that before Bugzilla 3.8, voting was a built-in part of Bugzilla, + # so updates to the columns for old versions of Bugzilla happen in + # Bugzilla::Install::DB, and can't safely be moved to this extension. + + my $field = new Bugzilla::Field({ name => 'votes' }); + if (!$field) { + Bugzilla::Field->create( + { name => 'votes', description => 'Votes', buglist => 1 }); + } + + $dbh->bz_add_column('products', 'votesperuser', + {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0}); + $dbh->bz_add_column('products', 'maxvotesperbug', + {TYPE => 'INT2', NOTNULL => 1, DEFAULT => DEFAULT_VOTES_PER_BUG}); + $dbh->bz_add_column('products', 'votestoconfirm', + {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0}); + + $dbh->bz_add_column('bugs', 'votes', + {TYPE => 'INT3', NOTNULL => 1, DEFAULT => 0}); + $dbh->bz_add_index('bugs', 'bugs_votes_idx', ['votes']); + + # maxvotesperbug used to default to 10,000, which isn't very sensible. + my $per_bug = $dbh->bz_column_info('products', 'maxvotesperbug'); + if ($per_bug->{DEFAULT} != DEFAULT_VOTES_PER_BUG) { + $dbh->bz_alter_column('products', 'maxvotesperbug', + {TYPE => 'INT2', NOTNULL => 1, DEFAULT => DEFAULT_VOTES_PER_BUG}); + } +} + +########### +# Objects # +########### + +sub object_columns { + my ($self, $args) = @_; + my ($class, $columns) = @$args{qw(class columns)}; + if ($class->isa('Bugzilla::Bug')) { + push(@$columns, 'votes'); + } + elsif ($class->isa('Bugzilla::Product')) { + push(@$columns, qw(votesperuser maxvotesperbug votestoconfirm)); + } +} + +sub bug_fields { + my ($self, $args) = @_; + my $fields = $args->{fields}; + push(@$fields, 'votes'); +} + +sub object_update_columns { + my ($self, $args) = @_; + my ($object, $columns) = @$args{qw(object columns)}; + if ($object->isa('Bugzilla::Product')) { + push(@$columns, qw(votesperuser maxvotesperbug votestoconfirm)); + } +} + +sub object_validators { + my ($self, $args) = @_; + my ($class, $validators) = @$args{qw(class validators)}; + if ($class->isa('Bugzilla::Product')) { + $validators->{'votesperuser'} = \&_check_votesperuser; + $validators->{'maxvotesperbug'} = \&_check_maxvotesperbug; + $validators->{'votestoconfirm'} = \&_check_votestoconfirm; + } +} + +sub object_before_create { + my ($self, $args) = @_; + my ($class, $params) = @$args{qw(class params)}; + if ($class->isa('Bugzilla::Bug')) { + # Don't ever allow people to directly specify "votes" into the bugs + # table. + delete $params->{votes}; + } + elsif ($class->isa('Bugzilla::Product')) { + my $input = Bugzilla->input_params; + $params->{votesperuser} = $input->{'votesperuser'}; + $params->{maxvotesperbug} = $input->{'maxvotesperbug'}; + $params->{votestoconfirm} = $input->{'votestoconfirm'}; + } +} + +sub object_end_of_set_all { + my ($self, $args) = @_; + my ($object) = $args->{object}; + if ($object->isa('Bugzilla::Product')) { + my $input = Bugzilla->input_params; + $object->set('votesperuser', $input->{'votesperuser'}); + $object->set('maxvotesperbug', $input->{'maxvotesperbug'}); + $object->set('votestoconfirm', $input->{'votestoconfirm'}); + } +} + +sub object_end_of_update { + my ($self, $args) = @_; + my ($object, $changes) = @$args{qw(object changes)}; + if ( $object->isa('Bugzilla::Product') + and ($changes->{maxvotesperbug} or $changes->{votesperuser} + or $changes->{votestoconfirm}) ) + { + _modify_bug_votes($object, $changes); + } +} + +sub bug_end_of_update { + my ($self, $args) = @_; + my ($bug, $changes) = @$args{qw(bug changes)}; + + if ($changes->{'product'}) { + my @msgs; + # If some votes have been removed, RemoveVotes() returns + # a list of messages to send to voters. + @msgs = _remove_votes($bug->id, 0, 'votes_bug_moved'); + _confirm_if_vote_confirmed($bug->id); + + foreach my $msg (@msgs) { + MessageToMTA($msg); + } + } +} + +############# +# Templates # +############# + +sub template_before_create { + my ($self, $args) = @_; + my $config = $args->{config}; + my $constants = $config->{CONSTANTS}; + $constants->{REL_VOTER} = REL_VOTER; + $constants->{CMT_POPULAR_VOTES} = CMT_POPULAR_VOTES; + $constants->{DEFAULT_VOTES_PER_BUG} = DEFAULT_VOTES_PER_BUG; +} + + +sub template_before_process { + my ($self, $args) = @_; + my ($vars, $file) = @$args{qw(vars file)}; + if ($file eq 'admin/users/confirm-delete.html.tmpl') { + my $who = $vars->{otheruser}; + my $votes = Bugzilla->dbh->selectrow_array( + 'SELECT COUNT(*) FROM votes WHERE who = ?', undef, $who->id); + if ($votes) { + $vars->{other_safe} = 1; + $vars->{votes} = $votes; + } + } +} + +########### +# Bugmail # +########### + +sub bugmail_recipients { + my ($self, $args) = @_; + my ($bug, $recipients) = @$args{qw(bug recipients)}; + my $dbh = Bugzilla->dbh; + + my $voters = $dbh->selectcol_arrayref( + "SELECT who FROM votes WHERE bug_id = ?", undef, $bug->id); + $recipients->{$_}->{+REL_VOTER} = 1 foreach (@$voters); +} + +sub bugmail_relationships { + my ($self, $args) = @_; + my $relationships = $args->{relationships}; + $relationships->{+REL_VOTER} = 'Voter'; +} + +############### +# Sanitycheck # +############### + +sub sanitycheck_check { + my ($self, $args) = @_; + my $status = $args->{status}; + + # Vote Cache + $status->('voting_count_start'); + my $dbh = Bugzilla->dbh; + my %cached_counts = @{ $dbh->selectcol_arrayref( + 'SELECT bug_id, votes FROM bugs', {Columns=>[1,2]}) }; + + my %real_counts = @{ $dbh->selectcol_arrayref( + 'SELECT bug_id, SUM(vote_count) FROM votes ' + . $dbh->sql_group_by('bug_id'), {Columns=>[1,2]}) }; + + my $needs_rebuild; + foreach my $id (keys %cached_counts) { + my $cached_count = $cached_counts{$id}; + my $real_count = $real_counts{$id} || 0; + if ($cached_count < 0) { + $status->('voting_count_alert', { id => $id }, 'alert'); + } + elsif ($cached_count != $real_count) { + $status->('voting_cache_alert', { id => $id }, 'alert'); + $needs_rebuild = 1; + } + } + + $status->('voting_cache_rebuild_fix') if $needs_rebuild; +} + +sub sanitycheck_repair { + my ($self, $args) = @_; + my $status = $args->{status}; + my $input = Bugzilla->input_params; + my $dbh = Bugzilla->dbh; + + return if !$input->{rebuild_vote_cache}; + + $status->('voting_cache_rebuild_start'); + $dbh->bz_start_transaction(); + $dbh->do('UPDATE bugs SET votes = 0'); + + my $sth = $dbh->prepare( + 'SELECT bug_id, SUM(vote_count) FROM votes ' + . $dbh->sql_group_by('bug_id')); + $sth->execute(); + + my $sth_update = $dbh->prepare( + 'UPDATE bugs SET votes = ? WHERE bug_id = ?'); + while (my ($id, $count) = $sth->fetchrow_array) { + $sth_update->execute($count, $id); + } + $dbh->bz_commit_transaction(); + $status->('voting_cache_rebuild_end'); +} + + +############## +# Validators # +############## + +sub _check_votesperuser { + return _check_votes(0, @_); +} + +sub _check_maxvotesperbug { + return _check_votes(DEFAULT_VOTES_PER_BUG, @_); +} + +sub _check_votestoconfirm { + return _check_votes(0, @_); +} + +# This subroutine is only used internally by other _check_votes_* validators. +sub _check_votes { + my ($default, $invocant, $votes, $field) = @_; + + detaint_natural($votes); + # On product creation, if the number of votes is not a valid integer, + # we silently fall back to the given default value. + # If the product already exists and the change is illegal, we complain. + if (!defined $votes) { + if (ref $invocant) { + ThrowUserError('voting_product_illegal_votes', + { field => $field, votes => $_[2] }); + } + else { + $votes = $default; + } + } + return $votes; +} + +######### +# Pages # +######### + +sub page_before_template { + my ($self, $args) = @_; + my $page = $args->{page_id}; + my $vars = $args->{vars}; + + if ($page =~ m{^voting/bug\.}) { + _page_bug($vars); + } + elsif ($page =~ m{^voting/user\.}) { + _page_user($vars); + } +} + +sub _page_bug { + my ($vars) = @_; + my $dbh = Bugzilla->dbh; + my $template = Bugzilla->template; + my $input = Bugzilla->input_params; + + my $bug_id = $input->{bug_id}; + my $bug = Bugzilla::Bug->check($bug_id); + + $vars->{'bug'} = $bug; + $vars->{'users'} = + $dbh->selectall_arrayref('SELECT profiles.login_name, + profiles.userid AS id, + votes.vote_count + FROM votes + INNER JOIN profiles + ON profiles.userid = votes.who + WHERE votes.bug_id = ?', + {Slice=>{}}, $bug->id); +} + +sub _page_user { + my ($vars) = @_; + my $dbh = Bugzilla->dbh; + my $user = Bugzilla->user; + my $template = Bugzilla->template; + my $input = Bugzilla->input_params; + + my $action = $input->{action}; + if ($action and $action eq 'vote') { + _update_votes($vars); + } + + # If a bug_id is given, and we're editing, we'll add it to the votes list. + + my $bug_id = $input->{bug_id}; + my $bug = Bugzilla::Bug->check($bug_id) if $bug_id; + my $who_id = $input->{user_id} || $user->id; + + # Logged-out users must specify a user_id. + Bugzilla->login(LOGIN_REQUIRED) if !$who_id; + + my $who = Bugzilla::User->check({ id => $who_id }); + + my $canedit = $user->id == $who->id; + + $dbh->bz_start_transaction(); + + if ($canedit && $bug) { + # Make sure there is an entry for this bug + # in the vote table, just so that things display right. + my $has_votes = $dbh->selectrow_array('SELECT vote_count FROM votes + WHERE bug_id = ? AND who = ?', + undef, ($bug->id, $who->id)); + if (!$has_votes) { + $dbh->do('INSERT INTO votes (who, bug_id, vote_count) + VALUES (?, ?, 0)', undef, ($who->id, $bug->id)); + } + } + + my (@products, @all_bug_ids); + # Read the votes data for this user for each product. + foreach my $product (@{ $user->get_selectable_products }) { + next unless ($product->{votesperuser} > 0); + + my @bugs; + my @bug_ids; + my $total = 0; + my $onevoteonly = 0; + + my $vote_list = + $dbh->selectall_arrayref('SELECT votes.bug_id, votes.vote_count, + bugs.short_desc + FROM votes + INNER JOIN bugs + ON votes.bug_id = bugs.bug_id + WHERE votes.who = ? + AND bugs.product_id = ? + ORDER BY votes.bug_id', + undef, ($who->id, $product->id)); + + foreach (@$vote_list) { + my ($id, $count, $summary) = @$_; + $total += $count; + + # Next if user can't see this bug. So, the totals will be correct + # and they can see there are votes 'missing', but not on what bug + # they are. This seems a reasonable compromise; the alternative is + # to lie in the totals. + next if !$user->can_see_bug($id); + + push (@bugs, { id => $id, + summary => $summary, + count => $count }); + push (@bug_ids, $id); + push (@all_bug_ids, $id); + } + + $onevoteonly = 1 if (min($product->{votesperuser}, + $product->{maxvotesperbug}) == 1); + + # Only add the product for display if there are any bugs in it. + if ($#bugs > -1) { + push (@products, { name => $product->name, + bugs => \@bugs, + bug_ids => \@bug_ids, + onevoteonly => $onevoteonly, + total => $total, + maxvotes => $product->{votesperuser}, + maxperbug => $product->{maxvotesperbug} }); + } + } + + $dbh->do('DELETE FROM votes WHERE vote_count <= 0'); + $dbh->bz_commit_transaction(); + + $vars->{'canedit'} = $canedit; + $vars->{'voting_user'} = { "login" => $who->name }; + $vars->{'products'} = \@products; + $vars->{'this_bug'} = $bug; + $vars->{'all_bug_ids'} = \@all_bug_ids; +} + +sub _update_votes { + my ($vars) = @_; + + ############################################################################ + # Begin Data/Security Validation + ############################################################################ + + my $cgi = Bugzilla->cgi; + my $dbh = Bugzilla->dbh; + my $template = Bugzilla->template; + my $user = Bugzilla->login(LOGIN_REQUIRED); + my $input = Bugzilla->input_params; + + # Build a list of bug IDs for which votes have been submitted. Votes + # are submitted in form fields in which the field names are the bug + # IDs and the field values are the number of votes. + + my @buglist = grep {/^\d+$/} keys %$input; + + # If no bugs are in the buglist, let's make sure the user gets notified + # that their votes will get nuked if they continue. + if (scalar(@buglist) == 0) { + if (!defined $cgi->param('delete_all_votes')) { + print $cgi->header(); + $template->process("voting/delete-all.html.tmpl", $vars) + || ThrowTemplateError($template->error()); + exit; + } + elsif ($cgi->param('delete_all_votes') == 0) { + print $cgi->redirect("page.cgi?id=voting/user.html"); + exit; + } + } + + # Call check() on each bug ID to make sure it is a positive + # integer representing an existing bug that the user is authorized + # to access, and make sure the number of votes submitted is also + # a non-negative integer (a series of digits not preceded by a + # minus sign). + my (%votes, @bugs); + foreach my $id (@buglist) { + my $bug = Bugzilla::Bug->check($id); + push(@bugs, $bug); + $id = $bug->id; + $votes{$id} = $input->{$id}; + detaint_natural($votes{$id}) + || ThrowUserError("voting_must_be_nonnegative"); + } + + ############################################################################ + # End Data/Security Validation + ############################################################################ + my $who = $user->id; + + # If the user is voting for bugs, make sure they aren't overstuffing + # the ballot box. + if (scalar @bugs) { + my (%prodcount, %products); + foreach my $bug (@bugs) { + my $bug_id = $bug->id; + my $prod = $bug->product; + $products{$prod} ||= $bug->product_obj; + $prodcount{$prod} ||= 0; + $prodcount{$prod} += $votes{$bug_id}; + + # Make sure we haven't broken the votes-per-bug limit + ($votes{$bug_id} <= $products{$prod}->{maxvotesperbug}) + || ThrowUserError("voting_too_many_votes_for_bug", + {max => $products{$prod}->{maxvotesperbug}, + product => $prod, + votes => $votes{$bug_id}}); + } + + # Make sure we haven't broken the votes-per-product limit + foreach my $prod (keys(%prodcount)) { + ($prodcount{$prod} <= $products{$prod}->{votesperuser}) + || ThrowUserError("voting_too_many_votes_for_product", + {max => $products{$prod}->{votesperuser}, + product => $prod, + votes => $prodcount{$prod}}); + } + } + + # Update the user's votes in the database. If the user did not submit + # any votes, they may be using a form with checkboxes to remove all their + # votes (checkboxes are not submitted along with other form data when + # they are not checked, and Bugzilla uses them to represent single votes + # for products that only allow one vote per bug). In that case, we still + # need to clear the user's votes from the database. + my %affected; + $dbh->bz_start_transaction(); + + # Take note of, and delete the user's old votes from the database. + my $bug_list = $dbh->selectcol_arrayref('SELECT bug_id FROM votes + WHERE who = ?', undef, $who); + + foreach my $id (@$bug_list) { + $affected{$id} = 1; + } + $dbh->do('DELETE FROM votes WHERE who = ?', undef, $who); + + my $sth_insertVotes = $dbh->prepare('INSERT INTO votes (who, bug_id, vote_count) + VALUES (?, ?, ?)'); + + # Insert the new values in their place + foreach my $id (@buglist) { + if ($votes{$id} > 0) { + $sth_insertVotes->execute($who, $id, $votes{$id}); + } + $affected{$id} = 1; + } + + # Update the cached values in the bugs table + print $cgi->header(); + my @updated_bugs = (); + + my $sth_getVotes = $dbh->prepare("SELECT SUM(vote_count) FROM votes + WHERE bug_id = ?"); + + my $sth_updateVotes = $dbh->prepare("UPDATE bugs SET votes = ? + WHERE bug_id = ?"); + + foreach my $id (keys %affected) { + $sth_getVotes->execute($id); + my $v = $sth_getVotes->fetchrow_array || 0; + $sth_updateVotes->execute($v, $id); + + my $confirmed = _confirm_if_vote_confirmed($id); + push (@updated_bugs, $id) if $confirmed; + } + + $dbh->bz_commit_transaction(); + + $vars->{'type'} = "votes"; + $vars->{'mailrecipients'} = { 'changer' => $user->login }; + $vars->{'title_tag'} = 'change_votes'; + foreach my $bug_id (@updated_bugs) { + $vars->{'id'} = $bug_id; + $template->process("bug/process/results.html.tmpl", $vars) + || ThrowTemplateError($template->error()); + # Set header_done to 1 only after the first bug. + $vars->{'header_done'} = 1; + } + $vars->{'votes_recorded'} = 1; +} + +###################### +# Helper Subroutines # +###################### + +sub _modify_bug_votes { + my ($product, $changes) = @_; + my $dbh = Bugzilla->dbh; + my @msgs; + + # 1. too many votes for a single user on a single bug. + my @toomanyvotes_list; + if ($product->{maxvotesperbug} < $product->{votesperuser}) { + my $votes = $dbh->selectall_arrayref( + 'SELECT votes.who, votes.bug_id + FROM votes + INNER JOIN bugs ON bugs.bug_id = votes.bug_id + WHERE bugs.product_id = ? + AND votes.vote_count > ?', + undef, ($product->id, $product->{maxvotesperbug})); + + foreach my $vote (@$votes) { + my ($who, $id) = (@$vote); + # If some votes are removed, _remove_votes() returns a list + # of messages to send to voters. + push(@msgs, _remove_votes($id, $who, 'votes_too_many_per_bug')); + my $name = user_id_to_login($who); + + push(@toomanyvotes_list, {id => $id, name => $name}); + } + } + + $changes->{'too_many_votes'} = \@toomanyvotes_list; + + # 2. too many total votes for a single user. + # This part doesn't work in the general case because _remove_votes + # doesn't enforce votesperuser (except per-bug when it's less + # than maxvotesperbug). See _remove_votes(). + + my $votes = $dbh->selectall_arrayref( + 'SELECT votes.who, votes.vote_count + FROM votes + INNER JOIN bugs ON bugs.bug_id = votes.bug_id + WHERE bugs.product_id = ?', + undef, $product->id); + + my %counts; + foreach my $vote (@$votes) { + my ($who, $count) = @$vote; + if (!defined $counts{$who}) { + $counts{$who} = $count; + } else { + $counts{$who} += $count; + } + } + + my @toomanytotalvotes_list; + foreach my $who (keys(%counts)) { + if ($counts{$who} > $product->{votesperuser}) { + my $bug_ids = $dbh->selectcol_arrayref( + 'SELECT votes.bug_id + FROM votes + INNER JOIN bugs ON bugs.bug_id = votes.bug_id + WHERE bugs.product_id = ? + AND votes.who = ?', + undef, $product->id, $who); + + foreach my $bug_id (@$bug_ids) { + # _remove_votes returns a list of messages to send + # in case some voters had too many votes. + push(@msgs, _remove_votes($bug_id, $who, + 'votes_too_many_per_user')); + my $name = user_id_to_login($who); + + push(@toomanytotalvotes_list, {id => $bug_id, name => $name}); + } + } + } + + $changes->{'too_many_total_votes'} = \@toomanytotalvotes_list; + + # 3. enough votes to confirm + my $bug_list = $dbh->selectcol_arrayref( + 'SELECT bug_id FROM bugs + WHERE product_id = ? AND bug_status = ? AND votes >= ?', + undef, ($product->id, 'UNCONFIRMED', $product->{votestoconfirm})); + + my @updated_bugs; + foreach my $bug_id (@$bug_list) { + my $confirmed = _confirm_if_vote_confirmed($bug_id); + push (@updated_bugs, $bug_id) if $confirmed; + } + $changes->{'confirmed_bugs'} = \@updated_bugs; + + # Now that changes are done, we can send emails to voters. + foreach my $msg (@msgs) { + MessageToMTA($msg); + } +} + +# If a bug is moved to a product which allows less votes per bug +# compared to the previous product, extra votes need to be removed. +sub _remove_votes { + my ($id, $who, $reason) = (@_); + my $dbh = Bugzilla->dbh; + + my $whopart = ($who) ? " AND votes.who = $who" : ""; + + my $sth = $dbh->prepare("SELECT profiles.login_name, " . + "profiles.userid, votes.vote_count, " . + "products.votesperuser, products.maxvotesperbug " . + "FROM profiles " . + "LEFT JOIN votes ON profiles.userid = votes.who " . + "LEFT JOIN bugs ON votes.bug_id = bugs.bug_id " . + "LEFT JOIN products ON products.id = bugs.product_id " . + "WHERE votes.bug_id = ? " . $whopart); + $sth->execute($id); + my @list; + while (my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = $sth->fetchrow_array()) { + push(@list, [$name, $userid, $oldvotes, $votesperuser, $maxvotesperbug]); + } + + # @messages stores all emails which have to be sent, if any. + # This array is passed to the caller which will send these emails itself. + my @messages = (); + + if (scalar(@list)) { + foreach my $ref (@list) { + my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = (@$ref); + + $maxvotesperbug = min($votesperuser, $maxvotesperbug); + + # If this product allows voting and the user's votes are in + # the acceptable range, then don't do anything. + next if $votesperuser && $oldvotes <= $maxvotesperbug; + + # If the user has more votes on this bug than this product + # allows, then reduce the number of votes so it fits + my $newvotes = $maxvotesperbug; + + my $removedvotes = $oldvotes - $newvotes; + + if ($newvotes) { + $dbh->do("UPDATE votes SET vote_count = ? " . + "WHERE bug_id = ? AND who = ?", + undef, ($newvotes, $id, $userid)); + } else { + $dbh->do("DELETE FROM votes WHERE bug_id = ? AND who = ?", + undef, ($id, $userid)); + } + + # Notice that we did not make sure that the user fit within the $votesperuser + # range. This is considered to be an acceptable alternative to losing votes + # during product moves. Then next time the user attempts to change their votes, + # they will be forced to fit within the $votesperuser limit. + + # Now lets send the e-mail to alert the user to the fact that their votes have + # been reduced or removed. + my $vars = { + 'to' => $name . Bugzilla->params->{'emailsuffix'}, + 'bugid' => $id, + 'reason' => $reason, + + 'votesremoved' => $removedvotes, + 'votesold' => $oldvotes, + 'votesnew' => $newvotes, + }; + + my $voter = new Bugzilla::User($userid); + my $template = Bugzilla->template_inner($voter->settings->{'lang'}->{'value'}); + + my $msg; + $template->process("voting/votes-removed.txt.tmpl", $vars, \$msg); + push(@messages, $msg); + } + Bugzilla->template_inner(""); + + my $votes = $dbh->selectrow_array("SELECT SUM(vote_count) " . + "FROM votes WHERE bug_id = ?", + undef, $id) || 0; + $dbh->do("UPDATE bugs SET votes = ? WHERE bug_id = ?", + undef, ($votes, $id)); + } + # Now return the array containing emails to be sent. + return @messages; +} + +# If a user votes for a bug, or the number of votes required to +# confirm a bug has been reduced, check if the bug is now confirmed. +sub _confirm_if_vote_confirmed { + my $id = shift; + my $bug = new Bugzilla::Bug($id); + + my $ret = 0; + if (!$bug->everconfirmed + and $bug->product_obj->{votestoconfirm} + and $bug->votes >= $bug->product_obj->{votestoconfirm}) + { + $bug->add_comment('', { type => CMT_POPULAR_VOTES }); + + if ($bug->bug_status eq 'UNCONFIRMED') { + # Get a valid open state. + my $new_status; + foreach my $state (@{$bug->status->can_change_to}) { + if ($state->is_open && $state->name ne 'UNCONFIRMED') { + $new_status = $state->name; + last; + } + } + ThrowCodeError('no_open_bug_status') unless $new_status; + + # We cannot call $bug->set_status() here, because a user without + # canconfirm privs should still be able to confirm a bug by + # popular vote. We already know the new status is valid, so it's safe. + $bug->{bug_status} = $new_status; + $bug->{everconfirmed} = 1; + delete $bug->{'status'}; # Contains the status object. + } + else { + # If the bug is in a closed state, only set everconfirmed to 1. + # Do not call $bug->_set_everconfirmed(), for the same reason as above. + $bug->{everconfirmed} = 1; + } + $bug->update(); + + $ret = 1; + } + return $ret; +} + + +__PACKAGE__->NAME; diff --git a/extensions/Voting/template/en/default/hook/account/prefs/email-relationships.html.tmpl b/extensions/Voting/template/en/default/hook/account/prefs/email-relationships.html.tmpl new file mode 100644 index 000000000..0bd81eae1 --- /dev/null +++ b/extensions/Voting/template/en/default/hook/account/prefs/email-relationships.html.tmpl @@ -0,0 +1,22 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% relationships.push({ id = constants.REL_VOTER, description = "Voter" }) %] +[% no_added_removed.push(constants.REL_VOTER) %] diff --git a/extensions/Voting/template/en/default/hook/admin/products/edit-common-rows.html.tmpl b/extensions/Voting/template/en/default/hook/admin/products/edit-common-rows.html.tmpl new file mode 100644 index 000000000..fbbda3ea0 --- /dev/null +++ b/extensions/Voting/template/en/default/hook/admin/products/edit-common-rows.html.tmpl @@ -0,0 +1,60 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% DEFAULT + product.maxvotesperbug = constants.DEFAULT_VOTES_PER_BUG + product.votesperuser = 0 + product.votestoconfirm = 0 +%] + + + Maximum votes per person: + + + + + + + Maximum votes a person can put on a single [% terms.bug %]: + + + + + + + + Confirm [% terms.abug %] if it gets this many votes: + + + +
(Setting this to 0 disables auto-confirming [% terms.bugs %] + by vote.) + + + + diff --git a/extensions/Voting/template/en/default/hook/admin/products/updated-changes.html.tmpl b/extensions/Voting/template/en/default/hook/admin/products/updated-changes.html.tmpl new file mode 100644 index 000000000..876c51187 --- /dev/null +++ b/extensions/Voting/template/en/default/hook/admin/products/updated-changes.html.tmpl @@ -0,0 +1,102 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% SET checkvotes = 0 %] + +[% IF changes.votesperuser.defined %] +

+ Updated votes per user from + [%+ changes.votesperuser.0 FILTER html %] to + [%+ product.votesperuser FILTER html %]. +

+ [% checkvotes = 1 %] +[% END %] + +[% IF changes.maxvotesperbug.defined %] +

+ Updated maximum votes per [% terms.bug %] from + [%+ changes.maxvotesperbug.0 FILTER html %] to + [%+ product.maxvotesperbug FILTER html %]. +

+ [% checkvotes = 1 %] +[% END %] + +[% IF changes.votestoconfirm.defined %] +

+ Updated number of votes needed to confirm a [% terms.bug %] from + [%+ changes.votestoconfirm.0 FILTER html %] to + [%+ product.votestoconfirm FILTER html %]. +

+ [% checkvotes = 1 %] +[% END %] + +[%# Note that this display of changed votes and/or confirmed bugs is + not very scalable. We could have a _lot_, and we just list them all. + One day we should limit this perhaps, or have a more scalable display %] + +[% IF checkvotes %] +
+ +

Checking existing votes in this product for anybody who now + has too many votes for [% terms.abug %]...
+ [% IF changes.too_many_votes.size %] + [% FOREACH detail = changes.too_many_votes %] + →removed votes for [% terms.bug %] + [%- detail.id FILTER html %] from [% detail.name FILTER html %]
+ [% END %] + [% ELSE %] + →there were none. + [% END %] +

+ +

Checking existing votes in this product for anybody + who now has too many total votes...
+ [% IF changes.too_many_total_votes.size %] + [% FOREACH detail = changes.too_many_total_votes %] + →removed votes for [% terms.bug %] + [%- detail.id FILTER html %] from [% detail.name FILTER html %]
+ [% END %] + [% ELSE %] + →there were none. + [% END %] +

+ +

Checking unconfirmed [% terms.bugs %] in this product for any which now have + sufficient votes...
+ [% IF changes.confirmed_bugs.size %] + [% FOREACH id = changes.confirmed_bugs %] + + [%# This is INCLUDED instead of PROCESSED to avoid variables getting + overwritten, which happens otherwise %] + [% INCLUDE bug/process/results.html.tmpl + type = 'votes' + mailrecipients = { 'changer' => user.login } + header_done = 1 + id = id + %] + [% END %] + [% ELSE %] + →there were none. + [% END %] +

+ +[% END %] diff --git a/extensions/Voting/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl b/extensions/Voting/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl new file mode 100644 index 000000000..afb81d34c --- /dev/null +++ b/extensions/Voting/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl @@ -0,0 +1,40 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% IF san_tag == "voting_cache_rebuild_fix" %] + Click here to + rebuild the vote cache + +[% ELSIF san_tag == "voting_cache_alert" %] + Bad vote cache for [% PROCESS bug_link bug_id = id %] + +[% ELSIF san_tag == "voting_count_start" %] + Checking cached vote counts. + +[% ELSIF san_tag == "voting_count_alert" %] + Bad vote sum for [% terms.bug %] [%+ id FILTER html %]. + +[% ELSIF san_tag == "voting_cache_rebuild_start" %] + OK, now rebuilding vote cache. + +[% ELSIF san_tag == "voting_cache_rebuild_end" %] + Vote cache has been rebuilt + +[% END %] diff --git a/extensions/Voting/template/en/default/hook/admin/users/confirm-delete-warn_safe.html.tmpl b/extensions/Voting/template/en/default/hook/admin/users/confirm-delete-warn_safe.html.tmpl new file mode 100644 index 000000000..f799f1254 --- /dev/null +++ b/extensions/Voting/template/en/default/hook/admin/users/confirm-delete-warn_safe.html.tmpl @@ -0,0 +1,38 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% IF votes %] +
  • + [% otheruser.login FILTER html %] has voted on + [% IF votes == 1 %] + [%+ terms.abug %] + [% ELSE %] + [%+ votes %] [%+ terms.bugs %] + [% END %]. + + If you delete the user account, + [% IF votes == 1 %] + this vote + [% ELSE %] + these votes + [% END %] + will be deleted along with the user account. +
  • +[% END %] diff --git a/extensions/Voting/template/en/default/hook/bug/edit-after_importance.html.tmpl b/extensions/Voting/template/en/default/hook/bug/edit-after_importance.html.tmpl new file mode 100644 index 000000000..7952442da --- /dev/null +++ b/extensions/Voting/template/en/default/hook/bug/edit-after_importance.html.tmpl @@ -0,0 +1,41 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] +[% IF bug.product_obj.votesperuser %] + + + + [% IF bug.votes %] + with + + [%- bug.votes %] + [% IF bug.votes == 1 %] + vote + [% ELSE %] + votes + [% END %] + [% END %] + (vote) + +[% END %] diff --git a/extensions/Voting/template/en/default/hook/bug/format_comment-type.txt.tmpl b/extensions/Voting/template/en/default/hook/bug/format_comment-type.txt.tmpl new file mode 100644 index 000000000..ebba6fcab --- /dev/null +++ b/extensions/Voting/template/en/default/hook/bug/format_comment-type.txt.tmpl @@ -0,0 +1,23 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% IF comment.type == constants.CMT_POPULAR_VOTES %] +*** This [% terms.bug %] has been confirmed by popular vote. *** +[% END %] diff --git a/extensions/Voting/template/en/default/hook/bug/process/header-title.html.tmpl b/extensions/Voting/template/en/default/hook/bug/process/header-title.html.tmpl new file mode 100644 index 000000000..a4530653b --- /dev/null +++ b/extensions/Voting/template/en/default/hook/bug/process/header-title.html.tmpl @@ -0,0 +1,24 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% IF title_tag == "change_votes" %] + [% title = "Change Votes" %] +[% END %] + diff --git a/extensions/Voting/template/en/default/hook/bug/process/results-title.html.tmpl b/extensions/Voting/template/en/default/hook/bug/process/results-title.html.tmpl new file mode 100644 index 000000000..ae0d465dc --- /dev/null +++ b/extensions/Voting/template/en/default/hook/bug/process/results-title.html.tmpl @@ -0,0 +1,21 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% title.votes = "$Link confirmed by number of votes" %] diff --git a/extensions/Voting/template/en/default/hook/global/field-descs-end.none.tmpl b/extensions/Voting/template/en/default/hook/global/field-descs-end.none.tmpl new file mode 100644 index 000000000..2fd798084 --- /dev/null +++ b/extensions/Voting/template/en/default/hook/global/field-descs-end.none.tmpl @@ -0,0 +1,22 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% field_descs.votes = "Votes" %] + diff --git a/extensions/Voting/template/en/default/hook/global/reason-descs-end.none.tmpl b/extensions/Voting/template/en/default/hook/global/reason-descs-end.none.tmpl new file mode 100644 index 000000000..3a1f5a189 --- /dev/null +++ b/extensions/Voting/template/en/default/hook/global/reason-descs-end.none.tmpl @@ -0,0 +1,23 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% reason_descs.${constants.REL_VOTER} = "You voted for the ${terms.bug}." %] +[% watch_reason_descs.${constants.REL_VOTER} = + "You are watching a voter for the ${terms.bug}." %] diff --git a/extensions/Voting/template/en/default/hook/global/user-error-errors.html.tmpl b/extensions/Voting/template/en/default/hook/global/user-error-errors.html.tmpl new file mode 100644 index 000000000..c2ff70728 --- /dev/null +++ b/extensions/Voting/template/en/default/hook/global/user-error-errors.html.tmpl @@ -0,0 +1,55 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% IF error == "voting_must_be_nonnegative" %] + [% title = "Votes Must Be Non-negative" %] + [% admindocslinks = {'voting.html' => 'Setting up the voting feature'} %] + Only use non-negative numbers for your [% terms.bug %] votes. + +[% ELSIF error == "voting_product_illegal_votes" %] + [% title = "Votes Must Be Non-negative" %] + [% admindocslinks = {'voting.html' => 'Setting up the voting feature'} %] + '[% votes FILTER html %]' is an invalid value for the + + [% IF field == "votesperuser" %] + Votes Per User + [% ELSIF field == "maxvotesperbug" %] + Maximum Votes Per [% terms.Bug %] + [% ELSIF field == "votestoconfirm" %] + Votes To Confirm + [% END %] + field, which should contain a non-negative number. + +[% ELSIF error == "voting_too_many_votes_for_bug" %] + [% title = "Illegal Vote" %] + [% admindocslinks = {'voting.html' => 'Setting up the voting feature'} %] + You may only use at most [% max FILTER html %] votes for a single + [%+ terms.bug %] in the + [% product FILTER html %] product, but you are trying to + use [% votes FILTER html %]. + +[% ELSIF error == "voting_too_many_votes_for_product" %] + [% title = "Illegal Vote" %] + [% admindocslinks = {'voting.html' => 'Setting up the voting feature'} %] + You tried to use [% votes FILTER html %] votes in the + [% product FILTER html %] product, which exceeds the maximum of + [%+ max FILTER html %] votes for this product. + +[% END %] diff --git a/extensions/Voting/template/en/default/hook/search/form-email_numbering_end.html.tmpl b/extensions/Voting/template/en/default/hook/search/form-email_numbering_end.html.tmpl new file mode 100644 index 000000000..5acfff14c --- /dev/null +++ b/extensions/Voting/template/en/default/hook/search/form-email_numbering_end.html.tmpl @@ -0,0 +1,31 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + + + + : + + + votes + + + + diff --git a/extensions/Voting/template/en/default/hook/search/search-report-select-rep_fields.html.tmpl b/extensions/Voting/template/en/default/hook/search/search-report-select-rep_fields.html.tmpl new file mode 100644 index 000000000..ca74f6d2d --- /dev/null +++ b/extensions/Voting/template/en/default/hook/search/search-report-select-rep_fields.html.tmpl @@ -0,0 +1,21 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% rep_fields.push('votes') %] diff --git a/extensions/Voting/template/en/default/pages/voting.html.tmpl b/extensions/Voting/template/en/default/pages/voting.html.tmpl new file mode 100644 index 000000000..99026c0d5 --- /dev/null +++ b/extensions/Voting/template/en/default/pages/voting.html.tmpl @@ -0,0 +1,69 @@ +[%# 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 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): Terry Weissman + # Gervase Markham + #%] + +[% PROCESS global/variables.none.tmpl %] +[% INCLUDE global/header.html.tmpl title = "Voting" %] + +

    [% terms.Bugzilla %] has a "voting" feature. Each product allows users to +have a certain number of votes. (Some products may not allow any, which means +you can't vote on things in those products at all.) With your vote, you +indicate which [% terms.bugs %] you think are the most important and +would like to see fixed. Note that voting is nowhere near as effective +as providing a fix yourself.

    + +

    Depending on how the administrator has configured the relevant product, +you may be able to vote for the same [% terms.bug %] more than once. +Remember that you have a limited number of votes. When weighted voting +is allowed and a limited number of votes are available to you, you will +have to decide whether you want to distribute your votes among a large +number of [% terms.bugs %] indicating your minimal interest or focus on +a few [% terms.bugs %] indicating your strong support for them. +

    + +

    To look at votes:

    + +
      +
    • Go to the query page. Do a normal query, but enter 1 in the "At least + ___ votes" field. This will show you items that match your query that + have at least one vote.
    • +
    + +

    To vote for [% terms.abug %]:

    + +
      +
    • Bring up the [% terms.bug %] in question.
    • + +
    • Click on the "(vote)" link that appears on the right of the "Importance" + fields. (If no such link appears, then voting may not be allowed in + this [% terms.bug %]'s product.)
    • + +
    • Indicate how many votes you want to give this [% terms.bug %]. This page + also displays how many votes you've given to other [% terms.bugs %], so you + may rebalance your votes as necessary.
    • +
    + +

    You will automatically get email notifying you of any changes that occur +on [% terms.bugs %] you vote for.

    + +

    You may review your votes at any time by clicking on the "My Votes" link in the page footer.

    + +[% INCLUDE global/footer.html.tmpl %] diff --git a/extensions/Voting/template/en/default/pages/voting/bug.html.tmpl b/extensions/Voting/template/en/default/pages/voting/bug.html.tmpl new file mode 100644 index 000000000..03434a505 --- /dev/null +++ b/extensions/Voting/template/en/default/pages/voting/bug.html.tmpl @@ -0,0 +1,61 @@ +[%# 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 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 + # Max Kanat-Alexander + #%] + +[%# INTERFACE: + # bug: Bugzilla::Bug that we are listing the votes for. + # users: list of hashes. May be empty. Each hash has two members: + # login_name: string. The login name of the user whose vote is attached + # vote_count: integer. The number of times that user has votes for this bug. + #%] + +[% PROCESS global/variables.none.tmpl %] + +[% PROCESS global/header.html.tmpl + title = "Show Votes" + subheader = "$terms.Bug $bug.id" FILTER bug_link(bug) + %] + +[% total = 0 %] + + + + + + + [% FOREACH voter = users %] + [% total = total + voter.vote_count %] + + + + + [% END %] +
    WhoNumber of votes
    + + [% voter.login_name FILTER email FILTER html %] + + + [% voter.vote_count FILTER html %] +
    + +

    Total votes: [% total FILTER html %]

    + +[% PROCESS global/footer.html.tmpl %] diff --git a/extensions/Voting/template/en/default/pages/voting/user.html.tmpl b/extensions/Voting/template/en/default/pages/voting/user.html.tmpl new file mode 100644 index 000000000..800079224 --- /dev/null +++ b/extensions/Voting/template/en/default/pages/voting/user.html.tmpl @@ -0,0 +1,185 @@ +[%# 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 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 + #%] + +[%# INTERFACE: + # voting_user: hash containing a 'login' field + # + # products: list of hashes containing details of products relating to + # voting: + # name: name of product + # bugs: list of bugs the user has voted for + # bug_ids: list of bug ids the user has voted for + # onevoteonly: one or more votes allowed per bug? + # total: users current vote count for the product + # maxvotes: max votes allowed for a user in this product + # maxperbug: max votes per bug allowed for a user in this product + # + # this_bug: Bugzilla::Bug; if the user is voting for a bug, this is the bug + # + # canedit: boolean; Should the votes be presented in a form, or readonly? + # + # all_bug_ids: List of all bug ids the user has voted for, across all products + #%] + +[% PROCESS global/variables.none.tmpl %] + +[% IF !header_done %] + [% subheader = voting_user.login FILTER html %] + [% IF canedit %] + [% title = "Change Votes" %] + [% IF this_bug %] + [%# We .select and .focus the input so it works for textbox and + checkbox %] + [% onload = "document.forms['voting_form'].bug_" _ this_bug.id _ + ".select();document.forms['voting_form'].bug_" _ this_bug.id _ + ".focus()" %] + [% END %] + [% ELSE %] + [% title = "Show Votes" %] + [% END %] + [% PROCESS global/header.html.tmpl + style_urls = [ "extensions/Voting/web/style.css" ] + %] +[% ELSE %] +
    +[% END %] + +[% IF votes_recorded %] +

    + + The changes to your votes have been saved. + +

    +[% ELSE %] +
    +[% END %] + +[% IF products.size %] +
    + + + + + + + + + + [% onevoteproduct = 0 %] + [% multivoteproduct = 0 %] + [% FOREACH product = products %] + [% IF product.onevoteonly %] + [% onevoteproduct = 1 %] + [% ELSE %] + [% multivoteproduct = 1 %] + [% END %] + + + + + + + [% FOREACH bug = product.bugs %] + + + + + + + [% END %] + + + + + + [% END %] +
    Votes[% terms.Bug %] #Summary
    [% product.name FILTER html %]([% terms.bug %] list) + + [% IF product.maxperbug < product.maxvotes AND + product.maxperbug > 1 %] + + (Note: only [% product.maxperbug %] vote + [% "s" IF product.maxperbug != 1 %] allowed per [% terms.bug %] in + this product.) + + [% END %] +
    [% IF bug.id == this_bug.id && canedit %]Enter New Vote here → + [%- END %] + [% IF canedit %] + [% IF product.onevoteonly %] + + [% ELSE %] + + [% END %] + [% ELSE %] + [% bug.count %] + [% END %] + + [% bug.id FILTER bug_link(bug) FILTER none %] + + [% bug.summary FILTER html %] + (Show Votes) +
    [% product.total %] vote + [% "s" IF product.total != 1 %] used out of [% product.maxvotes %] + allowed. +
    +
    +
    + + [% IF canedit %] + or + view all + as [% terms.bug %] list +
    +
    + To change your votes, + [% IF multivoteproduct %] + type in new numbers (using zero to mean no votes) + [% " or " IF onevoteproduct %] + [% END %] + [% IF onevoteproduct %] + change the checkbox + [% END %] + and then click Change My Votes. + [% ELSE %] + View all + as [% terms.bug %] list + [% END %] +
    +[% ELSE %] +

    + [% IF canedit %] + You are + [% ELSE %] + This user is + [% END %] + currently not voting on any [% terms.bugs %]. +

    +[% END %] + +

    + Help with voting. +

    + +[% PROCESS global/footer.html.tmpl %] diff --git a/extensions/Voting/template/en/default/voting/delete-all.html.tmpl b/extensions/Voting/template/en/default/voting/delete-all.html.tmpl new file mode 100644 index 000000000..82ddc3596 --- /dev/null +++ b/extensions/Voting/template/en/default/voting/delete-all.html.tmpl @@ -0,0 +1,51 @@ +[%# 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 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 + #%] + +[%# INTERFACE: + # This template has no interface. + #%] + +[% PROCESS global/variables.none.tmpl %] + +[% PROCESS global/header.html.tmpl + title = "Remove your votes?" + %] + +

    + You are about to remove all of your [% terms.bug %] votes. Are you sure you wish to + remove your vote from every [% terms.bug %] you've voted on? +

    + +
    + +

    + + Yes, delete all my votes +

    +

    + + No, go back and review my votes +

    +

    + +

    +
    + +[% PROCESS global/footer.html.tmpl %] diff --git a/extensions/Voting/template/en/default/voting/votes-removed.txt.tmpl b/extensions/Voting/template/en/default/voting/votes-removed.txt.tmpl new file mode 100644 index 000000000..bfb37c90d --- /dev/null +++ b/extensions/Voting/template/en/default/voting/votes-removed.txt.tmpl @@ -0,0 +1,55 @@ +[%# 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 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): Emmanuel Seyman + #%] + +[% PROCESS global/variables.none.tmpl %] + +From: [% Param('mailfrom') %] +To: [% to %] +Subject: [% terms.Bug %] [%+ bugid %] Some or all of your votes have been removed. +X-Bugzilla-Type: voteremoved + +Some or all of your votes have been removed from [% terms.bug %] [%+ bugid %]. + +You had [% votesold FILTER html %] [%+ IF votesold == 1 %]vote[% ELSE %]votes[% END +%] on this [% terms.bug %], but [% votesremoved FILTER html %] have been removed. + +[% IF votesnew %] +You still have [% votesnew FILTER html %] [%+ IF votesnew == 1 %]vote[% ELSE %]votes[% END %] on this [% terms.bug %]. +[% ELSE %] +You have no more votes remaining on this [% terms.bug %]. +[% END %] + +Reason: +[% IF reason == "votes_bug_moved" %] + This [% terms.bug %] has been moved to a different product. + +[% ELSIF reason == "votes_too_many_per_bug" %] + The rules for voting on this product has changed; + you had too many votes for a single [% terms.bug %]. + +[% ELSIF reason == "votes_too_many_per_user" %] + The rules for voting on this product has changed; you had + too many total votes, so all votes have been removed. +[% END %] + + + +[% urlbase %]show_bug.cgi?id=[% bugid %] + diff --git a/extensions/Voting/web/style.css b/extensions/Voting/web/style.css new file mode 100644 index 000000000..5d9c9afe6 --- /dev/null +++ b/extensions/Voting/web/style.css @@ -0,0 +1,24 @@ +/* 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 Bugzilla Bug Tracking System. + * + * Contributor(s): Gavin Shelley + */ + +/* Highlight the row for the bug being voted on */ +tr.bz_bug_being_voted_on { + background-color: #e2e2e2; +} + +tr.bz_bug_being_voted_on td { + border-style: solid none solid none; + border-width: thin; +} diff --git a/importxml.pl b/importxml.pl index 1a61c5ead..aff475b70 100755 --- a/importxml.pl +++ b/importxml.pl @@ -980,7 +980,6 @@ sub process_bug { if($status eq "UNCONFIRMED"){ $err .= "Bug Status was UNCONFIRMED but everconfirmed was true\n"; $err .= " Setting status to $initial_status\n"; - $err .= "Resetting votes to 0\n" if ( $bug_fields{'votes'} ); $status = $initial_status; } } diff --git a/process_bug.cgi b/process_bug.cgi index 237588ebd..d16298df6 100755 --- a/process_bug.cgi +++ b/process_bug.cgi @@ -573,27 +573,12 @@ foreach my $bug (@bug_objects) { # an error later. delete $changed_deps{''}; - # @msgs will store emails which have to be sent to voters, if any. - my @msgs; - if ($changes->{'product'}) { - # If some votes have been removed, RemoveVotes() returns - # a list of messages to send to voters. - # We delay the sending of these messages till changes are committed. - @msgs = RemoveVotes($bug->id, 0, 'votes_bug_moved'); - CheckIfVotedConfirmed($bug->id); - } - $dbh->bz_commit_transaction(); ############### # Send Emails # ############### - # Now is a good time to send email to voters. - foreach my $msg (@msgs) { - MessageToMTA($msg); - } - my $old_qa = $changes->{'qa_contact'} ? $changes->{'qa_contact'}->[0] : ''; my $old_own = $changes->{'assigned_to'} ? $changes->{'assigned_to'}->[0] : ''; my $old_cc = $changes->{cc} ? $changes->{cc}->[0] : ''; diff --git a/query.cgi b/query.cgi index 1cbcf0a60..101c90700 100755 --- a/query.cgi +++ b/query.cgi @@ -127,7 +127,7 @@ sub PrefillForm { "email", "emailtype", "emailreporter", "emailassigned_to", "emailcc", "emailqa_contact", "emaillongdesc", "content", - "changedin", "votes", "short_desc", "short_desc_type", + "changedin", "short_desc", "short_desc_type", "longdesc", "longdesc_type", "bug_file_loc", "bug_file_loc_type", "status_whiteboard", "status_whiteboard_type", "bug_id", diff --git a/report.cgi b/report.cgi index 6612ded2a..100c76e90 100755 --- a/report.cgi +++ b/report.cgi @@ -113,7 +113,6 @@ my @columns = qw( qa_contact classification version - votes keywords target_milestone ); diff --git a/sanitycheck.cgi b/sanitycheck.cgi index 036286454..4b6e524c2 100755 --- a/sanitycheck.cgi +++ b/sanitycheck.cgi @@ -102,7 +102,7 @@ unless (Bugzilla->usage_mode == USAGE_MODE_CMDLINE) { # Users with 'editkeywords' privs only can only check keywords. ########################################################################### unless ($user->in_group('editcomponents')) { - check_votes_or_keywords('keywords'); + check_keywords(); Status('checks_completed'); $template->process('global/footer.html.tmpl', $vars) @@ -110,27 +110,6 @@ unless ($user->in_group('editcomponents')) { exit; } -########################################################################### -# Fix vote cache -########################################################################### - -if ($cgi->param('rebuildvotecache')) { - Status('vote_cache_rebuild_start'); - $dbh->bz_start_transaction(); - $dbh->do(q{UPDATE bugs SET votes = 0}); - my $sth_update = $dbh->prepare(q{UPDATE bugs - SET votes = ? - WHERE bug_id = ?}); - my $sth = $dbh->prepare(q{SELECT bug_id, SUM(vote_count) - FROM votes }. $dbh->sql_group_by('bug_id')); - $sth->execute(); - while (my ($id, $v) = $sth->fetchrow_array) { - $sth_update->execute($v, $id); - } - $dbh->bz_commit_transaction(); - Status('vote_cache_rebuild_end'); -} - ########################################################################### # Create missing group_control_map entries ########################################################################### @@ -310,7 +289,7 @@ if ($cgi->param('remove_invalid_bug_references')) { 'bugs_fulltext/', 'cc/', 'dependencies/blocked', 'dependencies/dependson', 'duplicates/dupe', 'duplicates/dupe_of', - 'flags/', 'keywords/', 'longdescs/', 'votes/') { + 'flags/', 'keywords/', 'longdescs/') { my ($table, $field) = split('/', $pair); $field ||= "bug_id"; @@ -489,7 +468,6 @@ CrossCheck("bugs", "bug_id", ["dependencies", "blocked"], ["dependencies", "dependson"], ['flags', 'bug_id'], - ["votes", "bug_id"], ["keywords", "bug_id"], ["duplicates", "dupe_of", "dupe"], ["duplicates", "dupe", "dupe_of"]); @@ -524,7 +502,6 @@ CrossCheck("profiles", "userid", ["bugs_activity", "who", "bug_id"], ["cc", "who", "bug_id"], ['quips', 'userid'], - ["votes", "who", "bug_id"], ["longdescs", "who", "bug_id"], ["logincookies", "userid"], ["namedqueries", "userid"], @@ -681,75 +658,19 @@ while (my ($id, $email) = $sth->fetchrow_array) { } ########################################################################### -# Perform vote/keyword cache checks +# Perform keyword cache checks ########################################################################### -check_votes_or_keywords(); - -sub check_votes_or_keywords { - my $check = shift || 'all'; - +sub check_keywords { my $dbh = Bugzilla->dbh; - my $sth = $dbh->prepare(q{SELECT bug_id, votes, keywords - FROM bugs - WHERE votes != 0 OR keywords != ''}); - $sth->execute; - - my %votes; - my %keyword; - - while (my ($id, $v, $k) = $sth->fetchrow_array) { - if ($v != 0) { - $votes{$id} = $v; - } - if ($k) { - $keyword{$id} = $k; - } - } - - # If we only want to check keywords, skip checks about votes. - _check_votes(\%votes) unless ($check eq 'keywords'); - # If we only want to check votes, skip checks about keywords. - _check_keywords(\%keyword) unless ($check eq 'votes'); -} - -sub _check_votes { - my $votes = shift; - - Status('vote_count_start'); - my $dbh = Bugzilla->dbh; - my $sth = $dbh->prepare(q{SELECT bug_id, SUM(vote_count) - FROM votes }. - $dbh->sql_group_by('bug_id')); - $sth->execute; - - my $offer_votecache_rebuild = 0; - - while (my ($id, $v) = $sth->fetchrow_array) { - if ($v <= 0) { - Status('vote_count_alert', {id => $id}, 'alert'); - } else { - if (!defined $votes->{$id} || $votes->{$id} != $v) { - Status('vote_cache_alert', {id => $id}, 'alert'); - $offer_votecache_rebuild = 1; - } - delete $votes->{$id}; - } - } - foreach my $id (keys %$votes) { - Status('vote_cache_alert', {id => $id}, 'alert'); - $offer_votecache_rebuild = 1; - } + my $cgi = Bugzilla->cgi; - Status('vote_cache_rebuild_fix') if $offer_votecache_rebuild; -} + my %keyword = @{ $dbh->selectcol_arrayref( + q{SELECT bug_id, keywords FROM bugs WHERE keywords != ''}, + {Columns=>[1,2]}) }; -sub _check_keywords { - my $keyword = shift; Status('keyword_check_start'); - my $dbh = Bugzilla->dbh; - my $cgi = Bugzilla->cgi; my %keywordids; my $keywords = $dbh->selectall_arrayref(q{SELECT id, name @@ -819,13 +740,13 @@ sub _check_keywords { my @badbugs = (); - foreach my $b (keys(%$keyword)) { - if (!exists $realk{$b} || $realk{$b} ne $keyword->{$b}) { + foreach my $b (keys(%keyword)) { + if (!exists $realk{$b} || $realk{$b} ne $keyword{$b}) { push(@badbugs, $b); } } foreach my $b (keys(%realk)) { - if (!exists $keyword->{$b}) { + if (!exists $keyword{$b}) { push(@badbugs, $b); } } @@ -973,13 +894,6 @@ my $confirmed_open_states = join(', ', map {$dbh->quote($_)} @confirmed_open_sta BugCheck("bugs WHERE bug_status IN ($confirmed_open_states) AND everconfirmed = 0", 'bug_check_status_everconfirmed_error_text2', 'repair_everconfirmed'); -Status('bug_check_votes_everconfirmed'); - -BugCheck("bugs INNER JOIN products ON bugs.product_id = products.id " . - "WHERE everconfirmed = 0 AND votestoconfirm > 0 - AND votestoconfirm <= votes", - 'bug_check_votes_everconfirmed_error_text'); - ########################################################################### # Control Values ########################################################################### diff --git a/skins/standard/show_bug.css b/skins/standard/show_bug.css index 3e330a169..ec981d51c 100644 --- a/skins/standard/show_bug.css +++ b/skins/standard/show_bug.css @@ -54,9 +54,8 @@ table#flags { height: 1em; } -#duplicate_settings, #votes_container { +#duplicate_settings { white-space: nowrap; - } #bz_big_form_parts td { diff --git a/skins/standard/voting.css b/skins/standard/voting.css deleted file mode 100644 index 5d9c9afe6..000000000 --- a/skins/standard/voting.css +++ /dev/null @@ -1,24 +0,0 @@ -/* 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 Bugzilla Bug Tracking System. - * - * Contributor(s): Gavin Shelley - */ - -/* Highlight the row for the bug being voted on */ -tr.bz_bug_being_voted_on { - background-color: #e2e2e2; -} - -tr.bz_bug_being_voted_on td { - border-style: solid none solid none; - border-width: thin; -} diff --git a/template/en/default/account/prefs/email.html.tmpl b/template/en/default/account/prefs/email.html.tmpl index a4d22db73..4b76f734d 100644 --- a/template/en/default/account/prefs/email.html.tmpl +++ b/template/en/default/account/prefs/email.html.tmpl @@ -35,9 +35,6 @@ [% PROCESS global/variables.none.tmpl %] -[% useqacontact = Param('useqacontact') %] -[% usevotes = Param('usevotes') %] -

    If you don't like getting a notification for "trivial" changes to [% terms.bugs %], you can use the settings below to @@ -150,21 +147,28 @@ document.write(' - + When my relationship to this [% terms.bug %] is: @@ -174,8 +178,6 @@ document.write(' [% relationship.description FILTER html %] @@ -186,16 +188,14 @@ document.write(' [% FOREACH relationship = relationships %] - [% NEXT IF (relationship.id == constants.REL_QA AND NOT useqacontact) OR - (relationship.id == constants.REL_VOTER AND NOT usevotes) %]   @@ -223,8 +222,6 @@ document.write(' [% FOREACH relationship = relationships %] - [% NEXT IF (relationship.id == constants.REL_QA AND NOT useqacontact) OR - (relationship.id == constants.REL_VOTER AND NOT usevotes) %] - [% END %] + [% END %] [% END %] [% FOREACH event = neg_events %] [% FOREACH relationship = relationships %] - [% IF (relationship.id == constants.REL_QA AND NOT useqacontact) OR - (relationship.id == constants.REL_VOTER AND NOT usevotes) %] - - [% END %] + [% END %] [% END %] diff --git a/template/en/default/admin/params/bugfields.html.tmpl b/template/en/default/admin/params/bugfields.html.tmpl index 794f925b7..58b08f615 100644 --- a/template/en/default/admin/params/bugfields.html.tmpl +++ b/template/en/default/admin/params/bugfields.html.tmpl @@ -34,11 +34,6 @@ usestatuswhiteboard => "Do you wish to use the Status Whiteboard field?", - usevotes => "Do you wish to allow users to vote for ${terms.bugs}? Note that in order " _ - "for this to be effective, you will have to change the maximum " _ - "votes allowed in a product to be non-zero in " _ - "the product edit page.", - usebugaliases => "Do you wish to use $terms.bug aliases, which allow you to assign " _ "$terms.bugs an easy-to-remember name by which you can refer to them?", diff --git a/template/en/default/admin/products/create.html.tmpl b/template/en/default/admin/products/create.html.tmpl index f4a2161aa..045d3a34d 100644 --- a/template/en/default/admin/products/create.html.tmpl +++ b/template/en/default/admin/products/create.html.tmpl @@ -29,9 +29,6 @@ %] [% DEFAULT - product.votesperuser = "0", - product.maxvotesperbug = "10000", - product.votes_to_confirm = "0", product.is_active = 1, version = "unspecified", product.defaultmilestone = constants.DEFAULT_MILESTONE diff --git a/template/en/default/admin/products/edit-common.html.tmpl b/template/en/default/admin/products/edit-common.html.tmpl index 2c94402d6..4812707cd 100644 --- a/template/en/default/admin/products/edit-common.html.tmpl +++ b/template/en/default/admin/products/edit-common.html.tmpl @@ -76,37 +76,8 @@ in this product: - [% IF Param('usevotes') %] - - ...and automatically confirm [% terms.bugs %] if they get - - votes. (Setting this to 0 disables auto-confirming [% terms.bugs %] - by vote.) - - [% END %] + [% ' checked="checked"' IF product.allows_unconfirmed %]> -[% IF Param('usevotes') %] - - Maximum votes per person: - - - - - - Maximum votes a person can put on a single [% terms.bug %]: - - - - -[% END %] +[% Hook.process('rows') %] diff --git a/template/en/default/admin/products/list.html.tmpl b/template/en/default/admin/products/list.html.tmpl index 6fd5240af..fb026aaa4 100644 --- a/template/en/default/admin/products/list.html.tmpl +++ b/template/en/default/admin/products/list.html.tmpl @@ -64,22 +64,7 @@ heading => "Open For New $terms.Bugs" yesno_field => 1 }, - { - name => "votesperuser" - heading => "Votes Per User" - align => 'right' - }, - { - name => "maxvotesperbug" - heading => "Maximum Votes Per $terms.Bug" - align => 'right' - }, - { - name => "votestoconfirm" - heading => "Votes To Confirm" - align => 'right' - } ] -%] +] %] [% IF showbugcounts %] diff --git a/template/en/default/admin/products/updated.html.tmpl b/template/en/default/admin/products/updated.html.tmpl index 6e484ff34..4140bab62 100644 --- a/template/en/default/admin/products/updated.html.tmpl +++ b/template/en/default/admin/products/updated.html.tmpl @@ -75,33 +75,6 @@ '[% product.default_milestone FILTER html %]'.

    [% END %] - -[% IF changes.votesperuser.defined %] -

    - Updated votes per user from - [%+ changes.votesperuser.0 FILTER html %] to - [%+ product.votes_per_user FILTER html %]. -

    - [% checkvotes = 1 %] -[% END %] - -[% IF changes.maxvotesperbug.defined %] -

    - Updated maximum votes per [% terms.bug %] from - [%+ changes.maxvotesperbug.0 FILTER html %] to - [%+ product.max_votes_per_bug FILTER html %]. -

    - [% checkvotes = 1 %] -[% END %] - -[% IF changes.votestoconfirm.defined %] -

    - Updated number of votes needed to confirm a [% terms.bug %] from - [%+ changes.votestoconfirm.0 FILTER html %] to - [%+ product.votes_to_confirm FILTER html %]. -

    - [% checkvotes = 1 %] -[% END %] [% IF changes.allows_unconfirmed.defined %]

    @@ -121,65 +94,12 @@

    [% END %] +[% Hook.process('changes') %] + [% IF !changes.keys.size %]

    Nothing changed for product '[% product.name FILTER html %]'.

    [% END %] -[%# Note that this display of changed votes and/or confirmed bugs is - not very scalable. We could have a _lot_, and we just list them all. - One day we should limit this perhaps, or have a more scalable display %] - - -[% IF checkvotes %] -
    - -

    Checking existing votes in this product for anybody who now - has too many votes for [% terms.abug %]...
    - [% IF changes.too_many_votes.size %] - [% FOREACH detail = changes.too_many_votes %] - →removed votes for [% terms.bug %] - [%- detail.id FILTER html %] from [% detail.name FILTER html %]
    - [% END %] - [% ELSE %] - →there were none. - [% END %] -

    - -

    Checking existing votes in this product for anybody - who now has too many total votes...
    - [% IF changes.too_many_total_votes.size %] - [% FOREACH detail = changes.too_many_total_votes %] - →removed votes for [% terms.bug %] - [%- detail.id FILTER html %] from [% detail.name FILTER html %]
    - [% END %] - [% ELSE %] - →there were none. - [% END %] -

    - -

    Checking unconfirmed [% terms.bugs %] in this product for any which now have - sufficient votes...
    - [% IF changes.confirmed_bugs.size %] - [% FOREACH id = changes.confirmed_bugs %] - - [%# This is INCLUDED instead of PROCESSED to avoid variables getting - overwritten, which happens otherwise %] - [% INCLUDE bug/process/results.html.tmpl - type = 'votes' - mailrecipients = { 'changer' => user.login } - header_done = 1 - id = id - %] - [% END %] - [% ELSE %] - →there were none. - [% END %] -

    - -[% END %] - [% PROCESS admin/products/footer.html.tmpl %] [% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/admin/sanitycheck/messages.html.tmpl b/template/en/default/admin/sanitycheck/messages.html.tmpl index c3d5daacd..39e2258d0 100644 --- a/template/en/default/admin/sanitycheck/messages.html.tmpl +++ b/template/en/default/admin/sanitycheck/messages.html.tmpl @@ -81,12 +81,6 @@ [% ELSIF san_tag == "bug_check_status_everconfirmed_error_text2" %] [% terms.Bugs %] with confirmed status but don't have everconfirmed set - [% ELSIF san_tag == "bug_check_votes_everconfirmed" %] - Checking votes/everconfirmed - - [% ELSIF san_tag == "bug_check_votes_everconfirmed_error_text" %] - [% terms.Bugs %] that have enough votes to be confirmed but haven't been - [% ELSIF san_tag == "bug_check_control_values" %] Checking for bad values in group_control_map @@ -275,25 +269,6 @@ [% ELSIF san_tag == "unsent_bugmail_fix" %] Send these mails. - [% ELSIF san_tag == "vote_cache_rebuild_start" %] - OK, now rebuilding vote cache. - - [% ELSIF san_tag == "vote_cache_rebuild_end" %] - Vote cache has been rebuilt. - - [% ELSIF san_tag == "vote_cache_rebuild_fix" %] - Click here to - rebuild the vote cache - - [% ELSIF san_tag == "vote_cache_alert" %] - Bad vote cache for [% PROCESS bug_link bug_id = id %] - - [% ELSIF san_tag == "vote_count_start" %] - Checking cached vote counts. - - [% ELSIF san_tag == "vote_count_alert" %] - Bad vote sum for [% terms.bug %] [%+ id FILTER html %]. - [% ELSIF san_tag == "whines_obsolete_target_deletion_start" %] OK, now removing non-existent users/groups from whines. diff --git a/template/en/default/admin/users/confirm-delete.html.tmpl b/template/en/default/admin/users/confirm-delete.html.tmpl index b61a99541..4711376b0 100644 --- a/template/en/default/admin/users/confirm-delete.html.tmpl +++ b/template/en/default/admin/users/confirm-delete.html.tmpl @@ -33,7 +33,6 @@ # namedquery_group_map: number of named queries the user has shared # profiles_activity: number of changes made to other users' profiles # series: number of series the viewed user has created - # votes: number of bugs the viewed user has voted on # watch.watched: number of users the viewed user is being watched # by # watch.watcher: number of users the viewed user is watching @@ -226,8 +225,8 @@ [% END %] [% IF assignee_or_qa || cc || component_cc || email_setting || flags.requestee || - namedqueries || profile_setting || quips || series || votes || watch.watched || - watch.watcher || whine_events || whine_schedules %] + namedqueries || profile_setting || quips || series || watch.watched || + watch.watcher || whine_events || whine_schedules || other_safe %]

    The following deletions are safe and will not generate referential integrity inconsistencies.

    @@ -372,23 +371,6 @@ will have no author anymore, but will remain available. [% END %] - [% IF votes %] -
  • - [% otheruser.login FILTER html %] has voted on - [% IF votes == 1 %] - [%+ terms.abug %] - [% ELSE %] - [%+ votes %] [%+ terms.bugs %] - [% END %]. - If you delete the user account, - [% IF votes == 1 %] - this vote - [% ELSE %] - these votes - [% END %] - will be deleted along with the user account. -
  • - [% END %] [% IF watch.watched || watch.watcher %]
  • [% otheruser.login FILTER html %] @@ -445,6 +427,7 @@ but the whines themselves will be left unaltered.
  • [% END %] + [% Hook.process('warn_safe') %]
    diff --git a/template/en/default/bug/edit.html.tmpl b/template/en/default/bug/edit.html.tmpl index 95376bb7d..b84aa8238 100644 --- a/template/en/default/bug/edit.html.tmpl +++ b/template/en/default/bug/edit.html.tmpl @@ -398,7 +398,7 @@ [% BLOCK section_details2 %] [%###############################################################%] - [%# Importance (priority, severity and votes) #%] + [%# Importance (priority and severity) #%] [%###############################################################%] @@ -414,22 +414,7 @@ bug = bug, field = bug_fields.bug_severity, no_tds = 1, value = bug.bug_severity editable = bug.check_can_change_field('bug_severity', 0, 1) %] - [% IF bug.use_votes %] - - [% IF bug.votes %] - with - - [% bug.votes %] - [% IF bug.votes == 1 %] - vote - [% ELSE %] - votes - [% END %] - [% END %] - (vote) - - [% END %] + [% Hook.process('after_importance', 'bug/edit.html.tmpl') %] diff --git a/template/en/default/bug/format_comment.txt.tmpl b/template/en/default/bug/format_comment.txt.tmpl index 27b72a918..2d4a20303 100644 --- a/template/en/default/bug/format_comment.txt.tmpl +++ b/template/en/default/bug/format_comment.txt.tmpl @@ -39,8 +39,6 @@ X[% comment_body %] *** This [% terms.bug %] has been marked as a duplicate of [% terms.bug %] [%+ comment.extra_data %] *** [% ELSIF comment.type == constants.CMT_HAS_DUPE %] *** [% terms.Bug %] [%+ comment.extra_data %] has been marked as a duplicate of this [% terms.bug %]. *** -[% ELSIF comment.type == constants.CMT_POPULAR_VOTES %] -*** This [% terms.bug %] has been confirmed by popular vote. *** [% ELSIF comment.type == constants.CMT_MOVED_TO %] X[% comment_body %] @@ -65,6 +63,8 @@ Comment on attachment [% comment.extra_data %] [%+ comment.attachment.description %] [%+ comment.body %] +[% ELSIF comment.type %] + [% Hook.process('type') %] [% ELSE %] X[% comment_body %] [% END %] diff --git a/template/en/default/bug/process/header.html.tmpl b/template/en/default/bug/process/header.html.tmpl index 79f0126d4..6b608b9ed 100644 --- a/template/en/default/bug/process/header.html.tmpl +++ b/template/en/default/bug/process/header.html.tmpl @@ -39,8 +39,8 @@ [% END %] [% ELSIF title_tag == "mid_air" %] [% title = "Mid-air collision!" %] -[% ELSIF title_tag == "change_votes" %] - [% title = "Change Votes" %] [% END %] +[% Hook.process('title') %] + [% PROCESS global/header.html.tmpl %] diff --git a/template/en/default/bug/process/results.html.tmpl b/template/en/default/bug/process/results.html.tmpl index d2adca8b8..7c1af42af 100644 --- a/template/en/default/bug/process/results.html.tmpl +++ b/template/en/default/bug/process/results.html.tmpl @@ -44,12 +44,13 @@ 'bug' => "Changes submitted for $link" , 'dupe' => "Duplicate notation added to $link" , 'dep' => "Checking for dependency changes on $link" , - 'votes' => "$Link confirmed by number of votes" , 'created' => "$Link has been added to the database" , 'move' => "$Link has been moved to another database" , } %] +[% Hook.process('title') %] +
    [% title.$type %]
    diff --git a/template/en/default/bug/votes/delete-all.html.tmpl b/template/en/default/bug/votes/delete-all.html.tmpl deleted file mode 100644 index 41b75123d..000000000 --- a/template/en/default/bug/votes/delete-all.html.tmpl +++ /dev/null @@ -1,51 +0,0 @@ -[%# 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 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 - #%] - -[%# INTERFACE: - # This template has no interface. - #%] - -[% PROCESS global/variables.none.tmpl %] - -[% PROCESS global/header.html.tmpl - title = "Remove your votes?" - %] - -

    - You are about to remove all of your [% terms.bug %] votes. Are you sure you wish to - remove your vote from every [% terms.bug %] you've voted on? -

    - -
    - -

    - - Yes, delete all my votes -

    -

    - - No, go back and review my votes -

    -

    - -

    -
    - -[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/bug/votes/list-for-bug.html.tmpl b/template/en/default/bug/votes/list-for-bug.html.tmpl deleted file mode 100644 index a599dc0fb..000000000 --- a/template/en/default/bug/votes/list-for-bug.html.tmpl +++ /dev/null @@ -1,60 +0,0 @@ -[%# 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 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 - #%] - -[%# INTERFACE: - # bug_id: integer. ID of the bug we are listing the votes for. - # users: list of hashes. May be empty. Each hash has two members: - # login_name: string. The login name of the user whose vote is attached - # vote_count: integer. The number of times that user has votes for this bug. - #%] - -[% PROCESS global/variables.none.tmpl %] - -[% PROCESS global/header.html.tmpl - title = "Show Votes" - subheader = "$terms.Bug $bug_id" - %] - -[% total = 0 %] - - - - - - - [% FOREACH voter = users %] - [% total = total + voter.vote_count %] - - - - - [% END %] -
    WhoNumber of votes
    - - [% voter.login_name FILTER email FILTER html %] - - - [% voter.vote_count %] -
    - -

    Total votes: [% total %]

    - -[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/bug/votes/list-for-user.html.tmpl b/template/en/default/bug/votes/list-for-user.html.tmpl deleted file mode 100644 index 2f97616ed..000000000 --- a/template/en/default/bug/votes/list-for-user.html.tmpl +++ /dev/null @@ -1,185 +0,0 @@ -[%# 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 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 - #%] - -[%# INTERFACE: - # voting_user: hash containing a 'login' field - # - # products: list of hashes containing details of products relating to - # voting: - # name: name of product - # bugs: list of bugs the user has voted for - # bug_ids: list of bug ids the user has voted for - # onevoteonly: one or more votes allowed per bug? - # total: users current vote count for the product - # maxvotes: max votes allowed for a user in this product - # maxperbug: max votes per bug allowed for a user in this product - # - # bug_id: number; if the user is voting for a bug, this is the bug id - # - # canedit: boolean; Should the votes be presented in a form, or readonly? - # - # all_bug_ids: List of all bug ids the user has voted for, across all products - #%] - -[% PROCESS global/variables.none.tmpl %] - -[% IF !header_done %] - [% subheader = voting_user.login FILTER html %] - [% IF canedit %] - [% title = "Change Votes" %] - [% IF bug_id %] - [%# We .select and .focus the input so it works for textbox and - checkbox %] - [% onload = "document.forms['voting_form'].bug_" _ bug_id _ - ".select();document.forms['voting_form'].bug_" _ bug_id _ - ".focus()" %] - [% END %] - [% ELSE %] - [% title = "Show Votes" %] - [% END %] - [% PROCESS global/header.html.tmpl - style_urls = [ "skins/standard/voting.css" ] - %] -[% ELSE %] -
    -[% END %] - -[% IF votes_recorded %] -

    - - The changes to your votes have been saved. - -

    -[% ELSE %] -
    -[% END %] - -[% IF products.size %] -
    - - - - - - - - - - [% onevoteproduct = 0 %] - [% multivoteproduct = 0 %] - [% FOREACH product = products %] - [% IF product.onevoteonly %] - [% onevoteproduct = 1 %] - [% ELSE %] - [% multivoteproduct = 1 %] - [% END %] - - - - - - - [% FOREACH bug = product.bugs %] - - - - - - - [% END %] - - - - - - [% END %] -
    Votes[% terms.Bug %] #Summary
    [% product.name FILTER html %]([% terms.bug %] list) - - [% IF product.maxperbug < product.maxvotes AND - product.maxperbug > 1 %] - - (Note: only [% product.maxperbug %] vote - [% "s" IF product.maxperbug != 1 %] allowed per [% terms.bug %] in - this product.) - - [% END %] -
    [% IF bug.id == bug_id && canedit %]Enter New Vote here → - [%- END %] - [% IF canedit %] - [% IF product.onevoteonly %] - - [% ELSE %] - - [% END %] - [% ELSE %] - [% bug.count %] - [% END %] - - [% bug.id FILTER bug_link(bug) FILTER none %] - - [% bug.summary FILTER html %] - (Show Votes) -
    [% product.total %] vote - [% "s" IF product.total != 1 %] used out of [% product.maxvotes %] - allowed. -
    -
    -
    - - [% IF canedit %] - or - view all - as [% terms.bug %] list -
    -
    - To change your votes, - [% IF multivoteproduct %] - type in new numbers (using zero to mean no votes) - [% " or " IF onevoteproduct %] - [% END %] - [% IF onevoteproduct %] - change the checkbox - [% END %] - and then click Change My Votes. - [% ELSE %] - View all - as [% terms.bug %] list - [% END %] -
    -[% ELSE %] -

    - [% IF canedit %] - You are - [% ELSE %] - This user is - [% END %] - currently not voting on any [% terms.bugs %]. -

    -[% END %] - -

    - Help with voting. -

    - -[% PROCESS global/footer.html.tmpl %] diff --git a/template/en/default/email/newchangedmail.txt.tmpl b/template/en/default/email/newchangedmail.txt.tmpl index 1bcc2e40d..7d30b890d 100644 --- a/template/en/default/email/newchangedmail.txt.tmpl +++ b/template/en/default/email/newchangedmail.txt.tmpl @@ -19,6 +19,8 @@ #%] [% PROCESS "global/variables.none.tmpl" %] +[% PROCESS "global/reason-descs.none.tmpl" %] + From: [% Param('mailfrom') %] To: [% to_user.email %] Subject: [[% terms.Bug %] [%+ bugid %]] [% 'New: ' IF isnew %][%+ summary %] @@ -56,33 +58,12 @@ X-Bugzilla-Changed-Fields: [% changedfields %] -- [%# Protect the trailing space of the signature marker %] Configure [% terms.bug %]mail: [% urlbase %]userprefs.cgi?tab=email ------- You are receiving this mail because: ------- -[% FOREACH relationship = reasons %] - [% SWITCH relationship %] - [% CASE constants.REL_ASSIGNEE %] -You are the assignee for the [% terms.bug %]. - [% CASE constants.REL_REPORTER %] -You reported the [% terms.bug %]. - [% CASE constants.REL_QA %] -You are the QA contact for the [% terms.bug %]. - [% CASE constants.REL_CC %] -You are on the CC list for the [% terms.bug %]. - [% CASE constants.REL_VOTER %] -You are a voter for the [% terms.bug %]. - [% CASE constants.REL_GLOBAL_WATCHER %] -You are watching all [% terms.bug %] changes. - [% END %] +[% SET reason_lines = [] %] +[% FOREACH reason = reasons %] + [% reason_lines.push(reason_descs.$reason) IF reason_descs.$reason %] [% END %] -[% FOREACH relationship = reasons_watch %] - [% SWITCH relationship %] - [% CASE constants.REL_ASSIGNEE %] -You are watching the assignee of the [% terms.bug %]. - [% CASE constants.REL_REPORTER %] -You are watching the reporter. - [% CASE constants.REL_QA %] -You are watching the QA contact of the [% terms.bug %]. - [% CASE constants.REL_CC %] -You are watching someone on the CC list of the [% terms.bug %]. - [% CASE constants.REL_VOTER %] -You are watching a voter for the [% terms.bug %]. - [% END %] +[% FOREACH reason = reasons_watch %] + [% reason_lines.push(watch_reason_descs.$reason) + IF watch_reason_descs.$reason %] [% END %] +[%+ reason_lines.join("\n") %] diff --git a/template/en/default/email/votes-removed.txt.tmpl b/template/en/default/email/votes-removed.txt.tmpl deleted file mode 100644 index bfb37c90d..000000000 --- a/template/en/default/email/votes-removed.txt.tmpl +++ /dev/null @@ -1,55 +0,0 @@ -[%# 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 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): Emmanuel Seyman - #%] - -[% PROCESS global/variables.none.tmpl %] - -From: [% Param('mailfrom') %] -To: [% to %] -Subject: [% terms.Bug %] [%+ bugid %] Some or all of your votes have been removed. -X-Bugzilla-Type: voteremoved - -Some or all of your votes have been removed from [% terms.bug %] [%+ bugid %]. - -You had [% votesold FILTER html %] [%+ IF votesold == 1 %]vote[% ELSE %]votes[% END -%] on this [% terms.bug %], but [% votesremoved FILTER html %] have been removed. - -[% IF votesnew %] -You still have [% votesnew FILTER html %] [%+ IF votesnew == 1 %]vote[% ELSE %]votes[% END %] on this [% terms.bug %]. -[% ELSE %] -You have no more votes remaining on this [% terms.bug %]. -[% END %] - -Reason: -[% IF reason == "votes_bug_moved" %] - This [% terms.bug %] has been moved to a different product. - -[% ELSIF reason == "votes_too_many_per_bug" %] - The rules for voting on this product has changed; - you had too many votes for a single [% terms.bug %]. - -[% ELSIF reason == "votes_too_many_per_user" %] - The rules for voting on this product has changed; you had - too many total votes, so all votes have been removed. -[% END %] - - - -[% urlbase %]show_bug.cgi?id=[% bugid %] - diff --git a/template/en/default/filterexceptions.pl b/template/en/default/filterexceptions.pl index a488f50ca..94604dc17 100644 --- a/template/en/default/filterexceptions.pl +++ b/template/en/default/filterexceptions.pl @@ -233,7 +233,6 @@ 'global/site-navigation.html.tmpl' => [ 'bug.bug_id', - 'bug.votes', ], 'bug/comments.html.tmpl' => [ @@ -264,7 +263,6 @@ 'bug.remaining_time', 'bug.delta_ts', 'bug.bug_id', - 'bug.votes', 'group.bit', 'dep.title', 'dep.fieldname', @@ -312,19 +310,6 @@ FILTER format("%d")', ], -'bug/votes/list-for-bug.html.tmpl' => [ - 'voter.vote_count', - 'total', -], - -'bug/votes/list-for-user.html.tmpl' => [ - 'product.maxperbug', - 'bug.id', - 'bug.count', - 'product.total', - 'product.maxvotes', -], - 'bug/process/results.html.tmpl' => [ 'title.$type', '"$terms.Bug $id" FILTER bug_link(id)', @@ -482,7 +467,6 @@ 'flags.setter', 'longdescs', 'quips', - 'votes', 'series', 'watch.watched', 'watch.watcher', diff --git a/template/en/default/global/field-descs.none.tmpl b/template/en/default/global/field-descs.none.tmpl index 5012769ca..2c93c3d8a 100644 --- a/template/en/default/global/field-descs.none.tmpl +++ b/template/en/default/global/field-descs.none.tmpl @@ -84,7 +84,6 @@ "status_whiteboard" => "Whiteboard", "target_milestone" => "Target Milestone", "version" => "Version", - "votes" => "Votes", "work_time" => "Hours Worked"} %] [%# Also include any custom fields or fields which don't have a diff --git a/template/en/default/global/reason-descs.none.tmpl b/template/en/default/global/reason-descs.none.tmpl new file mode 100644 index 000000000..4a39497b5 --- /dev/null +++ b/template/en/default/global/reason-descs.none.tmpl @@ -0,0 +1,40 @@ +[%# 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 Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Everything Solved, Inc. + # Portions created by the Initial Developer are Copyright (C) 2010 + # the Initial Developer. All Rights Reserved. + # + # Contributor(s): + # Max Kanat-Alexander + #%] + +[% SET reason_descs = { + ${constants.REL_ASSIGNEE} => "You are the assignee for the ${terms.bug}.", + ${constants.REL_REPORTER} => "You reported the ${terms.bug}.", + ${constants.REL_QA} => "You are the QA Contact for the ${terms.bug}.", + ${constants.REL_CC} => "You are on the CC list for the ${terms.bug}.", + ${constants.REL_GLOBAL_WATCHER} => "You are watching all $terms.bug changes.", +} %] + +[% SET watch_reason_descs => { + ${constants.REL_ASSIGNEE} => + "You are the watching assignee of the ${terms.bug}.", + ${constants.REL_REPORTER} => + "You watching the reporter of the ${terms.bug}.", + ${constants.REL_QA} => + "You are watching the QA Contact of the ${terms.bug}.", + ${constants.REL_CC} => + "You are watching someone on the CC list of the ${terms.bug}.", +} %] + +[% Hook.process('end') %] diff --git a/template/en/default/global/site-navigation.html.tmpl b/template/en/default/global/site-navigation.html.tmpl index bbf4f6862..60a8ddf96 100644 --- a/template/en/default/global/site-navigation.html.tmpl +++ b/template/en/default/global/site-navigation.html.tmpl @@ -37,7 +37,7 @@ [% END %] - [%# *** Dependencies, Votes, Activity, Print-version *** %] + [%# *** Dependencies, Activity, Print-version *** %] [% IF bug %] @@ -46,11 +46,6 @@ href="showdependencygraph.cgi?id=[% bug.bug_id %]"> [% END %] - [% IF bug.use_votes %] - - [% END %] - At least ___ votes field must be a simple number. - You entered [% value FILTER html %], which isn't. - [% ELSIF error == "illegal_attachment_edit" %] [% title = "Unauthorized Action" %] You are not authorized to edit attachment [% attach_id FILTER html %]. @@ -1318,20 +1313,6 @@ [% group.name FILTER html %] is not an active [% terms.bug %] group and so you cannot edit group controls for it. - [% ELSIF error == "product_illegal_votes" %] - [% title = "Votes Must Be Non-negative" %] - [% admindocslinks = {'voting.html' => 'Setting up the voting feature'} %] - '[% votes FILTER html %]' is an invalid value for the - - [% IF field == "votesperuser" %] - Votes Per User - [% ELSIF field == "maxvotesperbug" %] - Maximum Votes Per [% terms.Bug %] - [% ELSIF field == "votestoconfirm" %] - Votes To Confirm - [% END %] - field, which should contain a non-negative number. - [% ELSIF error == "product_name_already_in_use" %] [% title = "Product name already exists" %] [% admindocslinks = {'products.html' => 'Administering products'} %] @@ -1548,21 +1529,6 @@ [% title = "User Protected" %] The user [% login FILTER html %] may not be impersonated by sudoers. - [% ELSIF error == "too_many_votes_for_bug" %] - [% title = "Illegal Vote" %] - [% admindocslinks = {'voting.html' => 'Setting up the voting feature'} %] - You may only use at most [% max FILTER html %] votes for a single - [%+ terms.bug %] in the - [% product FILTER html %] product, but you are trying to - use [% votes FILTER html %]. - - [% ELSIF error == "too_many_votes_for_product" %] - [% title = "Illegal Vote" %] - [% admindocslinks = {'voting.html' => 'Setting up the voting feature'} %] - You tried to use [% votes FILTER html %] votes in the - [% product FILTER html %] product, which exceeds the maximum of - [%+ max FILTER html %] votes for this product. - [% ELSIF error == "token_does_not_exist" %] [% title = "Token Does Not Exist" %] The token you submitted does not exist, has expired, or has @@ -1650,11 +1616,6 @@ Sorry, but you are not allowed to (un)mark comments or attachments as private. - [% ELSIF error == "votes_must_be_nonnegative" %] - [% title = "Votes Must Be Non-negative" %] - [% admindocslinks = {'voting.html' => 'Setting up the voting feature'} %] - Only use non-negative numbers for your [% terms.bug %] votes. - [% ELSIF error == "wrong_token_for_cancelling_email_change" %] [% title = "Wrong Token" %] That token cannot be used to cancel an email address change. diff --git a/template/en/default/list/list.rdf.tmpl b/template/en/default/list/list.rdf.tmpl index 99c06c1ee..d7879a694 100644 --- a/template/en/default/list/list.rdf.tmpl +++ b/template/en/default/list/list.rdf.tmpl @@ -38,7 +38,7 @@ [% bug.bug_id %] [% FOREACH column = displaycolumns %] - [% bug.$column FILTER html %] + [% bug.$column FILTER html %] [% END %] diff --git a/template/en/default/pages/voting.html.tmpl b/template/en/default/pages/voting.html.tmpl deleted file mode 100644 index 4e6fb473d..000000000 --- a/template/en/default/pages/voting.html.tmpl +++ /dev/null @@ -1,69 +0,0 @@ -[%# 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 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): Terry Weissman - # Gervase Markham - #%] - -[% PROCESS global/variables.none.tmpl %] -[% INCLUDE global/header.html.tmpl title = "Voting" %] - -

    [% terms.Bugzilla %] has a "voting" feature. Each product allows users to -have a certain number of votes. (Some products may not allow any, which means -you can't vote on things in those products at all.) With your vote, you -indicate which [% terms.bugs %] you think are the most important and -would like to see fixed. Note that voting is nowhere near as effective -as providing a fix yourself.

    - -

    Depending on how the administrator has configured the relevant product, -you may be able to vote for the same [% terms.bug %] more than once. -Remember that you have a limited number of votes. When weighted voting -is allowed and a limited number of votes are available to you, you will -have to decide whether you want to distribute your votes among a large -number of [% terms.bugs %] indicating your minimal interest or focus on -a few [% terms.bugs %] indicating your strong support for them. -

    - -

    To look at votes:

    - -
      -
    • Go to the query page. Do a normal query, but enter 1 in the "At least - ___ votes" field. This will show you items that match your query that - have at least one vote.
    • -
    - -

    To vote for [% terms.abug %]:

    - -
      -
    • Bring up the [% terms.bug %] in question.
    • - -
    • Click on the "(vote)" link that appears on the right of the "Importance" - fields. (If no such link appears, then voting may not be allowed in - this [% terms.bug %]'s product.)
    • - -
    • Indicate how many votes you want to give this [% terms.bug %]. This page - also displays how many votes you've given to other [% terms.bugs %], so you - may rebalance your votes as necessary.
    • -
    - -

    You will automatically get email notifying you of any changes that occur -on [% terms.bugs %] you vote for.

    - -

    You may review your votes at any time by clicking on the "My Votes" link in the page footer.

    - -[% INCLUDE global/footer.html.tmpl %] diff --git a/template/en/default/search/form.html.tmpl b/template/en/default/search/form.html.tmpl index 2e2ae73d6..63ca03565 100644 --- a/template/en/default/search/form.html.tmpl +++ b/template/en/default/search/form.html.tmpl @@ -422,20 +422,14 @@ function doOnSelectProduct(selectmode) { -[%# *** Email Numbering Votes *** %] +[%# *** Email Numbering *** %] - [% IF Param('usevotes') %] - - - - - [% END %] + [% Hook.process('email_numbering_end') %]
    - - [% IF Param('usevotes') %] - Email Addresses, [% terms.Bug %] Numbers, and Votes - [% ELSE %] - Email Addresses and [% terms.Bug %] Numbers - [% END %] - + Email Addresses and [% terms.Bug %] Numbers @@ -550,18 +544,7 @@ function doOnSelectProduct(selectmode) {
    (comma-separated list)
    - : - - - votes -
    diff --git a/template/en/default/search/search-help.html.tmpl b/template/en/default/search/search-help.html.tmpl index 12e82ba5e..4dbf6652a 100644 --- a/template/en/default/search/search-help.html.tmpl +++ b/template/en/default/search/search-help.html.tmpl @@ -82,9 +82,6 @@ roles.
    Here, you can search on what people are in what role." }, { id => "bug_id", html => "You can limit your search to a specific set of $terms.bugs ." }, -{ id => "votes", - html => "Some $terms.bugs can be voted for, and you can limit your search to - $terms.bugs
    with more than a certain number of votes." }, { id => "chfield", html => "You can search for specific types of change - this field define
    which field you are interested in changes for." }, diff --git a/template/en/default/search/search-report-select.html.tmpl b/template/en/default/search/search-report-select.html.tmpl index de6478716..2ad779248 100644 --- a/template/en/default/search/search-report-select.html.tmpl +++ b/template/en/default/search/search-report-select.html.tmpl @@ -29,7 +29,8 @@ [% rep_fields = ["classification", "product", "component", "version", "rep_platform", "op_sys", "bug_status", "resolution", "bug_severity", "priority", "target_milestone", "assigned_to", - "reporter", "qa_contact", "votes" ] %] + "reporter", "qa_contact" ] %] + [% Hook.process('rep_fields', 'search/search-report-select.html.tmpl') %]