diff options
author | Dave Lawrence <dlawrence@mozilla.com> | 2012-03-28 23:25:04 +0200 |
---|---|---|
committer | Dave Lawrence <dlawrence@mozilla.com> | 2012-03-28 23:25:04 +0200 |
commit | e4953b938ed652365eeba7c967ea74882afbb0a3 (patch) | |
tree | 6ccdfb134b245c064376d1ea9aa84fff551b7342 | |
parent | 2838dad07581a783cfb4bcf32a2c003e22cb13e5 (diff) | |
download | bugzilla-e4953b938ed652365eeba7c967ea74882afbb0a3.tar.gz bugzilla-e4953b938ed652365eeba7c967ea74882afbb0a3.tar.xz |
Bug 684701: add "watch user" to component watching
14 files changed, 613 insertions, 197 deletions
diff --git a/extensions/BMO/Extension.pm b/extensions/BMO/Extension.pm index 115d944b6..47f022c97 100644 --- a/extensions/BMO/Extension.pm +++ b/extensions/BMO/Extension.pm @@ -564,7 +564,8 @@ sub bug_check_groups { my ($self, $args) = @_; my $group_names = $args->{'group_names'}; my $add_groups = $args->{'add_groups'}; - + + return unless $group_names; $group_names = ref $group_names ? $group_names : [ map { trim($_) } split(',', $group_names) ]; diff --git a/extensions/ComponentWatching/Config.pm b/extensions/ComponentWatching/Config.pm index 534afaa61..560b5c3c5 100644 --- a/extensions/ComponentWatching/Config.pm +++ b/extensions/ComponentWatching/Config.pm @@ -1,23 +1,9 @@ -# -*- Mode: perl; indent-tabs-mode: nil -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. # -# 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 Component Watching Extension -# -# The Initial Developer of the Original Code is the Mozilla Foundation -# Portions created by the Initial Developers are Copyright (C) 2011 the -# Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Byron Jones <bjones@mozilla.com> +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. package Bugzilla::Extension::ComponentWatching; use strict; diff --git a/extensions/ComponentWatching/Extension.pm b/extensions/ComponentWatching/Extension.pm index d39d9cd55..c47fa4749 100644 --- a/extensions/ComponentWatching/Extension.pm +++ b/extensions/ComponentWatching/Extension.pm @@ -1,23 +1,9 @@ -# -*- Mode: perl; indent-tabs-mode: nil -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. # -# 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 Component Watching Extension -# -# The Initial Developer of the Original Code is the Mozilla Foundation -# Portions created by the Initial Developers are Copyright (C) 2011 the -# Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Byron Jones <bjones@mozilla.com> +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. package Bugzilla::Extension::ComponentWatching; use strict; @@ -28,8 +14,9 @@ use Bugzilla::Error; use Bugzilla::Group; use Bugzilla::User; use Bugzilla::User::Setting; +use Bugzilla::Util qw(trim); -our $VERSION = '1.1'; +our $VERSION = '2'; use constant REL_COMPONENT_WATCHER => 15; @@ -72,6 +59,22 @@ sub db_schema_abstract_schema { }; } +sub install_update_db { + my $dbh = Bugzilla->dbh; + $dbh->bz_add_column( + 'components', + 'watch_user', + { + TYPE => 'INT3', + REFERENCES => { + TABLE => 'profiles', + COLUMN => 'userid', + DELETE => 'SET NULL', + } + } + ); +} + # # templates # @@ -84,6 +87,87 @@ sub template_before_create { } # +# user-watch +# + +BEGIN { + *Bugzilla::Component::watch_user = \&_component_watch_user; +} + +sub _component_watch_user { + my ($self) = @_; + return unless $self->{watch_user}; + $self->{watch_user_object} ||= Bugzilla::User->new($self->{watch_user}); + return $self->{watch_user_object}; +} + +sub object_columns { + my ($self, $args) = @_; + my $class = $args->{class}; + my $columns = $args->{columns}; + return unless $class->isa('Bugzilla::Component'); + + push(@$columns, 'watch_user'); +} + +sub object_update_columns { + my ($self, $args) = @_; + my $object = $args->{object}; + my $columns = $args->{columns}; + return unless $object->isa('Bugzilla::Component'); + + push(@$columns, 'watch_user'); + + # editcomponents.cgi doesn't call set_all, so we have to do this here + my $input = Bugzilla->input_params; + $object->set('watch_user', $input->{watch_user}); +} + +sub object_validators { + my ($self, $args) = @_; + my $class = $args->{class}; + my $validators = $args->{validators}; + return unless $class->isa('Bugzilla::Component'); + + $validators->{watch_user} = \&_check_watch_user; +} + +sub object_before_create { + my ($self, $args) = @_; + my $class = $args->{class}; + my $params = $args->{params}; + return unless $class->isa('Bugzilla::Component'); + + my $input = Bugzilla->input_params; + $params->{watch_user} = $input->{watch_user}; +} + +sub object_end_of_update { + my ($self, $args) = @_; + my $object = $args->{object}; + my $old_object = $args->{old_object}; + my $changes = $args->{changes}; + return unless $object->isa('Bugzilla::Component'); + + my $old_id = $old_object->watch_user ? $old_object->watch_user->id : 0; + my $new_id = $object->watch_user ? $object->watch_user->id : 0; + return unless $old_id == $new_id; + + $changes->{watch_user} = [ $old_id ? $old_id : undef, $new_id ? $new_id : undef ]; +} + +sub _check_watch_user { + my ($self, $value, $field) = @_; + + $value = trim($value || ''); + return if $value eq ''; + if ($value !~ /\.bugs$/i) { + ThrowUserError('component_watch_invalid_watch_user'); + } + return Bugzilla::User->check($value)->id; +} + +# # preferences # @@ -95,15 +179,16 @@ sub user_preferences { my $save = $args->{'save_changes'}; my $handled = $args->{'handled'}; my $user = Bugzilla->user; + my $input = Bugzilla->input_params; if ($save) { my ($sth, $sthAdd, $sthDel); - if (Bugzilla->input_params->{'add'}) { + if ($input->{'add'} && $input->{'add_product'}) { # add watch - my $productName = Bugzilla->input_params->{'add_product'}; - my $ra_componentNames = Bugzilla->input_params->{'add_component'}; + my $productName = $input->{'add_product'}; + my $ra_componentNames = $input->{'add_component'}; $ra_componentNames = [$ra_componentNames] unless ref($ra_componentNames); # load product and verify access @@ -132,7 +217,7 @@ sub user_preferences { } else { # remove watch(s) - foreach my $name (keys %{Bugzilla->input_params}) { + foreach my $name (keys %$input) { if ($name =~ /^del_(\d+)$/) { _deleteProductWatch($user, $1); } elsif ($name =~ /^del_(\d+)_(\d+)$/) { @@ -185,6 +270,7 @@ sub bugmail_recipients { } } + # add component watchers my $dbh = Bugzilla->dbh; my $sth = $dbh->prepare(" SELECT user_id @@ -198,6 +284,35 @@ sub bugmail_recipients { $recipients->{$uid}->{+REL_COMPONENT_WATCHER} = Bugzilla::BugMail::BIT_WATCHING(); } } + + # add component watchers from watch-users + my $uidList = join(',', keys %$recipients); + $sth = $dbh->prepare(" + SELECT component_watch.user_id + FROM components + INNER JOIN component_watch ON component_watch.component_id = components.id + WHERE components.watch_user in ($uidList) + "); + $sth->execute(); + while (my ($uid) = $sth->fetchrow_array) { + if (!exists $recipients->{$uid}) { + $recipients->{$uid}->{+REL_COMPONENT_WATCHER} = Bugzilla::BugMail::BIT_WATCHING(); + } + } + + # add watch-users from component watchers + $sth = $dbh->prepare(" + SELECT watch_user + FROM components + WHERE (id = ? OR id = ?) + AND (watch_user IS NOT NULL) + "); + $sth->execute($oldComponentId, $newComponentId); + while (my ($uid) = $sth->fetchrow_array) { + if (!exists $recipients->{$uid}) { + $recipients->{$uid}->{+REL_COMPONENT_WATCHER} = Bugzilla::BugMail::BIT_DIRECT(); + } + } } sub bugmail_relationships { diff --git a/extensions/ComponentWatching/Extension.pm.orig b/extensions/ComponentWatching/Extension.pm.orig new file mode 100644 index 000000000..d39d9cd55 --- /dev/null +++ b/extensions/ComponentWatching/Extension.pm.orig @@ -0,0 +1,345 @@ +# -*- 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 Component Watching Extension +# +# The Initial Developer of the Original Code is the Mozilla Foundation +# Portions created by the Initial Developers are Copyright (C) 2011 the +# Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Byron Jones <bjones@mozilla.com> + +package Bugzilla::Extension::ComponentWatching; +use strict; +use base qw(Bugzilla::Extension); + +use Bugzilla::Constants; +use Bugzilla::Error; +use Bugzilla::Group; +use Bugzilla::User; +use Bugzilla::User::Setting; + +our $VERSION = '1.1'; + +use constant REL_COMPONENT_WATCHER => 15; + +# +# installation +# + +sub db_schema_abstract_schema { + my ($self, $args) = @_; + $args->{'schema'}->{'component_watch'} = { + FIELDS => [ + user_id => { + TYPE => 'INT3', + NOTNULL => 1, + REFERENCES => { + TABLE => 'profiles', + COLUMN => 'userid', + DELETE => 'CASCADE', + } + }, + component_id => { + TYPE => 'INT2', + NOTNULL => 0, + REFERENCES => { + TABLE => 'components', + COLUMN => 'id', + DELETE => 'CASCADE', + } + }, + product_id => { + TYPE => 'INT2', + NOTNULL => 0, + REFERENCES => { + TABLE => 'products', + COLUMN => 'id', + DELETE => 'CASCADE', + } + }, + ], + }; +} + +# +# templates +# + +sub template_before_create { + my ($self, $args) = @_; + my $config = $args->{config}; + my $constants = $config->{CONSTANTS}; + $constants->{REL_COMPONENT_WATCHER} = REL_COMPONENT_WATCHER; +} + +# +# preferences +# + +sub user_preferences { + my ($self, $args) = @_; + my $tab = $args->{'current_tab'}; + return unless $tab eq 'component_watch'; + + my $save = $args->{'save_changes'}; + my $handled = $args->{'handled'}; + my $user = Bugzilla->user; + + if ($save) { + my ($sth, $sthAdd, $sthDel); + + if (Bugzilla->input_params->{'add'}) { + # add watch + + my $productName = Bugzilla->input_params->{'add_product'}; + my $ra_componentNames = Bugzilla->input_params->{'add_component'}; + $ra_componentNames = [$ra_componentNames] unless ref($ra_componentNames); + + # load product and verify access + my $product = Bugzilla::Product->new({ name => $productName }); + unless ($product && $user->can_access_product($product)) { + ThrowUserError('product_access_denied', { product => $productName }); + } + + if (grep { $_ eq '' } @$ra_componentNames) { + # watching a product + _addProductWatch($user, $product); + + } else { + # watching specific components + foreach my $componentName (@$ra_componentNames) { + my $component = Bugzilla::Component->new({ name => $componentName, product => $product }); + unless ($component) { + ThrowUserError('product_access_denied', { product => $productName }); + } + _addComponentWatch($user, $component); + } + } + + _addDefaultSettings($user); + + } else { + # remove watch(s) + + foreach my $name (keys %{Bugzilla->input_params}) { + if ($name =~ /^del_(\d+)$/) { + _deleteProductWatch($user, $1); + } elsif ($name =~ /^del_(\d+)_(\d+)$/) { + _deleteComponentWatch($user, $1, $2); + } + } + } + } + + $args->{'vars'}->{'watches'} = _getWatches($user); + + $$handled = 1; +} + +# +# bugmail +# + +sub bugmail_recipients { + my ($self, $args) = @_; + my $bug = $args->{'bug'}; + my $recipients = $args->{'recipients'}; + my $diffs = $args->{'diffs'}; + + my ($oldProductId, $newProductId) = ($bug->product_id, $bug->product_id); + my ($oldComponentId, $newComponentId) = ($bug->component_id, $bug->component_id); + + # notify when the product/component is switch from one being watched + if (@$diffs) { + # we need the product to process the component, so scan for that first + my $product; + foreach my $ra (@$diffs) { + next if !(exists $ra->{'old'} + && exists $ra->{'field_name'}); + if ($ra->{'field_name'} eq 'product') { + $product = Bugzilla::Product->new({ name => $ra->{'old'} }); + $oldProductId = $product->id; + } + } + if (!$product) { + $product = Bugzilla::Product->new($oldProductId); + } + foreach my $ra (@$diffs) { + next if !(exists $ra->{'old'} + && exists $ra->{'field_name'}); + if ($ra->{'field_name'} eq 'component') { + my $component = Bugzilla::Component->new({ name => $ra->{'old'}, product => $product }); + $oldComponentId = $component->id; + } + } + } + + my $dbh = Bugzilla->dbh; + my $sth = $dbh->prepare(" + SELECT user_id + FROM component_watch + WHERE ((product_id = ? OR product_id = ?) AND component_id IS NULL) + OR (component_id = ? OR component_id = ?) + "); + $sth->execute($oldProductId, $newProductId, $oldComponentId, $newComponentId); + while (my ($uid) = $sth->fetchrow_array) { + if (!exists $recipients->{$uid}) { + $recipients->{$uid}->{+REL_COMPONENT_WATCHER} = Bugzilla::BugMail::BIT_WATCHING(); + } + } +} + +sub bugmail_relationships { + my ($self, $args) = @_; + my $relationships = $args->{relationships}; + $relationships->{+REL_COMPONENT_WATCHER} = 'Component-Watcher'; +} + +# +# db +# + +sub _getWatches { + my ($user) = @_; + my $dbh = Bugzilla->dbh; + + my $sth = $dbh->prepare(" + SELECT product_id, component_id + FROM component_watch + WHERE user_id = ? + "); + $sth->execute($user->id); + my @watches; + while (my ($productId, $componentId) = $sth->fetchrow_array) { + my $product = Bugzilla::Product->new($productId); + next unless $product && $user->can_access_product($product); + + my %watch = ( product => $product ); + if ($componentId) { + my $component = Bugzilla::Component->new($componentId); + next unless $component; + $watch{'component'} = $component; + } + + push @watches, \%watch; + } + + @watches = sort { + $a->{'product'}->name cmp $b->{'product'}->name + || $a->{'component'}->name cmp $b->{'component'}->name + } @watches; + + return \@watches; +} + +sub _addProductWatch { + my ($user, $product) = @_; + my $dbh = Bugzilla->dbh; + + my $sth = $dbh->prepare(" + SELECT 1 + FROM component_watch + WHERE user_id = ? AND product_id = ? AND component_id IS NULL + "); + $sth->execute($user->id, $product->id); + return if $sth->fetchrow_array; + + $sth = $dbh->prepare(" + DELETE FROM component_watch + WHERE user_id = ? AND product_id = ? + "); + $sth->execute($user->id, $product->id); + + $sth = $dbh->prepare(" + INSERT INTO component_watch(user_id, product_id) + VALUES (?, ?) + "); + $sth->execute($user->id, $product->id); +} + +sub _addComponentWatch { + my ($user, $component) = @_; + my $dbh = Bugzilla->dbh; + + my $sth = $dbh->prepare(" + SELECT 1 + FROM component_watch + WHERE user_id = ? + AND (component_id = ? OR (product_id = ? AND component_id IS NULL)) + "); + $sth->execute($user->id, $component->id, $component->product_id); + return if $sth->fetchrow_array; + + $sth = $dbh->prepare(" + INSERT INTO component_watch(user_id, product_id, component_id) + VALUES (?, ?, ?) + "); + $sth->execute($user->id, $component->product_id, $component->id); +} + +sub _deleteProductWatch { + my ($user, $productId) = @_; + my $dbh = Bugzilla->dbh; + + my $sth = $dbh->prepare(" + DELETE FROM component_watch + WHERE user_id = ? AND product_id = ? AND component_id IS NULL + "); + $sth->execute($user->id, $productId); +} + +sub _deleteComponentWatch { + my ($user, $productId, $componentId) = @_; + my $dbh = Bugzilla->dbh; + + my $sth = $dbh->prepare(" + DELETE FROM component_watch + WHERE user_id = ? AND product_id = ? AND component_id = ? + "); + $sth->execute($user->id, $productId, $componentId); +} + +sub _addDefaultSettings { + my ($user) = @_; + my $dbh = Bugzilla->dbh; + + my $sth = $dbh->prepare(" + SELECT 1 + FROM email_setting + WHERE user_id = ? AND relationship = ? + "); + $sth->execute($user->id, REL_COMPONENT_WATCHER); + return if $sth->fetchrow_array; + + my @defaultEvents = ( + EVT_OTHER, + EVT_COMMENT, + EVT_ATTACHMENT, + EVT_ATTACHMENT_DATA, + EVT_PROJ_MANAGEMENT, + EVT_OPENED_CLOSED, + EVT_KEYWORD, + EVT_DEPEND_BLOCK, + EVT_BUG_CREATED, + ); + foreach my $event (@defaultEvents) { + $dbh->do( + "INSERT INTO email_setting(user_id,relationship,event) VALUES (?,?,?)", + undef, + $user->id, REL_COMPONENT_WATCHER, $event + ); + } +} + +__PACKAGE__->NAME; diff --git a/extensions/ComponentWatching/reset-watch-preferences.pl b/extensions/ComponentWatching/reset-watch-preferences.pl deleted file mode 100755 index f190ebd48..000000000 --- a/extensions/ComponentWatching/reset-watch-preferences.pl +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/perl - -# -*- 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 Component Watching Extension -# -# The Initial Developer of the Original Code is the Mozilla Foundation -# Portions created by the Initial Developers are Copyright (C) 2011 the -# Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Byron Jones <bjones@mozilla.com> - -use strict; -use warnings; - -use lib '.'; -$| = 1; - -use Bugzilla; -use Bugzilla::Constants; -use Bugzilla::Install::Util qw(indicate_progress); - -Bugzilla->usage_mode(USAGE_MODE_CMDLINE); - -my @DEFAULT_EVENTS = qw(0 2 3 4 5 6 7 9 10 50); -my $REL_COMP_WATCH = 15; - -print "This script resets the component watching preferences back to\n"; -print "default values. It is required to be run when upgrading from\n"; -print "version 1.0 to 1.1\n"; -print "Press <ENTER> to start, or CTRL+C to cancel... "; -getc(); -print "\n"; - -my $dbh = Bugzilla->dbh; - -$dbh->bz_start_transaction(); - -my @users; -my $ra_user_ids = $dbh->selectcol_arrayref( - "SELECT DISTINCT user_id FROM component_watch" -); - -my $total = scalar @$ra_user_ids; -my $count = 0; -foreach my $user_id (@$ra_user_ids) { - indicate_progress({ current => $count++, total => $total }) if $total > 10; - $dbh->do( - "DELETE FROM email_setting WHERE user_id=? AND relationship=?", - undef, - $user_id, $REL_COMP_WATCH - ); - foreach my $event (@DEFAULT_EVENTS) { - $dbh->do( - "INSERT INTO email_setting(user_id,relationship,event) VALUES (?,?,?)", - undef, - $user_id, $REL_COMP_WATCH, $event - ); - } -} - -$dbh->bz_commit_transaction(); - -print "Done.\n"; diff --git a/extensions/ComponentWatching/template/en/default/account/prefs/component_watch.html.tmpl b/extensions/ComponentWatching/template/en/default/account/prefs/component_watch.html.tmpl index dd2fb0560..46acd386f 100644 --- a/extensions/ComponentWatching/template/en/default/account/prefs/component_watch.html.tmpl +++ b/extensions/ComponentWatching/template/en/default/account/prefs/component_watch.html.tmpl @@ -1,22 +1,9 @@ -[%# - # The contents of this file are subject to the Mozilla Public - # License Version 1.1 (the "License"); you may not use this file - # except in compliance with the License. You may obtain a copy of - # the License at http://www.mozilla.org/MPL/ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. # - # Software distributed under the License is distributed on an "AS - # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - # implied. See the License for the specific language governing - # rights and limitations under the License. - # - # The Original Code is the Component Watching Extension - # - # The Initial Developer of the Original Code is the Mozilla Foundation - # Portions created by the Initial Developers are Copyright (C) 2011 the - # Initial Developer. All Rights Reserved. - # - # Contributor(s): - # Byron Jones <bjones@mozilla.com> + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. #%] [%# initialise product to component mapping #%] @@ -29,15 +16,22 @@ var useclassification = false; var first_load = true; var last_sel = []; var cpts = new Array(); +var watch_users = new Array(); [% n = 0 %] [% FOREACH prod = selectable_products %] cpts['[% n %]'] = [ [%- FOREACH comp = prod.components %]'[% comp.name FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ]; - [% n = n+1 %] + [% n = n + 1 %] + [% FOREACH comp = prod.components %] + [% IF comp.watch_user %] + if (!watch_users['[% prod.name FILTER js %]']) + watch_users['[% prod.name FILTER js %]'] = new Array(); + watch_users['[% prod.name FILTER js %]']['[% comp.name FILTER js %]'] = '[% comp.watch_user.login FILTER js %]'; + [% END %] + [% END %] [% END %] </script> -<script type="text/javascript" - src="[% 'js/productform.js' FILTER mtime FILTER html %]"> +<script type="text/javascript" src="[% 'js/productform.js' FILTER mtime FILTER html %]"> </script> <script> @@ -52,6 +46,19 @@ function onSelectProduct() { // support IE component.add(new Option('__Any__', ''), 0); } + onSelectComponent(); +} + +function onSelectComponent() { + var product_select = Dom.get('product'); + var product = product_select.options[product_select.selectedIndex].value; + var component = Dom.get('component').value; + if (component && watch_users[product] && watch_users[product][component]) { + Dom.get('watch-user-email').innerHTML = watch_users[product][component]; + Dom.get('watch-user-div').style.display = ''; + } else { + Dom.get('watch-user-div').style.display = 'none'; + } } YAHOO.util.Event.onDOMReady(onSelectProduct); @@ -64,8 +71,8 @@ watch "__Any__". <table border="0" cellpadding="3" cellspacing="0"> <tr> - <td align="right">Product</td> - <td> + <td align="right">Product:</td> + <td colspan="2"> <select name="add_product" id="product" onChange="onSelectProduct()"> [% FOREACH product IN selectable_products %] <option>[% product.name FILTER html %]</option> @@ -74,9 +81,9 @@ watch "__Any__". </td> </tr> <tr> - <td align="right" valign="top">Component</td> + <td align="right" valign="top">Component:</td> <td> - <select name="add_component" id="component" multiple size="5"> + <select name="add_component" id="component" multiple size="5" onChange="onSelectComponent()"> <option value="">__Any__</option> [% FOREACH product IN selectable_products %] [% FOREACH component IN product.components %] @@ -85,6 +92,14 @@ watch "__Any__". [% END %] </select> </td> + <td valign="top"> + <div id="watch-user-div" + title="You can also watch a component by following this user. [% ~%] + CC'ing this user on a [% terms.bug %] will trigger notifications to all watchers of this component." + style="cursor:help"> + Watch User: <span id="watch-user-email"></span> + </div> + </td> </tr> <tr> <td> </td> diff --git a/extensions/ComponentWatching/template/en/default/hook/account/prefs/email-relationships.html.tmpl b/extensions/ComponentWatching/template/en/default/hook/account/prefs/email-relationships.html.tmpl index cab637967..69ab53751 100644 --- a/extensions/ComponentWatching/template/en/default/hook/account/prefs/email-relationships.html.tmpl +++ b/extensions/ComponentWatching/template/en/default/hook/account/prefs/email-relationships.html.tmpl @@ -1,21 +1,9 @@ -[%# The contents of this file are subject to the Mozilla Public - # License Version 1.1 (the "License"); you may not use this file - # except in compliance with the License. You may obtain a copy of - # the License at http://www.mozilla.org/MPL/ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. # - # Software distributed under the License is distributed on an "AS - # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - # implied. See the License for the specific language governing - # rights and limitations under the License. - # - # The Original Code is the Component Watching Extension - # - # The Initial Developer of the Original Code is the Mozilla Foundation - # Portions created by the Initial Developers are Copyright (C) 2011 the - # Initial Developer. All Rights Reserved. - # - # Contributor(s): - # Byron Jones <bjones@mozilla.com> + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. #%] [% relationships.push({ id = constants.REL_COMPONENT_WATCHER, description = "Component" }) %] diff --git a/extensions/ComponentWatching/template/en/default/hook/account/prefs/prefs-tabs.html.tmpl b/extensions/ComponentWatching/template/en/default/hook/account/prefs/prefs-tabs.html.tmpl index 7a615a8ac..9af22ed39 100644 --- a/extensions/ComponentWatching/template/en/default/hook/account/prefs/prefs-tabs.html.tmpl +++ b/extensions/ComponentWatching/template/en/default/hook/account/prefs/prefs-tabs.html.tmpl @@ -1,22 +1,9 @@ -[%# - # The contents of this file are subject to the Mozilla Public - # License Version 1.1 (the "License"); you may not use this file - # except in compliance with the License. You may obtain a copy of - # the License at http://www.mozilla.org/MPL/ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. # - # Software distributed under the License is distributed on an "AS - # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - # implied. See the License for the specific language governing - # rights and limitations under the License. - # - # The Original Code is the Component Watching Extension - # - # The Initial Developer of the Original Code is the Mozilla Foundation - # Portions created by the Initial Developers are Copyright (C) 2011 the - # Initial Developer. All Rights Reserved. - # - # Contributor(s): - # Byron Jones <bjones@mozilla.com> + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. #%] [% tabs = tabs.import([{ diff --git a/extensions/ComponentWatching/template/en/default/hook/admin/components/edit-common-rows.html.tmpl b/extensions/ComponentWatching/template/en/default/hook/admin/components/edit-common-rows.html.tmpl new file mode 100644 index 000000000..154ba089e --- /dev/null +++ b/extensions/ComponentWatching/template/en/default/hook/admin/components/edit-common-rows.html.tmpl @@ -0,0 +1,20 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +<tr> + <td valign="top"><label for="watch_user">Watch User:</label></td> + <td> + [% INCLUDE global/userselect.html.tmpl + name => "watch_user" + id => "watch_user" + value => comp.watch_user.login + size => 64 + emptyok => 1 + %] + </td> +</tr> diff --git a/extensions/ComponentWatching/template/en/default/hook/admin/components/list-before_table.html.tmpl b/extensions/ComponentWatching/template/en/default/hook/admin/components/list-before_table.html.tmpl new file mode 100644 index 000000000..ed8d6e350 --- /dev/null +++ b/extensions/ComponentWatching/template/en/default/hook/admin/components/list-before_table.html.tmpl @@ -0,0 +1,17 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% CALL columns.splice(5, 0, { name => 'watch_user', heading => 'Watch User' }) %] + +[% FOREACH my_component = product.components %] + [% overrides.watch_user.name.${my_component.name} = { + override_content => 1 + content => my_component.watch_user.login + } + %] +[% END %] diff --git a/extensions/ComponentWatching/template/en/default/hook/global/messages-component_updated_fields.html.tmpl b/extensions/ComponentWatching/template/en/default/hook/global/messages-component_updated_fields.html.tmpl new file mode 100644 index 000000000..38c7e8c8a --- /dev/null +++ b/extensions/ComponentWatching/template/en/default/hook/global/messages-component_updated_fields.html.tmpl @@ -0,0 +1,15 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% IF changes.watch_user.defined %] + [% IF comp.watch_user %] + <li>Watch User updated to '[% comp.watch_user.login FILTER html %]'</li> + [% ELSE %] + <li>Watch User deleted</li> + [% END %] +[% END %] diff --git a/extensions/ComponentWatching/template/en/default/hook/global/reason-descs-end.none.tmpl b/extensions/ComponentWatching/template/en/default/hook/global/reason-descs-end.none.tmpl index 2621f85e4..8cd67bdff 100644 --- a/extensions/ComponentWatching/template/en/default/hook/global/reason-descs-end.none.tmpl +++ b/extensions/ComponentWatching/template/en/default/hook/global/reason-descs-end.none.tmpl @@ -1,21 +1,9 @@ -[%# The contents of this file are subject to the Mozilla Public - # License Version 1.1 (the "License"); you may not use this file - # except in compliance with the License. You may obtain a copy of - # the License at http://www.mozilla.org/MPL/ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. # - # Software distributed under the License is distributed on an "AS - # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - # implied. See the License for the specific language governing - # rights and limitations under the License. - # - # The Original Code is the Component Watching Extension - # - # The Initial Developer of the Original Code is the Mozilla Foundation - # Portions created by the Initial Developers are Copyright (C) 2011 the - # Initial Developer. All Rights Reserved. - # - # Contributor(s): - # Byron Jones <bjones@mozilla.com> + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. #%] [% watch_reason_descs.${constants.REL_COMPONENT_WATCHER} = diff --git a/extensions/ComponentWatching/template/en/default/hook/global/user-error-errors.html.tmpl b/extensions/ComponentWatching/template/en/default/hook/global/user-error-errors.html.tmpl new file mode 100644 index 000000000..8da2f2790 --- /dev/null +++ b/extensions/ComponentWatching/template/en/default/hook/global/user-error-errors.html.tmpl @@ -0,0 +1,13 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% IF error == "component_watch_invalid_watch_user" %] + [% title = "Invalid Watch User" %] + The "Watch User" must be a <b>.bugs</b> email address.<br> + For example: <i>accessibility-apis@core.bugs</i> +[% END %] diff --git a/t/008filter.t b/t/008filter.t index f0e7a6429..d0c0311f6 100644 --- a/t/008filter.t +++ b/t/008filter.t @@ -175,7 +175,8 @@ sub directive_ok { return 1 if $directive =~ /^(IF|END|UNLESS|FOREACH|PROCESS|INCLUDE| BLOCK|USE|ELSE|NEXT|LAST|DEFAULT|FLUSH| ELSIF|SET|SWITCH|CASE|WHILE|RETURN|STOP| - TRY|CATCH|FINAL|THROW|CLEAR|MACRO|FILTER)/x; + TRY|CATCH|FINAL|THROW|CLEAR|MACRO|FILTER| + CALL)/x; # ? : if ($directive =~ /.+\?(.+):(.+)/) { |