summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extensions/BMO/Extension.pm3
-rw-r--r--extensions/ComponentWatching/Config.pm24
-rw-r--r--extensions/ComponentWatching/Extension.pm163
-rw-r--r--extensions/ComponentWatching/Extension.pm.orig345
-rwxr-xr-xextensions/ComponentWatching/reset-watch-preferences.pl75
-rw-r--r--extensions/ComponentWatching/template/en/default/account/prefs/component_watch.html.tmpl65
-rw-r--r--extensions/ComponentWatching/template/en/default/hook/account/prefs/email-relationships.html.tmpl22
-rw-r--r--extensions/ComponentWatching/template/en/default/hook/account/prefs/prefs-tabs.html.tmpl23
-rw-r--r--extensions/ComponentWatching/template/en/default/hook/admin/components/edit-common-rows.html.tmpl20
-rw-r--r--extensions/ComponentWatching/template/en/default/hook/admin/components/list-before_table.html.tmpl17
-rw-r--r--extensions/ComponentWatching/template/en/default/hook/global/messages-component_updated_fields.html.tmpl15
-rw-r--r--extensions/ComponentWatching/template/en/default/hook/global/reason-descs-end.none.tmpl22
-rw-r--r--extensions/ComponentWatching/template/en/default/hook/global/user-error-errors.html.tmpl13
-rw-r--r--t/008filter.t3
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>&nbsp;</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 =~ /.+\?(.+):(.+)/) {